seahaven-ap/packages/api/src/auth/rbac.ts
Adam Moussa 9d3646876e
feat(api): stand up Hono Drizzle foundation with auth and Redocly (AP-14) (#12)
* 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
2026-08-11 00:10:49 +00:00

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";
}
}