/** * Client-side capability mirror. * * This mirrors ``app/domain/identity/models.py`` so the UI can hide actions a * role cannot perform. It is **only** a UX affordance: the API re-checks every * capability server-side, and nothing here is a security boundary. */ import type { Role } from "@agy/contracts"; export const CAN_MANAGE_ORG = "org.manage"; export const CAN_MANAGE_MEMBERS = "org.members"; export const CAN_MANAGE_PROJECTS = "projects.manage"; export const CAN_MANAGE_EMPLOYEES = "employees.manage"; export const CAN_RUN_TASKS = "tasks.run"; export const CAN_VIEW_BILLING = "billing.view"; export const CAN_MANAGE_BILLING = "billing.manage"; export const CAN_VIEW_AUDIT = "audit.view"; export const CAN_USE_SANDBOX = "sandbox.use"; const ROLE_CAPABILITIES: Record> = { viewer: new Set(), member: new Set([CAN_RUN_TASKS, CAN_VIEW_BILLING]), manager: new Set([ CAN_RUN_TASKS, CAN_VIEW_BILLING, CAN_MANAGE_PROJECTS, CAN_MANAGE_EMPLOYEES, CAN_USE_SANDBOX, ]), admin: new Set([ CAN_RUN_TASKS, CAN_VIEW_BILLING, CAN_MANAGE_BILLING, CAN_MANAGE_PROJECTS, CAN_MANAGE_EMPLOYEES, CAN_USE_SANDBOX, CAN_MANAGE_MEMBERS, CAN_VIEW_AUDIT, ]), owner: new Set([ CAN_RUN_TASKS, CAN_VIEW_BILLING, CAN_MANAGE_BILLING, CAN_MANAGE_PROJECTS, CAN_MANAGE_EMPLOYEES, CAN_USE_SANDBOX, CAN_MANAGE_MEMBERS, CAN_VIEW_AUDIT, CAN_MANAGE_ORG, ]), }; export function roleHasCapability(role: Role | undefined | null, capability: string): boolean { if (!role) return false; return ROLE_CAPABILITIES[role]?.has(capability) ?? false; }