@open-mercato/core 0.10.1-develop.7749.1.ea3edf75e3 → 0.10.1-develop.7752.1.fd7c06569b

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/api_keys/services/principalService.js +3 -2
  3. package/dist/modules/api_keys/services/principalService.js.map +2 -2
  4. package/dist/modules/api_keys/services/sessionKeyRoles.js +29 -0
  5. package/dist/modules/api_keys/services/sessionKeyRoles.js.map +7 -0
  6. package/dist/modules/auth/cli.js +13 -2
  7. package/dist/modules/auth/cli.js.map +2 -2
  8. package/dist/modules/auth/services/rbacService.js +18 -10
  9. package/dist/modules/auth/services/rbacService.js.map +2 -2
  10. package/dist/modules/business_rules/lib/action-executor.js +2 -1
  11. package/dist/modules/business_rules/lib/action-executor.js.map +2 -2
  12. package/dist/modules/directory/utils/organizationScope.js +11 -4
  13. package/dist/modules/directory/utils/organizationScope.js.map +2 -2
  14. package/dist/modules/entities/subscribers/seed-tenant-encryption-maps-retry.js +14 -0
  15. package/dist/modules/entities/subscribers/seed-tenant-encryption-maps-retry.js.map +7 -0
  16. package/dist/modules/entities/subscribers/seed-tenant-encryption-maps.js +37 -0
  17. package/dist/modules/entities/subscribers/seed-tenant-encryption-maps.js.map +7 -0
  18. package/dist/modules/warranty_claims/commands/claim-lines.js +25 -1
  19. package/dist/modules/warranty_claims/commands/claim-lines.js.map +3 -3
  20. package/dist/modules/warranty_claims/commands/claims.js +19 -1
  21. package/dist/modules/warranty_claims/commands/claims.js.map +2 -2
  22. package/dist/modules/warranty_claims/commands/shared.js +30 -0
  23. package/dist/modules/warranty_claims/commands/shared.js.map +2 -2
  24. package/package.json +7 -7
  25. package/src/modules/api_keys/services/principalService.ts +3 -2
  26. package/src/modules/api_keys/services/sessionKeyRoles.ts +35 -0
  27. package/src/modules/auth/cli.ts +11 -4
  28. package/src/modules/auth/services/rbacService.ts +22 -9
  29. package/src/modules/business_rules/lib/action-executor.ts +2 -3
  30. package/src/modules/directory/utils/organizationScope.ts +11 -4
  31. package/src/modules/entities/subscribers/seed-tenant-encryption-maps-retry.ts +12 -0
  32. package/src/modules/entities/subscribers/seed-tenant-encryption-maps.ts +38 -0
  33. package/src/modules/warranty_claims/commands/claim-lines.ts +26 -1
  34. package/src/modules/warranty_claims/commands/claims.ts +19 -1
  35. package/src/modules/warranty_claims/commands/shared.ts +36 -1
  36. package/src/modules/warranty_claims/i18n/de.json +1 -0
  37. package/src/modules/warranty_claims/i18n/en.json +1 -0
  38. package/src/modules/warranty_claims/i18n/es.json +1 -0
  39. package/src/modules/warranty_claims/i18n/ko.json +1 -0
  40. package/src/modules/warranty_claims/i18n/pl.json +1 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/auth/services/rbacService.ts"],
4
- "sourcesContent": ["import type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { getCurrentCacheTenant, runWithCacheTenant } from '@open-mercato/cache'\nimport { UserAcl, RoleAcl, User, UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { ApiKey } from '@open-mercato/core/modules/api_keys/data/entities'\nimport { Organization } from '@open-mercato/core/modules/directory/data/entities'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { OrganizationHierarchyService } from '@open-mercato/shared/lib/auth/principal-service'\nimport { buildOrgScopeUserCacheTag, buildOrgScopeTenantCacheTag } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport {\n authorizeFeatures,\n resolveEffectiveFeatures,\n} from '@open-mercato/shared/security/featurePolicy'\nimport { filterGrantsByEnabledModules } from '@open-mercato/shared/security/enabledModulesRegistry'\nimport { resolveRoleOrganizationScope, roleAclAllowsOrganization } from './roleOrganizationScope'\n\ninterface AclData {\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n}\n\nasync function resolveRoleOrganizationScopeWithEntityManager(\n em: EntityManager,\n tenantId: string | null,\n organizationId: string | null,\n): Promise<ReadonlySet<string> | null> {\n if (!organizationId) return null\n if (!tenantId) return new Set()\n const organization = await findOneWithDecryption(\n em,\n Organization,\n { id: organizationId, tenant: tenantId, deletedAt: null } as FilterQuery<Organization>,\n { fields: ['id', 'ancestorIds'] },\n { tenantId, organizationId },\n )\n if (!organization) return new Set()\n const ancestors = Array.isArray(organization.ancestorIds)\n ? organization.ancestorIds.filter((value): value is string => typeof value === 'string' && value.length > 0)\n : []\n return new Set([organizationId, ...ancestors])\n}\n\nfunction isAclData(value: unknown): value is AclData {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Partial<AclData>\n if (typeof record.isSuperAdmin !== 'boolean') return false\n if (!Array.isArray(record.features) || record.features.some((feature) => typeof feature !== 'string')) return false\n if (record.organizations !== null && record.organizations !== undefined) {\n if (!Array.isArray(record.organizations)) return false\n if (record.organizations.some((org) => typeof org !== 'string')) return false\n }\n return true\n}\n\nfunction isRestrictedRoleAcl(acl: Pick<RoleAcl, 'organizationsJson'>): boolean {\n return Array.isArray(acl.organizationsJson)\n && acl.organizationsJson.length > 0\n && !acl.organizationsJson.includes('__all__')\n}\n\ntype FeatureOrganizationCandidate = {\n id: string\n ancestorIds?: readonly string[] | null\n}\n\ntype FeatureOrganizationAccess = {\n unrestricted: boolean\n filterOrganizationIds: (organizations: readonly FeatureOrganizationCandidate[]) => string[]\n}\n\ntype FeatureOrganizationRoleGrant = {\n isSuperAdmin: boolean\n featuresJson: string[] | null\n organizationsJson: string[] | null\n}\n\ntype FeatureOrganizationGrants =\n | { kind: 'none' }\n | { kind: 'api_key'; organizationId: string | null; roleGrants: FeatureOrganizationRoleGrant[] }\n | { kind: 'user_acl'; isSuperAdmin: boolean; features: string[]; organizations: string[] | null }\n | { kind: 'roles'; roleGrants: FeatureOrganizationRoleGrant[] }\n\nfunction isStringListOrNull(value: unknown): value is string[] | null {\n return value === null || (Array.isArray(value) && value.every((entry) => typeof entry === 'string'))\n}\n\nfunction isFeatureOrganizationRoleGrant(value: unknown): value is FeatureOrganizationRoleGrant {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Partial<FeatureOrganizationRoleGrant>\n return typeof record.isSuperAdmin === 'boolean'\n && isStringListOrNull(record.featuresJson)\n && isStringListOrNull(record.organizationsJson)\n}\n\nfunction isFeatureOrganizationGrants(value: unknown): value is FeatureOrganizationGrants {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Record<string, unknown>\n switch (record.kind) {\n case 'none':\n return true\n case 'api_key':\n return (record.organizationId === null || typeof record.organizationId === 'string')\n && Array.isArray(record.roleGrants)\n && record.roleGrants.every(isFeatureOrganizationRoleGrant)\n case 'user_acl':\n return typeof record.isSuperAdmin === 'boolean'\n && Array.isArray(record.features)\n && record.features.every((feature) => typeof feature === 'string')\n && isStringListOrNull(record.organizations)\n case 'roles':\n return Array.isArray(record.roleGrants) && record.roleGrants.every(isFeatureOrganizationRoleGrant)\n default:\n return false\n }\n}\n\nfunction toFeatureOrganizationRoleGrant(\n acl: Pick<RoleAcl, 'isSuperAdmin' | 'featuresJson' | 'organizationsJson'>,\n): FeatureOrganizationRoleGrant {\n return {\n isSuperAdmin: acl.isSuperAdmin === true,\n featuresJson: Array.isArray(acl.featuresJson) ? [...acl.featuresJson] : null,\n organizationsJson: Array.isArray(acl.organizationsJson) ? [...acl.organizationsJson] : null,\n }\n}\n\nfunction normalizeFeatureOrganizationCandidates(\n organizations: readonly FeatureOrganizationCandidate[],\n): FeatureOrganizationCandidate[] {\n const normalized = new Map<string, FeatureOrganizationCandidate>()\n for (const organization of organizations) {\n const id = typeof organization.id === 'string' ? organization.id.trim() : ''\n if (!id || normalized.has(id)) continue\n const ancestorIds = Array.isArray(organization.ancestorIds)\n ? Array.from(new Set(organization.ancestorIds\n .map((ancestorId) => typeof ancestorId === 'string' ? ancestorId.trim() : '')\n .filter(Boolean)))\n : []\n normalized.set(id, { id, ancestorIds })\n }\n return Array.from(normalized.values())\n}\n\nfunction buildFeatureOrganizationScope(\n organization: FeatureOrganizationCandidate,\n): ReadonlySet<string> {\n return new Set([organization.id, ...(organization.ancestorIds ?? [])])\n}\n\nfunction roleAclProvidesGlobalFeatureScope(acl: Pick<RoleAcl, 'organizationsJson'>): boolean {\n const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null\n return !organizations || organizations.length === 0 || organizations.includes('__all__')\n}\n\nfunction roleAclProvidesGlobalVisibility(\n acl: Pick<RoleAcl, 'organizationsJson'>,\n emptyOrganizationsAreUnrestricted: boolean,\n): boolean {\n const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null\n if (!organizations || organizations.includes('__all__')) return true\n return emptyOrganizationsAreUnrestricted && organizations.length === 0\n}\n\nfunction roleAclProvidesOrganizationVisibility(\n acl: Pick<RoleAcl, 'organizationsJson'>,\n organizationScope: ReadonlySet<string>,\n emptyOrganizationsAreUnrestricted: boolean,\n): boolean {\n const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null\n if (!organizations || organizations.includes('__all__')) return true\n if (organizations.length === 0) return emptyOrganizationsAreUnrestricted\n return organizations.some((organizationId) => organizationScope.has(organizationId))\n}\n\nfunction roleAclsAuthorizeFeatures(\n roleAcls: readonly FeatureOrganizationRoleGrant[],\n required: readonly string[],\n organization: FeatureOrganizationCandidate,\n emptyOrganizationsAreUnrestricted: boolean,\n): boolean {\n const organizationScope = buildFeatureOrganizationScope(organization)\n const grantedFeatures = new Set<string>()\n let unrestricted = false\n let scopeAllowed = false\n\n for (const acl of roleAcls) {\n if (roleAclProvidesOrganizationVisibility(acl, organizationScope, emptyOrganizationsAreUnrestricted)) {\n scopeAllowed = true\n }\n if (!roleAclAllowsOrganization(acl, organizationScope)) continue\n unrestricted = unrestricted || acl.isSuperAdmin === true\n for (const feature of Array.isArray(acl.featuresJson) ? acl.featuresJson : []) {\n grantedFeatures.add(feature)\n }\n }\n\n return authorizeFeatures([...required], {\n grantedFeatures: Array.from(grantedFeatures),\n unrestricted,\n scopeAllowed: scopeAllowed || unrestricted,\n })\n}\n\nfunction roleAclsAuthorizeFeaturesGlobally(\n roleAcls: readonly FeatureOrganizationRoleGrant[],\n required: readonly string[],\n emptyOrganizationsAreUnrestricted: boolean,\n): boolean {\n const grantedFeatures = new Set<string>()\n let unrestricted = false\n let scopeAllowed = false\n\n for (const acl of roleAcls) {\n if (roleAclProvidesGlobalVisibility(acl, emptyOrganizationsAreUnrestricted)) {\n scopeAllowed = true\n }\n if (!roleAclProvidesGlobalFeatureScope(acl)) continue\n unrestricted = unrestricted || acl.isSuperAdmin === true\n for (const feature of Array.isArray(acl.featuresJson) ? acl.featuresJson : []) {\n grantedFeatures.add(feature)\n }\n }\n\n return authorizeFeatures([...required], {\n grantedFeatures: Array.from(grantedFeatures),\n unrestricted,\n scopeAllowed: scopeAllowed || unrestricted,\n })\n}\n\nexport class RbacService {\n private cacheTtlMs: number = 5 * 60 * 1000 // 5 minutes default\n private cache: CacheStrategy | null = null\n private globalSuperAdminCache = new Map<string, boolean>()\n\n constructor(\n private em: EntityManager,\n cache?: CacheStrategy,\n private readonly organizationHierarchyService?: OrganizationHierarchyService,\n ) {\n this.cache = cache || null\n }\n\n /**\n * Set cache TTL in milliseconds\n * @param ttlMs - Time to live in milliseconds\n */\n setCacheTtl(ttlMs: number) {\n this.cacheTtlMs = ttlMs\n }\n\n /** Compatibility wrapper for callers that already have both feature lists. */\n public hasAllFeatures(required: string[], granted: string[]): boolean {\n return authorizeFeatures(required, { grantedFeatures: granted })\n }\n\n private getCacheKey(userId: string, scope: { tenantId: string | null; organizationId: string | null }): string {\n return `rbac:${userId}:${scope.tenantId || 'null'}:${scope.organizationId || 'null'}`\n }\n\n private getUserTag(userId: string): string {\n return `rbac:user:${userId}`\n }\n\n private getTenantTag(tenantId: string): string {\n return `rbac:tenant:${tenantId}`\n }\n\n private getOrganizationTag(organizationId: string): string {\n return `rbac:org:${organizationId}`\n }\n\n private async getFromCache(cacheKey: string): Promise<AclData | null> {\n if (!this.cache) return null\n const cached = await this.cache.get(cacheKey)\n if (!cached) return null\n return isAclData(cached) ? cached : null\n }\n\n private async setCache(cacheKey: string, data: AclData, userId: string, scope: { tenantId: string | null; organizationId: string | null }): Promise<void> {\n if (!this.cache) return\n\n await this.cache.set(cacheKey, data, {\n ttl: this.cacheTtlMs,\n tags: this.buildCacheTags(userId, scope),\n })\n }\n\n private buildCacheTags(userId: string, scope: { tenantId: string | null; organizationId: string | null }): string[] {\n const tags = [\n this.getUserTag(userId),\n 'rbac:all'\n ]\n\n if (scope.tenantId) {\n tags.push(this.getTenantTag(scope.tenantId))\n // Scoped role projections depend on the selected organization's ancestor\n // chain, so Directory hierarchy changes must evict them as well as the\n // separately cached OrganizationScope entries.\n tags.push(buildOrgScopeTenantCacheTag(scope.tenantId))\n }\n\n if (scope.organizationId) {\n tags.push(this.getOrganizationTag(scope.organizationId))\n }\n\n return tags\n }\n\n /**\n * Invalidates cached ACL data for a specific user across all tenants and organizations.\n * Call this when a user's roles or user-specific ACL is modified.\n * \n * @param userId - The ID of the user whose cache should be invalidated\n */\n async invalidateUserCache(userId: string): Promise<void> {\n this.globalSuperAdminCache.delete(userId)\n // Also drop the directory OrganizationScope cache for this user. That scope's\n // accessible-org set is derived from this user's ACL/role grants, so any\n // permission change that invalidates the RBAC cache must invalidate the\n // resolved scope too. This is the missing `org-scope:user:*` caller required\n // before the cross-request scope TTL can be safely enabled (issue #2259).\n await this.deleteCacheByTags([this.getUserTag(userId), buildOrgScopeUserCacheTag(userId)])\n }\n\n /**\n * Invalidates cached ACL data for all users within a specific tenant.\n * Call this when a role's ACL is modified, since roles are tenant-scoped\n * and affect all users in that tenant who have that role.\n * \n * @param tenantId - The ID of the tenant whose cache should be invalidated\n */\n async invalidateTenantCache(tenantId: string): Promise<void> {\n this.globalSuperAdminCache.clear()\n // Role ACL changes invalidate every user in the tenant; the resolved\n // OrganizationScope for those users derives from the same grants, so drop\n // the tenant-tagged scope entries alongside the RBAC ones (issue #2259).\n await this.deleteCacheByTags([this.getTenantTag(tenantId), buildOrgScopeTenantCacheTag(tenantId)], [tenantId])\n }\n\n /**\n * Invalidates cached ACL data for all users within a specific organization.\n * Call this when organization-level permissions or visibility changes.\n * \n * @param organizationId - The ID of the organization whose cache should be invalidated\n */\n async invalidateOrganizationCache(organizationId: string): Promise<void> {\n await this.deleteCacheByTags([this.getOrganizationTag(organizationId)])\n }\n\n /**\n * Clears all cached ACL data.\n * Use this for bulk operations or system-wide ACL changes.\n */\n async invalidateAllCache(): Promise<void> {\n this.globalSuperAdminCache.clear()\n await this.deleteCacheByTags(['rbac:all'])\n }\n\n private async deleteCacheByTags(tags: string[], tenantHints?: Array<string | null>): Promise<void> {\n if (!this.cache) return\n const contexts = new Set<string | null>()\n const current = getCurrentCacheTenant()\n contexts.add(current ?? null)\n contexts.add(null)\n if (Array.isArray(tenantHints)) {\n for (const hint of tenantHints) {\n contexts.add(hint ?? null)\n }\n }\n for (const ctx of contexts) {\n if (ctx === current) {\n await this.cache.deleteByTags(tags)\n } else {\n await runWithCacheTenant(ctx, async () => {\n await this.cache!.deleteByTags(tags)\n })\n }\n }\n }\n\n private async isGlobalSuperAdmin(userId: string): Promise<boolean> {\n if (this.globalSuperAdminCache.has(userId)) return this.globalSuperAdminCache.get(userId)!\n const em = this.em.fork()\n const userSuper = await em.findOne(UserAcl, { user: userId as any, isSuperAdmin: true })\n if (userSuper && (userSuper as any).isSuperAdmin) {\n this.globalSuperAdminCache.set(userId, true)\n return true\n }\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as any },\n { populate: ['role'] },\n { tenantId: null, organizationId: null },\n )\n const linkList = Array.isArray(links) ? links : []\n if (!linkList.length) {\n this.globalSuperAdminCache.set(userId, false)\n return false\n }\n const roleIds = Array.from(new Set(linkList.map((link) => {\n const role = link.role as any\n return role?.id ? String(role.id) : null\n }).filter((id): id is string => typeof id === 'string' && id.length > 0)))\n if (!roleIds.length) {\n this.globalSuperAdminCache.set(userId, false)\n return false\n }\n const roleSupers = await em.find(RoleAcl, { isSuperAdmin: true, role: { $in: roleIds as any } } as any)\n const result = roleSupers.some((roleAcl) => (\n !!roleAcl.isSuperAdmin && !isRestrictedRoleAcl(roleAcl)\n ))\n this.globalSuperAdminCache.set(userId, result)\n return result\n }\n\n /**\n * Loads the Access Control List (ACL) for a user within a given scope.\n * \n * The ACL resolution follows this priority:\n * 1. Per-user ACL (UserAcl) - if exists, use it exclusively\n * 2. Aggregated role ACLs (RoleAcl) - combine permissions from all user's roles\n * \n * Results are cached for performance (default 5 minutes TTL).\n * Cache is automatically invalidated when ACL-related data changes.\n * \n * @param userId - The ID of the user\n * @param scope - The tenant and organization context for ACL evaluation\n * @returns An object containing:\n * - isSuperAdmin: If true, user has unrestricted access to all features\n * - features: Array of feature strings (may include wildcards like 'entities.*')\n * - organizations: Array of organization IDs user can access, or null for all organizations\n * \n * @example\n * const acl = await rbacService.loadAcl('user-123', { tenantId: 'tenant-1', organizationId: 'org-1' })\n * // Returns: { isSuperAdmin: false, features: ['users.view', 'entities.*'], organizations: ['org-1', 'org-2'] }\n */\n async loadAcl(userId: string, scope: { tenantId: string | null; organizationId: string | null }): Promise<{\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n }> {\n const cacheKey = this.getCacheKey(userId, scope)\n const cached = await this.getFromCache(cacheKey)\n if (cached) return cached\n\n // Direct user-level super-admin grants and unrestricted role-level\n // super-admin grants are global. Organization-restricted role grants are\n // deliberately excluded by isGlobalSuperAdmin and continue through the\n // scoped ACL projection below.\n if (!userId.startsWith('api_key:')) {\n if (await this.isGlobalSuperAdmin(userId)) {\n const result = { isSuperAdmin: true, features: ['*'], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n }\n\n if (userId.startsWith('api_key:')) {\n const apiKeyId = userId.slice('api_key:'.length)\n const em = this.em.fork()\n const key = await em.findOne(ApiKey, { id: apiKeyId, deletedAt: null })\n if (!key || (key.expiresAt && key.expiresAt.getTime() < Date.now())) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n const tenantId = scope.tenantId || key.tenantId || null\n const roleIds = Array.isArray(key.rolesJson) ? key.rolesJson.filter(Boolean) : []\n const keyOrganizationId = typeof key.organizationId === 'string' && key.organizationId.trim().length > 0\n ? key.organizationId.trim()\n : null\n const evaluatedOrganizationId = scope.organizationId || keyOrganizationId\n let isSuper = false\n const features: string[] = []\n let roleOrganizations: string[] | null = []\n let hasApplicableRestrictedRole = false\n if (tenantId && roleIds.length) {\n const roleOrganizationScope = await resolveRoleOrganizationScope(\n this.organizationHierarchyService,\n tenantId,\n evaluatedOrganizationId,\n )\n const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds as any } } as any)\n for (const acl of racls) {\n if (roleAclAllowsOrganization(acl, roleOrganizationScope)) {\n isSuper = isSuper || !!acl.isSuperAdmin\n if (Array.isArray(acl.featuresJson)) {\n for (const f of acl.featuresJson) if (!features.includes(f)) features.push(f)\n }\n if (isRestrictedRoleAcl(acl)) hasApplicableRestrictedRole = true\n }\n if (roleOrganizations !== null) {\n if (acl.organizationsJson == null || (Array.isArray(acl.organizationsJson) && acl.organizationsJson.length === 0)) {\n roleOrganizations = null\n } else if (Array.isArray(acl.organizationsJson) && acl.organizationsJson.includes('__all__')) {\n roleOrganizations = null\n } else {\n roleOrganizations = Array.from(new Set([\n ...roleOrganizations,\n ...(Array.isArray(acl.organizationsJson) ? acl.organizationsJson : []),\n ]))\n }\n }\n }\n if (\n roleOrganizations !== null\n && evaluatedOrganizationId\n && roleOrganizationScope !== null\n && roleOrganizationScope.size > 0\n && hasApplicableRestrictedRole\n && !roleOrganizations.includes(evaluatedOrganizationId)\n ) {\n roleOrganizations.push(evaluatedOrganizationId)\n }\n }\n let organizations = roleOrganizations\n if (keyOrganizationId) {\n const keyOrganizationScope = await resolveRoleOrganizationScope(\n this.organizationHierarchyService,\n tenantId,\n keyOrganizationId,\n )\n organizations = roleOrganizations === null\n || roleOrganizations.some((organizationId) => keyOrganizationScope?.has(organizationId))\n ? [keyOrganizationId]\n : []\n }\n // A role-level super-admin grant still respects the API key's effective\n // organization allowlist. Represent it as a wildcard feature whenever\n // the key is restricted so downstream super-admin shortcuts cannot\n // bypass the key or role organization bounds.\n if (isSuper && organizations !== null && !features.includes('*')) features.push('*')\n const result = { isSuperAdmin: isSuper && organizations === null, features, organizations }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Use a forked EntityManager to avoid inheriting an aborted transaction from callers\n const em = this.em.fork()\n const user = await em.findOne(User, { id: userId })\n if (!user) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n const tenantId = scope.tenantId || user.tenantId || null\n const orgId = scope.organizationId || user.organizationId || null\n\n if (!tenantId) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Per-user ACL first\n const uacl = await em.findOne(UserAcl, { user: userId as any, tenantId })\n if (uacl) {\n const result = {\n isSuperAdmin: !!uacl.isSuperAdmin,\n features: Array.isArray(uacl.featuresJson) ? (uacl.featuresJson as string[]) : [],\n organizations: Array.isArray(uacl.organizationsJson) ? (uacl.organizationsJson as string[]) : null,\n }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Aggregate role ACLs\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as any, role: { tenantId } } as any,\n { populate: ['role'] },\n { tenantId, organizationId: orgId },\n )\n const linkList = Array.isArray(links) ? links : []\n const roleIds = linkList.map((l) => (l.role as any)?.id).filter(Boolean)\n let isSuper = false\n const features: string[] = []\n let organizations: string[] | null = []\n let hasApplicableRestrictedRole = false\n if (roleIds.length) {\n const roleOrganizationScope = await resolveRoleOrganizationScope(\n this.organizationHierarchyService,\n tenantId,\n scope.organizationId,\n )\n const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds as any } } as any, {})\n const roleAcls = Array.isArray(racls) ? racls : []\n for (const r of roleAcls) {\n if (roleAclAllowsOrganization(r, roleOrganizationScope)) {\n isSuper = isSuper || !!r.isSuperAdmin\n if (Array.isArray(r.featuresJson)) for (const f of r.featuresJson) if (!features.includes(f)) features.push(f)\n if (isRestrictedRoleAcl(r)) hasApplicableRestrictedRole = true\n }\n if (organizations !== null) {\n // For a user principal an empty allowlist is a deny-all scope (#4033), not\n // \"unrestricted\": it must merge to an empty set so scoped reads and deletes\n // fail closed. Only an absent allowlist or an explicit '__all__' widens to\n // every organization. (The API-key branch above deliberately differs \u2014 an\n // empty role list there means the key inherits the key's own scope.)\n if (r.organizationsJson == null) organizations = null\n else if (Array.isArray(r.organizationsJson) && r.organizationsJson.includes('__all__')) organizations = null\n else organizations = Array.from(new Set([...(organizations || []), ...r.organizationsJson]))\n }\n }\n if (\n organizations !== null\n && scope.organizationId\n && roleOrganizationScope !== null\n && roleOrganizationScope.size > 0\n && hasApplicableRestrictedRole\n && !organizations.includes(scope.organizationId)\n ) {\n organizations.push(scope.organizationId)\n }\n }\n if (organizations && orgId && !organizations.includes(orgId) && !organizations.includes('__all__')) {\n // Out-of-scope org; caller will enforce\n }\n const result = { isSuperAdmin: isSuper, features, organizations }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n /**\n * Cache-bypassing ACL resolution bound to a caller-supplied EntityManager.\n * Replay authorization uses this additive seam after taking its canonical\n * locks so every user, membership, role, ACL, API-key, and organization-scope\n * read observes the exact transaction that performs the mutation.\n */\n async loadAclWithEntityManager(\n em: EntityManager,\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<AclData> {\n if (userId.startsWith('api_key:')) {\n const key = await em.findOne(ApiKey, {\n id: userId.slice('api_key:'.length),\n deletedAt: null,\n })\n if (!key || (key.expiresAt && key.expiresAt.getTime() < Date.now())) {\n return { isSuperAdmin: false, features: [], organizations: null }\n }\n const tenantId = scope.tenantId || key.tenantId || null\n const roleIds = Array.isArray(key.rolesJson) ? key.rolesJson.filter(Boolean) : []\n const keyOrganizationId = typeof key.organizationId === 'string' && key.organizationId.trim().length > 0\n ? key.organizationId.trim()\n : null\n const evaluatedOrganizationId = scope.organizationId || keyOrganizationId\n const roleScope = await resolveRoleOrganizationScopeWithEntityManager(\n em,\n tenantId,\n evaluatedOrganizationId,\n )\n const roleAcls = tenantId && roleIds.length\n ? await em.find(RoleAcl, { tenantId, role: { $in: roleIds as never } } as never)\n : []\n let isSuperAdmin = false\n const features: string[] = []\n let organizations: string[] | null = []\n let hasApplicableRestrictedRole = false\n for (const acl of roleAcls) {\n if (roleAclAllowsOrganization(acl, roleScope)) {\n isSuperAdmin = isSuperAdmin || acl.isSuperAdmin === true\n for (const feature of Array.isArray(acl.featuresJson) ? acl.featuresJson : []) {\n if (!features.includes(feature)) features.push(feature)\n }\n if (isRestrictedRoleAcl(acl)) hasApplicableRestrictedRole = true\n }\n if (organizations !== null) {\n if (\n acl.organizationsJson == null\n || acl.organizationsJson.length === 0\n || acl.organizationsJson.includes('__all__')\n ) {\n organizations = null\n } else {\n organizations = Array.from(new Set([...organizations, ...acl.organizationsJson]))\n }\n }\n }\n if (\n organizations !== null\n && evaluatedOrganizationId\n && roleScope !== null\n && roleScope.size > 0\n && hasApplicableRestrictedRole\n && !organizations.includes(evaluatedOrganizationId)\n ) {\n organizations.push(evaluatedOrganizationId)\n }\n if (keyOrganizationId) {\n const keyScope = await resolveRoleOrganizationScopeWithEntityManager(em, tenantId, keyOrganizationId)\n organizations = organizations === null\n || organizations.some((organizationId) => keyScope?.has(organizationId))\n ? [keyOrganizationId]\n : []\n }\n if (isSuperAdmin && organizations !== null && !features.includes('*')) features.push('*')\n return { isSuperAdmin: isSuperAdmin && organizations === null, features, organizations }\n }\n\n const directGlobalGrant = await em.findOne(\n UserAcl,\n { user: userId as never, isSuperAdmin: true } as never,\n )\n if (directGlobalGrant?.isSuperAdmin) {\n return { isSuperAdmin: true, features: ['*'], organizations: null }\n }\n const globalLinks = await findWithDecryption(\n em,\n UserRole,\n { user: userId as never },\n { populate: ['role'] },\n { tenantId: null, organizationId: null },\n )\n const globalRoleIds = globalLinks\n .map((link) => typeof link.role === 'string' ? link.role : link.role?.id ? String(link.role.id) : null)\n .filter((roleId): roleId is string => typeof roleId === 'string' && roleId.length > 0)\n if (globalRoleIds.length) {\n const globalRoleGrants = await em.find(\n RoleAcl,\n {\n role: { $in: globalRoleIds as never },\n isSuperAdmin: true,\n } as never,\n )\n if (globalRoleGrants.some((grant) => grant.isSuperAdmin && !isRestrictedRoleAcl(grant))) {\n return { isSuperAdmin: true, features: ['*'], organizations: null }\n }\n }\n\n const user = await em.findOne(User, { id: userId })\n if (!user) return { isSuperAdmin: false, features: [], organizations: null }\n const tenantId = scope.tenantId || user.tenantId || null\n const organizationId = scope.organizationId || user.organizationId || null\n if (!tenantId) return { isSuperAdmin: false, features: [], organizations: null }\n\n const userAcl = await em.findOne(UserAcl, { user: userId as never, tenantId } as never)\n if (userAcl) {\n return {\n isSuperAdmin: userAcl.isSuperAdmin === true,\n features: Array.isArray(userAcl.featuresJson) ? [...userAcl.featuresJson] : [],\n organizations: Array.isArray(userAcl.organizationsJson) ? [...userAcl.organizationsJson] : null,\n }\n }\n\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as never, role: { tenantId } } as never,\n { populate: ['role'] },\n { tenantId, organizationId },\n )\n const roleIds = links\n .map((link) => typeof link.role === 'string' ? link.role : link.role?.id ? String(link.role.id) : null)\n .filter((roleId): roleId is string => typeof roleId === 'string' && roleId.length > 0)\n const roleAcls = roleIds.length\n ? await em.find(RoleAcl, { tenantId, role: { $in: roleIds as never } } as never)\n : []\n const roleScope = await resolveRoleOrganizationScopeWithEntityManager(\n em,\n tenantId,\n scope.organizationId,\n )\n let isSuperAdmin = false\n const features: string[] = []\n let organizations: string[] | null = []\n let hasApplicableRestrictedRole = false\n for (const acl of roleAcls) {\n if (roleAclAllowsOrganization(acl, roleScope)) {\n isSuperAdmin = isSuperAdmin || acl.isSuperAdmin === true\n for (const feature of Array.isArray(acl.featuresJson) ? acl.featuresJson : []) {\n if (!features.includes(feature)) features.push(feature)\n }\n if (isRestrictedRoleAcl(acl)) hasApplicableRestrictedRole = true\n }\n if (organizations !== null) {\n if (acl.organizationsJson == null || acl.organizationsJson.includes('__all__')) {\n organizations = null\n } else {\n organizations = Array.from(new Set([...organizations, ...acl.organizationsJson]))\n }\n }\n }\n if (\n organizations !== null\n && scope.organizationId\n && roleScope\n && roleScope.size > 0\n && hasApplicableRestrictedRole\n && !organizations.includes(scope.organizationId)\n ) {\n organizations.push(scope.organizationId)\n }\n return { isSuperAdmin, features, organizations }\n }\n\n async userHasAllFeaturesWithEntityManager(\n em: EntityManager,\n userId: string,\n required: string[],\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<boolean> {\n if (!required.length) return true\n const acl = await this.loadAclWithEntityManager(em, userId, scope)\n const organizationAllowed = acl.isSuperAdmin\n || !acl.organizations\n || !scope.organizationId\n || acl.organizations.includes(scope.organizationId)\n || acl.organizations.includes('__all__')\n return authorizeFeatures(required, {\n grantedFeatures: acl.features,\n unrestricted: acl.isSuperAdmin,\n scopeAllowed: organizationAllowed,\n })\n }\n\n async getGrantedFeaturesWithEntityManager(\n em: EntityManager,\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<string[]> {\n const acl = await this.loadAclWithEntityManager(em, userId, scope)\n if (acl.isSuperAdmin) return filterGrantsByEnabledModules(['*'])\n if (\n acl.organizations\n && scope.organizationId\n && !acl.organizations.includes(scope.organizationId)\n && !acl.organizations.includes('__all__')\n ) {\n return []\n }\n return filterGrantsByEnabledModules(acl.features)\n }\n\n /**\n * Checks whether any tenant role grants a feature.\n *\n * This supports non-user runtimes such as scheduler workers that execute with\n * tenant scope but without an authenticated user.\n */\n async tenantHasFeature(\n tenantId: string | null | undefined,\n feature: string,\n opts?: { organizationId?: string | null },\n ): Promise<boolean> {\n if (!tenantId || !feature) return false\n\n const em = this.em.fork()\n const roleOrganizationScope = await resolveRoleOrganizationScope(\n this.organizationHierarchyService,\n tenantId,\n opts?.organizationId,\n )\n const roleAcls = await em.find(RoleAcl, { tenantId, deletedAt: null } as any, {})\n const list = Array.isArray(roleAcls) ? roleAcls : []\n\n for (const acl of list) {\n if (!roleAclAllowsOrganization(acl, roleOrganizationScope)) continue\n const grants = Array.isArray(acl.featuresJson) ? acl.featuresJson : []\n if (authorizeFeatures([feature], {\n grantedFeatures: grants,\n unrestricted: acl.isSuperAdmin,\n })) {\n return true\n }\n }\n\n return false\n }\n\n /**\n * Checks if a user has all required features within a given scope.\n *\n * This is the primary authorization check method used throughout the application.\n * It combines feature checking with organization visibility validation.\n *\n * Authorization logic:\n * 1. No features required \u2192 always returns true\n * 2. User is super admin \u2192 always returns true\n * 3. Organization restriction check: If the user's ACL has a restricted organization list\n * and the requested organization is not in that list \u2192 returns false\n * 4. Feature matching: User must have all required features (supports wildcards)\n *\n * @param userId - The ID of the user\n * @param required - Array of feature strings to check (e.g., ['users.view', 'users.edit'])\n * @param scope - The tenant and organization context for authorization\n * @returns true if the user has all required features and organization access, false otherwise\n *\n * @example\n * // Check if user can view and edit users\n * const canManageUsers = await rbacService.userHasAllFeatures(\n * 'user-123',\n * ['users.view', 'users.edit'],\n * { tenantId: 'tenant-1', organizationId: 'org-1' }\n * )\n *\n * @example\n * // Check with wildcard features\n * const canAccessEntities = await rbacService.userHasAllFeatures(\n * 'user-123',\n * ['entities.records.view'],\n * { tenantId: 'tenant-1', organizationId: 'org-1' }\n * )\n * // Returns true if user has 'entities.*', '*', or 'entities.records.view'\n */\n async userHasAllFeatures(userId: string, required: string[], scope: { tenantId: string | null; organizationId: string | null }): Promise<boolean> {\n if (!required.length) return true\n const acl = await this.loadAcl(userId, scope)\n const organizationAllowed = acl.isSuperAdmin\n || !acl.organizations\n || !scope.organizationId\n || acl.organizations.includes(scope.organizationId)\n || acl.organizations.includes('__all__')\n return authorizeFeatures(required, {\n grantedFeatures: acl.features,\n unrestricted: acl.isSuperAdmin,\n scopeAllowed: organizationAllowed,\n })\n }\n\n async resolveFeatureOrganizationAccess(\n userId: string,\n required: readonly string[],\n input: { tenantId: string | null },\n ): Promise<FeatureOrganizationAccess> {\n const allowAll = (organizations: readonly FeatureOrganizationCandidate[]) =>\n normalizeFeatureOrganizationCandidates(organizations).map((organization) => organization.id)\n const denyAll = () => []\n if (!required.length) return { unrestricted: true, filterOrganizationIds: allowAll }\n if (!input.tenantId) return { unrestricted: false, filterOrganizationIds: denyAll }\n if (\n !userId.startsWith('api_key:')\n && await this.isGlobalSuperAdmin(userId)\n && authorizeFeatures(required, { grantedFeatures: ['*'], unrestricted: true })\n ) {\n return { unrestricted: true, filterOrganizationIds: allowAll }\n }\n\n const grants = await this.loadFeatureOrganizationGrants(userId, input.tenantId)\n if (grants.kind === 'none') return { unrestricted: false, filterOrganizationIds: denyAll }\n\n if (grants.kind === 'api_key') {\n const keyOrganizationId = grants.organizationId\n const unrestricted = keyOrganizationId === null\n && roleAclsAuthorizeFeaturesGlobally(grants.roleGrants, required, true)\n if (unrestricted) return { unrestricted: true, filterOrganizationIds: allowAll }\n\n return {\n unrestricted: false,\n filterOrganizationIds: (candidates) => normalizeFeatureOrganizationCandidates(candidates)\n .filter((organization) => (\n (!keyOrganizationId || organization.id === keyOrganizationId)\n && roleAclsAuthorizeFeatures(grants.roleGrants, required, organization, true)\n ))\n .map((organization) => organization.id),\n }\n }\n\n if (grants.kind === 'user_acl') {\n const grantedFeatures = grants.features\n const allowedOrganizations = grants.organizations\n const hasGlobalScope = grants.isSuperAdmin\n || allowedOrganizations === null\n || allowedOrganizations.includes('__all__')\n const unrestricted = authorizeFeatures([...required], {\n grantedFeatures,\n unrestricted: grants.isSuperAdmin,\n scopeAllowed: hasGlobalScope,\n })\n if (unrestricted) return { unrestricted: true, filterOrganizationIds: allowAll }\n\n return {\n unrestricted: false,\n filterOrganizationIds: (candidates) => normalizeFeatureOrganizationCandidates(candidates)\n .filter((organization) => {\n const scopeAllowed = grants.isSuperAdmin\n || allowedOrganizations === null\n || allowedOrganizations.includes('__all__')\n || allowedOrganizations.includes(organization.id)\n return authorizeFeatures([...required], {\n grantedFeatures,\n unrestricted: grants.isSuperAdmin,\n scopeAllowed,\n })\n })\n .map((organization) => organization.id),\n }\n }\n\n if (roleAclsAuthorizeFeaturesGlobally(grants.roleGrants, required, false)) {\n return { unrestricted: true, filterOrganizationIds: allowAll }\n }\n\n return {\n unrestricted: false,\n filterOrganizationIds: (candidates) => normalizeFeatureOrganizationCandidates(candidates)\n .filter((organization) => roleAclsAuthorizeFeatures(grants.roleGrants, required, organization, false))\n .map((organization) => organization.id),\n }\n }\n\n private async loadFeatureOrganizationGrants(\n userId: string,\n tenantId: string,\n ): Promise<FeatureOrganizationGrants> {\n const cacheKey = `rbac:feature-organizations:${userId}:${tenantId}`\n if (this.cache) {\n const cached = await this.cache.get(cacheKey)\n if (isFeatureOrganizationGrants(cached)) return cached\n }\n const grants = await this.queryFeatureOrganizationGrants(userId, tenantId)\n if (this.cache) {\n await this.cache.set(cacheKey, grants, {\n ttl: this.cacheTtlMs,\n tags: this.buildCacheTags(userId, { tenantId, organizationId: null }),\n })\n }\n return grants\n }\n\n private async queryFeatureOrganizationGrants(\n userId: string,\n tenantId: string,\n ): Promise<FeatureOrganizationGrants> {\n const em = this.em.fork()\n if (userId.startsWith('api_key:')) {\n const apiKeyId = userId.slice('api_key:'.length)\n const key = await em.findOne(ApiKey, { id: apiKeyId, deletedAt: null })\n if (\n !key\n || (key.expiresAt && key.expiresAt.getTime() < Date.now())\n || (key.tenantId && key.tenantId !== tenantId)\n ) {\n return { kind: 'none' }\n }\n\n const roleIds = Array.isArray(key.rolesJson) ? key.rolesJson.filter(Boolean) : []\n if (!roleIds.length) return { kind: 'none' }\n const roleAcls = await em.find(RoleAcl, {\n tenantId,\n role: { $in: roleIds },\n })\n const keyOrganizationId = typeof key.organizationId === 'string' && key.organizationId.trim().length > 0\n ? key.organizationId.trim()\n : null\n return {\n kind: 'api_key',\n organizationId: keyOrganizationId,\n roleGrants: roleAcls.map(toFeatureOrganizationRoleGrant),\n }\n }\n\n const user = await em.findOne(User, { id: userId })\n if (!user) return { kind: 'none' }\n\n const userAcl = await em.findOne(UserAcl, { user: userId, tenantId })\n if (userAcl) {\n return {\n kind: 'user_acl',\n isSuperAdmin: userAcl.isSuperAdmin === true,\n features: Array.isArray(userAcl.featuresJson) ? [...userAcl.featuresJson] : [],\n organizations: Array.isArray(userAcl.organizationsJson) ? [...userAcl.organizationsJson] : null,\n }\n }\n\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId, role: { tenantId } },\n { populate: ['role'] },\n { tenantId, organizationId: null },\n )\n const roleIds = Array.from(new Set(links\n .map((link) => link.role?.id)\n .filter((roleId): roleId is string => typeof roleId === 'string' && roleId.length > 0)))\n if (!roleIds.length) return { kind: 'none' }\n\n const roleAcls = await em.find(RoleAcl, {\n tenantId,\n role: { $in: roleIds },\n })\n return { kind: 'roles', roleGrants: roleAcls.map(toFeatureOrganizationRoleGrant) }\n }\n\n /**\n * Returns the user's infrastructure grant list, filtered to enabled modules.\n * The result may contain wildcards; authoritative checks must still go through\n * `authorizeFeatures` or `userHasAllFeatures` so null overrides are enforced.\n */\n async getGrantedFeatures(\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<string[]> {\n const acl = await this.loadAcl(userId, scope)\n if (acl.isSuperAdmin) return filterGrantsByEnabledModules(['*'])\n if (\n acl.organizations &&\n scope.organizationId &&\n !acl.organizations.includes(scope.organizationId) &&\n !acl.organizations.includes('__all__')\n ) {\n return []\n }\n return filterGrantsByEnabledModules(acl.features)\n }\n\n /** Returns concrete active feature IDs for browser capability payloads. */\n async getEffectiveFeatures(\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<string[]> {\n const acl = await this.loadAcl(userId, scope)\n const organizationAllowed = acl.isSuperAdmin\n || !acl.organizations\n || !scope.organizationId\n || acl.organizations.includes(scope.organizationId)\n || acl.organizations.includes('__all__')\n if (!organizationAllowed) return []\n return resolveEffectiveFeatures(acl.isSuperAdmin ? ['*'] : acl.features)\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport type { CacheStrategy } from '@open-mercato/cache'\nimport { getCurrentCacheTenant, runWithCacheTenant } from '@open-mercato/cache'\nimport { UserAcl, RoleAcl, User, UserRole } from '@open-mercato/core/modules/auth/data/entities'\nimport { ApiKey } from '@open-mercato/core/modules/api_keys/data/entities'\nimport { isSessionBoundApiKey, resolveApiKeyRoleIds } from '@open-mercato/core/modules/api_keys/services/sessionKeyRoles'\nimport { Organization } from '@open-mercato/core/modules/directory/data/entities'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { OrganizationHierarchyService } from '@open-mercato/shared/lib/auth/principal-service'\nimport { buildOrgScopeUserCacheTag, buildOrgScopeTenantCacheTag } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport {\n authorizeFeatures,\n resolveEffectiveFeatures,\n} from '@open-mercato/shared/security/featurePolicy'\nimport { filterGrantsByEnabledModules } from '@open-mercato/shared/security/enabledModulesRegistry'\nimport { resolveRoleOrganizationScope, roleAclAllowsOrganization } from './roleOrganizationScope'\n\ninterface AclData {\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n}\n\nasync function resolveRoleOrganizationScopeWithEntityManager(\n em: EntityManager,\n tenantId: string | null,\n organizationId: string | null,\n): Promise<ReadonlySet<string> | null> {\n if (!organizationId) return null\n if (!tenantId) return new Set()\n const organization = await findOneWithDecryption(\n em,\n Organization,\n { id: organizationId, tenant: tenantId, deletedAt: null } as FilterQuery<Organization>,\n { fields: ['id', 'ancestorIds'] },\n { tenantId, organizationId },\n )\n if (!organization) return new Set()\n const ancestors = Array.isArray(organization.ancestorIds)\n ? organization.ancestorIds.filter((value): value is string => typeof value === 'string' && value.length > 0)\n : []\n return new Set([organizationId, ...ancestors])\n}\n\nfunction isAclData(value: unknown): value is AclData {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Partial<AclData>\n if (typeof record.isSuperAdmin !== 'boolean') return false\n if (!Array.isArray(record.features) || record.features.some((feature) => typeof feature !== 'string')) return false\n if (record.organizations !== null && record.organizations !== undefined) {\n if (!Array.isArray(record.organizations)) return false\n if (record.organizations.some((org) => typeof org !== 'string')) return false\n }\n return true\n}\n\nfunction isRestrictedRoleAcl(acl: Pick<RoleAcl, 'organizationsJson'>): boolean {\n return Array.isArray(acl.organizationsJson)\n && acl.organizationsJson.length > 0\n && !acl.organizationsJson.includes('__all__')\n}\n\ntype FeatureOrganizationCandidate = {\n id: string\n ancestorIds?: readonly string[] | null\n}\n\ntype FeatureOrganizationAccess = {\n unrestricted: boolean\n filterOrganizationIds: (organizations: readonly FeatureOrganizationCandidate[]) => string[]\n}\n\ntype FeatureOrganizationRoleGrant = {\n isSuperAdmin: boolean\n featuresJson: string[] | null\n organizationsJson: string[] | null\n}\n\ntype FeatureOrganizationGrants =\n | { kind: 'none' }\n | { kind: 'api_key'; organizationId: string | null; roleGrants: FeatureOrganizationRoleGrant[] }\n | { kind: 'user_acl'; isSuperAdmin: boolean; features: string[]; organizations: string[] | null }\n | { kind: 'roles'; roleGrants: FeatureOrganizationRoleGrant[] }\n\nfunction isStringListOrNull(value: unknown): value is string[] | null {\n return value === null || (Array.isArray(value) && value.every((entry) => typeof entry === 'string'))\n}\n\nfunction isFeatureOrganizationRoleGrant(value: unknown): value is FeatureOrganizationRoleGrant {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Partial<FeatureOrganizationRoleGrant>\n return typeof record.isSuperAdmin === 'boolean'\n && isStringListOrNull(record.featuresJson)\n && isStringListOrNull(record.organizationsJson)\n}\n\nfunction isFeatureOrganizationGrants(value: unknown): value is FeatureOrganizationGrants {\n if (typeof value !== 'object' || value === null) return false\n const record = value as Record<string, unknown>\n switch (record.kind) {\n case 'none':\n return true\n case 'api_key':\n return (record.organizationId === null || typeof record.organizationId === 'string')\n && Array.isArray(record.roleGrants)\n && record.roleGrants.every(isFeatureOrganizationRoleGrant)\n case 'user_acl':\n return typeof record.isSuperAdmin === 'boolean'\n && Array.isArray(record.features)\n && record.features.every((feature) => typeof feature === 'string')\n && isStringListOrNull(record.organizations)\n case 'roles':\n return Array.isArray(record.roleGrants) && record.roleGrants.every(isFeatureOrganizationRoleGrant)\n default:\n return false\n }\n}\n\nfunction toFeatureOrganizationRoleGrant(\n acl: Pick<RoleAcl, 'isSuperAdmin' | 'featuresJson' | 'organizationsJson'>,\n): FeatureOrganizationRoleGrant {\n return {\n isSuperAdmin: acl.isSuperAdmin === true,\n featuresJson: Array.isArray(acl.featuresJson) ? [...acl.featuresJson] : null,\n organizationsJson: Array.isArray(acl.organizationsJson) ? [...acl.organizationsJson] : null,\n }\n}\n\nfunction normalizeFeatureOrganizationCandidates(\n organizations: readonly FeatureOrganizationCandidate[],\n): FeatureOrganizationCandidate[] {\n const normalized = new Map<string, FeatureOrganizationCandidate>()\n for (const organization of organizations) {\n const id = typeof organization.id === 'string' ? organization.id.trim() : ''\n if (!id || normalized.has(id)) continue\n const ancestorIds = Array.isArray(organization.ancestorIds)\n ? Array.from(new Set(organization.ancestorIds\n .map((ancestorId) => typeof ancestorId === 'string' ? ancestorId.trim() : '')\n .filter(Boolean)))\n : []\n normalized.set(id, { id, ancestorIds })\n }\n return Array.from(normalized.values())\n}\n\nfunction buildFeatureOrganizationScope(\n organization: FeatureOrganizationCandidate,\n): ReadonlySet<string> {\n return new Set([organization.id, ...(organization.ancestorIds ?? [])])\n}\n\nfunction roleAclProvidesGlobalFeatureScope(acl: Pick<RoleAcl, 'organizationsJson'>): boolean {\n const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null\n return !organizations || organizations.length === 0 || organizations.includes('__all__')\n}\n\nfunction roleAclProvidesGlobalVisibility(\n acl: Pick<RoleAcl, 'organizationsJson'>,\n emptyOrganizationsAreUnrestricted: boolean,\n): boolean {\n const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null\n if (!organizations || organizations.includes('__all__')) return true\n return emptyOrganizationsAreUnrestricted && organizations.length === 0\n}\n\nfunction roleAclProvidesOrganizationVisibility(\n acl: Pick<RoleAcl, 'organizationsJson'>,\n organizationScope: ReadonlySet<string>,\n emptyOrganizationsAreUnrestricted: boolean,\n): boolean {\n const organizations = Array.isArray(acl.organizationsJson) ? acl.organizationsJson : null\n if (!organizations || organizations.includes('__all__')) return true\n if (organizations.length === 0) return emptyOrganizationsAreUnrestricted\n return organizations.some((organizationId) => organizationScope.has(organizationId))\n}\n\nfunction roleAclsAuthorizeFeatures(\n roleAcls: readonly FeatureOrganizationRoleGrant[],\n required: readonly string[],\n organization: FeatureOrganizationCandidate,\n emptyOrganizationsAreUnrestricted: boolean,\n): boolean {\n const organizationScope = buildFeatureOrganizationScope(organization)\n const grantedFeatures = new Set<string>()\n let unrestricted = false\n let scopeAllowed = false\n\n for (const acl of roleAcls) {\n if (roleAclProvidesOrganizationVisibility(acl, organizationScope, emptyOrganizationsAreUnrestricted)) {\n scopeAllowed = true\n }\n if (!roleAclAllowsOrganization(acl, organizationScope)) continue\n unrestricted = unrestricted || acl.isSuperAdmin === true\n for (const feature of Array.isArray(acl.featuresJson) ? acl.featuresJson : []) {\n grantedFeatures.add(feature)\n }\n }\n\n return authorizeFeatures([...required], {\n grantedFeatures: Array.from(grantedFeatures),\n unrestricted,\n scopeAllowed: scopeAllowed || unrestricted,\n })\n}\n\nfunction roleAclsAuthorizeFeaturesGlobally(\n roleAcls: readonly FeatureOrganizationRoleGrant[],\n required: readonly string[],\n emptyOrganizationsAreUnrestricted: boolean,\n): boolean {\n const grantedFeatures = new Set<string>()\n let unrestricted = false\n let scopeAllowed = false\n\n for (const acl of roleAcls) {\n if (roleAclProvidesGlobalVisibility(acl, emptyOrganizationsAreUnrestricted)) {\n scopeAllowed = true\n }\n if (!roleAclProvidesGlobalFeatureScope(acl)) continue\n unrestricted = unrestricted || acl.isSuperAdmin === true\n for (const feature of Array.isArray(acl.featuresJson) ? acl.featuresJson : []) {\n grantedFeatures.add(feature)\n }\n }\n\n return authorizeFeatures([...required], {\n grantedFeatures: Array.from(grantedFeatures),\n unrestricted,\n scopeAllowed: scopeAllowed || unrestricted,\n })\n}\n\nexport class RbacService {\n private cacheTtlMs: number = 5 * 60 * 1000 // 5 minutes default\n private cache: CacheStrategy | null = null\n private globalSuperAdminCache = new Map<string, boolean>()\n\n constructor(\n private em: EntityManager,\n cache?: CacheStrategy,\n private readonly organizationHierarchyService?: OrganizationHierarchyService,\n ) {\n this.cache = cache || null\n }\n\n /**\n * Set cache TTL in milliseconds\n * @param ttlMs - Time to live in milliseconds\n */\n setCacheTtl(ttlMs: number) {\n this.cacheTtlMs = ttlMs\n }\n\n /** Compatibility wrapper for callers that already have both feature lists. */\n public hasAllFeatures(required: string[], granted: string[]): boolean {\n return authorizeFeatures(required, { grantedFeatures: granted })\n }\n\n private getCacheKey(userId: string, scope: { tenantId: string | null; organizationId: string | null }): string {\n return `rbac:${userId}:${scope.tenantId || 'null'}:${scope.organizationId || 'null'}`\n }\n\n private getUserTag(userId: string): string {\n return `rbac:user:${userId}`\n }\n\n private getTenantTag(tenantId: string): string {\n return `rbac:tenant:${tenantId}`\n }\n\n private getOrganizationTag(organizationId: string): string {\n return `rbac:org:${organizationId}`\n }\n\n private async getFromCache(cacheKey: string): Promise<AclData | null> {\n if (!this.cache) return null\n const cached = await this.cache.get(cacheKey)\n if (!cached) return null\n return isAclData(cached) ? cached : null\n }\n\n private async setCache(cacheKey: string, data: AclData, userId: string, scope: { tenantId: string | null; organizationId: string | null }): Promise<void> {\n if (!this.cache) return\n\n await this.cache.set(cacheKey, data, {\n ttl: this.cacheTtlMs,\n tags: this.buildCacheTags(userId, scope),\n })\n }\n\n private buildCacheTags(userId: string, scope: { tenantId: string | null; organizationId: string | null }): string[] {\n const tags = [\n this.getUserTag(userId),\n 'rbac:all'\n ]\n\n if (scope.tenantId) {\n tags.push(this.getTenantTag(scope.tenantId))\n // Scoped role projections depend on the selected organization's ancestor\n // chain, so Directory hierarchy changes must evict them as well as the\n // separately cached OrganizationScope entries.\n tags.push(buildOrgScopeTenantCacheTag(scope.tenantId))\n }\n\n if (scope.organizationId) {\n tags.push(this.getOrganizationTag(scope.organizationId))\n }\n\n return tags\n }\n\n /**\n * Invalidates cached ACL data for a specific user across all tenants and organizations.\n * Call this when a user's roles or user-specific ACL is modified.\n * \n * @param userId - The ID of the user whose cache should be invalidated\n */\n async invalidateUserCache(userId: string): Promise<void> {\n this.globalSuperAdminCache.delete(userId)\n // Also drop the directory OrganizationScope cache for this user. That scope's\n // accessible-org set is derived from this user's ACL/role grants, so any\n // permission change that invalidates the RBAC cache must invalidate the\n // resolved scope too. This is the missing `org-scope:user:*` caller required\n // before the cross-request scope TTL can be safely enabled (issue #2259).\n await this.deleteCacheByTags([this.getUserTag(userId), buildOrgScopeUserCacheTag(userId)])\n }\n\n /**\n * Invalidates cached ACL data for all users within a specific tenant.\n * Call this when a role's ACL is modified, since roles are tenant-scoped\n * and affect all users in that tenant who have that role.\n * \n * @param tenantId - The ID of the tenant whose cache should be invalidated\n */\n async invalidateTenantCache(tenantId: string): Promise<void> {\n this.globalSuperAdminCache.clear()\n // Role ACL changes invalidate every user in the tenant; the resolved\n // OrganizationScope for those users derives from the same grants, so drop\n // the tenant-tagged scope entries alongside the RBAC ones (issue #2259).\n await this.deleteCacheByTags([this.getTenantTag(tenantId), buildOrgScopeTenantCacheTag(tenantId)], [tenantId])\n }\n\n /**\n * Invalidates cached ACL data for all users within a specific organization.\n * Call this when organization-level permissions or visibility changes.\n * \n * @param organizationId - The ID of the organization whose cache should be invalidated\n */\n async invalidateOrganizationCache(organizationId: string): Promise<void> {\n await this.deleteCacheByTags([this.getOrganizationTag(organizationId)])\n }\n\n /**\n * Clears all cached ACL data.\n * Use this for bulk operations or system-wide ACL changes.\n */\n async invalidateAllCache(): Promise<void> {\n this.globalSuperAdminCache.clear()\n await this.deleteCacheByTags(['rbac:all'])\n }\n\n private async deleteCacheByTags(tags: string[], tenantHints?: Array<string | null>): Promise<void> {\n if (!this.cache) return\n const contexts = new Set<string | null>()\n const current = getCurrentCacheTenant()\n contexts.add(current ?? null)\n contexts.add(null)\n if (Array.isArray(tenantHints)) {\n for (const hint of tenantHints) {\n contexts.add(hint ?? null)\n }\n }\n for (const ctx of contexts) {\n if (ctx === current) {\n await this.cache.deleteByTags(tags)\n } else {\n await runWithCacheTenant(ctx, async () => {\n await this.cache!.deleteByTags(tags)\n })\n }\n }\n }\n\n private async isGlobalSuperAdmin(userId: string): Promise<boolean> {\n if (this.globalSuperAdminCache.has(userId)) return this.globalSuperAdminCache.get(userId)!\n const em = this.em.fork()\n const userSuper = await em.findOne(UserAcl, { user: userId as any, isSuperAdmin: true })\n if (userSuper && (userSuper as any).isSuperAdmin) {\n this.globalSuperAdminCache.set(userId, true)\n return true\n }\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as any },\n { populate: ['role'] },\n { tenantId: null, organizationId: null },\n )\n const linkList = Array.isArray(links) ? links : []\n if (!linkList.length) {\n this.globalSuperAdminCache.set(userId, false)\n return false\n }\n const roleIds = Array.from(new Set(linkList.map((link) => {\n const role = link.role as any\n return role?.id ? String(role.id) : null\n }).filter((id): id is string => typeof id === 'string' && id.length > 0)))\n if (!roleIds.length) {\n this.globalSuperAdminCache.set(userId, false)\n return false\n }\n const roleSupers = await em.find(RoleAcl, { isSuperAdmin: true, role: { $in: roleIds as any } } as any)\n const result = roleSupers.some((roleAcl) => (\n !!roleAcl.isSuperAdmin && !isRestrictedRoleAcl(roleAcl)\n ))\n this.globalSuperAdminCache.set(userId, result)\n return result\n }\n\n /**\n * Loads the Access Control List (ACL) for a user within a given scope.\n * \n * The ACL resolution follows this priority:\n * 1. Per-user ACL (UserAcl) - if exists, use it exclusively\n * 2. Aggregated role ACLs (RoleAcl) - combine permissions from all user's roles\n * \n * Results are cached for performance (default 5 minutes TTL).\n * Cache is automatically invalidated when ACL-related data changes.\n * \n * @param userId - The ID of the user\n * @param scope - The tenant and organization context for ACL evaluation\n * @returns An object containing:\n * - isSuperAdmin: If true, user has unrestricted access to all features\n * - features: Array of feature strings (may include wildcards like 'entities.*')\n * - organizations: Array of organization IDs user can access, or null for all organizations\n * \n * @example\n * const acl = await rbacService.loadAcl('user-123', { tenantId: 'tenant-1', organizationId: 'org-1' })\n * // Returns: { isSuperAdmin: false, features: ['users.view', 'entities.*'], organizations: ['org-1', 'org-2'] }\n */\n async loadAcl(userId: string, scope: { tenantId: string | null; organizationId: string | null }): Promise<{\n isSuperAdmin: boolean\n features: string[]\n organizations: string[] | null\n }> {\n const cacheKey = this.getCacheKey(userId, scope)\n const cached = userId.startsWith('api_key:') ? null : await this.getFromCache(cacheKey)\n if (cached) return cached\n\n // Direct user-level super-admin grants and unrestricted role-level\n // super-admin grants are global. Organization-restricted role grants are\n // deliberately excluded by isGlobalSuperAdmin and continue through the\n // scoped ACL projection below.\n if (!userId.startsWith('api_key:')) {\n if (await this.isGlobalSuperAdmin(userId)) {\n const result = { isSuperAdmin: true, features: ['*'], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n }\n\n if (userId.startsWith('api_key:')) {\n const apiKeyId = userId.slice('api_key:'.length)\n const em = this.em.fork()\n const key = await em.findOne(ApiKey, { id: apiKeyId, deletedAt: null })\n if (!key || (key.expiresAt && key.expiresAt.getTime() < Date.now())) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n const cacheable = !isSessionBoundApiKey(key)\n if (cacheable) {\n const cachedKeyAcl = await this.getFromCache(cacheKey)\n if (cachedKeyAcl) return cachedKeyAcl\n }\n const tenantId = scope.tenantId || key.tenantId || null\n const roleIds = await resolveApiKeyRoleIds(em, key, tenantId)\n const keyOrganizationId = typeof key.organizationId === 'string' && key.organizationId.trim().length > 0\n ? key.organizationId.trim()\n : null\n const evaluatedOrganizationId = scope.organizationId || keyOrganizationId\n let isSuper = false\n const features: string[] = []\n let roleOrganizations: string[] | null = []\n let hasApplicableRestrictedRole = false\n if (tenantId && roleIds.length) {\n const roleOrganizationScope = await resolveRoleOrganizationScope(\n this.organizationHierarchyService,\n tenantId,\n evaluatedOrganizationId,\n )\n const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds as any } } as any)\n for (const acl of racls) {\n if (roleAclAllowsOrganization(acl, roleOrganizationScope)) {\n isSuper = isSuper || !!acl.isSuperAdmin\n if (Array.isArray(acl.featuresJson)) {\n for (const f of acl.featuresJson) if (!features.includes(f)) features.push(f)\n }\n if (isRestrictedRoleAcl(acl)) hasApplicableRestrictedRole = true\n }\n if (roleOrganizations !== null) {\n if (acl.organizationsJson == null || (Array.isArray(acl.organizationsJson) && acl.organizationsJson.length === 0)) {\n roleOrganizations = null\n } else if (Array.isArray(acl.organizationsJson) && acl.organizationsJson.includes('__all__')) {\n roleOrganizations = null\n } else {\n roleOrganizations = Array.from(new Set([\n ...roleOrganizations,\n ...(Array.isArray(acl.organizationsJson) ? acl.organizationsJson : []),\n ]))\n }\n }\n }\n if (\n roleOrganizations !== null\n && evaluatedOrganizationId\n && roleOrganizationScope !== null\n && roleOrganizationScope.size > 0\n && hasApplicableRestrictedRole\n && !roleOrganizations.includes(evaluatedOrganizationId)\n ) {\n roleOrganizations.push(evaluatedOrganizationId)\n }\n }\n let organizations = roleOrganizations\n if (keyOrganizationId) {\n const keyOrganizationScope = await resolveRoleOrganizationScope(\n this.organizationHierarchyService,\n tenantId,\n keyOrganizationId,\n )\n organizations = roleOrganizations === null\n || roleOrganizations.some((organizationId) => keyOrganizationScope?.has(organizationId))\n ? [keyOrganizationId]\n : []\n }\n // A role-level super-admin grant still respects the API key's effective\n // organization allowlist. Represent it as a wildcard feature whenever\n // the key is restricted so downstream super-admin shortcuts cannot\n // bypass the key or role organization bounds.\n if (isSuper && organizations !== null && !features.includes('*')) features.push('*')\n const result = { isSuperAdmin: isSuper && organizations === null, features, organizations }\n if (cacheable) await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Use a forked EntityManager to avoid inheriting an aborted transaction from callers\n const em = this.em.fork()\n const user = await em.findOne(User, { id: userId })\n if (!user) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n const tenantId = scope.tenantId || user.tenantId || null\n const orgId = scope.organizationId || user.organizationId || null\n\n if (!tenantId) {\n const result = { isSuperAdmin: false, features: [], organizations: null }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Per-user ACL first\n const uacl = await em.findOne(UserAcl, { user: userId as any, tenantId })\n if (uacl) {\n const result = {\n isSuperAdmin: !!uacl.isSuperAdmin,\n features: Array.isArray(uacl.featuresJson) ? (uacl.featuresJson as string[]) : [],\n organizations: Array.isArray(uacl.organizationsJson) ? (uacl.organizationsJson as string[]) : null,\n }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n // Aggregate role ACLs\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as any, role: { tenantId } } as any,\n { populate: ['role'] },\n { tenantId, organizationId: orgId },\n )\n const linkList = Array.isArray(links) ? links : []\n const roleIds = linkList.map((l) => (l.role as any)?.id).filter(Boolean)\n let isSuper = false\n const features: string[] = []\n let organizations: string[] | null = []\n let hasApplicableRestrictedRole = false\n if (roleIds.length) {\n const roleOrganizationScope = await resolveRoleOrganizationScope(\n this.organizationHierarchyService,\n tenantId,\n scope.organizationId,\n )\n const racls = await em.find(RoleAcl, { tenantId, role: { $in: roleIds as any } } as any, {})\n const roleAcls = Array.isArray(racls) ? racls : []\n for (const r of roleAcls) {\n if (roleAclAllowsOrganization(r, roleOrganizationScope)) {\n isSuper = isSuper || !!r.isSuperAdmin\n if (Array.isArray(r.featuresJson)) for (const f of r.featuresJson) if (!features.includes(f)) features.push(f)\n if (isRestrictedRoleAcl(r)) hasApplicableRestrictedRole = true\n }\n if (organizations !== null) {\n // For a user principal an empty allowlist is a deny-all scope (#4033), not\n // \"unrestricted\": it must merge to an empty set so scoped reads and deletes\n // fail closed. Only an absent allowlist or an explicit '__all__' widens to\n // every organization. (The API-key branch above deliberately differs \u2014 an\n // empty role list there means the key inherits the key's own scope.)\n if (r.organizationsJson == null) organizations = null\n else if (Array.isArray(r.organizationsJson) && r.organizationsJson.includes('__all__')) organizations = null\n else organizations = Array.from(new Set([...(organizations || []), ...r.organizationsJson]))\n }\n }\n if (\n organizations !== null\n && scope.organizationId\n && roleOrganizationScope !== null\n && roleOrganizationScope.size > 0\n && hasApplicableRestrictedRole\n && !organizations.includes(scope.organizationId)\n ) {\n organizations.push(scope.organizationId)\n }\n }\n if (organizations && orgId && !organizations.includes(orgId) && !organizations.includes('__all__')) {\n // Out-of-scope org; caller will enforce\n }\n const result = { isSuperAdmin: isSuper, features, organizations }\n await this.setCache(cacheKey, result, userId, scope)\n return result\n }\n\n /**\n * Cache-bypassing ACL resolution bound to a caller-supplied EntityManager.\n * Replay authorization uses this additive seam after taking its canonical\n * locks so every user, membership, role, ACL, API-key, and organization-scope\n * read observes the exact transaction that performs the mutation.\n */\n async loadAclWithEntityManager(\n em: EntityManager,\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<AclData> {\n if (userId.startsWith('api_key:')) {\n const key = await em.findOne(ApiKey, {\n id: userId.slice('api_key:'.length),\n deletedAt: null,\n })\n if (!key || (key.expiresAt && key.expiresAt.getTime() < Date.now())) {\n return { isSuperAdmin: false, features: [], organizations: null }\n }\n const tenantId = scope.tenantId || key.tenantId || null\n const roleIds = await resolveApiKeyRoleIds(em, key, tenantId)\n const keyOrganizationId = typeof key.organizationId === 'string' && key.organizationId.trim().length > 0\n ? key.organizationId.trim()\n : null\n const evaluatedOrganizationId = scope.organizationId || keyOrganizationId\n const roleScope = await resolveRoleOrganizationScopeWithEntityManager(\n em,\n tenantId,\n evaluatedOrganizationId,\n )\n const roleAcls = tenantId && roleIds.length\n ? await em.find(RoleAcl, { tenantId, role: { $in: roleIds as never } } as never)\n : []\n let isSuperAdmin = false\n const features: string[] = []\n let organizations: string[] | null = []\n let hasApplicableRestrictedRole = false\n for (const acl of roleAcls) {\n if (roleAclAllowsOrganization(acl, roleScope)) {\n isSuperAdmin = isSuperAdmin || acl.isSuperAdmin === true\n for (const feature of Array.isArray(acl.featuresJson) ? acl.featuresJson : []) {\n if (!features.includes(feature)) features.push(feature)\n }\n if (isRestrictedRoleAcl(acl)) hasApplicableRestrictedRole = true\n }\n if (organizations !== null) {\n if (\n acl.organizationsJson == null\n || acl.organizationsJson.length === 0\n || acl.organizationsJson.includes('__all__')\n ) {\n organizations = null\n } else {\n organizations = Array.from(new Set([...organizations, ...acl.organizationsJson]))\n }\n }\n }\n if (\n organizations !== null\n && evaluatedOrganizationId\n && roleScope !== null\n && roleScope.size > 0\n && hasApplicableRestrictedRole\n && !organizations.includes(evaluatedOrganizationId)\n ) {\n organizations.push(evaluatedOrganizationId)\n }\n if (keyOrganizationId) {\n const keyScope = await resolveRoleOrganizationScopeWithEntityManager(em, tenantId, keyOrganizationId)\n organizations = organizations === null\n || organizations.some((organizationId) => keyScope?.has(organizationId))\n ? [keyOrganizationId]\n : []\n }\n if (isSuperAdmin && organizations !== null && !features.includes('*')) features.push('*')\n return { isSuperAdmin: isSuperAdmin && organizations === null, features, organizations }\n }\n\n const directGlobalGrant = await em.findOne(\n UserAcl,\n { user: userId as never, isSuperAdmin: true } as never,\n )\n if (directGlobalGrant?.isSuperAdmin) {\n return { isSuperAdmin: true, features: ['*'], organizations: null }\n }\n const globalLinks = await findWithDecryption(\n em,\n UserRole,\n { user: userId as never },\n { populate: ['role'] },\n { tenantId: null, organizationId: null },\n )\n const globalRoleIds = globalLinks\n .map((link) => typeof link.role === 'string' ? link.role : link.role?.id ? String(link.role.id) : null)\n .filter((roleId): roleId is string => typeof roleId === 'string' && roleId.length > 0)\n if (globalRoleIds.length) {\n const globalRoleGrants = await em.find(\n RoleAcl,\n {\n role: { $in: globalRoleIds as never },\n isSuperAdmin: true,\n } as never,\n )\n if (globalRoleGrants.some((grant) => grant.isSuperAdmin && !isRestrictedRoleAcl(grant))) {\n return { isSuperAdmin: true, features: ['*'], organizations: null }\n }\n }\n\n const user = await em.findOne(User, { id: userId })\n if (!user) return { isSuperAdmin: false, features: [], organizations: null }\n const tenantId = scope.tenantId || user.tenantId || null\n const organizationId = scope.organizationId || user.organizationId || null\n if (!tenantId) return { isSuperAdmin: false, features: [], organizations: null }\n\n const userAcl = await em.findOne(UserAcl, { user: userId as never, tenantId } as never)\n if (userAcl) {\n return {\n isSuperAdmin: userAcl.isSuperAdmin === true,\n features: Array.isArray(userAcl.featuresJson) ? [...userAcl.featuresJson] : [],\n organizations: Array.isArray(userAcl.organizationsJson) ? [...userAcl.organizationsJson] : null,\n }\n }\n\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId as never, role: { tenantId } } as never,\n { populate: ['role'] },\n { tenantId, organizationId },\n )\n const roleIds = links\n .map((link) => typeof link.role === 'string' ? link.role : link.role?.id ? String(link.role.id) : null)\n .filter((roleId): roleId is string => typeof roleId === 'string' && roleId.length > 0)\n const roleAcls = roleIds.length\n ? await em.find(RoleAcl, { tenantId, role: { $in: roleIds as never } } as never)\n : []\n const roleScope = await resolveRoleOrganizationScopeWithEntityManager(\n em,\n tenantId,\n scope.organizationId,\n )\n let isSuperAdmin = false\n const features: string[] = []\n let organizations: string[] | null = []\n let hasApplicableRestrictedRole = false\n for (const acl of roleAcls) {\n if (roleAclAllowsOrganization(acl, roleScope)) {\n isSuperAdmin = isSuperAdmin || acl.isSuperAdmin === true\n for (const feature of Array.isArray(acl.featuresJson) ? acl.featuresJson : []) {\n if (!features.includes(feature)) features.push(feature)\n }\n if (isRestrictedRoleAcl(acl)) hasApplicableRestrictedRole = true\n }\n if (organizations !== null) {\n if (acl.organizationsJson == null || acl.organizationsJson.includes('__all__')) {\n organizations = null\n } else {\n organizations = Array.from(new Set([...organizations, ...acl.organizationsJson]))\n }\n }\n }\n if (\n organizations !== null\n && scope.organizationId\n && roleScope\n && roleScope.size > 0\n && hasApplicableRestrictedRole\n && !organizations.includes(scope.organizationId)\n ) {\n organizations.push(scope.organizationId)\n }\n return { isSuperAdmin, features, organizations }\n }\n\n async userHasAllFeaturesWithEntityManager(\n em: EntityManager,\n userId: string,\n required: string[],\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<boolean> {\n if (!required.length) return true\n const acl = await this.loadAclWithEntityManager(em, userId, scope)\n const organizationAllowed = acl.isSuperAdmin\n || !acl.organizations\n || !scope.organizationId\n || acl.organizations.includes(scope.organizationId)\n || acl.organizations.includes('__all__')\n return authorizeFeatures(required, {\n grantedFeatures: acl.features,\n unrestricted: acl.isSuperAdmin,\n scopeAllowed: organizationAllowed,\n })\n }\n\n async getGrantedFeaturesWithEntityManager(\n em: EntityManager,\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<string[]> {\n const acl = await this.loadAclWithEntityManager(em, userId, scope)\n if (acl.isSuperAdmin) return filterGrantsByEnabledModules(['*'])\n if (\n acl.organizations\n && scope.organizationId\n && !acl.organizations.includes(scope.organizationId)\n && !acl.organizations.includes('__all__')\n ) {\n return []\n }\n return filterGrantsByEnabledModules(acl.features)\n }\n\n /**\n * Checks whether any tenant role grants a feature.\n *\n * This supports non-user runtimes such as scheduler workers that execute with\n * tenant scope but without an authenticated user.\n */\n async tenantHasFeature(\n tenantId: string | null | undefined,\n feature: string,\n opts?: { organizationId?: string | null },\n ): Promise<boolean> {\n if (!tenantId || !feature) return false\n\n const em = this.em.fork()\n const roleOrganizationScope = await resolveRoleOrganizationScope(\n this.organizationHierarchyService,\n tenantId,\n opts?.organizationId,\n )\n const roleAcls = await em.find(RoleAcl, { tenantId, deletedAt: null } as any, {})\n const list = Array.isArray(roleAcls) ? roleAcls : []\n\n for (const acl of list) {\n if (!roleAclAllowsOrganization(acl, roleOrganizationScope)) continue\n const grants = Array.isArray(acl.featuresJson) ? acl.featuresJson : []\n if (authorizeFeatures([feature], {\n grantedFeatures: grants,\n unrestricted: acl.isSuperAdmin,\n })) {\n return true\n }\n }\n\n return false\n }\n\n /**\n * Checks if a user has all required features within a given scope.\n *\n * This is the primary authorization check method used throughout the application.\n * It combines feature checking with organization visibility validation.\n *\n * Authorization logic:\n * 1. No features required \u2192 always returns true\n * 2. User is super admin \u2192 always returns true\n * 3. Organization restriction check: If the user's ACL has a restricted organization list\n * and the requested organization is not in that list \u2192 returns false\n * 4. Feature matching: User must have all required features (supports wildcards)\n *\n * @param userId - The ID of the user\n * @param required - Array of feature strings to check (e.g., ['users.view', 'users.edit'])\n * @param scope - The tenant and organization context for authorization\n * @returns true if the user has all required features and organization access, false otherwise\n *\n * @example\n * // Check if user can view and edit users\n * const canManageUsers = await rbacService.userHasAllFeatures(\n * 'user-123',\n * ['users.view', 'users.edit'],\n * { tenantId: 'tenant-1', organizationId: 'org-1' }\n * )\n *\n * @example\n * // Check with wildcard features\n * const canAccessEntities = await rbacService.userHasAllFeatures(\n * 'user-123',\n * ['entities.records.view'],\n * { tenantId: 'tenant-1', organizationId: 'org-1' }\n * )\n * // Returns true if user has 'entities.*', '*', or 'entities.records.view'\n */\n async userHasAllFeatures(userId: string, required: string[], scope: { tenantId: string | null; organizationId: string | null }): Promise<boolean> {\n if (!required.length) return true\n const acl = await this.loadAcl(userId, scope)\n const organizationAllowed = acl.isSuperAdmin\n || !acl.organizations\n || !scope.organizationId\n || acl.organizations.includes(scope.organizationId)\n || acl.organizations.includes('__all__')\n return authorizeFeatures(required, {\n grantedFeatures: acl.features,\n unrestricted: acl.isSuperAdmin,\n scopeAllowed: organizationAllowed,\n })\n }\n\n async resolveFeatureOrganizationAccess(\n userId: string,\n required: readonly string[],\n input: { tenantId: string | null },\n ): Promise<FeatureOrganizationAccess> {\n const allowAll = (organizations: readonly FeatureOrganizationCandidate[]) =>\n normalizeFeatureOrganizationCandidates(organizations).map((organization) => organization.id)\n const denyAll = () => []\n if (!required.length) return { unrestricted: true, filterOrganizationIds: allowAll }\n if (!input.tenantId) return { unrestricted: false, filterOrganizationIds: denyAll }\n if (\n !userId.startsWith('api_key:')\n && await this.isGlobalSuperAdmin(userId)\n && authorizeFeatures(required, { grantedFeatures: ['*'], unrestricted: true })\n ) {\n return { unrestricted: true, filterOrganizationIds: allowAll }\n }\n\n const grants = await this.loadFeatureOrganizationGrants(userId, input.tenantId)\n if (grants.kind === 'none') return { unrestricted: false, filterOrganizationIds: denyAll }\n\n if (grants.kind === 'api_key') {\n const keyOrganizationId = grants.organizationId\n const unrestricted = keyOrganizationId === null\n && roleAclsAuthorizeFeaturesGlobally(grants.roleGrants, required, true)\n if (unrestricted) return { unrestricted: true, filterOrganizationIds: allowAll }\n\n return {\n unrestricted: false,\n filterOrganizationIds: (candidates) => normalizeFeatureOrganizationCandidates(candidates)\n .filter((organization) => (\n (!keyOrganizationId || organization.id === keyOrganizationId)\n && roleAclsAuthorizeFeatures(grants.roleGrants, required, organization, true)\n ))\n .map((organization) => organization.id),\n }\n }\n\n if (grants.kind === 'user_acl') {\n const grantedFeatures = grants.features\n const allowedOrganizations = grants.organizations\n const hasGlobalScope = grants.isSuperAdmin\n || allowedOrganizations === null\n || allowedOrganizations.includes('__all__')\n const unrestricted = authorizeFeatures([...required], {\n grantedFeatures,\n unrestricted: grants.isSuperAdmin,\n scopeAllowed: hasGlobalScope,\n })\n if (unrestricted) return { unrestricted: true, filterOrganizationIds: allowAll }\n\n return {\n unrestricted: false,\n filterOrganizationIds: (candidates) => normalizeFeatureOrganizationCandidates(candidates)\n .filter((organization) => {\n const scopeAllowed = grants.isSuperAdmin\n || allowedOrganizations === null\n || allowedOrganizations.includes('__all__')\n || allowedOrganizations.includes(organization.id)\n return authorizeFeatures([...required], {\n grantedFeatures,\n unrestricted: grants.isSuperAdmin,\n scopeAllowed,\n })\n })\n .map((organization) => organization.id),\n }\n }\n\n if (roleAclsAuthorizeFeaturesGlobally(grants.roleGrants, required, false)) {\n return { unrestricted: true, filterOrganizationIds: allowAll }\n }\n\n return {\n unrestricted: false,\n filterOrganizationIds: (candidates) => normalizeFeatureOrganizationCandidates(candidates)\n .filter((organization) => roleAclsAuthorizeFeatures(grants.roleGrants, required, organization, false))\n .map((organization) => organization.id),\n }\n }\n\n private async loadFeatureOrganizationGrants(\n userId: string,\n tenantId: string,\n ): Promise<FeatureOrganizationGrants> {\n const cacheKey = `rbac:feature-organizations:${userId}:${tenantId}`\n const key = userId.startsWith('api_key:')\n ? await this.em.fork().findOne(ApiKey, { id: userId.slice('api_key:'.length), deletedAt: null })\n : undefined\n const cacheable = key === undefined || (key !== null && !isSessionBoundApiKey(key))\n if (this.cache && cacheable) {\n const cached = await this.cache.get(cacheKey)\n if (isFeatureOrganizationGrants(cached)) return cached\n }\n const grants = await this.queryFeatureOrganizationGrants(userId, tenantId, key)\n if (this.cache && cacheable) {\n await this.cache.set(cacheKey, grants, {\n ttl: this.cacheTtlMs,\n tags: this.buildCacheTags(userId, { tenantId, organizationId: null }),\n })\n }\n return grants\n }\n\n private async queryFeatureOrganizationGrants(\n userId: string,\n tenantId: string,\n knownApiKey?: ApiKey | null,\n ): Promise<FeatureOrganizationGrants> {\n const em = this.em.fork()\n if (userId.startsWith('api_key:')) {\n const apiKeyId = userId.slice('api_key:'.length)\n const key = knownApiKey === undefined\n ? await em.findOne(ApiKey, { id: apiKeyId, deletedAt: null })\n : knownApiKey\n if (\n !key\n || (key.expiresAt && key.expiresAt.getTime() < Date.now())\n || (key.tenantId && key.tenantId !== tenantId)\n ) {\n return { kind: 'none' }\n }\n\n const roleIds = await resolveApiKeyRoleIds(em, key, tenantId)\n if (!roleIds.length) return { kind: 'none' }\n const roleAcls = await em.find(RoleAcl, {\n tenantId,\n role: { $in: roleIds },\n })\n const keyOrganizationId = typeof key.organizationId === 'string' && key.organizationId.trim().length > 0\n ? key.organizationId.trim()\n : null\n return {\n kind: 'api_key',\n organizationId: keyOrganizationId,\n roleGrants: roleAcls.map(toFeatureOrganizationRoleGrant),\n }\n }\n\n const user = await em.findOne(User, { id: userId })\n if (!user) return { kind: 'none' }\n\n const userAcl = await em.findOne(UserAcl, { user: userId, tenantId })\n if (userAcl) {\n return {\n kind: 'user_acl',\n isSuperAdmin: userAcl.isSuperAdmin === true,\n features: Array.isArray(userAcl.featuresJson) ? [...userAcl.featuresJson] : [],\n organizations: Array.isArray(userAcl.organizationsJson) ? [...userAcl.organizationsJson] : null,\n }\n }\n\n const links = await findWithDecryption(\n em,\n UserRole,\n { user: userId, role: { tenantId } },\n { populate: ['role'] },\n { tenantId, organizationId: null },\n )\n const roleIds = Array.from(new Set(links\n .map((link) => link.role?.id)\n .filter((roleId): roleId is string => typeof roleId === 'string' && roleId.length > 0)))\n if (!roleIds.length) return { kind: 'none' }\n\n const roleAcls = await em.find(RoleAcl, {\n tenantId,\n role: { $in: roleIds },\n })\n return { kind: 'roles', roleGrants: roleAcls.map(toFeatureOrganizationRoleGrant) }\n }\n\n /**\n * Returns the user's infrastructure grant list, filtered to enabled modules.\n * The result may contain wildcards; authoritative checks must still go through\n * `authorizeFeatures` or `userHasAllFeatures` so null overrides are enforced.\n */\n async getGrantedFeatures(\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<string[]> {\n const acl = await this.loadAcl(userId, scope)\n if (acl.isSuperAdmin) return filterGrantsByEnabledModules(['*'])\n if (\n acl.organizations &&\n scope.organizationId &&\n !acl.organizations.includes(scope.organizationId) &&\n !acl.organizations.includes('__all__')\n ) {\n return []\n }\n return filterGrantsByEnabledModules(acl.features)\n }\n\n /** Returns concrete active feature IDs for browser capability payloads. */\n async getEffectiveFeatures(\n userId: string,\n scope: { tenantId: string | null; organizationId: string | null },\n ): Promise<string[]> {\n const acl = await this.loadAcl(userId, scope)\n const organizationAllowed = acl.isSuperAdmin\n || !acl.organizations\n || !scope.organizationId\n || acl.organizations.includes(scope.organizationId)\n || acl.organizations.includes('__all__')\n if (!organizationAllowed) return []\n return resolveEffectiveFeatures(acl.isSuperAdmin ? ['*'] : acl.features)\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["result", "em", "tenantId", "roleIds", "isSuper", "features", "hasApplicableRestrictedRole", "organizations", "roleScope", "roleAcls", "isSuperAdmin", "organizationId"]
7
7
  }
@@ -6,6 +6,7 @@ import {
6
6
  resolveOpenMercatoApiKeyProfile
7
7
  } from "./openmercato-call-options.js";
8
8
  import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
9
+ import { resolveApiKeyRoleIds } from "@open-mercato/core/modules/api_keys/services/sessionKeyRoles";
9
10
  async function executeActions(actions, context) {
10
11
  const startTime = Date.now();
11
12
  const results = [];
@@ -254,7 +255,7 @@ async function handleCallOpenMercato(action, context) {
254
255
  if (!apiKeyProfile) {
255
256
  throw new Error("CALL_OPEN_MERCATO action requires an active API key profile in scope");
256
257
  }
257
- const roleIds = Array.isArray(apiKeyProfile.rolesJson) ? apiKeyProfile.rolesJson.filter((roleId) => typeof roleId === "string" && roleId.length > 0) : [];
258
+ const roleIds = await resolveApiKeyRoleIds(em, apiKeyProfile, tenantId);
258
259
  if (roleIds.length === 0) {
259
260
  throw new Error("CALL_OPEN_MERCATO action requires an API key profile with at least one role");
260
261
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/business_rules/lib/action-executor.ts"],
4
- "sourcesContent": ["import type { EntityManager as PostgreSqlEntityManager } from '@mikro-orm/postgresql'\nimport type { EvaluationContext } from './expression-evaluator'\nimport { getNestedValue, resolveSpecialValue } from './value-resolver'\nimport {\n canActorUseOpenMercatoApiKeyProfile,\n findOpenMercatoEndpointOption,\n getCurrentOpenMercatoEndpointOptions,\n resolveOpenMercatoApiKeyProfile,\n} from './openmercato-call-options'\nimport type { RbacService } from '../../auth/services/rbacService'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { OpenMercatoEndpointOption } from './openmercato-call-options-types'\n\n/**\n * Action definition\n */\nexport interface Action {\n type: string\n config?: Record<string, any>\n}\n\n/**\n * Action execution context\n */\nexport interface ActionContext extends EvaluationContext {\n entityType?: string\n entityId?: string\n eventType?: string\n data?: any\n ruleId?: string\n ruleName?: string\n tenantId?: string\n organizationId?: string\n executedBy?: string | null\n em?: PostgreSqlEntityManager\n openMercatoEndpointOptions?: OpenMercatoEndpointOption[]\n ruleAuthorId?: string | null\n rbacService?: RbacService\n [key: string]: any\n}\n\n/**\n * Specific action result types\n */\nexport interface AllowTransitionResult {\n type: 'ALLOW_TRANSITION'\n allowed: true\n message: string\n}\n\nexport interface BlockTransitionResult {\n type: 'BLOCK_TRANSITION'\n allowed: false\n message: string\n}\n\nexport interface LogResult {\n type: 'LOG'\n level: string\n message: string\n timestamp: string\n}\n\nexport interface ShowErrorResult {\n type: 'SHOW_ERROR'\n severity: 'error'\n message: string\n}\n\nexport interface ShowWarningResult {\n type: 'SHOW_WARNING'\n severity: 'warning'\n message: string\n}\n\nexport interface ShowInfoResult {\n type: 'SHOW_INFO'\n severity: 'info'\n message: string\n}\n\nexport interface NotifyResult {\n type: 'NOTIFY'\n recipients: string[]\n subject: string\n message: string\n template?: string\n}\n\nexport interface SetFieldResult {\n type: 'SET_FIELD'\n field: string\n value: any\n}\n\nexport interface CallWebhookResult {\n type: 'CALL_WEBHOOK'\n url: string\n method: string\n headers: Record<string, any>\n body?: any\n status: 'pending'\n}\n\nexport interface CallOpenMercatoResult {\n type: 'CALL_OPEN_MERCATO'\n endpoint: string\n method: string\n apiKeyId: string\n status: number\n statusText: string\n body: any\n authenticated: true\n tenantId: string\n organizationId: string\n}\n\nexport interface EmitEventResult {\n type: 'EMIT_EVENT'\n event: string\n payload: Record<string, any>\n}\n\n/**\n * Union type of all action results\n */\nexport type ActionHandlerResult =\n | AllowTransitionResult\n | BlockTransitionResult\n | LogResult\n | ShowErrorResult\n | ShowWarningResult\n | ShowInfoResult\n | NotifyResult\n | SetFieldResult\n | CallWebhookResult\n | CallOpenMercatoResult\n | EmitEventResult\n\n/**\n * Action execution result\n */\nexport interface ActionResult {\n action: Action\n success: boolean\n result?: ActionHandlerResult\n error?: string\n executionTime: number\n}\n\n/**\n * Action execution outcome (aggregated results)\n */\nexport interface ActionExecutionOutcome {\n success: boolean\n results: ActionResult[]\n totalTime: number\n errors?: string[]\n}\n\n/**\n * Execute multiple actions in sequence\n */\nexport async function executeActions(\n actions: Action[],\n context: ActionContext\n): Promise<ActionExecutionOutcome> {\n const startTime = Date.now()\n const results: ActionResult[] = []\n const errors: string[] = []\n\n for (const action of actions) {\n try {\n const result = await executeAction(action, context)\n results.push(result)\n\n if (result.error) {\n errors.push(`Action ${action.type}: ${result.error}`)\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n errors.push(`Action ${action.type}: ${errorMessage}`)\n\n results.push({\n action,\n success: false,\n error: errorMessage,\n executionTime: 0,\n })\n }\n }\n\n const totalTime = Date.now() - startTime\n\n return {\n success: results.every((r) => r.success),\n results,\n totalTime,\n errors: errors.length > 0 ? errors : undefined,\n }\n}\n\n/**\n * Execute a single action\n */\nexport async function executeAction(action: Action, context: ActionContext): Promise<ActionResult> {\n const startTime = Date.now()\n\n try {\n const handler = getActionHandler(action.type)\n const result = await handler(action, context)\n\n const executionTime = Date.now() - startTime\n\n return {\n action,\n success: true,\n result,\n executionTime,\n }\n } catch (error) {\n const executionTime = Date.now() - startTime\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n return {\n action,\n success: false,\n error: errorMessage,\n executionTime,\n }\n }\n}\n\n/**\n * Action handler function type\n */\ntype ActionHandler = (action: Action, context: ActionContext) => Promise<ActionHandlerResult>\n\n/**\n * Get action handler by type\n */\nfunction getActionHandler(actionType: string): ActionHandler {\n const handlers: Record<string, ActionHandler> = {\n ALLOW_TRANSITION: handleAllowTransition,\n BLOCK_TRANSITION: handleBlockTransition,\n LOG: handleLog,\n SHOW_ERROR: handleShowError,\n SHOW_WARNING: handleShowWarning,\n SHOW_INFO: handleShowInfo,\n NOTIFY: handleNotify,\n SET_FIELD: handleSetField,\n CALL_WEBHOOK: handleCallWebhook,\n CALL_OPEN_MERCATO: handleCallOpenMercato,\n EMIT_EVENT: handleEmitEvent,\n }\n\n const handler = handlers[actionType]\n\n if (!handler) {\n throw new Error(`Unknown action type: ${actionType}`)\n }\n\n return handler\n}\n\n/**\n * ALLOW_TRANSITION action handler\n */\nasync function handleAllowTransition(\n action: Action,\n context: ActionContext\n): Promise<AllowTransitionResult> {\n return {\n type: 'ALLOW_TRANSITION',\n allowed: true,\n message: interpolateMessage(action.config?.message || 'Transition allowed', context),\n }\n}\n\n/**\n * BLOCK_TRANSITION action handler\n */\nasync function handleBlockTransition(\n action: Action,\n context: ActionContext\n): Promise<BlockTransitionResult> {\n return {\n type: 'BLOCK_TRANSITION',\n allowed: false,\n message: interpolateMessage(action.config?.message || 'Transition blocked', context),\n }\n}\n\n/**\n * LOG action handler\n */\nasync function handleLog(action: Action, context: ActionContext): Promise<LogResult> {\n const level = action.config?.level || 'info'\n const message = interpolateMessage(action.config?.message || '', context)\n\n return {\n type: 'LOG',\n level,\n message,\n timestamp: new Date().toISOString(),\n }\n}\n\n/**\n * SHOW_ERROR action handler\n */\nasync function handleShowError(action: Action, context: ActionContext): Promise<ShowErrorResult> {\n const message = interpolateMessage(action.config?.message || '', context)\n\n return {\n type: 'SHOW_ERROR',\n severity: 'error',\n message,\n }\n}\n\n/**\n * SHOW_WARNING action handler\n */\nasync function handleShowWarning(\n action: Action,\n context: ActionContext\n): Promise<ShowWarningResult> {\n const message = interpolateMessage(action.config?.message || '', context)\n\n return {\n type: 'SHOW_WARNING',\n severity: 'warning',\n message,\n }\n}\n\n/**\n * SHOW_INFO action handler\n */\nasync function handleShowInfo(action: Action, context: ActionContext): Promise<ShowInfoResult> {\n const message = interpolateMessage(action.config?.message || '', context)\n\n return {\n type: 'SHOW_INFO',\n severity: 'info',\n message,\n }\n}\n\n/**\n * NOTIFY action handler\n */\nasync function handleNotify(action: Action, context: ActionContext): Promise<NotifyResult> {\n const recipients = action.config?.recipients || []\n const message = interpolateMessage(action.config?.message || '', context)\n const subject = interpolateMessage(action.config?.subject || '', context)\n const template = action.config?.template\n\n if (!Array.isArray(recipients)) {\n throw new Error('NOTIFY action requires recipients to be an array')\n }\n\n if (recipients.length === 0) {\n throw new Error('NOTIFY action requires at least one recipient')\n }\n\n return {\n type: 'NOTIFY',\n recipients,\n subject,\n message,\n template,\n }\n}\n\n/**\n * SET_FIELD action handler\n */\nasync function handleSetField(action: Action, context: ActionContext): Promise<SetFieldResult> {\n const field = action.config?.field\n const value = resolveValue(action.config?.value, context)\n\n if (!field) {\n throw new Error('SET_FIELD action requires a field name')\n }\n\n if (typeof field !== 'string' || field.trim() === '') {\n throw new Error('SET_FIELD action requires a non-empty field name')\n }\n\n return {\n type: 'SET_FIELD',\n field,\n value,\n }\n}\n\n/**\n * CALL_WEBHOOK action handler\n */\nasync function handleCallWebhook(\n action: Action,\n context: ActionContext\n): Promise<CallWebhookResult> {\n const url = interpolateMessage(action.config?.url || '', context)\n const method = action.config?.method || 'POST'\n const headers = action.config?.headers || {}\n const body = action.config?.body\n\n if (!url || url.trim() === '') {\n throw new Error('CALL_WEBHOOK action requires a non-empty URL')\n }\n\n const validMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']\n if (!validMethods.includes(method.toUpperCase())) {\n throw new Error(\n `CALL_WEBHOOK action requires a valid HTTP method (${validMethods.join(', ')})`\n )\n }\n\n return {\n type: 'CALL_WEBHOOK',\n url,\n method: method.toUpperCase(),\n headers,\n body,\n status: 'pending',\n }\n}\n\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\nconst API_KEY_ACTOR_PREFIX = 'api_key:'\n\nasync function resolveRbacService(): Promise<RbacService> {\n const { createRequestContainer } = await import('@open-mercato/shared/lib/di/container')\n const container = await createRequestContainer()\n return container.resolve('rbacService') as RbacService\n}\n\nasync function translatedOpenMercatoCallError(key: string, fallback: string): Promise<Error> {\n const { resolveTranslations } = await import('@open-mercato/shared/lib/i18n/server')\n const { t } = await resolveTranslations()\n return new Error(t(key, fallback))\n}\n\nasync function resolveActiveRuleAuthorId(\n em: PostgreSqlEntityManager,\n authorId: string | null | undefined,\n tenantId: string,\n): Promise<string | null> {\n const candidate = typeof authorId === 'string' ? authorId.trim() : ''\n if (!candidate) return null\n if (candidate.startsWith(API_KEY_ACTOR_PREFIX)) {\n const apiKeyId = candidate.slice(API_KEY_ACTOR_PREFIX.length)\n if (!UUID_PATTERN.test(apiKeyId)) return null\n const { ApiKey } = await import('../../api_keys/data/entities')\n const key = await findOneWithDecryption(em, ApiKey, { id: apiKeyId, tenantId, deletedAt: null }, {}, { tenantId, organizationId: null })\n if (!key) return null\n if (key.expiresAt && key.expiresAt.getTime() <= Date.now()) return null\n return candidate\n }\n if (!UUID_PATTERN.test(candidate)) return null\n const { User } = await import('../../auth/data/entities')\n const user = await findOneWithDecryption(em, User, { id: candidate, deletedAt: null }, {}, { tenantId: null, organizationId: null })\n if (!user) return null\n if (user.tenantId && String(user.tenantId) === tenantId) return candidate\n const { isUserEffectivelySuperAdmin } = await import('../../auth/lib/grantChecks')\n return await isUserEffectivelySuperAdmin(em, candidate) ? candidate : null\n}\n\n/**\n * CALL_OPEN_MERCATO action handler\n */\nasync function handleCallOpenMercato(\n action: Action,\n context: ActionContext\n): Promise<CallOpenMercatoResult> {\n const endpoint = String(action.config?.endpoint ?? '').trim()\n const method = String(action.config?.method ?? '').trim().toUpperCase()\n const apiKeyId = String(action.config?.apiKeyId ?? '').trim()\n\n if (!endpoint) {\n throw new Error('CALL_OPEN_MERCATO action requires an endpoint')\n }\n if (!method) {\n throw new Error('CALL_OPEN_MERCATO action requires an HTTP method')\n }\n if (!apiKeyId) {\n throw new Error('CALL_OPEN_MERCATO action requires an API key profile')\n }\n\n const endpointOptions = context.openMercatoEndpointOptions ?? await getCurrentOpenMercatoEndpointOptions()\n const endpointOption = findOpenMercatoEndpointOption(\n endpoint,\n method,\n endpointOptions,\n )\n if (!endpointOption) {\n throw new Error('CALL_OPEN_MERCATO action requires a currently available /api/* endpoint')\n }\n\n const em = context.em\n if (!em) {\n throw new Error('CALL_OPEN_MERCATO action requires an EntityManager in action context')\n }\n\n const tenantId = context.tenantId ?? context.tenant?.id\n const organizationId = context.organizationId ?? context.organization?.id\n if (!tenantId || !organizationId) {\n throw new Error('CALL_OPEN_MERCATO action requires tenant and organization context')\n }\n\n const apiKeyProfile = await resolveOpenMercatoApiKeyProfile(em, apiKeyId, {\n tenantId,\n organizationId,\n })\n if (!apiKeyProfile) {\n throw new Error('CALL_OPEN_MERCATO action requires an active API key profile in scope')\n }\n\n const roleIds = Array.isArray(apiKeyProfile.rolesJson)\n ? apiKeyProfile.rolesJson.filter((roleId): roleId is string => typeof roleId === 'string' && roleId.length > 0)\n : []\n if (roleIds.length === 0) {\n throw new Error('CALL_OPEN_MERCATO action requires an API key profile with at least one role')\n }\n\n const ruleAuthorId = await resolveActiveRuleAuthorId(em, context.ruleAuthorId, tenantId)\n if (!ruleAuthorId) {\n throw await translatedOpenMercatoCallError(\n 'business_rules.errors.openMercatoCall.executionAuthorInactive',\n 'CALL_OPEN_MERCATO action refused: the rule has no active author',\n )\n }\n const rbacService = context.rbacService ?? await resolveRbacService()\n const authorCanUseProfile = await canActorUseOpenMercatoApiKeyProfile({\n em,\n rbacService,\n actorId: ruleAuthorId,\n tenantId,\n organizationId,\n apiKey: apiKeyProfile,\n })\n if (!authorCanUseProfile) {\n throw await translatedOpenMercatoCallError(\n 'business_rules.errors.openMercatoCall.executionAuthorCannotGrant',\n 'CALL_OPEN_MERCATO action refused: the rule author cannot grant every role of the API key profile',\n )\n }\n\n const { withOnetimeApiKey } = await import('../../api_keys/services/apiKeyService')\n const fullUrl = buildOpenMercatoApiUrl(endpointOption.path)\n const requestBody = method === 'GET'\n ? undefined\n : normalizeOpenMercatoRequestBody(action.config?.body, context)\n\n return await withOnetimeApiKey(\n em,\n {\n name: `__business_rule_${context.ruleId || 'unknown'}__`,\n description: `One-time key for business rule ${context.ruleId || 'unknown'}`,\n tenantId,\n organizationId,\n roles: roleIds,\n createdBy: null,\n expiresAt: null,\n },\n async (apiKeySecret) => {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `apikey ${apiKeySecret}`,\n 'X-Tenant-Id': tenantId,\n 'X-Organization-Id': organizationId,\n }\n if (context.ruleId) headers['X-Business-Rule-Id'] = context.ruleId\n if (context.ruleName) headers['X-Business-Rule-Name'] = context.ruleName\n if (context.entityType) headers['X-Business-Rule-Entity-Type'] = context.entityType\n if (context.entityId) headers['X-Business-Rule-Entity-Id'] = context.entityId\n\n const response = await fetch(fullUrl, {\n method,\n headers,\n body: requestBody === undefined ? undefined : JSON.stringify(requestBody),\n })\n\n const responseBody = await parseOpenMercatoResponseBody(response)\n if (!response.ok) {\n throwOpenMercatoResponseError(response.status)\n }\n\n return {\n type: 'CALL_OPEN_MERCATO',\n endpoint: endpointOption.path,\n method,\n apiKeyId,\n status: response.status,\n statusText: response.statusText,\n body: responseBody,\n authenticated: true,\n tenantId,\n organizationId,\n }\n },\n )\n}\n\n/**\n * EMIT_EVENT action handler\n */\nasync function handleEmitEvent(action: Action, context: ActionContext): Promise<EmitEventResult> {\n const eventName = action.config?.event\n const payload = action.config?.payload || {}\n\n if (!eventName) {\n throw new Error('EMIT_EVENT action requires an event name')\n }\n\n if (typeof eventName !== 'string' || eventName.trim() === '') {\n throw new Error('EMIT_EVENT action requires a non-empty event name')\n }\n\n return {\n type: 'EMIT_EVENT',\n event: eventName,\n payload,\n }\n}\n\n/**\n * Interpolate message template with context values\n * Supports {{field}} syntax for variable substitution\n */\nexport function interpolateMessage(template: string, context: ActionContext): string {\n if (!template) {\n return ''\n }\n\n return template.replace(/\\{\\{([^}]+)\\}\\}/g, (match, path) => {\n const trimmedPath = path.trim()\n const value = resolveValue(`{{${trimmedPath}}}`, context)\n\n if (value === undefined || value === null) {\n return match\n }\n\n return String(value)\n })\n}\n\n/**\n * Resolve a value from context (supports special values like {{today}}, {{user.id}}, etc.)\n */\nfunction resolveValue(value: any, context: ActionContext): any {\n if (typeof value !== 'string') {\n return value\n }\n\n if (value.startsWith('{{') && value.endsWith('}}')) {\n return resolveSpecialValue(value, context)\n }\n\n return value\n}\n\nfunction buildOpenMercatoApiUrl(endpoint: string): string {\n if (!endpoint.startsWith('/api/')) {\n throw new Error(`CALL_OPEN_MERCATO only supports /api/* paths, got: ${endpoint}`)\n }\n const appUrl = (process.env.APP_URL || 'http://localhost:3000').replace(/\\/$/, '')\n return `${appUrl}${endpoint}`\n}\n\nfunction normalizeOpenMercatoRequestBody(value: any, context: ActionContext): any {\n if (value === undefined || value === null || value === '') return undefined\n const interpolated = interpolateActionValue(value, context)\n if (typeof interpolated !== 'string') return interpolated\n\n const trimmed = interpolated.trim()\n if (!trimmed) return undefined\n\n try {\n return JSON.parse(trimmed)\n } catch {\n return interpolated\n }\n}\n\nfunction interpolateActionValue(value: any, context: ActionContext): any {\n if (typeof value === 'string') {\n return interpolateMessage(value, context)\n }\n if (Array.isArray(value)) {\n return value.map((item) => interpolateActionValue(item, context))\n }\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value).map(([key, entry]) => [key, interpolateActionValue(entry, context)]),\n )\n }\n return value\n}\n\nasync function parseOpenMercatoResponseBody(response: Response): Promise<any> {\n const contentType = response.headers.get('content-type')\n try {\n if (contentType && contentType.includes('application/json')) {\n return await response.json()\n }\n return await response.text()\n } catch {\n return null\n }\n}\n\nfunction throwOpenMercatoResponseError(status: number): never {\n const error: Error & { retriable?: boolean } = new Error(`CALL_OPEN_MERCATO request failed with status ${status}`)\n if (status >= 500) {\n error.retriable = true\n }\n throw error\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { EntityManager as PostgreSqlEntityManager } from '@mikro-orm/postgresql'\nimport type { EvaluationContext } from './expression-evaluator'\nimport { getNestedValue, resolveSpecialValue } from './value-resolver'\nimport {\n canActorUseOpenMercatoApiKeyProfile,\n findOpenMercatoEndpointOption,\n getCurrentOpenMercatoEndpointOptions,\n resolveOpenMercatoApiKeyProfile,\n} from './openmercato-call-options'\nimport type { RbacService } from '../../auth/services/rbacService'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { OpenMercatoEndpointOption } from './openmercato-call-options-types'\nimport { resolveApiKeyRoleIds } from '@open-mercato/core/modules/api_keys/services/sessionKeyRoles'\n\n/**\n * Action definition\n */\nexport interface Action {\n type: string\n config?: Record<string, any>\n}\n\n/**\n * Action execution context\n */\nexport interface ActionContext extends EvaluationContext {\n entityType?: string\n entityId?: string\n eventType?: string\n data?: any\n ruleId?: string\n ruleName?: string\n tenantId?: string\n organizationId?: string\n executedBy?: string | null\n em?: PostgreSqlEntityManager\n openMercatoEndpointOptions?: OpenMercatoEndpointOption[]\n ruleAuthorId?: string | null\n rbacService?: RbacService\n [key: string]: any\n}\n\n/**\n * Specific action result types\n */\nexport interface AllowTransitionResult {\n type: 'ALLOW_TRANSITION'\n allowed: true\n message: string\n}\n\nexport interface BlockTransitionResult {\n type: 'BLOCK_TRANSITION'\n allowed: false\n message: string\n}\n\nexport interface LogResult {\n type: 'LOG'\n level: string\n message: string\n timestamp: string\n}\n\nexport interface ShowErrorResult {\n type: 'SHOW_ERROR'\n severity: 'error'\n message: string\n}\n\nexport interface ShowWarningResult {\n type: 'SHOW_WARNING'\n severity: 'warning'\n message: string\n}\n\nexport interface ShowInfoResult {\n type: 'SHOW_INFO'\n severity: 'info'\n message: string\n}\n\nexport interface NotifyResult {\n type: 'NOTIFY'\n recipients: string[]\n subject: string\n message: string\n template?: string\n}\n\nexport interface SetFieldResult {\n type: 'SET_FIELD'\n field: string\n value: any\n}\n\nexport interface CallWebhookResult {\n type: 'CALL_WEBHOOK'\n url: string\n method: string\n headers: Record<string, any>\n body?: any\n status: 'pending'\n}\n\nexport interface CallOpenMercatoResult {\n type: 'CALL_OPEN_MERCATO'\n endpoint: string\n method: string\n apiKeyId: string\n status: number\n statusText: string\n body: any\n authenticated: true\n tenantId: string\n organizationId: string\n}\n\nexport interface EmitEventResult {\n type: 'EMIT_EVENT'\n event: string\n payload: Record<string, any>\n}\n\n/**\n * Union type of all action results\n */\nexport type ActionHandlerResult =\n | AllowTransitionResult\n | BlockTransitionResult\n | LogResult\n | ShowErrorResult\n | ShowWarningResult\n | ShowInfoResult\n | NotifyResult\n | SetFieldResult\n | CallWebhookResult\n | CallOpenMercatoResult\n | EmitEventResult\n\n/**\n * Action execution result\n */\nexport interface ActionResult {\n action: Action\n success: boolean\n result?: ActionHandlerResult\n error?: string\n executionTime: number\n}\n\n/**\n * Action execution outcome (aggregated results)\n */\nexport interface ActionExecutionOutcome {\n success: boolean\n results: ActionResult[]\n totalTime: number\n errors?: string[]\n}\n\n/**\n * Execute multiple actions in sequence\n */\nexport async function executeActions(\n actions: Action[],\n context: ActionContext\n): Promise<ActionExecutionOutcome> {\n const startTime = Date.now()\n const results: ActionResult[] = []\n const errors: string[] = []\n\n for (const action of actions) {\n try {\n const result = await executeAction(action, context)\n results.push(result)\n\n if (result.error) {\n errors.push(`Action ${action.type}: ${result.error}`)\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n errors.push(`Action ${action.type}: ${errorMessage}`)\n\n results.push({\n action,\n success: false,\n error: errorMessage,\n executionTime: 0,\n })\n }\n }\n\n const totalTime = Date.now() - startTime\n\n return {\n success: results.every((r) => r.success),\n results,\n totalTime,\n errors: errors.length > 0 ? errors : undefined,\n }\n}\n\n/**\n * Execute a single action\n */\nexport async function executeAction(action: Action, context: ActionContext): Promise<ActionResult> {\n const startTime = Date.now()\n\n try {\n const handler = getActionHandler(action.type)\n const result = await handler(action, context)\n\n const executionTime = Date.now() - startTime\n\n return {\n action,\n success: true,\n result,\n executionTime,\n }\n } catch (error) {\n const executionTime = Date.now() - startTime\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n return {\n action,\n success: false,\n error: errorMessage,\n executionTime,\n }\n }\n}\n\n/**\n * Action handler function type\n */\ntype ActionHandler = (action: Action, context: ActionContext) => Promise<ActionHandlerResult>\n\n/**\n * Get action handler by type\n */\nfunction getActionHandler(actionType: string): ActionHandler {\n const handlers: Record<string, ActionHandler> = {\n ALLOW_TRANSITION: handleAllowTransition,\n BLOCK_TRANSITION: handleBlockTransition,\n LOG: handleLog,\n SHOW_ERROR: handleShowError,\n SHOW_WARNING: handleShowWarning,\n SHOW_INFO: handleShowInfo,\n NOTIFY: handleNotify,\n SET_FIELD: handleSetField,\n CALL_WEBHOOK: handleCallWebhook,\n CALL_OPEN_MERCATO: handleCallOpenMercato,\n EMIT_EVENT: handleEmitEvent,\n }\n\n const handler = handlers[actionType]\n\n if (!handler) {\n throw new Error(`Unknown action type: ${actionType}`)\n }\n\n return handler\n}\n\n/**\n * ALLOW_TRANSITION action handler\n */\nasync function handleAllowTransition(\n action: Action,\n context: ActionContext\n): Promise<AllowTransitionResult> {\n return {\n type: 'ALLOW_TRANSITION',\n allowed: true,\n message: interpolateMessage(action.config?.message || 'Transition allowed', context),\n }\n}\n\n/**\n * BLOCK_TRANSITION action handler\n */\nasync function handleBlockTransition(\n action: Action,\n context: ActionContext\n): Promise<BlockTransitionResult> {\n return {\n type: 'BLOCK_TRANSITION',\n allowed: false,\n message: interpolateMessage(action.config?.message || 'Transition blocked', context),\n }\n}\n\n/**\n * LOG action handler\n */\nasync function handleLog(action: Action, context: ActionContext): Promise<LogResult> {\n const level = action.config?.level || 'info'\n const message = interpolateMessage(action.config?.message || '', context)\n\n return {\n type: 'LOG',\n level,\n message,\n timestamp: new Date().toISOString(),\n }\n}\n\n/**\n * SHOW_ERROR action handler\n */\nasync function handleShowError(action: Action, context: ActionContext): Promise<ShowErrorResult> {\n const message = interpolateMessage(action.config?.message || '', context)\n\n return {\n type: 'SHOW_ERROR',\n severity: 'error',\n message,\n }\n}\n\n/**\n * SHOW_WARNING action handler\n */\nasync function handleShowWarning(\n action: Action,\n context: ActionContext\n): Promise<ShowWarningResult> {\n const message = interpolateMessage(action.config?.message || '', context)\n\n return {\n type: 'SHOW_WARNING',\n severity: 'warning',\n message,\n }\n}\n\n/**\n * SHOW_INFO action handler\n */\nasync function handleShowInfo(action: Action, context: ActionContext): Promise<ShowInfoResult> {\n const message = interpolateMessage(action.config?.message || '', context)\n\n return {\n type: 'SHOW_INFO',\n severity: 'info',\n message,\n }\n}\n\n/**\n * NOTIFY action handler\n */\nasync function handleNotify(action: Action, context: ActionContext): Promise<NotifyResult> {\n const recipients = action.config?.recipients || []\n const message = interpolateMessage(action.config?.message || '', context)\n const subject = interpolateMessage(action.config?.subject || '', context)\n const template = action.config?.template\n\n if (!Array.isArray(recipients)) {\n throw new Error('NOTIFY action requires recipients to be an array')\n }\n\n if (recipients.length === 0) {\n throw new Error('NOTIFY action requires at least one recipient')\n }\n\n return {\n type: 'NOTIFY',\n recipients,\n subject,\n message,\n template,\n }\n}\n\n/**\n * SET_FIELD action handler\n */\nasync function handleSetField(action: Action, context: ActionContext): Promise<SetFieldResult> {\n const field = action.config?.field\n const value = resolveValue(action.config?.value, context)\n\n if (!field) {\n throw new Error('SET_FIELD action requires a field name')\n }\n\n if (typeof field !== 'string' || field.trim() === '') {\n throw new Error('SET_FIELD action requires a non-empty field name')\n }\n\n return {\n type: 'SET_FIELD',\n field,\n value,\n }\n}\n\n/**\n * CALL_WEBHOOK action handler\n */\nasync function handleCallWebhook(\n action: Action,\n context: ActionContext\n): Promise<CallWebhookResult> {\n const url = interpolateMessage(action.config?.url || '', context)\n const method = action.config?.method || 'POST'\n const headers = action.config?.headers || {}\n const body = action.config?.body\n\n if (!url || url.trim() === '') {\n throw new Error('CALL_WEBHOOK action requires a non-empty URL')\n }\n\n const validMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']\n if (!validMethods.includes(method.toUpperCase())) {\n throw new Error(\n `CALL_WEBHOOK action requires a valid HTTP method (${validMethods.join(', ')})`\n )\n }\n\n return {\n type: 'CALL_WEBHOOK',\n url,\n method: method.toUpperCase(),\n headers,\n body,\n status: 'pending',\n }\n}\n\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i\nconst API_KEY_ACTOR_PREFIX = 'api_key:'\n\nasync function resolveRbacService(): Promise<RbacService> {\n const { createRequestContainer } = await import('@open-mercato/shared/lib/di/container')\n const container = await createRequestContainer()\n return container.resolve('rbacService') as RbacService\n}\n\nasync function translatedOpenMercatoCallError(key: string, fallback: string): Promise<Error> {\n const { resolveTranslations } = await import('@open-mercato/shared/lib/i18n/server')\n const { t } = await resolveTranslations()\n return new Error(t(key, fallback))\n}\n\nasync function resolveActiveRuleAuthorId(\n em: PostgreSqlEntityManager,\n authorId: string | null | undefined,\n tenantId: string,\n): Promise<string | null> {\n const candidate = typeof authorId === 'string' ? authorId.trim() : ''\n if (!candidate) return null\n if (candidate.startsWith(API_KEY_ACTOR_PREFIX)) {\n const apiKeyId = candidate.slice(API_KEY_ACTOR_PREFIX.length)\n if (!UUID_PATTERN.test(apiKeyId)) return null\n const { ApiKey } = await import('../../api_keys/data/entities')\n const key = await findOneWithDecryption(em, ApiKey, { id: apiKeyId, tenantId, deletedAt: null }, {}, { tenantId, organizationId: null })\n if (!key) return null\n if (key.expiresAt && key.expiresAt.getTime() <= Date.now()) return null\n return candidate\n }\n if (!UUID_PATTERN.test(candidate)) return null\n const { User } = await import('../../auth/data/entities')\n const user = await findOneWithDecryption(em, User, { id: candidate, deletedAt: null }, {}, { tenantId: null, organizationId: null })\n if (!user) return null\n if (user.tenantId && String(user.tenantId) === tenantId) return candidate\n const { isUserEffectivelySuperAdmin } = await import('../../auth/lib/grantChecks')\n return await isUserEffectivelySuperAdmin(em, candidate) ? candidate : null\n}\n\n/**\n * CALL_OPEN_MERCATO action handler\n */\nasync function handleCallOpenMercato(\n action: Action,\n context: ActionContext\n): Promise<CallOpenMercatoResult> {\n const endpoint = String(action.config?.endpoint ?? '').trim()\n const method = String(action.config?.method ?? '').trim().toUpperCase()\n const apiKeyId = String(action.config?.apiKeyId ?? '').trim()\n\n if (!endpoint) {\n throw new Error('CALL_OPEN_MERCATO action requires an endpoint')\n }\n if (!method) {\n throw new Error('CALL_OPEN_MERCATO action requires an HTTP method')\n }\n if (!apiKeyId) {\n throw new Error('CALL_OPEN_MERCATO action requires an API key profile')\n }\n\n const endpointOptions = context.openMercatoEndpointOptions ?? await getCurrentOpenMercatoEndpointOptions()\n const endpointOption = findOpenMercatoEndpointOption(\n endpoint,\n method,\n endpointOptions,\n )\n if (!endpointOption) {\n throw new Error('CALL_OPEN_MERCATO action requires a currently available /api/* endpoint')\n }\n\n const em = context.em\n if (!em) {\n throw new Error('CALL_OPEN_MERCATO action requires an EntityManager in action context')\n }\n\n const tenantId = context.tenantId ?? context.tenant?.id\n const organizationId = context.organizationId ?? context.organization?.id\n if (!tenantId || !organizationId) {\n throw new Error('CALL_OPEN_MERCATO action requires tenant and organization context')\n }\n\n const apiKeyProfile = await resolveOpenMercatoApiKeyProfile(em, apiKeyId, {\n tenantId,\n organizationId,\n })\n if (!apiKeyProfile) {\n throw new Error('CALL_OPEN_MERCATO action requires an active API key profile in scope')\n }\n\n const roleIds = await resolveApiKeyRoleIds(em, apiKeyProfile, tenantId)\n if (roleIds.length === 0) {\n throw new Error('CALL_OPEN_MERCATO action requires an API key profile with at least one role')\n }\n\n const ruleAuthorId = await resolveActiveRuleAuthorId(em, context.ruleAuthorId, tenantId)\n if (!ruleAuthorId) {\n throw await translatedOpenMercatoCallError(\n 'business_rules.errors.openMercatoCall.executionAuthorInactive',\n 'CALL_OPEN_MERCATO action refused: the rule has no active author',\n )\n }\n const rbacService = context.rbacService ?? await resolveRbacService()\n const authorCanUseProfile = await canActorUseOpenMercatoApiKeyProfile({\n em,\n rbacService,\n actorId: ruleAuthorId,\n tenantId,\n organizationId,\n apiKey: apiKeyProfile,\n })\n if (!authorCanUseProfile) {\n throw await translatedOpenMercatoCallError(\n 'business_rules.errors.openMercatoCall.executionAuthorCannotGrant',\n 'CALL_OPEN_MERCATO action refused: the rule author cannot grant every role of the API key profile',\n )\n }\n\n const { withOnetimeApiKey } = await import('../../api_keys/services/apiKeyService')\n const fullUrl = buildOpenMercatoApiUrl(endpointOption.path)\n const requestBody = method === 'GET'\n ? undefined\n : normalizeOpenMercatoRequestBody(action.config?.body, context)\n\n return await withOnetimeApiKey(\n em,\n {\n name: `__business_rule_${context.ruleId || 'unknown'}__`,\n description: `One-time key for business rule ${context.ruleId || 'unknown'}`,\n tenantId,\n organizationId,\n roles: roleIds,\n createdBy: null,\n expiresAt: null,\n },\n async (apiKeySecret) => {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'Authorization': `apikey ${apiKeySecret}`,\n 'X-Tenant-Id': tenantId,\n 'X-Organization-Id': organizationId,\n }\n if (context.ruleId) headers['X-Business-Rule-Id'] = context.ruleId\n if (context.ruleName) headers['X-Business-Rule-Name'] = context.ruleName\n if (context.entityType) headers['X-Business-Rule-Entity-Type'] = context.entityType\n if (context.entityId) headers['X-Business-Rule-Entity-Id'] = context.entityId\n\n const response = await fetch(fullUrl, {\n method,\n headers,\n body: requestBody === undefined ? undefined : JSON.stringify(requestBody),\n })\n\n const responseBody = await parseOpenMercatoResponseBody(response)\n if (!response.ok) {\n throwOpenMercatoResponseError(response.status)\n }\n\n return {\n type: 'CALL_OPEN_MERCATO',\n endpoint: endpointOption.path,\n method,\n apiKeyId,\n status: response.status,\n statusText: response.statusText,\n body: responseBody,\n authenticated: true,\n tenantId,\n organizationId,\n }\n },\n )\n}\n\n/**\n * EMIT_EVENT action handler\n */\nasync function handleEmitEvent(action: Action, context: ActionContext): Promise<EmitEventResult> {\n const eventName = action.config?.event\n const payload = action.config?.payload || {}\n\n if (!eventName) {\n throw new Error('EMIT_EVENT action requires an event name')\n }\n\n if (typeof eventName !== 'string' || eventName.trim() === '') {\n throw new Error('EMIT_EVENT action requires a non-empty event name')\n }\n\n return {\n type: 'EMIT_EVENT',\n event: eventName,\n payload,\n }\n}\n\n/**\n * Interpolate message template with context values\n * Supports {{field}} syntax for variable substitution\n */\nexport function interpolateMessage(template: string, context: ActionContext): string {\n if (!template) {\n return ''\n }\n\n return template.replace(/\\{\\{([^}]+)\\}\\}/g, (match, path) => {\n const trimmedPath = path.trim()\n const value = resolveValue(`{{${trimmedPath}}}`, context)\n\n if (value === undefined || value === null) {\n return match\n }\n\n return String(value)\n })\n}\n\n/**\n * Resolve a value from context (supports special values like {{today}}, {{user.id}}, etc.)\n */\nfunction resolveValue(value: any, context: ActionContext): any {\n if (typeof value !== 'string') {\n return value\n }\n\n if (value.startsWith('{{') && value.endsWith('}}')) {\n return resolveSpecialValue(value, context)\n }\n\n return value\n}\n\nfunction buildOpenMercatoApiUrl(endpoint: string): string {\n if (!endpoint.startsWith('/api/')) {\n throw new Error(`CALL_OPEN_MERCATO only supports /api/* paths, got: ${endpoint}`)\n }\n const appUrl = (process.env.APP_URL || 'http://localhost:3000').replace(/\\/$/, '')\n return `${appUrl}${endpoint}`\n}\n\nfunction normalizeOpenMercatoRequestBody(value: any, context: ActionContext): any {\n if (value === undefined || value === null || value === '') return undefined\n const interpolated = interpolateActionValue(value, context)\n if (typeof interpolated !== 'string') return interpolated\n\n const trimmed = interpolated.trim()\n if (!trimmed) return undefined\n\n try {\n return JSON.parse(trimmed)\n } catch {\n return interpolated\n }\n}\n\nfunction interpolateActionValue(value: any, context: ActionContext): any {\n if (typeof value === 'string') {\n return interpolateMessage(value, context)\n }\n if (Array.isArray(value)) {\n return value.map((item) => interpolateActionValue(item, context))\n }\n if (value && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value).map(([key, entry]) => [key, interpolateActionValue(entry, context)]),\n )\n }\n return value\n}\n\nasync function parseOpenMercatoResponseBody(response: Response): Promise<any> {\n const contentType = response.headers.get('content-type')\n try {\n if (contentType && contentType.includes('application/json')) {\n return await response.json()\n }\n return await response.text()\n } catch {\n return null\n }\n}\n\nfunction throwOpenMercatoResponseError(status: number): never {\n const error: Error & { retriable?: boolean } = new Error(`CALL_OPEN_MERCATO request failed with status ${status}`)\n if (status >= 500) {\n error.retriable = true\n }\n throw error\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,6 @@
1
1
  import { Organization } from "@open-mercato/core/modules/directory/data/entities";
2
+ import { ApiKey } from "@open-mercato/core/modules/api_keys/data/entities";
3
+ import { isSessionBoundApiKey } from "@open-mercato/core/modules/api_keys/services/sessionKeyRoles";
2
4
  import { isAllOrganizationsSelection } from "@open-mercato/core/modules/directory/constants";
3
5
  import { getCurrentCacheTenant, runWithCacheTenant } from "@open-mercato/cache";
4
6
  import { parseSelectedOrganizationCookie, parseSelectedTenantCookie } from "./scopeCookies.js";
@@ -327,9 +329,14 @@ async function resolveOrganizationScopeForRequest({
327
329
  if (memoized) return memoized;
328
330
  }
329
331
  const resolveScope = async () => {
330
- if (cache && cacheKey && typeof cache.get === "function") {
332
+ let crossRequestCache = cache;
333
+ if (crossRequestCache && userId?.startsWith("api_key:")) {
334
+ const key = await em.findOne(ApiKey, { id: userId.slice("api_key:".length), deletedAt: null });
335
+ if (!key || isSessionBoundApiKey(key)) crossRequestCache = null;
336
+ }
337
+ if (crossRequestCache && cacheKey && typeof crossRequestCache.get === "function") {
331
338
  try {
332
- const cached = await cache.get(cacheKey);
339
+ const cached = await crossRequestCache.get(cacheKey);
333
340
  if (isValidCachedScope(cached)) return cached;
334
341
  } catch (err) {
335
342
  logger.warn("Cache read failed", { err });
@@ -342,9 +349,9 @@ async function resolveOrganizationScopeForRequest({
342
349
  selectedId: rawSelected,
343
350
  tenantId: effectiveTenantId
344
351
  });
345
- if (cache && cacheKey && userId && typeof cache.set === "function") {
352
+ if (crossRequestCache && cacheKey && userId && typeof crossRequestCache.set === "function") {
346
353
  try {
347
- await cache.set(cacheKey, baseScope, {
354
+ await crossRequestCache.set(cacheKey, baseScope, {
348
355
  ttl: ttlMs,
349
356
  tags: buildOrgScopeCacheTags({ userId, effectiveTenantId })
350
357
  });