mirror of
https://github.com/Sea-Haven-Industries/seahaven-ap.git
synced 2026-10-07 16:18:53 +00:00
* feat(api): stand up Hono Drizzle foundation with auth and Redocly * fix(api): bump drizzle-orm and hono node-server past audit highs * fix(api): harden auth upsert and Cognito token verification
41 lines
1.1 KiB
TypeScript
41 lines
1.1 KiB
TypeScript
import type { UserRole } from "../env.js";
|
|
|
|
/** Foundation + forward-looking actions used by the RBAC matrix. */
|
|
export const RBAC_ACTIONS = [
|
|
"read:me",
|
|
"read:invoices",
|
|
"write:invoices",
|
|
"approve:invoices",
|
|
"admin:settings",
|
|
] as const;
|
|
|
|
export type RbacAction = (typeof RBAC_ACTIONS)[number];
|
|
|
|
const MATRIX: Readonly<Record<UserRole, ReadonlySet<RbacAction>>> = {
|
|
admin: new Set(RBAC_ACTIONS),
|
|
ap_processor: new Set(["read:me", "read:invoices", "write:invoices"]),
|
|
approver: new Set(["read:me", "read:invoices", "approve:invoices"]),
|
|
viewer: new Set(["read:me", "read:invoices"]),
|
|
};
|
|
|
|
export function can(role: UserRole, action: RbacAction): boolean {
|
|
return MATRIX[role].has(action);
|
|
}
|
|
|
|
export function requireRole(role: UserRole, action: RbacAction): void {
|
|
if (!can(role, action)) {
|
|
throw new RbacDeniedError(role, action);
|
|
}
|
|
}
|
|
|
|
export class RbacDeniedError extends Error {
|
|
readonly status = 403 as const;
|
|
|
|
constructor(
|
|
readonly role: UserRole,
|
|
readonly action: RbacAction,
|
|
) {
|
|
super(`Role ${role} is not allowed to ${action}.`);
|
|
this.name = "RbacDeniedError";
|
|
}
|
|
}
|