@venizia/ignis 0.3.8 → 0.4.1

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 (59) hide show
  1. package/LICENSE.md +1 -1
  2. package/dist/base/applications/base.js +1 -1
  3. package/dist/base/applications/base.js.map +1 -1
  4. package/dist/base/applications/server.js +4 -4
  5. package/dist/base/applications/server.js.map +1 -1
  6. package/dist/base/middlewares/app-error/app-error.middleware.js +1 -1
  7. package/dist/base/middlewares/app-error/app-error.middleware.js.map +1 -1
  8. package/dist/components/auth/authenticate/controllers/factory.js +1 -1
  9. package/dist/components/auth/authenticate/controllers/factory.js.map +1 -1
  10. package/dist/components/auth/authenticate/controllers/jwks/controller.js.map +1 -1
  11. package/dist/components/auth/authenticate/controllers/service-certs/controller.js.map +1 -1
  12. package/dist/components/auth/authenticate/services/bearer/jwks/abstract.service.js +1 -1
  13. package/dist/components/auth/authenticate/services/bearer/jwks/abstract.service.js.map +1 -1
  14. package/dist/components/auth/authenticate/services/bearer/jwks/issuer.service.js +1 -1
  15. package/dist/components/auth/authenticate/services/bearer/jwks/issuer.service.js.map +1 -1
  16. package/dist/components/auth/authorize/adapters/custom-grant-expander.js +3 -3
  17. package/dist/components/auth/authorize/adapters/custom-grant-expander.js.map +1 -1
  18. package/dist/components/auth/authorize/adapters/scoped-casbin/adapter.d.ts.map +1 -1
  19. package/dist/components/auth/authorize/adapters/scoped-casbin/adapter.js +3 -3
  20. package/dist/components/auth/authorize/adapters/scoped-casbin/adapter.js.map +1 -1
  21. package/dist/components/auth/authorize/enforcers/casbin.enforcer.js +2 -2
  22. package/dist/components/auth/authorize/enforcers/casbin.enforcer.js.map +1 -1
  23. package/dist/components/auth/authorize/enforcers/user-policy-line-cache.js +1 -1
  24. package/dist/components/auth/authorize/enforcers/user-policy-line-cache.js.map +1 -1
  25. package/dist/components/health-check/controller.js +2 -2
  26. package/dist/components/health-check/controller.js.map +1 -1
  27. package/dist/components/mail/helpers/executors/bull-mq-executor.helper.js +2 -2
  28. package/dist/components/mail/helpers/executors/bull-mq-executor.helper.js.map +1 -1
  29. package/dist/components/mail/helpers/executors/internal-queue-executor.helper.js +2 -2
  30. package/dist/components/mail/helpers/executors/internal-queue-executor.helper.js.map +1 -1
  31. package/dist/components/mail/helpers/transporters/mailgun-transporter.helper.js +1 -1
  32. package/dist/components/mail/helpers/transporters/mailgun-transporter.helper.js.map +1 -1
  33. package/dist/components/mail/services/mail.service.js +2 -2
  34. package/dist/components/mail/services/mail.service.js.map +1 -1
  35. package/dist/components/mail/utilities/attachment.utility.js +2 -2
  36. package/dist/components/mail/utilities/attachment.utility.js.map +1 -1
  37. package/dist/components/mail/utilities/mime.utility.js +3 -3
  38. package/dist/components/mail/utilities/mime.utility.js.map +1 -1
  39. package/dist/components/static-asset/component.js +1 -1
  40. package/dist/components/static-asset/component.js.map +1 -1
  41. package/dist/components/static-asset/controller/factory.d.ts.map +1 -1
  42. package/dist/components/static-asset/controller/factory.js +9 -9
  43. package/dist/components/static-asset/controller/factory.js.map +1 -1
  44. package/dist/components/static-asset/controller/key-scope.js +1 -1
  45. package/dist/components/static-asset/controller/key-scope.js.map +1 -1
  46. package/dist/components/static-asset/controller/meta-link.js +2 -2
  47. package/dist/components/static-asset/controller/meta-link.js.map +1 -1
  48. package/dist/components/static-asset/models/base.model.js +1 -1
  49. package/dist/components/static-asset/models/base.model.js.map +1 -1
  50. package/dist/presets/app/files/.configs/formatters/.ignore +2 -2
  51. package/dist/presets/app/files/src/smoke.test.ts +1 -1
  52. package/dist/presets/app/files/tsconfig.json +2 -8
  53. package/dist/presets/app/preset.json +4 -5
  54. package/dist/presets/lib/files/.configs/formatters/.ignore +2 -2
  55. package/dist/presets/lib/files/tsconfig.json +2 -7
  56. package/dist/presets/lib/preset.json +3 -4
  57. package/package.json +51 -52
  58. package/dist/presets/app/files/.configs/formatters/oxfmt.config.mts +0 -4
  59. package/dist/presets/lib/files/.configs/formatters/oxfmt.config.mts +0 -4
@@ -1 +1 @@
1
- {"version":3,"file":"custom-grant-expander.js","sourceRoot":"","sources":["../../../../../src/components/auth/authorize/adapters/custom-grant-expander.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IdType } from '@/base';\nimport { readResultRows } from '@/utilities';\nimport { BaseHelper } from '@venizia/ignis-helpers/core';\nimport {\n AuthorizationActions,\n AuthorizationPermissionBuilder,\n AuthorizationPolicyVariants,\n GrantBuilder,\n type TCustomGrantMetadata,\n} from '@venizia/ignis-kernel';\nimport { sql, type SQL } from 'drizzle-orm';\nimport { PolicyConnectorResolver } from './connector';\nimport type { ICasbinPolicySource, IScopedCasbinEntities } from './common';\n\nconst DEFAULT_SCHEMA = 'public';\n\n/** A custom row that survived {@link CustomGrantExpander.rejectCustomRow}, ready for op-to-catalog resolution. */\nexport type TCustomGrantRow = {\n subjectId: IdType;\n objectSubject: string;\n ops: string[];\n domain: string;\n effect: string;\n};\n\n/**\n * Expands \"custom\" operation-subset grants (`metadata.ops`) into one casbin line per catalogued\n * operation. Isolated from the filtered-policy loader on purpose: it owns its own SQL\n * (`queryOperationCatalog`) and error vocabulary, and never reaches back into ScopedCasbinAdapter.\n */\nexport class CustomGrantExpander extends BaseHelper {\n protected readonly dataSource: ICasbinPolicySource;\n protected readonly permission: IScopedCasbinEntities['permission'];\n protected readonly softDelete: IScopedCasbinEntities['softDelete'];\n\n constructor(opts: {\n dataSource: ICasbinPolicySource;\n entities: Pick<IScopedCasbinEntities, 'permission' | 'softDelete'>;\n }) {\n super({ scope: CustomGrantExpander.name });\n this.dataSource = opts.dataSource;\n this.permission = opts.entities.permission;\n this.softDelete = opts.entities.softDelete;\n }\n\n /** Why a custom-looking grant row cannot be honoured, or null when it is well formed. */\n rejectCustomRow(opts: {\n row: { subjectId: IdType; objectCode: string; objectMethod: string };\n parsed: TCustomGrantMetadata | null;\n isCustomAction: boolean;\n metadataColumnName?: string;\n }): string | null {\n const { row, parsed, isCustomAction, metadataColumnName } = opts;\n\n if (isCustomAction && !metadataColumnName) {\n return `Skipping custom grant - entities.policyDefinition.metadata.columnName is not mapped, so metadata.ops cannot be read | subject id: ${row.subjectId} | object: ${row.objectCode}`;\n }\n\n if (isCustomAction && !parsed) {\n return `Skipping custom grant - metadata.ops is missing, empty, or not an array of non-empty strings | subject id: ${row.subjectId} | object: ${row.objectCode}`;\n }\n\n if (!isCustomAction && parsed) {\n return `Skipping grant - metadata.ops is present but action is not \"${AuthorizationActions.CUSTOM}\", so the intent is ambiguous | subject id: ${row.subjectId} | object: ${row.objectCode}`;\n }\n\n if (row.objectMethod !== AuthorizationPermissionBuilder.RESOURCE_NODE_METHOD) {\n return `Skipping custom grant - the target must be a subject-level resource node | subject id: ${row.subjectId} | object: ${row.objectCode}`;\n }\n\n return null;\n }\n\n /** Resolve every custom row's ops in one catalog query, then emit one line per resolved operation. Unresolvable ops come back as `rejections` rather than being logged here - the caller owns the logger the tests swap. */\n async expandCustomGrants(opts: {\n subjectType: string;\n customRows: TCustomGrantRow[];\n }): Promise<{ lines: string[]; rejections: string[] }> {\n if (!opts.customRows.length) {\n return { lines: [], rejections: [] };\n }\n\n const seen = new Set<string>();\n const pairs: Array<{ subject: string; method: string }> = [];\n\n const candidates = opts.customRows.flatMap(row =>\n row.ops.map(op => ({ subject: row.objectSubject, method: op })),\n );\n\n for (const candidate of candidates) {\n const key = `${candidate.subject}.${candidate.method}`;\n if (seen.has(key)) {\n continue;\n }\n\n seen.add(key);\n pairs.push(candidate);\n }\n\n const catalog = await this.queryOperationCatalog({ pairs });\n const byKey = new Map(catalog.map(entry => [`${entry.subject}.${entry.method}`, entry]));\n const lines: string[] = [];\n const rejections: string[] = [];\n\n for (const row of opts.customRows) {\n const { valid, unknown } = GrantBuilder.getInstance().validateCustomGrantOps({\n ops: row.ops,\n subject: row.objectSubject,\n catalog,\n });\n\n if (unknown.length) {\n rejections.push(\n `Skipping unresolvable operations in a custom grant | subject id: ${row.subjectId} | resource: ${row.objectSubject} | unknown: ${unknown.join(', ')}`,\n );\n }\n\n for (const op of valid) {\n const entry = byKey.get(`${row.objectSubject}.${op}`)!;\n\n lines.push(\n `${AuthorizationPolicyVariants.GRANT.rule}, ${opts.subjectType}_${row.subjectId}, ${row.domain}, ${entry.code}, ${entry.action}, ${row.effect}`,\n );\n }\n }\n\n return { lines, rejections };\n }\n\n /** Schema-qualified table reference (`\"<schema>\".\"<table>\"`) for use after FROM/JOIN with an alias. */\n private qualifiedTable(opts: { table: { schemaName?: string; tableName: string } }): SQL {\n const { table } = opts;\n const schema = table.schemaName ?? DEFAULT_SCHEMA;\n return sql`${sql.identifier(schema)}.${sql.identifier(table.tableName)}`;\n }\n\n /** `AND <alias>.<col> IS NULL` when soft-delete is on, else empty. The alias is emitted raw to match the unquoted FROM alias - quoting folds it to a different case and breaks the join. */\n private softDeleteClause(opts: { alias: string }): SQL {\n const sd = this.softDelete;\n if (!sd?.use) {\n return sql.empty();\n }\n\n return sql` AND ${sql.raw(opts.alias)}.${sql.identifier(sd.columnName)} IS NULL`;\n }\n\n /** Resolve `(subject, method)` pairs to catalogued operations. One query for the whole extraction. */\n private async queryOperationCatalog(opts: {\n pairs: Array<{ subject: string; method: string }>;\n }): Promise<Array<{ subject: string; method: string; code: string; action: string }>> {\n if (!opts.pairs.length) {\n return [];\n }\n\n const permissionTable = this.qualifiedTable({ table: this.permission });\n const connector = PolicyConnectorResolver.resolve({\n source: this.dataSource,\n caller: CustomGrantExpander.name,\n });\n\n const result = await connector.execute(sql`\n SELECT permission.subject, permission.method, permission.code, permission.action\n FROM ${permissionTable} permission\n WHERE (permission.subject, permission.method) IN (${sql.join(\n opts.pairs.map(pair => sql`(${pair.subject}, ${pair.method})`),\n sql`, `,\n )})\n AND permission.method <> ${AuthorizationPermissionBuilder.RESOURCE_NODE_METHOD}${this.softDeleteClause(\n { alias: 'permission' },\n )}\n `);\n\n return readResultRows<{ subject: string; method: string; code: string; action: string }>({\n result,\n });\n }\n}\n"]}
1
+ {"version":3,"file":"custom-grant-expander.js","sourceRoot":"","sources":["../../../../../src/components/auth/authorize/adapters/custom-grant-expander.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IdType } from '@/base';\nimport { readResultRows } from '@/utilities';\nimport { BaseHelper } from '@venizia/ignis-helpers/core';\nimport {\n AuthorizationActions,\n AuthorizationPermissionBuilder,\n AuthorizationPolicyVariants,\n GrantBuilder,\n type TCustomGrantMetadata,\n} from '@venizia/ignis-kernel';\nimport { sql, type SQL } from 'drizzle-orm';\nimport { PolicyConnectorResolver } from './connector';\nimport type { ICasbinPolicySource, IScopedCasbinEntities } from './common';\n\nconst DEFAULT_SCHEMA = 'public';\n\n/** A custom row that survived {@link CustomGrantExpander.rejectCustomRow}, ready for op-to-catalog resolution. */\nexport type TCustomGrantRow = {\n subjectId: IdType;\n objectSubject: string;\n ops: string[];\n domain: string;\n effect: string;\n};\n\n/**\n * Expands \"custom\" operation-subset grants (`metadata.ops`) into one casbin line per catalogued\n * operation. Isolated from the filtered-policy loader on purpose: it owns its own SQL\n * (`queryOperationCatalog`) and error vocabulary, and never reaches back into ScopedCasbinAdapter.\n */\nexport class CustomGrantExpander extends BaseHelper {\n protected readonly dataSource: ICasbinPolicySource;\n protected readonly permission: IScopedCasbinEntities['permission'];\n protected readonly softDelete: IScopedCasbinEntities['softDelete'];\n\n constructor(opts: {\n dataSource: ICasbinPolicySource;\n entities: Pick<IScopedCasbinEntities, 'permission' | 'softDelete'>;\n }) {\n super({ scope: CustomGrantExpander.name });\n this.dataSource = opts.dataSource;\n this.permission = opts.entities.permission;\n this.softDelete = opts.entities.softDelete;\n }\n\n /** Why a custom-looking grant row cannot be honoured, or null when it is well formed. */\n rejectCustomRow(opts: {\n row: { subjectId: IdType; objectCode: string; objectMethod: string };\n parsed: TCustomGrantMetadata | null;\n isCustomAction: boolean;\n metadataColumnName?: string;\n }): string | null {\n const { row, parsed, isCustomAction, metadataColumnName } = opts;\n\n if (isCustomAction && !metadataColumnName) {\n return `Skipping custom grant - entities.policyDefinition.metadata.columnName is not mapped, so metadata.ops cannot be read | subject id: ${row.subjectId} | object: ${row.objectCode}`;\n }\n\n if (isCustomAction && !parsed) {\n return `Skipping custom grant - metadata.ops is missing, empty, or not an array of non-empty strings | subject id: ${row.subjectId} | object: ${row.objectCode}`;\n }\n\n if (!isCustomAction && parsed) {\n return `Skipping grant - metadata.ops is present but action is not \"${AuthorizationActions.CUSTOM}\", so the intent is ambiguous | subject id: ${row.subjectId} | object: ${row.objectCode}`;\n }\n\n if (row.objectMethod !== AuthorizationPermissionBuilder.RESOURCE_NODE_METHOD) {\n return `Skipping custom grant - the target must be a subject-level resource node | subject id: ${row.subjectId} | object: ${row.objectCode}`;\n }\n\n return null;\n }\n\n /** Resolve every custom row's ops in one catalog query, then emit one line per resolved operation. Unresolvable ops come back as `rejections` rather than being logged here - the caller owns the logger the tests swap. */\n async expandCustomGrants(opts: {\n subjectType: string;\n customRows: TCustomGrantRow[];\n }): Promise<{ lines: string[]; rejections: string[] }> {\n if (!opts.customRows.length) {\n return { lines: [], rejections: [] };\n }\n\n const seen = new Set<string>();\n const pairs: Array<{ subject: string; method: string }> = [];\n\n const candidates = opts.customRows.flatMap((row) =>\n row.ops.map((op) => ({ subject: row.objectSubject, method: op })),\n );\n\n for (const candidate of candidates) {\n const key = `${candidate.subject}.${candidate.method}`;\n if (seen.has(key)) {\n continue;\n }\n\n seen.add(key);\n pairs.push(candidate);\n }\n\n const catalog = await this.queryOperationCatalog({ pairs });\n const byKey = new Map(catalog.map((entry) => [`${entry.subject}.${entry.method}`, entry]));\n const lines: string[] = [];\n const rejections: string[] = [];\n\n for (const row of opts.customRows) {\n const { valid, unknown } = GrantBuilder.getInstance().validateCustomGrantOps({\n ops: row.ops,\n subject: row.objectSubject,\n catalog,\n });\n\n if (unknown.length) {\n rejections.push(\n `Skipping unresolvable operations in a custom grant | subject id: ${row.subjectId} | resource: ${row.objectSubject} | unknown: ${unknown.join(', ')}`,\n );\n }\n\n for (const op of valid) {\n const entry = byKey.get(`${row.objectSubject}.${op}`)!;\n\n lines.push(\n `${AuthorizationPolicyVariants.GRANT.rule}, ${opts.subjectType}_${row.subjectId}, ${row.domain}, ${entry.code}, ${entry.action}, ${row.effect}`,\n );\n }\n }\n\n return { lines, rejections };\n }\n\n /** Schema-qualified table reference (`\"<schema>\".\"<table>\"`) for use after FROM/JOIN with an alias. */\n private qualifiedTable(opts: { table: { schemaName?: string; tableName: string } }): SQL {\n const { table } = opts;\n const schema = table.schemaName ?? DEFAULT_SCHEMA;\n return sql`${sql.identifier(schema)}.${sql.identifier(table.tableName)}`;\n }\n\n /** `AND <alias>.<col> IS NULL` when soft-delete is on, else empty. The alias is emitted raw to match the unquoted FROM alias - quoting folds it to a different case and breaks the join. */\n private softDeleteClause(opts: { alias: string }): SQL {\n const sd = this.softDelete;\n if (!sd?.use) {\n return sql.empty();\n }\n\n return sql` AND ${sql.raw(opts.alias)}.${sql.identifier(sd.columnName)} IS NULL`;\n }\n\n /** Resolve `(subject, method)` pairs to catalogued operations. One query for the whole extraction. */\n private async queryOperationCatalog(opts: {\n pairs: Array<{ subject: string; method: string }>;\n }): Promise<Array<{ subject: string; method: string; code: string; action: string }>> {\n if (!opts.pairs.length) {\n return [];\n }\n\n const permissionTable = this.qualifiedTable({ table: this.permission });\n const connector = PolicyConnectorResolver.resolve({\n source: this.dataSource,\n caller: CustomGrantExpander.name,\n });\n\n const result = await connector.execute(sql`\n SELECT permission.subject, permission.method, permission.code, permission.action\n FROM ${permissionTable} permission\n WHERE (permission.subject, permission.method) IN (${sql.join(\n opts.pairs.map((pair) => sql`(${pair.subject}, ${pair.method})`),\n sql`, `,\n )})\n AND permission.method <> ${AuthorizationPermissionBuilder.RESOURCE_NODE_METHOD}${this.softDeleteClause(\n { alias: 'permission' },\n )}\n `);\n\n return readResultRows<{ subject: string; method: string; code: string; action: string }>({\n result,\n });\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../../../src/components/auth/authorize/adapters/scoped-casbin/adapter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../../../../src/components/auth/authorize/adapters/scoped-casbin/adapter.ts"],"names":[],"mappings":"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"}
@@ -130,7 +130,7 @@ class ScopedCasbinAdapter extends base_filtered_1.BaseFilteredAdapter {
130
130
  .error('resolveDomainEdges hook threw - continuing without its edges for this load | principal: %s_%s | error: %s', opts.principal.type, opts.principal.id, error);
131
131
  return [];
132
132
  }
133
- return edges.map(edge => `${ignis_kernel_2.AuthorizationPolicyVariants.DOMAIN_INHERITS.rule}, ${edge.child}, ${edge.parent}`);
133
+ return edges.map((edge) => `${ignis_kernel_2.AuthorizationPolicyVariants.DOMAIN_INHERITS.rule}, ${edge.child}, ${edge.parent}`);
134
134
  }
135
135
  /** Schema for a table, defaulting to `public`. */
136
136
  schemaOf(table) {
@@ -171,7 +171,7 @@ class ScopedCasbinAdapter extends base_filtered_1.BaseFilteredAdapter {
171
171
  ? (0, drizzle_orm_1.sql) `, policyDefinition.${drizzle_orm_1.sql.identifier(metadataColumnName)} AS "metadata"`
172
172
  : drizzle_orm_1.sql.empty();
173
173
  const metadataNull = metadataColumnName ? (0, drizzle_orm_1.sql) `, NULL::jsonb AS "metadata"` : drizzle_orm_1.sql.empty();
174
- const domainTypeList = drizzle_orm_1.sql.join(domainTypes.map(domainType => (0, drizzle_orm_1.sql) `${domainType}`), (0, drizzle_orm_1.sql) `, `);
174
+ const domainTypeList = drizzle_orm_1.sql.join(domainTypes.map((domainType) => (0, drizzle_orm_1.sql) `${domainType}`), (0, drizzle_orm_1.sql) `, `);
175
175
  const rows = await this.query({
176
176
  statement: (0, drizzle_orm_1.sql) `
177
177
  WITH RECURSIVE role_closure AS (
@@ -386,7 +386,7 @@ class ScopedCasbinAdapter extends base_filtered_1.BaseFilteredAdapter {
386
386
  WHERE policyDefinition.variant = ${ignis_kernel_2.AuthorizationPolicyVariants.ACTION_INHERITS.action}${this.softDeleteClause({ alias: 'policyDefinition' })}
387
387
  `,
388
388
  });
389
- return rows.map(row => `${row.rel}, ${row.child}, ${row.parent}`);
389
+ return rows.map((row) => `${row.rel}, ${row.child}, ${row.parent}`);
390
390
  }
391
391
  }
392
392
  exports.ScopedCasbinAdapter = ScopedCasbinAdapter;
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../../../../src/components/auth/authorize/adapters/scoped-casbin/adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IdType } from '@/base';\nimport { type Model } from 'casbin';\nimport { sql, type SQL } from 'drizzle-orm';\nimport { GrantBuilder } from '@venizia/ignis-kernel';\nimport {\n AuthorizationActions,\n AuthorizationDecisions,\n AuthorizationDomainScopes,\n AuthorizationPolicyVariants,\n} from '@venizia/ignis-kernel';\nimport { BaseFilteredAdapter } from '../base-filtered';\nimport { CustomGrantExpander, type TCustomGrantRow } from '../custom-grant-expander';\nimport type { ICasbinPolicySource, IScopedCasbinEntities } from '../common';\nimport { PrincipalPolicyEdges, type TPrincipalPolicyRow } from './policy-edges';\nimport {\n DEFAULT_SCHEMA,\n type IScopedCasbinPolicyFilter,\n type TDomainHierarchyEdge,\n type TGrantRow,\n type TResolveDomainEdgesFn,\n} from './common';\n\n/**\n * Filtered casbin adapter for the scoped RBAC model: loads ONE principal's edges (role assignments,\n * memberships, grants) plus the shared structural hierarchy trees as casbin lines. Read-only.\n *\n * EVERY branch below must select by `variant = <known value>` or `variant IN (<known values>)`.\n * Never `variant NOT IN (...)`, and never a bare select that classifies afterwards. Applications\n * store their own edge kinds in this same table (declared via `extraVariants`), and an exclusion\n * filter would sweep those unknown rows into a branch that has no idea what they mean. The current\n * shape makes an undeclared variant inert, which is what makes sharing the table safe.\n */\nexport class ScopedCasbinAdapter extends BaseFilteredAdapter<IScopedCasbinPolicyFilter> {\n protected readonly entities: IScopedCasbinEntities;\n protected readonly customGrantExpander: CustomGrantExpander;\n protected readonly resolveDomainEdges?: TResolveDomainEdgesFn;\n\n constructor(opts: {\n dataSource: ICasbinPolicySource;\n entities: IScopedCasbinEntities;\n resolveDomainEdges?: TResolveDomainEdgesFn;\n }) {\n super({ scope: ScopedCasbinAdapter.name, dataSource: opts.dataSource });\n this.entities = opts.entities;\n this.resolveDomainEdges = opts.resolveDomainEdges;\n this.customGrantExpander = new CustomGrantExpander({\n dataSource: opts.dataSource,\n entities: { permission: opts.entities.permission, softDelete: opts.entities.softDelete },\n });\n }\n\n /**\n * One wave: the principal-scoped CTE and the merged structural-edges query are issued together -\n * the role closure resolves in SQL, so neither waits on the other. `resolveDomainEdges` cannot\n * join that wave - it needs the domain closure the principal-scoped CTE produces - but it does\n * not wait for the structural-edges query either: both run concurrently once the closure is known.\n */\n async loadFilteredPolicy(model: Model, filter: IScopedCasbinPolicyFilter): Promise<void> {\n const { principal } = filter;\n const { principals } = this.entities;\n\n const principalPoliciesPromise = this.queryPrincipalPolicies({ principal });\n const structuralEdgesPromise = this.queryEdgePolicies();\n const principalRows = await principalPoliciesPromise;\n\n const lines: string[] = [];\n const directGrants: TGrantRow[] = [];\n const roleGrants: TGrantRow[] = [];\n const domainClosure = new Set<string>();\n\n for (const row of principalRows) {\n switch (row.kind) {\n case PrincipalPolicyEdges.ROLE_EDGE: {\n lines.push(\n `${AuthorizationPolicyVariants.ROLE_INHERITS.rule}, ${principals.role}_${row.subjectId}, ${principals.role}_${row.targetId}, *`,\n );\n break;\n }\n\n case PrincipalPolicyEdges.ROLE_GRANT: {\n roleGrants.push(row);\n break;\n }\n\n case PrincipalPolicyEdges.DOMAIN_EDGE: {\n lines.push(\n `${AuthorizationPolicyVariants.DOMAIN_INHERITS.rule}, ${row.subjectId}, ${row.targetId}`,\n );\n // Both ends are, by construction, members of the principal's domain_closure CTE.\n domainClosure.add(String(row.subjectId));\n domainClosure.add(String(row.targetId));\n break;\n }\n\n default: {\n if (row.variant === AuthorizationPolicyVariants.JOIN_DOMAIN.action) {\n domainClosure.add(`${row.targetType}_${row.targetId}`);\n }\n this.collectDirectRow({ row, principal, lines, directGrants });\n break;\n }\n }\n }\n\n const hookLinesPromise = this.resolveDomainEdgeLines({\n principal,\n domains: [...domainClosure],\n });\n\n lines.push(\n ...(await this.buildGrantLines({ subjectType: principal.type, rows: directGrants })),\n );\n lines.push(...(await this.buildGrantLines({ subjectType: principals.role, rows: roleGrants })));\n\n const [structuralEdges, hookLines] = await Promise.all([\n structuralEdgesPromise,\n hookLinesPromise,\n ]);\n lines.push(...structuralEdges);\n lines.push(...hookLines);\n\n await this.loadLines({ model, lines });\n }\n\n /** Route one `direct` row to its casbin line, or to the grant batch. */\n protected collectDirectRow(opts: {\n row: TPrincipalPolicyRow;\n principal: { type: string; id: IdType };\n lines: string[];\n directGrants: TGrantRow[];\n }): void {\n const { row, principal, lines, directGrants } = opts;\n const { principals } = this.entities;\n\n switch (row.variant) {\n case AuthorizationPolicyVariants.ASSIGN_ROLE.action: {\n lines.push(\n `${AuthorizationPolicyVariants.ASSIGN_ROLE.rule}, ${principal.type}_${principal.id}, ${principals.role}_${row.targetId}, ${row.domain ?? '*'}`,\n );\n break;\n }\n\n case AuthorizationPolicyVariants.JOIN_DOMAIN.action: {\n lines.push(\n `${AuthorizationPolicyVariants.JOIN_DOMAIN.rule}, ${principal.type}_${principal.id}, ${row.targetType}_${row.targetId}`,\n );\n break;\n }\n\n case AuthorizationPolicyVariants.GRANT.action: {\n directGrants.push(row);\n break;\n }\n\n default: {\n this.logger\n .for(this.collectDirectRow.name)\n .error('Unexpected variant in the direct branch | variant: %s', row.variant);\n break;\n }\n }\n }\n\n /**\n * Calls the `resolveDomainEdges` hook, if supplied, and turns its edges into `g3` lines using\n * the same shape the DOMAIN_EDGE branch emits. A throwing hook is logged and treated as no\n * edges - the rows already gathered for this principal still load. This is the safe direction:\n * a missing hierarchy edge can only narrow what `g`/`g2`/`g3` reach, never widen it, so the\n * failure degrades to less access rather than either an outage or excess access.\n */\n protected async resolveDomainEdgeLines(opts: {\n principal: { type: string; id: IdType };\n domains: string[];\n }): Promise<string[]> {\n if (!this.resolveDomainEdges) {\n return [];\n }\n\n let edges: TDomainHierarchyEdge[];\n try {\n edges = await this.resolveDomainEdges(opts);\n } catch (error) {\n this.logger\n .for(this.resolveDomainEdgeLines.name)\n .error(\n 'resolveDomainEdges hook threw - continuing without its edges for this load | principal: %s_%s | error: %s',\n opts.principal.type,\n opts.principal.id,\n error,\n );\n return [];\n }\n\n return edges.map(\n edge => `${AuthorizationPolicyVariants.DOMAIN_INHERITS.rule}, ${edge.child}, ${edge.parent}`,\n );\n }\n\n /** Schema for a table, defaulting to `public`. */\n protected schemaOf(table: { schemaName?: string }): string {\n return table.schemaName ?? DEFAULT_SCHEMA;\n }\n\n /** The casbin domain token, built from the stored pair - one expression for every SELECT so they cannot drift. NULL reaches `buildGrantLines` as `ANY_MEMBER`. The alias is emitted raw for the same reason as in `softDeleteClause`: quoting folds it to a different case than the unquoted FROM alias. */\n protected domainTokenSelection(opts: { alias: string }): SQL {\n const column = (name: string) => sql`${sql.raw(opts.alias)}.${sql.identifier(name)}`;\n const domainType = column('domain_type');\n const domainId = column('domain_id');\n\n return sql`CASE\n WHEN ${domainType} IS NULL THEN NULL\n WHEN ${domainId} IS NULL THEN ${domainType}\n ELSE ${domainType} || '_' || ${domainId}::text\n END AS \"domain\"`;\n }\n\n /** Schema-qualified table reference (`\"<schema>\".\"<table>\"`) for use after FROM/JOIN with an alias. */\n protected qualifiedTable(opts: { table: { schemaName?: string; tableName: string } }): SQL {\n const { table } = opts;\n return sql`${sql.identifier(this.schemaOf(table))}.${sql.identifier(table.tableName)}`;\n }\n\n /** `AND <alias>.<col> IS NULL` when soft-delete is on, else empty. The alias is emitted raw to match the unquoted FROM alias - quoting folds it to a different case and breaks the join. */\n protected softDeleteClause(opts: { alias: string }): SQL {\n const sd = this.entities.softDelete;\n if (!sd?.use) {\n return sql.empty();\n }\n\n return sql` AND ${sql.raw(opts.alias)}.${sql.identifier(sd.columnName)} IS NULL`;\n }\n\n /** One statement for everything scoped to a principal: its own edges, the role_inherits edges reachable from its roles, and the grants of that closure. `UNION` in the recursive term is what terminates a cyclic role graph. */\n protected async queryPrincipalPolicies(opts: {\n principal: { type: string; id: IdType };\n }): Promise<TPrincipalPolicyRow[]> {\n const { policyDefinition, permission, principals, domainTypes } = this.entities;\n const policyDefinitionTable = this.qualifiedTable({ table: policyDefinition });\n const permissionTable = this.qualifiedTable({ table: permission });\n const { principal } = opts;\n\n const metadataColumnName = policyDefinition.metadata?.columnName;\n const metadataSelection = metadataColumnName\n ? sql`, policyDefinition.${sql.identifier(metadataColumnName)} AS \"metadata\"`\n : sql.empty();\n const metadataNull = metadataColumnName ? sql`, NULL::jsonb AS \"metadata\"` : sql.empty();\n\n const domainTypeList = sql.join(\n domainTypes.map(domainType => sql`${domainType}`),\n sql`, `,\n );\n\n const rows = await this.query<TPrincipalPolicyRow>({\n statement: sql`\n WITH RECURSIVE role_closure AS (\n SELECT policyDefinition.target_id AS role_id\n FROM ${policyDefinitionTable} policyDefinition\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.ASSIGN_ROLE.action}\n AND policyDefinition.subject_type = ${principal.type}\n AND policyDefinition.subject_id = ${principal.id}\n AND policyDefinition.target_type = ${principals.role}${this.softDeleteClause({ alias: 'policyDefinition' })}\n\n UNION\n\n SELECT policyDefinition.target_id\n FROM ${policyDefinitionTable} policyDefinition\n JOIN role_closure ON policyDefinition.subject_id = role_closure.role_id\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.ROLE_INHERITS.action}${this.softDeleteClause({ alias: 'policyDefinition' })}\n ),\n\n domain_closure AS (\n SELECT policyDefinition.target_type AS dom_type, policyDefinition.target_id AS dom_id\n FROM ${policyDefinitionTable} policyDefinition\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.JOIN_DOMAIN.action}\n AND policyDefinition.subject_type = ${principal.type}\n AND policyDefinition.subject_id = ${principal.id}\n AND policyDefinition.target_type IN (${domainTypeList})${this.softDeleteClause({ alias: 'policyDefinition' })}\n\n UNION\n\n SELECT policyDefinition.target_type, policyDefinition.target_id\n FROM ${policyDefinitionTable} policyDefinition\n JOIN domain_closure ON policyDefinition.subject_type = domain_closure.dom_type\n AND policyDefinition.subject_id = domain_closure.dom_id\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.DOMAIN_INHERITS.action}${this.softDeleteClause({ alias: 'policyDefinition' })}\n )\n\n SELECT\n ${PrincipalPolicyEdges.DIRECT}::text AS \"kind\",\n policyDefinition.variant,\n policyDefinition.subject_id::text AS \"subjectId\",\n policyDefinition.target_type AS \"targetType\",\n policyDefinition.target_id::text AS \"targetId\",\n policyDefinition.action,\n policyDefinition.effect,\n ${this.domainTokenSelection({ alias: 'policyDefinition' })},\n permission.code AS \"objectCode\",\n permission.subject AS \"objectSubject\",\n permission.method AS \"objectMethod\"${metadataSelection}\n FROM ${policyDefinitionTable} policyDefinition\n LEFT JOIN ${permissionTable} permission\n ON policyDefinition.target_id = permission.id${this.softDeleteClause({ alias: 'permission' })}\n WHERE policyDefinition.subject_type = ${principal.type}\n AND policyDefinition.subject_id = ${principal.id}\n AND policyDefinition.variant IN (\n ${AuthorizationPolicyVariants.ASSIGN_ROLE.action},\n ${AuthorizationPolicyVariants.JOIN_DOMAIN.action},\n ${AuthorizationPolicyVariants.GRANT.action}\n )\n AND (\n policyDefinition.variant <> ${AuthorizationPolicyVariants.JOIN_DOMAIN.action}\n OR policyDefinition.target_type IN (${domainTypeList})\n )${this.softDeleteClause({ alias: 'policyDefinition' })}\n\n UNION ALL\n\n SELECT\n ${PrincipalPolicyEdges.ROLE_EDGE}::text AS \"kind\",\n policyDefinition.variant,\n policyDefinition.subject_id::text AS \"subjectId\",\n policyDefinition.target_type AS \"targetType\",\n policyDefinition.target_id::text AS \"targetId\",\n NULL AS \"action\",\n NULL AS \"effect\",\n NULL AS \"domain\",\n NULL AS \"objectCode\",\n NULL AS \"objectSubject\",\n NULL AS \"objectMethod\"${metadataNull}\n FROM ${policyDefinitionTable} policyDefinition\n JOIN role_closure ON policyDefinition.subject_id = role_closure.role_id\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.ROLE_INHERITS.action}${this.softDeleteClause({ alias: 'policyDefinition' })}\n\n UNION ALL\n\n SELECT\n ${PrincipalPolicyEdges.ROLE_GRANT}::text AS \"kind\",\n policyDefinition.variant,\n policyDefinition.subject_id::text AS \"subjectId\",\n policyDefinition.target_type AS \"targetType\",\n policyDefinition.target_id::text AS \"targetId\",\n policyDefinition.action,\n policyDefinition.effect,\n ${this.domainTokenSelection({ alias: 'policyDefinition' })},\n permission.code AS \"objectCode\",\n permission.subject AS \"objectSubject\",\n permission.method AS \"objectMethod\"${metadataSelection}\n FROM ${policyDefinitionTable} policyDefinition\n JOIN role_closure ON policyDefinition.subject_id = role_closure.role_id\n LEFT JOIN ${permissionTable} permission\n ON policyDefinition.target_id = permission.id${this.softDeleteClause({ alias: 'permission' })}\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.GRANT.action}\n AND policyDefinition.subject_type = ${principals.role}${this.softDeleteClause({ alias: 'policyDefinition' })}\n\n UNION ALL\n\n SELECT\n ${PrincipalPolicyEdges.DOMAIN_EDGE}::text AS \"kind\",\n policyDefinition.variant,\n policyDefinition.subject_type || '_' || policyDefinition.subject_id::text AS \"subjectId\",\n NULL AS \"targetType\",\n policyDefinition.target_type || '_' || policyDefinition.target_id::text AS \"targetId\",\n NULL AS \"action\",\n NULL AS \"effect\",\n NULL AS \"domain\",\n NULL AS \"objectCode\",\n NULL AS \"objectSubject\",\n NULL AS \"objectMethod\"${metadataNull}\n FROM ${policyDefinitionTable} policyDefinition\n JOIN domain_closure ON policyDefinition.subject_type = domain_closure.dom_type\n AND policyDefinition.subject_id = domain_closure.dom_id\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.DOMAIN_INHERITS.action}${this.softDeleteClause({ alias: 'policyDefinition' })}\n `,\n });\n\n return rows;\n }\n\n /** Turn fetched grant rows into casbin lines. Shared by the direct and role-closure branches. */\n protected async buildGrantLines(opts: {\n subjectType: string;\n rows: TGrantRow[];\n }): Promise<string[]> {\n const { subjectType, rows } = opts;\n const metadataColumnName = this.entities.policyDefinition.metadata?.columnName;\n\n const lines: string[] = [];\n const customRows: TCustomGrantRow[] = [];\n\n for (const row of rows) {\n if (!row.objectCode) {\n this.logger\n .for(this.buildGrantLines.name)\n .error(\n 'Skipping grant row whose permission did not resolve - the target is missing or soft-deleted | subject: %s_%s',\n subjectType,\n row.subjectId,\n );\n continue;\n }\n\n const domain = row.domain ?? AuthorizationDomainScopes.ANY_MEMBER;\n const effect = row.effect ?? AuthorizationDecisions.ALLOW;\n const parsed = metadataColumnName\n ? GrantBuilder.getInstance().parseCustomGrantMetadata({ metadata: row.metadata })\n : null;\n const isCustomAction = row.action === AuthorizationActions.CUSTOM;\n const isCustomRow = isCustomAction || Boolean(parsed);\n\n if (!isCustomRow && !row.action) {\n this.logger\n .for(this.buildGrantLines.name)\n .error(\n 'Skipping grant row with no action - the permission it should confer is silently missing | subject: %s_%s | object: %s',\n subjectType,\n row.subjectId,\n row.objectCode,\n );\n continue;\n }\n\n if (!isCustomRow) {\n lines.push(\n `${AuthorizationPolicyVariants.GRANT.rule}, ${subjectType}_${row.subjectId}, ${domain}, ${row.objectCode}, ${row.action}, ${effect}`,\n );\n continue;\n }\n\n if (!row.objectSubject || !row.objectMethod) {\n this.logger\n .for(this.buildGrantLines.name)\n .error(\n 'Skipping custom grant row whose subject or method did not resolve - the target is missing or soft-deleted | subject: %s_%s | object: %s',\n subjectType,\n row.subjectId,\n row.objectCode,\n );\n continue;\n }\n\n const rejection = this.customGrantExpander.rejectCustomRow({\n row: {\n subjectId: row.subjectId,\n objectCode: row.objectCode,\n objectMethod: row.objectMethod,\n },\n parsed,\n isCustomAction,\n metadataColumnName,\n });\n\n if (rejection) {\n this.logger.for(this.buildGrantLines.name).error(rejection);\n continue;\n }\n\n customRows.push({\n subjectId: row.subjectId,\n objectSubject: row.objectSubject,\n ops: parsed!.ops,\n domain,\n effect,\n });\n }\n\n const expanded = await this.customGrantExpander.expandCustomGrants({ subjectType, customRows });\n for (const rejection of expanded.rejections) {\n this.logger.for(this.buildGrantLines.name).error(rejection);\n }\n lines.push(...expanded.lines);\n\n return lines;\n }\n\n /** The two code-fixed structural trees only (`g4` resource, `g5` action) - constant regardless of tenant count. Domain edges (`g3`) grow with the domain count, so they are principal-scoped in {@link queryPrincipalPolicies} instead. */\n protected async queryEdgePolicies(): Promise<string[]> {\n const { policyDefinition, permission } = this.entities;\n const policyDefinitionTable = this.qualifiedTable({ table: policyDefinition });\n const permissionTable = this.qualifiedTable({ table: permission });\n\n const rows = await this.query<{ rel: string; child: string; parent: string }>({\n statement: sql`\n SELECT\n ${AuthorizationPolicyVariants.RESOURCE_INHERITS.rule} AS \"rel\",\n child_permission.code AS \"child\",\n parent_permission.code AS \"parent\"\n FROM ${policyDefinitionTable} policyDefinition\n INNER JOIN ${permissionTable} child_permission ON policyDefinition.subject_id = child_permission.id\n INNER JOIN ${permissionTable} parent_permission ON policyDefinition.target_id = parent_permission.id\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.RESOURCE_INHERITS.action}${this.softDeleteClause({ alias: 'policyDefinition' })}\n\n UNION ALL\n\n SELECT\n ${AuthorizationPolicyVariants.ACTION_INHERITS.rule} AS \"rel\",\n policyDefinition.subject_id::text AS \"child\",\n policyDefinition.target_id::text AS \"parent\"\n FROM ${policyDefinitionTable} policyDefinition\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.ACTION_INHERITS.action}${this.softDeleteClause({ alias: 'policyDefinition' })}\n `,\n });\n\n return rows.map(row => `${row.rel}, ${row.child}, ${row.parent}`);\n }\n}\n"]}
1
+ {"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../../../../src/components/auth/authorize/adapters/scoped-casbin/adapter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IdType } from '@/base';\nimport { type Model } from 'casbin';\nimport { sql, type SQL } from 'drizzle-orm';\nimport { GrantBuilder } from '@venizia/ignis-kernel';\nimport {\n AuthorizationActions,\n AuthorizationDecisions,\n AuthorizationDomainScopes,\n AuthorizationPolicyVariants,\n} from '@venizia/ignis-kernel';\nimport { BaseFilteredAdapter } from '../base-filtered';\nimport { CustomGrantExpander, type TCustomGrantRow } from '../custom-grant-expander';\nimport type { ICasbinPolicySource, IScopedCasbinEntities } from '../common';\nimport { PrincipalPolicyEdges, type TPrincipalPolicyRow } from './policy-edges';\nimport {\n DEFAULT_SCHEMA,\n type IScopedCasbinPolicyFilter,\n type TDomainHierarchyEdge,\n type TGrantRow,\n type TResolveDomainEdgesFn,\n} from './common';\n\n/**\n * Filtered casbin adapter for the scoped RBAC model: loads ONE principal's edges (role assignments,\n * memberships, grants) plus the shared structural hierarchy trees as casbin lines. Read-only.\n *\n * EVERY branch below must select by `variant = <known value>` or `variant IN (<known values>)`.\n * Never `variant NOT IN (...)`, and never a bare select that classifies afterwards. Applications\n * store their own edge kinds in this same table (declared via `extraVariants`), and an exclusion\n * filter would sweep those unknown rows into a branch that has no idea what they mean. The current\n * shape makes an undeclared variant inert, which is what makes sharing the table safe.\n */\nexport class ScopedCasbinAdapter extends BaseFilteredAdapter<IScopedCasbinPolicyFilter> {\n protected readonly entities: IScopedCasbinEntities;\n protected readonly customGrantExpander: CustomGrantExpander;\n protected readonly resolveDomainEdges?: TResolveDomainEdgesFn;\n\n constructor(opts: {\n dataSource: ICasbinPolicySource;\n entities: IScopedCasbinEntities;\n resolveDomainEdges?: TResolveDomainEdgesFn;\n }) {\n super({ scope: ScopedCasbinAdapter.name, dataSource: opts.dataSource });\n this.entities = opts.entities;\n this.resolveDomainEdges = opts.resolveDomainEdges;\n this.customGrantExpander = new CustomGrantExpander({\n dataSource: opts.dataSource,\n entities: { permission: opts.entities.permission, softDelete: opts.entities.softDelete },\n });\n }\n\n /**\n * One wave: the principal-scoped CTE and the merged structural-edges query are issued together -\n * the role closure resolves in SQL, so neither waits on the other. `resolveDomainEdges` cannot\n * join that wave - it needs the domain closure the principal-scoped CTE produces - but it does\n * not wait for the structural-edges query either: both run concurrently once the closure is known.\n */\n async loadFilteredPolicy(model: Model, filter: IScopedCasbinPolicyFilter): Promise<void> {\n const { principal } = filter;\n const { principals } = this.entities;\n\n const principalPoliciesPromise = this.queryPrincipalPolicies({ principal });\n const structuralEdgesPromise = this.queryEdgePolicies();\n const principalRows = await principalPoliciesPromise;\n\n const lines: string[] = [];\n const directGrants: TGrantRow[] = [];\n const roleGrants: TGrantRow[] = [];\n const domainClosure = new Set<string>();\n\n for (const row of principalRows) {\n switch (row.kind) {\n case PrincipalPolicyEdges.ROLE_EDGE: {\n lines.push(\n `${AuthorizationPolicyVariants.ROLE_INHERITS.rule}, ${principals.role}_${row.subjectId}, ${principals.role}_${row.targetId}, *`,\n );\n break;\n }\n\n case PrincipalPolicyEdges.ROLE_GRANT: {\n roleGrants.push(row);\n break;\n }\n\n case PrincipalPolicyEdges.DOMAIN_EDGE: {\n lines.push(\n `${AuthorizationPolicyVariants.DOMAIN_INHERITS.rule}, ${row.subjectId}, ${row.targetId}`,\n );\n // Both ends are, by construction, members of the principal's domain_closure CTE.\n domainClosure.add(String(row.subjectId));\n domainClosure.add(String(row.targetId));\n break;\n }\n\n default: {\n if (row.variant === AuthorizationPolicyVariants.JOIN_DOMAIN.action) {\n domainClosure.add(`${row.targetType}_${row.targetId}`);\n }\n this.collectDirectRow({ row, principal, lines, directGrants });\n break;\n }\n }\n }\n\n const hookLinesPromise = this.resolveDomainEdgeLines({\n principal,\n domains: [...domainClosure],\n });\n\n lines.push(\n ...(await this.buildGrantLines({ subjectType: principal.type, rows: directGrants })),\n );\n lines.push(...(await this.buildGrantLines({ subjectType: principals.role, rows: roleGrants })));\n\n const [structuralEdges, hookLines] = await Promise.all([\n structuralEdgesPromise,\n hookLinesPromise,\n ]);\n lines.push(...structuralEdges);\n lines.push(...hookLines);\n\n await this.loadLines({ model, lines });\n }\n\n /** Route one `direct` row to its casbin line, or to the grant batch. */\n protected collectDirectRow(opts: {\n row: TPrincipalPolicyRow;\n principal: { type: string; id: IdType };\n lines: string[];\n directGrants: TGrantRow[];\n }): void {\n const { row, principal, lines, directGrants } = opts;\n const { principals } = this.entities;\n\n switch (row.variant) {\n case AuthorizationPolicyVariants.ASSIGN_ROLE.action: {\n lines.push(\n `${AuthorizationPolicyVariants.ASSIGN_ROLE.rule}, ${principal.type}_${principal.id}, ${principals.role}_${row.targetId}, ${row.domain ?? '*'}`,\n );\n break;\n }\n\n case AuthorizationPolicyVariants.JOIN_DOMAIN.action: {\n lines.push(\n `${AuthorizationPolicyVariants.JOIN_DOMAIN.rule}, ${principal.type}_${principal.id}, ${row.targetType}_${row.targetId}`,\n );\n break;\n }\n\n case AuthorizationPolicyVariants.GRANT.action: {\n directGrants.push(row);\n break;\n }\n\n default: {\n this.logger\n .for(this.collectDirectRow.name)\n .error('Unexpected variant in the direct branch | variant: %s', row.variant);\n break;\n }\n }\n }\n\n /**\n * Calls the `resolveDomainEdges` hook, if supplied, and turns its edges into `g3` lines using\n * the same shape the DOMAIN_EDGE branch emits. A throwing hook is logged and treated as no\n * edges - the rows already gathered for this principal still load. This is the safe direction:\n * a missing hierarchy edge can only narrow what `g`/`g2`/`g3` reach, never widen it, so the\n * failure degrades to less access rather than either an outage or excess access.\n */\n protected async resolveDomainEdgeLines(opts: {\n principal: { type: string; id: IdType };\n domains: string[];\n }): Promise<string[]> {\n if (!this.resolveDomainEdges) {\n return [];\n }\n\n let edges: TDomainHierarchyEdge[];\n try {\n edges = await this.resolveDomainEdges(opts);\n } catch (error) {\n this.logger\n .for(this.resolveDomainEdgeLines.name)\n .error(\n 'resolveDomainEdges hook threw - continuing without its edges for this load | principal: %s_%s | error: %s',\n opts.principal.type,\n opts.principal.id,\n error,\n );\n return [];\n }\n\n return edges.map(\n (edge) =>\n `${AuthorizationPolicyVariants.DOMAIN_INHERITS.rule}, ${edge.child}, ${edge.parent}`,\n );\n }\n\n /** Schema for a table, defaulting to `public`. */\n protected schemaOf(table: { schemaName?: string }): string {\n return table.schemaName ?? DEFAULT_SCHEMA;\n }\n\n /** The casbin domain token, built from the stored pair - one expression for every SELECT so they cannot drift. NULL reaches `buildGrantLines` as `ANY_MEMBER`. The alias is emitted raw for the same reason as in `softDeleteClause`: quoting folds it to a different case than the unquoted FROM alias. */\n protected domainTokenSelection(opts: { alias: string }): SQL {\n const column = (name: string) => sql`${sql.raw(opts.alias)}.${sql.identifier(name)}`;\n const domainType = column('domain_type');\n const domainId = column('domain_id');\n\n return sql`CASE\n WHEN ${domainType} IS NULL THEN NULL\n WHEN ${domainId} IS NULL THEN ${domainType}\n ELSE ${domainType} || '_' || ${domainId}::text\n END AS \"domain\"`;\n }\n\n /** Schema-qualified table reference (`\"<schema>\".\"<table>\"`) for use after FROM/JOIN with an alias. */\n protected qualifiedTable(opts: { table: { schemaName?: string; tableName: string } }): SQL {\n const { table } = opts;\n return sql`${sql.identifier(this.schemaOf(table))}.${sql.identifier(table.tableName)}`;\n }\n\n /** `AND <alias>.<col> IS NULL` when soft-delete is on, else empty. The alias is emitted raw to match the unquoted FROM alias - quoting folds it to a different case and breaks the join. */\n protected softDeleteClause(opts: { alias: string }): SQL {\n const sd = this.entities.softDelete;\n if (!sd?.use) {\n return sql.empty();\n }\n\n return sql` AND ${sql.raw(opts.alias)}.${sql.identifier(sd.columnName)} IS NULL`;\n }\n\n /** One statement for everything scoped to a principal: its own edges, the role_inherits edges reachable from its roles, and the grants of that closure. `UNION` in the recursive term is what terminates a cyclic role graph. */\n protected async queryPrincipalPolicies(opts: {\n principal: { type: string; id: IdType };\n }): Promise<TPrincipalPolicyRow[]> {\n const { policyDefinition, permission, principals, domainTypes } = this.entities;\n const policyDefinitionTable = this.qualifiedTable({ table: policyDefinition });\n const permissionTable = this.qualifiedTable({ table: permission });\n const { principal } = opts;\n\n const metadataColumnName = policyDefinition.metadata?.columnName;\n const metadataSelection = metadataColumnName\n ? sql`, policyDefinition.${sql.identifier(metadataColumnName)} AS \"metadata\"`\n : sql.empty();\n const metadataNull = metadataColumnName ? sql`, NULL::jsonb AS \"metadata\"` : sql.empty();\n\n const domainTypeList = sql.join(\n domainTypes.map((domainType) => sql`${domainType}`),\n sql`, `,\n );\n\n const rows = await this.query<TPrincipalPolicyRow>({\n statement: sql`\n WITH RECURSIVE role_closure AS (\n SELECT policyDefinition.target_id AS role_id\n FROM ${policyDefinitionTable} policyDefinition\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.ASSIGN_ROLE.action}\n AND policyDefinition.subject_type = ${principal.type}\n AND policyDefinition.subject_id = ${principal.id}\n AND policyDefinition.target_type = ${principals.role}${this.softDeleteClause({ alias: 'policyDefinition' })}\n\n UNION\n\n SELECT policyDefinition.target_id\n FROM ${policyDefinitionTable} policyDefinition\n JOIN role_closure ON policyDefinition.subject_id = role_closure.role_id\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.ROLE_INHERITS.action}${this.softDeleteClause({ alias: 'policyDefinition' })}\n ),\n\n domain_closure AS (\n SELECT policyDefinition.target_type AS dom_type, policyDefinition.target_id AS dom_id\n FROM ${policyDefinitionTable} policyDefinition\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.JOIN_DOMAIN.action}\n AND policyDefinition.subject_type = ${principal.type}\n AND policyDefinition.subject_id = ${principal.id}\n AND policyDefinition.target_type IN (${domainTypeList})${this.softDeleteClause({ alias: 'policyDefinition' })}\n\n UNION\n\n SELECT policyDefinition.target_type, policyDefinition.target_id\n FROM ${policyDefinitionTable} policyDefinition\n JOIN domain_closure ON policyDefinition.subject_type = domain_closure.dom_type\n AND policyDefinition.subject_id = domain_closure.dom_id\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.DOMAIN_INHERITS.action}${this.softDeleteClause({ alias: 'policyDefinition' })}\n )\n\n SELECT\n ${PrincipalPolicyEdges.DIRECT}::text AS \"kind\",\n policyDefinition.variant,\n policyDefinition.subject_id::text AS \"subjectId\",\n policyDefinition.target_type AS \"targetType\",\n policyDefinition.target_id::text AS \"targetId\",\n policyDefinition.action,\n policyDefinition.effect,\n ${this.domainTokenSelection({ alias: 'policyDefinition' })},\n permission.code AS \"objectCode\",\n permission.subject AS \"objectSubject\",\n permission.method AS \"objectMethod\"${metadataSelection}\n FROM ${policyDefinitionTable} policyDefinition\n LEFT JOIN ${permissionTable} permission\n ON policyDefinition.target_id = permission.id${this.softDeleteClause({ alias: 'permission' })}\n WHERE policyDefinition.subject_type = ${principal.type}\n AND policyDefinition.subject_id = ${principal.id}\n AND policyDefinition.variant IN (\n ${AuthorizationPolicyVariants.ASSIGN_ROLE.action},\n ${AuthorizationPolicyVariants.JOIN_DOMAIN.action},\n ${AuthorizationPolicyVariants.GRANT.action}\n )\n AND (\n policyDefinition.variant <> ${AuthorizationPolicyVariants.JOIN_DOMAIN.action}\n OR policyDefinition.target_type IN (${domainTypeList})\n )${this.softDeleteClause({ alias: 'policyDefinition' })}\n\n UNION ALL\n\n SELECT\n ${PrincipalPolicyEdges.ROLE_EDGE}::text AS \"kind\",\n policyDefinition.variant,\n policyDefinition.subject_id::text AS \"subjectId\",\n policyDefinition.target_type AS \"targetType\",\n policyDefinition.target_id::text AS \"targetId\",\n NULL AS \"action\",\n NULL AS \"effect\",\n NULL AS \"domain\",\n NULL AS \"objectCode\",\n NULL AS \"objectSubject\",\n NULL AS \"objectMethod\"${metadataNull}\n FROM ${policyDefinitionTable} policyDefinition\n JOIN role_closure ON policyDefinition.subject_id = role_closure.role_id\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.ROLE_INHERITS.action}${this.softDeleteClause({ alias: 'policyDefinition' })}\n\n UNION ALL\n\n SELECT\n ${PrincipalPolicyEdges.ROLE_GRANT}::text AS \"kind\",\n policyDefinition.variant,\n policyDefinition.subject_id::text AS \"subjectId\",\n policyDefinition.target_type AS \"targetType\",\n policyDefinition.target_id::text AS \"targetId\",\n policyDefinition.action,\n policyDefinition.effect,\n ${this.domainTokenSelection({ alias: 'policyDefinition' })},\n permission.code AS \"objectCode\",\n permission.subject AS \"objectSubject\",\n permission.method AS \"objectMethod\"${metadataSelection}\n FROM ${policyDefinitionTable} policyDefinition\n JOIN role_closure ON policyDefinition.subject_id = role_closure.role_id\n LEFT JOIN ${permissionTable} permission\n ON policyDefinition.target_id = permission.id${this.softDeleteClause({ alias: 'permission' })}\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.GRANT.action}\n AND policyDefinition.subject_type = ${principals.role}${this.softDeleteClause({ alias: 'policyDefinition' })}\n\n UNION ALL\n\n SELECT\n ${PrincipalPolicyEdges.DOMAIN_EDGE}::text AS \"kind\",\n policyDefinition.variant,\n policyDefinition.subject_type || '_' || policyDefinition.subject_id::text AS \"subjectId\",\n NULL AS \"targetType\",\n policyDefinition.target_type || '_' || policyDefinition.target_id::text AS \"targetId\",\n NULL AS \"action\",\n NULL AS \"effect\",\n NULL AS \"domain\",\n NULL AS \"objectCode\",\n NULL AS \"objectSubject\",\n NULL AS \"objectMethod\"${metadataNull}\n FROM ${policyDefinitionTable} policyDefinition\n JOIN domain_closure ON policyDefinition.subject_type = domain_closure.dom_type\n AND policyDefinition.subject_id = domain_closure.dom_id\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.DOMAIN_INHERITS.action}${this.softDeleteClause({ alias: 'policyDefinition' })}\n `,\n });\n\n return rows;\n }\n\n /** Turn fetched grant rows into casbin lines. Shared by the direct and role-closure branches. */\n protected async buildGrantLines(opts: {\n subjectType: string;\n rows: TGrantRow[];\n }): Promise<string[]> {\n const { subjectType, rows } = opts;\n const metadataColumnName = this.entities.policyDefinition.metadata?.columnName;\n\n const lines: string[] = [];\n const customRows: TCustomGrantRow[] = [];\n\n for (const row of rows) {\n if (!row.objectCode) {\n this.logger\n .for(this.buildGrantLines.name)\n .error(\n 'Skipping grant row whose permission did not resolve - the target is missing or soft-deleted | subject: %s_%s',\n subjectType,\n row.subjectId,\n );\n continue;\n }\n\n const domain = row.domain ?? AuthorizationDomainScopes.ANY_MEMBER;\n const effect = row.effect ?? AuthorizationDecisions.ALLOW;\n const parsed = metadataColumnName\n ? GrantBuilder.getInstance().parseCustomGrantMetadata({ metadata: row.metadata })\n : null;\n const isCustomAction = row.action === AuthorizationActions.CUSTOM;\n const isCustomRow = isCustomAction || Boolean(parsed);\n\n if (!isCustomRow && !row.action) {\n this.logger\n .for(this.buildGrantLines.name)\n .error(\n 'Skipping grant row with no action - the permission it should confer is silently missing | subject: %s_%s | object: %s',\n subjectType,\n row.subjectId,\n row.objectCode,\n );\n continue;\n }\n\n if (!isCustomRow) {\n lines.push(\n `${AuthorizationPolicyVariants.GRANT.rule}, ${subjectType}_${row.subjectId}, ${domain}, ${row.objectCode}, ${row.action}, ${effect}`,\n );\n continue;\n }\n\n if (!row.objectSubject || !row.objectMethod) {\n this.logger\n .for(this.buildGrantLines.name)\n .error(\n 'Skipping custom grant row whose subject or method did not resolve - the target is missing or soft-deleted | subject: %s_%s | object: %s',\n subjectType,\n row.subjectId,\n row.objectCode,\n );\n continue;\n }\n\n const rejection = this.customGrantExpander.rejectCustomRow({\n row: {\n subjectId: row.subjectId,\n objectCode: row.objectCode,\n objectMethod: row.objectMethod,\n },\n parsed,\n isCustomAction,\n metadataColumnName,\n });\n\n if (rejection) {\n this.logger.for(this.buildGrantLines.name).error(rejection);\n continue;\n }\n\n customRows.push({\n subjectId: row.subjectId,\n objectSubject: row.objectSubject,\n ops: parsed!.ops,\n domain,\n effect,\n });\n }\n\n const expanded = await this.customGrantExpander.expandCustomGrants({ subjectType, customRows });\n for (const rejection of expanded.rejections) {\n this.logger.for(this.buildGrantLines.name).error(rejection);\n }\n lines.push(...expanded.lines);\n\n return lines;\n }\n\n /** The two code-fixed structural trees only (`g4` resource, `g5` action) - constant regardless of tenant count. Domain edges (`g3`) grow with the domain count, so they are principal-scoped in {@link queryPrincipalPolicies} instead. */\n protected async queryEdgePolicies(): Promise<string[]> {\n const { policyDefinition, permission } = this.entities;\n const policyDefinitionTable = this.qualifiedTable({ table: policyDefinition });\n const permissionTable = this.qualifiedTable({ table: permission });\n\n const rows = await this.query<{ rel: string; child: string; parent: string }>({\n statement: sql`\n SELECT\n ${AuthorizationPolicyVariants.RESOURCE_INHERITS.rule} AS \"rel\",\n child_permission.code AS \"child\",\n parent_permission.code AS \"parent\"\n FROM ${policyDefinitionTable} policyDefinition\n INNER JOIN ${permissionTable} child_permission ON policyDefinition.subject_id = child_permission.id\n INNER JOIN ${permissionTable} parent_permission ON policyDefinition.target_id = parent_permission.id\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.RESOURCE_INHERITS.action}${this.softDeleteClause({ alias: 'policyDefinition' })}\n\n UNION ALL\n\n SELECT\n ${AuthorizationPolicyVariants.ACTION_INHERITS.rule} AS \"rel\",\n policyDefinition.subject_id::text AS \"child\",\n policyDefinition.target_id::text AS \"parent\"\n FROM ${policyDefinitionTable} policyDefinition\n WHERE policyDefinition.variant = ${AuthorizationPolicyVariants.ACTION_INHERITS.action}${this.softDeleteClause({ alias: 'policyDefinition' })}\n `,\n });\n\n return rows.map((row) => `${row.rel}, ${row.child}, ${row.parent}`);\n }\n}\n"]}
@@ -70,7 +70,7 @@ let CasbinAuthorizationEnforcer = CasbinAuthorizationEnforcer_1 = class CasbinAu
70
70
  .info('Casbin enforcer pool ready (size: %s, cached: %s)', this.options.poolSize ?? 16, cached.use ? cached.driver : 'none');
71
71
  }
72
72
  destroy() {
73
- this.pool?.destroy().catch(error => {
73
+ this.pool?.destroy().catch((error) => {
74
74
  this.logger.for(this.destroy.name).warn('Pool destroy failed: %s', error);
75
75
  });
76
76
  }
@@ -179,7 +179,7 @@ let CasbinAuthorizationEnforcer = CasbinAuthorizationEnforcer_1 = class CasbinAu
179
179
  }
180
180
  return (this.userPolicyLineCache ??= new user_policy_line_cache_1.UserPolicyLineCache({
181
181
  cached,
182
- loadLines: opts => this.extractUserLines(opts),
182
+ loadLines: (opts) => this.extractUserLines(opts),
183
183
  }));
184
184
  }
185
185
  // Matchers & model resolvers
@@ -1 +1 @@
1
- {"version":3,"file":"casbin.enforcer.js","sourceRoot":"","sources":["../../../../../src/components/auth/authorize/enforcers/casbin.enforcer.ts"],"names":[],"mappings":"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","sourcesContent":["import { type TContext } from '@venizia/ignis-kernel';\nimport { inject } from '@venizia/ignis-kernel';\nimport { BaseHelper, BasePoolHelper, getError } from '@venizia/ignis-helpers/core';\nimport { type TNullable } from '@venizia/ignis-helpers/common';\nimport type {\n Enforcer as CasbinEnforcerType,\n Helper as CasbinHelperType,\n RoleManager as CasbinRoleManagerType,\n} from 'casbin';\nimport { type Env } from 'hono';\nimport { AuthorizationPermissionBuilder } from '@venizia/ignis-kernel';\nimport {\n AuthorizationDecisions,\n AuthorizationDomainScopes,\n AuthorizationEnforcerTypes,\n AuthorizationPolicyVariants,\n AuthorizeBindingKeys,\n CasbinDomainMatchingFunctions,\n CasbinEnforcerModelDrivers,\n CasbinRuleVariants,\n type IAuthorizationEnforcer,\n type IAuthorizationUser,\n type ICasbinEnforcerOptions,\n type ICasbinRules,\n type IAuthorizationRequest,\n type TAuthorizationDecision,\n type TCasbinDomainMatchingFunction,\n} from '@venizia/ignis-kernel';\nimport { DomainHierarchyRoleManager } from '../role-managers/domain-hierarchy';\nimport { CasbinModule } from './casbin-module';\nimport { MembershipRoleManager } from '../role-managers/membership';\nimport { ResourceRoleManager } from '../role-managers/resource';\nimport { PolicyLineCodec } from './policy-line-codec';\nimport { UserPolicyLineCache } from './user-policy-line-cache';\n\n/** Payload shape for the scoped/custom path, matching defaultScopedPayloadFn(). */\ntype TNormalizePayloadFn<E extends Env, TAction, TResource> = (opts: {\n user: IAuthorizationUser;\n action: TAction;\n resource: TResource;\n context: TContext<E, string>;\n}) => { subject: string; resource: string; action: string; domain?: string };\n\n/** `addDomainHierarchy` lives on casbin's `DefaultRoleManager`, not on the `RoleManager` interface or the `Enforcer` facade - feature-detect it on whatever `getNamedRoleManager` returns. */\ninterface ICasbinRoleManagerWithDomainHierarchy {\n addDomainHierarchy?(rm: CasbinRoleManagerType): Promise<void>;\n}\n\n// Wraps casbin (optional peer dep). Each request borrows its own pooled enforcer; any error during use destroys it (fail-closed). Pooled enforcers carry no adapter - only extractUserLines uses one.\n\nexport class CasbinAuthorizationEnforcer<\n E extends Env = Env,\n TAction extends string = string,\n TResource extends string = string,\n>\n extends BaseHelper\n implements IAuthorizationEnforcer<E, TAction, TResource, ICasbinRules>\n{\n name = CasbinAuthorizationEnforcer.name;\n private readonly MIN_EXPIRES_IN = 10_000;\n\n private pool: TNullable<BasePoolHelper<CasbinEnforcerType>> = null;\n private helper: TNullable<typeof CasbinHelperType> = null;\n // Lazily created on first cache use (see requireRedisCache) - one instance for the enforcer's lifetime so its single-flight de-dup map actually dedupes.\n private userPolicyLineCache: TNullable<UserPolicyLineCache> = null;\n\n // Memoized in configure() (options are fixed after) to avoid rebuilding this closure on every evaluate() (hot path).\n private resolvedPayloadFn: TNullable<TNormalizePayloadFn<E, TAction, TResource>> = null;\n\n constructor(\n @inject({ key: AuthorizeBindingKeys.enforcerOptions(AuthorizationEnforcerTypes.CASBIN) })\n private options: ICasbinEnforcerOptions<E, TAction, TResource>,\n ) {\n super({ scope: CasbinAuthorizationEnforcer.name });\n }\n\n // Lifecycle\n\n async configure(): Promise<void> {\n const casbin = await CasbinModule.load();\n\n if (!this.options.model) {\n throw getError({\n message: '[CasbinAuthorizationEnforcer] options.model is required.',\n });\n }\n\n this.helper = casbin.Helper;\n\n this.resolvedPayloadFn = this.options.normalizePayloadFn ?? this.defaultScopedPayloadFn();\n\n const { cached } = this.options;\n if (cached.use) {\n this.validateExpiresIn({ expiresIn: cached.options.expiresIn });\n }\n\n this.pool = new BasePoolHelper<CasbinEnforcerType>({\n scope: `${CasbinAuthorizationEnforcer.name}.Pool`,\n size: this.options.poolSize ?? 16,\n acquireTimeoutMs: this.options.poolAcquireTimeoutMs ?? 5000,\n create: async () => {\n const model = this.resolveModel({ casbin, model: this.options.model });\n\n const enforcer = await casbin.newEnforcer(model);\n await this.registerMatchers({ enforcer, casbin });\n this.assertMatcherCompilesSync({ enforcer });\n\n return enforcer;\n },\n });\n await this.pool.warmup();\n\n this.logger\n .for(this.configure.name)\n .info(\n 'Casbin enforcer pool ready (size: %s, cached: %s)',\n this.options.poolSize ?? 16,\n cached.use ? cached.driver : 'none',\n );\n }\n\n destroy(): void {\n this.pool?.destroy().catch(error => {\n this.logger.for(this.destroy.name).warn('Pool destroy failed: %s', error);\n });\n }\n\n /** casbin compiles the matcher lazily (first enforce, not newEnforcer/buildRoleLinks); this dummy enforceSync forces the compile at warmup so syntax / unregistered-function / arity errors fail boot. */\n protected assertMatcherCompilesSync(opts: { enforcer: CasbinEnforcerType }) {\n try {\n if (this.options.isScoped || this.options.normalizePayloadFn) {\n opts.enforcer.enforceSync('::warmup', '::warmup', '::warmup', '::warmup');\n return;\n }\n\n opts.enforcer.enforceSync('::warmup', '::warmup', '::warmup');\n } catch (error) {\n throw getError({\n message: `[CasbinAuthorizationEnforcer] Matcher smoke test failed at warmup - the model matcher did not compile (check matcher syntax, that every referenced function is registered, and the request arity). ${String(error)}`,\n });\n }\n }\n\n // IAuthorizationEnforcer - public API\n\n async buildRules(opts: {\n user: IAuthorizationUser;\n context: TContext<E, string>;\n }): Promise<ICasbinRules> {\n const { user } = opts;\n const cached = this.options.cached;\n\n const lines = cached.use\n ? await this.requireRedisCache().fetch({ user })\n : await this.extractUserLines({ user });\n\n return { user, lines };\n }\n\n async evaluate(opts: {\n rules: ICasbinRules;\n request: IAuthorizationRequest<TAction, TResource>;\n context: TContext<E, string>;\n }): Promise<TAuthorizationDecision> {\n if (!this.pool) {\n throw getError({\n message: '[CasbinAuthorizationEnforcer] Not configured. Call configure() first.',\n });\n }\n\n if (!opts.request?.action || !opts.request?.resource) {\n throw getError({\n message: '[CasbinAuthorizationEnforcer] request.action and request.resource are required.',\n });\n }\n\n const { rules, request, context } = opts;\n const { user, lines } = rules;\n\n return this.pool.use({\n execution: async enforcer => {\n await this.loadPolicyLinesIntoModel({ enforcer, lines });\n\n const normalizePayloadFn = this.resolvedPayloadFn;\n\n if (!normalizePayloadFn) {\n const subject = `${user.principalType}_${user.userId}`;\n const isAllowed = this.enforceWithExplain({\n enforcer,\n vals: [subject, String(request.resource), String(request.action)],\n });\n return isAllowed ? AuthorizationDecisions.ALLOW : AuthorizationDecisions.DENY;\n }\n\n const normalized = normalizePayloadFn({\n user,\n action: request.action,\n resource: request.resource,\n context,\n });\n\n // Scoped model is 4-token (sub, dom, obj, act): a request with no resolvable domain still needs one - default SYSTEM_WIDE, never the 3-arg path, which misaligns args and silently misjudges.\n const domain =\n normalized.domain ??\n request.domain ??\n (this.options.isScoped ? AuthorizationDomainScopes.SYSTEM_WIDE : undefined);\n\n const vals = domain\n ? [normalized.subject, domain, normalized.resource, normalized.action]\n : [normalized.subject, normalized.resource, normalized.action];\n const isAllowed = this.enforceWithExplain({ enforcer, vals });\n\n return isAllowed ? AuthorizationDecisions.ALLOW : AuthorizationDecisions.DENY;\n },\n });\n }\n\n /** On DENY, logs the deciding policy rule; matchedPolicy is `[]` when nothing matched (default-deny). */\n protected enforceWithExplain(opts: { enforcer: CasbinEnforcerType; vals: string[] }): boolean {\n const [isAllowed, matchedPolicy] = opts.enforcer.enforceExSync(...opts.vals);\n\n if (!isAllowed) {\n this.logger\n .for(this.evaluate.name)\n .info(\n 'DENY | request: [%s] | matchedPolicy: %s',\n opts.vals.join(', '),\n matchedPolicy.length ? matchedPolicy.join(', ') : '<none - default-deny>',\n );\n }\n\n return isAllowed;\n }\n\n // Cache management - optional IAuthorizationEnforcer members (on-demand)\n async invalidateUserCache(opts: {\n user: IAuthorizationUser;\n }): Promise<{ invalidatedKeys: number }> {\n const { cacheKey, invalidatedKeys } = await this.requireRedisCache().invalidate({\n user: opts.user,\n });\n\n this.logger\n .for(this.invalidateUserCache.name)\n .info(\n 'Invalidated authz cache | user: %s | key: %s | deleted: %s',\n opts.user.userId,\n cacheKey,\n invalidatedKeys,\n );\n\n return { invalidatedKeys };\n }\n\n async rebuildUserCache(opts: {\n user: IAuthorizationUser;\n }): Promise<{ cacheKey: string; lineCount: number }> {\n // Extraction runs on an isolated throwaway enforcer (not a serving model), so a concurrent request cannot make us cache another user's policies under this key.\n const { cacheKey, lines } = await this.requireRedisCache().rebuild({ user: opts.user });\n\n this.logger\n .for(this.rebuildUserCache.name)\n .info(\n 'Rebuilt authz cache | user: %s | key: %s | lines: %s',\n opts.user.userId,\n cacheKey,\n lines.length,\n );\n\n return { cacheKey, lineCount: lines.length };\n }\n\n /** Narrow `options.cached` to the redis variant and lazily create the per-user line cache - memoized so its single-flight de-dup map is shared across calls rather than reset on every access. */\n protected requireRedisCache(): UserPolicyLineCache {\n const { cached } = this.options;\n\n if (!cached.use) {\n throw getError({\n message:\n '[CasbinAuthorizationEnforcer] Cache management requires the redis cache driver, but caching is disabled.',\n });\n }\n\n return (this.userPolicyLineCache ??= new UserPolicyLineCache({\n cached,\n loadLines: opts => this.extractUserLines(opts),\n }));\n }\n\n // Matchers & model resolvers\n\n protected async registerMatchers(opts: {\n enforcer: CasbinEnforcerType;\n casbin: typeof import('casbin');\n }): Promise<void> {\n const { enforcer, casbin } = opts;\n const { domainMatching, isScoped } = this.options;\n\n if (domainMatching) {\n if (!enforcer.getNamedRoleManager(domainMatching.roleDefinition)) {\n throw getError({\n message: `[registerMatchers] Role definition \"${domainMatching.roleDefinition}\" is not declared in the Casbin model. Declare it under [role_definition] (e.g. \\`g = _, _, _\\`) before enabling domainMatching.`,\n });\n }\n\n const matchFn = this.resolveDomainMatchingFn({ casbin, name: domainMatching.fn });\n await enforcer.addNamedDomainMatchingFunc(domainMatching.roleDefinition, matchFn);\n }\n\n if (isScoped) {\n await enforcer.addNamedDomainMatchingFunc(CasbinRuleVariants.G, casbin.Util.keyMatchFunc);\n await enforcer.addFunction('objectMatch', AuthorizationPermissionBuilder.objectMatch);\n\n // A dedicated role manager for the resource axis, NOT addNamedMatchingFunc: a matching func sets casbin's `hasPattern`, which makes every hasLink rebuild the whole g4 graph.\n enforcer.setNamedRoleManager(\n AuthorizationPolicyVariants.RESOURCE_INHERITS.rule,\n new ResourceRoleManager(),\n );\n\n // Shared across g2, g3, and the reversed `g` instance below: casbin never puts the\n // `g`-axis hierarchy manager in rmMap, so it never receives addLink and would miss\n // per-request g3 edges - g2 needs the same freshness for a just-created child domain.\n // This is a per-REQUEST overlay: `clear()` empties it every buildRoleLinks cycle, and it is\n // repopulated from whatever `g3` lines this principal's own policy line set carries.\n const domainHierarchyOverlay = new Map<string, Set<string>>();\n\n // g2 (membership) and g3 (domain nesting, request-domain-first) sit on their own axes.\n enforcer.setNamedRoleManager(\n CasbinRuleVariants.G2,\n new MembershipRoleManager({ overlay: domainHierarchyOverlay }),\n );\n\n enforcer.setNamedRoleManager(\n CasbinRuleVariants.G3,\n new DomainHierarchyRoleManager({ overlay: domainHierarchyOverlay }),\n );\n\n // addNamedDomainMatchingFunc(G, keyMatchFunc) above must stay: generateTempRoles ORs\n // hasDomainPattern with hasDomainHierarchy, and role_inherits `*` rides the keyMatch path.\n const gRoleManager = enforcer.getNamedRoleManager(CasbinRuleVariants.G) as\n | (CasbinRoleManagerType & ICasbinRoleManagerWithDomainHierarchy)\n | undefined;\n\n if (!gRoleManager?.addDomainHierarchy) {\n throw getError({\n message:\n '[registerMatchers] The \"g\" role manager does not expose addDomainHierarchy() - the scoped model requires casbin\\'s DefaultRoleManager on the g axis (present in casbin ^5.51.1, this package\\'s pinned range). Upgrade casbin, or check that a custom role manager was not substituted for \"g\".',\n });\n }\n\n await gRoleManager.addDomainHierarchy(\n new DomainHierarchyRoleManager({ reversed: true, overlay: domainHierarchyOverlay }),\n );\n }\n\n await enforcer.buildRoleLinks();\n }\n\n /** Map a CasbinDomainMatchingFunctions value to casbin's Util.*Func matcher. */\n protected resolveDomainMatchingFn(opts: {\n casbin: typeof import('casbin');\n name: TCasbinDomainMatchingFunction;\n }): (arg1: string, arg2: string) => boolean {\n // casbin Util built-ins: (requestValue, policyValue) => match. keyMatchFunc only special-cases `*` (never splits on `/` or `:`), so it cannot pattern-match a `Merchant_<uuid>`; see CasbinDomainMatchingFunctions for per-function semantics.\n const { Util } = opts.casbin;\n switch (opts.name) {\n case CasbinDomainMatchingFunctions.KEY_MATCH: {\n return Util.keyMatchFunc;\n }\n case CasbinDomainMatchingFunctions.KEY_MATCH_2: {\n return Util.keyMatch2Func;\n }\n case CasbinDomainMatchingFunctions.KEY_MATCH_3: {\n return Util.keyMatch3Func;\n }\n case CasbinDomainMatchingFunctions.KEY_MATCH_4: {\n return Util.keyMatch4Func;\n }\n case CasbinDomainMatchingFunctions.REGEX_MATCH: {\n return Util.regexMatchFunc;\n }\n default: {\n throw getError({\n message: `[resolveDomainMatchingFn] Unsupported func: ${opts.name} | Valids: [${[...CasbinDomainMatchingFunctions.SCHEME_SET].join(', ')}]`,\n });\n }\n }\n }\n\n /** Default (sub,dom,obj,act) payload for the scoped model; domain comes from request.domain. */\n protected defaultScopedPayloadFn(): TNormalizePayloadFn<E, TAction, TResource> | undefined {\n if (!this.options.isScoped) {\n return undefined;\n }\n\n return (opts: {\n user: IAuthorizationUser;\n action: TAction;\n resource: TResource;\n }): { subject: string; resource: string; action: string; domain?: string } => {\n // No domain here - evaluate() fills it from request.domain (set by the provider).\n return {\n subject: `${opts.user.principalType}_${opts.user.userId}`,\n resource: String(opts.resource),\n action: String(opts.action),\n };\n };\n }\n\n protected resolveModel(opts: {\n casbin: typeof import('casbin');\n model: ICasbinEnforcerOptions['model'];\n }) {\n const { casbin, model } = opts;\n\n switch (model.driver) {\n case CasbinEnforcerModelDrivers.FILE: {\n return casbin.newModelFromFile(model.definition);\n }\n case CasbinEnforcerModelDrivers.TEXT: {\n return casbin.newModelFromString(model.definition);\n }\n default: {\n throw getError({\n message: `[resolveModel] Invalid model.driver | Valids: [${CasbinEnforcerModelDrivers.FILE}, ${CasbinEnforcerModelDrivers.TEXT}]`,\n });\n }\n }\n }\n\n protected validateExpiresIn(opts: { expiresIn: number }): void {\n if (opts.expiresIn >= this.MIN_EXPIRES_IN) {\n return;\n }\n\n throw getError({\n message: `[CasbinAuthorizationEnforcer] cached.options.expiresIn must be >= ${this.MIN_EXPIRES_IN} (ms) | Received: ${opts.expiresIn}`,\n });\n }\n\n // Policy loading internals\n\n /** Resolves this enforcer's model, then delegates the isolated-enforcer extraction (own model + adapter, never a pooled serving one, so concurrent requests cannot change what we cache) to PolicyLineCodec. */\n protected async extractUserLines(opts: { user: IAuthorizationUser }): Promise<string[]> {\n const casbin = await CasbinModule.load();\n const model = this.resolveModel({ casbin, model: this.options.model });\n\n return PolicyLineCodec.extractUserLines({\n casbin,\n model,\n adapter: this.options.adapter,\n user: opts.user,\n });\n }\n\n /** Requires configure() to have resolved the casbin Helper; the clearPolicy + loadPolicyLine + buildRoleLinks ordering lives in PolicyLineCodec. */\n protected async loadPolicyLinesIntoModel(opts: {\n enforcer: CasbinEnforcerType;\n lines: string[];\n }): Promise<void> {\n if (!this.helper) {\n throw getError({\n message: '[loadPolicyLinesIntoModel] Not configured. Call configure() first.',\n });\n }\n\n await PolicyLineCodec.loadLinesIntoModel({\n enforcer: opts.enforcer,\n lines: opts.lines,\n helper: this.helper,\n });\n }\n}\n"]}
1
+ {"version":3,"file":"casbin.enforcer.js","sourceRoot":"","sources":["../../../../../src/components/auth/authorize/enforcers/casbin.enforcer.ts"],"names":[],"mappings":"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","sourcesContent":["import { type TContext } from '@venizia/ignis-kernel';\nimport { inject } from '@venizia/ignis-kernel';\nimport { BaseHelper, BasePoolHelper, getError } from '@venizia/ignis-helpers/core';\nimport { type TNullable } from '@venizia/ignis-helpers/common';\nimport type {\n Enforcer as CasbinEnforcerType,\n Helper as CasbinHelperType,\n RoleManager as CasbinRoleManagerType,\n} from 'casbin';\nimport { type Env } from 'hono';\nimport { AuthorizationPermissionBuilder } from '@venizia/ignis-kernel';\nimport {\n AuthorizationDecisions,\n AuthorizationDomainScopes,\n AuthorizationEnforcerTypes,\n AuthorizationPolicyVariants,\n AuthorizeBindingKeys,\n CasbinDomainMatchingFunctions,\n CasbinEnforcerModelDrivers,\n CasbinRuleVariants,\n type IAuthorizationEnforcer,\n type IAuthorizationUser,\n type ICasbinEnforcerOptions,\n type ICasbinRules,\n type IAuthorizationRequest,\n type TAuthorizationDecision,\n type TCasbinDomainMatchingFunction,\n} from '@venizia/ignis-kernel';\nimport { DomainHierarchyRoleManager } from '../role-managers/domain-hierarchy';\nimport { CasbinModule } from './casbin-module';\nimport { MembershipRoleManager } from '../role-managers/membership';\nimport { ResourceRoleManager } from '../role-managers/resource';\nimport { PolicyLineCodec } from './policy-line-codec';\nimport { UserPolicyLineCache } from './user-policy-line-cache';\n\n/** Payload shape for the scoped/custom path, matching defaultScopedPayloadFn(). */\ntype TNormalizePayloadFn<E extends Env, TAction, TResource> = (opts: {\n user: IAuthorizationUser;\n action: TAction;\n resource: TResource;\n context: TContext<E, string>;\n}) => { subject: string; resource: string; action: string; domain?: string };\n\n/** `addDomainHierarchy` lives on casbin's `DefaultRoleManager`, not on the `RoleManager` interface or the `Enforcer` facade - feature-detect it on whatever `getNamedRoleManager` returns. */\ninterface ICasbinRoleManagerWithDomainHierarchy {\n addDomainHierarchy?(rm: CasbinRoleManagerType): Promise<void>;\n}\n\n// Wraps casbin (optional peer dep). Each request borrows its own pooled enforcer; any error during use destroys it (fail-closed). Pooled enforcers carry no adapter - only extractUserLines uses one.\n\nexport class CasbinAuthorizationEnforcer<\n E extends Env = Env,\n TAction extends string = string,\n TResource extends string = string,\n>\n extends BaseHelper\n implements IAuthorizationEnforcer<E, TAction, TResource, ICasbinRules>\n{\n name = CasbinAuthorizationEnforcer.name;\n private readonly MIN_EXPIRES_IN = 10_000;\n\n private pool: TNullable<BasePoolHelper<CasbinEnforcerType>> = null;\n private helper: TNullable<typeof CasbinHelperType> = null;\n // Lazily created on first cache use (see requireRedisCache) - one instance for the enforcer's lifetime so its single-flight de-dup map actually dedupes.\n private userPolicyLineCache: TNullable<UserPolicyLineCache> = null;\n\n // Memoized in configure() (options are fixed after) to avoid rebuilding this closure on every evaluate() (hot path).\n private resolvedPayloadFn: TNullable<TNormalizePayloadFn<E, TAction, TResource>> = null;\n\n constructor(\n @inject({ key: AuthorizeBindingKeys.enforcerOptions(AuthorizationEnforcerTypes.CASBIN) })\n private options: ICasbinEnforcerOptions<E, TAction, TResource>,\n ) {\n super({ scope: CasbinAuthorizationEnforcer.name });\n }\n\n // Lifecycle\n\n async configure(): Promise<void> {\n const casbin = await CasbinModule.load();\n\n if (!this.options.model) {\n throw getError({\n message: '[CasbinAuthorizationEnforcer] options.model is required.',\n });\n }\n\n this.helper = casbin.Helper;\n\n this.resolvedPayloadFn = this.options.normalizePayloadFn ?? this.defaultScopedPayloadFn();\n\n const { cached } = this.options;\n if (cached.use) {\n this.validateExpiresIn({ expiresIn: cached.options.expiresIn });\n }\n\n this.pool = new BasePoolHelper<CasbinEnforcerType>({\n scope: `${CasbinAuthorizationEnforcer.name}.Pool`,\n size: this.options.poolSize ?? 16,\n acquireTimeoutMs: this.options.poolAcquireTimeoutMs ?? 5000,\n create: async () => {\n const model = this.resolveModel({ casbin, model: this.options.model });\n\n const enforcer = await casbin.newEnforcer(model);\n await this.registerMatchers({ enforcer, casbin });\n this.assertMatcherCompilesSync({ enforcer });\n\n return enforcer;\n },\n });\n await this.pool.warmup();\n\n this.logger\n .for(this.configure.name)\n .info(\n 'Casbin enforcer pool ready (size: %s, cached: %s)',\n this.options.poolSize ?? 16,\n cached.use ? cached.driver : 'none',\n );\n }\n\n destroy(): void {\n this.pool?.destroy().catch((error) => {\n this.logger.for(this.destroy.name).warn('Pool destroy failed: %s', error);\n });\n }\n\n /** casbin compiles the matcher lazily (first enforce, not newEnforcer/buildRoleLinks); this dummy enforceSync forces the compile at warmup so syntax / unregistered-function / arity errors fail boot. */\n protected assertMatcherCompilesSync(opts: { enforcer: CasbinEnforcerType }) {\n try {\n if (this.options.isScoped || this.options.normalizePayloadFn) {\n opts.enforcer.enforceSync('::warmup', '::warmup', '::warmup', '::warmup');\n return;\n }\n\n opts.enforcer.enforceSync('::warmup', '::warmup', '::warmup');\n } catch (error) {\n throw getError({\n message: `[CasbinAuthorizationEnforcer] Matcher smoke test failed at warmup - the model matcher did not compile (check matcher syntax, that every referenced function is registered, and the request arity). ${String(error)}`,\n });\n }\n }\n\n // IAuthorizationEnforcer - public API\n\n async buildRules(opts: {\n user: IAuthorizationUser;\n context: TContext<E, string>;\n }): Promise<ICasbinRules> {\n const { user } = opts;\n const cached = this.options.cached;\n\n const lines = cached.use\n ? await this.requireRedisCache().fetch({ user })\n : await this.extractUserLines({ user });\n\n return { user, lines };\n }\n\n async evaluate(opts: {\n rules: ICasbinRules;\n request: IAuthorizationRequest<TAction, TResource>;\n context: TContext<E, string>;\n }): Promise<TAuthorizationDecision> {\n if (!this.pool) {\n throw getError({\n message: '[CasbinAuthorizationEnforcer] Not configured. Call configure() first.',\n });\n }\n\n if (!opts.request?.action || !opts.request?.resource) {\n throw getError({\n message: '[CasbinAuthorizationEnforcer] request.action and request.resource are required.',\n });\n }\n\n const { rules, request, context } = opts;\n const { user, lines } = rules;\n\n return this.pool.use({\n execution: async (enforcer) => {\n await this.loadPolicyLinesIntoModel({ enforcer, lines });\n\n const normalizePayloadFn = this.resolvedPayloadFn;\n\n if (!normalizePayloadFn) {\n const subject = `${user.principalType}_${user.userId}`;\n const isAllowed = this.enforceWithExplain({\n enforcer,\n vals: [subject, String(request.resource), String(request.action)],\n });\n return isAllowed ? AuthorizationDecisions.ALLOW : AuthorizationDecisions.DENY;\n }\n\n const normalized = normalizePayloadFn({\n user,\n action: request.action,\n resource: request.resource,\n context,\n });\n\n // Scoped model is 4-token (sub, dom, obj, act): a request with no resolvable domain still needs one - default SYSTEM_WIDE, never the 3-arg path, which misaligns args and silently misjudges.\n const domain =\n normalized.domain ??\n request.domain ??\n (this.options.isScoped ? AuthorizationDomainScopes.SYSTEM_WIDE : undefined);\n\n const vals = domain\n ? [normalized.subject, domain, normalized.resource, normalized.action]\n : [normalized.subject, normalized.resource, normalized.action];\n const isAllowed = this.enforceWithExplain({ enforcer, vals });\n\n return isAllowed ? AuthorizationDecisions.ALLOW : AuthorizationDecisions.DENY;\n },\n });\n }\n\n /** On DENY, logs the deciding policy rule; matchedPolicy is `[]` when nothing matched (default-deny). */\n protected enforceWithExplain(opts: { enforcer: CasbinEnforcerType; vals: string[] }): boolean {\n const [isAllowed, matchedPolicy] = opts.enforcer.enforceExSync(...opts.vals);\n\n if (!isAllowed) {\n this.logger\n .for(this.evaluate.name)\n .info(\n 'DENY | request: [%s] | matchedPolicy: %s',\n opts.vals.join(', '),\n matchedPolicy.length ? matchedPolicy.join(', ') : '<none - default-deny>',\n );\n }\n\n return isAllowed;\n }\n\n // Cache management - optional IAuthorizationEnforcer members (on-demand)\n async invalidateUserCache(opts: {\n user: IAuthorizationUser;\n }): Promise<{ invalidatedKeys: number }> {\n const { cacheKey, invalidatedKeys } = await this.requireRedisCache().invalidate({\n user: opts.user,\n });\n\n this.logger\n .for(this.invalidateUserCache.name)\n .info(\n 'Invalidated authz cache | user: %s | key: %s | deleted: %s',\n opts.user.userId,\n cacheKey,\n invalidatedKeys,\n );\n\n return { invalidatedKeys };\n }\n\n async rebuildUserCache(opts: {\n user: IAuthorizationUser;\n }): Promise<{ cacheKey: string; lineCount: number }> {\n // Extraction runs on an isolated throwaway enforcer (not a serving model), so a concurrent request cannot make us cache another user's policies under this key.\n const { cacheKey, lines } = await this.requireRedisCache().rebuild({ user: opts.user });\n\n this.logger\n .for(this.rebuildUserCache.name)\n .info(\n 'Rebuilt authz cache | user: %s | key: %s | lines: %s',\n opts.user.userId,\n cacheKey,\n lines.length,\n );\n\n return { cacheKey, lineCount: lines.length };\n }\n\n /** Narrow `options.cached` to the redis variant and lazily create the per-user line cache - memoized so its single-flight de-dup map is shared across calls rather than reset on every access. */\n protected requireRedisCache(): UserPolicyLineCache {\n const { cached } = this.options;\n\n if (!cached.use) {\n throw getError({\n message:\n '[CasbinAuthorizationEnforcer] Cache management requires the redis cache driver, but caching is disabled.',\n });\n }\n\n return (this.userPolicyLineCache ??= new UserPolicyLineCache({\n cached,\n loadLines: (opts) => this.extractUserLines(opts),\n }));\n }\n\n // Matchers & model resolvers\n\n protected async registerMatchers(opts: {\n enforcer: CasbinEnforcerType;\n casbin: typeof import('casbin');\n }): Promise<void> {\n const { enforcer, casbin } = opts;\n const { domainMatching, isScoped } = this.options;\n\n if (domainMatching) {\n if (!enforcer.getNamedRoleManager(domainMatching.roleDefinition)) {\n throw getError({\n message: `[registerMatchers] Role definition \"${domainMatching.roleDefinition}\" is not declared in the Casbin model. Declare it under [role_definition] (e.g. \\`g = _, _, _\\`) before enabling domainMatching.`,\n });\n }\n\n const matchFn = this.resolveDomainMatchingFn({ casbin, name: domainMatching.fn });\n await enforcer.addNamedDomainMatchingFunc(domainMatching.roleDefinition, matchFn);\n }\n\n if (isScoped) {\n await enforcer.addNamedDomainMatchingFunc(CasbinRuleVariants.G, casbin.Util.keyMatchFunc);\n await enforcer.addFunction('objectMatch', AuthorizationPermissionBuilder.objectMatch);\n\n // A dedicated role manager for the resource axis, NOT addNamedMatchingFunc: a matching func sets casbin's `hasPattern`, which makes every hasLink rebuild the whole g4 graph.\n enforcer.setNamedRoleManager(\n AuthorizationPolicyVariants.RESOURCE_INHERITS.rule,\n new ResourceRoleManager(),\n );\n\n // Shared across g2, g3, and the reversed `g` instance below: casbin never puts the\n // `g`-axis hierarchy manager in rmMap, so it never receives addLink and would miss\n // per-request g3 edges - g2 needs the same freshness for a just-created child domain.\n // This is a per-REQUEST overlay: `clear()` empties it every buildRoleLinks cycle, and it is\n // repopulated from whatever `g3` lines this principal's own policy line set carries.\n const domainHierarchyOverlay = new Map<string, Set<string>>();\n\n // g2 (membership) and g3 (domain nesting, request-domain-first) sit on their own axes.\n enforcer.setNamedRoleManager(\n CasbinRuleVariants.G2,\n new MembershipRoleManager({ overlay: domainHierarchyOverlay }),\n );\n\n enforcer.setNamedRoleManager(\n CasbinRuleVariants.G3,\n new DomainHierarchyRoleManager({ overlay: domainHierarchyOverlay }),\n );\n\n // addNamedDomainMatchingFunc(G, keyMatchFunc) above must stay: generateTempRoles ORs\n // hasDomainPattern with hasDomainHierarchy, and role_inherits `*` rides the keyMatch path.\n const gRoleManager = enforcer.getNamedRoleManager(CasbinRuleVariants.G) as\n | (CasbinRoleManagerType & ICasbinRoleManagerWithDomainHierarchy)\n | undefined;\n\n if (!gRoleManager?.addDomainHierarchy) {\n throw getError({\n message:\n '[registerMatchers] The \"g\" role manager does not expose addDomainHierarchy() - the scoped model requires casbin\\'s DefaultRoleManager on the g axis (present in casbin ^5.51.1, this package\\'s pinned range). Upgrade casbin, or check that a custom role manager was not substituted for \"g\".',\n });\n }\n\n await gRoleManager.addDomainHierarchy(\n new DomainHierarchyRoleManager({ reversed: true, overlay: domainHierarchyOverlay }),\n );\n }\n\n await enforcer.buildRoleLinks();\n }\n\n /** Map a CasbinDomainMatchingFunctions value to casbin's Util.*Func matcher. */\n protected resolveDomainMatchingFn(opts: {\n casbin: typeof import('casbin');\n name: TCasbinDomainMatchingFunction;\n }): (arg1: string, arg2: string) => boolean {\n // casbin Util built-ins: (requestValue, policyValue) => match. keyMatchFunc only special-cases `*` (never splits on `/` or `:`), so it cannot pattern-match a `Merchant_<uuid>`; see CasbinDomainMatchingFunctions for per-function semantics.\n const { Util } = opts.casbin;\n switch (opts.name) {\n case CasbinDomainMatchingFunctions.KEY_MATCH: {\n return Util.keyMatchFunc;\n }\n case CasbinDomainMatchingFunctions.KEY_MATCH_2: {\n return Util.keyMatch2Func;\n }\n case CasbinDomainMatchingFunctions.KEY_MATCH_3: {\n return Util.keyMatch3Func;\n }\n case CasbinDomainMatchingFunctions.KEY_MATCH_4: {\n return Util.keyMatch4Func;\n }\n case CasbinDomainMatchingFunctions.REGEX_MATCH: {\n return Util.regexMatchFunc;\n }\n default: {\n throw getError({\n message: `[resolveDomainMatchingFn] Unsupported func: ${opts.name} | Valids: [${[...CasbinDomainMatchingFunctions.SCHEME_SET].join(', ')}]`,\n });\n }\n }\n }\n\n /** Default (sub,dom,obj,act) payload for the scoped model; domain comes from request.domain. */\n protected defaultScopedPayloadFn(): TNormalizePayloadFn<E, TAction, TResource> | undefined {\n if (!this.options.isScoped) {\n return undefined;\n }\n\n return (opts: {\n user: IAuthorizationUser;\n action: TAction;\n resource: TResource;\n }): { subject: string; resource: string; action: string; domain?: string } => {\n // No domain here - evaluate() fills it from request.domain (set by the provider).\n return {\n subject: `${opts.user.principalType}_${opts.user.userId}`,\n resource: String(opts.resource),\n action: String(opts.action),\n };\n };\n }\n\n protected resolveModel(opts: {\n casbin: typeof import('casbin');\n model: ICasbinEnforcerOptions['model'];\n }) {\n const { casbin, model } = opts;\n\n switch (model.driver) {\n case CasbinEnforcerModelDrivers.FILE: {\n return casbin.newModelFromFile(model.definition);\n }\n case CasbinEnforcerModelDrivers.TEXT: {\n return casbin.newModelFromString(model.definition);\n }\n default: {\n throw getError({\n message: `[resolveModel] Invalid model.driver | Valids: [${CasbinEnforcerModelDrivers.FILE}, ${CasbinEnforcerModelDrivers.TEXT}]`,\n });\n }\n }\n }\n\n protected validateExpiresIn(opts: { expiresIn: number }): void {\n if (opts.expiresIn >= this.MIN_EXPIRES_IN) {\n return;\n }\n\n throw getError({\n message: `[CasbinAuthorizationEnforcer] cached.options.expiresIn must be >= ${this.MIN_EXPIRES_IN} (ms) | Received: ${opts.expiresIn}`,\n });\n }\n\n // Policy loading internals\n\n /** Resolves this enforcer's model, then delegates the isolated-enforcer extraction (own model + adapter, never a pooled serving one, so concurrent requests cannot change what we cache) to PolicyLineCodec. */\n protected async extractUserLines(opts: { user: IAuthorizationUser }): Promise<string[]> {\n const casbin = await CasbinModule.load();\n const model = this.resolveModel({ casbin, model: this.options.model });\n\n return PolicyLineCodec.extractUserLines({\n casbin,\n model,\n adapter: this.options.adapter,\n user: opts.user,\n });\n }\n\n /** Requires configure() to have resolved the casbin Helper; the clearPolicy + loadPolicyLine + buildRoleLinks ordering lives in PolicyLineCodec. */\n protected async loadPolicyLinesIntoModel(opts: {\n enforcer: CasbinEnforcerType;\n lines: string[];\n }): Promise<void> {\n if (!this.helper) {\n throw getError({\n message: '[loadPolicyLinesIntoModel] Not configured. Call configure() first.',\n });\n }\n\n await PolicyLineCodec.loadLinesIntoModel({\n enforcer: opts.enforcer,\n lines: opts.lines,\n helper: this.helper,\n });\n }\n}\n"]}
@@ -79,7 +79,7 @@ class UserPolicyLineCache extends core_1.BaseHelper {
79
79
  parseLines(opts) {
80
80
  try {
81
81
  const parsed = JSON.parse(opts.raw);
82
- if (!Array.isArray(parsed) || parsed.some(line => typeof line !== 'string')) {
82
+ if (!Array.isArray(parsed) || parsed.some((line) => typeof line !== 'string')) {
83
83
  throw (0, core_1.getError)({
84
84
  message: '[UserPolicyLineCache] Cached payload is not an array of policy lines.',
85
85
  });
@@ -1 +1 @@
1
- {"version":3,"file":"user-policy-line-cache.js","sourceRoot":"","sources":["../../../../../src/components/auth/authorize/enforcers/user-policy-line-cache.ts"],"names":[],"mappings":";;;AAAA,sDAAmE;AAEnE,wDAI+B;AAK/B;;;GAGG;AACH,MAAa,mBAAoB,SAAQ,iBAAU;IAOjD,YAAY,IAGX;QACC,KAAK,CAAC,EAAE,KAAK,EAAE,mBAAmB,CAAC,IAAI,EAAE,CAAC,CAAC;QAP7C,4IAA4I;QAC3H,uBAAkB,GAAG,IAAI,GAAG,EAA6B,CAAC;QAOzE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;IAClC,CAAC;IAED,uMAAuM;IACvM,KAAK,CAAC,KAAK,CAAC,IAAkC;QAC5C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAEjE,+JAA+J;QAC/J,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;QACxE,IAAI,GAAG,EAAE,CAAC;YACR,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;YAEjD,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACvD,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,qLAAqL;QACrL,MAAM,IAAI,GAAG,KAAK,IAAI,EAAE;YACtB,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACxD,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;YAC3C,OAAO,KAAK,CAAC;QACf,CAAC,CAAC;QAEF,MAAM,OAAO,GAAG,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;YAClC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,oCAAoC;IACpC,KAAK,CAAC,UAAU,CAAC,IAEhB;QACC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACjE,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAEvF,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC;IACvC,CAAC;IAED,uMAAuM;IACvM,KAAK,CAAC,OAAO,CAAC,IAEb;QACC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACjE,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAE/D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACxD,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAE3C,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAC7B,CAAC;IAED,+FAA+F;IACvF,KAAK,CAAC,eAAe,CAAC,IAAkC;QAC9D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACtE,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAA,eAAQ,EAAC;gBACb,KAAK,EAAE,kCAAmB,CAAC,iBAAiB;gBAC5C,OAAO,EAAE,0DAA0D;aACpE,CAAC,CAAC;QACL,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,0FAA0F;IAClF,KAAK,CAAC,UAAU,CAAC,IAA2C;QAClE,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YACvC,GAAG,EAAE,IAAI,CAAC,QAAQ;YAClB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,EAAE;SACtD,CAAC,CAAC;IACL,CAAC;IAED,kGAAkG;IAC1F,UAAU,CAAC,IAAuC;QACxD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAEpC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,EAAE,CAAC;gBAC5E,MAAM,IAAA,eAAQ,EAAC;oBACb,OAAO,EAAE,uEAAuE;iBACjF,CAAC,CAAC;YACL,CAAC;YAED,OAAO,MAAkB,CAAC;QAC5B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM;iBACR,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;iBACzB,IAAI,CAAC,8DAA8D,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAC9F,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAlHD,kDAkHC","sourcesContent":["import { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport type { TNullable } from '@venizia/ignis-helpers/common';\nimport {\n AuthorizationErrors,\n type IAuthorizationUser,\n type ICasbinEnforcerCachedRedis,\n} from '@venizia/ignis-kernel';\n\n/** Computes a user's policy lines on a cache miss - CasbinAuthorizationEnforcer wires this to its isolated-enforcer extraction (PolicyLineCodec.extractUserLines). */\nexport type TPolicyLineLoader = (opts: { user: IAuthorizationUser }) => Promise<string[]>;\n\n/**\n * Per-user redis cache of casbin policy lines. Owns the cache key, the TTL, and concurrent-miss\n * de-duplication so N simultaneous misses for the same user collapse onto one extraction.\n */\nexport class UserPolicyLineCache extends BaseHelper {\n private readonly cached: ICasbinEnforcerCachedRedis & { use: true };\n private readonly loadLines: TPolicyLineLoader;\n\n // cacheKey -> in-progress line-fetch; concurrent misses for the same user share one extraction instead of all hitting the DB (see fetch()).\n private readonly pendingLineFetches = new Map<string, Promise<string[]>>();\n\n constructor(opts: {\n cached: ICasbinEnforcerCachedRedis & { use: true };\n loadLines: TPolicyLineLoader;\n }) {\n super({ scope: UserPolicyLineCache.name });\n this.cached = opts.cached;\n this.loadLines = opts.loadLines;\n }\n\n /** Fetch the user's lines, collapsing concurrent misses per key onto one extraction. Best-effort: two misses may race past the cache read and both extract (benign - per-user lines are identical). */\n async fetch(opts: { user: IAuthorizationUser }): Promise<string[]> {\n const cacheKey = await this.resolveCacheKey({ user: opts.user });\n\n // Cache hit - Redis owns expiry (PX on write), so a present key is fresh; a corrupted/legacy entry must NOT 500 the request, so it is discarded and refetched.\n const raw = await this.cached.options.connection.get({ key: cacheKey });\n if (raw) {\n const lines = this.parseLines({ raw, cacheKey });\n\n if (lines) {\n return lines;\n }\n }\n\n const existing = this.pendingLineFetches.get(cacheKey);\n if (existing) {\n return existing;\n }\n\n // Cache miss (or discarded corrupt entry) - extract from an ISOLATED enforcer so a concurrent load cannot contaminate the cache, persist it, then return the lines for THIS request.\n const task = async () => {\n const lines = await this.loadLines({ user: opts.user });\n await this.writeLines({ cacheKey, lines });\n return lines;\n };\n\n const promise = task().finally(() => {\n this.pendingLineFetches.delete(cacheKey);\n });\n\n this.pendingLineFetches.set(cacheKey, promise);\n return promise;\n }\n\n /** Drop the user's cached entry. */\n async invalidate(opts: {\n user: IAuthorizationUser;\n }): Promise<{ cacheKey: string; invalidatedKeys: number }> {\n const cacheKey = await this.resolveCacheKey({ user: opts.user });\n const invalidatedKeys = await this.cached.options.connection.del({ keys: [cacheKey] });\n\n return { cacheKey, invalidatedKeys };\n }\n\n /** Drop then recompute the user's cached entry via `loadLines` - an isolated extraction (never a pooled serving enforcer), so a concurrent request cannot make the cache hold another user's lines. */\n async rebuild(opts: {\n user: IAuthorizationUser;\n }): Promise<{ cacheKey: string; lines: string[] }> {\n const cacheKey = await this.resolveCacheKey({ user: opts.user });\n await this.cached.options.connection.del({ keys: [cacheKey] });\n\n const lines = await this.loadLines({ user: opts.user });\n await this.writeLines({ cacheKey, lines });\n\n return { cacheKey, lines };\n }\n\n /** Compute the user's cache key and reject an empty result - consistent with the read path. */\n private async resolveCacheKey(opts: { user: IAuthorizationUser }): Promise<string> {\n const cacheKey = await this.cached.options.keyFn({ user: opts.user });\n if (!cacheKey) {\n throw getError({\n error: AuthorizationErrors.CACHE_KEY_INVALID,\n message: '[UserPolicyLineCache] keyFn returned an empty cache key.',\n });\n }\n\n return cacheKey;\n }\n\n /** Single source of truth for the cache encoding. Used by the miss path and rebuild(). */\n private async writeLines(opts: { cacheKey: string; lines: string[] }): Promise<void> {\n await this.cached.options.connection.set({\n key: opts.cacheKey,\n value: opts.lines,\n options: { expiresIn: this.cached.options.expiresIn },\n });\n }\n\n /** Decode cached policy lines; on any corruption, log and return null so the caller refetches. */\n private parseLines(opts: { raw: string; cacheKey: string }): TNullable<string[]> {\n try {\n const parsed = JSON.parse(opts.raw);\n\n if (!Array.isArray(parsed) || parsed.some(line => typeof line !== 'string')) {\n throw getError({\n message: '[UserPolicyLineCache] Cached payload is not an array of policy lines.',\n });\n }\n\n return parsed as string[];\n } catch (error) {\n this.logger\n .for(this.parseLines.name)\n .warn('Discarding corrupted authz cache entry | key: %s | error: %s', opts.cacheKey, error);\n return null;\n }\n }\n}\n"]}
1
+ {"version":3,"file":"user-policy-line-cache.js","sourceRoot":"","sources":["../../../../../src/components/auth/authorize/enforcers/user-policy-line-cache.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport type { TNullable } from '@venizia/ignis-helpers/common';\nimport {\n AuthorizationErrors,\n type IAuthorizationUser,\n type ICasbinEnforcerCachedRedis,\n} from '@venizia/ignis-kernel';\n\n/** Computes a user's policy lines on a cache miss - CasbinAuthorizationEnforcer wires this to its isolated-enforcer extraction (PolicyLineCodec.extractUserLines). */\nexport type TPolicyLineLoader = (opts: { user: IAuthorizationUser }) => Promise<string[]>;\n\n/**\n * Per-user redis cache of casbin policy lines. Owns the cache key, the TTL, and concurrent-miss\n * de-duplication so N simultaneous misses for the same user collapse onto one extraction.\n */\nexport class UserPolicyLineCache extends BaseHelper {\n private readonly cached: ICasbinEnforcerCachedRedis & { use: true };\n private readonly loadLines: TPolicyLineLoader;\n\n // cacheKey -> in-progress line-fetch; concurrent misses for the same user share one extraction instead of all hitting the DB (see fetch()).\n private readonly pendingLineFetches = new Map<string, Promise<string[]>>();\n\n constructor(opts: {\n cached: ICasbinEnforcerCachedRedis & { use: true };\n loadLines: TPolicyLineLoader;\n }) {\n super({ scope: UserPolicyLineCache.name });\n this.cached = opts.cached;\n this.loadLines = opts.loadLines;\n }\n\n /** Fetch the user's lines, collapsing concurrent misses per key onto one extraction. Best-effort: two misses may race past the cache read and both extract (benign - per-user lines are identical). */\n async fetch(opts: { user: IAuthorizationUser }): Promise<string[]> {\n const cacheKey = await this.resolveCacheKey({ user: opts.user });\n\n // Cache hit - Redis owns expiry (PX on write), so a present key is fresh; a corrupted/legacy entry must NOT 500 the request, so it is discarded and refetched.\n const raw = await this.cached.options.connection.get({ key: cacheKey });\n if (raw) {\n const lines = this.parseLines({ raw, cacheKey });\n\n if (lines) {\n return lines;\n }\n }\n\n const existing = this.pendingLineFetches.get(cacheKey);\n if (existing) {\n return existing;\n }\n\n // Cache miss (or discarded corrupt entry) - extract from an ISOLATED enforcer so a concurrent load cannot contaminate the cache, persist it, then return the lines for THIS request.\n const task = async () => {\n const lines = await this.loadLines({ user: opts.user });\n await this.writeLines({ cacheKey, lines });\n return lines;\n };\n\n const promise = task().finally(() => {\n this.pendingLineFetches.delete(cacheKey);\n });\n\n this.pendingLineFetches.set(cacheKey, promise);\n return promise;\n }\n\n /** Drop the user's cached entry. */\n async invalidate(opts: {\n user: IAuthorizationUser;\n }): Promise<{ cacheKey: string; invalidatedKeys: number }> {\n const cacheKey = await this.resolveCacheKey({ user: opts.user });\n const invalidatedKeys = await this.cached.options.connection.del({ keys: [cacheKey] });\n\n return { cacheKey, invalidatedKeys };\n }\n\n /** Drop then recompute the user's cached entry via `loadLines` - an isolated extraction (never a pooled serving enforcer), so a concurrent request cannot make the cache hold another user's lines. */\n async rebuild(opts: {\n user: IAuthorizationUser;\n }): Promise<{ cacheKey: string; lines: string[] }> {\n const cacheKey = await this.resolveCacheKey({ user: opts.user });\n await this.cached.options.connection.del({ keys: [cacheKey] });\n\n const lines = await this.loadLines({ user: opts.user });\n await this.writeLines({ cacheKey, lines });\n\n return { cacheKey, lines };\n }\n\n /** Compute the user's cache key and reject an empty result - consistent with the read path. */\n private async resolveCacheKey(opts: { user: IAuthorizationUser }): Promise<string> {\n const cacheKey = await this.cached.options.keyFn({ user: opts.user });\n if (!cacheKey) {\n throw getError({\n error: AuthorizationErrors.CACHE_KEY_INVALID,\n message: '[UserPolicyLineCache] keyFn returned an empty cache key.',\n });\n }\n\n return cacheKey;\n }\n\n /** Single source of truth for the cache encoding. Used by the miss path and rebuild(). */\n private async writeLines(opts: { cacheKey: string; lines: string[] }): Promise<void> {\n await this.cached.options.connection.set({\n key: opts.cacheKey,\n value: opts.lines,\n options: { expiresIn: this.cached.options.expiresIn },\n });\n }\n\n /** Decode cached policy lines; on any corruption, log and return null so the caller refetches. */\n private parseLines(opts: { raw: string; cacheKey: string }): TNullable<string[]> {\n try {\n const parsed = JSON.parse(opts.raw);\n\n if (!Array.isArray(parsed) || parsed.some((line) => typeof line !== 'string')) {\n throw getError({\n message: '[UserPolicyLineCache] Cached payload is not an array of policy lines.',\n });\n }\n\n return parsed as string[];\n } catch (error) {\n this.logger\n .for(this.parseLines.name)\n .warn('Discarding corrupted authz cache entry | key: %s | error: %s', opts.cacheKey, error);\n return null;\n }\n }\n}\n"]}
@@ -110,7 +110,7 @@ let HealthCheckController = HealthCheckController_1 = class HealthCheckControlle
110
110
  binding() {
111
111
  // Public liveness probe: status and clock only. Nothing here names a runtime or a version.
112
112
  this.bindRoute({ configs: RouteConfigs.ROOT }).to({
113
- handler: context => {
113
+ handler: (context) => {
114
114
  return context.json(reporter_1.HealthCheckReporter.buildSummary(), common_1.HTTP.ResultCodes.RS_2.Ok);
115
115
  },
116
116
  });
@@ -121,7 +121,7 @@ let HealthCheckController = HealthCheckController_1 = class HealthCheckControlle
121
121
  return;
122
122
  }
123
123
  this.bindRoute({ configs: RouteConfigs.STATS }).to({
124
- handler: context => {
124
+ handler: (context) => {
125
125
  // `context.notFound()`, not a thrown 404: it runs the application's own notFound handler,
126
126
  // so the refusal is byte-identical to the answer for a route that was never mounted. A
127
127
  // thrown `ApplicationError` serializes a different body and would confirm the route exists.
@@ -1 +1 @@
1
- {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../src/components/health-check/controller.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oDAA4E;AAC5E,8CAA8C;AAC9C,wDAAkE;AAElE,mDAAsC;AACtC,0DAA0E;AAC1E,qCAKkB;AAClB,yCAAiD;AAEjD,MAAM,YAAY,GAAG;IACnB,IAAI,EAAE;QACJ,MAAM,EAAE,aAAI,CAAC,OAAO,CAAC,GAAG;QACxB,IAAI,EAAE,6BAAoB,CAAC,IAAI;QAC/B,SAAS,EAAE,IAAA,2BAAY,EAAC;YACtB,MAAM,EAAE,eAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,eAAC,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,eAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC;gBAC5E,WAAW,EAAE,oBAAoB;gBACjC,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;aAClE,CAAC;YACF,WAAW,EAAE,qBAAqB;SACnC,CAAC;KACH;IACD,KAAK,EAAE;QACL,MAAM,EAAE,aAAI,CAAC,OAAO,CAAC,GAAG;QACxB,IAAI,EAAE,6BAAoB,CAAC,KAAK;QAChC,OAAO,EAAE;YACP,OAAO,EAAE,eAAC,CAAC,MAAM,CAAC;gBAChB,CAAC,2BAAkB,CAAC,UAAU,CAAC,EAAE,eAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC;oBAC7D,WAAW,EAAE,eAAe;iBAC7B,CAAC;aACH,CAAC;SACH;QACD,SAAS,EAAE,IAAA,2BAAY,EAAC;YACtB,MAAM,EAAE,eAAC;iBACN,MAAM,CAAC;gBACN,MAAM,EAAE,eAAC,CAAC,MAAM,EAAE;gBAClB,SAAS,EAAE,eAAC,CAAC,GAAG,CAAC,QAAQ,EAAE;gBAC3B,KAAK,EAAE,eAAC,CAAC,MAAM,CAAC;oBACd,OAAO,EAAE,eAAC,CAAC,MAAM,EAAE;oBACnB,OAAO,EAAE,eAAC,CAAC,MAAM,EAAE;oBACnB,MAAM,EAAE,eAAC,CAAC,MAAM,EAAE;oBAClB,MAAM,EAAE,eAAC,CAAC,MAAM,EAAE;oBAClB,OAAO,EAAE,eAAC,CAAC,MAAM,EAAE;iBACpB,CAAC;gBACF,OAAO,EAAE,eAAC,CAAC,MAAM,CAAC;oBAChB,GAAG,EAAE,eAAC,CAAC,MAAM,EAAE;oBACf,MAAM,EAAE,eAAC,CAAC,MAAM,EAAE;oBAClB,WAAW,EAAE,eAAC,CAAC,MAAM,EAAE;oBACvB,OAAO,EAAE,eAAC,CAAC,MAAM,EAAE;oBACnB,WAAW,EAAE,eAAC,CAAC,MAAM,EAAE;iBACxB,CAAC;gBACF,MAAM,EAAE,eAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,eAAC,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,eAAC,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,eAAC,CAAC,MAAM,EAAE,EAAE,CAAC;aACnF,CAAC;iBACD,OAAO,CAAC,EAAE,WAAW,EAAE,0BAA0B,EAAE,CAAC;YACvD,WAAW,EACT,8FAA8F;SACjG,CAAC;KACH;IACD,IAAI,EAAE;QACJ,MAAM,EAAE,aAAI,CAAC,OAAO,CAAC,IAAI;QACzB,IAAI,EAAE,6BAAoB,CAAC,IAAI;QAC/B,OAAO,EAAE;YACP,IAAI,EAAE,IAAA,0BAAW,EAAC;gBAChB,WAAW,EAAE,qBAAqB;gBAClC,MAAM,EAAE,eAAC,CAAC,MAAM,CAAC;oBACf,IAAI,EAAE,eAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;oBAC3C,OAAO,EAAE,eAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;iBACpC,CAAC;aACH,CAAC;SACH;QACD,SAAS,EAAE,IAAA,2BAAY,EAAC;YACtB,MAAM,EAAE,eAAC;iBACN,MAAM,CAAC;gBACN,IAAI,EAAE,eAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;gBAC3C,IAAI,EAAE,eAAC,CAAC,GAAG,CAAC,QAAQ,EAAE;gBACtB,OAAO,EAAE,eAAC,CAAC,MAAM,EAAE;aACpB,CAAC;iBACD,OAAO,CAAC;gBACP,WAAW,EAAE,6BAA6B;gBAC1C,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;aAC9D,CAAC;YACJ,WAAW,EAAE,8BAA8B;SAC5C,CAAC;KACH;CACO,CAAC;AAEX,IAAa,qBAAqB,6BAAlC,MAAa,qBAAsB,SAAQ,gCAAkB;IAC3D;;;OAGG;IACH,YAEmB,gBAAqC,EAAE,EAEvC,OAA0B;QAE3C,KAAK,CAAC,EAAE,KAAK,EAAE,uBAAqB,CAAC,IAAI,EAAE,CAAC,CAAC;QAJ5B,kBAAa,GAAb,aAAa,CAA0B;QAEvC,YAAO,GAAP,OAAO,CAAmB;QAI3C,uEAAuE;QACvE,IAAI,CAAC,WAAW,GAAG,YAAY,CAAC;IAClC,CAAC;IAEQ,OAAO;QACd,2FAA2F;QAC3F,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;YAChD,OAAO,EAAE,OAAO,CAAC,EAAE;gBACjB,OAAO,OAAO,CAAC,IAAI,CAAC,8BAAmB,CAAC,YAAY,EAAE,EAAE,aAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACpF,CAAC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,8BAAmB,CAAC,cAAc,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,EAAE,CAAC;YACzE,IAAI,CAAC,MAAM;iBACR,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;iBACtB,KAAK,CAAC,iCAAiC,EAAE,6BAAoB,CAAC,KAAK,CAAC,CAAC;YACxE,OAAO;QACT,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC;YACjD,OAAO,EAAE,OAAO,CAAC,EAAE;gBACjB,0FAA0F;gBAC1F,uFAAuF;gBACvF,4FAA4F;gBAC5F,IACE,CAAC,8BAAmB,CAAC,iBAAiB,CAAC;oBACrC,OAAO,EAAE,IAAI,CAAC,aAAa;oBAC3B,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,2BAAkB,CAAC,UAAU,CAAC;iBAC1D,CAAC,EACF,CAAC;oBACD,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC;gBAC5B,CAAC;gBAED,OAAO,OAAO,CAAC,IAAI,CACjB,8BAAmB,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,EACtF,aAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CACzB,CAAC;YACJ,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IAED,4HAA4H;IAE5H,QAAQ,CAAC,OAAsB;QAC7B,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAqC,MAAM,CAAC,CAAC;QAElF,qEAAqE;QACrE,OAAO,OAAO,CAAC,IAAI,CACjB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,EACzD,aAAI,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CACzB,CAAC;IACJ,CAAC;CACF,CAAA;AAjEY,sDAAqB;AAwDhC;IADC,IAAA,cAAG,EAAC,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,EAAE,CAAC;;;;qDASnC;gCAhEU,qBAAqB;IAM7B,WAAA,IAAA,iBAAM,EAAC,EAAE,GAAG,EAAE,+BAAsB,CAAC,oBAAoB,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAA;IAE9E,WAAA,IAAA,iBAAM,EAAC,EAAE,GAAG,EAAE,+BAAsB,CAAC,gBAAgB,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAA;;GARlE,qBAAqB,CAiEjC","sourcesContent":["import { BaseRestController, type TRouteContext } from '@/base/controllers';\nimport { api, inject } from '@/base/metadata';\nimport { jsonContent, jsonResponse } from '@venizia/ignis-kernel';\nimport type { IApplicationInfo } from '@venizia/ignis-kernel';\nimport { z } from '@hono/zod-openapi';\nimport { HTTP, type ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport {\n HealthCheckBindingKeys,\n HealthCheckHeaders,\n HealthCheckRestPaths,\n type IHealthCheckOptions,\n} from './common';\nimport { HealthCheckReporter } from './reporter';\n\nconst RouteConfigs = {\n ROOT: {\n method: HTTP.Methods.GET,\n path: HealthCheckRestPaths.ROOT,\n responses: jsonResponse({\n schema: z.object({ status: z.string(), timestamp: z.iso.datetime() }).openapi({\n description: 'HealthCheck Schema',\n examples: [{ status: 'ok', timestamp: new Date().toISOString() }],\n }),\n description: 'Health check status',\n }),\n },\n STATS: {\n method: HTTP.Methods.GET,\n path: HealthCheckRestPaths.STATS,\n request: {\n headers: z.object({\n [HealthCheckHeaders.SECRET_KEY]: z.string().optional().openapi({\n description: 'The stats key',\n }),\n }),\n },\n responses: jsonResponse({\n schema: z\n .object({\n status: z.string(),\n timestamp: z.iso.datetime(),\n build: z.object({\n service: z.string(),\n version: z.string(),\n commit: z.string(),\n branch: z.string(),\n builtAt: z.string(),\n }),\n process: z.object({\n pid: z.number(),\n uptime: z.number(),\n uptimeHuman: z.string(),\n runtime: z.string(),\n environment: z.string(),\n }),\n memory: z.object({ rss: z.string(), heapUsed: z.string(), heapTotal: z.string() }),\n })\n .openapi({ description: 'HealthCheck Stats Schema' }),\n description:\n 'Build stamp, process and memory - closed outside the development environments unless enabled',\n }),\n },\n PING: {\n method: HTTP.Methods.POST,\n path: HealthCheckRestPaths.PING,\n request: {\n body: jsonContent({\n description: 'PING | Request body',\n schema: z.object({\n type: z.string().optional().default('PING'),\n message: z.string().min(1).max(255),\n }),\n }),\n },\n responses: jsonResponse({\n schema: z\n .object({\n type: z.string().optional().default('PONG'),\n date: z.iso.datetime(),\n message: z.string(),\n })\n .openapi({\n description: 'HealthCheck PingPong Schema',\n examples: [{ date: new Date().toISOString(), message: 'ok' }],\n }),\n description: 'HealthCheck PingPong Message',\n }),\n },\n} as const;\n\nexport class HealthCheckController extends BaseRestController {\n /**\n * Both dependencies arrive through the container, so two applications in one process each get\n * their own gate - a static field would let the last one to boot decide for every other.\n */\n constructor(\n @inject({ key: HealthCheckBindingKeys.HEALTH_CHECK_OPTIONS, isOptional: true })\n private readonly healthOptions: IHealthCheckOptions = {},\n @inject({ key: HealthCheckBindingKeys.APPLICATION_INFO, isOptional: true })\n private readonly appInfo?: IApplicationInfo,\n ) {\n super({ scope: HealthCheckController.name });\n\n // Note: This is optional declare internal controller route definitions\n this.definitions = RouteConfigs;\n }\n\n override binding(): ValueOrPromise<void> {\n // Public liveness probe: status and clock only. Nothing here names a runtime or a version.\n this.bindRoute({ configs: RouteConfigs.ROOT }).to({\n handler: context => {\n return context.json(HealthCheckReporter.buildSummary(), HTTP.ResultCodes.RS_2.Ok);\n },\n });\n\n if (!HealthCheckReporter.isStatsEnabled({ options: this.healthOptions })) {\n this.logger\n .for(this.binding.name)\n .debug('Stats route disabled | path: %s', HealthCheckRestPaths.STATS);\n return;\n }\n\n this.bindRoute({ configs: RouteConfigs.STATS }).to({\n handler: context => {\n // `context.notFound()`, not a thrown 404: it runs the application's own notFound handler,\n // so the refusal is byte-identical to the answer for a route that was never mounted. A\n // thrown `ApplicationError` serializes a different body and would confirm the route exists.\n if (\n !HealthCheckReporter.isStatsAuthorized({\n options: this.healthOptions,\n header: context.req.header(HealthCheckHeaders.SECRET_KEY),\n })\n ) {\n return context.notFound();\n }\n\n return context.json(\n HealthCheckReporter.buildStats({ options: this.healthOptions, appInfo: this.appInfo }),\n HTTP.ResultCodes.RS_2.Ok,\n );\n },\n });\n }\n\n // Method 3: Using 'decorators' to create a controller route, with an explicit type assertion for the validated request data\n @api({ configs: RouteConfigs.PING })\n pingPong(context: TRouteContext) {\n const { message } = context.req.valid<{ type?: string; message: string }>('json');\n\n // Return type is automatically validated against the response schema\n return context.json(\n { type: 'PONG', date: new Date().toISOString(), message },\n HTTP.ResultCodes.RS_2.Ok,\n );\n }\n}\n"]}
1
+ {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../src/components/health-check/controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseRestController, type TRouteContext } from '@/base/controllers';\nimport { api, inject } from '@/base/metadata';\nimport { jsonContent, jsonResponse } from '@venizia/ignis-kernel';\nimport type { IApplicationInfo } from '@venizia/ignis-kernel';\nimport { z } from '@hono/zod-openapi';\nimport { HTTP, type ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport {\n HealthCheckBindingKeys,\n HealthCheckHeaders,\n HealthCheckRestPaths,\n type IHealthCheckOptions,\n} from './common';\nimport { HealthCheckReporter } from './reporter';\n\nconst RouteConfigs = {\n ROOT: {\n method: HTTP.Methods.GET,\n path: HealthCheckRestPaths.ROOT,\n responses: jsonResponse({\n schema: z.object({ status: z.string(), timestamp: z.iso.datetime() }).openapi({\n description: 'HealthCheck Schema',\n examples: [{ status: 'ok', timestamp: new Date().toISOString() }],\n }),\n description: 'Health check status',\n }),\n },\n STATS: {\n method: HTTP.Methods.GET,\n path: HealthCheckRestPaths.STATS,\n request: {\n headers: z.object({\n [HealthCheckHeaders.SECRET_KEY]: z.string().optional().openapi({\n description: 'The stats key',\n }),\n }),\n },\n responses: jsonResponse({\n schema: z\n .object({\n status: z.string(),\n timestamp: z.iso.datetime(),\n build: z.object({\n service: z.string(),\n version: z.string(),\n commit: z.string(),\n branch: z.string(),\n builtAt: z.string(),\n }),\n process: z.object({\n pid: z.number(),\n uptime: z.number(),\n uptimeHuman: z.string(),\n runtime: z.string(),\n environment: z.string(),\n }),\n memory: z.object({ rss: z.string(), heapUsed: z.string(), heapTotal: z.string() }),\n })\n .openapi({ description: 'HealthCheck Stats Schema' }),\n description:\n 'Build stamp, process and memory - closed outside the development environments unless enabled',\n }),\n },\n PING: {\n method: HTTP.Methods.POST,\n path: HealthCheckRestPaths.PING,\n request: {\n body: jsonContent({\n description: 'PING | Request body',\n schema: z.object({\n type: z.string().optional().default('PING'),\n message: z.string().min(1).max(255),\n }),\n }),\n },\n responses: jsonResponse({\n schema: z\n .object({\n type: z.string().optional().default('PONG'),\n date: z.iso.datetime(),\n message: z.string(),\n })\n .openapi({\n description: 'HealthCheck PingPong Schema',\n examples: [{ date: new Date().toISOString(), message: 'ok' }],\n }),\n description: 'HealthCheck PingPong Message',\n }),\n },\n} as const;\n\nexport class HealthCheckController extends BaseRestController {\n /**\n * Both dependencies arrive through the container, so two applications in one process each get\n * their own gate - a static field would let the last one to boot decide for every other.\n */\n constructor(\n @inject({ key: HealthCheckBindingKeys.HEALTH_CHECK_OPTIONS, isOptional: true })\n private readonly healthOptions: IHealthCheckOptions = {},\n @inject({ key: HealthCheckBindingKeys.APPLICATION_INFO, isOptional: true })\n private readonly appInfo?: IApplicationInfo,\n ) {\n super({ scope: HealthCheckController.name });\n\n // Note: This is optional declare internal controller route definitions\n this.definitions = RouteConfigs;\n }\n\n override binding(): ValueOrPromise<void> {\n // Public liveness probe: status and clock only. Nothing here names a runtime or a version.\n this.bindRoute({ configs: RouteConfigs.ROOT }).to({\n handler: (context) => {\n return context.json(HealthCheckReporter.buildSummary(), HTTP.ResultCodes.RS_2.Ok);\n },\n });\n\n if (!HealthCheckReporter.isStatsEnabled({ options: this.healthOptions })) {\n this.logger\n .for(this.binding.name)\n .debug('Stats route disabled | path: %s', HealthCheckRestPaths.STATS);\n return;\n }\n\n this.bindRoute({ configs: RouteConfigs.STATS }).to({\n handler: (context) => {\n // `context.notFound()`, not a thrown 404: it runs the application's own notFound handler,\n // so the refusal is byte-identical to the answer for a route that was never mounted. A\n // thrown `ApplicationError` serializes a different body and would confirm the route exists.\n if (\n !HealthCheckReporter.isStatsAuthorized({\n options: this.healthOptions,\n header: context.req.header(HealthCheckHeaders.SECRET_KEY),\n })\n ) {\n return context.notFound();\n }\n\n return context.json(\n HealthCheckReporter.buildStats({ options: this.healthOptions, appInfo: this.appInfo }),\n HTTP.ResultCodes.RS_2.Ok,\n );\n },\n });\n }\n\n // Method 3: Using 'decorators' to create a controller route, with an explicit type assertion for the validated request data\n @api({ configs: RouteConfigs.PING })\n pingPong(context: TRouteContext) {\n const { message } = context.req.valid<{ type?: string; message: string }>('json');\n\n // Return type is automatically validated against the response schema\n return context.json(\n { type: 'PONG', date: new Date().toISOString(), message },\n HTTP.ResultCodes.RS_2.Ok,\n );\n }\n}\n"]}
@@ -145,7 +145,7 @@ class BullMQMailExecutorHelper extends core_1.BaseHelper {
145
145
  async closeWorkers() {
146
146
  const workerHelpers = this.workerHelpers;
147
147
  this.workerHelpers = [];
148
- const results = await Promise.allSettled(workerHelpers.map(workerHelper => workerHelper.worker.close()));
148
+ const results = await Promise.allSettled(workerHelpers.map((workerHelper) => workerHelper.worker.close()));
149
149
  const failures = [];
150
150
  for (const result of results) {
151
151
  if (result.status !== 'rejected') {
@@ -190,7 +190,7 @@ class BullMQMailExecutorHelper extends core_1.BaseHelper {
190
190
  if (failures.length > 0) {
191
191
  throw (0, core_1.getError)({
192
192
  message: `[close] Incomplete BullMQ mail executor teardown | failures: ${failures
193
- .map(failure => failure.message)
193
+ .map((failure) => failure.message)
194
194
  .join(' | ')}`,
195
195
  });
196
196
  }