export const ROLE_PERMS: Record<Role, Permission[]> = {
Owner: PERMISSIONS.map((p) => p.id),
Admin: ["viewUsage", "manageKeys", "manageProjects", "manageLimits",
"viewBilling", "manageBilling", "manageTeam"],
Developer: ["viewUsage", "manageKeys", "manageProjects"],
"Finance viewer": ["viewUsage", "viewBilling"],
};
// <Gate> only disables buttons. guarded() re-checks the role inside each
// store action, so a missed button or a console call can't change data.
export function guarded<T extends ActionMap>(actions: T, perms: PermMap<T>) {
return Object.fromEntries(Object.entries(actions).map(([name, fn]) => [name,
(...args: unknown[]) => {
const perm = perms[name], role = roleOf(state);
if (perm && !ROLE_PERMS[role].includes(perm)) {
toast.error(deniedReason(role));
return undefined;
}
return fn(...args);
}]));
}
export const billingActions = guarded({ topUp, setAutoRecharge, /* … */ },
{ topUp: "manageBilling", setAutoRecharge: "manageBilling" });