UNPKG

@beignet/core

Version:

Core framework primitives for Beignet

56 lines (50 loc) 1.65 kB
import type { ActivityTenant } from "../ports/audit.js"; import { type RequireOptions, requireTenant } from "../ports/auth.js"; const tenantScopeBrand = Symbol("TenantScope"); /** * Branded tenant scope token for repository boundaries. * * Apps still own tenant resolution and tenant data modeling. `TenantScope` * carries the already-resolved activity tenant through app-facing repository * ports so adapters can apply tenant predicates without accepting arbitrary * caller-provided tenant IDs. */ export type TenantScope = Readonly<{ id: string; tenant: ActivityTenant; readonly [tenantScopeBrand]: true; }>; /** * Create a tenant scope from a resolved activity tenant. * * This does not load, create, or validate a tenant record. It only brands the * already-resolved tenant for repository and adapter boundaries. */ export function createTenantScope(tenant: ActivityTenant): TenantScope { return { id: tenant.id, tenant, [tenantScopeBrand]: true, }; } /** * Return a branded tenant scope from `ctx.tenant` or throw. * * Throws `TenantRequiredError` by default through `requireTenant`. Pass * `options.error` to throw an app-owned error instead. */ export function requireTenantScope( ctx: { tenant?: ActivityTenant | null }, options?: RequireOptions, ): TenantScope { return createTenantScope(requireTenant(ctx, options)); } /** * Extract the stable tenant ID from a tenant scope. * * Repository adapters should use this helper at the persistence boundary * instead of accepting raw tenant IDs from use cases. */ export function tenantScopeId(scope: TenantScope): string { return scope.id; }