import React from 'react'; import type { TableMetadata, ActionDefinition } from './types'; /** Predicate answering "can the current user use this capability?". */ export type CanFn = (capability: string) => boolean; export interface PermissionsProviderProps { /** Granted capabilities (`"pos_orders.create"`, `"general.x"`, or `"*"`). */ permissions: string[]; /** Superrole bypass — admins/owners see everything, no filtering at all. */ isAdmin: boolean; /** * Roles of the current user (e.g. `['doctor']`), used ONLY to honour the * per-action `allowedRoles` declared in table metadata. Opt-in: while this * is `undefined` (and `loading` is not set) role filtering is OFF and * `allowedRoles` is ignored, exactly as before this prop existed. Once the * host passes an array (even `[]` = "resolved, no roles") the filter is * fail-closed: an action with a non-empty `allowedRoles` that shares no * role with the user is hidden. * * Pass a referentially stable array (`useMemo`, or a value straight from a * store): the table rebuilds its columns when `roles` / `superRoles` change * identity, so an inline `roles={[role]}` recreates them on every render. */ roles?: string[]; /** * Roles that bypass `allowedRoles` entirely (the host's superroles, e.g. * `['admin', 'super_admin']`). Default `[]` = no role bypasses. `isAdmin` * also bypasses. Same stable-reference advice as `roles`. */ superRoles?: string[]; /** * The host is still hydrating the session roles. While true no action is * hidden by `allowedRoles` (avoids a flash of missing actions); set it back * to false once `roles` is resolved. */ rolesLoading?: boolean; children: React.ReactNode; } /** Resolved role-gating state shared with the table surfaces. */ export interface RoleGate { /** User roles; `undefined` while unresolved. */ roles?: string[]; superRoles: string[]; loading: boolean; isAdmin: boolean; } /** * Builds the capability predicate from a raw permission list. Pure — exported * so hosts/tests can evaluate permissions outside React. */ export declare function makeCan(permissions: string[], isAdmin: boolean): CanFn; export declare function PermissionsProvider({ permissions, isAdmin, roles, superRoles, rolesLoading, children, }: PermissionsProviderProps): React.JSX.Element; /** * Role-gating state of the nearest , or `null` when none * is mounted (no provider → no role filtering, legacy behaviour). */ export declare function useRoleGate(): RoleGate | null; /** * Whether `action` is visible for the user under `gate`. Pure. * * UX ONLY: this hides buttons, it does not authorize anything. The backend * remains the authority and must enforce the same `allowedRoles` on execution. * * Rules: * - no gate (no provider) → visible (unchanged behaviour). * - action without `allowedRoles` (or empty) → visible. Reads both the * camelCase `allowedRoles` and the snake_case `allowed_roles` wire forms. * - `gate.loading` → visible (don't flash-hide while the session hydrates). * - `gate.roles === undefined` and not loading → the host did not opt in to * role gating → visible. * - `gate.isAdmin` or any user role in `gate.superRoles` → visible. * - otherwise visible only if the user shares a role with `allowedRoles` * (fail-closed: `roles: []` sees none of the restricted actions). */ export declare function isActionAllowedForRoles(action: ActionDefinition, gate: RoleGate | null): boolean; /** * Returns the capability predicate. Without a ancestor * it returns an always-true function — existing hosts that never mount the * provider keep today's "everything visible" behaviour. */ export declare function useCan(): CanFn; /** True when a is mounted above (permission gating active). */ export declare function usePermissionsActive(): boolean; /** * Maps a row/table action key onto the capability action segment. The UI's * legacy `view`/`edit` keys correspond to the kernel's `index`/`update` * capabilities; everything else (delete, custom keys) maps verbatim. */ export declare function capabilityForActionKey(actionKey: string): string; /** Canonical capability for an action on a model: `lowercase(model).`. */ export declare function modelCapability(model: string, actionKey: string): string; /** * Applies the capability predicate to a model's table metadata: * - `canExport` / `canImport` are ANDed with `can(model.export|import)`. * - explicit row/table actions are filtered by `can(model.)` (with the * view→index / edit→update mapping above). * - when the metadata has NO explicit actions but `enableCRUDActions` is on, * the implicit View/Edit/Delete trio is materialized here as explicit * actions so individual entries can be dropped; `tx` resolves their labels * (defaults to the Spanish fallbacks used by the column factory). * * When `roleGate` is given, actions declaring `allowedRoles` are also dropped * for users outside those roles (see `isActionAllowedForRoles`; UX only, the * backend stays the authority). * * Pure + idempotent. Callers should only invoke it when a provider is active * (`usePermissionsActive()`), otherwise pass the metadata through untouched. */ export declare function gateTableMetadata(metadata: TableMetadata, model: string, can: CanFn, tx?: (i18nKey: string, fallback: string) => string, roleGate?: RoleGate | null): TableMetadata; /** * Resolves the per-row (`placement: 'row'`) action list for a model exactly the * way DynamicTable's action column does, so the kanban card menu shows the SAME * actions: * - when a is active, the metadata is run through * `gateTableMetadata` first (filters by capability + materializes the CRUD * trio), otherwise the raw metadata is used. * - explicit actions win; absent them, the implicit View/Edit/Delete trio is * materialized when `enableCRUDActions` is on. * - table/create-placement actions are stripped (they belong to the toolbar). * * Pure. `tx` resolves the trio's i18n labels (defaults to the Spanish fallbacks). */ export declare function resolveRowActions(metadata: TableMetadata, model: string, can: CanFn, permissionsActive: boolean, tx?: (i18nKey: string, fallback: string) => string, roleGate?: RoleGate | null): ActionDefinition[]; //# sourceMappingURL=permissions-context.d.ts.map