import type { AssignmentPolicy } from "./types.js"; /** The minimum a catalog row must expose for the admin-set derivation. * Structurally a subset of `PermissionDef`, so a `PermissionDef[]` (or the * values of a `DefinedPermissionMap`) can be passed directly. */ export interface AdminComputeEntry { key: string; /** Total post-D649 — the primitive REQUIRES it and refuses to guess. */ entitlementKey: string; assignmentPolicy?: AssignmentPolicy; } export interface ComputeModuleAdminOptions { /** Caller-supplied separation-of-duties exclusions. Tenant data, never a * library constant. */ excludeKeys?: Iterable; } /** * D649 § 1 — the computed permission set of module M's admin role: * * admin(M) = { p : p.entitlementKey === M } * ∪ ( ⋃ A ∈ activeAddonKeys : { p : p.entitlementKey === A } ) * − { p : p.assignmentPolicy === 'seat_locked' } (D612) * − excludeKeys (SoD, caller-supplied) * * Pure and deterministic: the result is in first-seen order of `catalog`, and * neither argument is mutated. * * `activeAddonKeys` is used UNFILTERED — the function does NOT prefix-filter it * to M's own namespace. That is the honest contract: the caller passes M's * add-ons, and every add-on key in the D620 fill is already module-prefixed and * 2-segment (`hr.*` ×9, `crm.collector`, `crm.distributor`, * `ticketing.field_agent`), so a defensive filter here would be a silent * behaviour change dressed as safety. It remains addable later if the taxonomy * ever grows an unprefixed add-on key. * * The `SUBSTRATE_ENTITLEMENT` sentinel can never match `moduleKey` or an add-on * key — it is a RESERVED_NAMESPACES member, so `validateDomainKey` rejects it as * a publish namespace and nothing can mint a module called `substrate`. * Substrate rows therefore cannot leak into an admin set through this * primitive. That is asserted by test, not merely reasoned. * * @throws {InvalidEntitlementKey} if any entry carries an empty/missing * `entitlementKey`. The primitive refuses to run on pre-backfill data rather * than silently computing a WRONG admin set — a quietly-undersized admin role * is an outage, and a quietly-oversized one is a privilege leak. */ export declare function computeModuleAdminPermissionKeys(catalog: Iterable, moduleKey: string, activeAddonKeys: Iterable, opts?: ComputeModuleAdminOptions): string[]; /** * D649 § 2 — the tenant-owner role stamp. * * The owner ALWAYS holds `tenant_admin` PLUS one admin role per subscribed * module. These are SEPARATE roles and are never unified into one mega-role: * a unified role cannot be partially revoked when a module is unsubscribed, and * it makes "which module made this person an admin?" unanswerable in an audit. * * Pure and deterministic: `tenant_admin` first, then the module admin roles in * the caller's iteration order, de-duplicated. Neither argument is mutated. * * `adminRoleKeyFor` is injectable because the `_admin` slug convention * belongs to nodii-tenant-service's `predefined_roles`, not to this library — * the default is an accommodation, not an authority. */ export declare function expandOwnerStampRoleKeys(subscribedModuleKeys: Iterable, adminRoleKeyFor?: (moduleKey: string) => string): string[]; //# sourceMappingURL=compute.d.ts.map