/** * @beignet/core/entitlements * * Provider-neutral product access primitives for Beignet applications. */ type MaybePromise = T | Promise; /** * Stable app-defined capability key, such as "issues.create". */ export type EntitlementKey = string; /** * Principal whose product access is being checked. */ export type EntitlementSubject = { /** * App-defined subject type, commonly "tenant" or "account". */ type: string; /** * Stable subject identifier. */ id: string; }; /** * Input for checking whether a subject has access to a capability. */ export type EntitlementCheckInput = { /** * Capability being checked. */ entitlement: TKey; /** * Tenant, account, or other app-owned subject whose product access is checked. */ subject: EntitlementSubject; }; /** * An entitlement decision that allows the capability. */ export type EntitlementAllowedDecision = { allowed: true; }; /** * An entitlement decision that denies the capability. */ export type EntitlementDeniedDecision = { allowed: false; reason?: string; code?: string; details?: unknown; }; /** * Normalized entitlement decision. */ export type EntitlementDecision = EntitlementAllowedDecision | EntitlementDeniedDecision; /** * Value an entitlement resolver may return. */ export type EntitlementResolverResult = boolean | EntitlementDecision; /** * Entitlement port method that produced a decision. */ export type EntitlementDecisionSource = "can" | "inspect" | "require"; /** * Optional context for entitlement checks. */ export type EntitlementCheckOptions = { /** * Application context used for the check. Observers can use this to copy * request correlation fields without coupling the resolver to app context. */ ctx?: TContext; /** * Source to report to observers. Port methods set this automatically. */ source?: EntitlementDecisionSource; }; /** * App-facing product access port. */ export type EntitlementsPort = { /** * Return only whether the capability is allowed. */ can(input: EntitlementCheckInput, options?: EntitlementCheckOptions): Promise; /** * Return the full allow/deny decision without throwing. */ inspect(input: EntitlementCheckInput, options?: EntitlementCheckOptions): Promise; }; /** * Function that decides whether an entitlement is granted. */ export type EntitlementResolver = (input: EntitlementCheckInput) => MaybePromise; /** * Best-effort entitlement decision observation emitted by an entitlements port. * * Observers are diagnostic only. They do not participate in entitlement * control flow and thrown/rejected observer errors are ignored. */ export type EntitlementDecisionObservation = { /** * Port helper that produced the decision. */ source: EntitlementDecisionSource; /** * Application context passed by the caller, when available. */ ctx?: TContext; /** * Capability being evaluated. */ entitlement: TKey; /** * Subject whose product access is checked. */ subject: EntitlementSubject; /** * Normalized decision, when resolver evaluation returned normally. */ decision?: EntitlementDecision; /** * Error thrown by the resolver, when evaluation failed. */ error?: unknown; /** * Resolver duration, excluding observer work. */ durationMs: number; /** * Correlation fields copied from the context when present. */ requestId?: string; traceId?: string; spanId?: string; parentSpanId?: string; traceparent?: string; }; /** * Best-effort observer called after each entitlement decision or resolver * error. */ export type EntitlementDecisionObserver = (observation: EntitlementDecisionObservation) => MaybePromise; /** * Options for `createEntitlements(...)`. */ export type CreateEntitlementsOptions = { /** * Resolver that maps app-owned product state to an entitlement decision. */ inspect: EntitlementResolver; /** * Optional best-effort observer for entitlement decisions. * * This hook is diagnostic only: it cannot change decisions or thrown errors. */ onDecision?: EntitlementDecisionObserver; }; /** * Static grant map keyed by subject key. */ export type StaticEntitlementGrantMap = Record; /** * Options for `createStaticEntitlements(...)`. */ export type CreateStaticEntitlementsOptions = { /** * Granted capabilities keyed by subject. The default key is * `${subject.type}:${subject.id}`. */ grants: StaticEntitlementGrantMap; /** * Optional subject key mapper. */ subjectKey?: (subject: EntitlementSubject) => string; /** * Default denial decision fields. */ denied?: Omit; /** * Optional best-effort observer for entitlement decisions. */ onDecision?: EntitlementDecisionObserver; }; /** * Options accepted by `requireEntitlement(...)`. */ export type RequireEntitlementOptions = { /** * Create the error to throw instead of the framework default. */ error?: (decision: EntitlementDeniedDecision, input: EntitlementCheckInput) => unknown; }; /** * Context shape consumed by `requireEntitlement(...)`. */ export type EntitlementsContext = { ports: { entitlements: EntitlementsPort; }; }; /** * Error thrown by `requireEntitlement(...)` when product access is denied. */ export declare class EntitlementRequiredError extends Error { readonly code: string; readonly status = 403; readonly details?: unknown; readonly entitlement: string; readonly subject: EntitlementSubject; constructor(input: EntitlementCheckInput, decision?: EntitlementDeniedDecision); } /** * Create an explicit allow decision. */ export declare function allowEntitlement(): EntitlementAllowedDecision; /** * Create an explicit deny decision. */ export declare function denyEntitlement(reasonOrDecision?: string | Omit): EntitlementDeniedDecision; /** * Create an entitlement port from an app-owned resolver. */ export declare function createEntitlements(options: CreateEntitlementsOptions): EntitlementsPort; /** * Create a static entitlement port for tests, starters, and simple apps. */ export declare function createStaticEntitlements(options: CreateStaticEntitlementsOptions): EntitlementsPort; /** * Require an entitlement or throw a framework-owned 403 error. */ export declare function requireEntitlement(ctx: EntitlementsContext, input: EntitlementCheckInput, options?: RequireEntitlementOptions): Promise; export {}; //# sourceMappingURL=index.d.ts.map