@venizia/ignis-kernel 0.4.0 → 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 (139) hide show
  1. package/dist/cjs/base/applications/abstract.js +2 -2
  2. package/dist/cjs/base/applications/abstract.js.map +1 -1
  3. package/dist/cjs/base/applications/artifact-group.js +1 -1
  4. package/dist/cjs/base/applications/artifact-group.js.map +1 -1
  5. package/dist/cjs/base/applications/artifact-index.js +11 -11
  6. package/dist/cjs/base/applications/artifact-index.js.map +1 -1
  7. package/dist/cjs/base/applications/boot-sequence.js +1 -1
  8. package/dist/cjs/base/applications/boot-sequence.js.map +1 -1
  9. package/dist/cjs/base/applications/rest.js +5 -5
  10. package/dist/cjs/base/applications/rest.js.map +1 -1
  11. package/dist/cjs/base/auth/authenticate/common/codecs.js +2 -2
  12. package/dist/cjs/base/auth/authenticate/common/codecs.js.map +1 -1
  13. package/dist/cjs/base/auth/authenticate/providers/authentication.provider.js +1 -1
  14. package/dist/cjs/base/auth/authenticate/providers/authentication.provider.js.map +1 -1
  15. package/dist/cjs/base/auth/authenticate/strategies/strategy-registry.js +1 -1
  16. package/dist/cjs/base/auth/authenticate/strategies/strategy-registry.js.map +1 -1
  17. package/dist/cjs/base/auth/authorize/builders/grant.builder.js +12 -12
  18. package/dist/cjs/base/auth/authorize/builders/grant.builder.js.map +1 -1
  19. package/dist/cjs/base/auth/authorize/builders/permission.builder.js +1 -1
  20. package/dist/cjs/base/auth/authorize/builders/permission.builder.js.map +1 -1
  21. package/dist/cjs/base/auth/authorize/builders/policy.builder.js +1 -1
  22. package/dist/cjs/base/auth/authorize/builders/policy.builder.js.map +1 -1
  23. package/dist/cjs/base/auth/authorize/common/constants/authorization.d.ts.map +1 -1
  24. package/dist/cjs/base/auth/authorize/common/constants/authorization.js +2 -2
  25. package/dist/cjs/base/auth/authorize/common/constants/authorization.js.map +1 -1
  26. package/dist/cjs/base/auth/authorize/enforcers/enforcer-registry.js +1 -1
  27. package/dist/cjs/base/auth/authorize/enforcers/enforcer-registry.js.map +1 -1
  28. package/dist/cjs/base/auth/authorize/providers/authorization.provider.js +3 -3
  29. package/dist/cjs/base/auth/authorize/providers/authorization.provider.js.map +1 -1
  30. package/dist/cjs/base/controllers/factory/controller.d.ts +2 -2
  31. package/dist/cjs/base/controllers/factory/controller.d.ts.map +1 -1
  32. package/dist/cjs/base/controllers/factory/controller.js +1 -0
  33. package/dist/cjs/base/controllers/factory/controller.js.map +1 -1
  34. package/dist/cjs/base/controllers/factory/crud/abstract.d.ts +1 -1
  35. package/dist/cjs/base/controllers/factory/crud/abstract.d.ts.map +1 -1
  36. package/dist/cjs/base/controllers/factory/crud/abstract.js.map +1 -1
  37. package/dist/cjs/base/controllers/factory/definition.js +1 -1
  38. package/dist/cjs/base/controllers/factory/definition.js.map +1 -1
  39. package/dist/cjs/base/controllers/rest/extras.js +5 -5
  40. package/dist/cjs/base/controllers/rest/extras.js.map +1 -1
  41. package/dist/cjs/base/metadata/injectable.js +1 -1
  42. package/dist/cjs/base/metadata/injectable.js.map +1 -1
  43. package/dist/cjs/base/metadata/persistents.js +4 -4
  44. package/dist/cjs/base/metadata/persistents.js.map +1 -1
  45. package/dist/cjs/base/metadata/routes/controller.js +1 -1
  46. package/dist/cjs/base/metadata/routes/controller.js.map +1 -1
  47. package/dist/cjs/base/middlewares/app-error/app-error.middleware.js +3 -3
  48. package/dist/cjs/base/middlewares/app-error/app-error.middleware.js.map +1 -1
  49. package/dist/cjs/base/middlewares/app-error/zod.handler.js +2 -2
  50. package/dist/cjs/base/middlewares/app-error/zod.handler.js.map +1 -1
  51. package/dist/cjs/base/middlewares/form-body/form-body.middleware.js +2 -2
  52. package/dist/cjs/base/middlewares/form-body/form-body.middleware.js.map +1 -1
  53. package/dist/cjs/base/middlewares/not-found/not-found.middleware.js.map +1 -1
  54. package/dist/cjs/base/models/common/utilities.js +1 -1
  55. package/dist/cjs/base/models/common/utilities.js.map +1 -1
  56. package/dist/cjs/base/repositories/common/types/contracts.d.ts +17 -17
  57. package/dist/cjs/base/repositories/common/types/contracts.d.ts.map +1 -1
  58. package/dist/cjs/base/repositories/common/types/contracts.js.map +1 -1
  59. package/dist/cjs/base/repositories/core/abstract.d.ts +17 -17
  60. package/dist/cjs/base/repositories/core/abstract.d.ts.map +1 -1
  61. package/dist/cjs/base/repositories/core/abstract.js +4 -3
  62. package/dist/cjs/base/repositories/core/abstract.js.map +1 -1
  63. package/dist/cjs/helpers/inversion/mixins/model.mixin.js +1 -1
  64. package/dist/cjs/helpers/inversion/mixins/model.mixin.js.map +1 -1
  65. package/dist/cjs/helpers/inversion/mixins/repository.mixin.js +1 -1
  66. package/dist/cjs/helpers/inversion/mixins/repository.mixin.js.map +1 -1
  67. package/dist/cjs/repository.d.ts +1 -1
  68. package/dist/cjs/repository.d.ts.map +1 -1
  69. package/dist/cjs/repository.js.map +1 -1
  70. package/dist/esm/base/applications/abstract.js +2 -2
  71. package/dist/esm/base/applications/abstract.js.map +1 -1
  72. package/dist/esm/base/applications/artifact-group.js +1 -1
  73. package/dist/esm/base/applications/artifact-group.js.map +1 -1
  74. package/dist/esm/base/applications/artifact-index.js +11 -11
  75. package/dist/esm/base/applications/artifact-index.js.map +1 -1
  76. package/dist/esm/base/applications/boot-sequence.js +1 -1
  77. package/dist/esm/base/applications/boot-sequence.js.map +1 -1
  78. package/dist/esm/base/applications/rest.js +5 -5
  79. package/dist/esm/base/applications/rest.js.map +1 -1
  80. package/dist/esm/base/auth/authenticate/common/codecs.js +2 -2
  81. package/dist/esm/base/auth/authenticate/common/codecs.js.map +1 -1
  82. package/dist/esm/base/auth/authenticate/providers/authentication.provider.js +1 -1
  83. package/dist/esm/base/auth/authenticate/providers/authentication.provider.js.map +1 -1
  84. package/dist/esm/base/auth/authenticate/strategies/strategy-registry.js +1 -1
  85. package/dist/esm/base/auth/authenticate/strategies/strategy-registry.js.map +1 -1
  86. package/dist/esm/base/auth/authorize/builders/grant.builder.js +12 -12
  87. package/dist/esm/base/auth/authorize/builders/grant.builder.js.map +1 -1
  88. package/dist/esm/base/auth/authorize/builders/permission.builder.js +1 -1
  89. package/dist/esm/base/auth/authorize/builders/permission.builder.js.map +1 -1
  90. package/dist/esm/base/auth/authorize/builders/policy.builder.js +1 -1
  91. package/dist/esm/base/auth/authorize/builders/policy.builder.js.map +1 -1
  92. package/dist/esm/base/auth/authorize/common/constants/authorization.d.ts.map +1 -1
  93. package/dist/esm/base/auth/authorize/common/constants/authorization.js +2 -2
  94. package/dist/esm/base/auth/authorize/common/constants/authorization.js.map +1 -1
  95. package/dist/esm/base/auth/authorize/enforcers/enforcer-registry.js +1 -1
  96. package/dist/esm/base/auth/authorize/enforcers/enforcer-registry.js.map +1 -1
  97. package/dist/esm/base/auth/authorize/providers/authorization.provider.js +3 -3
  98. package/dist/esm/base/auth/authorize/providers/authorization.provider.js.map +1 -1
  99. package/dist/esm/base/controllers/factory/controller.d.ts +2 -2
  100. package/dist/esm/base/controllers/factory/controller.d.ts.map +1 -1
  101. package/dist/esm/base/controllers/factory/controller.js +1 -0
  102. package/dist/esm/base/controllers/factory/controller.js.map +1 -1
  103. package/dist/esm/base/controllers/factory/crud/abstract.d.ts +1 -1
  104. package/dist/esm/base/controllers/factory/crud/abstract.d.ts.map +1 -1
  105. package/dist/esm/base/controllers/factory/crud/abstract.js.map +1 -1
  106. package/dist/esm/base/controllers/factory/definition.js +1 -1
  107. package/dist/esm/base/controllers/factory/definition.js.map +1 -1
  108. package/dist/esm/base/controllers/rest/extras.js +5 -5
  109. package/dist/esm/base/controllers/rest/extras.js.map +1 -1
  110. package/dist/esm/base/metadata/injectable.js +1 -1
  111. package/dist/esm/base/metadata/injectable.js.map +1 -1
  112. package/dist/esm/base/metadata/persistents.js +4 -4
  113. package/dist/esm/base/metadata/persistents.js.map +1 -1
  114. package/dist/esm/base/metadata/routes/controller.js +1 -1
  115. package/dist/esm/base/metadata/routes/controller.js.map +1 -1
  116. package/dist/esm/base/middlewares/app-error/app-error.middleware.js +3 -3
  117. package/dist/esm/base/middlewares/app-error/app-error.middleware.js.map +1 -1
  118. package/dist/esm/base/middlewares/app-error/zod.handler.js +2 -2
  119. package/dist/esm/base/middlewares/app-error/zod.handler.js.map +1 -1
  120. package/dist/esm/base/middlewares/form-body/form-body.middleware.js +2 -2
  121. package/dist/esm/base/middlewares/form-body/form-body.middleware.js.map +1 -1
  122. package/dist/esm/base/middlewares/not-found/not-found.middleware.js.map +1 -1
  123. package/dist/esm/base/models/common/utilities.js +1 -1
  124. package/dist/esm/base/models/common/utilities.js.map +1 -1
  125. package/dist/esm/base/repositories/common/types/contracts.d.ts +17 -17
  126. package/dist/esm/base/repositories/common/types/contracts.d.ts.map +1 -1
  127. package/dist/esm/base/repositories/common/types/contracts.js.map +1 -1
  128. package/dist/esm/base/repositories/core/abstract.d.ts +17 -17
  129. package/dist/esm/base/repositories/core/abstract.d.ts.map +1 -1
  130. package/dist/esm/base/repositories/core/abstract.js +4 -3
  131. package/dist/esm/base/repositories/core/abstract.js.map +1 -1
  132. package/dist/esm/helpers/inversion/mixins/model.mixin.js +1 -1
  133. package/dist/esm/helpers/inversion/mixins/model.mixin.js.map +1 -1
  134. package/dist/esm/helpers/inversion/mixins/repository.mixin.js +1 -1
  135. package/dist/esm/helpers/inversion/mixins/repository.mixin.js.map +1 -1
  136. package/dist/esm/repository.d.ts +1 -1
  137. package/dist/esm/repository.d.ts.map +1 -1
  138. package/dist/esm/repository.js.map +1 -1
  139. package/package.json +6 -6
@@ -136,9 +136,9 @@ export class GrantBuilder extends BaseHelper {
136
136
  if (!ops.length) {
137
137
  throw getError({ message: '[planGrant] intent.ops must not be empty.' });
138
138
  }
139
- const subjectCatalog = opts.catalog.filter(entry => entry.subject === opts.resource.subject);
140
- const byMethod = new Map(subjectCatalog.map(entry => [entry.method, entry]));
141
- const unknown = ops.filter(op => !byMethod.has(op));
139
+ const subjectCatalog = opts.catalog.filter((entry) => entry.subject === opts.resource.subject);
140
+ const byMethod = new Map(subjectCatalog.map((entry) => [entry.method, entry]));
141
+ const unknown = ops.filter((op) => !byMethod.has(op));
142
142
  if (unknown.length) {
143
143
  throw getError({
144
144
  message: `[planGrant] Unknown operations for resource "${opts.resource.subject}": ${unknown.join(', ')}`,
@@ -156,7 +156,7 @@ export class GrantBuilder extends BaseHelper {
156
156
  if (opts.exact !== true) {
157
157
  this.collapseRemainingIntoTiers({ subjectCatalog, remaining, rows, tierRow });
158
158
  }
159
- const leftover = ops.filter(op => remaining.has(op));
159
+ const leftover = ops.filter((op) => remaining.has(op));
160
160
  if (!leftover.length) {
161
161
  return rows;
162
162
  }
@@ -190,17 +190,17 @@ export class GrantBuilder extends BaseHelper {
190
190
  collapseRemainingIntoTiers(opts) {
191
191
  const { subjectCatalog, remaining, rows, tierRow } = opts;
192
192
  // manage equals read+write+execute only when the subject has at least one operation in EACH narrow tier; otherwise manage also covers a future tier, which is more than the narrow tiers confer today.
193
- const spansAllNarrowTiers = GrantBuilder.NARROW_TIERS.every(tier => {
193
+ const spansAllNarrowTiers = GrantBuilder.NARROW_TIERS.every((tier) => {
194
194
  const covered = this.actionsCoveredBy({ tier });
195
- return subjectCatalog.some(entry => covered.has(entry.action));
195
+ return subjectCatalog.some((entry) => covered.has(entry.action));
196
196
  });
197
197
  const manageCovered = this.actionsCoveredBy({ tier: AuthorizationActions.MANAGE });
198
198
  const manageOps = subjectCatalog
199
- .filter(entry => manageCovered.has(entry.action))
200
- .map(entry => entry.method);
199
+ .filter((entry) => manageCovered.has(entry.action))
200
+ .map((entry) => entry.method);
201
201
  if (spansAllNarrowTiers &&
202
202
  manageOps.length &&
203
- manageOps.every(method => remaining.has(method))) {
203
+ manageOps.every((method) => remaining.has(method))) {
204
204
  rows.push(tierRow(AuthorizationActions.MANAGE));
205
205
  for (const method of manageOps) {
206
206
  remaining.delete(method);
@@ -210,9 +210,9 @@ export class GrantBuilder extends BaseHelper {
210
210
  for (const tier of GrantBuilder.NARROW_TIERS) {
211
211
  const covered = this.actionsCoveredBy({ tier });
212
212
  const methods = subjectCatalog
213
- .filter(entry => covered.has(entry.action))
214
- .map(entry => entry.method);
215
- if (!methods.length || !methods.every(method => remaining.has(method))) {
213
+ .filter((entry) => covered.has(entry.action))
214
+ .map((entry) => entry.method);
215
+ if (!methods.length || !methods.every((method) => remaining.has(method))) {
216
216
  continue;
217
217
  }
218
218
  rows.push(tierRow(tier));
@@ -1 +1 @@
1
- {"version":3,"file":"grant.builder.js","sourceRoot":"","sources":["../../../../../../src/base/auth/authorize/builders/grant.builder.ts"],"names":[],"mappings":"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","sourcesContent":["import { SingletonRealm } from '@/helpers/singleton-realm';\nimport type { IdType } from '@/base';\nimport { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport { type TNullable } from '@venizia/ignis-helpers/common';\nimport {\n AuthorizationActions,\n AuthorizationDecisions,\n type TAuthorizationAction,\n type TAuthorizationDecision,\n type TGrantIntent,\n type TPlannedGrantRow,\n} from '../common';\nimport { AuthorizationPolicyBuilder, type TPolicyDomainInput } from './policy.builder';\n\n/** One closure pass over the action lattice: adds every child reachable from an already-covered parent, reporting whether the set grew. */\nconst expandCoveredActions = (opts: { covered: Set<string> }): boolean => {\n const { covered } = opts;\n let grew = false;\n\n for (const edge of AuthorizationActions.LATTICE) {\n if (!covered.has(edge.parent) || covered.has(edge.child)) {\n continue;\n }\n\n covered.add(edge.child);\n grew = true;\n }\n\n return grew;\n};\n\nexport class GrantBuilder extends BaseHelper {\n static readonly SINGLETON_REAL_KEY = 'grant-builder';\n\n /** Tiers a caller may ask for; `custom` is an encoding marker and is never a valid intent. */\n private static readonly PLANNABLE_TIERS = new Set<string>([\n AuthorizationActions.READ,\n AuthorizationActions.WRITE,\n AuthorizationActions.EXECUTE,\n AuthorizationActions.MANAGE,\n ]);\n\n /** Tried after `manage`; disjoint from each other, since an operation has one catalogued action. */\n private static readonly NARROW_TIERS: ReadonlyArray<TAuthorizationAction> = [\n AuthorizationActions.READ,\n AuthorizationActions.WRITE,\n AuthorizationActions.EXECUTE,\n ];\n\n constructor() {\n super({ scope: GrantBuilder.name });\n }\n\n static getInstance() {\n return SingletonRealm.resolve({\n key: GrantBuilder.SINGLETON_REAL_KEY,\n create: () => new GrantBuilder(),\n });\n }\n\n decodeMetadata<MetadataType = unknown>(opts: { metadata: MetadataType }) {\n if (typeof opts.metadata !== 'string') {\n return opts.metadata;\n }\n\n try {\n return JSON.parse(opts.metadata);\n } catch (error) {\n this.logger\n .for(this.decodeMetadata.name)\n .error('Failed to parse metadata | Error: %s', error);\n return null;\n }\n }\n\n /** Read `{ ops }` off a grant row's metadata, or null when the shape is unusable. Callers treat null as a defect to log and skip - never as an empty grant. */\n parseCustomGrantMetadata(opts: { metadata: unknown }): { ops: string[] } | null {\n const decoded = this.decodeMetadata(opts);\n\n if (typeof decoded !== 'object' || decoded === null || Array.isArray(decoded)) {\n return null;\n }\n\n const ops = (decoded as { ops?: unknown }).ops;\n if (!Array.isArray(ops) || ops.length === 0) {\n return null;\n }\n\n const seen = new Set<string>();\n const unique: string[] = [];\n\n for (const op of ops) {\n if (typeof op !== 'string' || op.length === 0) {\n return null;\n }\n\n if (!seen.has(op)) {\n seen.add(op);\n unique.push(op);\n }\n }\n\n return { ops: unique };\n }\n\n /** Split operation names into those present in the catalog for `subject` and those that are not. Pure - the caller supplies the catalog slice; the adapter re-runs this independently at read time. */\n validateCustomGrantOps(opts: {\n ops: string[];\n subject: string;\n catalog: Array<{ subject: string; method: string }>;\n }): { valid: string[]; unknown: string[] } {\n const known = new Set<string>();\n\n for (const entry of opts.catalog) {\n if (entry.subject === opts.subject) {\n known.add(entry.method);\n }\n }\n\n const valid: string[] = [];\n const unknown: string[] = [];\n\n for (const op of opts.ops) {\n if (known.has(op)) {\n valid.push(op);\n continue;\n }\n\n unknown.push(op);\n }\n\n return { valid, unknown };\n }\n\n /** Actions a tier confers, derived from LATTICE rather than hardcoded so the two cannot drift. */\n actionsCoveredBy(opts: { tier: TAuthorizationAction }): Set<string> {\n const covered = new Set<string>([opts.tier]);\n\n let grew = true;\n while (grew) {\n grew = expandCoveredActions({ covered });\n }\n\n return covered;\n }\n\n /** Decide which rows express an intent: a custom row is a last resort, so as much of the selection as possible collapses into tier grants first. `exact` disables collapsing when the caller means these operations and no future ones. Pure - the caller supplies the catalog and persists. */\n planGrant(opts: {\n subject: { type: string; id: IdType };\n resource: { type: string; id: IdType; subject: string };\n intent: TGrantIntent;\n catalog: Array<{ subject: string; method: string; code: string; action: string }>;\n domain?: TNullable<TPolicyDomainInput>;\n effect?: TAuthorizationDecision;\n supportsCustomMetadata?: boolean;\n exact?: boolean;\n }): TPlannedGrantRow[] {\n const effect = opts.effect ?? AuthorizationDecisions.ALLOW;\n const domain = opts.domain ?? null;\n\n if ('tier' in opts.intent) {\n if (!GrantBuilder.PLANNABLE_TIERS.has(opts.intent.tier)) {\n throw getError({\n message: `[planGrant] Invalid tier: ${opts.intent.tier} | Valids: [${[...GrantBuilder.PLANNABLE_TIERS].join(', ')}]`,\n });\n }\n\n return [\n AuthorizationPolicyBuilder.grant({\n subject: opts.subject,\n permission: { type: opts.resource.type, id: opts.resource.id },\n action: opts.intent.tier,\n domain,\n effect,\n }),\n ];\n }\n\n const seen = new Set<string>();\n const ops: string[] = [];\n\n for (const op of opts.intent.ops) {\n if (seen.has(op)) {\n continue;\n }\n\n seen.add(op);\n ops.push(op);\n }\n\n if (!ops.length) {\n throw getError({ message: '[planGrant] intent.ops must not be empty.' });\n }\n\n const subjectCatalog = opts.catalog.filter(entry => entry.subject === opts.resource.subject);\n const byMethod = new Map(subjectCatalog.map(entry => [entry.method, entry]));\n\n const unknown = ops.filter(op => !byMethod.has(op));\n if (unknown.length) {\n throw getError({\n message: `[planGrant] Unknown operations for resource \"${opts.resource.subject}\": ${unknown.join(', ')}`,\n });\n }\n\n const tierRow = (tier: TAuthorizationAction) =>\n AuthorizationPolicyBuilder.grant({\n subject: opts.subject,\n permission: { type: opts.resource.type, id: opts.resource.id },\n action: tier,\n domain,\n effect,\n });\n\n const rows: TPlannedGrantRow[] = [];\n const remaining = new Set(ops);\n\n if (opts.exact !== true) {\n this.collapseRemainingIntoTiers({ subjectCatalog, remaining, rows, tierRow });\n }\n\n const leftover = ops.filter(op => remaining.has(op));\n\n if (!leftover.length) {\n return rows;\n }\n\n const isPerOperationGrant = leftover.length === 1 || opts.supportsCustomMetadata === false;\n\n if (!isPerOperationGrant) {\n rows.push(\n AuthorizationPolicyBuilder.customGrant({\n subject: opts.subject,\n permission: { type: opts.resource.type, id: opts.resource.id },\n ops: leftover,\n domain,\n effect,\n }),\n );\n\n return rows;\n }\n\n for (const op of leftover) {\n const entry = byMethod.get(op);\n if (!entry) {\n throw getError({ message: `[planGrant] No catalog entry for operation \"${op}\".` });\n }\n\n rows.push(\n AuthorizationPolicyBuilder.grant({\n subject: opts.subject,\n permission: { type: opts.resource.type, id: entry.code },\n action: entry.action,\n domain,\n effect,\n }),\n );\n }\n\n return rows;\n }\n\n /** Collapse `remaining` into the fewest tier grants, mutating `remaining` and appending to `rows`. */\n protected collapseRemainingIntoTiers(opts: {\n subjectCatalog: Array<{ subject: string; method: string; code: string; action: string }>;\n remaining: Set<string>;\n rows: TPlannedGrantRow[];\n tierRow: (tier: TAuthorizationAction) => TPlannedGrantRow;\n }): void {\n const { subjectCatalog, remaining, rows, tierRow } = opts;\n\n // manage equals read+write+execute only when the subject has at least one operation in EACH narrow tier; otherwise manage also covers a future tier, which is more than the narrow tiers confer today.\n const spansAllNarrowTiers = GrantBuilder.NARROW_TIERS.every(tier => {\n const covered = this.actionsCoveredBy({ tier });\n return subjectCatalog.some(entry => covered.has(entry.action));\n });\n\n const manageCovered = this.actionsCoveredBy({ tier: AuthorizationActions.MANAGE });\n const manageOps = subjectCatalog\n .filter(entry => manageCovered.has(entry.action))\n .map(entry => entry.method);\n\n if (\n spansAllNarrowTiers &&\n manageOps.length &&\n manageOps.every(method => remaining.has(method))\n ) {\n rows.push(tierRow(AuthorizationActions.MANAGE));\n for (const method of manageOps) {\n remaining.delete(method);\n }\n\n return;\n }\n\n for (const tier of GrantBuilder.NARROW_TIERS) {\n const covered = this.actionsCoveredBy({ tier });\n const methods = subjectCatalog\n .filter(entry => covered.has(entry.action))\n .map(entry => entry.method);\n\n if (!methods.length || !methods.every(method => remaining.has(method))) {\n continue;\n }\n\n rows.push(tierRow(tier));\n for (const method of methods) {\n remaining.delete(method);\n }\n }\n }\n}\n"]}
1
+ {"version":3,"file":"grant.builder.js","sourceRoot":"","sources":["../../../../../../src/base/auth/authorize/builders/grant.builder.ts"],"names":[],"mappings":"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","sourcesContent":["import { SingletonRealm } from '@/helpers/singleton-realm';\nimport type { IdType } from '@/base';\nimport { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport { type TNullable } from '@venizia/ignis-helpers/common';\nimport {\n AuthorizationActions,\n AuthorizationDecisions,\n type TAuthorizationAction,\n type TAuthorizationDecision,\n type TGrantIntent,\n type TPlannedGrantRow,\n} from '../common';\nimport { AuthorizationPolicyBuilder, type TPolicyDomainInput } from './policy.builder';\n\n/** One closure pass over the action lattice: adds every child reachable from an already-covered parent, reporting whether the set grew. */\nconst expandCoveredActions = (opts: { covered: Set<string> }): boolean => {\n const { covered } = opts;\n let grew = false;\n\n for (const edge of AuthorizationActions.LATTICE) {\n if (!covered.has(edge.parent) || covered.has(edge.child)) {\n continue;\n }\n\n covered.add(edge.child);\n grew = true;\n }\n\n return grew;\n};\n\nexport class GrantBuilder extends BaseHelper {\n static readonly SINGLETON_REAL_KEY = 'grant-builder';\n\n /** Tiers a caller may ask for; `custom` is an encoding marker and is never a valid intent. */\n private static readonly PLANNABLE_TIERS = new Set<string>([\n AuthorizationActions.READ,\n AuthorizationActions.WRITE,\n AuthorizationActions.EXECUTE,\n AuthorizationActions.MANAGE,\n ]);\n\n /** Tried after `manage`; disjoint from each other, since an operation has one catalogued action. */\n private static readonly NARROW_TIERS: ReadonlyArray<TAuthorizationAction> = [\n AuthorizationActions.READ,\n AuthorizationActions.WRITE,\n AuthorizationActions.EXECUTE,\n ];\n\n constructor() {\n super({ scope: GrantBuilder.name });\n }\n\n static getInstance() {\n return SingletonRealm.resolve({\n key: GrantBuilder.SINGLETON_REAL_KEY,\n create: () => new GrantBuilder(),\n });\n }\n\n decodeMetadata<MetadataType = unknown>(opts: { metadata: MetadataType }) {\n if (typeof opts.metadata !== 'string') {\n return opts.metadata;\n }\n\n try {\n return JSON.parse(opts.metadata);\n } catch (error) {\n this.logger\n .for(this.decodeMetadata.name)\n .error('Failed to parse metadata | Error: %s', error);\n return null;\n }\n }\n\n /** Read `{ ops }` off a grant row's metadata, or null when the shape is unusable. Callers treat null as a defect to log and skip - never as an empty grant. */\n parseCustomGrantMetadata(opts: { metadata: unknown }): { ops: string[] } | null {\n const decoded = this.decodeMetadata(opts);\n\n if (typeof decoded !== 'object' || decoded === null || Array.isArray(decoded)) {\n return null;\n }\n\n const ops = (decoded as { ops?: unknown }).ops;\n if (!Array.isArray(ops) || ops.length === 0) {\n return null;\n }\n\n const seen = new Set<string>();\n const unique: string[] = [];\n\n for (const op of ops) {\n if (typeof op !== 'string' || op.length === 0) {\n return null;\n }\n\n if (!seen.has(op)) {\n seen.add(op);\n unique.push(op);\n }\n }\n\n return { ops: unique };\n }\n\n /** Split operation names into those present in the catalog for `subject` and those that are not. Pure - the caller supplies the catalog slice; the adapter re-runs this independently at read time. */\n validateCustomGrantOps(opts: {\n ops: string[];\n subject: string;\n catalog: Array<{ subject: string; method: string }>;\n }): { valid: string[]; unknown: string[] } {\n const known = new Set<string>();\n\n for (const entry of opts.catalog) {\n if (entry.subject === opts.subject) {\n known.add(entry.method);\n }\n }\n\n const valid: string[] = [];\n const unknown: string[] = [];\n\n for (const op of opts.ops) {\n if (known.has(op)) {\n valid.push(op);\n continue;\n }\n\n unknown.push(op);\n }\n\n return { valid, unknown };\n }\n\n /** Actions a tier confers, derived from LATTICE rather than hardcoded so the two cannot drift. */\n actionsCoveredBy(opts: { tier: TAuthorizationAction }): Set<string> {\n const covered = new Set<string>([opts.tier]);\n\n let grew = true;\n while (grew) {\n grew = expandCoveredActions({ covered });\n }\n\n return covered;\n }\n\n /** Decide which rows express an intent: a custom row is a last resort, so as much of the selection as possible collapses into tier grants first. `exact` disables collapsing when the caller means these operations and no future ones. Pure - the caller supplies the catalog and persists. */\n planGrant(opts: {\n subject: { type: string; id: IdType };\n resource: { type: string; id: IdType; subject: string };\n intent: TGrantIntent;\n catalog: Array<{ subject: string; method: string; code: string; action: string }>;\n domain?: TNullable<TPolicyDomainInput>;\n effect?: TAuthorizationDecision;\n supportsCustomMetadata?: boolean;\n exact?: boolean;\n }): TPlannedGrantRow[] {\n const effect = opts.effect ?? AuthorizationDecisions.ALLOW;\n const domain = opts.domain ?? null;\n\n if ('tier' in opts.intent) {\n if (!GrantBuilder.PLANNABLE_TIERS.has(opts.intent.tier)) {\n throw getError({\n message: `[planGrant] Invalid tier: ${opts.intent.tier} | Valids: [${[...GrantBuilder.PLANNABLE_TIERS].join(', ')}]`,\n });\n }\n\n return [\n AuthorizationPolicyBuilder.grant({\n subject: opts.subject,\n permission: { type: opts.resource.type, id: opts.resource.id },\n action: opts.intent.tier,\n domain,\n effect,\n }),\n ];\n }\n\n const seen = new Set<string>();\n const ops: string[] = [];\n\n for (const op of opts.intent.ops) {\n if (seen.has(op)) {\n continue;\n }\n\n seen.add(op);\n ops.push(op);\n }\n\n if (!ops.length) {\n throw getError({ message: '[planGrant] intent.ops must not be empty.' });\n }\n\n const subjectCatalog = opts.catalog.filter((entry) => entry.subject === opts.resource.subject);\n const byMethod = new Map(subjectCatalog.map((entry) => [entry.method, entry]));\n\n const unknown = ops.filter((op) => !byMethod.has(op));\n if (unknown.length) {\n throw getError({\n message: `[planGrant] Unknown operations for resource \"${opts.resource.subject}\": ${unknown.join(', ')}`,\n });\n }\n\n const tierRow = (tier: TAuthorizationAction) =>\n AuthorizationPolicyBuilder.grant({\n subject: opts.subject,\n permission: { type: opts.resource.type, id: opts.resource.id },\n action: tier,\n domain,\n effect,\n });\n\n const rows: TPlannedGrantRow[] = [];\n const remaining = new Set(ops);\n\n if (opts.exact !== true) {\n this.collapseRemainingIntoTiers({ subjectCatalog, remaining, rows, tierRow });\n }\n\n const leftover = ops.filter((op) => remaining.has(op));\n\n if (!leftover.length) {\n return rows;\n }\n\n const isPerOperationGrant = leftover.length === 1 || opts.supportsCustomMetadata === false;\n\n if (!isPerOperationGrant) {\n rows.push(\n AuthorizationPolicyBuilder.customGrant({\n subject: opts.subject,\n permission: { type: opts.resource.type, id: opts.resource.id },\n ops: leftover,\n domain,\n effect,\n }),\n );\n\n return rows;\n }\n\n for (const op of leftover) {\n const entry = byMethod.get(op);\n if (!entry) {\n throw getError({ message: `[planGrant] No catalog entry for operation \"${op}\".` });\n }\n\n rows.push(\n AuthorizationPolicyBuilder.grant({\n subject: opts.subject,\n permission: { type: opts.resource.type, id: entry.code },\n action: entry.action,\n domain,\n effect,\n }),\n );\n }\n\n return rows;\n }\n\n /** Collapse `remaining` into the fewest tier grants, mutating `remaining` and appending to `rows`. */\n protected collapseRemainingIntoTiers(opts: {\n subjectCatalog: Array<{ subject: string; method: string; code: string; action: string }>;\n remaining: Set<string>;\n rows: TPlannedGrantRow[];\n tierRow: (tier: TAuthorizationAction) => TPlannedGrantRow;\n }): void {\n const { subjectCatalog, remaining, rows, tierRow } = opts;\n\n // manage equals read+write+execute only when the subject has at least one operation in EACH narrow tier; otherwise manage also covers a future tier, which is more than the narrow tiers confer today.\n const spansAllNarrowTiers = GrantBuilder.NARROW_TIERS.every((tier) => {\n const covered = this.actionsCoveredBy({ tier });\n return subjectCatalog.some((entry) => covered.has(entry.action));\n });\n\n const manageCovered = this.actionsCoveredBy({ tier: AuthorizationActions.MANAGE });\n const manageOps = subjectCatalog\n .filter((entry) => manageCovered.has(entry.action))\n .map((entry) => entry.method);\n\n if (\n spansAllNarrowTiers &&\n manageOps.length &&\n manageOps.every((method) => remaining.has(method))\n ) {\n rows.push(tierRow(AuthorizationActions.MANAGE));\n for (const method of manageOps) {\n remaining.delete(method);\n }\n\n return;\n }\n\n for (const tier of GrantBuilder.NARROW_TIERS) {\n const covered = this.actionsCoveredBy({ tier });\n const methods = subjectCatalog\n .filter((entry) => covered.has(entry.action))\n .map((entry) => entry.method);\n\n if (!methods.length || !methods.every((method) => remaining.has(method))) {\n continue;\n }\n\n rows.push(tierRow(tier));\n for (const method of methods) {\n remaining.delete(method);\n }\n }\n }\n}\n"]}
@@ -60,7 +60,7 @@ export class AuthorizationPermissionBuilder {
60
60
  /** The CRUD permission set for a subject. `name` (and optional `description`) are per-method formatters, so the app supplies its own labels/i18n; the framework only owns the method-to-action map and the code shape. */
61
61
  static crud(opts) {
62
62
  const methods = opts.methods ?? AuthorizationPermissionBuilder.DEFAULT_CRUD_METHODS;
63
- return methods.map(method => {
63
+ return methods.map((method) => {
64
64
  const action = AuthorizationPermissionBuilder.actionForMethod(method);
65
65
  const ctx = {
66
66
  subject: opts.subject,
@@ -1 +1 @@
1
- {"version":3,"file":"permission.builder.js","sourceRoot":"","sources":["../../../../../../src/base/auth/authorize/builders/permission.builder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IdType } from '@/base';\nimport type { TNullable } from '@venizia/ignis-helpers/common';\nimport type { TAuthorizationAction } from '../common/constants';\nimport { AuthorizationActions } from '../common/constants';\n\n/** Builders for `Permission` catalog rows (the `obj` axis the scoped matcher resolves), generic over `TName` so i18n and plain-text apps both fit; only framework-owned columns (code/subject/method/action/scope/description/parentId) are produced - app columns are added by the caller. */\nexport class AuthorizationPermissionBuilder {\n /** Sentinel `method` for a coarse resource node (a grant target that is not a route). */\n static readonly RESOURCE_NODE_METHOD = '*';\n\n /** Standard repository method → base action. Unlisted methods (custom ops, aggregates) resolve to `execute`. */\n static readonly METHOD_ACTIONS: Readonly<Record<string, TAuthorizationAction>> = {\n find: AuthorizationActions.READ,\n findById: AuthorizationActions.READ,\n findOne: AuthorizationActions.READ,\n count: AuthorizationActions.READ,\n create: AuthorizationActions.CREATE,\n updateById: AuthorizationActions.UPDATE,\n updateBy: AuthorizationActions.UPDATE,\n deleteById: AuthorizationActions.DELETE,\n deleteBy: AuthorizationActions.DELETE,\n };\n\n /** The CRUD methods {@link crud} generates by default. */\n static readonly DEFAULT_CRUD_METHODS: ReadonlyArray<string> = [\n 'find',\n 'findById',\n 'findOne',\n 'count',\n 'create',\n 'updateById',\n 'updateBy',\n 'deleteById',\n 'deleteBy',\n ];\n\n /** Base action for a method: a known CRUD method maps to read/create/update/delete; anything else → `execute`. */\n static actionForMethod(method: string): TAuthorizationAction {\n return AuthorizationPermissionBuilder.METHOD_ACTIONS[method] ?? AuthorizationActions.EXECUTE;\n }\n\n /** One operation-level permission, `code = <subject>.<method>`. `action` defaults to {@link actionForMethod}. */\n static operation<TName>(opts: {\n subject: string;\n method: string;\n scope: string;\n name: TName;\n description?: TNullable<TName>;\n action?: TAuthorizationAction;\n parentId?: TNullable<IdType>;\n }) {\n return {\n code: [opts.subject, opts.method].join('.'),\n subject: opts.subject,\n method: opts.method,\n action: opts.action ?? AuthorizationPermissionBuilder.actionForMethod(opts.method),\n scope: opts.scope,\n description: opts.description ?? null,\n parentId: opts.parentId ?? null,\n name: opts.name,\n };\n }\n\n /** A coarse resource node used as a grant target: `code` is the bare name, `method` the {@link RESOURCE_NODE_METHOD} sentinel, `action` defaults to `manage` (grants carry their own action). */\n static resourceNode<TName>(opts: {\n code: string;\n subject?: string;\n scope: string;\n name: TName;\n description?: TNullable<TName>;\n action?: TAuthorizationAction;\n parentId?: TNullable<IdType>;\n }) {\n return {\n code: opts.code,\n subject: opts.subject ?? opts.code,\n method: AuthorizationPermissionBuilder.RESOURCE_NODE_METHOD,\n action: opts.action ?? AuthorizationActions.MANAGE,\n scope: opts.scope,\n description: opts.description ?? null,\n parentId: opts.parentId ?? null,\n name: opts.name,\n };\n }\n\n /** The CRUD permission set for a subject. `name` (and optional `description`) are per-method formatters, so the app supplies its own labels/i18n; the framework only owns the method-to-action map and the code shape. */\n static crud<TName>(opts: {\n subject: string;\n scope: string;\n name: (ctx: { subject: string; method: string; action: TAuthorizationAction }) => TName;\n description?: (ctx: {\n subject: string;\n method: string;\n action: TAuthorizationAction;\n }) => TNullable<TName>;\n methods?: ReadonlyArray<string>;\n }) {\n const methods = opts.methods ?? AuthorizationPermissionBuilder.DEFAULT_CRUD_METHODS;\n\n return methods.map(method => {\n const action = AuthorizationPermissionBuilder.actionForMethod(method);\n const ctx: { subject: string; method: string; action: TAuthorizationAction } = {\n subject: opts.subject,\n method,\n action,\n };\n\n return AuthorizationPermissionBuilder.operation<TName>({\n subject: opts.subject,\n method,\n scope: opts.scope,\n action,\n name: opts.name(ctx),\n description: opts.description ? opts.description(ctx) : undefined,\n });\n });\n }\n\n /** g4 resource matcher (r.obj vs p.obj): derives standard edges (endpoint ⊂ subject ⊂ `*`) from the dotted code {@link operation} produces, while non-standard nesting stays stored g4 edges served by `ResourceRoleManager`. Registered via `enforcer.addFunction` - must stay static. */\n static objectMatch(requested: string, granted: string): boolean {\n if (granted === '*') {\n return true;\n }\n\n if (requested === granted) {\n return true;\n }\n\n return requested.startsWith(`${granted}.`);\n }\n}\n"]}
1
+ {"version":3,"file":"permission.builder.js","sourceRoot":"","sources":["../../../../../../src/base/auth/authorize/builders/permission.builder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IdType } from '@/base';\nimport type { TNullable } from '@venizia/ignis-helpers/common';\nimport type { TAuthorizationAction } from '../common/constants';\nimport { AuthorizationActions } from '../common/constants';\n\n/** Builders for `Permission` catalog rows (the `obj` axis the scoped matcher resolves), generic over `TName` so i18n and plain-text apps both fit; only framework-owned columns (code/subject/method/action/scope/description/parentId) are produced - app columns are added by the caller. */\nexport class AuthorizationPermissionBuilder {\n /** Sentinel `method` for a coarse resource node (a grant target that is not a route). */\n static readonly RESOURCE_NODE_METHOD = '*';\n\n /** Standard repository method → base action. Unlisted methods (custom ops, aggregates) resolve to `execute`. */\n static readonly METHOD_ACTIONS: Readonly<Record<string, TAuthorizationAction>> = {\n find: AuthorizationActions.READ,\n findById: AuthorizationActions.READ,\n findOne: AuthorizationActions.READ,\n count: AuthorizationActions.READ,\n create: AuthorizationActions.CREATE,\n updateById: AuthorizationActions.UPDATE,\n updateBy: AuthorizationActions.UPDATE,\n deleteById: AuthorizationActions.DELETE,\n deleteBy: AuthorizationActions.DELETE,\n };\n\n /** The CRUD methods {@link crud} generates by default. */\n static readonly DEFAULT_CRUD_METHODS: ReadonlyArray<string> = [\n 'find',\n 'findById',\n 'findOne',\n 'count',\n 'create',\n 'updateById',\n 'updateBy',\n 'deleteById',\n 'deleteBy',\n ];\n\n /** Base action for a method: a known CRUD method maps to read/create/update/delete; anything else → `execute`. */\n static actionForMethod(method: string): TAuthorizationAction {\n return AuthorizationPermissionBuilder.METHOD_ACTIONS[method] ?? AuthorizationActions.EXECUTE;\n }\n\n /** One operation-level permission, `code = <subject>.<method>`. `action` defaults to {@link actionForMethod}. */\n static operation<TName>(opts: {\n subject: string;\n method: string;\n scope: string;\n name: TName;\n description?: TNullable<TName>;\n action?: TAuthorizationAction;\n parentId?: TNullable<IdType>;\n }) {\n return {\n code: [opts.subject, opts.method].join('.'),\n subject: opts.subject,\n method: opts.method,\n action: opts.action ?? AuthorizationPermissionBuilder.actionForMethod(opts.method),\n scope: opts.scope,\n description: opts.description ?? null,\n parentId: opts.parentId ?? null,\n name: opts.name,\n };\n }\n\n /** A coarse resource node used as a grant target: `code` is the bare name, `method` the {@link RESOURCE_NODE_METHOD} sentinel, `action` defaults to `manage` (grants carry their own action). */\n static resourceNode<TName>(opts: {\n code: string;\n subject?: string;\n scope: string;\n name: TName;\n description?: TNullable<TName>;\n action?: TAuthorizationAction;\n parentId?: TNullable<IdType>;\n }) {\n return {\n code: opts.code,\n subject: opts.subject ?? opts.code,\n method: AuthorizationPermissionBuilder.RESOURCE_NODE_METHOD,\n action: opts.action ?? AuthorizationActions.MANAGE,\n scope: opts.scope,\n description: opts.description ?? null,\n parentId: opts.parentId ?? null,\n name: opts.name,\n };\n }\n\n /** The CRUD permission set for a subject. `name` (and optional `description`) are per-method formatters, so the app supplies its own labels/i18n; the framework only owns the method-to-action map and the code shape. */\n static crud<TName>(opts: {\n subject: string;\n scope: string;\n name: (ctx: { subject: string; method: string; action: TAuthorizationAction }) => TName;\n description?: (ctx: {\n subject: string;\n method: string;\n action: TAuthorizationAction;\n }) => TNullable<TName>;\n methods?: ReadonlyArray<string>;\n }) {\n const methods = opts.methods ?? AuthorizationPermissionBuilder.DEFAULT_CRUD_METHODS;\n\n return methods.map((method) => {\n const action = AuthorizationPermissionBuilder.actionForMethod(method);\n const ctx: { subject: string; method: string; action: TAuthorizationAction } = {\n subject: opts.subject,\n method,\n action,\n };\n\n return AuthorizationPermissionBuilder.operation<TName>({\n subject: opts.subject,\n method,\n scope: opts.scope,\n action,\n name: opts.name(ctx),\n description: opts.description ? opts.description(ctx) : undefined,\n });\n });\n }\n\n /** g4 resource matcher (r.obj vs p.obj): derives standard edges (endpoint ⊂ subject ⊂ `*`) from the dotted code {@link operation} produces, while non-standard nesting stays stored g4 edges served by `ResourceRoleManager`. Registered via `enforcer.addFunction` - must stay static. */\n static objectMatch(requested: string, granted: string): boolean {\n if (granted === '*') {\n return true;\n }\n\n if (requested === granted) {\n return true;\n }\n\n return requested.startsWith(`${granted}.`);\n }\n}\n"]}
@@ -91,7 +91,7 @@ export class AuthorizationPolicyBuilder {
91
91
  }
92
92
  /** All `action_inherits` rows for the standard {@link AuthorizationActions.LATTICE}. Seed once, idempotently. */
93
93
  static actionLattice() {
94
- return AuthorizationActions.LATTICE.map(action => this.actionInherits(action));
94
+ return AuthorizationActions.LATTICE.map((action) => this.actionInherits(action));
95
95
  }
96
96
  /** A domain inherits another (casbin `g3`): a grant in the parent domain cascades to the child. e.g. Merchant ⊂ Organizer. */
97
97
  static domainInherits(opts) {
@@ -1 +1 @@
1
- {"version":3,"file":"policy.builder.js","sourceRoot":"","sources":["../../../../../../src/base/auth/authorize/builders/policy.builder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IdType } from '@/base';\nimport type { TNullable } from '@venizia/ignis-helpers/common';\nimport type { TAuthorizationAction, TAuthorizationDecision } from '../common/constants';\nimport {\n AuthorizationActions,\n AuthorizationDomainScopes,\n AuthorizationPolicyVariants,\n} from '../common/constants';\n\n/** A grant/assignment domain: a scope literal (`SYSTEM_WIDE`/`ANY_MEMBER`) or a typed domain entity. */\nexport type TPolicyDomainInput = string | { type: string; id: IdType };\n\n/**\n * Explicit on purpose: `TAuthorizationDecision` is `Extract<ValueOf<T>, string | number>`, and its\n * literal members widen to `string` when a method's return type is inferred rather than declared.\n * Without this annotation `grant()`'s `effect` stops satisfying `PolicyDefinition`'s narrowed column.\n * Not exported - `TGrantRow`/`TCustomGrantRow` already name unrelated adapter-side row shapes\n * downstream; consumers derive this shape via `ReturnType<typeof AuthorizationPolicyBuilder.grant>`.\n */\ntype TBuilderGrantRow = {\n variant: typeof AuthorizationPolicyVariants.GRANT.action;\n subjectType: string;\n subjectId: IdType;\n targetType: string;\n targetId: IdType;\n action: string;\n effect: TAuthorizationDecision;\n domainType: TNullable<string>;\n domainId: TNullable<IdType>;\n};\n\n/**\n * What IGNIS itself stores in `PolicyDefinition.metadata`: the operations of a subset grant, read\n * back by `ScopedCasbinAdapter` through `parseCustomGrantMetadata`. An application whose own\n * metadata has a different shape points the adapter at a different column\n * (`entities.policyDefinition.metadata.columnName`) rather than widening this one.\n *\n * Declared here, beside the only writer, so the column type and the row type cannot drift.\n */\nexport type TSubsetGrantMetadata = { ops: string[] };\n\ntype TBuilderCustomGrantRow = Omit<TBuilderGrantRow, 'action'> & {\n action: typeof AuthorizationActions.CUSTOM;\n metadata: TSubsetGrantMetadata;\n};\n\nexport class AuthorizationPolicyBuilder {\n static readonly ACTION_PRINCIPAL = 'Action';\n\n /** A domain as the two columns that store it. `ANY_MEMBER` normalises to null - admitting both spellings would leave one state reachable two ways. */\n private static splitDomain(domain?: TNullable<TPolicyDomainInput>): {\n domainType: TNullable<string>;\n domainId: TNullable<IdType>;\n } {\n if (domain == null || domain === AuthorizationDomainScopes.ANY_MEMBER) {\n return { domainType: null, domainId: null };\n }\n\n if (typeof domain === 'string') {\n return { domainType: domain, domainId: null };\n }\n\n return { domainType: domain.type, domainId: domain.id };\n }\n\n /** A grant (casbin `p`): role/user -> permission, carrying action + effect + domain. A null `domain` means `ANY_MEMBER` (adapter default); pass a scope literal or a typed `{ type, id }` domain. */\n static grant(opts: {\n subject: { type: string; id: IdType };\n permission: { type: string; id: IdType };\n action: string;\n domain?: TNullable<TPolicyDomainInput>;\n effect: TAuthorizationDecision;\n }): TBuilderGrantRow {\n return {\n variant: AuthorizationPolicyVariants.GRANT.action,\n subjectType: opts.subject.type,\n subjectId: opts.subject.id,\n targetType: opts.permission.type,\n targetId: opts.permission.id,\n action: opts.action,\n effect: opts.effect,\n ...AuthorizationPolicyBuilder.splitDomain(opts.domain),\n };\n }\n\n /** A subset grant (casbin `p` x N): role/user -> resource node with the granted operations in metadata. `action` is fixed to the CUSTOM sentinel; the adapter expands `ops` at read time. */\n static customGrant(opts: {\n subject: { type: string; id: IdType };\n permission: { type: string; id: IdType };\n ops: string[];\n domain?: TNullable<TPolicyDomainInput>;\n effect: TAuthorizationDecision;\n }): TBuilderCustomGrantRow {\n return {\n variant: AuthorizationPolicyVariants.GRANT.action,\n subjectType: opts.subject.type,\n subjectId: opts.subject.id,\n targetType: opts.permission.type,\n targetId: opts.permission.id,\n action: AuthorizationActions.CUSTOM,\n effect: opts.effect,\n ...AuthorizationPolicyBuilder.splitDomain(opts.domain),\n metadata: { ops: opts.ops },\n };\n }\n\n /** Assign a role to a user (casbin `g`). `domain` null ⇒ `*` (every domain). */\n static assignRole(opts: {\n user: { type: string; id: IdType };\n role: { type: string; id: IdType };\n domain?: TNullable<TPolicyDomainInput>;\n }) {\n return {\n variant: AuthorizationPolicyVariants.ASSIGN_ROLE.action,\n subjectType: opts.user.type,\n subjectId: opts.user.id,\n targetType: opts.role.type,\n targetId: opts.role.id,\n ...AuthorizationPolicyBuilder.splitDomain(opts.domain),\n };\n }\n\n /** A user joins a domain (casbin `g2`) - backs the `ANY_MEMBER` grant scope. */\n static joinDomain(opts: {\n user: { type: string; id: IdType };\n domain: { type: string; id: IdType };\n }) {\n return {\n variant: AuthorizationPolicyVariants.JOIN_DOMAIN.action,\n subjectType: opts.user.type,\n subjectId: opts.user.id,\n targetType: opts.domain.type,\n targetId: opts.domain.id,\n };\n }\n\n /** A role inherits another role (casbin `g`, shared relation with assign_role). */\n static roleInherits(opts: {\n child: { type: string; id: IdType };\n parent: { type: string; id: IdType };\n }) {\n return {\n variant: AuthorizationPolicyVariants.ROLE_INHERITS.action,\n subjectType: opts.child.type,\n subjectId: opts.child.id,\n targetType: opts.parent.type,\n targetId: opts.parent.id,\n };\n }\n\n /** A resource inherits another (casbin `g4`): a grant on the PARENT covers the CHILD. Many-to-many - a subject may inherit several module parents, one edge each. */\n static resourceInherits(opts: {\n child: { type: string; id: IdType }; // Permission\n parent: { type: string; id: IdType }; // Permission\n }) {\n return {\n variant: AuthorizationPolicyVariants.RESOURCE_INHERITS.action,\n subjectType: opts.child.type,\n subjectId: opts.child.id,\n targetType: opts.parent.type,\n targetId: opts.parent.id,\n };\n }\n\n /** An action inherits another (casbin `g5`): the child action is implied by the parent, e.g. read ⊂ manage. */\n static actionInherits(opts: { child: TAuthorizationAction; parent: TAuthorizationAction }) {\n return {\n variant: AuthorizationPolicyVariants.ACTION_INHERITS.action,\n subjectType: this.ACTION_PRINCIPAL,\n subjectId: opts.child,\n targetType: this.ACTION_PRINCIPAL,\n targetId: opts.parent,\n };\n }\n\n /** All `action_inherits` rows for the standard {@link AuthorizationActions.LATTICE}. Seed once, idempotently. */\n static actionLattice() {\n return AuthorizationActions.LATTICE.map(action => this.actionInherits(action));\n }\n\n /** A domain inherits another (casbin `g3`): a grant in the parent domain cascades to the child. e.g. Merchant ⊂ Organizer. */\n static domainInherits(opts: {\n child: { type: string; id: IdType };\n parent: { type: string; id: IdType };\n }) {\n return {\n variant: AuthorizationPolicyVariants.DOMAIN_INHERITS.action,\n subjectType: opts.child.type,\n subjectId: opts.child.id,\n targetType: opts.parent.type,\n targetId: opts.parent.id,\n };\n }\n\n /** Build a role's coarse grant rows from resolved permission ids. The caller resolves each `resourceCode` (subject/module) to a `Permission` and supplies the lookup; unresolved codes are skipped. */\n static roleGrants(opts: {\n role: { type: string; id: IdType };\n permission: {\n type: string;\n idByCode: ReadonlyMap<string, string>;\n };\n\n grants: ReadonlyArray<{\n resourceCode: string;\n action: string;\n domain?: TNullable<TPolicyDomainInput>;\n effect: TAuthorizationDecision;\n }>;\n }) {\n const rows: Array<ReturnType<typeof AuthorizationPolicyBuilder.grant>> = [];\n\n for (const grant of opts.grants) {\n const permissionId = opts.permission.idByCode.get(grant.resourceCode);\n if (!permissionId) {\n continue;\n }\n\n const policy = AuthorizationPolicyBuilder.grant({\n subject: { type: opts.role.type, id: opts.role.id },\n permission: { type: opts.permission.type, id: permissionId },\n action: grant.action,\n domain: grant.domain,\n effect: grant.effect,\n });\n\n rows.push(policy);\n }\n\n return rows;\n }\n}\n"]}
1
+ {"version":3,"file":"policy.builder.js","sourceRoot":"","sources":["../../../../../../src/base/auth/authorize/builders/policy.builder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IdType } from '@/base';\nimport type { TNullable } from '@venizia/ignis-helpers/common';\nimport type { TAuthorizationAction, TAuthorizationDecision } from '../common/constants';\nimport {\n AuthorizationActions,\n AuthorizationDomainScopes,\n AuthorizationPolicyVariants,\n} from '../common/constants';\n\n/** A grant/assignment domain: a scope literal (`SYSTEM_WIDE`/`ANY_MEMBER`) or a typed domain entity. */\nexport type TPolicyDomainInput = string | { type: string; id: IdType };\n\n/**\n * Explicit on purpose: `TAuthorizationDecision` is `Extract<ValueOf<T>, string | number>`, and its\n * literal members widen to `string` when a method's return type is inferred rather than declared.\n * Without this annotation `grant()`'s `effect` stops satisfying `PolicyDefinition`'s narrowed column.\n * Not exported - `TGrantRow`/`TCustomGrantRow` already name unrelated adapter-side row shapes\n * downstream; consumers derive this shape via `ReturnType<typeof AuthorizationPolicyBuilder.grant>`.\n */\ntype TBuilderGrantRow = {\n variant: typeof AuthorizationPolicyVariants.GRANT.action;\n subjectType: string;\n subjectId: IdType;\n targetType: string;\n targetId: IdType;\n action: string;\n effect: TAuthorizationDecision;\n domainType: TNullable<string>;\n domainId: TNullable<IdType>;\n};\n\n/**\n * What IGNIS itself stores in `PolicyDefinition.metadata`: the operations of a subset grant, read\n * back by `ScopedCasbinAdapter` through `parseCustomGrantMetadata`. An application whose own\n * metadata has a different shape points the adapter at a different column\n * (`entities.policyDefinition.metadata.columnName`) rather than widening this one.\n *\n * Declared here, beside the only writer, so the column type and the row type cannot drift.\n */\nexport type TSubsetGrantMetadata = { ops: string[] };\n\ntype TBuilderCustomGrantRow = Omit<TBuilderGrantRow, 'action'> & {\n action: typeof AuthorizationActions.CUSTOM;\n metadata: TSubsetGrantMetadata;\n};\n\nexport class AuthorizationPolicyBuilder {\n static readonly ACTION_PRINCIPAL = 'Action';\n\n /** A domain as the two columns that store it. `ANY_MEMBER` normalises to null - admitting both spellings would leave one state reachable two ways. */\n private static splitDomain(domain?: TNullable<TPolicyDomainInput>): {\n domainType: TNullable<string>;\n domainId: TNullable<IdType>;\n } {\n if (domain == null || domain === AuthorizationDomainScopes.ANY_MEMBER) {\n return { domainType: null, domainId: null };\n }\n\n if (typeof domain === 'string') {\n return { domainType: domain, domainId: null };\n }\n\n return { domainType: domain.type, domainId: domain.id };\n }\n\n /** A grant (casbin `p`): role/user -> permission, carrying action + effect + domain. A null `domain` means `ANY_MEMBER` (adapter default); pass a scope literal or a typed `{ type, id }` domain. */\n static grant(opts: {\n subject: { type: string; id: IdType };\n permission: { type: string; id: IdType };\n action: string;\n domain?: TNullable<TPolicyDomainInput>;\n effect: TAuthorizationDecision;\n }): TBuilderGrantRow {\n return {\n variant: AuthorizationPolicyVariants.GRANT.action,\n subjectType: opts.subject.type,\n subjectId: opts.subject.id,\n targetType: opts.permission.type,\n targetId: opts.permission.id,\n action: opts.action,\n effect: opts.effect,\n ...AuthorizationPolicyBuilder.splitDomain(opts.domain),\n };\n }\n\n /** A subset grant (casbin `p` x N): role/user -> resource node with the granted operations in metadata. `action` is fixed to the CUSTOM sentinel; the adapter expands `ops` at read time. */\n static customGrant(opts: {\n subject: { type: string; id: IdType };\n permission: { type: string; id: IdType };\n ops: string[];\n domain?: TNullable<TPolicyDomainInput>;\n effect: TAuthorizationDecision;\n }): TBuilderCustomGrantRow {\n return {\n variant: AuthorizationPolicyVariants.GRANT.action,\n subjectType: opts.subject.type,\n subjectId: opts.subject.id,\n targetType: opts.permission.type,\n targetId: opts.permission.id,\n action: AuthorizationActions.CUSTOM,\n effect: opts.effect,\n ...AuthorizationPolicyBuilder.splitDomain(opts.domain),\n metadata: { ops: opts.ops },\n };\n }\n\n /** Assign a role to a user (casbin `g`). `domain` null ⇒ `*` (every domain). */\n static assignRole(opts: {\n user: { type: string; id: IdType };\n role: { type: string; id: IdType };\n domain?: TNullable<TPolicyDomainInput>;\n }) {\n return {\n variant: AuthorizationPolicyVariants.ASSIGN_ROLE.action,\n subjectType: opts.user.type,\n subjectId: opts.user.id,\n targetType: opts.role.type,\n targetId: opts.role.id,\n ...AuthorizationPolicyBuilder.splitDomain(opts.domain),\n };\n }\n\n /** A user joins a domain (casbin `g2`) - backs the `ANY_MEMBER` grant scope. */\n static joinDomain(opts: {\n user: { type: string; id: IdType };\n domain: { type: string; id: IdType };\n }) {\n return {\n variant: AuthorizationPolicyVariants.JOIN_DOMAIN.action,\n subjectType: opts.user.type,\n subjectId: opts.user.id,\n targetType: opts.domain.type,\n targetId: opts.domain.id,\n };\n }\n\n /** A role inherits another role (casbin `g`, shared relation with assign_role). */\n static roleInherits(opts: {\n child: { type: string; id: IdType };\n parent: { type: string; id: IdType };\n }) {\n return {\n variant: AuthorizationPolicyVariants.ROLE_INHERITS.action,\n subjectType: opts.child.type,\n subjectId: opts.child.id,\n targetType: opts.parent.type,\n targetId: opts.parent.id,\n };\n }\n\n /** A resource inherits another (casbin `g4`): a grant on the PARENT covers the CHILD. Many-to-many - a subject may inherit several module parents, one edge each. */\n static resourceInherits(opts: {\n child: { type: string; id: IdType }; // Permission\n parent: { type: string; id: IdType }; // Permission\n }) {\n return {\n variant: AuthorizationPolicyVariants.RESOURCE_INHERITS.action,\n subjectType: opts.child.type,\n subjectId: opts.child.id,\n targetType: opts.parent.type,\n targetId: opts.parent.id,\n };\n }\n\n /** An action inherits another (casbin `g5`): the child action is implied by the parent, e.g. read ⊂ manage. */\n static actionInherits(opts: { child: TAuthorizationAction; parent: TAuthorizationAction }) {\n return {\n variant: AuthorizationPolicyVariants.ACTION_INHERITS.action,\n subjectType: this.ACTION_PRINCIPAL,\n subjectId: opts.child,\n targetType: this.ACTION_PRINCIPAL,\n targetId: opts.parent,\n };\n }\n\n /** All `action_inherits` rows for the standard {@link AuthorizationActions.LATTICE}. Seed once, idempotently. */\n static actionLattice() {\n return AuthorizationActions.LATTICE.map((action) => this.actionInherits(action));\n }\n\n /** A domain inherits another (casbin `g3`): a grant in the parent domain cascades to the child. e.g. Merchant ⊂ Organizer. */\n static domainInherits(opts: {\n child: { type: string; id: IdType };\n parent: { type: string; id: IdType };\n }) {\n return {\n variant: AuthorizationPolicyVariants.DOMAIN_INHERITS.action,\n subjectType: opts.child.type,\n subjectId: opts.child.id,\n targetType: opts.parent.type,\n targetId: opts.parent.id,\n };\n }\n\n /** Build a role's coarse grant rows from resolved permission ids. The caller resolves each `resourceCode` (subject/module) to a `Permission` and supplies the lookup; unresolved codes are skipped. */\n static roleGrants(opts: {\n role: { type: string; id: IdType };\n permission: {\n type: string;\n idByCode: ReadonlyMap<string, string>;\n };\n\n grants: ReadonlyArray<{\n resourceCode: string;\n action: string;\n domain?: TNullable<TPolicyDomainInput>;\n effect: TAuthorizationDecision;\n }>;\n }) {\n const rows: Array<ReturnType<typeof AuthorizationPolicyBuilder.grant>> = [];\n\n for (const grant of opts.grants) {\n const permissionId = opts.permission.idByCode.get(grant.resourceCode);\n if (!permissionId) {\n continue;\n }\n\n const policy = AuthorizationPolicyBuilder.grant({\n subject: { type: opts.role.type, id: opts.role.id },\n permission: { type: opts.permission.type, id: permissionId },\n action: grant.action,\n domain: grant.domain,\n effect: grant.effect,\n });\n\n rows.push(policy);\n }\n\n return rows;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"authorization.d.ts","sourceRoot":"","sources":["../../../../../../../src/base/auth/authorize/common/constants/authorization.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"authorization.d.ts","sourceRoot":"","sources":["../../../../../../../src/base/auth/authorize/common/constants/authorization.ts"],"names":[],"mappings":"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"}
@@ -142,8 +142,8 @@ export class AuthorizationPolicyVariants {
142
142
  this.RESOURCE_INHERITS,
143
143
  this.ACTION_INHERITS,
144
144
  ]; }
145
- static { this.ACTION_SCHEME_SET = new Set(this.ALL.map(variant => variant.action.toString())); }
146
- static { this.RULE_SCHEME_SET = new Set(this.ALL.map(variant => variant.rule.toString())); }
145
+ static { this.ACTION_SCHEME_SET = new Set(this.ALL.map((variant) => variant.action.toString())); }
146
+ static { this.RULE_SCHEME_SET = new Set(this.ALL.map((variant) => variant.rule.toString())); }
147
147
  static isValidAction(input) {
148
148
  return this.ACTION_SCHEME_SET.has(input);
149
149
  }
@@ -1 +1 @@
1
- {"version":3,"file":"authorization.js","sourceRoot":"","sources":["../../../../../../../src/base/auth/authorize/common/constants/authorization.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TConstValue } from '@venizia/ignis-helpers/common';\nimport { AuthorizationRole } from '../../models/authorization-role.model';\nimport { CasbinRuleVariants } from './enforcer';\n\nexport class Authorization {\n static readonly RULES = 'authorization.rules';\n static readonly SKIP_AUTHORIZATION = 'authorization.skip';\n static readonly ENFORCER = 'authorization.enforcer';\n static readonly DOMAIN = 'authorization.domain';\n}\n\nexport class AuthorizationActions {\n static readonly CREATE = 'create';\n static readonly UPDATE = 'update';\n static readonly DELETE = 'delete';\n static readonly EXECUTE = 'execute';\n\n static readonly READ = 'read';\n static readonly WRITE = 'write';\n static readonly MANAGE = 'manage';\n\n /** Grant-mode marker for a subset grant carrying `metadata.ops`; never a member of LATTICE. */\n static readonly CUSTOM = 'custom';\n\n static readonly SCHEME_SET = new Set([\n this.CREATE,\n this.UPDATE,\n this.DELETE,\n this.EXECUTE,\n\n this.READ,\n this.WRITE,\n this.MANAGE,\n\n this.CUSTOM,\n ]);\n\n static readonly LATTICE: ReadonlyArray<{\n child: TAuthorizationAction;\n parent: TAuthorizationAction;\n }> = [\n { child: this.READ, parent: this.MANAGE },\n { child: this.WRITE, parent: this.MANAGE },\n { child: this.EXECUTE, parent: this.MANAGE },\n { child: this.CREATE, parent: this.WRITE },\n { child: this.UPDATE, parent: this.WRITE },\n { child: this.DELETE, parent: this.WRITE },\n ];\n\n static isValid(input: string): boolean {\n return this.SCHEME_SET.has(input);\n }\n}\nexport type TAuthorizationAction = TConstValue<typeof AuthorizationActions>;\n\nexport class AuthorizationDecisions {\n static readonly ALLOW = 'allow';\n static readonly DENY = 'deny';\n static readonly ABSTAIN = 'abstain';\n\n static readonly SCHEME_SET = new Set([this.ALLOW, this.DENY, this.ABSTAIN]);\n\n static isValid(input: string): boolean {\n return this.SCHEME_SET.has(input);\n }\n\n static isAllow(input: string | number): boolean {\n if (typeof input === 'number') {\n return input > 0;\n }\n return input.toLowerCase() === this.ALLOW;\n }\n\n static isDeny(input: string | number): boolean {\n if (typeof input === 'number') {\n return input < 0;\n }\n return input.toLowerCase() === this.DENY;\n }\n\n static isAbstain(input: string | number): boolean {\n if (typeof input === 'number') {\n return input === 0;\n }\n return input.toLowerCase() === this.ABSTAIN;\n }\n}\nexport type TAuthorizationDecision = TConstValue<typeof AuthorizationDecisions>;\n\nexport class AuthorizationRoles {\n static readonly SUPER_ADMIN = AuthorizationRole.build({\n name: 'super-admin',\n priority: 999,\n });\n static readonly ADMIN = AuthorizationRole.build({\n name: 'admin',\n priority: 900,\n });\n static readonly USER = AuthorizationRole.build({\n name: 'user',\n priority: 10,\n });\n static readonly GUEST = AuthorizationRole.build({\n name: 'guest',\n priority: 1,\n });\n static readonly UNKNOWN_USER = AuthorizationRole.build({\n name: 'unknown-user',\n priority: 0,\n });\n\n static readonly SCHEME_SET = new Set<string>([\n this.SUPER_ADMIN.identifier,\n this.ADMIN.identifier,\n this.USER.identifier,\n this.GUEST.identifier,\n this.UNKNOWN_USER.identifier,\n ]);\n\n static isValid(input: string): boolean {\n return this.SCHEME_SET.has(input);\n }\n}\n\nexport class AuthorizationDomainScopes {\n /** Grant applies in EVERY domain the subject is a member of (checked via join_domain / g2). */\n static readonly ANY_MEMBER = 'ANY_MEMBER';\n\n /** Grant applies system-wide, bypassing membership - super-admin only. */\n static readonly SYSTEM_WIDE = 'SYSTEM_WIDE';\n\n static readonly SCHEME_SET = new Set([this.ANY_MEMBER, this.SYSTEM_WIDE]);\n\n static isValid(input: string): boolean {\n return this.SCHEME_SET.has(input);\n }\n}\nexport type TAuthorizationDomainScope = TConstValue<typeof AuthorizationDomainScopes>;\n\n/** Edge kinds in the `PolicyDefinition` table (each row: subject -> target, `variant` = kind), carrying `action` (DB `variant` value) + `rule` (casbin prefix emitted per edge). Per-USER edges: GRANT, ASSIGN_ROLE, JOIN_DOMAIN; shared org-structure edges: the *_INHERITS ones. */\nexport class AuthorizationPolicyVariants {\n /** Give a Permission to a User/Role (row also carries action / effect / domain). casbin `p`: `p, <Role|User>_<id>, <domain>, <permissionCode>, <action>, <allow|deny>` */\n static readonly GRANT = { action: 'grant', rule: CasbinRuleVariants.P } as const;\n\n /** Give a User a Role (optionally domain-scoped; no domain -> `*` = every domain). casbin `g`: `g, User_<id>, Role_<id>, <domain|*>` */\n static readonly ASSIGN_ROLE = { action: 'assign_role', rule: CasbinRuleVariants.G } as const;\n\n /** A Role inherits another Role (DAG). Shares `g` with ASSIGN_ROLE so user -> role -> parent-role resolves in one lookup. Emitted with domain `*`: `g, Role_<child>, Role_<parent>, *` */\n static readonly ROLE_INHERITS = { action: 'role_inherits', rule: CasbinRuleVariants.G } as const;\n\n /** User is a member of a Domain; powers the `ANY_MEMBER` grant scope via `g2(r.sub, r.dom)`. casbin `g2`: `g2, User_<id>, <Type>_<domainId>` */\n static readonly JOIN_DOMAIN = { action: 'join_domain', rule: CasbinRuleVariants.G2 } as const;\n\n /** DOMAIN axis (`dom`): domain nesting. Matcher: `g3(r.dom, p.dom)` + self-link so an exact domain always matches itself. casbin `g3`: `g3, <Type>_<childId>, <Type>_<parentId>` */\n static readonly DOMAIN_INHERITS = {\n action: 'domain_inherits',\n rule: CasbinRuleVariants.G3,\n } as const;\n\n /** RESOURCE axis (`obj`), NON-standard nesting only - dotted nesting (`Order.findById ⊂ Order`) is handled by `objectMatch` WITHOUT an edge. Matcher: `objectMatch(r.obj, p.obj) || g4(r.obj, p.obj)`, casbin `g4`: `g4, <childCode>, <parentCode>` */\n static readonly RESOURCE_INHERITS = {\n action: 'resource_inherits',\n rule: CasbinRuleVariants.G4,\n } as const;\n\n /** ACTION axis (`act`): a narrow action covered by a broader one; no dotted shortcut, so it needs an explicit edge. Matcher: `g5(r.act, p.act)`, casbin `g5`: `g5, <childAction>, <parentAction>`. g4 + g5 combine multiplicatively: `manage Order` covers a `read OrderItem` request. */\n static readonly ACTION_INHERITS = {\n action: 'action_inherits',\n rule: CasbinRuleVariants.G5,\n } as const;\n\n /** Every edge kind, in declaration order - the one place the scheme sets and the `variant` column's literal type both derive from. */\n static readonly ALL = [\n this.GRANT,\n this.ASSIGN_ROLE,\n this.ROLE_INHERITS,\n this.JOIN_DOMAIN,\n this.DOMAIN_INHERITS,\n this.RESOURCE_INHERITS,\n this.ACTION_INHERITS,\n ] as const;\n\n static readonly ACTION_SCHEME_SET = new Set(this.ALL.map(variant => variant.action.toString()));\n\n static readonly RULE_SCHEME_SET = new Set(this.ALL.map(variant => variant.rule.toString()));\n\n static isValidAction(input: string): boolean {\n return this.ACTION_SCHEME_SET.has(input);\n }\n\n static isValidRule(input: string): boolean {\n return this.RULE_SCHEME_SET.has(input);\n }\n}\n\n/** The `variant` column's full value set, derived from {@link AuthorizationPolicyVariants.ALL} - never hand-list the seven strings again. */\nexport type TAuthorizationPolicyVariant =\n (typeof AuthorizationPolicyVariants.ALL)[number]['action'];\n"]}
1
+ {"version":3,"file":"authorization.js","sourceRoot":"","sources":["../../../../../../../src/base/auth/authorize/common/constants/authorization.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TConstValue } from '@venizia/ignis-helpers/common';\nimport { AuthorizationRole } from '../../models/authorization-role.model';\nimport { CasbinRuleVariants } from './enforcer';\n\nexport class Authorization {\n static readonly RULES = 'authorization.rules';\n static readonly SKIP_AUTHORIZATION = 'authorization.skip';\n static readonly ENFORCER = 'authorization.enforcer';\n static readonly DOMAIN = 'authorization.domain';\n}\n\nexport class AuthorizationActions {\n static readonly CREATE = 'create';\n static readonly UPDATE = 'update';\n static readonly DELETE = 'delete';\n static readonly EXECUTE = 'execute';\n\n static readonly READ = 'read';\n static readonly WRITE = 'write';\n static readonly MANAGE = 'manage';\n\n /** Grant-mode marker for a subset grant carrying `metadata.ops`; never a member of LATTICE. */\n static readonly CUSTOM = 'custom';\n\n static readonly SCHEME_SET = new Set([\n this.CREATE,\n this.UPDATE,\n this.DELETE,\n this.EXECUTE,\n\n this.READ,\n this.WRITE,\n this.MANAGE,\n\n this.CUSTOM,\n ]);\n\n static readonly LATTICE: ReadonlyArray<{\n child: TAuthorizationAction;\n parent: TAuthorizationAction;\n }> = [\n { child: this.READ, parent: this.MANAGE },\n { child: this.WRITE, parent: this.MANAGE },\n { child: this.EXECUTE, parent: this.MANAGE },\n { child: this.CREATE, parent: this.WRITE },\n { child: this.UPDATE, parent: this.WRITE },\n { child: this.DELETE, parent: this.WRITE },\n ];\n\n static isValid(input: string): boolean {\n return this.SCHEME_SET.has(input);\n }\n}\nexport type TAuthorizationAction = TConstValue<typeof AuthorizationActions>;\n\nexport class AuthorizationDecisions {\n static readonly ALLOW = 'allow';\n static readonly DENY = 'deny';\n static readonly ABSTAIN = 'abstain';\n\n static readonly SCHEME_SET = new Set([this.ALLOW, this.DENY, this.ABSTAIN]);\n\n static isValid(input: string): boolean {\n return this.SCHEME_SET.has(input);\n }\n\n static isAllow(input: string | number): boolean {\n if (typeof input === 'number') {\n return input > 0;\n }\n return input.toLowerCase() === this.ALLOW;\n }\n\n static isDeny(input: string | number): boolean {\n if (typeof input === 'number') {\n return input < 0;\n }\n return input.toLowerCase() === this.DENY;\n }\n\n static isAbstain(input: string | number): boolean {\n if (typeof input === 'number') {\n return input === 0;\n }\n return input.toLowerCase() === this.ABSTAIN;\n }\n}\nexport type TAuthorizationDecision = TConstValue<typeof AuthorizationDecisions>;\n\nexport class AuthorizationRoles {\n static readonly SUPER_ADMIN = AuthorizationRole.build({\n name: 'super-admin',\n priority: 999,\n });\n static readonly ADMIN = AuthorizationRole.build({\n name: 'admin',\n priority: 900,\n });\n static readonly USER = AuthorizationRole.build({\n name: 'user',\n priority: 10,\n });\n static readonly GUEST = AuthorizationRole.build({\n name: 'guest',\n priority: 1,\n });\n static readonly UNKNOWN_USER = AuthorizationRole.build({\n name: 'unknown-user',\n priority: 0,\n });\n\n static readonly SCHEME_SET = new Set<string>([\n this.SUPER_ADMIN.identifier,\n this.ADMIN.identifier,\n this.USER.identifier,\n this.GUEST.identifier,\n this.UNKNOWN_USER.identifier,\n ]);\n\n static isValid(input: string): boolean {\n return this.SCHEME_SET.has(input);\n }\n}\n\nexport class AuthorizationDomainScopes {\n /** Grant applies in EVERY domain the subject is a member of (checked via join_domain / g2). */\n static readonly ANY_MEMBER = 'ANY_MEMBER';\n\n /** Grant applies system-wide, bypassing membership - super-admin only. */\n static readonly SYSTEM_WIDE = 'SYSTEM_WIDE';\n\n static readonly SCHEME_SET = new Set([this.ANY_MEMBER, this.SYSTEM_WIDE]);\n\n static isValid(input: string): boolean {\n return this.SCHEME_SET.has(input);\n }\n}\nexport type TAuthorizationDomainScope = TConstValue<typeof AuthorizationDomainScopes>;\n\n/** Edge kinds in the `PolicyDefinition` table (each row: subject -> target, `variant` = kind), carrying `action` (DB `variant` value) + `rule` (casbin prefix emitted per edge). Per-USER edges: GRANT, ASSIGN_ROLE, JOIN_DOMAIN; shared org-structure edges: the *_INHERITS ones. */\nexport class AuthorizationPolicyVariants {\n /** Give a Permission to a User/Role (row also carries action / effect / domain). casbin `p`: `p, <Role|User>_<id>, <domain>, <permissionCode>, <action>, <allow|deny>` */\n static readonly GRANT = { action: 'grant', rule: CasbinRuleVariants.P } as const;\n\n /** Give a User a Role (optionally domain-scoped; no domain -> `*` = every domain). casbin `g`: `g, User_<id>, Role_<id>, <domain|*>` */\n static readonly ASSIGN_ROLE = { action: 'assign_role', rule: CasbinRuleVariants.G } as const;\n\n /** A Role inherits another Role (DAG). Shares `g` with ASSIGN_ROLE so user -> role -> parent-role resolves in one lookup. Emitted with domain `*`: `g, Role_<child>, Role_<parent>, *` */\n static readonly ROLE_INHERITS = { action: 'role_inherits', rule: CasbinRuleVariants.G } as const;\n\n /** User is a member of a Domain; powers the `ANY_MEMBER` grant scope via `g2(r.sub, r.dom)`. casbin `g2`: `g2, User_<id>, <Type>_<domainId>` */\n static readonly JOIN_DOMAIN = { action: 'join_domain', rule: CasbinRuleVariants.G2 } as const;\n\n /** DOMAIN axis (`dom`): domain nesting. Matcher: `g3(r.dom, p.dom)` + self-link so an exact domain always matches itself. casbin `g3`: `g3, <Type>_<childId>, <Type>_<parentId>` */\n static readonly DOMAIN_INHERITS = {\n action: 'domain_inherits',\n rule: CasbinRuleVariants.G3,\n } as const;\n\n /** RESOURCE axis (`obj`), NON-standard nesting only - dotted nesting (`Order.findById ⊂ Order`) is handled by `objectMatch` WITHOUT an edge. Matcher: `objectMatch(r.obj, p.obj) || g4(r.obj, p.obj)`, casbin `g4`: `g4, <childCode>, <parentCode>` */\n static readonly RESOURCE_INHERITS = {\n action: 'resource_inherits',\n rule: CasbinRuleVariants.G4,\n } as const;\n\n /** ACTION axis (`act`): a narrow action covered by a broader one; no dotted shortcut, so it needs an explicit edge. Matcher: `g5(r.act, p.act)`, casbin `g5`: `g5, <childAction>, <parentAction>`. g4 + g5 combine multiplicatively: `manage Order` covers a `read OrderItem` request. */\n static readonly ACTION_INHERITS = {\n action: 'action_inherits',\n rule: CasbinRuleVariants.G5,\n } as const;\n\n /** Every edge kind, in declaration order - the one place the scheme sets and the `variant` column's literal type both derive from. */\n static readonly ALL = [\n this.GRANT,\n this.ASSIGN_ROLE,\n this.ROLE_INHERITS,\n this.JOIN_DOMAIN,\n this.DOMAIN_INHERITS,\n this.RESOURCE_INHERITS,\n this.ACTION_INHERITS,\n ] as const;\n\n static readonly ACTION_SCHEME_SET = new Set(this.ALL.map((variant) => variant.action.toString()));\n\n static readonly RULE_SCHEME_SET = new Set(this.ALL.map((variant) => variant.rule.toString()));\n\n static isValidAction(input: string): boolean {\n return this.ACTION_SCHEME_SET.has(input);\n }\n\n static isValidRule(input: string): boolean {\n return this.RULE_SCHEME_SET.has(input);\n }\n}\n\n/** The `variant` column's full value set, derived from {@link AuthorizationPolicyVariants.ALL} - never hand-list the seven strings again. */\nexport type TAuthorizationPolicyVariant =\n (typeof AuthorizationPolicyVariants.ALL)[number]['action'];\n"]}
@@ -29,7 +29,7 @@ export class AuthorizationEnforcerRegistry extends AbstractAuthRegistry {
29
29
  }
30
30
  register(opts) {
31
31
  const { container, enforcers } = opts;
32
- const names = enforcers.map(e => e.name);
32
+ const names = enforcers.map((e) => e.name);
33
33
  const duplicateNames = names.filter((n, i) => names.indexOf(n) !== i);
34
34
  if (duplicateNames.length) {
35
35
  throw getError({
@@ -1 +1 @@
1
- {"version":3,"file":"enforcer-registry.js","sourceRoot":"","sources":["../../../../../../src/base/auth/authorize/enforcers/enforcer-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { SingletonRealm } from '@/helpers/singleton-realm';\nimport type { Container } from '@/helpers/inversion/container';\nimport type { TClass, TNullable } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport type { IAuthUser } from '../../authenticate/common/types';\nimport { AbstractAuthRegistry } from '../../base';\nimport type {\n AuthorizationEnforcerTypes,\n IAuthorizationEnforcer,\n IAuthorizationUser,\n IAuthorizeOptions,\n ICasbinEnforcerOptions,\n} from '../common';\nimport { Authorization, AuthorizeBindingKeys } from '../common';\n\nexport class AuthorizationEnforcerRegistry extends AbstractAuthRegistry<IAuthorizationEnforcer> {\n static readonly SINGLETON_REAL_KEY = 'authorization-enforcer-registry';\n\n private configuredEnforcers: Set<string>;\n\n /** In-flight `configure()` calls, so concurrent first requests share one warmup instead of racing. */\n private pendingConfigurations: Map<string, Promise<void>>;\n\n /** Set by AuthorizeComponent from the application container. Held here because the descriptor scan\n * below sees only registered enforcers, and `defaultDecision` has to be readable when there are none. */\n private applicationOptions: TNullable<IAuthorizeOptions> = null;\n\n constructor() {\n super({ scope: AuthorizationEnforcerRegistry.name });\n this.configuredEnforcers = new Set();\n this.pendingConfigurations = new Map();\n }\n\n static getInstance() {\n return SingletonRealm.resolve({\n key: AuthorizationEnforcerRegistry.SINGLETON_REAL_KEY,\n create: () => new AuthorizationEnforcerRegistry(),\n });\n }\n\n override reset(): void {\n super.reset();\n this.configuredEnforcers.clear();\n this.pendingConfigurations.clear();\n this.applicationOptions = null;\n }\n\n protected getBindingPrefix(): string {\n return Authorization.ENFORCER;\n }\n\n register(opts: {\n container: Container;\n enforcers: Array<\n | {\n enforcer: TClass<IAuthorizationEnforcer>;\n name: string;\n type: typeof AuthorizationEnforcerTypes.CASBIN;\n options?: ICasbinEnforcerOptions;\n }\n | {\n enforcer: TClass<IAuthorizationEnforcer>;\n name: string;\n type: typeof AuthorizationEnforcerTypes.CUSTOM;\n options?: unknown;\n }\n >;\n }) {\n const { container, enforcers } = opts;\n\n const names = enforcers.map(e => e.name);\n const duplicateNames = names.filter((n, i) => names.indexOf(n) !== i);\n if (duplicateNames.length) {\n throw getError({\n message: `[AuthorizationEnforcerRegistry] Duplicate enforcer name(s): ${[...new Set(duplicateNames)].join(', ')}`,\n });\n }\n\n for (const { enforcer, name, options } of enforcers) {\n if (this.descriptors.has(name)) {\n throw getError({\n message: `[AuthorizationEnforcerRegistry] Enforcer already registered: ${name}`,\n });\n }\n\n this.registerDescriptor({ container, target: enforcer, name });\n\n if (options) {\n container.bind({ key: AuthorizeBindingKeys.enforcerOptions(name) }).toValue(options);\n }\n }\n\n return this;\n }\n\n hasEnforcers(): boolean {\n return this.descriptors.size > 0;\n }\n\n getDefaultEnforcerName(): string {\n return this.getDefaultName();\n }\n\n /**\n * The PROMISE is memoised, not just the completed flag.\n *\n * `configure()` yields (it dynamic-imports casbin), and the flag was only set after the await -\n * so a burst of first requests each saw an unconfigured enforcer and each built a full pool.\n * Measured: 40 concurrent first requests produced 40 configure() calls and 640 enforcers.\n * The entry is dropped on rejection so a failed warmup does not poison every later request.\n */\n async resolveEnforcer(opts: { name: string }): Promise<IAuthorizationEnforcer> {\n const enforcer = this.resolveDescriptor(opts);\n\n if (this.configuredEnforcers.has(opts.name)) {\n return enforcer;\n }\n\n const inFlight = this.pendingConfigurations.get(opts.name);\n if (inFlight) {\n await inFlight;\n return enforcer;\n }\n\n // `Promise.resolve` because `configure()` is declared `ValueOrPromise<void>` - a synchronous\n // implementation returns plain `void`, which has no `.then`.\n const pending = Promise.resolve(enforcer.configure())\n .then(() => {\n this.configuredEnforcers.add(opts.name);\n })\n .finally(() => {\n this.pendingConfigurations.delete(opts.name);\n });\n\n this.pendingConfigurations.set(opts.name, pending);\n\n await pending;\n return enforcer;\n }\n\n /** Drop a user's cached policies on the resolved enforcer. Lazy - next request rebuilds. */\n async invalidateUserCache(opts: {\n user: IAuthorizationUser;\n enforcerName?: string;\n }): Promise<{ invalidatedKeys: number }> {\n const name = opts.enforcerName ?? this.getDefaultEnforcerName();\n const enforcer = await this.resolveEnforcer({ name });\n\n // Cache management is an optional IAuthorizationEnforcer capability - feature-detect it.\n if (typeof enforcer.invalidateUserCache !== 'function') {\n throw getError({\n message: `[AuthorizationEnforcerRegistry] Enforcer \"${name}\" does not support cache invalidation`,\n });\n }\n\n return enforcer.invalidateUserCache({ user: opts.user });\n }\n\n /** Drop then immediately rebuild + re-cache a user's policies on the resolved enforcer. */\n async rebuildUserCache(opts: {\n user: { principalType: string } & IAuthUser;\n enforcerName?: string;\n }): Promise<{ cacheKey: string; lineCount: number }> {\n const name = opts.enforcerName ?? this.getDefaultEnforcerName();\n const enforcer = await this.resolveEnforcer({ name });\n\n if (typeof enforcer.rebuildUserCache !== 'function') {\n throw getError({\n message: `[AuthorizationEnforcerRegistry] Enforcer \"${name}\" does not support cache invalidation`,\n });\n }\n\n return enforcer.rebuildUserCache({ user: opts.user });\n }\n\n /** Options bound on the application, independent of any enforcer. */\n setOptions(opts: { options: IAuthorizeOptions }): void {\n this.applicationOptions = opts.options;\n }\n\n resolveOptions(): IAuthorizeOptions | undefined {\n if (this.applicationOptions) {\n return this.applicationOptions;\n }\n\n for (const [, metadata] of this.descriptors) {\n const { container } = metadata;\n const options = container.get<IAuthorizeOptions>({\n key: AuthorizeBindingKeys.OPTIONS,\n isOptional: true,\n });\n if (options) {\n return options;\n }\n }\n return undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"enforcer-registry.js","sourceRoot":"","sources":["../../../../../../src/base/auth/authorize/enforcers/enforcer-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { SingletonRealm } from '@/helpers/singleton-realm';\nimport type { Container } from '@/helpers/inversion/container';\nimport type { TClass, TNullable } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport type { IAuthUser } from '../../authenticate/common/types';\nimport { AbstractAuthRegistry } from '../../base';\nimport type {\n AuthorizationEnforcerTypes,\n IAuthorizationEnforcer,\n IAuthorizationUser,\n IAuthorizeOptions,\n ICasbinEnforcerOptions,\n} from '../common';\nimport { Authorization, AuthorizeBindingKeys } from '../common';\n\nexport class AuthorizationEnforcerRegistry extends AbstractAuthRegistry<IAuthorizationEnforcer> {\n static readonly SINGLETON_REAL_KEY = 'authorization-enforcer-registry';\n\n private configuredEnforcers: Set<string>;\n\n /** In-flight `configure()` calls, so concurrent first requests share one warmup instead of racing. */\n private pendingConfigurations: Map<string, Promise<void>>;\n\n /** Set by AuthorizeComponent from the application container. Held here because the descriptor scan\n * below sees only registered enforcers, and `defaultDecision` has to be readable when there are none. */\n private applicationOptions: TNullable<IAuthorizeOptions> = null;\n\n constructor() {\n super({ scope: AuthorizationEnforcerRegistry.name });\n this.configuredEnforcers = new Set();\n this.pendingConfigurations = new Map();\n }\n\n static getInstance() {\n return SingletonRealm.resolve({\n key: AuthorizationEnforcerRegistry.SINGLETON_REAL_KEY,\n create: () => new AuthorizationEnforcerRegistry(),\n });\n }\n\n override reset(): void {\n super.reset();\n this.configuredEnforcers.clear();\n this.pendingConfigurations.clear();\n this.applicationOptions = null;\n }\n\n protected getBindingPrefix(): string {\n return Authorization.ENFORCER;\n }\n\n register(opts: {\n container: Container;\n enforcers: Array<\n | {\n enforcer: TClass<IAuthorizationEnforcer>;\n name: string;\n type: typeof AuthorizationEnforcerTypes.CASBIN;\n options?: ICasbinEnforcerOptions;\n }\n | {\n enforcer: TClass<IAuthorizationEnforcer>;\n name: string;\n type: typeof AuthorizationEnforcerTypes.CUSTOM;\n options?: unknown;\n }\n >;\n }) {\n const { container, enforcers } = opts;\n\n const names = enforcers.map((e) => e.name);\n const duplicateNames = names.filter((n, i) => names.indexOf(n) !== i);\n if (duplicateNames.length) {\n throw getError({\n message: `[AuthorizationEnforcerRegistry] Duplicate enforcer name(s): ${[...new Set(duplicateNames)].join(', ')}`,\n });\n }\n\n for (const { enforcer, name, options } of enforcers) {\n if (this.descriptors.has(name)) {\n throw getError({\n message: `[AuthorizationEnforcerRegistry] Enforcer already registered: ${name}`,\n });\n }\n\n this.registerDescriptor({ container, target: enforcer, name });\n\n if (options) {\n container.bind({ key: AuthorizeBindingKeys.enforcerOptions(name) }).toValue(options);\n }\n }\n\n return this;\n }\n\n hasEnforcers(): boolean {\n return this.descriptors.size > 0;\n }\n\n getDefaultEnforcerName(): string {\n return this.getDefaultName();\n }\n\n /**\n * The PROMISE is memoised, not just the completed flag.\n *\n * `configure()` yields (it dynamic-imports casbin), and the flag was only set after the await -\n * so a burst of first requests each saw an unconfigured enforcer and each built a full pool.\n * Measured: 40 concurrent first requests produced 40 configure() calls and 640 enforcers.\n * The entry is dropped on rejection so a failed warmup does not poison every later request.\n */\n async resolveEnforcer(opts: { name: string }): Promise<IAuthorizationEnforcer> {\n const enforcer = this.resolveDescriptor(opts);\n\n if (this.configuredEnforcers.has(opts.name)) {\n return enforcer;\n }\n\n const inFlight = this.pendingConfigurations.get(opts.name);\n if (inFlight) {\n await inFlight;\n return enforcer;\n }\n\n // `Promise.resolve` because `configure()` is declared `ValueOrPromise<void>` - a synchronous\n // implementation returns plain `void`, which has no `.then`.\n const pending = Promise.resolve(enforcer.configure())\n .then(() => {\n this.configuredEnforcers.add(opts.name);\n })\n .finally(() => {\n this.pendingConfigurations.delete(opts.name);\n });\n\n this.pendingConfigurations.set(opts.name, pending);\n\n await pending;\n return enforcer;\n }\n\n /** Drop a user's cached policies on the resolved enforcer. Lazy - next request rebuilds. */\n async invalidateUserCache(opts: {\n user: IAuthorizationUser;\n enforcerName?: string;\n }): Promise<{ invalidatedKeys: number }> {\n const name = opts.enforcerName ?? this.getDefaultEnforcerName();\n const enforcer = await this.resolveEnforcer({ name });\n\n // Cache management is an optional IAuthorizationEnforcer capability - feature-detect it.\n if (typeof enforcer.invalidateUserCache !== 'function') {\n throw getError({\n message: `[AuthorizationEnforcerRegistry] Enforcer \"${name}\" does not support cache invalidation`,\n });\n }\n\n return enforcer.invalidateUserCache({ user: opts.user });\n }\n\n /** Drop then immediately rebuild + re-cache a user's policies on the resolved enforcer. */\n async rebuildUserCache(opts: {\n user: { principalType: string } & IAuthUser;\n enforcerName?: string;\n }): Promise<{ cacheKey: string; lineCount: number }> {\n const name = opts.enforcerName ?? this.getDefaultEnforcerName();\n const enforcer = await this.resolveEnforcer({ name });\n\n if (typeof enforcer.rebuildUserCache !== 'function') {\n throw getError({\n message: `[AuthorizationEnforcerRegistry] Enforcer \"${name}\" does not support cache invalidation`,\n });\n }\n\n return enforcer.rebuildUserCache({ user: opts.user });\n }\n\n /** Options bound on the application, independent of any enforcer. */\n setOptions(opts: { options: IAuthorizeOptions }): void {\n this.applicationOptions = opts.options;\n }\n\n resolveOptions(): IAuthorizeOptions | undefined {\n if (this.applicationOptions) {\n return this.applicationOptions;\n }\n\n for (const [, metadata] of this.descriptors) {\n const { container } = metadata;\n const options = container.get<IAuthorizeOptions>({\n key: AuthorizeBindingKeys.OPTIONS,\n isOptional: true,\n });\n if (options) {\n return options;\n }\n }\n return undefined;\n }\n}\n"]}
@@ -11,7 +11,7 @@ export class AuthorizationProvider extends BaseHelper {
11
11
  super({ scope: AuthorizationProvider.name });
12
12
  }
13
13
  value() {
14
- return opts => {
14
+ return (opts) => {
15
15
  return this.createAuthorizeMiddleware(opts);
16
16
  };
17
17
  }
@@ -37,11 +37,11 @@ export class AuthorizationProvider extends BaseHelper {
37
37
  if (needsRoleCheck) {
38
38
  const userRoles = this.extractUserRoles({ user });
39
39
  if (options?.alwaysAllowRoles?.length &&
40
- userRoles.some(r => options.alwaysAllowRoles.includes(r))) {
40
+ userRoles.some((r) => options.alwaysAllowRoles.includes(r))) {
41
41
  logger.warn('SKIP checking authorization | User has always-allow role | userRoles: %s', userRoles);
42
42
  return next();
43
43
  }
44
- if (spec.allowedRoles?.length && userRoles.some(r => spec.allowedRoles.includes(r))) {
44
+ if (spec.allowedRoles?.length && userRoles.some((r) => spec.allowedRoles.includes(r))) {
45
45
  logger.warn('GRANT access | User has allowed role for route | userRoles: %s', userRoles);
46
46
  return next();
47
47
  }
@@ -1 +1 @@
1
- {"version":3,"file":"authorization.provider.js","sourceRoot":"","sources":["../../../../../../src/base/auth/authorize/providers/authorization.provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { asTypedContext } from '@/base/controllers/context';\nimport { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport type { IProvider } from '@venizia/ignis-inversion';\nimport { createMiddleware } from 'hono/factory';\nimport type { IAuthUser } from '../../authenticate/common/types';\n// Deep import (not the authenticate barrel): the barrel re-exports ./controllers, whose factory extends BaseRestController - a value import here forms the base/controllers <-> auth init cycle.\nimport { Authentication } from '../../authenticate/common/constants';\nimport type { IAuthorizationSpec, TAuthorizeFn } from '../common';\nimport { Authorization, AuthorizationDecisions, AuthorizationErrors } from '../common';\nimport { AuthorizationEnforcerRegistry } from '../enforcers/enforcer-registry';\nimport { resolveRequestDomain } from './request-domain';\n\nexport class AuthorizationProvider extends BaseHelper implements IProvider<TAuthorizeFn> {\n constructor() {\n super({ scope: AuthorizationProvider.name });\n }\n\n value(): TAuthorizeFn {\n return opts => {\n return this.createAuthorizeMiddleware(opts);\n };\n }\n\n private createAuthorizeMiddleware(opts: { spec: IAuthorizationSpec; enforcerName?: string }) {\n const { spec, enforcerName } = opts;\n const logger = this.logger.for(this.createAuthorizeMiddleware.name);\n\n return createMiddleware(async (context, next) => {\n const registry = AuthorizationEnforcerRegistry.getInstance();\n const options = registry.resolveOptions();\n\n const isSkipAuthorize = context.get(Authorization.SKIP_AUTHORIZATION);\n if (isSkipAuthorize) {\n logger.warn('SKIP checking authorization | path: %s', context.req.path);\n return next();\n }\n\n const user = context.get(Authentication.CURRENT_USER) as IAuthUser | undefined;\n if (!user) {\n throw getError({\n error: AuthorizationErrors.UNAUTHENTICATED,\n message: 'Authorization failed: No authenticated user found',\n });\n }\n\n const needsRoleCheck =\n Boolean(options?.alwaysAllowRoles?.length) || Boolean(spec.allowedRoles?.length);\n if (needsRoleCheck) {\n const userRoles = this.extractUserRoles({ user });\n\n if (\n options?.alwaysAllowRoles?.length &&\n userRoles.some(r => options.alwaysAllowRoles!.includes(r))\n ) {\n logger.warn(\n 'SKIP checking authorization | User has always-allow role | userRoles: %s',\n userRoles,\n );\n return next();\n }\n\n if (spec.allowedRoles?.length && userRoles.some(r => spec.allowedRoles!.includes(r))) {\n logger.warn('GRANT access | User has allowed role for route | userRoles: %s', userRoles);\n return next();\n }\n }\n\n const votersList = spec.voters ?? [];\n for (const voter of votersList) {\n const decision = await voter({\n user,\n action: spec.action,\n resource: spec.resource,\n context: asTypedContext(context),\n });\n\n if (decision === AuthorizationDecisions.DENY) {\n throw getError({\n error: AuthorizationErrors.DENIED_BY_VOTER,\n message: `Authorization denied by voter | action: ${spec.action} | resource: ${spec.resource}`,\n messageArgs: { action: spec.action, resource: spec.resource },\n });\n }\n\n if (decision === AuthorizationDecisions.ALLOW) {\n await next();\n return;\n }\n\n // ABSTAIN → continue to enforcer\n }\n\n if (!registry.hasEnforcers()) {\n const noEnforcerDecision = options?.defaultDecision ?? AuthorizationDecisions.DENY;\n\n if (noEnforcerDecision === AuthorizationDecisions.ALLOW) {\n logger.warn(\n 'ALLOW checking authorization | No enforcers registered | path: %s',\n context.req.path,\n );\n return next();\n }\n\n throw getError({\n error: AuthorizationErrors.ENFORCER_NOT_REGISTERED,\n message: `Authorization failed: authorize() was declared for this route but no enforcer is registered | path: ${context.req.path}`,\n });\n }\n\n const resolvedName = enforcerName ?? registry.getDefaultEnforcerName();\n const enforcer = await registry.resolveEnforcer({ name: resolvedName });\n\n // Only resolve domain scope when it is actually in play (per-route domain OR a configured global resolver) - avoids a resolver call (possible DB hit) for legacy enforcers.\n //\n // Held in a LOCAL, not read back out of the context. One middleware is pushed per spec onto\n // the same Hono context, so reading `Authorization.DOMAIN` at decision time meant a\n // domain-less spec inherited the tenant domain a PREVIOUS spec had written - silently\n // widening a check that should have run at SYSTEM_WIDE. The context is still set, for\n // observability, but nothing decides on it.\n const domainScope =\n spec.domain || options?.domainResolver\n ? await resolveRequestDomain({\n spec,\n context: asTypedContext(context),\n options,\n })\n : undefined;\n context.set(Authorization.DOMAIN, domainScope);\n\n // Keyed by enforcer. The slot used to hold one rule set for the whole request, so a second\n // `authorize()` naming a DIFFERENT enforcer evaluated against the first enforcer's rules -\n // granting where its own policy set denies.\n //\n // `instanceof Map`, not a truthiness test: the slot previously held a bare rule set, so\n // anything that pre-populates it with the old shape would otherwise reach `.get` on a value\n // that has no such method and take the request down with a TypeError.\n const existingRules = context.get(Authorization.RULES);\n const rulesByEnforcer =\n existingRules instanceof Map ? existingRules : new Map<string, unknown>();\n let rules = rulesByEnforcer.get(resolvedName);\n\n if (!rules) {\n if (!user.principalType) {\n throw getError({\n error: AuthorizationErrors.PRINCIPAL_TYPE_MISSING,\n message:\n 'Authorization failed: user.principalType is required for enforcer-based authorization',\n });\n }\n\n rules = await enforcer.buildRules({\n user: user as { principalType: string } & IAuthUser,\n context: asTypedContext(context),\n });\n rulesByEnforcer.set(resolvedName, rules);\n context.set(Authorization.RULES, rulesByEnforcer);\n }\n\n let decision = await enforcer.evaluate({\n rules,\n request: {\n action: spec.action,\n resource: spec.resource,\n conditions: spec.conditions,\n domain: domainScope,\n },\n context: asTypedContext(context),\n });\n\n if (decision === AuthorizationDecisions.ABSTAIN) {\n decision = options?.defaultDecision ?? AuthorizationDecisions.DENY;\n }\n\n if (decision !== AuthorizationDecisions.ALLOW) {\n throw getError({\n error: AuthorizationErrors.DENIED,\n message: `Authorization denied | action: ${spec.action} | resource: ${spec.resource}`,\n messageArgs: { action: spec.action, resource: spec.resource },\n });\n }\n\n await next();\n });\n }\n\n private extractUserRoles(opts: { user: IAuthUser }): string[] {\n const { user } = opts;\n const roles = user.roles;\n\n if (!Array.isArray(roles)) {\n return [];\n }\n\n return roles.map((r: string | { identifier?: string; name?: string; id?: unknown }) => {\n if (typeof r === 'string') {\n return r;\n }\n return r.identifier ?? r.name ?? String(r.id ?? '');\n });\n }\n}\n"]}
1
+ {"version":3,"file":"authorization.provider.js","sourceRoot":"","sources":["../../../../../../src/base/auth/authorize/providers/authorization.provider.ts"],"names":[],"mappings":"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","sourcesContent":["import { asTypedContext } from '@/base/controllers/context';\nimport { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport type { IProvider } from '@venizia/ignis-inversion';\nimport { createMiddleware } from 'hono/factory';\nimport type { IAuthUser } from '../../authenticate/common/types';\n// Deep import (not the authenticate barrel): the barrel re-exports ./controllers, whose factory extends BaseRestController - a value import here forms the base/controllers <-> auth init cycle.\nimport { Authentication } from '../../authenticate/common/constants';\nimport type { IAuthorizationSpec, TAuthorizeFn } from '../common';\nimport { Authorization, AuthorizationDecisions, AuthorizationErrors } from '../common';\nimport { AuthorizationEnforcerRegistry } from '../enforcers/enforcer-registry';\nimport { resolveRequestDomain } from './request-domain';\n\nexport class AuthorizationProvider extends BaseHelper implements IProvider<TAuthorizeFn> {\n constructor() {\n super({ scope: AuthorizationProvider.name });\n }\n\n value(): TAuthorizeFn {\n return (opts) => {\n return this.createAuthorizeMiddleware(opts);\n };\n }\n\n private createAuthorizeMiddleware(opts: { spec: IAuthorizationSpec; enforcerName?: string }) {\n const { spec, enforcerName } = opts;\n const logger = this.logger.for(this.createAuthorizeMiddleware.name);\n\n return createMiddleware(async (context, next) => {\n const registry = AuthorizationEnforcerRegistry.getInstance();\n const options = registry.resolveOptions();\n\n const isSkipAuthorize = context.get(Authorization.SKIP_AUTHORIZATION);\n if (isSkipAuthorize) {\n logger.warn('SKIP checking authorization | path: %s', context.req.path);\n return next();\n }\n\n const user = context.get(Authentication.CURRENT_USER) as IAuthUser | undefined;\n if (!user) {\n throw getError({\n error: AuthorizationErrors.UNAUTHENTICATED,\n message: 'Authorization failed: No authenticated user found',\n });\n }\n\n const needsRoleCheck =\n Boolean(options?.alwaysAllowRoles?.length) || Boolean(spec.allowedRoles?.length);\n if (needsRoleCheck) {\n const userRoles = this.extractUserRoles({ user });\n\n if (\n options?.alwaysAllowRoles?.length &&\n userRoles.some((r) => options.alwaysAllowRoles!.includes(r))\n ) {\n logger.warn(\n 'SKIP checking authorization | User has always-allow role | userRoles: %s',\n userRoles,\n );\n return next();\n }\n\n if (spec.allowedRoles?.length && userRoles.some((r) => spec.allowedRoles!.includes(r))) {\n logger.warn('GRANT access | User has allowed role for route | userRoles: %s', userRoles);\n return next();\n }\n }\n\n const votersList = spec.voters ?? [];\n for (const voter of votersList) {\n const decision = await voter({\n user,\n action: spec.action,\n resource: spec.resource,\n context: asTypedContext(context),\n });\n\n if (decision === AuthorizationDecisions.DENY) {\n throw getError({\n error: AuthorizationErrors.DENIED_BY_VOTER,\n message: `Authorization denied by voter | action: ${spec.action} | resource: ${spec.resource}`,\n messageArgs: { action: spec.action, resource: spec.resource },\n });\n }\n\n if (decision === AuthorizationDecisions.ALLOW) {\n await next();\n return;\n }\n\n // ABSTAIN → continue to enforcer\n }\n\n if (!registry.hasEnforcers()) {\n const noEnforcerDecision = options?.defaultDecision ?? AuthorizationDecisions.DENY;\n\n if (noEnforcerDecision === AuthorizationDecisions.ALLOW) {\n logger.warn(\n 'ALLOW checking authorization | No enforcers registered | path: %s',\n context.req.path,\n );\n return next();\n }\n\n throw getError({\n error: AuthorizationErrors.ENFORCER_NOT_REGISTERED,\n message: `Authorization failed: authorize() was declared for this route but no enforcer is registered | path: ${context.req.path}`,\n });\n }\n\n const resolvedName = enforcerName ?? registry.getDefaultEnforcerName();\n const enforcer = await registry.resolveEnforcer({ name: resolvedName });\n\n // Only resolve domain scope when it is actually in play (per-route domain OR a configured global resolver) - avoids a resolver call (possible DB hit) for legacy enforcers.\n //\n // Held in a LOCAL, not read back out of the context. One middleware is pushed per spec onto\n // the same Hono context, so reading `Authorization.DOMAIN` at decision time meant a\n // domain-less spec inherited the tenant domain a PREVIOUS spec had written - silently\n // widening a check that should have run at SYSTEM_WIDE. The context is still set, for\n // observability, but nothing decides on it.\n const domainScope =\n spec.domain || options?.domainResolver\n ? await resolveRequestDomain({\n spec,\n context: asTypedContext(context),\n options,\n })\n : undefined;\n context.set(Authorization.DOMAIN, domainScope);\n\n // Keyed by enforcer. The slot used to hold one rule set for the whole request, so a second\n // `authorize()` naming a DIFFERENT enforcer evaluated against the first enforcer's rules -\n // granting where its own policy set denies.\n //\n // `instanceof Map`, not a truthiness test: the slot previously held a bare rule set, so\n // anything that pre-populates it with the old shape would otherwise reach `.get` on a value\n // that has no such method and take the request down with a TypeError.\n const existingRules = context.get(Authorization.RULES);\n const rulesByEnforcer =\n existingRules instanceof Map ? existingRules : new Map<string, unknown>();\n let rules = rulesByEnforcer.get(resolvedName);\n\n if (!rules) {\n if (!user.principalType) {\n throw getError({\n error: AuthorizationErrors.PRINCIPAL_TYPE_MISSING,\n message:\n 'Authorization failed: user.principalType is required for enforcer-based authorization',\n });\n }\n\n rules = await enforcer.buildRules({\n user: user as { principalType: string } & IAuthUser,\n context: asTypedContext(context),\n });\n rulesByEnforcer.set(resolvedName, rules);\n context.set(Authorization.RULES, rulesByEnforcer);\n }\n\n let decision = await enforcer.evaluate({\n rules,\n request: {\n action: spec.action,\n resource: spec.resource,\n conditions: spec.conditions,\n domain: domainScope,\n },\n context: asTypedContext(context),\n });\n\n if (decision === AuthorizationDecisions.ABSTAIN) {\n decision = options?.defaultDecision ?? AuthorizationDecisions.DENY;\n }\n\n if (decision !== AuthorizationDecisions.ALLOW) {\n throw getError({\n error: AuthorizationErrors.DENIED,\n message: `Authorization denied | action: ${spec.action} | resource: ${spec.resource}`,\n messageArgs: { action: spec.action, resource: spec.resource },\n });\n }\n\n await next();\n });\n }\n\n private extractUserRoles(opts: { user: IAuthUser }): string[] {\n const { user } = opts;\n const roles = user.roles;\n\n if (!Array.isArray(roles)) {\n return [];\n }\n\n return roles.map((r: string | { identifier?: string; name?: string; id?: unknown }) => {\n if (typeof r === 'string') {\n return r;\n }\n return r.identifier ?? r.name ?? String(r.id ?? '');\n });\n }\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import type { AbstractEntity } from '../../models/index.js';
2
2
  import type { AbstractRepository } from '../../repositories/index.js';
3
3
  import type { TAnyObjectSchema } from '../common/schema-builders.js';
4
- import type { ValueOrPromise } from '@venizia/ignis-helpers/common';
4
+ import type { AnyType, ValueOrPromise } from '@venizia/ignis-helpers/common';
5
5
  import { BaseHelper } from '@venizia/ignis-helpers/core';
6
6
  import type { Env, Schema } from 'hono';
7
7
  import type { ICrudControllerOptions, ICustomizableRoutes, TEntityDataObject, TEntityPersistObject } from '../common/index.js';
@@ -9,7 +9,7 @@ import type { ICrudControllerOptions, ICustomizableRoutes, TEntityDataObject, TE
9
9
  export declare class ControllerFactory extends BaseHelper {
10
10
  constructor();
11
11
  static defineCrudController<TEntity extends AbstractEntity<TAnyObjectSchema> = AbstractEntity<TAnyObjectSchema>, Routes extends ICustomizableRoutes = ICustomizableRoutes, RouteEnv extends Env = Env, RouteSchema extends Schema = {}, BasePath extends string = '/', ConfigurableOptions extends object = {}, TDataObject extends object = TEntityDataObject<TEntity>, TPersistObject extends object = TEntityPersistObject<TEntity>>(defOpts: ICrudControllerOptions<TEntity, Routes>): {
12
- new (repository: AbstractRepository<TDataObject, TPersistObject>): {
12
+ new (repository: AbstractRepository<TDataObject, TPersistObject, AnyType>): {
13
13
  /** Registers each CRUD route whose handler tier supplies it, honoring enabledRoutes/readonly. */
14
14
  binding(): ValueOrPromise<void>;
15
15
  create(opts: {
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,UAAU,EAAY,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,WAAW,CAAC;AAKnB,6EAA6E;AAC7E,qBAAa,iBAAkB,SAAQ,UAAU;;IAK/C,MAAM,CAAC,oBAAoB,CACzB,OAAO,SAAS,cAAc,CAAC,gBAAgB,CAAC,GAAG,cAAc,CAAC,gBAAgB,CAAC,EACnF,MAAM,SAAS,mBAAmB,GAAG,mBAAmB,EACxD,QAAQ,SAAS,GAAG,GAAG,GAAG,EAC1B,WAAW,SAAS,MAAM,GAAG,EAAE,EAC/B,QAAQ,SAAS,MAAM,GAAG,GAAG,EAC7B,mBAAmB,SAAS,MAAM,GAAG,EAAE,EACvC,WAAW,SAAS,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,EACvD,cAAc,SAAS,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,EAC7D,OAAO,EAAE,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC;yBAwCtB,kBAAkB,CAAC,WAAW,EAAE,cAAc,CAAC;YAUvE,iGAAiG;uBAC7E,cAAc,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBADkB,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyF/D"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAY,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,WAAW,CAAC;AAKnB,6EAA6E;AAC7E,qBAAa,iBAAkB,SAAQ,UAAU;;IAK/C,MAAM,CAAC,oBAAoB,CACzB,OAAO,SAAS,cAAc,CAAC,gBAAgB,CAAC,GAAG,cAAc,CAAC,gBAAgB,CAAC,EACnF,MAAM,SAAS,mBAAmB,GAAG,mBAAmB,EACxD,QAAQ,SAAS,GAAG,GAAG,GAAG,EAC1B,WAAW,SAAS,MAAM,GAAG,EAAE,EAC/B,QAAQ,SAAS,MAAM,GAAG,GAAG,EAC7B,mBAAmB,SAAS,MAAM,GAAG,EAAE,EACvC,WAAW,SAAS,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,EACvD,cAAc,SAAS,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,EAC7D,OAAO,EAAE,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC;yBAyCtB,kBAAkB,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,CAAC;YAUhF,iGAAiG;uBAC7E,cAAc,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAN3B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8FnB"}
@@ -33,6 +33,7 @@ export class ControllerFactory extends BaseHelper {
33
33
  serverStampedKeys: entityInstance.getServerStampedKeys(),
34
34
  });
35
35
  const controllerClass = class extends PersistableCrudController {
36
+ // Any extra options: a repository whose options narrow `IExtraOptions` (a typed transaction) must fit.
36
37
  constructor(repository) {
37
38
  super({
38
39
  scope: name,