@venizia/ignis-kernel 0.4.0 → 0.4.2

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 (191) 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/cors.d.ts +13 -0
  10. package/dist/cjs/base/applications/cors.d.ts.map +1 -0
  11. package/dist/cjs/base/applications/cors.js +43 -0
  12. package/dist/cjs/base/applications/cors.js.map +1 -0
  13. package/dist/cjs/base/applications/deprecations.d.ts +10 -0
  14. package/dist/cjs/base/applications/deprecations.d.ts.map +1 -0
  15. package/dist/cjs/base/applications/deprecations.js +23 -0
  16. package/dist/cjs/base/applications/deprecations.js.map +1 -0
  17. package/dist/cjs/base/applications/rest.d.ts.map +1 -1
  18. package/dist/cjs/base/applications/rest.js +11 -5
  19. package/dist/cjs/base/applications/rest.js.map +1 -1
  20. package/dist/cjs/base/auth/authenticate/common/codecs.js +2 -2
  21. package/dist/cjs/base/auth/authenticate/common/codecs.js.map +1 -1
  22. package/dist/cjs/base/auth/authenticate/providers/authentication.provider.js +1 -1
  23. package/dist/cjs/base/auth/authenticate/providers/authentication.provider.js.map +1 -1
  24. package/dist/cjs/base/auth/authenticate/strategies/strategy-registry.js +1 -1
  25. package/dist/cjs/base/auth/authenticate/strategies/strategy-registry.js.map +1 -1
  26. package/dist/cjs/base/auth/authorize/builders/grant.builder.js +12 -12
  27. package/dist/cjs/base/auth/authorize/builders/grant.builder.js.map +1 -1
  28. package/dist/cjs/base/auth/authorize/builders/permission.builder.js +1 -1
  29. package/dist/cjs/base/auth/authorize/builders/permission.builder.js.map +1 -1
  30. package/dist/cjs/base/auth/authorize/builders/policy.builder.js +1 -1
  31. package/dist/cjs/base/auth/authorize/builders/policy.builder.js.map +1 -1
  32. package/dist/cjs/base/auth/authorize/common/constants/authorization.d.ts.map +1 -1
  33. package/dist/cjs/base/auth/authorize/common/constants/authorization.js +2 -2
  34. package/dist/cjs/base/auth/authorize/common/constants/authorization.js.map +1 -1
  35. package/dist/cjs/base/auth/authorize/enforcers/enforcer-registry.js +1 -1
  36. package/dist/cjs/base/auth/authorize/enforcers/enforcer-registry.js.map +1 -1
  37. package/dist/cjs/base/auth/authorize/providers/authorization.provider.js +3 -3
  38. package/dist/cjs/base/auth/authorize/providers/authorization.provider.js.map +1 -1
  39. package/dist/cjs/base/controllers/factory/authorize-guard.d.ts +19 -0
  40. package/dist/cjs/base/controllers/factory/authorize-guard.d.ts.map +1 -0
  41. package/dist/cjs/base/controllers/factory/authorize-guard.js +60 -0
  42. package/dist/cjs/base/controllers/factory/authorize-guard.js.map +1 -0
  43. package/dist/cjs/base/controllers/factory/controller.d.ts +2 -2
  44. package/dist/cjs/base/controllers/factory/controller.d.ts.map +1 -1
  45. package/dist/cjs/base/controllers/factory/controller.js +9 -0
  46. package/dist/cjs/base/controllers/factory/controller.js.map +1 -1
  47. package/dist/cjs/base/controllers/factory/crud/abstract.d.ts +1 -1
  48. package/dist/cjs/base/controllers/factory/crud/abstract.d.ts.map +1 -1
  49. package/dist/cjs/base/controllers/factory/crud/abstract.js.map +1 -1
  50. package/dist/cjs/base/controllers/factory/definition.js +1 -1
  51. package/dist/cjs/base/controllers/factory/definition.js.map +1 -1
  52. package/dist/cjs/base/controllers/rest/extras.js +5 -5
  53. package/dist/cjs/base/controllers/rest/extras.js.map +1 -1
  54. package/dist/cjs/base/metadata/injectable.js +1 -1
  55. package/dist/cjs/base/metadata/injectable.js.map +1 -1
  56. package/dist/cjs/base/metadata/model-settings.d.ts +21 -0
  57. package/dist/cjs/base/metadata/model-settings.d.ts.map +1 -0
  58. package/dist/cjs/base/metadata/model-settings.js +77 -0
  59. package/dist/cjs/base/metadata/model-settings.js.map +1 -0
  60. package/dist/cjs/base/metadata/persistents.d.ts +1 -1
  61. package/dist/cjs/base/metadata/persistents.d.ts.map +1 -1
  62. package/dist/cjs/base/metadata/persistents.js +24 -12
  63. package/dist/cjs/base/metadata/persistents.js.map +1 -1
  64. package/dist/cjs/base/metadata/routes/controller.js +1 -1
  65. package/dist/cjs/base/metadata/routes/controller.js.map +1 -1
  66. package/dist/cjs/base/middlewares/app-error/app-error.middleware.js +3 -3
  67. package/dist/cjs/base/middlewares/app-error/app-error.middleware.js.map +1 -1
  68. package/dist/cjs/base/middlewares/app-error/zod.handler.js +2 -2
  69. package/dist/cjs/base/middlewares/app-error/zod.handler.js.map +1 -1
  70. package/dist/cjs/base/middlewares/form-body/form-body.middleware.js +2 -2
  71. package/dist/cjs/base/middlewares/form-body/form-body.middleware.js.map +1 -1
  72. package/dist/cjs/base/middlewares/not-found/not-found.middleware.js.map +1 -1
  73. package/dist/cjs/base/models/common/utilities.js +1 -1
  74. package/dist/cjs/base/models/common/utilities.js.map +1 -1
  75. package/dist/cjs/base/repositories/common/constants.d.ts +18 -1
  76. package/dist/cjs/base/repositories/common/constants.d.ts.map +1 -1
  77. package/dist/cjs/base/repositories/common/constants.js +22 -2
  78. package/dist/cjs/base/repositories/common/constants.js.map +1 -1
  79. package/dist/cjs/base/repositories/common/types/contracts.d.ts +17 -17
  80. package/dist/cjs/base/repositories/common/types/contracts.d.ts.map +1 -1
  81. package/dist/cjs/base/repositories/common/types/contracts.js.map +1 -1
  82. package/dist/cjs/base/repositories/core/abstract.d.ts +18 -18
  83. package/dist/cjs/base/repositories/core/abstract.d.ts.map +1 -1
  84. package/dist/cjs/base/repositories/core/abstract.js +8 -7
  85. package/dist/cjs/base/repositories/core/abstract.js.map +1 -1
  86. package/dist/cjs/helpers/inversion/common/types/model.d.ts +94 -22
  87. package/dist/cjs/helpers/inversion/common/types/model.d.ts.map +1 -1
  88. package/dist/cjs/helpers/inversion/common/types/model.js.map +1 -1
  89. package/dist/cjs/helpers/inversion/mixins/model.mixin.js +1 -1
  90. package/dist/cjs/helpers/inversion/mixins/model.mixin.js.map +1 -1
  91. package/dist/cjs/helpers/inversion/mixins/repository.mixin.js +1 -1
  92. package/dist/cjs/helpers/inversion/mixins/repository.mixin.js.map +1 -1
  93. package/dist/cjs/repository.d.ts +1 -1
  94. package/dist/cjs/repository.d.ts.map +1 -1
  95. package/dist/cjs/repository.js.map +1 -1
  96. package/dist/esm/base/applications/abstract.js +2 -2
  97. package/dist/esm/base/applications/abstract.js.map +1 -1
  98. package/dist/esm/base/applications/artifact-group.js +1 -1
  99. package/dist/esm/base/applications/artifact-group.js.map +1 -1
  100. package/dist/esm/base/applications/artifact-index.js +11 -11
  101. package/dist/esm/base/applications/artifact-index.js.map +1 -1
  102. package/dist/esm/base/applications/boot-sequence.js +1 -1
  103. package/dist/esm/base/applications/boot-sequence.js.map +1 -1
  104. package/dist/esm/base/applications/cors.d.ts +13 -0
  105. package/dist/esm/base/applications/cors.d.ts.map +1 -0
  106. package/dist/esm/base/applications/cors.js +39 -0
  107. package/dist/esm/base/applications/cors.js.map +1 -0
  108. package/dist/esm/base/applications/deprecations.d.ts +10 -0
  109. package/dist/esm/base/applications/deprecations.d.ts.map +1 -0
  110. package/dist/esm/base/applications/deprecations.js +19 -0
  111. package/dist/esm/base/applications/deprecations.js.map +1 -0
  112. package/dist/esm/base/applications/rest.d.ts.map +1 -1
  113. package/dist/esm/base/applications/rest.js +11 -5
  114. package/dist/esm/base/applications/rest.js.map +1 -1
  115. package/dist/esm/base/auth/authenticate/common/codecs.js +2 -2
  116. package/dist/esm/base/auth/authenticate/common/codecs.js.map +1 -1
  117. package/dist/esm/base/auth/authenticate/providers/authentication.provider.js +1 -1
  118. package/dist/esm/base/auth/authenticate/providers/authentication.provider.js.map +1 -1
  119. package/dist/esm/base/auth/authenticate/strategies/strategy-registry.js +1 -1
  120. package/dist/esm/base/auth/authenticate/strategies/strategy-registry.js.map +1 -1
  121. package/dist/esm/base/auth/authorize/builders/grant.builder.js +12 -12
  122. package/dist/esm/base/auth/authorize/builders/grant.builder.js.map +1 -1
  123. package/dist/esm/base/auth/authorize/builders/permission.builder.js +1 -1
  124. package/dist/esm/base/auth/authorize/builders/permission.builder.js.map +1 -1
  125. package/dist/esm/base/auth/authorize/builders/policy.builder.js +1 -1
  126. package/dist/esm/base/auth/authorize/builders/policy.builder.js.map +1 -1
  127. package/dist/esm/base/auth/authorize/common/constants/authorization.d.ts.map +1 -1
  128. package/dist/esm/base/auth/authorize/common/constants/authorization.js +2 -2
  129. package/dist/esm/base/auth/authorize/common/constants/authorization.js.map +1 -1
  130. package/dist/esm/base/auth/authorize/enforcers/enforcer-registry.js +1 -1
  131. package/dist/esm/base/auth/authorize/enforcers/enforcer-registry.js.map +1 -1
  132. package/dist/esm/base/auth/authorize/providers/authorization.provider.js +3 -3
  133. package/dist/esm/base/auth/authorize/providers/authorization.provider.js.map +1 -1
  134. package/dist/esm/base/controllers/factory/authorize-guard.d.ts +19 -0
  135. package/dist/esm/base/controllers/factory/authorize-guard.d.ts.map +1 -0
  136. package/dist/esm/base/controllers/factory/authorize-guard.js +56 -0
  137. package/dist/esm/base/controllers/factory/authorize-guard.js.map +1 -0
  138. package/dist/esm/base/controllers/factory/controller.d.ts +2 -2
  139. package/dist/esm/base/controllers/factory/controller.d.ts.map +1 -1
  140. package/dist/esm/base/controllers/factory/controller.js +9 -0
  141. package/dist/esm/base/controllers/factory/controller.js.map +1 -1
  142. package/dist/esm/base/controllers/factory/crud/abstract.d.ts +1 -1
  143. package/dist/esm/base/controllers/factory/crud/abstract.d.ts.map +1 -1
  144. package/dist/esm/base/controllers/factory/crud/abstract.js.map +1 -1
  145. package/dist/esm/base/controllers/factory/definition.js +1 -1
  146. package/dist/esm/base/controllers/factory/definition.js.map +1 -1
  147. package/dist/esm/base/controllers/rest/extras.js +5 -5
  148. package/dist/esm/base/controllers/rest/extras.js.map +1 -1
  149. package/dist/esm/base/metadata/injectable.js +1 -1
  150. package/dist/esm/base/metadata/injectable.js.map +1 -1
  151. package/dist/esm/base/metadata/model-settings.d.ts +21 -0
  152. package/dist/esm/base/metadata/model-settings.d.ts.map +1 -0
  153. package/dist/esm/base/metadata/model-settings.js +73 -0
  154. package/dist/esm/base/metadata/model-settings.js.map +1 -0
  155. package/dist/esm/base/metadata/persistents.d.ts +1 -1
  156. package/dist/esm/base/metadata/persistents.d.ts.map +1 -1
  157. package/dist/esm/base/metadata/persistents.js +24 -12
  158. package/dist/esm/base/metadata/persistents.js.map +1 -1
  159. package/dist/esm/base/metadata/routes/controller.js +1 -1
  160. package/dist/esm/base/metadata/routes/controller.js.map +1 -1
  161. package/dist/esm/base/middlewares/app-error/app-error.middleware.js +3 -3
  162. package/dist/esm/base/middlewares/app-error/app-error.middleware.js.map +1 -1
  163. package/dist/esm/base/middlewares/app-error/zod.handler.js +2 -2
  164. package/dist/esm/base/middlewares/app-error/zod.handler.js.map +1 -1
  165. package/dist/esm/base/middlewares/form-body/form-body.middleware.js +2 -2
  166. package/dist/esm/base/middlewares/form-body/form-body.middleware.js.map +1 -1
  167. package/dist/esm/base/middlewares/not-found/not-found.middleware.js.map +1 -1
  168. package/dist/esm/base/models/common/utilities.js +1 -1
  169. package/dist/esm/base/models/common/utilities.js.map +1 -1
  170. package/dist/esm/base/repositories/common/constants.d.ts +18 -1
  171. package/dist/esm/base/repositories/common/constants.d.ts.map +1 -1
  172. package/dist/esm/base/repositories/common/constants.js +20 -1
  173. package/dist/esm/base/repositories/common/constants.js.map +1 -1
  174. package/dist/esm/base/repositories/common/types/contracts.d.ts +17 -17
  175. package/dist/esm/base/repositories/common/types/contracts.d.ts.map +1 -1
  176. package/dist/esm/base/repositories/common/types/contracts.js.map +1 -1
  177. package/dist/esm/base/repositories/core/abstract.d.ts +18 -18
  178. package/dist/esm/base/repositories/core/abstract.d.ts.map +1 -1
  179. package/dist/esm/base/repositories/core/abstract.js +8 -7
  180. package/dist/esm/base/repositories/core/abstract.js.map +1 -1
  181. package/dist/esm/helpers/inversion/common/types/model.d.ts +94 -22
  182. package/dist/esm/helpers/inversion/common/types/model.d.ts.map +1 -1
  183. package/dist/esm/helpers/inversion/common/types/model.js.map +1 -1
  184. package/dist/esm/helpers/inversion/mixins/model.mixin.js +1 -1
  185. package/dist/esm/helpers/inversion/mixins/model.mixin.js.map +1 -1
  186. package/dist/esm/helpers/inversion/mixins/repository.mixin.js +1 -1
  187. package/dist/esm/helpers/inversion/mixins/repository.mixin.js.map +1 -1
  188. package/dist/esm/repository.d.ts +1 -1
  189. package/dist/esm/repository.d.ts.map +1 -1
  190. package/dist/esm/repository.js.map +1 -1
  191. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"model.js","sourceRoot":"","sources":["../../../../../../src/helpers/inversion/common/types/model.ts"],"names":[],"mappings":"","sourcesContent":["import type { AbstractEntity } from '@/base/models';\nimport type {\n ScopeFilters,\n TFilter,\n TScopeFilterMissingBehavior,\n TWhere,\n} from '@/base/repositories';\nimport type { TClass, TNullable, TValueOrResolver } from '@venizia/ignis-helpers/common';\nimport type { IArtifactRegistrationOptions } from './artifact';\n\nexport interface IModelAuthorizeSettings {\n /** The authorization principal name (resource/subject) for this model. */\n principal: string;\n /** Extensible - consumers can add any extra authorization metadata. */\n [extra: string | symbol]: any;\n}\n\n/**\n * Row-scope resolver for `@model` settings.scopeFilter - resolved per query, so it can depend on\n * the current request (tenant, org, membership). Framework-internal escape hatches aside, nothing\n * short of removing this setting from the model turns scoping off.\n */\nexport interface IScopeFilterSettings {\n /**\n * Returns the scope `where`; `ScopeFilters.UNRESTRICTED` to apply no scope for THIS call (an\n * internal operator, a caller the application has decided sees everything); or null/undefined\n * when this caller's scope cannot be determined at all.\n */\n resolve: () => TNullable<TWhere> | typeof ScopeFilters.UNRESTRICTED;\n\n /**\n * What `applyScopeFilter` does when `resolve()` returns null/undefined - no request context, no\n * tenant, a background job. Defaults to `deny`: an unresolved scope matches zero rows, never\n * every row. `allow` is an explicit, reviewed opt-out for migrations and background jobs, declared\n * per MODEL - it cannot express a per-USER bypass; use `ScopeFilters.UNRESTRICTED` for that.\n */\n onMissing?: TScopeFilterMissingBehavior;\n}\n\nexport interface IModelSettings {\n /** Properties excluded from all query results at SQL level. */\n hiddenProperties?: string[];\n\n /** Default filter auto-applied to all repository operations. Bypassable via shouldSkipDefaultFilter. */\n defaultFilter?: TFilter;\n\n /**\n * Row scope: ANDed into every read and write whose scope is expressible as a filter clause, and\n * NOT removable by `shouldSkipDefaultFilter`. Resolved per query, so it can depend on the current\n * request. Ownership resolved per row or through a polymorphic reference is NOT expressible here -\n * that check is still the application's to perform.\n *\n * Relational repositories only - a search-backed model (Typesense, Meilisearch) never reads\n * this setting, so mirroring a scoped entity into a search index needs its own query-time scope.\n */\n scopeFilter?: IScopeFilterSettings;\n\n /** Default row limit when a query omits `limit`. Must be a positive integer. Falls back to DEFAULT_LIMIT (10). */\n defaultLimit?: number;\n\n /**\n * Largest `limit` a CALLER may ask for. Must be a positive integer. Falls back to\n * DEFAULT_MAX_LIMIT (1000).\n *\n * Policy, not capacity - the engine's own ceiling sits far above it. The number is chosen so\n * that reaching it means the caller is doing something unusual, and raising it is how a model\n * says so deliberately.\n */\n maxLimit?: number;\n\n /** Authorization settings for this model (principal name, etc.). */\n authorize?: IModelAuthorizeSettings;\n}\n\nexport interface IModelMetadata extends IArtifactRegistrationOptions {\n type: 'entity' | 'view';\n tableName?: string;\n skipMigrate?: boolean;\n settings?: IModelSettings;\n}\n\nexport interface IEntityStatics {\n schema?: unknown;\n relations?: TValueOrResolver<Array<unknown>>;\n}\n\nexport type TModelClass<Model extends AbstractEntity = AbstractEntity> = TClass<Model> &\n IEntityStatics;\n\n/** Decorator target for model classes (supports both strongly typed and ClassDecorator patterns). */\nexport type TDecoratorModelTarget<Model extends AbstractEntity = AbstractEntity> =\n | TModelClass<Model>\n | (Function & IEntityStatics);\n\nexport interface IModelRegistryEntry<Model extends AbstractEntity = AbstractEntity> {\n target: TValueOrResolver<TClass<Model>>;\n metadata: IModelMetadata;\n schema: unknown;\n\n /** Lazy resolver to avoid circular deps. Resolved when DataSource builds schema. */\n relationsResolver?: TValueOrResolver<Array<unknown>>;\n\n /** Cache populated on first buildSchema() call. */\n _builtRelations?: unknown;\n}\n"]}
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../../../../../src/helpers/inversion/common/types/model.ts"],"names":[],"mappings":"","sourcesContent":["import type { AbstractEntity } from '@/base/models';\nimport type {\n ScopeFilters,\n TFilter,\n TScopeFilterMissingBehavior,\n TScopeWriteGuard,\n TWhere,\n} from '@/base/repositories';\nimport type { TClass, TNullable, TValueOrResolver } from '@venizia/ignis-helpers/common';\nimport type { IArtifactRegistrationOptions } from './artifact';\n\nexport interface IModelAuthorizeSettings {\n /** The authorization principal name (resource/subject) for this model. */\n principal: string;\n /** Extensible - consumers can add any extra authorization metadata. */\n [extra: string | symbol]: any;\n}\n\n/** What a restricted caller may write to the scope columns (`@model` settings.access.write). */\nexport interface IModelAccessWriteSettings {\n /**\n * What a create, createAll or an update payload that names a scope column does when its value\n * disagrees with the resolved scope. `reject` (default) refuses the write and writes nothing - for\n * `createAll` not even the valid rows. `assign` also fills a scope column that is ABSENT from a\n * created row, when the scope is a single equality; a value that is present and disagrees is\n * still refused.\n *\n * The scope's columns and allowed values are read from the resolved `where` (equality, `eq`, `inq`\n * and arrays, `and`, and an `or` over one column). Any other shape cannot be checked, and the write\n * is refused with its own message - never skipped. `ScopeFilters.UNRESTRICTED` bypasses the guard\n * too, which is the deliberate way to write across scopes (system scope, an admin role).\n *\n * Not checked: an update that does not name the scope column (the row was already selected through\n * the scoped `where`), and raw statements that bypass the repository.\n */\n mode?: TScopeWriteGuard;\n\n /**\n * `true` lets a restricted caller write `null` to a scope column, or leave it out on create: the\n * row has no owner and is shared. Default `false`, so `null` is refused like any other value\n * outside the scope, even when the resolved scope has a `null` branch (that branch lets the caller\n * READ shared rows, a separate permission). Reads are scoped as before.\n */\n sharedRows?: boolean;\n}\n\n/**\n * Row access for `@model` settings.access - resolved per query, so it can depend on the current\n * request (tenant, org, membership). Framework-internal escape hatches aside, nothing short of\n * removing this setting from the model turns scoping off.\n */\nexport interface IModelAccessSettings {\n /**\n * Returns the scope `where`; `ScopeFilters.UNRESTRICTED` to apply no scope for THIS call (an\n * internal operator, a caller the application has decided sees everything); or null/undefined\n * when this caller's scope cannot be determined at all.\n */\n resolve: () => TNullable<TWhere> | typeof ScopeFilters.UNRESTRICTED;\n\n /**\n * What `applyScopeFilter` does when `resolve()` returns null/undefined - no request context, no\n * tenant, a background job. Defaults to `deny`: an unresolved scope matches zero rows, never\n * every row. `allow` is an explicit, reviewed opt-out for migrations and background jobs, declared\n * per MODEL - it cannot express a per-USER bypass; use `ScopeFilters.UNRESTRICTED` for that.\n */\n onMissing?: TScopeFilterMissingBehavior;\n\n /**\n * The property names the write guard checks. Optional: with none declared the guard checks every\n * column the resolved scope constrains. When declared, each name must exist on the model (checked\n * at boot), and a resolved scope that constrains any other column is refused as unverifiable.\n */\n columns?: string[];\n\n /** What a restricted caller may write to the scope columns. See {@link IModelAccessWriteSettings}. */\n write?: IModelAccessWriteSettings;\n}\n\n/**\n * The old, flat shape of {@link IModelAccessSettings}.\n *\n * @deprecated Use `settings.access` (`writeGuard` is `access.write.mode`, `sharedRows` is\n * `access.write.sharedRows`). Removed in 0.4.3.\n */\nexport interface IScopeFilterSettings {\n resolve: () => TNullable<TWhere> | typeof ScopeFilters.UNRESTRICTED;\n onMissing?: TScopeFilterMissingBehavior;\n writeGuard?: TScopeWriteGuard;\n sharedRows?: boolean;\n columns?: string[];\n}\n\n/** What a query runs with when it names nothing (`@model` settings.query). */\nexport interface IModelQuerySettings {\n /** Default filter auto-applied to all repository operations. Bypassable via shouldSkipDefaultFilter. */\n filter?: TFilter;\n\n limit?: {\n /** Default row limit when a query omits `limit`. Must be a positive integer. Falls back to DEFAULT_LIMIT (10). */\n default?: number;\n\n /**\n * Largest `limit` a CALLER may ask for. Must be a positive integer. Falls back to\n * DEFAULT_MAX_LIMIT (1000).\n *\n * Policy, not capacity - the engine's own ceiling sits far above it. The number is chosen so\n * that reaching it means the caller is doing something unusual, and raising it is how a model\n * says so deliberately.\n */\n max?: number;\n };\n}\n\nexport interface IModelSettings {\n /** Properties excluded from all query results at SQL level. */\n hiddenProperties?: string[];\n\n /** Default filter and limits of a query: `filter`, `limit.default`, `limit.max`. */\n query?: IModelQuerySettings;\n\n /**\n * Row access: the scope ANDed into every read and write whose scope is expressible as a filter\n * clause, NOT removable by `shouldSkipDefaultFilter`, and the guard that holds writes to it.\n * Ownership resolved per row or through a polymorphic reference is NOT expressible here - that\n * check is still the application's to perform.\n *\n * Relational repositories only - a search-backed model (Typesense, Meilisearch) never reads\n * this setting, so mirroring a scoped entity into a search index needs its own query-time scope.\n */\n access?: IModelAccessSettings;\n\n /** Authorization settings for this model (principal name, etc.). */\n authorize?: IModelAuthorizeSettings;\n\n /** @deprecated Use `query.filter`. Removed in 0.4.3. */\n defaultFilter?: TFilter;\n\n /** @deprecated Use `access`. Removed in 0.4.3. */\n scopeFilter?: IScopeFilterSettings;\n\n /** @deprecated Use `query.limit.default`. Removed in 0.4.3. */\n defaultLimit?: number;\n\n /** @deprecated Use `query.limit.max`. Removed in 0.4.3. */\n maxLimit?: number;\n}\n\n/** One deprecated settings key a model still uses, and the key that replaces it. */\nexport interface IDeprecatedModelSetting {\n /** The old key, written as the model wrote it: `defaultFilter`, `scopeFilter.writeGuard`. */\n key: string;\n /** The key that replaces it: `query.filter`, `access.write.mode`. */\n use: string;\n}\n\nexport interface IModelMetadata extends IArtifactRegistrationOptions {\n type: 'entity' | 'view';\n tableName?: string;\n skipMigrate?: boolean;\n\n /** As the `@model` decorator stores it: normalised to the new keys; the deprecated keys are gone. */\n settings?: IModelSettings;\n\n /** Set by the decorator, read by the boot warning; not for application code. */\n deprecatedSettings?: IDeprecatedModelSetting[];\n}\n\nexport interface IEntityStatics {\n schema?: unknown;\n relations?: TValueOrResolver<Array<unknown>>;\n}\n\nexport type TModelClass<Model extends AbstractEntity = AbstractEntity> = TClass<Model> &\n IEntityStatics;\n\n/** Decorator target for model classes (supports both strongly typed and ClassDecorator patterns). */\nexport type TDecoratorModelTarget<Model extends AbstractEntity = AbstractEntity> =\n | TModelClass<Model>\n | (Function & IEntityStatics);\n\nexport interface IModelRegistryEntry<Model extends AbstractEntity = AbstractEntity> {\n target: TValueOrResolver<TClass<Model>>;\n metadata: IModelMetadata;\n schema: unknown;\n\n /** Lazy resolver to avoid circular deps. Resolved when DataSource builds schema. */\n relationsResolver?: TValueOrResolver<Array<unknown>>;\n\n /** Cache populated on first buildSchema() call. */\n _builtRelations?: unknown;\n}\n"]}
@@ -83,7 +83,7 @@ const ModelMetadataMixin = (baseClass) => {
83
83
  getAuthorizeModelPrincipals(opts) {
84
84
  switch (opts.format) {
85
85
  case 'array': {
86
- return collectAuthorizePrincipals({ modelRegistry: this.modelRegistry }).map(item => item.principal);
86
+ return collectAuthorizePrincipals({ modelRegistry: this.modelRegistry }).map((item) => item.principal);
87
87
  }
88
88
  case 'record': {
89
89
  const record = {};
@@ -1 +1 @@
1
- {"version":3,"file":"model.mixin.js","sourceRoot":"","sources":["../../../../../src/helpers/inversion/mixins/model.mixin.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AbstractEntity } from '@/base/models';\nimport type { TMixinTarget } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport type { MetadataRegistry as _MetadataRegistry } from '@venizia/ignis-inversion';\nimport { MetadataKeys } from '../common/keys';\nimport type {\n IModelAuthorizeSettings,\n IModelMetadata,\n IModelRegistryEntry,\n TDecoratorModelTarget,\n TModelClass,\n} from '../common/types';\n\n/** Registered models that declare an authorize setting, in registry order. */\nconst collectAuthorizeEntries = (opts: {\n modelRegistry: Map<string, IModelRegistryEntry>;\n}): Array<{ name: string; authorize: IModelAuthorizeSettings; entry: IModelRegistryEntry }> => {\n const result: Array<{\n name: string;\n authorize: IModelAuthorizeSettings;\n entry: IModelRegistryEntry;\n }> = [];\n\n for (const [name, entry] of opts.modelRegistry) {\n const authorize = entry.metadata.settings?.authorize;\n if (!authorize) {\n continue;\n }\n\n result.push({ name, authorize, entry });\n }\n\n return result;\n};\n\n/** Registered models that declare an authorize principal, in registry order. */\nconst collectAuthorizePrincipals = (opts: {\n modelRegistry: Map<string, IModelRegistryEntry>;\n}): Array<{ name: string; principal: string }> => {\n const result: Array<{ name: string; principal: string }> = [];\n\n for (const [name, entry] of opts.modelRegistry) {\n const principal = entry.metadata.settings?.authorize?.principal;\n if (!principal) {\n continue;\n }\n\n result.push({ name, principal });\n }\n\n return result;\n};\n\nexport const ModelMetadataMixin = <BaseClass extends TMixinTarget<_MetadataRegistry>>(\n baseClass: BaseClass,\n) => {\n return class extends baseClass {\n modelRegistry: Map<string, IModelRegistryEntry>;\n modelsBySchema: WeakMap<object, IModelRegistryEntry>;\n\n setModelMetadata<Target extends object = object>(opts: {\n target: Target;\n metadata: IModelMetadata;\n }): void {\n const { target, metadata } = opts;\n Reflect.defineMetadata(MetadataKeys.MODEL, metadata, target);\n }\n\n getModelMetadata<Target extends object = object>(opts: {\n target: Target;\n }): IModelMetadata | undefined {\n const { target } = opts;\n return Reflect.getMetadata(MetadataKeys.MODEL, target);\n }\n\n /** Registers a model (called by @model) - relations are stored as a resolver, not resolved immediately, so circular references between models resolve lazily in buildSchema(). */\n registerModel<Model extends AbstractEntity = AbstractEntity>(opts: {\n target: TDecoratorModelTarget<Model>;\n metadata: IModelMetadata;\n }) {\n const { target, metadata } = opts;\n\n // Decorator target is always a class constructor at runtime\n const modelClass = target as TModelClass<Model>;\n\n // Table name precedence: explicit metadata > static TABLE_NAME > class name. TABLE_NAME is deliberately outside IEntityStatics (not part of the neutral contract) but still honored here via a local cast.\n const tableName =\n [metadata.tableName, (modelClass as { TABLE_NAME?: string }).TABLE_NAME].find(Boolean) ??\n modelClass.name;\n\n // Resolver, not resolved value - executed lazily in buildSchema() once all models are loaded\n const relationsResolver = modelClass.relations;\n\n const entry: IModelRegistryEntry = {\n target: modelClass,\n metadata,\n schema: modelClass.schema,\n relationsResolver,\n };\n this.modelRegistry.set(tableName, entry);\n\n const { schema } = modelClass;\n if (schema && typeof schema === 'object') {\n const claimed = this.modelsBySchema.get(schema);\n if (claimed && claimed.target !== modelClass) {\n this.modelsBySchema.delete(schema);\n } else {\n this.modelsBySchema.set(schema, entry);\n }\n }\n\n // Also mirrored via Reflect so plain metadata lookups (getModelMetadata) still see it\n this.setModelMetadata({ target, metadata });\n }\n\n getModelEntry(opts: { name: string }): IModelRegistryEntry | undefined {\n return this.modelRegistry.get(opts.name);\n }\n\n getModelEntryBySchema(opts: { schema: object }): IModelRegistryEntry | undefined {\n return this.modelsBySchema.get(opts.schema);\n }\n\n getAllModels(): Map<string, IModelRegistryEntry> {\n return this.modelRegistry;\n }\n\n getModelAuthorizeSettings(opts: { name: string }): IModelAuthorizeSettings | undefined {\n const entry = this.getModelEntry(opts);\n return entry?.metadata?.settings?.authorize;\n }\n\n /** Authorization principals across all models that declare an authorize setting. */\n getAuthorizeModelPrincipals(opts: { format: 'array' }): string[];\n getAuthorizeModelPrincipals(opts: { format: 'record' }): Record<string, string>;\n getAuthorizeModelPrincipals(opts: { format: 'array' | 'record' }) {\n switch (opts.format) {\n case 'array': {\n return collectAuthorizePrincipals({ modelRegistry: this.modelRegistry }).map(\n item => item.principal,\n );\n }\n case 'record': {\n const record: Record<string, string> = {};\n\n const authorizePrincipals = collectAuthorizePrincipals({\n modelRegistry: this.modelRegistry,\n });\n for (const item of authorizePrincipals) {\n record[item.name] = item.principal;\n }\n\n return record;\n }\n default: {\n throw getError({\n message: `[getAuthorizeModelPrincipals] Invalid format | format: ${opts.format} | valid: array, record`,\n });\n }\n }\n }\n\n getAuthorizeModelSettings(opts: { format: 'array' }): Array<{\n name: string;\n authorize: IModelAuthorizeSettings;\n entry: IModelRegistryEntry;\n }>;\n getAuthorizeModelSettings(opts: {\n format: 'record';\n }): Record<string, { authorize: IModelAuthorizeSettings; entry: IModelRegistryEntry }>;\n getAuthorizeModelSettings(opts: { format: 'array' | 'record' }) {\n switch (opts.format) {\n case 'array': {\n return collectAuthorizeEntries({ modelRegistry: this.modelRegistry });\n }\n case 'record': {\n const record: Record<\n string,\n { authorize: IModelAuthorizeSettings; entry: IModelRegistryEntry }\n > = {};\n\n const authorizeEntries = collectAuthorizeEntries({ modelRegistry: this.modelRegistry });\n for (const item of authorizeEntries) {\n record[item.name] = { authorize: item.authorize, entry: item.entry };\n }\n\n return record;\n }\n default: {\n throw getError({\n message: `[getAuthorizeModelSettings] Invalid format | format: ${opts.format} | valid: array, record`,\n });\n }\n }\n }\n };\n};\n"]}
1
+ {"version":3,"file":"model.mixin.js","sourceRoot":"","sources":["../../../../../src/helpers/inversion/mixins/model.mixin.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AbstractEntity } from '@/base/models';\nimport type { TMixinTarget } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport type { MetadataRegistry as _MetadataRegistry } from '@venizia/ignis-inversion';\nimport { MetadataKeys } from '../common/keys';\nimport type {\n IModelAuthorizeSettings,\n IModelMetadata,\n IModelRegistryEntry,\n TDecoratorModelTarget,\n TModelClass,\n} from '../common/types';\n\n/** Registered models that declare an authorize setting, in registry order. */\nconst collectAuthorizeEntries = (opts: {\n modelRegistry: Map<string, IModelRegistryEntry>;\n}): Array<{ name: string; authorize: IModelAuthorizeSettings; entry: IModelRegistryEntry }> => {\n const result: Array<{\n name: string;\n authorize: IModelAuthorizeSettings;\n entry: IModelRegistryEntry;\n }> = [];\n\n for (const [name, entry] of opts.modelRegistry) {\n const authorize = entry.metadata.settings?.authorize;\n if (!authorize) {\n continue;\n }\n\n result.push({ name, authorize, entry });\n }\n\n return result;\n};\n\n/** Registered models that declare an authorize principal, in registry order. */\nconst collectAuthorizePrincipals = (opts: {\n modelRegistry: Map<string, IModelRegistryEntry>;\n}): Array<{ name: string; principal: string }> => {\n const result: Array<{ name: string; principal: string }> = [];\n\n for (const [name, entry] of opts.modelRegistry) {\n const principal = entry.metadata.settings?.authorize?.principal;\n if (!principal) {\n continue;\n }\n\n result.push({ name, principal });\n }\n\n return result;\n};\n\nexport const ModelMetadataMixin = <BaseClass extends TMixinTarget<_MetadataRegistry>>(\n baseClass: BaseClass,\n) => {\n return class extends baseClass {\n modelRegistry: Map<string, IModelRegistryEntry>;\n modelsBySchema: WeakMap<object, IModelRegistryEntry>;\n\n setModelMetadata<Target extends object = object>(opts: {\n target: Target;\n metadata: IModelMetadata;\n }): void {\n const { target, metadata } = opts;\n Reflect.defineMetadata(MetadataKeys.MODEL, metadata, target);\n }\n\n getModelMetadata<Target extends object = object>(opts: {\n target: Target;\n }): IModelMetadata | undefined {\n const { target } = opts;\n return Reflect.getMetadata(MetadataKeys.MODEL, target);\n }\n\n /** Registers a model (called by @model) - relations are stored as a resolver, not resolved immediately, so circular references between models resolve lazily in buildSchema(). */\n registerModel<Model extends AbstractEntity = AbstractEntity>(opts: {\n target: TDecoratorModelTarget<Model>;\n metadata: IModelMetadata;\n }) {\n const { target, metadata } = opts;\n\n // Decorator target is always a class constructor at runtime\n const modelClass = target as TModelClass<Model>;\n\n // Table name precedence: explicit metadata > static TABLE_NAME > class name. TABLE_NAME is deliberately outside IEntityStatics (not part of the neutral contract) but still honored here via a local cast.\n const tableName =\n [metadata.tableName, (modelClass as { TABLE_NAME?: string }).TABLE_NAME].find(Boolean) ??\n modelClass.name;\n\n // Resolver, not resolved value - executed lazily in buildSchema() once all models are loaded\n const relationsResolver = modelClass.relations;\n\n const entry: IModelRegistryEntry = {\n target: modelClass,\n metadata,\n schema: modelClass.schema,\n relationsResolver,\n };\n this.modelRegistry.set(tableName, entry);\n\n const { schema } = modelClass;\n if (schema && typeof schema === 'object') {\n const claimed = this.modelsBySchema.get(schema);\n if (claimed && claimed.target !== modelClass) {\n this.modelsBySchema.delete(schema);\n } else {\n this.modelsBySchema.set(schema, entry);\n }\n }\n\n // Also mirrored via Reflect so plain metadata lookups (getModelMetadata) still see it\n this.setModelMetadata({ target, metadata });\n }\n\n getModelEntry(opts: { name: string }): IModelRegistryEntry | undefined {\n return this.modelRegistry.get(opts.name);\n }\n\n getModelEntryBySchema(opts: { schema: object }): IModelRegistryEntry | undefined {\n return this.modelsBySchema.get(opts.schema);\n }\n\n getAllModels(): Map<string, IModelRegistryEntry> {\n return this.modelRegistry;\n }\n\n getModelAuthorizeSettings(opts: { name: string }): IModelAuthorizeSettings | undefined {\n const entry = this.getModelEntry(opts);\n return entry?.metadata?.settings?.authorize;\n }\n\n /** Authorization principals across all models that declare an authorize setting. */\n getAuthorizeModelPrincipals(opts: { format: 'array' }): string[];\n getAuthorizeModelPrincipals(opts: { format: 'record' }): Record<string, string>;\n getAuthorizeModelPrincipals(opts: { format: 'array' | 'record' }) {\n switch (opts.format) {\n case 'array': {\n return collectAuthorizePrincipals({ modelRegistry: this.modelRegistry }).map(\n (item) => item.principal,\n );\n }\n case 'record': {\n const record: Record<string, string> = {};\n\n const authorizePrincipals = collectAuthorizePrincipals({\n modelRegistry: this.modelRegistry,\n });\n for (const item of authorizePrincipals) {\n record[item.name] = item.principal;\n }\n\n return record;\n }\n default: {\n throw getError({\n message: `[getAuthorizeModelPrincipals] Invalid format | format: ${opts.format} | valid: array, record`,\n });\n }\n }\n }\n\n getAuthorizeModelSettings(opts: { format: 'array' }): Array<{\n name: string;\n authorize: IModelAuthorizeSettings;\n entry: IModelRegistryEntry;\n }>;\n getAuthorizeModelSettings(opts: {\n format: 'record';\n }): Record<string, { authorize: IModelAuthorizeSettings; entry: IModelRegistryEntry }>;\n getAuthorizeModelSettings(opts: { format: 'array' | 'record' }) {\n switch (opts.format) {\n case 'array': {\n return collectAuthorizeEntries({ modelRegistry: this.modelRegistry });\n }\n case 'record': {\n const record: Record<\n string,\n { authorize: IModelAuthorizeSettings; entry: IModelRegistryEntry }\n > = {};\n\n const authorizeEntries = collectAuthorizeEntries({ modelRegistry: this.modelRegistry });\n for (const item of authorizeEntries) {\n record[item.name] = { authorize: item.authorize, entry: item.entry };\n }\n\n return record;\n }\n default: {\n throw getError({\n message: `[getAuthorizeModelSettings] Invalid format | format: ${opts.format} | valid: array, record`,\n });\n }\n }\n }\n };\n};\n"]}
@@ -90,7 +90,7 @@ const RepositoryMetadataMixin = (baseClass) => {
90
90
  getModels(opts) {
91
91
  const modelClasses = this.getDataSourceModelClasses({ dataSource: opts.dataSource });
92
92
  const rs = Array.from(modelClasses)
93
- .map(modelClass => {
93
+ .map((modelClass) => {
94
94
  // Read straight off the class: a class -> name -> modelRegistry round-trip collapses two
95
95
  // same-named models onto one entry, silently swapping schemas. `modelRegistry` stays
96
96
  // name-keyed for the by-name APIs that need it.
@@ -1 +1 @@
1
- {"version":3,"file":"repository.mixin.js","sourceRoot":"","sources":["../../../../../src/helpers/inversion/mixins/repository.mixin.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IDataSource } from '@/base/datasources';\nimport type { AbstractEntity } from '@/base/models';\nimport type { AnyType, TClass, TMixinTarget } from '@venizia/ignis-helpers/common';\nimport { resolveValue } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport type { MetadataRegistry as _MetadataRegistry } from '@venizia/ignis-inversion';\nimport { MetadataKeys } from '../common/keys';\nimport { RelationBuilderRegistry } from '../common/relation-builder';\nimport type {\n IModelMetadata,\n IModelRegistryEntry,\n IRepositoryBinding,\n IResolvedRepositoryMetadata,\n TRepositoryMetadata,\n} from '../common/types';\n\nexport const RepositoryMetadataMixin = <\n BaseClass extends TMixinTarget<\n _MetadataRegistry & {\n modelRegistry: Map<string, IModelRegistryEntry>;\n getModelMetadata(opts: { target: object }): IModelMetadata | undefined;\n }\n >,\n>(\n baseClass: BaseClass,\n) => {\n return class extends baseClass {\n /** By repository class name, for the by-name API. Two classes may share a name; `repositoryBindingsByClass` cannot confuse them. */\n repositoryBindings: Map<string, IRepositoryBinding<AbstractEntity>>;\n\n /** By repository class: a minified build renames classes, and two chunks may give two of them one name. */\n repositoryBindingsByClass: Map<Function, IRepositoryBinding<AbstractEntity>>;\n\n /**\n * The model classes each datasource owns, keyed by the datasource class - or by the string a\n * repository named it with (`dataSource: 'PgDataSource'`), which only a class of that name\n * can match. Never by class name alone: a minified build gives two datasources one name.\n */\n datasourceModels: Map<string | Function, Set<TClass<AnyType>>>;\n\n setRepositoryMetadata<\n Target extends object = object,\n Model extends AbstractEntity = AbstractEntity,\n DataSource extends IDataSource = IDataSource,\n >(opts: {\n target: Target;\n metadata: TRepositoryMetadata<Model, DataSource> & {\n _resolved?: IResolvedRepositoryMetadata<Model, DataSource>;\n };\n }): void {\n const { target, metadata } = opts;\n Reflect.defineMetadata(MetadataKeys.REPOSITORY, metadata, target);\n }\n\n getRepositoryMetadata<Target extends object = object>(opts: {\n target: Target;\n }): (TRepositoryMetadata & { _resolved?: IResolvedRepositoryMetadata }) | undefined {\n const { target } = opts;\n return Reflect.getMetadata(MetadataKeys.REPOSITORY, target);\n }\n\n /** Registers a repository binding (called by @repository) linking a repository to its model + datasource. */\n registerRepositoryBinding<\n Model extends AbstractEntity = AbstractEntity,\n DataSource extends IDataSource = IDataSource,\n >(opts: IRepositoryBinding<Model, DataSource>) {\n // Every member of the binding may be a resolver, the escape hatch for circular imports.\n // Reading `.name` off the resolver keys the registry by the arrow's inferred name, and the\n // datasource then silently discovers no schema.\n const repositoryClass = resolveValue({ value: opts.repository });\n this.repositoryBindings.set(repositoryClass.name, opts);\n this.repositoryBindingsByClass.set(repositoryClass, opts);\n\n const dataSourceRef = resolveValue({ value: opts.dataSource });\n const modelClass = resolveValue({ value: opts.model });\n\n if (!this.datasourceModels.has(dataSourceRef)) {\n this.datasourceModels.set(dataSourceRef, new Set());\n }\n\n this.datasourceModels.get(dataSourceRef)!.add(modelClass);\n }\n\n /** By class, walking up to the nearest decorated parent; by name only for callers holding a name. */\n getRepositoryBinding(\n opts: { target: Function } | { name: string },\n ): IRepositoryBinding<AbstractEntity> | undefined {\n if ('name' in opts) {\n return this.repositoryBindings.get(opts.name);\n }\n\n for (\n let current: Function | null = opts.target;\n current && current !== Function.prototype;\n current = Object.getPrototypeOf(current)\n ) {\n const binding = this.repositoryBindingsByClass.get(current);\n if (binding) {\n return binding;\n }\n }\n\n return undefined;\n }\n\n /** A class finds what was registered under it, and under a string equal to its name. */\n getDataSourceModelClasses(opts: {\n dataSource: string | TClass<IDataSource>;\n }): Set<TClass<AnyType>> {\n const { dataSource } = opts;\n\n if (typeof dataSource === 'string') {\n return this.datasourceModels.get(dataSource) ?? new Set();\n }\n\n return new Set([\n ...(this.datasourceModels.get(dataSource) ?? []),\n ...(this.datasourceModels.get(dataSource.name) ?? []),\n ]);\n }\n\n /**\n * Resolves and caches relations for a model entry - called lazily from buildSchema() so that\n * every `@model` class is registered first, which avoids circular-dependency ordering issues.\n * @internal\n */\n resolveModelRelations(modelMeta: IModelRegistryEntry): unknown {\n if (modelMeta._builtRelations !== undefined) {\n return modelMeta._builtRelations;\n }\n\n if (!modelMeta.relationsResolver) {\n return undefined;\n }\n\n const relations = resolveValue({ value: modelMeta.relationsResolver });\n\n if (!relations || !modelMeta.schema) {\n return undefined;\n }\n\n const builder = RelationBuilderRegistry.resolve();\n\n // Relations were declared but no connector installed a builder - silently dropping them\n // would surface much later as an empty `with` clause.\n if (!builder) {\n throw getError({\n message: `[RepositoryMetadataMixin][resolveModelRelations] Model declares relations but no relation builder is registered | Import the relational connector so it installs one`,\n });\n }\n\n const builtRelations = builder({ source: modelMeta.schema, relations });\n\n modelMeta._builtRelations = builtRelations?.relations;\n return modelMeta._builtRelations;\n }\n\n /**\n * Models registered for a datasource, relations resolved lazily. `schema`/`relations` stay\n * `unknown` - the registry is shared across connectors, so each connector narrows at its call\n * site.\n */\n getModels(opts: { dataSource: string | TClass<IDataSource> }): Array<{\n tableName: string;\n schema: unknown;\n relations?: unknown;\n }> {\n const modelClasses = this.getDataSourceModelClasses({ dataSource: opts.dataSource });\n\n const rs = Array.from(modelClasses)\n .map(modelClass => {\n // Read straight off the class: a class -> name -> modelRegistry round-trip collapses two\n // same-named models onto one entry, silently swapping schemas. `modelRegistry` stays\n // name-keyed for the by-name APIs that need it.\n const entry: IModelRegistryEntry = {\n target: modelClass as AnyType,\n metadata:\n this.getModelMetadata({ target: modelClass }) ?? ({ settings: {} } as AnyType),\n schema: (modelClass as AnyType).schema,\n relationsResolver: (modelClass as AnyType).relations,\n };\n\n if (entry.schema === undefined) {\n return null;\n }\n\n return {\n tableName: this.resolveModelKey({ modelClass }),\n schema: entry.schema,\n relations: this.resolveModelRelations(entry),\n };\n })\n .filter((item): item is NonNullable<typeof item> => {\n return item !== undefined && item !== null;\n });\n\n return rs;\n }\n\n /**\n * Like getModels but returns only resolved model classes - used by BaseSearchDataSource, which\n * has no pgTable to resolve.\n */\n getModelClasses(opts: { dataSource: string | TClass<IDataSource> }): Array<TClass<unknown>> {\n // Straight from the stored class refs: a name round-trip through the shared modelRegistry\n // would hand back whichever same-named class registered last.\n return Array.from(this.getDataSourceModelClasses({ dataSource: opts.dataSource }));\n }\n\n /** The key a model occupies in `modelRegistry` - its table name, or its class name when it has none. */\n resolveModelKey(opts: { modelClass: TClass<AnyType> }): string {\n const { modelClass } = opts;\n const modelMetadata = this.getModelMetadata({ target: modelClass });\n\n return (\n [modelMetadata?.tableName, (modelClass as AnyType).TABLE_NAME].find(Boolean) ??\n modelClass.name\n );\n }\n\n /** Assembles table schemas + relations for a datasource's registered models. */\n buildSchema(opts: { dataSource: string | TClass<IDataSource> }): {\n schema: Record<string, unknown>;\n relations: Record<string, unknown>;\n } {\n const { dataSource } = opts;\n const models = this.getModels({ dataSource });\n\n const rs: {\n schema: Record<string, unknown>;\n relations: Record<string, unknown>;\n } = { schema: {}, relations: {} };\n\n for (const model of models) {\n if (model.schema) {\n rs.schema[model.tableName] = model.schema;\n }\n\n if (model.relations) {\n rs.relations[`${model.tableName}Relations`] = model.relations;\n }\n }\n\n return rs;\n }\n\n hasModels(opts: { dataSource: string | TClass<IDataSource> }): boolean {\n return this.getDataSourceModelClasses({ dataSource: opts.dataSource }).size > 0;\n }\n };\n};\n"]}
1
+ {"version":3,"file":"repository.mixin.js","sourceRoot":"","sources":["../../../../../src/helpers/inversion/mixins/repository.mixin.ts"],"names":[],"mappings":"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","sourcesContent":["import type { IDataSource } from '@/base/datasources';\nimport type { AbstractEntity } from '@/base/models';\nimport type { AnyType, TClass, TMixinTarget } from '@venizia/ignis-helpers/common';\nimport { resolveValue } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport type { MetadataRegistry as _MetadataRegistry } from '@venizia/ignis-inversion';\nimport { MetadataKeys } from '../common/keys';\nimport { RelationBuilderRegistry } from '../common/relation-builder';\nimport type {\n IModelMetadata,\n IModelRegistryEntry,\n IRepositoryBinding,\n IResolvedRepositoryMetadata,\n TRepositoryMetadata,\n} from '../common/types';\n\nexport const RepositoryMetadataMixin = <\n BaseClass extends TMixinTarget<\n _MetadataRegistry & {\n modelRegistry: Map<string, IModelRegistryEntry>;\n getModelMetadata(opts: { target: object }): IModelMetadata | undefined;\n }\n >,\n>(\n baseClass: BaseClass,\n) => {\n return class extends baseClass {\n /** By repository class name, for the by-name API. Two classes may share a name; `repositoryBindingsByClass` cannot confuse them. */\n repositoryBindings: Map<string, IRepositoryBinding<AbstractEntity>>;\n\n /** By repository class: a minified build renames classes, and two chunks may give two of them one name. */\n repositoryBindingsByClass: Map<Function, IRepositoryBinding<AbstractEntity>>;\n\n /**\n * The model classes each datasource owns, keyed by the datasource class - or by the string a\n * repository named it with (`dataSource: 'PgDataSource'`), which only a class of that name\n * can match. Never by class name alone: a minified build gives two datasources one name.\n */\n datasourceModels: Map<string | Function, Set<TClass<AnyType>>>;\n\n setRepositoryMetadata<\n Target extends object = object,\n Model extends AbstractEntity = AbstractEntity,\n DataSource extends IDataSource = IDataSource,\n >(opts: {\n target: Target;\n metadata: TRepositoryMetadata<Model, DataSource> & {\n _resolved?: IResolvedRepositoryMetadata<Model, DataSource>;\n };\n }): void {\n const { target, metadata } = opts;\n Reflect.defineMetadata(MetadataKeys.REPOSITORY, metadata, target);\n }\n\n getRepositoryMetadata<Target extends object = object>(opts: {\n target: Target;\n }): (TRepositoryMetadata & { _resolved?: IResolvedRepositoryMetadata }) | undefined {\n const { target } = opts;\n return Reflect.getMetadata(MetadataKeys.REPOSITORY, target);\n }\n\n /** Registers a repository binding (called by @repository) linking a repository to its model + datasource. */\n registerRepositoryBinding<\n Model extends AbstractEntity = AbstractEntity,\n DataSource extends IDataSource = IDataSource,\n >(opts: IRepositoryBinding<Model, DataSource>) {\n // Every member of the binding may be a resolver, the escape hatch for circular imports.\n // Reading `.name` off the resolver keys the registry by the arrow's inferred name, and the\n // datasource then silently discovers no schema.\n const repositoryClass = resolveValue({ value: opts.repository });\n this.repositoryBindings.set(repositoryClass.name, opts);\n this.repositoryBindingsByClass.set(repositoryClass, opts);\n\n const dataSourceRef = resolveValue({ value: opts.dataSource });\n const modelClass = resolveValue({ value: opts.model });\n\n if (!this.datasourceModels.has(dataSourceRef)) {\n this.datasourceModels.set(dataSourceRef, new Set());\n }\n\n this.datasourceModels.get(dataSourceRef)!.add(modelClass);\n }\n\n /** By class, walking up to the nearest decorated parent; by name only for callers holding a name. */\n getRepositoryBinding(\n opts: { target: Function } | { name: string },\n ): IRepositoryBinding<AbstractEntity> | undefined {\n if ('name' in opts) {\n return this.repositoryBindings.get(opts.name);\n }\n\n for (\n let current: Function | null = opts.target;\n current && current !== Function.prototype;\n current = Object.getPrototypeOf(current)\n ) {\n const binding = this.repositoryBindingsByClass.get(current);\n if (binding) {\n return binding;\n }\n }\n\n return undefined;\n }\n\n /** A class finds what was registered under it, and under a string equal to its name. */\n getDataSourceModelClasses(opts: {\n dataSource: string | TClass<IDataSource>;\n }): Set<TClass<AnyType>> {\n const { dataSource } = opts;\n\n if (typeof dataSource === 'string') {\n return this.datasourceModels.get(dataSource) ?? new Set();\n }\n\n return new Set([\n ...(this.datasourceModels.get(dataSource) ?? []),\n ...(this.datasourceModels.get(dataSource.name) ?? []),\n ]);\n }\n\n /**\n * Resolves and caches relations for a model entry - called lazily from buildSchema() so that\n * every `@model` class is registered first, which avoids circular-dependency ordering issues.\n * @internal\n */\n resolveModelRelations(modelMeta: IModelRegistryEntry): unknown {\n if (modelMeta._builtRelations !== undefined) {\n return modelMeta._builtRelations;\n }\n\n if (!modelMeta.relationsResolver) {\n return undefined;\n }\n\n const relations = resolveValue({ value: modelMeta.relationsResolver });\n\n if (!relations || !modelMeta.schema) {\n return undefined;\n }\n\n const builder = RelationBuilderRegistry.resolve();\n\n // Relations were declared but no connector installed a builder - silently dropping them\n // would surface much later as an empty `with` clause.\n if (!builder) {\n throw getError({\n message: `[RepositoryMetadataMixin][resolveModelRelations] Model declares relations but no relation builder is registered | Import the relational connector so it installs one`,\n });\n }\n\n const builtRelations = builder({ source: modelMeta.schema, relations });\n\n modelMeta._builtRelations = builtRelations?.relations;\n return modelMeta._builtRelations;\n }\n\n /**\n * Models registered for a datasource, relations resolved lazily. `schema`/`relations` stay\n * `unknown` - the registry is shared across connectors, so each connector narrows at its call\n * site.\n */\n getModels(opts: { dataSource: string | TClass<IDataSource> }): Array<{\n tableName: string;\n schema: unknown;\n relations?: unknown;\n }> {\n const modelClasses = this.getDataSourceModelClasses({ dataSource: opts.dataSource });\n\n const rs = Array.from(modelClasses)\n .map((modelClass) => {\n // Read straight off the class: a class -> name -> modelRegistry round-trip collapses two\n // same-named models onto one entry, silently swapping schemas. `modelRegistry` stays\n // name-keyed for the by-name APIs that need it.\n const entry: IModelRegistryEntry = {\n target: modelClass as AnyType,\n metadata:\n this.getModelMetadata({ target: modelClass }) ?? ({ settings: {} } as AnyType),\n schema: (modelClass as AnyType).schema,\n relationsResolver: (modelClass as AnyType).relations,\n };\n\n if (entry.schema === undefined) {\n return null;\n }\n\n return {\n tableName: this.resolveModelKey({ modelClass }),\n schema: entry.schema,\n relations: this.resolveModelRelations(entry),\n };\n })\n .filter((item): item is NonNullable<typeof item> => {\n return item !== undefined && item !== null;\n });\n\n return rs;\n }\n\n /**\n * Like getModels but returns only resolved model classes - used by BaseSearchDataSource, which\n * has no pgTable to resolve.\n */\n getModelClasses(opts: { dataSource: string | TClass<IDataSource> }): Array<TClass<unknown>> {\n // Straight from the stored class refs: a name round-trip through the shared modelRegistry\n // would hand back whichever same-named class registered last.\n return Array.from(this.getDataSourceModelClasses({ dataSource: opts.dataSource }));\n }\n\n /** The key a model occupies in `modelRegistry` - its table name, or its class name when it has none. */\n resolveModelKey(opts: { modelClass: TClass<AnyType> }): string {\n const { modelClass } = opts;\n const modelMetadata = this.getModelMetadata({ target: modelClass });\n\n return (\n [modelMetadata?.tableName, (modelClass as AnyType).TABLE_NAME].find(Boolean) ??\n modelClass.name\n );\n }\n\n /** Assembles table schemas + relations for a datasource's registered models. */\n buildSchema(opts: { dataSource: string | TClass<IDataSource> }): {\n schema: Record<string, unknown>;\n relations: Record<string, unknown>;\n } {\n const { dataSource } = opts;\n const models = this.getModels({ dataSource });\n\n const rs: {\n schema: Record<string, unknown>;\n relations: Record<string, unknown>;\n } = { schema: {}, relations: {} };\n\n for (const model of models) {\n if (model.schema) {\n rs.schema[model.tableName] = model.schema;\n }\n\n if (model.relations) {\n rs.relations[`${model.tableName}Relations`] = model.relations;\n }\n }\n\n return rs;\n }\n\n hasModels(opts: { dataSource: string | TClass<IDataSource> }): boolean {\n return this.getDataSourceModelClasses({ dataSource: opts.dataSource }).size > 0;\n }\n };\n};\n"]}
@@ -28,5 +28,5 @@ export type { IDataSource } from './base/datasources/common/types';
28
28
  export { AbstractEntity } from './base/models/base';
29
29
  export { SchemaTypes } from './base/models/common/constants';
30
30
  export type { TIdSchemaType, TSchemaType } from './base/models/common';
31
- export type { TFilter, TInclusion, TWhere } from '@venizia/ignis-filter';
31
+ export type { TByIdFilter, TFields, TFilter, TInclusion, TRow, TSelectedRow, TWhere, } from '@venizia/ignis-filter';
32
32
  //# sourceMappingURL=repository.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/repository.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEjE,YAAY,EACV,oBAAoB,EACpB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,WAAW,EACX,oBAAoB,GACrB,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAI1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAC;AAI5F,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,yBAAyB,EACzB,eAAe,GAChB,MAAM,sCAAsC,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAEnG,YAAY,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAInE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAC7D,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGvE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/repository.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEjE,YAAY,EACV,oBAAoB,EACpB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,WAAW,EACX,oBAAoB,GACrB,MAAM,4CAA4C,CAAC;AAEpD,OAAO,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAI1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AAC5E,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,0CAA0C,CAAC;AAI5F,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,yBAAyB,EACzB,eAAe,GAChB,MAAM,sCAAsC,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,0CAA0C,CAAC;AAEnG,YAAY,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAInE,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAC7D,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGvE,YAAY,EACV,WAAW,EACX,OAAO,EACP,OAAO,EACP,UAAU,EACV,IAAI,EACJ,YAAY,EACZ,MAAM,GACP,MAAM,uBAAuB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/repository.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAEH,8DAAuE;AAA9D,8GAAA,kBAAkB,OAAA;AAC3B,wDAAiE;AAAxD,8GAAA,kBAAkB,OAAA;AAY3B,oEAA0E;AAAjE,yGAAA,cAAc,OAAA;AAEvB,gGAAgG;AAChG,yCAAyC;AACzC,8EAAgF;AAAvE,qHAAA,kBAAkB,OAAA;AAC3B,0EAA4E;AAAnE,iHAAA,gBAAgB,OAAA;AAGzB,mGAAmG;AACnG,mEAAmE;AACnE,kEAK8C;AAJ5C,0GAAA,aAAa,OAAA;AACb,8GAAA,iBAAiB,OAAA;AACjB,sHAAA,yBAAyB,OAAA;AACzB,4GAAA,eAAe,OAAA;AAGjB,oDAAwE;AAA/D,6GAAA,cAAc,OAAA;AAAE,+GAAA,gBAAgB,OAAA;AACzC,2DAA8D;AAArD,kHAAA,iBAAiB,OAAA;AAK1B,mGAAmG;AACnG,qFAAqF;AACrF,2CAAoD;AAA3C,sGAAA,cAAc,OAAA;AACvB,4DAA6D;AAApD,wGAAA,WAAW,OAAA","sourcesContent":["/**\n * The persistence contract, and nothing about how a row is served or validated.\n *\n * A repository talks to a datasource. `AbstractDataSource` is engine-neutral - its only required\n * member is `configure()` - so \"an HTTP request to another server\" is a datasource in the same sense\n * Drizzle-over-Postgres is one: same role, different transport. This entry exists so a consumer can\n * implement that without taking the OpenAPI layer, which `base/repositories` reaches through\n * `query-schemas` and `result-schemas`.\n *\n * Both halves already speak `@venizia/ignis-filter`, so a consumer on another transport shares the\n * query vocabulary rather than translating into one.\n *\n * Weight is a contract, checked by `src/__tests__/bundle/browser-weight.test.ts`.\n */\n\nexport { AbstractRepository } from '@/base/repositories/core/abstract';\nexport { AbstractDataSource } from '@/base/datasources/abstract';\n\nexport type {\n ICreatableRepository,\n ICrudRepository,\n IDeletableRepository,\n IPersistableRepository,\n IReadableRepository,\n IRepository,\n IUpdatableRepository,\n} from '@/base/repositories/common/types/contracts';\n\nexport { buildDataRange } from '@/base/repositories/common/types/results';\n\n// How a client reads what an IGNIS server answers - shared by the http connector and any client\n// that reads the same server without it.\nexport { HttpResponseReader } from '@/base/repositories/common/response-reader';\nexport { HttpExtraRequest } from '@/base/repositories/common/extra-request';\nexport type { TExtraRequest, TExtraResult } from '@/base/repositories/common/extra-request';\n\n// What a repository on any transport raises and bounds itself by - the constants, the error codes,\n// and the helper an engine that lacks an operation throws through.\nexport {\n DEFAULT_LIMIT,\n DEFAULT_MAX_LIMIT,\n RepositoryOperationScopes,\n RepositoryTypes,\n} from '@/base/repositories/common/constants';\nexport type { TRepositoryType } from '@/base/repositories/common/constants';\nexport { CoreErrorCodes, SearchErrorCodes } from '@/common/error-codes';\nexport { throwNotSupported } from '@/utilities/error.utility';\nexport type { TCount, TDataRange, TDataWithRange } from '@/base/repositories/common/types/results';\n\nexport type { IDataSource } from '@/base/datasources/common/types';\n\n// `IRepository` names an entity, so a consumer implementing the contract needs the base to extend.\n// Engine-neutral like the datasource: a name, `getSchema({ type })`, and an id type.\nexport { AbstractEntity } from '@/base/models/base';\nexport { SchemaTypes } from '@/base/models/common/constants';\nexport type { TIdSchemaType, TSchemaType } from '@/base/models/common';\n\n// The query vocabulary both transports share.\nexport type { TFilter, TInclusion, TWhere } from '@venizia/ignis-filter';\n"]}
1
+ {"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/repository.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAEH,8DAAuE;AAA9D,8GAAA,kBAAkB,OAAA;AAC3B,wDAAiE;AAAxD,8GAAA,kBAAkB,OAAA;AAY3B,oEAA0E;AAAjE,yGAAA,cAAc,OAAA;AAEvB,gGAAgG;AAChG,yCAAyC;AACzC,8EAAgF;AAAvE,qHAAA,kBAAkB,OAAA;AAC3B,0EAA4E;AAAnE,iHAAA,gBAAgB,OAAA;AAGzB,mGAAmG;AACnG,mEAAmE;AACnE,kEAK8C;AAJ5C,0GAAA,aAAa,OAAA;AACb,8GAAA,iBAAiB,OAAA;AACjB,sHAAA,yBAAyB,OAAA;AACzB,4GAAA,eAAe,OAAA;AAGjB,oDAAwE;AAA/D,6GAAA,cAAc,OAAA;AAAE,+GAAA,gBAAgB,OAAA;AACzC,2DAA8D;AAArD,kHAAA,iBAAiB,OAAA;AAK1B,mGAAmG;AACnG,qFAAqF;AACrF,2CAAoD;AAA3C,sGAAA,cAAc,OAAA;AACvB,4DAA6D;AAApD,wGAAA,WAAW,OAAA","sourcesContent":["/**\n * The persistence contract, and nothing about how a row is served or validated.\n *\n * A repository talks to a datasource. `AbstractDataSource` is engine-neutral - its only required\n * member is `configure()` - so \"an HTTP request to another server\" is a datasource in the same sense\n * Drizzle-over-Postgres is one: same role, different transport. This entry exists so a consumer can\n * implement that without taking the OpenAPI layer, which `base/repositories` reaches through\n * `query-schemas` and `result-schemas`.\n *\n * Both halves already speak `@venizia/ignis-filter`, so a consumer on another transport shares the\n * query vocabulary rather than translating into one.\n *\n * Weight is a contract, checked by `src/__tests__/bundle/browser-weight.test.ts`.\n */\n\nexport { AbstractRepository } from '@/base/repositories/core/abstract';\nexport { AbstractDataSource } from '@/base/datasources/abstract';\n\nexport type {\n ICreatableRepository,\n ICrudRepository,\n IDeletableRepository,\n IPersistableRepository,\n IReadableRepository,\n IRepository,\n IUpdatableRepository,\n} from '@/base/repositories/common/types/contracts';\n\nexport { buildDataRange } from '@/base/repositories/common/types/results';\n\n// How a client reads what an IGNIS server answers - shared by the http connector and any client\n// that reads the same server without it.\nexport { HttpResponseReader } from '@/base/repositories/common/response-reader';\nexport { HttpExtraRequest } from '@/base/repositories/common/extra-request';\nexport type { TExtraRequest, TExtraResult } from '@/base/repositories/common/extra-request';\n\n// What a repository on any transport raises and bounds itself by - the constants, the error codes,\n// and the helper an engine that lacks an operation throws through.\nexport {\n DEFAULT_LIMIT,\n DEFAULT_MAX_LIMIT,\n RepositoryOperationScopes,\n RepositoryTypes,\n} from '@/base/repositories/common/constants';\nexport type { TRepositoryType } from '@/base/repositories/common/constants';\nexport { CoreErrorCodes, SearchErrorCodes } from '@/common/error-codes';\nexport { throwNotSupported } from '@/utilities/error.utility';\nexport type { TCount, TDataRange, TDataWithRange } from '@/base/repositories/common/types/results';\n\nexport type { IDataSource } from '@/base/datasources/common/types';\n\n// `IRepository` names an entity, so a consumer implementing the contract needs the base to extend.\n// Engine-neutral like the datasource: a name, `getSchema({ type })`, and an id type.\nexport { AbstractEntity } from '@/base/models/base';\nexport { SchemaTypes } from '@/base/models/common/constants';\nexport type { TIdSchemaType, TSchemaType } from '@/base/models/common';\n\n// The query vocabulary both transports share.\nexport type {\n TByIdFilter,\n TFields,\n TFilter,\n TInclusion,\n TRow,\n TSelectedRow,\n TWhere,\n} from '@venizia/ignis-filter';\n"]}
@@ -59,7 +59,7 @@ export class AbstractApplication extends Container {
59
59
  throw getError({
60
60
  statusCode: HTTP.ResultCodes.RS_5.InternalServerError,
61
61
  message: `[executePostStartHooks] Failed post-start hook(s): ${failures
62
- .map(failure => `${failure.identifier} (${failure.error})`)
62
+ .map((failure) => `${failure.identifier} (${failure.error})`)
63
63
  .join(', ')}`,
64
64
  });
65
65
  }
@@ -83,7 +83,7 @@ export class AbstractApplication extends Container {
83
83
  registerCoreBindings() {
84
84
  this.bind({
85
85
  key: CoreBindings.APPLICATION_INSTANCE,
86
- }).toProvider(_ => this);
86
+ }).toProvider((_) => this);
87
87
  }
88
88
  init() {
89
89
  this.registerCoreBindings();
@@ -1 +1 @@
1
- {"version":3,"file":"abstract.js","sourceRoot":"","sources":["../../../../src/base/applications/abstract.ts"],"names":[],"mappings":"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","sourcesContent":["import { CoreBindings } from '@/common/bindings';\nimport { Container } from '@/helpers/inversion/container';\nimport type { ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport { HTTP } from '@venizia/ignis-helpers/common';\nimport type { IApplicationConfigs, IApplicationInfo } from './common';\n\nexport abstract class AbstractApplication extends Container {\n protected configs: IApplicationConfigs;\n protected projectRoot: string;\n\n private postStartHooks: Array<{ identifier: string; hook: () => ValueOrPromise<void> }> = [];\n private postStopHooks: Array<{ identifier: string; hook: () => ValueOrPromise<void> }> = [];\n\n constructor(opts: { scope: string; config: IApplicationConfigs }) {\n const { scope, config } = opts;\n super({ scope });\n\n this.configs = Object.assign({}, config, {\n asyncContext: {\n enable: config?.asyncContext?.enable ?? this.getDefaultAsyncContextEnabled(),\n },\n });\n\n this.projectRoot = this.getProjectRoot();\n this.logger.for('constructor').info('Project root: %s', this.projectRoot);\n }\n\n abstract getAppInfo(): ValueOrPromise<IApplicationInfo>;\n abstract preConfigure(): ValueOrPromise<void>;\n\n /**\n * Runs after every registration sweep (datasources, components, controllers) has already\n * completed. Registering a new one here is not auto-registered and silently does nothing -\n * call `configure()` manually instead.\n */\n abstract postConfigure(): ValueOrPromise<void>;\n\n abstract staticConfigure(): void;\n\n abstract setupMiddlewares(opts?: {\n middlewares?: Record<string | symbol, any>;\n }): ValueOrPromise<void>;\n\n abstract initialize(): Promise<void>;\n\n protected getDefaultAsyncContextEnabled(): boolean {\n return false;\n }\n\n getProjectConfigs(): IApplicationConfigs {\n return this.configs;\n }\n\n getProjectRoot(): string {\n const projectRoot = '';\n this.bind<string>({ key: CoreBindings.APPLICATION_PROJECT_ROOT }).toValue(projectRoot);\n return projectRoot;\n }\n\n registerPostStartHook(opts: { identifier: string; hook: () => ValueOrPromise<void> }) {\n this.postStartHooks.push(opts);\n this.logger\n .for(this.registerPostStartHook.name)\n .debug('Registered post-start hook | identifier: %s', opts.identifier);\n }\n\n /** Runs every post-start hook in isolation - the server is already listening, so a throwing hook must not cancel the ones behind it; failures are collected and reported as one error at the end. */\n protected async executePostStartHooks() {\n if (this.postStartHooks.length === 0) {\n return;\n }\n\n const logger = this.logger.for(this.executePostStartHooks.name);\n logger.info('Executing %s post-start hook(s)...', this.postStartHooks.length);\n\n const failures: Array<{ identifier: string; error: unknown }> = [];\n\n for (const { identifier, hook } of this.postStartHooks) {\n const t = performance.now();\n\n try {\n await hook();\n } catch (error) {\n logger.error('Failed to execute hook | identifier: %s | error: %s', identifier, error);\n failures.push({ identifier, error });\n continue;\n }\n\n logger.info(\n 'Executed hook | identifier: %s | took: %s (ms)',\n identifier,\n performance.now() - t,\n );\n }\n\n if (failures.length === 0) {\n return;\n }\n\n throw getError({\n statusCode: HTTP.ResultCodes.RS_5.InternalServerError,\n message: `[executePostStartHooks] Failed post-start hook(s): ${failures\n .map(failure => `${failure.identifier} (${failure.error})`)\n .join(', ')}`,\n });\n }\n\n registerPostStopHook(opts: { identifier: string; hook: () => ValueOrPromise<void> }) {\n this.postStopHooks.push(opts);\n this.logger\n .for(this.registerPostStopHook.name)\n .debug('Registered post-stop hook | identifier: %s', opts.identifier);\n }\n\n protected async executePostStopHooks() {\n const logger = this.logger.for(this.executePostStopHooks.name);\n for (const { identifier, hook } of this.postStopHooks) {\n try {\n await hook();\n } catch (error) {\n logger.error('Post-stop hook failed | identifier: %s | error: %s', identifier, error);\n }\n }\n }\n\n protected registerCoreBindings() {\n this.bind<typeof this>({\n key: CoreBindings.APPLICATION_INSTANCE,\n }).toProvider(_ => this);\n }\n\n init() {\n this.registerCoreBindings();\n }\n}\n"]}
1
+ {"version":3,"file":"abstract.js","sourceRoot":"","sources":["../../../../src/base/applications/abstract.ts"],"names":[],"mappings":"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","sourcesContent":["import { CoreBindings } from '@/common/bindings';\nimport { Container } from '@/helpers/inversion/container';\nimport type { ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport { HTTP } from '@venizia/ignis-helpers/common';\nimport type { IApplicationConfigs, IApplicationInfo } from './common';\n\nexport abstract class AbstractApplication extends Container {\n protected configs: IApplicationConfigs;\n protected projectRoot: string;\n\n private postStartHooks: Array<{ identifier: string; hook: () => ValueOrPromise<void> }> = [];\n private postStopHooks: Array<{ identifier: string; hook: () => ValueOrPromise<void> }> = [];\n\n constructor(opts: { scope: string; config: IApplicationConfigs }) {\n const { scope, config } = opts;\n super({ scope });\n\n this.configs = Object.assign({}, config, {\n asyncContext: {\n enable: config?.asyncContext?.enable ?? this.getDefaultAsyncContextEnabled(),\n },\n });\n\n this.projectRoot = this.getProjectRoot();\n this.logger.for('constructor').info('Project root: %s', this.projectRoot);\n }\n\n abstract getAppInfo(): ValueOrPromise<IApplicationInfo>;\n abstract preConfigure(): ValueOrPromise<void>;\n\n /**\n * Runs after every registration sweep (datasources, components, controllers) has already\n * completed. Registering a new one here is not auto-registered and silently does nothing -\n * call `configure()` manually instead.\n */\n abstract postConfigure(): ValueOrPromise<void>;\n\n abstract staticConfigure(): void;\n\n abstract setupMiddlewares(opts?: {\n middlewares?: Record<string | symbol, any>;\n }): ValueOrPromise<void>;\n\n abstract initialize(): Promise<void>;\n\n protected getDefaultAsyncContextEnabled(): boolean {\n return false;\n }\n\n getProjectConfigs(): IApplicationConfigs {\n return this.configs;\n }\n\n getProjectRoot(): string {\n const projectRoot = '';\n this.bind<string>({ key: CoreBindings.APPLICATION_PROJECT_ROOT }).toValue(projectRoot);\n return projectRoot;\n }\n\n registerPostStartHook(opts: { identifier: string; hook: () => ValueOrPromise<void> }) {\n this.postStartHooks.push(opts);\n this.logger\n .for(this.registerPostStartHook.name)\n .debug('Registered post-start hook | identifier: %s', opts.identifier);\n }\n\n /** Runs every post-start hook in isolation - the server is already listening, so a throwing hook must not cancel the ones behind it; failures are collected and reported as one error at the end. */\n protected async executePostStartHooks() {\n if (this.postStartHooks.length === 0) {\n return;\n }\n\n const logger = this.logger.for(this.executePostStartHooks.name);\n logger.info('Executing %s post-start hook(s)...', this.postStartHooks.length);\n\n const failures: Array<{ identifier: string; error: unknown }> = [];\n\n for (const { identifier, hook } of this.postStartHooks) {\n const t = performance.now();\n\n try {\n await hook();\n } catch (error) {\n logger.error('Failed to execute hook | identifier: %s | error: %s', identifier, error);\n failures.push({ identifier, error });\n continue;\n }\n\n logger.info(\n 'Executed hook | identifier: %s | took: %s (ms)',\n identifier,\n performance.now() - t,\n );\n }\n\n if (failures.length === 0) {\n return;\n }\n\n throw getError({\n statusCode: HTTP.ResultCodes.RS_5.InternalServerError,\n message: `[executePostStartHooks] Failed post-start hook(s): ${failures\n .map((failure) => `${failure.identifier} (${failure.error})`)\n .join(', ')}`,\n });\n }\n\n registerPostStopHook(opts: { identifier: string; hook: () => ValueOrPromise<void> }) {\n this.postStopHooks.push(opts);\n this.logger\n .for(this.registerPostStopHook.name)\n .debug('Registered post-stop hook | identifier: %s', opts.identifier);\n }\n\n protected async executePostStopHooks() {\n const logger = this.logger.for(this.executePostStopHooks.name);\n for (const { identifier, hook } of this.postStopHooks) {\n try {\n await hook();\n } catch (error) {\n logger.error('Post-stop hook failed | identifier: %s | error: %s', identifier, error);\n }\n }\n }\n\n protected registerCoreBindings() {\n this.bind<typeof this>({\n key: CoreBindings.APPLICATION_INSTANCE,\n }).toProvider((_) => this);\n }\n\n init() {\n this.registerCoreBindings();\n }\n}\n"]}
@@ -35,7 +35,7 @@ export class ArtifactGroup {
35
35
  /** A group carrying only `kinds` - for a slicer that splits `configs.artifacts` by run mode. The source group is resolved when artifacts are registered, never here. */
36
36
  static pick(opts) {
37
37
  const { group, kinds } = opts;
38
- const slice = (index) => Object.fromEntries(kinds.filter(kind => index[kind] !== undefined).map(kind => [kind, index[kind]]));
38
+ const slice = (index) => Object.fromEntries(kinds.filter((kind) => index[kind] !== undefined).map((kind) => [kind, index[kind]]));
39
39
  return new ArtifactGroup({
40
40
  folder: group.folder,
41
41
  site: group.site,
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-group.js","sourceRoot":"","sources":["../../../../src/base/applications/artifact-group.ts"],"names":[],"mappings":"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","sourcesContent":["import { SingletonRealm } from '@/helpers/singleton-realm';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport type { IArtifactGroup, IArtifactIndex } from './common';\n\ntype TGroupResolver = (opts: { group: IArtifactGroup }) => Promise<IArtifactIndex>;\n\n/** A typed slice of a shared package's artifacts - every decorated class under a directory named `folder` in the package that defined it. A package declares one per domain, once; an application borrows it in `configs.artifacts`. The content is filled by `@venizia/ignis-boot`: inlined when the application is built, or resolved from source when artifacts are registered. */\nexport class ArtifactGroup implements IArtifactGroup {\n /** A string brand, so the group protocol is structural: `@venizia/ignis-boot/auto` builds one without depending on the kernel. */\n static readonly BRAND_KEY = 'isArtifactGroup';\n /** The realm slot `@venizia/ignis-boot` fills with the resolver for groups defined without content. */\n static readonly SINGLETON_REALM_KEY = 'artifact-group-resolver';\n\n readonly isArtifactGroup = true as const;\n readonly resolve: (() => Promise<IArtifactIndex>) | undefined;\n readonly kinds: ReadonlyArray<keyof IArtifactIndex> | undefined;\n\n private constructor(opts: {\n folder: string | undefined;\n site: string | undefined;\n content: IArtifactIndex | undefined;\n resolve?: () => Promise<IArtifactIndex>;\n kinds?: ReadonlyArray<keyof IArtifactIndex>;\n ignore?: ReadonlyArray<string>;\n }) {\n this.folder = opts.folder;\n this.site = opts.site;\n this.content = opts.content;\n this.resolve = opts.resolve;\n this.kinds = opts.kinds;\n this.ignore = opts.ignore;\n }\n\n readonly folder: string | undefined;\n readonly site: string | undefined;\n readonly content: IArtifactIndex | undefined;\n readonly ignore: ReadonlyArray<string> | undefined;\n\n /** `content` is written by the build plugin; a hand-written group passes only `folder`. */\n static define(opts: { folder: string; content?: IArtifactIndex }): ArtifactGroup {\n return new ArtifactGroup({\n folder: opts.folder,\n site: ArtifactGroup.callSite(),\n content: opts.content,\n });\n }\n\n /** Every decorated class of the calling package - an application's own artifacts, picked by its call site, so several applications in one process each get their own. `ignore` takes the globs `ignis-artifacts --ignore` takes, relative to the package `src`. `content` is written by the build plugin. */\n static application(\n opts: { ignore?: ReadonlyArray<string>; content?: IArtifactIndex } = {},\n ): ArtifactGroup {\n return new ArtifactGroup({\n folder: undefined,\n site: ArtifactGroup.callSite(),\n content: opts.content,\n ignore: opts.ignore,\n });\n }\n\n /** A group carrying only `kinds` - for a slicer that splits `configs.artifacts` by run mode. The source group is resolved when artifacts are registered, never here. */\n static pick(opts: {\n group: IArtifactGroup;\n kinds: ReadonlyArray<keyof IArtifactIndex>;\n }): ArtifactGroup {\n const { group, kinds } = opts;\n const slice = (index: IArtifactIndex): IArtifactIndex =>\n Object.fromEntries(\n kinds.filter(kind => index[kind] !== undefined).map(kind => [kind, index[kind]]),\n );\n\n return new ArtifactGroup({\n folder: group.folder,\n site: group.site,\n content: group.content ? slice(group.content) : undefined,\n resolve: async () => slice(await ArtifactGroup.resolveContent({ group })),\n kinds,\n ignore: group.ignore,\n });\n }\n\n /** A group's classes: inlined by a build, else its own `resolve()`, else the resolver `@venizia/ignis-boot/auto` installs. */\n static async resolveContent(opts: { group: IArtifactGroup }): Promise<IArtifactIndex> {\n const { group } = opts;\n if (group.content) {\n return group.content;\n }\n if (group.resolve) {\n return group.resolve();\n }\n const resolve = ArtifactGroup.getResolver();\n if (!resolve) {\n throw getError({\n message: `[ArtifactGroup] '${group.folder ?? '<application>'}' has no content | Import @venizia/ignis-boot/auto in the application (it resolves groups from source), or add IgnisArtifactsPlugin to the build's plugins`,\n });\n }\n return resolve({ group });\n }\n\n /** Positional on purpose: a type predicate narrows its own parameter, and an options object would narrow the wrapper instead of `value`. */\n static isGroup(value: unknown): value is IArtifactGroup {\n return (\n typeof value === 'object' &&\n value !== null &&\n ArtifactGroup.BRAND_KEY in value &&\n value[ArtifactGroup.BRAND_KEY] === true\n );\n }\n\n static setResolver(opts: { resolve: TGroupResolver | undefined }): void {\n ArtifactGroup.holder().resolve = opts.resolve;\n }\n\n static getResolver(): TGroupResolver | undefined {\n return ArtifactGroup.holder().resolve;\n }\n\n /** The error a walker over `configs.artifacts` gets for reading a kind off a group - loud, never an empty list. */\n static unreadKindError(opts: { folder: string | undefined }): Error {\n return getError({\n message: `[ArtifactGroup] '${opts.folder ?? '<application>'}' is resolved when artifacts are registered | A function that walks configs.artifacts must pass a group through untouched (ArtifactGroup.isGroup) instead of reading its kinds`,\n });\n }\n\n get configurations(): never {\n throw ArtifactGroup.unreadKindError({ folder: this.folder });\n }\n\n get dataSources(): never {\n throw ArtifactGroup.unreadKindError({ folder: this.folder });\n }\n\n get components(): never {\n throw ArtifactGroup.unreadKindError({ folder: this.folder });\n }\n\n get repositories(): never {\n throw ArtifactGroup.unreadKindError({ folder: this.folder });\n }\n\n get services(): never {\n throw ArtifactGroup.unreadKindError({ folder: this.folder });\n }\n\n get controllers(): never {\n throw ArtifactGroup.unreadKindError({ folder: this.folder });\n }\n\n private static holder(): { resolve: TGroupResolver | undefined } {\n return SingletonRealm.resolve({\n key: ArtifactGroup.SINGLETON_REALM_KEY,\n create: () => ({ resolve: undefined }),\n });\n }\n\n /** The module that declared the group, read from the call stack. */\n private static callSite(): string | undefined {\n // A stack trace, not a failure: reading the call site needs an Error object, and nothing is thrown.\n // eslint-disable-next-line venizia/no-new-error\n return ArtifactGroup.siteFromStack({ stack: new Error().stack ?? '' });\n }\n\n /** The first frame outside the kernel's own `artifact-group` file: POSIX and Windows paths, `file://` URLs (decoded, drive kept), parentheses inside a path. */\n static siteFromStack(opts: { stack: string }): string | undefined {\n for (const raw of opts.stack.split('\\n').slice(1)) {\n const frame = raw.trim().replace(/^at\\s+/, '');\n const opening = frame.indexOf(' (');\n const location = frame.endsWith(')') && opening >= 0 ? frame.slice(opening + 2, -1) : frame;\n let file = location.replace(/:\\d+:\\d+$/, '');\n if (file.startsWith('file://')) {\n file = decodeURIComponent(file.slice('file://'.length)).replace(/^\\/([A-Za-z]:\\/)/, '$1');\n }\n const isPath = file.startsWith('/') || /^[A-Za-z]:[\\\\/]/.test(file);\n if (isPath && !/(?:^|[\\\\/])artifact-group\\.(?:ts|js)$/.test(file)) {\n return file;\n }\n }\n return undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"artifact-group.js","sourceRoot":"","sources":["../../../../src/base/applications/artifact-group.ts"],"names":[],"mappings":"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","sourcesContent":["import { SingletonRealm } from '@/helpers/singleton-realm';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport type { IArtifactGroup, IArtifactIndex } from './common';\n\ntype TGroupResolver = (opts: { group: IArtifactGroup }) => Promise<IArtifactIndex>;\n\n/** A typed slice of a shared package's artifacts - every decorated class under a directory named `folder` in the package that defined it. A package declares one per domain, once; an application borrows it in `configs.artifacts`. The content is filled by `@venizia/ignis-boot`: inlined when the application is built, or resolved from source when artifacts are registered. */\nexport class ArtifactGroup implements IArtifactGroup {\n /** A string brand, so the group protocol is structural: `@venizia/ignis-boot/auto` builds one without depending on the kernel. */\n static readonly BRAND_KEY = 'isArtifactGroup';\n /** The realm slot `@venizia/ignis-boot` fills with the resolver for groups defined without content. */\n static readonly SINGLETON_REALM_KEY = 'artifact-group-resolver';\n\n readonly isArtifactGroup = true as const;\n readonly resolve: (() => Promise<IArtifactIndex>) | undefined;\n readonly kinds: ReadonlyArray<keyof IArtifactIndex> | undefined;\n\n private constructor(opts: {\n folder: string | undefined;\n site: string | undefined;\n content: IArtifactIndex | undefined;\n resolve?: () => Promise<IArtifactIndex>;\n kinds?: ReadonlyArray<keyof IArtifactIndex>;\n ignore?: ReadonlyArray<string>;\n }) {\n this.folder = opts.folder;\n this.site = opts.site;\n this.content = opts.content;\n this.resolve = opts.resolve;\n this.kinds = opts.kinds;\n this.ignore = opts.ignore;\n }\n\n readonly folder: string | undefined;\n readonly site: string | undefined;\n readonly content: IArtifactIndex | undefined;\n readonly ignore: ReadonlyArray<string> | undefined;\n\n /** `content` is written by the build plugin; a hand-written group passes only `folder`. */\n static define(opts: { folder: string; content?: IArtifactIndex }): ArtifactGroup {\n return new ArtifactGroup({\n folder: opts.folder,\n site: ArtifactGroup.callSite(),\n content: opts.content,\n });\n }\n\n /** Every decorated class of the calling package - an application's own artifacts, picked by its call site, so several applications in one process each get their own. `ignore` takes the globs `ignis-artifacts --ignore` takes, relative to the package `src`. `content` is written by the build plugin. */\n static application(\n opts: { ignore?: ReadonlyArray<string>; content?: IArtifactIndex } = {},\n ): ArtifactGroup {\n return new ArtifactGroup({\n folder: undefined,\n site: ArtifactGroup.callSite(),\n content: opts.content,\n ignore: opts.ignore,\n });\n }\n\n /** A group carrying only `kinds` - for a slicer that splits `configs.artifacts` by run mode. The source group is resolved when artifacts are registered, never here. */\n static pick(opts: {\n group: IArtifactGroup;\n kinds: ReadonlyArray<keyof IArtifactIndex>;\n }): ArtifactGroup {\n const { group, kinds } = opts;\n const slice = (index: IArtifactIndex): IArtifactIndex =>\n Object.fromEntries(\n kinds.filter((kind) => index[kind] !== undefined).map((kind) => [kind, index[kind]]),\n );\n\n return new ArtifactGroup({\n folder: group.folder,\n site: group.site,\n content: group.content ? slice(group.content) : undefined,\n resolve: async () => slice(await ArtifactGroup.resolveContent({ group })),\n kinds,\n ignore: group.ignore,\n });\n }\n\n /** A group's classes: inlined by a build, else its own `resolve()`, else the resolver `@venizia/ignis-boot/auto` installs. */\n static async resolveContent(opts: { group: IArtifactGroup }): Promise<IArtifactIndex> {\n const { group } = opts;\n if (group.content) {\n return group.content;\n }\n if (group.resolve) {\n return group.resolve();\n }\n const resolve = ArtifactGroup.getResolver();\n if (!resolve) {\n throw getError({\n message: `[ArtifactGroup] '${group.folder ?? '<application>'}' has no content | Import @venizia/ignis-boot/auto in the application (it resolves groups from source), or add IgnisArtifactsPlugin to the build's plugins`,\n });\n }\n return resolve({ group });\n }\n\n /** Positional on purpose: a type predicate narrows its own parameter, and an options object would narrow the wrapper instead of `value`. */\n static isGroup(value: unknown): value is IArtifactGroup {\n return (\n typeof value === 'object' &&\n value !== null &&\n ArtifactGroup.BRAND_KEY in value &&\n value[ArtifactGroup.BRAND_KEY] === true\n );\n }\n\n static setResolver(opts: { resolve: TGroupResolver | undefined }): void {\n ArtifactGroup.holder().resolve = opts.resolve;\n }\n\n static getResolver(): TGroupResolver | undefined {\n return ArtifactGroup.holder().resolve;\n }\n\n /** The error a walker over `configs.artifacts` gets for reading a kind off a group - loud, never an empty list. */\n static unreadKindError(opts: { folder: string | undefined }): Error {\n return getError({\n message: `[ArtifactGroup] '${opts.folder ?? '<application>'}' is resolved when artifacts are registered | A function that walks configs.artifacts must pass a group through untouched (ArtifactGroup.isGroup) instead of reading its kinds`,\n });\n }\n\n get configurations(): never {\n throw ArtifactGroup.unreadKindError({ folder: this.folder });\n }\n\n get dataSources(): never {\n throw ArtifactGroup.unreadKindError({ folder: this.folder });\n }\n\n get components(): never {\n throw ArtifactGroup.unreadKindError({ folder: this.folder });\n }\n\n get repositories(): never {\n throw ArtifactGroup.unreadKindError({ folder: this.folder });\n }\n\n get services(): never {\n throw ArtifactGroup.unreadKindError({ folder: this.folder });\n }\n\n get controllers(): never {\n throw ArtifactGroup.unreadKindError({ folder: this.folder });\n }\n\n private static holder(): { resolve: TGroupResolver | undefined } {\n return SingletonRealm.resolve({\n key: ArtifactGroup.SINGLETON_REALM_KEY,\n create: () => ({ resolve: undefined }),\n });\n }\n\n /** The module that declared the group, read from the call stack. */\n private static callSite(): string | undefined {\n // A stack trace, not a failure: reading the call site needs an Error object, and nothing is thrown.\n // eslint-disable-next-line venizia/no-new-error\n return ArtifactGroup.siteFromStack({ stack: new Error().stack ?? '' });\n }\n\n /** The first frame outside the kernel's own `artifact-group` file: POSIX and Windows paths, `file://` URLs (decoded, drive kept), parentheses inside a path. */\n static siteFromStack(opts: { stack: string }): string | undefined {\n for (const raw of opts.stack.split('\\n').slice(1)) {\n const frame = raw.trim().replace(/^at\\s+/, '');\n const opening = frame.indexOf(' (');\n const location = frame.endsWith(')') && opening >= 0 ? frame.slice(opening + 2, -1) : frame;\n let file = location.replace(/:\\d+:\\d+$/, '');\n if (file.startsWith('file://')) {\n file = decodeURIComponent(file.slice('file://'.length)).replace(/^\\/([A-Za-z]:\\/)/, '$1');\n }\n const isPath = file.startsWith('/') || /^[A-Za-z]:[\\\\/]/.test(file);\n if (isPath && !/(?:^|[\\\\/])artifact-group\\.(?:ts|js)$/.test(file)) {\n return file;\n }\n }\n return undefined;\n }\n}\n"]}
@@ -107,8 +107,8 @@ export class ArtifactIndexHelper extends BaseHelper {
107
107
  for (const prereq of afterList) {
108
108
  // A string names a class, the only form that can; a class is matched by identity.
109
109
  const prereqClass = typeof prereq === 'function'
110
- ? classes.find(candidate => candidate === prereq)
111
- : classes.find(candidate => candidate.name === String(prereq));
110
+ ? classes.find((candidate) => candidate === prereq)
111
+ : classes.find((candidate) => candidate.name === String(prereq));
112
112
  if (!prereqClass) {
113
113
  const prereqName = typeof prereq === 'function' ? prereq.name : String(prereq);
114
114
  throw getError({
@@ -122,7 +122,7 @@ export class ArtifactIndexHelper extends BaseHelper {
122
122
  // Kahn's algorithm. Siblings run in class-name order; a minified build renames classes, so an
123
123
  // order that matters belongs in `after`.
124
124
  const byName = (a, b) => a.name.localeCompare(b.name);
125
- const available = classes.filter(target => inDegree.get(target) === 0).sort(byName);
125
+ const available = classes.filter((target) => inDegree.get(target) === 0).sort(byName);
126
126
  const sorted = [];
127
127
  while (available.length > 0) {
128
128
  const current = available.shift();
@@ -138,8 +138,8 @@ export class ArtifactIndexHelper extends BaseHelper {
138
138
  }
139
139
  if (sorted.length !== classes.length) {
140
140
  const unvisited = classes
141
- .filter(target => !sorted.includes(target))
142
- .map(target => target.name);
141
+ .filter((target) => !sorted.includes(target))
142
+ .map((target) => target.name);
143
143
  throw getError({
144
144
  message: `[sortConfigurationsTopologically] Dependency cycle detected in configurations: ${unvisited.join(', ')}`,
145
145
  });
@@ -148,7 +148,7 @@ export class ArtifactIndexHelper extends BaseHelper {
148
148
  }
149
149
  /** Every entry of a kind must be a class. `undefined` is what an import cycle leaves - the index was read before a class's module finished loading - so it gets a message that names the cause instead of a crash on `.name`. */
150
150
  assertClasses(opts) {
151
- const position = (opts.classes ?? []).findIndex(target => typeof target !== 'function');
151
+ const position = (opts.classes ?? []).findIndex((target) => typeof target !== 'function');
152
152
  if (position >= 0) {
153
153
  throw getError({
154
154
  message: `[ArtifactIndex] '${opts.field}' lists an entry that is not a class (position ${position}) | Usually an import cycle: the index was read before that class's module finished loading. The module that imports the index (or @venizia/ignis-boot/auto) must not define decorated classes or be imported by them`,
@@ -162,7 +162,7 @@ export class ArtifactIndexHelper extends BaseHelper {
162
162
  return this.flatten({ input: await this.contentOf({ group: input }), application });
163
163
  }
164
164
  if (Array.isArray(input)) {
165
- const nested = await Promise.all(input.map(entry => this.flatten({ input: entry, application })));
165
+ const nested = await Promise.all(input.map((entry) => this.flatten({ input: entry, application })));
166
166
  return nested.flat();
167
167
  }
168
168
  if (this.isConditional(input)) {
@@ -184,7 +184,7 @@ export class ArtifactIndexHelper extends BaseHelper {
184
184
  this.assertClasses({ field, classes });
185
185
  }
186
186
  const kinds = Object.values(content);
187
- const names = kinds.flatMap(classes => (classes ?? []).map(target => target.name));
187
+ const names = kinds.flatMap((classes) => (classes ?? []).map((target) => target.name));
188
188
  if (names.length === 0 && !group.kinds) {
189
189
  throw getError({
190
190
  message: `[ArtifactGroup] '${group.folder ?? '<application>'}' resolved to no class | Defined in ${group.site ?? 'an unknown module'} - check the folder name and that its classes carry a stereotype decorator`,
@@ -203,9 +203,9 @@ export class ArtifactIndexHelper extends BaseHelper {
203
203
  const registry = MetadataRegistry.getInstance();
204
204
  // De-duplicated: discovery and a declared index can name the same class, and registering it
205
205
  // twice trips `bootChecks.binding.allowOverride: false`. First mention wins its position.
206
- const listed = [...new Set(indexes.flatMap(index => [...(index[field] ?? [])]))];
206
+ const listed = [...new Set(indexes.flatMap((index) => [...(index[field] ?? [])]))];
207
207
  this.assertClasses({ field, classes: listed });
208
- const decisions = await Promise.all(listed.map(target => this.isSelected({ target, application })));
208
+ const decisions = await Promise.all(listed.map((target) => this.isSelected({ target, application })));
209
209
  const kept = listed.filter((target, position) => {
210
210
  if (decisions[position]) {
211
211
  return true;
@@ -220,7 +220,7 @@ export class ArtifactIndexHelper extends BaseHelper {
220
220
  order: registry.getArtifactMetadata({ target })?.order ?? 0,
221
221
  }))
222
222
  .sort((a, b) => a.order - b.order || a.position - b.position)
223
- .map(entry => entry.target);
223
+ .map((entry) => entry.target);
224
224
  }
225
225
  async isSelected(opts) {
226
226
  const { target, application } = opts;
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-index.js","sourceRoot":"","sources":["../../../../src/base/applications/artifact-index.ts"],"names":[],"mappings":"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","sourcesContent":["import { MetadataRegistry } from '@/helpers/inversion';\nimport { SingletonRealm } from '@/helpers/singleton-realm';\nimport type { AnyType, TClass } from '@venizia/ignis-helpers/common';\nimport { ArtifactTypes, isClass } from '@/helpers/inversion';\nimport { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport { ArtifactGroup } from './artifact-group';\nimport type {\n IArtifactGroup,\n IArtifactIndex,\n IConditionalArtifactIndex,\n TArtifactIndexInput,\n} from './common';\nimport { ArtifactIndexFields } from './common';\n\n/** Turns a `configs.artifacts` input into the classes to register: flattens nested indexes, drops the classes whose `when` says no, orders the rest. It never touches the container - `registerArtifacts` does the binding. */\nexport class ArtifactIndexHelper extends BaseHelper {\n static readonly SINGLETON_REALM_KEY = 'artifact-index-helper';\n\n private constructor() {\n super({ scope: ArtifactIndexHelper.name });\n }\n\n static getInstance(): ArtifactIndexHelper {\n return SingletonRealm.resolve({\n key: ArtifactIndexHelper.SINGLETON_REALM_KEY,\n create: () => new ArtifactIndexHelper(),\n });\n }\n\n /** Maps an artifact type to the index field that carries it. `ArtifactTypes.MODEL` is deliberately absent: a model has a binding namespace but no index field, because its repository registers it. */\n private static readonly INDEX_FIELD_BY_TYPE: Record<string, string> = {\n [ArtifactTypes.CONFIGURATION]: ArtifactIndexFields.CONFIGURATIONS,\n [ArtifactTypes.DATASOURCE]: ArtifactIndexFields.DATA_SOURCES,\n [ArtifactTypes.COMPONENT]: ArtifactIndexFields.COMPONENTS,\n [ArtifactTypes.REPOSITORY]: ArtifactIndexFields.REPOSITORIES,\n [ArtifactTypes.SERVICE]: ArtifactIndexFields.SERVICES,\n [ArtifactTypes.CONTROLLER]: ArtifactIndexFields.CONTROLLERS,\n };\n\n /** The index a decorator-only application has: every class a stereotype saw at import time, bucketed by its type. `when` and `order` still apply - `resolve` does that, exactly as it does for a declared index. */\n buildDiscoveredIndex(): IArtifactIndex {\n const registry = MetadataRegistry.getInstance();\n const index: Record<string, TClass<AnyType>[]> = {};\n\n const discoveredArtifacts = registry.getDiscoveredArtifacts();\n for (const target of discoveredArtifacts) {\n if (!isClass<AnyType>(target)) {\n continue;\n }\n\n const type = registry.getArtifactMetadata({ target })?.type;\n const field = type ? ArtifactIndexHelper.INDEX_FIELD_BY_TYPE[type] : undefined;\n if (!field) {\n continue;\n }\n\n index[field] = [...(index[field] ?? []), target];\n }\n\n return index;\n }\n\n /** Every kind of the input, each already filtered by `when` and sorted by `order`, keyed the way `IArtifactIndex` is. */\n async resolve(opts: {\n input: TArtifactIndexInput;\n application: unknown;\n }): Promise<Required<IArtifactIndex>> {\n const { input, application } = opts;\n const indexes = await this.flatten({ input, application });\n\n const rawConfigurations = await this.select({\n indexes,\n field: ArtifactIndexFields.CONFIGURATIONS,\n application,\n });\n const configurations = this.sortConfigurationsTopologically({\n classes: rawConfigurations,\n });\n\n const dataSources = await this.select({\n indexes,\n field: ArtifactIndexFields.DATA_SOURCES,\n application,\n });\n const components = await this.select({\n indexes,\n field: ArtifactIndexFields.COMPONENTS,\n application,\n });\n const repositories = await this.select({\n indexes,\n field: ArtifactIndexFields.REPOSITORIES,\n application,\n });\n const services = await this.select({\n indexes,\n field: ArtifactIndexFields.SERVICES,\n application,\n });\n const controllers = await this.select({\n indexes,\n field: ArtifactIndexFields.CONTROLLERS,\n application,\n });\n\n return { configurations, dataSources, components, repositories, services, controllers };\n }\n\n /**\n * Topologically sort configurations based on `after` dependencies.\n * Siblings with no dependency relation are sorted deterministically by class name.\n * Throws if an unknown `after` dependency is referenced or if a dependency cycle is detected.\n */\n sortConfigurationsTopologically(opts: { classes: ReadonlyArray<TClass<any>> }): TClass<any>[] {\n const { classes } = opts;\n if (classes.length === 0) {\n return [];\n }\n\n const registry = MetadataRegistry.getInstance();\n\n // Keyed by the class itself: two configurations may share a name (a minified build renames them),\n // and a name-keyed graph silently drops one of them.\n const inDegree = new Map<TClass<any>, number>();\n const adjacency = new Map<TClass<any>, TClass<any>[]>();\n\n for (const target of classes) {\n inDegree.set(target, 0);\n adjacency.set(target, []);\n }\n\n for (const target of classes) {\n const metadata = registry.getArtifactMetadata({ target });\n const afterList = metadata?.after ?? [];\n\n for (const prereq of afterList) {\n // A string names a class, the only form that can; a class is matched by identity.\n const prereqClass =\n typeof prereq === 'function'\n ? classes.find(candidate => candidate === prereq)\n : classes.find(candidate => candidate.name === String(prereq));\n\n if (!prereqClass) {\n const prereqName = typeof prereq === 'function' ? prereq.name : String(prereq);\n throw getError({\n message: `[sortConfigurationsTopologically][${target.name}] Declared 'after' dependency '${prereqName}' is not registered as a configuration`,\n });\n }\n\n adjacency.get(prereqClass)!.push(target);\n inDegree.set(target, (inDegree.get(target) ?? 0) + 1);\n }\n }\n\n // Kahn's algorithm. Siblings run in class-name order; a minified build renames classes, so an\n // order that matters belongs in `after`.\n const byName = (a: TClass<any>, b: TClass<any>) => a.name.localeCompare(b.name);\n const available = classes.filter(target => inDegree.get(target) === 0).sort(byName);\n const sorted: TClass<any>[] = [];\n\n while (available.length > 0) {\n const current = available.shift()!;\n sorted.push(current);\n\n for (const dependent of adjacency.get(current) ?? []) {\n const newDeg = inDegree.get(dependent)! - 1;\n inDegree.set(dependent, newDeg);\n if (newDeg === 0) {\n available.push(dependent);\n available.sort(byName);\n }\n }\n }\n\n if (sorted.length !== classes.length) {\n const unvisited = classes\n .filter(target => !sorted.includes(target))\n .map(target => target.name);\n throw getError({\n message: `[sortConfigurationsTopologically] Dependency cycle detected in configurations: ${unvisited.join(', ')}`,\n });\n }\n\n return sorted;\n }\n\n /** Every entry of a kind must be a class. `undefined` is what an import cycle leaves - the index was read before a class's module finished loading - so it gets a message that names the cause instead of a crash on `.name`. */\n private assertClasses(opts: {\n field: string;\n classes: ReadonlyArray<unknown> | undefined;\n }): void {\n const position = (opts.classes ?? []).findIndex(target => typeof target !== 'function');\n if (position >= 0) {\n throw getError({\n message: `[ArtifactIndex] '${opts.field}' lists an entry that is not a class (position ${position}) | Usually an import cycle: the index was read before that class's module finished loading. The module that imports the index (or @venizia/ignis-boot/auto) must not define decorated classes or be imported by them`,\n });\n }\n }\n\n /** One index, or arrays nested to any depth, as a flat list in input order; a conditional entry contributes its subtree only when its `when` answers true. */\n async flatten(opts: {\n input: TArtifactIndexInput;\n application: unknown;\n }): Promise<IArtifactIndex[]> {\n const { input, application } = opts;\n if (ArtifactGroup.isGroup(input)) {\n return this.flatten({ input: await this.contentOf({ group: input }), application });\n }\n if (Array.isArray(input)) {\n const nested = await Promise.all(\n input.map(entry => this.flatten({ input: entry, application })),\n );\n return nested.flat();\n }\n\n if (this.isConditional(input)) {\n const isSelected = await input.when({ application });\n if (!isSelected) {\n this.logger.debug('Skipped by condition | conditional index entry');\n return [];\n }\n\n return this.flatten({ input: input.index, application });\n }\n\n return [input];\n }\n\n /** A group's classes: inlined at build time, else the resolver `@venizia/ignis-boot/auto` installs. Never empty - a group that names nothing is a typo or a moved folder. */\n private async contentOf(opts: { group: IArtifactGroup }): Promise<IArtifactIndex> {\n const { group } = opts;\n const content = await ArtifactGroup.resolveContent({ group });\n\n // One element type for the six kinds, so `.map` is callable on every member of the union.\n for (const [field, classes] of Object.entries(content)) {\n this.assertClasses({ field, classes });\n }\n const kinds: Array<ReadonlyArray<TClass<unknown>> | undefined> = Object.values(content);\n const names = kinds.flatMap(classes => (classes ?? []).map(target => target.name));\n if (names.length === 0 && !group.kinds) {\n throw getError({\n message: `[ArtifactGroup] '${group.folder ?? '<application>'}' resolved to no class | Defined in ${group.site ?? 'an unknown module'} - check the folder name and that its classes carry a stereotype decorator`,\n });\n }\n this.logger.info('[ArtifactGroup] %s -> %s', group.folder ?? '<application>', names.join(', '));\n return content;\n }\n\n /** Positional on purpose: a type predicate narrows its own parameter, and an options object would narrow the wrapper instead of `input`. */\n private isConditional(\n entry: IArtifactIndex | IConditionalArtifactIndex,\n ): entry is IConditionalArtifactIndex {\n return 'when' in entry && 'index' in entry;\n }\n\n /** The classes of one kind across every index, minus those whose `when` says no, sorted by `order` (stable). The `when` conditions run concurrently: each reads config and environment, never another artifact. */\n async select<Field extends keyof IArtifactIndex>(opts: {\n indexes: IArtifactIndex[];\n field: Field;\n application: unknown;\n }): Promise<NonNullable<IArtifactIndex[Field]>[number][]> {\n const { indexes, field, application } = opts;\n const registry = MetadataRegistry.getInstance();\n\n // De-duplicated: discovery and a declared index can name the same class, and registering it\n // twice trips `bootChecks.binding.allowOverride: false`. First mention wins its position.\n const listed = [...new Set(indexes.flatMap(index => [...(index[field] ?? [])]))];\n this.assertClasses({ field, classes: listed });\n const decisions = await Promise.all(\n listed.map(target => this.isSelected({ target, application })),\n );\n\n const kept = listed.filter((target, position) => {\n if (decisions[position]) {\n return true;\n }\n\n this.logger.debug('Skipped by condition | kind: %s | class: %s', field, target.name);\n return false;\n });\n\n return kept\n .map((target, position) => ({\n target,\n position,\n order: registry.getArtifactMetadata({ target })?.order ?? 0,\n }))\n .sort((a, b) => a.order - b.order || a.position - b.position)\n .map(entry => entry.target);\n }\n\n private async isSelected(opts: {\n target: TClass<unknown>;\n application: unknown;\n }): Promise<boolean> {\n const { target, application } = opts;\n const when = MetadataRegistry.getInstance().getArtifactMetadata({ target })?.when;\n if (!when) {\n return true;\n }\n return when({ application });\n }\n}\n"]}
1
+ {"version":3,"file":"artifact-index.js","sourceRoot":"","sources":["../../../../src/base/applications/artifact-index.ts"],"names":[],"mappings":"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","sourcesContent":["import { MetadataRegistry } from '@/helpers/inversion';\nimport { SingletonRealm } from '@/helpers/singleton-realm';\nimport type { AnyType, TClass } from '@venizia/ignis-helpers/common';\nimport { ArtifactTypes, isClass } from '@/helpers/inversion';\nimport { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport { ArtifactGroup } from './artifact-group';\nimport type {\n IArtifactGroup,\n IArtifactIndex,\n IConditionalArtifactIndex,\n TArtifactIndexInput,\n} from './common';\nimport { ArtifactIndexFields } from './common';\n\n/** Turns a `configs.artifacts` input into the classes to register: flattens nested indexes, drops the classes whose `when` says no, orders the rest. It never touches the container - `registerArtifacts` does the binding. */\nexport class ArtifactIndexHelper extends BaseHelper {\n static readonly SINGLETON_REALM_KEY = 'artifact-index-helper';\n\n private constructor() {\n super({ scope: ArtifactIndexHelper.name });\n }\n\n static getInstance(): ArtifactIndexHelper {\n return SingletonRealm.resolve({\n key: ArtifactIndexHelper.SINGLETON_REALM_KEY,\n create: () => new ArtifactIndexHelper(),\n });\n }\n\n /** Maps an artifact type to the index field that carries it. `ArtifactTypes.MODEL` is deliberately absent: a model has a binding namespace but no index field, because its repository registers it. */\n private static readonly INDEX_FIELD_BY_TYPE: Record<string, string> = {\n [ArtifactTypes.CONFIGURATION]: ArtifactIndexFields.CONFIGURATIONS,\n [ArtifactTypes.DATASOURCE]: ArtifactIndexFields.DATA_SOURCES,\n [ArtifactTypes.COMPONENT]: ArtifactIndexFields.COMPONENTS,\n [ArtifactTypes.REPOSITORY]: ArtifactIndexFields.REPOSITORIES,\n [ArtifactTypes.SERVICE]: ArtifactIndexFields.SERVICES,\n [ArtifactTypes.CONTROLLER]: ArtifactIndexFields.CONTROLLERS,\n };\n\n /** The index a decorator-only application has: every class a stereotype saw at import time, bucketed by its type. `when` and `order` still apply - `resolve` does that, exactly as it does for a declared index. */\n buildDiscoveredIndex(): IArtifactIndex {\n const registry = MetadataRegistry.getInstance();\n const index: Record<string, TClass<AnyType>[]> = {};\n\n const discoveredArtifacts = registry.getDiscoveredArtifacts();\n for (const target of discoveredArtifacts) {\n if (!isClass<AnyType>(target)) {\n continue;\n }\n\n const type = registry.getArtifactMetadata({ target })?.type;\n const field = type ? ArtifactIndexHelper.INDEX_FIELD_BY_TYPE[type] : undefined;\n if (!field) {\n continue;\n }\n\n index[field] = [...(index[field] ?? []), target];\n }\n\n return index;\n }\n\n /** Every kind of the input, each already filtered by `when` and sorted by `order`, keyed the way `IArtifactIndex` is. */\n async resolve(opts: {\n input: TArtifactIndexInput;\n application: unknown;\n }): Promise<Required<IArtifactIndex>> {\n const { input, application } = opts;\n const indexes = await this.flatten({ input, application });\n\n const rawConfigurations = await this.select({\n indexes,\n field: ArtifactIndexFields.CONFIGURATIONS,\n application,\n });\n const configurations = this.sortConfigurationsTopologically({\n classes: rawConfigurations,\n });\n\n const dataSources = await this.select({\n indexes,\n field: ArtifactIndexFields.DATA_SOURCES,\n application,\n });\n const components = await this.select({\n indexes,\n field: ArtifactIndexFields.COMPONENTS,\n application,\n });\n const repositories = await this.select({\n indexes,\n field: ArtifactIndexFields.REPOSITORIES,\n application,\n });\n const services = await this.select({\n indexes,\n field: ArtifactIndexFields.SERVICES,\n application,\n });\n const controllers = await this.select({\n indexes,\n field: ArtifactIndexFields.CONTROLLERS,\n application,\n });\n\n return { configurations, dataSources, components, repositories, services, controllers };\n }\n\n /**\n * Topologically sort configurations based on `after` dependencies.\n * Siblings with no dependency relation are sorted deterministically by class name.\n * Throws if an unknown `after` dependency is referenced or if a dependency cycle is detected.\n */\n sortConfigurationsTopologically(opts: { classes: ReadonlyArray<TClass<any>> }): TClass<any>[] {\n const { classes } = opts;\n if (classes.length === 0) {\n return [];\n }\n\n const registry = MetadataRegistry.getInstance();\n\n // Keyed by the class itself: two configurations may share a name (a minified build renames them),\n // and a name-keyed graph silently drops one of them.\n const inDegree = new Map<TClass<any>, number>();\n const adjacency = new Map<TClass<any>, TClass<any>[]>();\n\n for (const target of classes) {\n inDegree.set(target, 0);\n adjacency.set(target, []);\n }\n\n for (const target of classes) {\n const metadata = registry.getArtifactMetadata({ target });\n const afterList = metadata?.after ?? [];\n\n for (const prereq of afterList) {\n // A string names a class, the only form that can; a class is matched by identity.\n const prereqClass =\n typeof prereq === 'function'\n ? classes.find((candidate) => candidate === prereq)\n : classes.find((candidate) => candidate.name === String(prereq));\n\n if (!prereqClass) {\n const prereqName = typeof prereq === 'function' ? prereq.name : String(prereq);\n throw getError({\n message: `[sortConfigurationsTopologically][${target.name}] Declared 'after' dependency '${prereqName}' is not registered as a configuration`,\n });\n }\n\n adjacency.get(prereqClass)!.push(target);\n inDegree.set(target, (inDegree.get(target) ?? 0) + 1);\n }\n }\n\n // Kahn's algorithm. Siblings run in class-name order; a minified build renames classes, so an\n // order that matters belongs in `after`.\n const byName = (a: TClass<any>, b: TClass<any>) => a.name.localeCompare(b.name);\n const available = classes.filter((target) => inDegree.get(target) === 0).sort(byName);\n const sorted: TClass<any>[] = [];\n\n while (available.length > 0) {\n const current = available.shift()!;\n sorted.push(current);\n\n for (const dependent of adjacency.get(current) ?? []) {\n const newDeg = inDegree.get(dependent)! - 1;\n inDegree.set(dependent, newDeg);\n if (newDeg === 0) {\n available.push(dependent);\n available.sort(byName);\n }\n }\n }\n\n if (sorted.length !== classes.length) {\n const unvisited = classes\n .filter((target) => !sorted.includes(target))\n .map((target) => target.name);\n throw getError({\n message: `[sortConfigurationsTopologically] Dependency cycle detected in configurations: ${unvisited.join(', ')}`,\n });\n }\n\n return sorted;\n }\n\n /** Every entry of a kind must be a class. `undefined` is what an import cycle leaves - the index was read before a class's module finished loading - so it gets a message that names the cause instead of a crash on `.name`. */\n private assertClasses(opts: {\n field: string;\n classes: ReadonlyArray<unknown> | undefined;\n }): void {\n const position = (opts.classes ?? []).findIndex((target) => typeof target !== 'function');\n if (position >= 0) {\n throw getError({\n message: `[ArtifactIndex] '${opts.field}' lists an entry that is not a class (position ${position}) | Usually an import cycle: the index was read before that class's module finished loading. The module that imports the index (or @venizia/ignis-boot/auto) must not define decorated classes or be imported by them`,\n });\n }\n }\n\n /** One index, or arrays nested to any depth, as a flat list in input order; a conditional entry contributes its subtree only when its `when` answers true. */\n async flatten(opts: {\n input: TArtifactIndexInput;\n application: unknown;\n }): Promise<IArtifactIndex[]> {\n const { input, application } = opts;\n if (ArtifactGroup.isGroup(input)) {\n return this.flatten({ input: await this.contentOf({ group: input }), application });\n }\n if (Array.isArray(input)) {\n const nested = await Promise.all(\n input.map((entry) => this.flatten({ input: entry, application })),\n );\n return nested.flat();\n }\n\n if (this.isConditional(input)) {\n const isSelected = await input.when({ application });\n if (!isSelected) {\n this.logger.debug('Skipped by condition | conditional index entry');\n return [];\n }\n\n return this.flatten({ input: input.index, application });\n }\n\n return [input];\n }\n\n /** A group's classes: inlined at build time, else the resolver `@venizia/ignis-boot/auto` installs. Never empty - a group that names nothing is a typo or a moved folder. */\n private async contentOf(opts: { group: IArtifactGroup }): Promise<IArtifactIndex> {\n const { group } = opts;\n const content = await ArtifactGroup.resolveContent({ group });\n\n // One element type for the six kinds, so `.map` is callable on every member of the union.\n for (const [field, classes] of Object.entries(content)) {\n this.assertClasses({ field, classes });\n }\n const kinds: Array<ReadonlyArray<TClass<unknown>> | undefined> = Object.values(content);\n const names = kinds.flatMap((classes) => (classes ?? []).map((target) => target.name));\n if (names.length === 0 && !group.kinds) {\n throw getError({\n message: `[ArtifactGroup] '${group.folder ?? '<application>'}' resolved to no class | Defined in ${group.site ?? 'an unknown module'} - check the folder name and that its classes carry a stereotype decorator`,\n });\n }\n this.logger.info('[ArtifactGroup] %s -> %s', group.folder ?? '<application>', names.join(', '));\n return content;\n }\n\n /** Positional on purpose: a type predicate narrows its own parameter, and an options object would narrow the wrapper instead of `input`. */\n private isConditional(\n entry: IArtifactIndex | IConditionalArtifactIndex,\n ): entry is IConditionalArtifactIndex {\n return 'when' in entry && 'index' in entry;\n }\n\n /** The classes of one kind across every index, minus those whose `when` says no, sorted by `order` (stable). The `when` conditions run concurrently: each reads config and environment, never another artifact. */\n async select<Field extends keyof IArtifactIndex>(opts: {\n indexes: IArtifactIndex[];\n field: Field;\n application: unknown;\n }): Promise<NonNullable<IArtifactIndex[Field]>[number][]> {\n const { indexes, field, application } = opts;\n const registry = MetadataRegistry.getInstance();\n\n // De-duplicated: discovery and a declared index can name the same class, and registering it\n // twice trips `bootChecks.binding.allowOverride: false`. First mention wins its position.\n const listed = [...new Set(indexes.flatMap((index) => [...(index[field] ?? [])]))];\n this.assertClasses({ field, classes: listed });\n const decisions = await Promise.all(\n listed.map((target) => this.isSelected({ target, application })),\n );\n\n const kept = listed.filter((target, position) => {\n if (decisions[position]) {\n return true;\n }\n\n this.logger.debug('Skipped by condition | kind: %s | class: %s', field, target.name);\n return false;\n });\n\n return kept\n .map((target, position) => ({\n target,\n position,\n order: registry.getArtifactMetadata({ target })?.order ?? 0,\n }))\n .sort((a, b) => a.order - b.order || a.position - b.position)\n .map((entry) => entry.target);\n }\n\n private async isSelected(opts: {\n target: TClass<unknown>;\n application: unknown;\n }): Promise<boolean> {\n const { target, application } = opts;\n const when = MetadataRegistry.getInstance().getArtifactMetadata({ target })?.when;\n if (!when) {\n return true;\n }\n return when({ application });\n }\n}\n"]}
@@ -35,7 +35,7 @@ export class BootSequence {
35
35
  static indexOf(opts) {
36
36
  const { steps, target } = opts;
37
37
  const matches = steps.flatMap((step, index) => (step.name === target ? [index] : []));
38
- const known = steps.map(step => step.name).join(', ');
38
+ const known = steps.map((step) => step.name).join(', ');
39
39
  switch (matches.length) {
40
40
  case 0: {
41
41
  throw getError({
@@ -1 +1 @@
1
- {"version":3,"file":"boot-sequence.js","sourceRoot":"","sources":["../../../../src/base/applications/boot-sequence.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAEvD,+LAA+L;AAC/L,MAAM,OAAO,SAAS;aACJ,qBAAgB,GAAG,iBAAiB,CAAC;aACrC,uBAAkB,GAAG,mBAAmB,CAAC;aACzC,kBAAa,GAAG,cAAc,CAAC;aAC/B,iCAA4B,GAAG,4BAA4B,CAAC;aAC5D,4BAAuB,GAAG,wBAAwB,CAAC;aACnD,0BAAqB,GAAG,qBAAqB,CAAC;aAC9C,wBAAmB,GAAG,oBAAoB,CAAC;aAC3C,sCAAiC,GAAG,gCAAgC,CAAC;aACrE,yBAAoB,GAAG,qBAAqB,CAAC;aAC7C,mBAAc,GAAG,eAAe,CAAC;aACjC,oBAAe,GAAG,gBAAgB,CAAC;aACnC,eAAU,GAAG,IAAI,GAAG,CAAS;QAC3C,IAAI,CAAC,gBAAgB;QACrB,IAAI,CAAC,kBAAkB;QACvB,IAAI,CAAC,aAAa;QAClB,IAAI,CAAC,4BAA4B;QACjC,IAAI,CAAC,uBAAuB;QAC5B,IAAI,CAAC,qBAAqB;QAC1B,IAAI,CAAC,mBAAmB;QACxB,IAAI,CAAC,iCAAiC;QACtC,IAAI,CAAC,oBAAoB;QACzB,IAAI,CAAC,cAAc;QACnB,IAAI,CAAC,eAAe;KACrB,CAAC,CAAC;IAEH,MAAM,CAAC,OAAO,CAAC,KAAa;QAC1B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;;AAUH,2KAA2K;AAC3K,MAAM,OAAO,YAAY;IACvB,2IAA2I;IACnI,MAAM,CAAC,OAAO,CAAC,IAAoD;QACzE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtF,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEtD,QAAQ,OAAO,CAAC,MAAM,EAAE,CAAC;YACvB,KAAK,CAAC,CAAC,CAAC,CAAC;gBACP,MAAM,QAAQ,CAAC;oBACb,OAAO,EAAE,iCAAiC,MAAM,oBAAoB,KAAK,EAAE;iBAC5E,CAAC,CAAC;YACL,CAAC;YACD,KAAK,CAAC,CAAC,CAAC,CAAC;gBACP,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;YACD,OAAO,CAAC,CAAC,CAAC;gBACR,MAAM,QAAQ,CAAC;oBACb,OAAO,EAAE,mCAAmC,MAAM,aAAa,OAAO,CAAC,MAAM,yBAAyB,KAAK,EAAE;iBAC9G,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,IAIlB;QACC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;QACrC,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAEtD,OAAO,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC;CACF","sourcesContent":["import type { TConstValue, ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\n\n/** The step names the kernel defines - the vocabulary a subclass targets with `BootSequence.insertAfter`. A server application adds its own on top (`ServerBootSteps` in `@venizia/ignis`). */\nexport class BootSteps {\n static readonly STATIC_CONFIGURE = 'staticConfigure';\n static readonly REGISTER_ARTIFACTS = 'registerArtifacts';\n static readonly PRE_CONFIGURE = 'preConfigure';\n static readonly REGISTER_DEFAULT_MIDDLEWARES = 'registerDefaultMiddlewares';\n static readonly REGISTER_CONFIGURATIONS = 'registerConfigurations';\n static readonly REGISTER_DATA_SOURCES = 'registerDataSources';\n static readonly REGISTER_COMPONENTS = 'registerComponents';\n static readonly REGISTER_CONTRIBUTED_DATA_SOURCES = 'registerContributedDataSources';\n static readonly REGISTER_CONTROLLERS = 'registerControllers';\n static readonly POST_CONFIGURE = 'postConfigure';\n static readonly VERIFY_BINDINGS = 'verifyBindings';\n static readonly SCHEME_SET = new Set<string>([\n this.STATIC_CONFIGURE,\n this.REGISTER_ARTIFACTS,\n this.PRE_CONFIGURE,\n this.REGISTER_DEFAULT_MIDDLEWARES,\n this.REGISTER_CONFIGURATIONS,\n this.REGISTER_DATA_SOURCES,\n this.REGISTER_COMPONENTS,\n this.REGISTER_CONTRIBUTED_DATA_SOURCES,\n this.REGISTER_CONTROLLERS,\n this.POST_CONFIGURE,\n this.VERIFY_BINDINGS,\n ]);\n\n static isValid(value: string): boolean {\n return this.SCHEME_SET.has(value);\n }\n}\n\nexport type TBootStep = TConstValue<typeof BootSteps>;\n\nexport interface IBootSequenceStep {\n name: string;\n run: () => ValueOrPromise<void>;\n}\n\n/** Composes a boot sequence by name instead of copying the array - a subclass reads exactly what it adds by reading its own override, without diffing two files by eye. */\nexport class BootSequence {\n /** A duplicated name is refused as loudly as a missing one - picking the first match would splice a step into the wrong place silently. */\n private static indexOf(opts: { steps: IBootSequenceStep[]; target: string }): number {\n const { steps, target } = opts;\n const matches = steps.flatMap((step, index) => (step.name === target ? [index] : []));\n const known = steps.map(step => step.name).join(', ');\n\n switch (matches.length) {\n case 0: {\n throw getError({\n message: `[BootSequence] Unknown step: '${target}' | Known steps: ${known}`,\n });\n }\n case 1: {\n return matches[0];\n }\n default: {\n throw getError({\n message: `[BootSequence] Ambiguous step: '${target}' appears ${matches.length} times | Known steps: ${known}`,\n });\n }\n }\n }\n\n static insertAfter(opts: {\n steps: IBootSequenceStep[];\n target: string;\n step: IBootSequenceStep;\n }): IBootSequenceStep[] {\n const { steps, target, step } = opts;\n const index = BootSequence.indexOf({ steps, target });\n\n return [...steps.slice(0, index + 1), step, ...steps.slice(index + 1)];\n }\n}\n"]}
1
+ {"version":3,"file":"boot-sequence.js","sourceRoot":"","sources":["../../../../src/base/applications/boot-sequence.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAEvD,+LAA+L;AAC/L,MAAM,OAAO,SAAS;aACJ,qBAAgB,GAAG,iBAAiB,CAAC;aACrC,uBAAkB,GAAG,mBAAmB,CAAC;aACzC,kBAAa,GAAG,cAAc,CAAC;aAC/B,iCAA4B,GAAG,4BAA4B,CAAC;aAC5D,4BAAuB,GAAG,wBAAwB,CAAC;aACnD,0BAAqB,GAAG,qBAAqB,CAAC;aAC9C,wBAAmB,GAAG,oBAAoB,CAAC;aAC3C,sCAAiC,GAAG,gCAAgC,CAAC;aACrE,yBAAoB,GAAG,qBAAqB,CAAC;aAC7C,mBAAc,GAAG,eAAe,CAAC;aACjC,oBAAe,GAAG,gBAAgB,CAAC;aACnC,eAAU,GAAG,IAAI,GAAG,CAAS;QAC3C,IAAI,CAAC,gBAAgB;QACrB,IAAI,CAAC,kBAAkB;QACvB,IAAI,CAAC,aAAa;QAClB,IAAI,CAAC,4BAA4B;QACjC,IAAI,CAAC,uBAAuB;QAC5B,IAAI,CAAC,qBAAqB;QAC1B,IAAI,CAAC,mBAAmB;QACxB,IAAI,CAAC,iCAAiC;QACtC,IAAI,CAAC,oBAAoB;QACzB,IAAI,CAAC,cAAc;QACnB,IAAI,CAAC,eAAe;KACrB,CAAC,CAAC;IAEH,MAAM,CAAC,OAAO,CAAC,KAAa;QAC1B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACpC,CAAC;;AAUH,2KAA2K;AAC3K,MAAM,OAAO,YAAY;IACvB,2IAA2I;IACnI,MAAM,CAAC,OAAO,CAAC,IAAoD;QACzE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtF,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAExD,QAAQ,OAAO,CAAC,MAAM,EAAE,CAAC;YACvB,KAAK,CAAC,CAAC,CAAC,CAAC;gBACP,MAAM,QAAQ,CAAC;oBACb,OAAO,EAAE,iCAAiC,MAAM,oBAAoB,KAAK,EAAE;iBAC5E,CAAC,CAAC;YACL,CAAC;YACD,KAAK,CAAC,CAAC,CAAC,CAAC;gBACP,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;YACpB,CAAC;YACD,OAAO,CAAC,CAAC,CAAC;gBACR,MAAM,QAAQ,CAAC;oBACb,OAAO,EAAE,mCAAmC,MAAM,aAAa,OAAO,CAAC,MAAM,yBAAyB,KAAK,EAAE;iBAC9G,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,IAIlB;QACC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;QACrC,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAEtD,OAAO,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC;IACzE,CAAC;CACF","sourcesContent":["import type { TConstValue, ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\n\n/** The step names the kernel defines - the vocabulary a subclass targets with `BootSequence.insertAfter`. A server application adds its own on top (`ServerBootSteps` in `@venizia/ignis`). */\nexport class BootSteps {\n static readonly STATIC_CONFIGURE = 'staticConfigure';\n static readonly REGISTER_ARTIFACTS = 'registerArtifacts';\n static readonly PRE_CONFIGURE = 'preConfigure';\n static readonly REGISTER_DEFAULT_MIDDLEWARES = 'registerDefaultMiddlewares';\n static readonly REGISTER_CONFIGURATIONS = 'registerConfigurations';\n static readonly REGISTER_DATA_SOURCES = 'registerDataSources';\n static readonly REGISTER_COMPONENTS = 'registerComponents';\n static readonly REGISTER_CONTRIBUTED_DATA_SOURCES = 'registerContributedDataSources';\n static readonly REGISTER_CONTROLLERS = 'registerControllers';\n static readonly POST_CONFIGURE = 'postConfigure';\n static readonly VERIFY_BINDINGS = 'verifyBindings';\n static readonly SCHEME_SET = new Set<string>([\n this.STATIC_CONFIGURE,\n this.REGISTER_ARTIFACTS,\n this.PRE_CONFIGURE,\n this.REGISTER_DEFAULT_MIDDLEWARES,\n this.REGISTER_CONFIGURATIONS,\n this.REGISTER_DATA_SOURCES,\n this.REGISTER_COMPONENTS,\n this.REGISTER_CONTRIBUTED_DATA_SOURCES,\n this.REGISTER_CONTROLLERS,\n this.POST_CONFIGURE,\n this.VERIFY_BINDINGS,\n ]);\n\n static isValid(value: string): boolean {\n return this.SCHEME_SET.has(value);\n }\n}\n\nexport type TBootStep = TConstValue<typeof BootSteps>;\n\nexport interface IBootSequenceStep {\n name: string;\n run: () => ValueOrPromise<void>;\n}\n\n/** Composes a boot sequence by name instead of copying the array - a subclass reads exactly what it adds by reading its own override, without diffing two files by eye. */\nexport class BootSequence {\n /** A duplicated name is refused as loudly as a missing one - picking the first match would splice a step into the wrong place silently. */\n private static indexOf(opts: { steps: IBootSequenceStep[]; target: string }): number {\n const { steps, target } = opts;\n const matches = steps.flatMap((step, index) => (step.name === target ? [index] : []));\n const known = steps.map((step) => step.name).join(', ');\n\n switch (matches.length) {\n case 0: {\n throw getError({\n message: `[BootSequence] Unknown step: '${target}' | Known steps: ${known}`,\n });\n }\n case 1: {\n return matches[0];\n }\n default: {\n throw getError({\n message: `[BootSequence] Ambiguous step: '${target}' appears ${matches.length} times | Known steps: ${known}`,\n });\n }\n }\n }\n\n static insertAfter(opts: {\n steps: IBootSequenceStep[];\n target: string;\n step: IBootSequenceStep;\n }): IBootSequenceStep[] {\n const { steps, target, step } = opts;\n const index = BootSequence.indexOf({ steps, target });\n\n return [...steps.slice(0, index + 1), step, ...steps.slice(index + 1)];\n }\n}\n"]}