import type { Role } from './types.js' import { ROLE_HIERARCHY } from './types.js' /** * The plugin can't know the client's generated User type, and Payload types * `req.user` loosely (UntypedUser | null). Predicates therefore accept an * unknown-ish user and read `roles` defensively — no assumptions about shape * beyond an optional roles array. */ type MaybeUser = { roles?: null | Role[] } | null | Record | undefined /** Safely extracts the roles array from a loosely-typed user. */ function getRoles(user: MaybeUser): Role[] { if (!user || typeof user !== 'object') {return []} const roles = (user as { roles?: unknown }).roles if (!Array.isArray(roles)) {return []} return roles.filter((role): role is Role => ROLE_HIERARCHY.includes(role as Role)) } /** Highest-privilege role index the user holds, or -1 if none. */ function highestRoleIndex(user: MaybeUser): number { const roles = getRoles(user) if (!roles.length) {return -1} return Math.max(...roles.map((role) => ROLE_HIERARCHY.indexOf(role))) } /** * True if the user holds at least the given role in the hierarchy. * admin satisfies 'editor' and 'user'; editor satisfies 'user'. */ export function hasMinimumRole(user: MaybeUser, minimum: Role): boolean { return highestRoleIndex(user) >= ROLE_HIERARCHY.indexOf(minimum) } /** True if the user is an admin. */ export function isAdmin(user: MaybeUser): boolean { return hasMinimumRole(user, 'admin') } /** True if the user is an editor or higher (editor, admin). */ export function isEditor(user: MaybeUser): boolean { return hasMinimumRole(user, 'editor') }