@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
@@ -0,0 +1,56 @@
1
+ import { AuthorizationActions } from '../../auth/authorize/common/constants/index.js';
2
+ import { getError } from '@venizia/ignis-helpers/core';
3
+ /** The generated routes that change data: the ones that must never be answered by a `read` permission. */
4
+ const WRITE_VERBS = ['create', 'updateById', 'updateBy', 'deleteById', 'deleteBy'];
5
+ const describeSpec = (spec) => {
6
+ return `{ action: ${String(spec.action)}, resource: ${String(spec.resource)} }`;
7
+ };
8
+ /**
9
+ * Refuses a CRUD controller whose enabled write verb would inherit a controller-level `authorize`
10
+ * that is only a `read` permission: the verb would then answer to anyone who may read.
11
+ *
12
+ * A write verb is fine when it declares its own `authorize` (a spec, an array, or `{ skip: true }`),
13
+ * skips authentication, is not enabled, or the controller is `readonly`. Only the literal action
14
+ * `read` is detected; a custom action name is the application's own vocabulary. An array counts when
15
+ * every spec in it is `read`, since the specs of one route must all pass.
16
+ */
17
+ export const assertWriteVerbsDeclareAuthorize = (opts) => {
18
+ const { controllerName, authorize, routes, readonly, enabledRoutes } = opts;
19
+ if (readonly || authorize == null) {
20
+ return;
21
+ }
22
+ const specs = Array.isArray(authorize) ? authorize : [authorize];
23
+ const isReadOnlyPermission = specs.length > 0 && specs.every((spec) => spec.action === AuthorizationActions.READ);
24
+ if (!isReadOnlyPermission) {
25
+ return;
26
+ }
27
+ const offending = WRITE_VERBS.filter((verb) => {
28
+ const isEnabled = enabledRoutes
29
+ ? enabledRoutes.includes(verb)
30
+ : routes?.[verb]?.enabled !== false;
31
+ if (!isEnabled) {
32
+ return false;
33
+ }
34
+ const route = routes?.[verb];
35
+ return route?.authenticate?.skip !== true && route?.authorize == null;
36
+ });
37
+ if (offending.length === 0) {
38
+ return;
39
+ }
40
+ const inherited = specs.map(describeSpec).join(', ');
41
+ const verbs = offending.map((verb) => `${controllerName}.${verb}`).join(', ');
42
+ const hasBulkVerb = offending.some((verb) => verb === 'updateBy' || verb === 'deleteBy');
43
+ throw getError({
44
+ message: [
45
+ `[defineCrudController] Write routes would inherit a read-only authorize | controller: ${controllerName} | routes: ${verbs} | inherited: ${inherited}`,
46
+ 'Anyone allowed to read could then create, update or delete.',
47
+ `Fix: declare routes.<verb>.authorize for each of them (a spec, an array or { skip: true }), or set controller.readonly, or leave them out of controller.enabledRoutes.`,
48
+ ...(hasBulkVerb
49
+ ? [
50
+ 'updateBy and deleteBy are bulk routes on the collection and are generated unless controller.enabledRoutes lists the routes you want, so dropping them there closes this too.',
51
+ ]
52
+ : []),
53
+ ].join(' | '),
54
+ });
55
+ };
56
+ //# sourceMappingURL=authorize-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorize-guard.js","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/authorize-guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AAE9E,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAGvD,0GAA0G;AAC1G,MAAM,WAAW,GAAG,CAAC,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,CAAU,CAAC;AAE5F,MAAM,YAAY,GAAG,CAAC,IAAwB,EAAU,EAAE;IACxD,OAAO,aAAa,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;AAClF,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,CAAC,IAMhD,EAAQ,EAAE;IACT,MAAM,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IAE5E,IAAI,QAAQ,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;QAClC,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACjE,MAAM,oBAAoB,GACxB,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,oBAAoB,CAAC,IAAI,CAAC,CAAC;IAEvF,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC1B,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QAC5C,MAAM,SAAS,GAAG,aAAa;YAC7B,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC9B,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,KAAK,KAAK,CAAC;QACtC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;QAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,IAAI,KAAK,IAAI,IAAI,KAAK,EAAE,SAAS,IAAI,IAAI,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,cAAc,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9E,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,UAAU,IAAI,IAAI,KAAK,UAAU,CAAC,CAAC;IAEzF,MAAM,QAAQ,CAAC;QACb,OAAO,EAAE;YACP,yFAAyF,cAAc,cAAc,KAAK,iBAAiB,SAAS,EAAE;YACtJ,6DAA6D;YAC7D,wKAAwK;YACxK,GAAG,CAAC,WAAW;gBACb,CAAC,CAAC;oBACE,8KAA8K;iBAC/K;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,IAAI,CAAC,KAAK,CAAC;KACd,CAAC,CAAC;AACL,CAAC,CAAC","sourcesContent":["import { AuthorizationActions } from '@/base/auth/authorize/common/constants';\nimport type { IAuthorizationSpec } from '@/base/auth/authorize/common/types';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport type { ICustomizableRoutes } from '../common';\n\n/** The generated routes that change data: the ones that must never be answered by a `read` permission. */\nconst WRITE_VERBS = ['create', 'updateById', 'updateBy', 'deleteById', 'deleteBy'] as const;\n\nconst describeSpec = (spec: IAuthorizationSpec): string => {\n return `{ action: ${String(spec.action)}, resource: ${String(spec.resource)} }`;\n};\n\n/**\n * Refuses a CRUD controller whose enabled write verb would inherit a controller-level `authorize`\n * that is only a `read` permission: the verb would then answer to anyone who may read.\n *\n * A write verb is fine when it declares its own `authorize` (a spec, an array, or `{ skip: true }`),\n * skips authentication, is not enabled, or the controller is `readonly`. Only the literal action\n * `read` is detected; a custom action name is the application's own vocabulary. An array counts when\n * every spec in it is `read`, since the specs of one route must all pass.\n */\nexport const assertWriteVerbsDeclareAuthorize = (opts: {\n controllerName: string;\n authorize: IAuthorizationSpec | IAuthorizationSpec[] | undefined;\n routes: ICustomizableRoutes | undefined;\n readonly: boolean | undefined;\n enabledRoutes: Array<keyof ICustomizableRoutes> | undefined;\n}): void => {\n const { controllerName, authorize, routes, readonly, enabledRoutes } = opts;\n\n if (readonly || authorize == null) {\n return;\n }\n\n const specs = Array.isArray(authorize) ? authorize : [authorize];\n const isReadOnlyPermission =\n specs.length > 0 && specs.every((spec) => spec.action === AuthorizationActions.READ);\n\n if (!isReadOnlyPermission) {\n return;\n }\n\n const offending = WRITE_VERBS.filter((verb) => {\n const isEnabled = enabledRoutes\n ? enabledRoutes.includes(verb)\n : routes?.[verb]?.enabled !== false;\n if (!isEnabled) {\n return false;\n }\n\n const route = routes?.[verb];\n return route?.authenticate?.skip !== true && route?.authorize == null;\n });\n\n if (offending.length === 0) {\n return;\n }\n\n const inherited = specs.map(describeSpec).join(', ');\n const verbs = offending.map((verb) => `${controllerName}.${verb}`).join(', ');\n const hasBulkVerb = offending.some((verb) => verb === 'updateBy' || verb === 'deleteBy');\n\n throw getError({\n message: [\n `[defineCrudController] Write routes would inherit a read-only authorize | controller: ${controllerName} | routes: ${verbs} | inherited: ${inherited}`,\n 'Anyone allowed to read could then create, update or delete.',\n `Fix: declare routes.<verb>.authorize for each of them (a spec, an array or { skip: true }), or set controller.readonly, or leave them out of controller.enabledRoutes.`,\n ...(hasBulkVerb\n ? [\n 'updateBy and deleteBy are bulk routes on the collection and are generated unless controller.enabledRoutes lists the routes you want, so dropping them there closes this too.',\n ]\n : []),\n ].join(' | '),\n });\n};\n"]}
@@ -1,7 +1,7 @@
1
1
  import type { AbstractEntity } from '../../models/index.js';
2
2
  import type { AbstractRepository } from '../../repositories/index.js';
3
3
  import type { TAnyObjectSchema } from '../common/schema-builders.js';
4
- import type { ValueOrPromise } from '@venizia/ignis-helpers/common';
4
+ import type { AnyType, ValueOrPromise } from '@venizia/ignis-helpers/common';
5
5
  import { BaseHelper } from '@venizia/ignis-helpers/core';
6
6
  import type { Env, Schema } from 'hono';
7
7
  import type { ICrudControllerOptions, ICustomizableRoutes, TEntityDataObject, TEntityPersistObject } from '../common/index.js';
@@ -9,7 +9,7 @@ import type { ICrudControllerOptions, ICustomizableRoutes, TEntityDataObject, TE
9
9
  export declare class ControllerFactory extends BaseHelper {
10
10
  constructor();
11
11
  static defineCrudController<TEntity extends AbstractEntity<TAnyObjectSchema> = AbstractEntity<TAnyObjectSchema>, Routes extends ICustomizableRoutes = ICustomizableRoutes, RouteEnv extends Env = Env, RouteSchema extends Schema = {}, BasePath extends string = '/', ConfigurableOptions extends object = {}, TDataObject extends object = TEntityDataObject<TEntity>, TPersistObject extends object = TEntityPersistObject<TEntity>>(defOpts: ICrudControllerOptions<TEntity, Routes>): {
12
- new (repository: AbstractRepository<TDataObject, TPersistObject>): {
12
+ new (repository: AbstractRepository<TDataObject, TPersistObject, AnyType>): {
13
13
  /** Registers each CRUD route whose handler tier supplies it, honoring enabledRoutes/readonly. */
14
14
  binding(): ValueOrPromise<void>;
15
15
  create(opts: {
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,UAAU,EAAY,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,WAAW,CAAC;AAKnB,6EAA6E;AAC7E,qBAAa,iBAAkB,SAAQ,UAAU;;IAK/C,MAAM,CAAC,oBAAoB,CACzB,OAAO,SAAS,cAAc,CAAC,gBAAgB,CAAC,GAAG,cAAc,CAAC,gBAAgB,CAAC,EACnF,MAAM,SAAS,mBAAmB,GAAG,mBAAmB,EACxD,QAAQ,SAAS,GAAG,GAAG,GAAG,EAC1B,WAAW,SAAS,MAAM,GAAG,EAAE,EAC/B,QAAQ,SAAS,MAAM,GAAG,GAAG,EAC7B,mBAAmB,SAAS,MAAM,GAAG,EAAE,EACvC,WAAW,SAAS,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,EACvD,cAAc,SAAS,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,EAC7D,OAAO,EAAE,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC;yBAwCtB,kBAAkB,CAAC,WAAW,EAAE,cAAc,CAAC;YAUvE,iGAAiG;uBAC7E,cAAc,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBADkB,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyF/D"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/controller.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAY,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,WAAW,CAAC;AAMnB,6EAA6E;AAC7E,qBAAa,iBAAkB,SAAQ,UAAU;;IAK/C,MAAM,CAAC,oBAAoB,CACzB,OAAO,SAAS,cAAc,CAAC,gBAAgB,CAAC,GAAG,cAAc,CAAC,gBAAgB,CAAC,EACnF,MAAM,SAAS,mBAAmB,GAAG,mBAAmB,EACxD,QAAQ,SAAS,GAAG,GAAG,GAAG,EAC1B,WAAW,SAAS,MAAM,GAAG,EAAE,EAC/B,QAAQ,SAAS,MAAM,GAAG,GAAG,EAC7B,mBAAmB,SAAS,MAAM,GAAG,EAAE,EACvC,WAAW,SAAS,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,EACvD,cAAc,SAAS,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,EAC7D,OAAO,EAAE,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC;yBAiDtB,kBAAkB,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,CAAC;YAUhF,iGAAiG;uBAC7E,cAAc,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAZoB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoGlE"}
@@ -2,6 +2,7 @@ import { SchemaTypes } from '../../models/common/constants.js';
2
2
  import { BaseHelper, getError } from '@venizia/ignis-helpers/core';
3
3
  import { isClass } from '@venizia/ignis-inversion';
4
4
  import { PersistableCrudController } from './crud/index.js';
5
+ import { assertWriteVerbsDeclareAuthorize } from './authorize-guard.js';
5
6
  import { defineControllerRouteConfigs } from './definition.js';
6
7
  import { registerFactoryRepositoryInjection } from './repository-injection.js';
7
8
  /** Factory for generating typed CRUD controllers from entity definitions. */
@@ -17,6 +18,13 @@ export class ControllerFactory extends BaseHelper {
17
18
  message: `[defineCrudController] Invalid controller basePath | name: ${name} | basePath: ${basePath}`,
18
19
  });
19
20
  }
21
+ assertWriteVerbsDeclareAuthorize({
22
+ controllerName: name,
23
+ authorize,
24
+ routes,
25
+ readonly: controller.readonly,
26
+ enabledRoutes: controller.enabledRoutes,
27
+ });
20
28
  const entityClass = isClass(entity) ? entity : entity();
21
29
  const entityInstance = new entityClass();
22
30
  const routeDefinitions = defineControllerRouteConfigs({
@@ -33,6 +41,7 @@ export class ControllerFactory extends BaseHelper {
33
41
  serverStampedKeys: entityInstance.getServerStampedKeys(),
34
42
  });
35
43
  const controllerClass = class extends PersistableCrudController {
44
+ // Any extra options: a repository whose options narrow `IExtraOptions` (a typed transaction) must fit.
36
45
  constructor(repository) {
37
46
  super({
38
47
  scope: name,
@@ -1 +1 @@
1
- {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAI7D,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAQnD,OAAO,EAAE,yBAAyB,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,EAAE,4BAA4B,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,kCAAkC,EAAE,MAAM,wBAAwB,CAAC;AAE5E,6EAA6E;AAC7E,MAAM,OAAO,iBAAkB,SAAQ,UAAU;IAC/C;QACE,KAAK,CAAC,EAAE,KAAK,EAAE,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,CAAC,oBAAoB,CASzB,OAAgD;QAChD,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAExE,MAAM,EACJ,IAAI,EACJ,QAAQ,GAAG,cAAc,EACzB,QAAQ,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,GAC/C,GAAG,UAAU,CAAC;QACf,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,cAAc,EAAE,CAAC;YAC7C,MAAM,QAAQ,CAAC;gBACb,OAAO,EAAE,8DAA8D,IAAI,gBAAgB,QAAQ,EAAE;aACtG,CAAC,CAAC;QACL,CAAC;QAED,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACxD,MAAM,cAAc,GAAG,IAAI,WAAW,EAAE,CAAC;QAEzC,MAAM,gBAAgB,GAAG,4BAA4B,CAAC;YACpD,QAAQ,EAAE,QAAQ,CAAC,aAAa,IAAI,IAAI;YACxC,MAAM,EAAE,cAAc,CAAC,SAAS,EAAE;YAClC,YAAY;YACZ,SAAS;YACT,MAAM;YACN,MAAM,EAAE;gBACN,MAAM,EAAE,cAAc,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC;gBAC9D,MAAM,EAAE,cAAc,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC;gBAC9D,MAAM,EAAE,cAAc,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,EAAE,CAAC;aAC/D;YACD,iBAAiB,EAAE,cAAc,CAAC,oBAAoB,EAAE;SACzD,CAAC,CAAC;QAEH,MAAM,eAAe,GAAG,KAAM,SAAQ,yBAQrC;YACC,YAAY,UAA2D;gBACrE,KAAK,CAAC;oBACJ,KAAK,EAAE,IAAI;oBACX,IAAI,EAAE,QAAQ;oBACd,QAAQ,EAAE,QAAQ,CAAC,IAAI,IAAI,IAAI;oBAC/B,UAAU;oBACV,WAAW,EAAE,gBAAgB;iBAC9B,CAAC,CAAC;YACL,CAAC;YAED,iGAAiG;YACxF,OAAO;gBACd,MAAM,SAAS,GAAG,CAAC,QAAmC,EAAE,EAAE;oBACxD,IAAI,UAAU,CAAC,aAAa,EAAE,CAAC;wBAC7B,OAAO,UAAU,CAAC,aAAa,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;oBACrD,CAAC;oBACD,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,KAAK,KAAK,CAAC;gBAC/C,CAAC,CAAC;gBAEF,+DAA+D;gBAC/D,IAAI,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;oBACvB,IAAI,CAAC,WAAW,CAAC;wBACf,OAAO,EAAE,gBAAgB,CAAC,KAAK;wBAC/B,OAAO,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;qBAClD,CAAC,CAAC;gBACL,CAAC;gBAED,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;oBACtB,IAAI,CAAC,WAAW,CAAC;wBACf,OAAO,EAAE,gBAAgB,CAAC,IAAI;wBAC9B,OAAO,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;qBACjD,CAAC,CAAC;gBACL,CAAC;gBAED,IAAI,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;oBACzB,IAAI,CAAC,WAAW,CAAC;wBACf,OAAO,EAAE,gBAAgB,CAAC,QAAQ;wBAClC,OAAO,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;qBACpD,CAAC,CAAC;gBACL,CAAC;gBAED,IAAI,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC1B,IAAI,CAAC,WAAW,CAAC;wBACf,OAAO,EAAE,gBAAgB,CAAC,UAAU;wBACpC,OAAO,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;qBACrD,CAAC,CAAC;gBACL,CAAC;gBAED,uCAAuC;gBACvC,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;oBACxB,OAAO;gBACT,CAAC;gBAED,IAAI,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;oBACxB,IAAI,CAAC,WAAW,CAAC;wBACf,OAAO,EAAE,gBAAgB,CAAC,MAAM;wBAChC,OAAO,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;qBACnD,CAAC,CAAC;gBACL,CAAC;gBAED,IAAI,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC;oBAC5B,IAAI,CAAC,WAAW,CAAC;wBACf,OAAO,EAAE,gBAAgB,CAAC,YAAY;wBACtC,OAAO,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;qBACvD,CAAC,CAAC;gBACL,CAAC;gBAED,IAAI,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC1B,IAAI,CAAC,WAAW,CAAC;wBACf,OAAO,EAAE,gBAAgB,CAAC,SAAS;wBACnC,OAAO,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;qBACrD,CAAC,CAAC;gBACL,CAAC;gBAED,IAAI,SAAS,CAAC,YAAY,CAAC,EAAE,CAAC;oBAC5B,IAAI,CAAC,WAAW,CAAC;wBACf,OAAO,EAAE,gBAAgB,CAAC,YAAY;wBACtC,OAAO,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;qBACvD,CAAC,CAAC;gBACL,CAAC;gBAED,IAAI,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;oBAC1B,IAAI,CAAC,WAAW,CAAC;wBACf,OAAO,EAAE,gBAAgB,CAAC,SAAS;wBACnC,OAAO,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;qBACrD,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;QAEF,MAAM,CAAC,cAAc,CAAC,eAAe,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;QACpF,kCAAkC,CAAC;YACjC,MAAM,EAAE,eAAe;YACvB,WAAW,EAAE,sBAAsB;YACnC,cAAc,EAAE,IAAI;YACpB,cAAc,EAAE,OAAO,CAAC,UAAU,CAAC,IAAI;SACxC,CAAC,CAAC;QACH,OAAO,eAAe,CAAC;IACzB,CAAC;CACF","sourcesContent":["import type { AbstractEntity } from '@/base/models';\nimport { SchemaTypes } from '@/base/models/common/constants';\nimport type { AbstractRepository } from '@/base/repositories';\nimport type { TAnyObjectSchema } from '@/base/controllers/common/schema-builders';\nimport type { ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport { isClass } from '@venizia/ignis-inversion';\nimport type { Env, Schema } from 'hono';\nimport type {\n ICrudControllerOptions,\n ICustomizableRoutes,\n TEntityDataObject,\n TEntityPersistObject,\n} from '../common';\nimport { PersistableCrudController } from './crud';\nimport { defineControllerRouteConfigs } from './definition';\nimport { registerFactoryRepositoryInjection } from './repository-injection';\n\n/** Factory for generating typed CRUD controllers from entity definitions. */\nexport class ControllerFactory extends BaseHelper {\n constructor() {\n super({ scope: ControllerFactory.name });\n }\n\n static defineCrudController<\n TEntity extends AbstractEntity<TAnyObjectSchema> = AbstractEntity<TAnyObjectSchema>,\n Routes extends ICustomizableRoutes = ICustomizableRoutes,\n RouteEnv extends Env = Env,\n RouteSchema extends Schema = {},\n BasePath extends string = '/',\n ConfigurableOptions extends object = {},\n TDataObject extends object = TEntityDataObject<TEntity>,\n TPersistObject extends object = TEntityPersistObject<TEntity>,\n >(defOpts: ICrudControllerOptions<TEntity, Routes>) {\n const { controller, entity, authenticate, authorize, routes } = defOpts;\n\n const {\n name,\n basePath = 'unknown_path',\n isStrict = { path: true, requestSchema: true },\n } = controller;\n if (!basePath || basePath === 'unknown_path') {\n throw getError({\n message: `[defineCrudController] Invalid controller basePath | name: ${name} | basePath: ${basePath}`,\n });\n }\n\n const entityClass = isClass(entity) ? entity : entity();\n const entityInstance = new entityClass();\n\n const routeDefinitions = defineControllerRouteConfigs({\n isStrict: isStrict.requestSchema ?? true,\n idType: entityInstance.getIdType(),\n authenticate,\n authorize,\n routes,\n schema: {\n select: entityInstance.getSchema({ type: SchemaTypes.SELECT }),\n create: entityInstance.getSchema({ type: SchemaTypes.CREATE }),\n update: entityInstance.getSchema({ type: SchemaTypes.UPDATE }),\n },\n serverStampedKeys: entityInstance.getServerStampedKeys(),\n });\n\n const controllerClass = class extends PersistableCrudController<\n TEntity,\n RouteEnv,\n RouteSchema,\n BasePath,\n ConfigurableOptions,\n TDataObject,\n TPersistObject\n > {\n constructor(repository: AbstractRepository<TDataObject, TPersistObject>) {\n super({\n scope: name,\n path: basePath,\n isStrict: isStrict.path ?? true,\n repository,\n definitions: routeDefinitions,\n });\n }\n\n /** Registers each CRUD route whose handler tier supplies it, honoring enabledRoutes/readonly. */\n override binding(): ValueOrPromise<void> {\n const isEnabled = (routeKey: keyof ICustomizableRoutes) => {\n if (controller.enabledRoutes) {\n return controller.enabledRoutes.includes(routeKey);\n }\n return routes?.[routeKey]?.enabled !== false;\n };\n\n // Read routes - always registered (unless explicitly disabled)\n if (isEnabled('count')) {\n this.defineRoute({\n configs: routeDefinitions.COUNT,\n handler: async context => this.count({ context }),\n });\n }\n\n if (isEnabled('find')) {\n this.defineRoute({\n configs: routeDefinitions.FIND,\n handler: async context => this.find({ context }),\n });\n }\n\n if (isEnabled('findOne')) {\n this.defineRoute({\n configs: routeDefinitions.FIND_ONE,\n handler: async context => this.findOne({ context }),\n });\n }\n\n if (isEnabled('findById')) {\n this.defineRoute({\n configs: routeDefinitions.FIND_BY_ID,\n handler: async context => this.findById({ context }),\n });\n }\n\n // Write routes - skipped when readonly\n if (controller.readonly) {\n return;\n }\n\n if (isEnabled('create')) {\n this.defineRoute({\n configs: routeDefinitions.CREATE,\n handler: async context => this.create({ context }),\n });\n }\n\n if (isEnabled('updateById')) {\n this.defineRoute({\n configs: routeDefinitions.UPDATE_BY_ID,\n handler: async context => this.updateById({ context }),\n });\n }\n\n if (isEnabled('updateBy')) {\n this.defineRoute({\n configs: routeDefinitions.UPDATE_BY,\n handler: async context => this.updateBy({ context }),\n });\n }\n\n if (isEnabled('deleteById')) {\n this.defineRoute({\n configs: routeDefinitions.DELETE_BY_ID,\n handler: async context => this.deleteById({ context }),\n });\n }\n\n if (isEnabled('deleteBy')) {\n this.defineRoute({\n configs: routeDefinitions.DELETE_BY,\n handler: async context => this.deleteBy({ context }),\n });\n }\n }\n };\n\n Object.defineProperty(controllerClass, 'name', { value: name, configurable: true });\n registerFactoryRepositoryInjection({\n target: controllerClass,\n factoryName: 'defineCrudController',\n controllerName: name,\n repositoryName: defOpts.repository.name,\n });\n return controllerClass;\n }\n}\n"]}
1
+ {"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AbstractEntity } from '@/base/models';\nimport { SchemaTypes } from '@/base/models/common/constants';\nimport type { AbstractRepository } from '@/base/repositories';\nimport type { TAnyObjectSchema } from '@/base/controllers/common/schema-builders';\nimport type { AnyType, ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport { isClass } from '@venizia/ignis-inversion';\nimport type { Env, Schema } from 'hono';\nimport type {\n ICrudControllerOptions,\n ICustomizableRoutes,\n TEntityDataObject,\n TEntityPersistObject,\n} from '../common';\nimport { PersistableCrudController } from './crud';\nimport { assertWriteVerbsDeclareAuthorize } from './authorize-guard';\nimport { defineControllerRouteConfigs } from './definition';\nimport { registerFactoryRepositoryInjection } from './repository-injection';\n\n/** Factory for generating typed CRUD controllers from entity definitions. */\nexport class ControllerFactory extends BaseHelper {\n constructor() {\n super({ scope: ControllerFactory.name });\n }\n\n static defineCrudController<\n TEntity extends AbstractEntity<TAnyObjectSchema> = AbstractEntity<TAnyObjectSchema>,\n Routes extends ICustomizableRoutes = ICustomizableRoutes,\n RouteEnv extends Env = Env,\n RouteSchema extends Schema = {},\n BasePath extends string = '/',\n ConfigurableOptions extends object = {},\n TDataObject extends object = TEntityDataObject<TEntity>,\n TPersistObject extends object = TEntityPersistObject<TEntity>,\n >(defOpts: ICrudControllerOptions<TEntity, Routes>) {\n const { controller, entity, authenticate, authorize, routes } = defOpts;\n\n const {\n name,\n basePath = 'unknown_path',\n isStrict = { path: true, requestSchema: true },\n } = controller;\n if (!basePath || basePath === 'unknown_path') {\n throw getError({\n message: `[defineCrudController] Invalid controller basePath | name: ${name} | basePath: ${basePath}`,\n });\n }\n\n assertWriteVerbsDeclareAuthorize({\n controllerName: name,\n authorize,\n routes,\n readonly: controller.readonly,\n enabledRoutes: controller.enabledRoutes,\n });\n\n const entityClass = isClass(entity) ? entity : entity();\n const entityInstance = new entityClass();\n\n const routeDefinitions = defineControllerRouteConfigs({\n isStrict: isStrict.requestSchema ?? true,\n idType: entityInstance.getIdType(),\n authenticate,\n authorize,\n routes,\n schema: {\n select: entityInstance.getSchema({ type: SchemaTypes.SELECT }),\n create: entityInstance.getSchema({ type: SchemaTypes.CREATE }),\n update: entityInstance.getSchema({ type: SchemaTypes.UPDATE }),\n },\n serverStampedKeys: entityInstance.getServerStampedKeys(),\n });\n\n const controllerClass = class extends PersistableCrudController<\n TEntity,\n RouteEnv,\n RouteSchema,\n BasePath,\n ConfigurableOptions,\n TDataObject,\n TPersistObject\n > {\n // Any extra options: a repository whose options narrow `IExtraOptions` (a typed transaction) must fit.\n constructor(repository: AbstractRepository<TDataObject, TPersistObject, AnyType>) {\n super({\n scope: name,\n path: basePath,\n isStrict: isStrict.path ?? true,\n repository,\n definitions: routeDefinitions,\n });\n }\n\n /** Registers each CRUD route whose handler tier supplies it, honoring enabledRoutes/readonly. */\n override binding(): ValueOrPromise<void> {\n const isEnabled = (routeKey: keyof ICustomizableRoutes) => {\n if (controller.enabledRoutes) {\n return controller.enabledRoutes.includes(routeKey);\n }\n return routes?.[routeKey]?.enabled !== false;\n };\n\n // Read routes - always registered (unless explicitly disabled)\n if (isEnabled('count')) {\n this.defineRoute({\n configs: routeDefinitions.COUNT,\n handler: async (context) => this.count({ context }),\n });\n }\n\n if (isEnabled('find')) {\n this.defineRoute({\n configs: routeDefinitions.FIND,\n handler: async (context) => this.find({ context }),\n });\n }\n\n if (isEnabled('findOne')) {\n this.defineRoute({\n configs: routeDefinitions.FIND_ONE,\n handler: async (context) => this.findOne({ context }),\n });\n }\n\n if (isEnabled('findById')) {\n this.defineRoute({\n configs: routeDefinitions.FIND_BY_ID,\n handler: async (context) => this.findById({ context }),\n });\n }\n\n // Write routes - skipped when readonly\n if (controller.readonly) {\n return;\n }\n\n if (isEnabled('create')) {\n this.defineRoute({\n configs: routeDefinitions.CREATE,\n handler: async (context) => this.create({ context }),\n });\n }\n\n if (isEnabled('updateById')) {\n this.defineRoute({\n configs: routeDefinitions.UPDATE_BY_ID,\n handler: async (context) => this.updateById({ context }),\n });\n }\n\n if (isEnabled('updateBy')) {\n this.defineRoute({\n configs: routeDefinitions.UPDATE_BY,\n handler: async (context) => this.updateBy({ context }),\n });\n }\n\n if (isEnabled('deleteById')) {\n this.defineRoute({\n configs: routeDefinitions.DELETE_BY_ID,\n handler: async (context) => this.deleteById({ context }),\n });\n }\n\n if (isEnabled('deleteBy')) {\n this.defineRoute({\n configs: routeDefinitions.DELETE_BY,\n handler: async (context) => this.deleteBy({ context }),\n });\n }\n }\n };\n\n Object.defineProperty(controllerClass, 'name', { value: name, configurable: true });\n registerFactoryRepositoryInjection({\n target: controllerClass,\n factoryName: 'defineCrudController',\n controllerName: name,\n repositoryName: defOpts.repository.name,\n });\n return controllerClass;\n }\n}\n"]}
@@ -19,7 +19,7 @@ export declare abstract class AbstractCrudController<TEntity extends AbstractEnt
19
19
  scope: string;
20
20
  path: string;
21
21
  isStrict?: boolean;
22
- repository: AbstractRepository<TDataObject, TPersistObject>;
22
+ repository: AbstractRepository<TDataObject, TPersistObject, AnyType>;
23
23
  definitions: AnyType;
24
24
  });
25
25
  /** 400 when a bulk operation is missing its `where` filter; undefined when it is present. */
@@ -1 +1 @@
1
- {"version":3,"file":"abstract.d.ts","sourceRoot":"","sources":["../../../../../../src/base/controllers/factory/crud/abstract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,KAAK,oBAAoB,CAAC,SAAS,IAC/B;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAE,GACvC;IAAE,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,CAAC;AAE3C,yRAAyR;AACzR,8BAAsB,sBAAsB,CAC1C,OAAO,SAAS,cAAc,CAAC,gBAAgB,CAAC,GAAG,cAAc,CAAC,gBAAgB,CAAC,EACnF,QAAQ,SAAS,GAAG,GAAG,GAAG,EAC1B,WAAW,SAAS,MAAM,GAAG,EAAE,EAC/B,QAAQ,SAAS,MAAM,GAAG,GAAG,EAC7B,mBAAmB,SAAS,MAAM,GAAG,EAAE,EACvC,WAAW,SAAS,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,EACvD,cAAc,SAAS,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAC7D,SAAQ,kBAAkB,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,mBAAmB,CAAC;IAChF,UAAU,EAAE,kBAAkB,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;gBAEhD,IAAI,EAAE;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,UAAU,EAAE,kBAAkB,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;QAC5D,WAAW,EAAE,OAAO,CAAC;KACtB;IAMD,6FAA6F;IAC7F,cAAc,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAWzE,2GAA2G;IAC3G,gBAAgB,CAAC,SAAS,SAAS,MAAM,EAAE,IAAI,EAAE;QAC/C,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;QACjC,KAAK,CAAC,EAAE;YACN,SAAS,CAAC,EAAE,SAAS,CAAC;YACtB,QAAQ,CAAC,EAAE,SAAS,CAAC;SACtB,CAAC;KACH,GAAG,oBAAoB,CAAC,SAAS,CAAC;CAyBpC"}
1
+ {"version":3,"file":"abstract.d.ts","sourceRoot":"","sources":["../../../../../../src/base/controllers/factory/crud/abstract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAE7D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,KAAK,oBAAoB,CAAC,SAAS,IAC/B;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAE,GACvC;IAAE,KAAK,CAAC,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,CAAC;AAE3C,yRAAyR;AACzR,8BAAsB,sBAAsB,CAC1C,OAAO,SAAS,cAAc,CAAC,gBAAgB,CAAC,GAAG,cAAc,CAAC,gBAAgB,CAAC,EACnF,QAAQ,SAAS,GAAG,GAAG,GAAG,EAC1B,WAAW,SAAS,MAAM,GAAG,EAAE,EAC/B,QAAQ,SAAS,MAAM,GAAG,GAAG,EAC7B,mBAAmB,SAAS,MAAM,GAAG,EAAE,EACvC,WAAW,SAAS,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,EACvD,cAAc,SAAS,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAC7D,SAAQ,kBAAkB,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,mBAAmB,CAAC;IAChF,UAAU,EAAE,kBAAkB,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;gBAEhD,IAAI,EAAE;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,UAAU,EAAE,kBAAkB,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;QACrE,WAAW,EAAE,OAAO,CAAC;KACtB;IAMD,6FAA6F;IAC7F,cAAc,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;IAWzE,2GAA2G;IAC3G,gBAAgB,CAAC,SAAS,SAAS,MAAM,EAAE,IAAI,EAAE;QAC/C,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;QACjC,KAAK,CAAC,EAAE;YACN,SAAS,CAAC,EAAE,SAAS,CAAC;YACtB,QAAQ,CAAC,EAAE,SAAS,CAAC;SACtB,CAAC;KACH,GAAG,oBAAoB,CAAC,SAAS,CAAC;CAyBpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"abstract.js","sourceRoot":"","sources":["../../../../../../src/base/controllers/factory/crud/abstract.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAC;AAGrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAMrD,yRAAyR;AACzR,MAAM,OAAgB,sBAQpB,SAAQ,kBAAwE;IAGhF,YAAY,IAMX;QACC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACtC,CAAC;IAED,6FAA6F;IAC7F,cAAc,CAAC,IAA0D;QACvE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;QAChC,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,OAAO,OAAO,CAAC,IAAI,CACjB,EAAE,OAAO,EAAE,8CAA8C,EAAE,EAC3D,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CACjC,CAAC;QACJ,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,2GAA2G;IAC3G,gBAAgB,CAA2B,IAM1C;QACC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;QAC9C,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,YAAY,IAAI,EAAE,CAAC;QAEnD,IAAI,SAAS,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YACtD,OAAO;gBACL,KAAK,EAAE,OAAO,CAAC,IAAI,CACjB,EAAE,OAAO,EAAE,6DAA6D,EAAE,EAC1E,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CACjC;aACF,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,SAAS,IAAI,QAAQ,CAAC;QACpC,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,OAAO;gBACL,KAAK,EAAE,OAAO,CAAC,IAAI,CACjB,EAAE,OAAO,EAAE,8CAA8C,EAAE,EAC3D,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CACjC;aACF,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,CAAC;IACnB,CAAC;CACF","sourcesContent":["import type { AbstractEntity } from '@/base/models/base';\nimport type { AbstractRepository } from '@/base/repositories';\nimport type { TAnyObjectSchema } from '@/base/controllers/common/schema-builders';\nimport type { AnyType } from '@venizia/ignis-helpers/common';\nimport { HTTP } from '@venizia/ignis-helpers/common';\nimport type { Env, Schema } from 'hono';\nimport type { TEntityDataObject, TEntityPersistObject, TRouteContext } from '../../common';\nimport { BaseRestController } from '../../rest/base';\n\ntype TBulkWhereResolution<WhereType> =\n | { where: WhereType; error?: undefined }\n | { where?: undefined; error: Response };\n\n/** Base tier of a generated CRUD controller - the repository handle; the response helpers (`respond`, `setListHeaders`) live on BaseRestController so hand-written controllers share them. Read and write verbs are layered on by ReadableCrudController / PersistableCrudController. */\nexport abstract class AbstractCrudController<\n TEntity extends AbstractEntity<TAnyObjectSchema> = AbstractEntity<TAnyObjectSchema>,\n RouteEnv extends Env = Env,\n RouteSchema extends Schema = {},\n BasePath extends string = '/',\n ConfigurableOptions extends object = {},\n TDataObject extends object = TEntityDataObject<TEntity>,\n TPersistObject extends object = TEntityPersistObject<TEntity>,\n> extends BaseRestController<RouteEnv, RouteSchema, BasePath, ConfigurableOptions> {\n repository: AbstractRepository<TDataObject, TPersistObject>;\n\n constructor(opts: {\n scope: string;\n path: string;\n isStrict?: boolean;\n repository: AbstractRepository<TDataObject, TPersistObject>;\n definitions: AnyType;\n }) {\n super({ scope: opts.scope, path: opts.path, isStrict: opts.isStrict });\n this.repository = opts.repository;\n this.definitions = opts.definitions;\n }\n\n /** 400 when a bulk operation is missing its `where` filter; undefined when it is present. */\n bulkWhereError(opts: { context: TRouteContext<RouteEnv>; where?: object }) {\n const { context, where } = opts;\n if (!where || Object.keys(where).length === 0) {\n return context.json(\n { message: 'where filter is required for bulk operations' },\n HTTP.ResultCodes.RS_4.BadRequest,\n );\n }\n return undefined;\n }\n\n /** Bulk `where` from the query or the JSON body (long id lists outgrow a URL). Both, or none, is a 400. */\n resolveBulkWhere<WhereType extends object>(opts: {\n context: TRouteContext<RouteEnv>;\n where?: {\n fromQuery?: WhereType;\n fromBody?: WhereType;\n };\n }): TBulkWhereResolution<WhereType> {\n const { context, where: whereSources } = opts;\n const { fromQuery, fromBody } = whereSources ?? {};\n\n if (fromQuery !== undefined && fromBody !== undefined) {\n return {\n error: context.json(\n { message: 'where given in both the query and the body - send it in one' },\n HTTP.ResultCodes.RS_4.BadRequest,\n ),\n };\n }\n\n const where = fromQuery ?? fromBody;\n if (!where || Object.keys(where).length === 0) {\n return {\n error: context.json(\n { message: 'where filter is required for bulk operations' },\n HTTP.ResultCodes.RS_4.BadRequest,\n ),\n };\n }\n\n return { where };\n }\n}\n"]}
1
+ {"version":3,"file":"abstract.js","sourceRoot":"","sources":["../../../../../../src/base/controllers/factory/crud/abstract.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,MAAM,+BAA+B,CAAC;AAGrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAMrD,yRAAyR;AACzR,MAAM,OAAgB,sBAQpB,SAAQ,kBAAwE;IAGhF,YAAY,IAMX;QACC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACtC,CAAC;IAED,6FAA6F;IAC7F,cAAc,CAAC,IAA0D;QACvE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;QAChC,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,OAAO,OAAO,CAAC,IAAI,CACjB,EAAE,OAAO,EAAE,8CAA8C,EAAE,EAC3D,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CACjC,CAAC;QACJ,CAAC;QACD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,2GAA2G;IAC3G,gBAAgB,CAA2B,IAM1C;QACC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;QAC9C,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,YAAY,IAAI,EAAE,CAAC;QAEnD,IAAI,SAAS,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YACtD,OAAO;gBACL,KAAK,EAAE,OAAO,CAAC,IAAI,CACjB,EAAE,OAAO,EAAE,6DAA6D,EAAE,EAC1E,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CACjC;aACF,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,SAAS,IAAI,QAAQ,CAAC;QACpC,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9C,OAAO;gBACL,KAAK,EAAE,OAAO,CAAC,IAAI,CACjB,EAAE,OAAO,EAAE,8CAA8C,EAAE,EAC3D,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CACjC;aACF,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,CAAC;IACnB,CAAC;CACF","sourcesContent":["import type { AbstractEntity } from '@/base/models/base';\nimport type { AbstractRepository } from '@/base/repositories';\nimport type { TAnyObjectSchema } from '@/base/controllers/common/schema-builders';\nimport type { AnyType } from '@venizia/ignis-helpers/common';\nimport { HTTP } from '@venizia/ignis-helpers/common';\nimport type { Env, Schema } from 'hono';\nimport type { TEntityDataObject, TEntityPersistObject, TRouteContext } from '../../common';\nimport { BaseRestController } from '../../rest/base';\n\ntype TBulkWhereResolution<WhereType> =\n | { where: WhereType; error?: undefined }\n | { where?: undefined; error: Response };\n\n/** Base tier of a generated CRUD controller - the repository handle; the response helpers (`respond`, `setListHeaders`) live on BaseRestController so hand-written controllers share them. Read and write verbs are layered on by ReadableCrudController / PersistableCrudController. */\nexport abstract class AbstractCrudController<\n TEntity extends AbstractEntity<TAnyObjectSchema> = AbstractEntity<TAnyObjectSchema>,\n RouteEnv extends Env = Env,\n RouteSchema extends Schema = {},\n BasePath extends string = '/',\n ConfigurableOptions extends object = {},\n TDataObject extends object = TEntityDataObject<TEntity>,\n TPersistObject extends object = TEntityPersistObject<TEntity>,\n> extends BaseRestController<RouteEnv, RouteSchema, BasePath, ConfigurableOptions> {\n repository: AbstractRepository<TDataObject, TPersistObject>;\n\n constructor(opts: {\n scope: string;\n path: string;\n isStrict?: boolean;\n repository: AbstractRepository<TDataObject, TPersistObject, AnyType>;\n definitions: AnyType;\n }) {\n super({ scope: opts.scope, path: opts.path, isStrict: opts.isStrict });\n this.repository = opts.repository;\n this.definitions = opts.definitions;\n }\n\n /** 400 when a bulk operation is missing its `where` filter; undefined when it is present. */\n bulkWhereError(opts: { context: TRouteContext<RouteEnv>; where?: object }) {\n const { context, where } = opts;\n if (!where || Object.keys(where).length === 0) {\n return context.json(\n { message: 'where filter is required for bulk operations' },\n HTTP.ResultCodes.RS_4.BadRequest,\n );\n }\n return undefined;\n }\n\n /** Bulk `where` from the query or the JSON body (long id lists outgrow a URL). Both, or none, is a 400. */\n resolveBulkWhere<WhereType extends object>(opts: {\n context: TRouteContext<RouteEnv>;\n where?: {\n fromQuery?: WhereType;\n fromBody?: WhereType;\n };\n }): TBulkWhereResolution<WhereType> {\n const { context, where: whereSources } = opts;\n const { fromQuery, fromBody } = whereSources ?? {};\n\n if (fromQuery !== undefined && fromBody !== undefined) {\n return {\n error: context.json(\n { message: 'where given in both the query and the body - send it in one' },\n HTTP.ResultCodes.RS_4.BadRequest,\n ),\n };\n }\n\n const where = fromQuery ?? fromBody;\n if (!where || Object.keys(where).length === 0) {\n return {\n error: context.json(\n { message: 'where filter is required for bulk operations' },\n HTTP.ResultCodes.RS_4.BadRequest,\n ),\n };\n }\n\n return { where };\n }\n}\n"]}
@@ -35,7 +35,7 @@ export class RouteConfigResolver {
35
35
  // A `.transform()` pipe has no shape to read, so every key it might hold counts.
36
36
  const isObjectSchema = schema instanceof z.ZodObject;
37
37
  const omittedKeys = isObjectSchema
38
- ? droppedKeys.filter(key => Object.hasOwn(schema.shape, key))
38
+ ? droppedKeys.filter((key) => Object.hasOwn(schema.shape, key))
39
39
  : droppedKeys;
40
40
  if (omittedKeys.length === 0) {
41
41
  return schema;
@@ -1 +1 @@
1
- {"version":3,"file":"definition.js","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/definition.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TAuthMode, TAuthStrategy } from '@/base/auth/authenticate/common/constants';\nimport type { IAuthorizationSpec } from '@/base/auth/authorize/common/types';\nimport type { TIdSchemaType } from '@/base/models/common';\nimport { idParamsSchema, jsonContent, jsonResponse } from '@/base/models/common';\nimport { CountSchema } from '@/base/repositories/common';\nimport { FilterQuerySchema, WhereSchema } from '@/base/repositories/query-schemas';\nimport type { TAnyObjectSchema } from '@/base/controllers/common/schema-builders';\nimport { z } from '@hono/zod-openapi';\nimport { HTTP } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport type { ICustomizableRoutes } from '../common';\nimport {\n commonResponseHeaders,\n defaultRequestHeaders,\n findResponseHeaders,\n RestPaths,\n trackableHeaders,\n} from '../common';\n\n/** Picks user-overridden response schema if present (and non-undefined), else the default. */\ntype TResolvedResponseSchema<C, D extends z.ZodType> = C extends {\n response: {\n schema: infer S extends z.ZodType;\n };\n}\n ? S\n : D;\n\n/**\n * Every method here is an unbound static, called from the exported aliases below without a\n * receiver - a method must call another via `RouteConfigResolver.other(...)`, never\n * `this.other(...)`, or `this` is `undefined` at the call site.\n */\nexport class RouteConfigResolver {\n /** Path params always reach the validator as strings, so a number-typed id must be coerced before `z.number()` sees it - `idParamsSchema` alone rejects `/accounts/7`. */\n private static idPathParamsSchema(opts: { idType: TIdSchemaType }) {\n const { idType } = opts;\n\n if (idType !== 'number') {\n return idParamsSchema({ idType });\n }\n\n return z.object({\n id: z.coerce.number().openapi({\n param: { name: 'id', in: 'path', description: 'The unique id of the resource' },\n examples: [1, 2, 3],\n }),\n });\n }\n\n /**\n * The default body of a write route: the entity schema without the keys the entity stamps, and on\n * an update without `id` - the path or `where` names the rows. Zod strips a left-out key a client\n * sends. With nothing to leave out the schema itself is the body, refinements and OpenAPI name kept.\n */\n private static toWriteBodySchema(opts: {\n schema: TAnyObjectSchema;\n route: keyof ICustomizableRoutes;\n serverStampedKeys: string[];\n }): TAnyObjectSchema {\n const { schema, route, serverStampedKeys } = opts;\n const droppedKeys = route === 'create' ? serverStampedKeys : [...serverStampedKeys, 'id'];\n // A `.transform()` pipe has no shape to read, so every key it might hold counts.\n const isObjectSchema = schema instanceof z.ZodObject;\n const omittedKeys = isObjectSchema\n ? droppedKeys.filter(key => Object.hasOwn(schema.shape, key))\n : droppedKeys;\n\n if (omittedKeys.length === 0) {\n return schema;\n }\n\n if (!isObjectSchema || schema.def.checks?.length) {\n throw getError({\n message: `[defineControllerRouteConfigs] Cannot build the default ${route} body | keys to leave out: ${omittedKeys.join(', ')} | The schema is refined or transformed, so zod cannot remove them | Pass routes.${route}.request.body`,\n });\n }\n\n const mask: Record<string, true> = {};\n for (const key of omittedKeys) {\n mask[key] = true;\n }\n\n return schema.omit(mask);\n }\n\n /** Picks the caller's per-route `request.params` override, else the entity's id path-param schema. */\n private static resolveIdParams<\n C extends { request?: { params?: TAnyObjectSchema } } | undefined,\n >(opts: { config: C; idType: TIdSchemaType }) {\n const { config, idType } = opts;\n return config?.request?.params ?? RouteConfigResolver.idPathParamsSchema({ idType });\n }\n\n /** Creates conditional count response schema. */\n static conditionalCountResponse<T extends z.ZodType>(dataSchema: T) {\n return z.union([\n CountSchema.extend({ data: dataSchema }).openapi({\n description: 'Response with count (when x-request-count header is \"true\" or omitted)',\n }),\n dataSchema.openapi({\n description: 'Data only response (when x-request-count header is \"false\")',\n }),\n ]);\n }\n\n /** Resolves a route's response schema - user override or default. Holds the one cast every `resolve*Config` needs: generic `C` is only known by its wider structural constraint, so it cannot be proven at the value level to collapse to `TResolvedResponseSchema`. */\n private static resolveResponseSchema<\n C extends { response?: { schema?: z.ZodType } } | undefined,\n D extends z.ZodType,\n >(opts: { config: C; defaultSchema: D }): TResolvedResponseSchema<C, D> {\n const { config, defaultSchema } = opts;\n return (config?.response?.schema ?? defaultSchema) as TResolvedResponseSchema<C, D>;\n }\n\n static resolveCountConfig<C extends ICustomizableRoutes['count']>(opts: {\n config: C;\n isStrict: boolean;\n }) {\n const { config, isStrict } = opts;\n const defaultQuery = z\n .object({\n where: isStrict\n ? WhereSchema\n : z.optional(WhereSchema).openapi({ description: 'Filter conditions' }),\n })\n .openapi({ description: 'Count query params' });\n\n return {\n request: {\n query: config?.request?.query ?? defaultQuery,\n headers: config?.request?.headers ?? trackableHeaders,\n },\n response: {\n description: 'Total count of matching records',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema: CountSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n static resolveFindConfig<\n C extends ICustomizableRoutes['find'],\n FindSchema extends TAnyObjectSchema,\n >(opts: { config: C; selectSchema: FindSchema }) {\n const { config, selectSchema } = opts;\n const defaultQuery = FilterQuerySchema;\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(z.array(selectSchema));\n\n return {\n request: {\n query: config?.request?.query ?? defaultQuery,\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Array of matching records (with optional count)',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? findResponseHeaders,\n },\n };\n }\n\n static resolveFindByIdConfig<\n C extends ICustomizableRoutes['findById'],\n FindByIdSchema extends TAnyObjectSchema,\n >(opts: { idType: TIdSchemaType; config: C; selectSchema: FindByIdSchema }) {\n const { config, selectSchema, idType } = opts;\n const defaultQuery = FilterQuerySchema.openapi({\n description: 'Filter with fields, order, include (where ignored)',\n });\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(selectSchema);\n\n return {\n request: {\n params: RouteConfigResolver.resolveIdParams({ config, idType }),\n query: config?.request?.query ?? defaultQuery,\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Single record matching ID or null',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n static resolveFindOneConfig<\n C extends ICustomizableRoutes['findOne'],\n FindOneSchema extends TAnyObjectSchema,\n >(opts: { config: C; selectSchema: FindOneSchema }) {\n const { config, selectSchema } = opts;\n const defaultQuery = FilterQuerySchema.openapi({\n description: 'Filter with where, fields, order, include',\n });\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(selectSchema);\n\n return {\n request: {\n query: config?.request?.query ?? defaultQuery,\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'First matching record or null',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n /** `serverStampedKeys` - what the entity reports from `getServerStampedKeys()`; the default body leaves them out. */\n static resolveCreateConfig<\n C extends ICustomizableRoutes['create'],\n SelectSchema extends TAnyObjectSchema,\n CreateSchema extends TAnyObjectSchema,\n >(opts: {\n config: C;\n selectSchema: SelectSchema;\n createSchema: CreateSchema;\n serverStampedKeys?: string[];\n }) {\n const { config, selectSchema, createSchema, serverStampedKeys = [] } = opts;\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(selectSchema);\n\n return {\n request: {\n body:\n config?.request?.body ??\n RouteConfigResolver.toWriteBodySchema({\n schema: createSchema,\n route: 'create',\n serverStampedKeys,\n }),\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Created record with generated fields (id, createdAt, etc.)',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n private static resolveUpdateByIdConfig<\n C extends ICustomizableRoutes['updateById'],\n SelectSchema extends TAnyObjectSchema,\n UpdateSchema extends TAnyObjectSchema,\n >(opts: {\n idType: TIdSchemaType;\n config: C;\n selectSchema: SelectSchema;\n updateSchema: UpdateSchema;\n serverStampedKeys: string[];\n }) {\n const { config, selectSchema, updateSchema, idType, serverStampedKeys } = opts;\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(selectSchema);\n return {\n request: {\n params: RouteConfigResolver.resolveIdParams({ config, idType }),\n body:\n config?.request?.body ??\n RouteConfigResolver.toWriteBodySchema({\n schema: updateSchema,\n route: 'updateById',\n serverStampedKeys,\n }),\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Updated record with all current fields',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n private static resolveUpdateByConfig<\n C extends ICustomizableRoutes['updateBy'],\n SelectSchema extends TAnyObjectSchema,\n UpdateSchema extends TAnyObjectSchema,\n >(opts: {\n config: C;\n selectSchema: SelectSchema;\n updateSchema: UpdateSchema;\n serverStampedKeys: string[];\n }) {\n const { config, selectSchema, updateSchema, serverStampedKeys } = opts;\n const defaultQuery = z.object({ where: WhereSchema.optional() }).openapi({\n description:\n 'Where condition selecting the records to update - here or in the body, not both',\n });\n // Built only without a custom body: a custom body must not trip the entity schema's checks.\n const buildDefaultBody = () => {\n const writableSchema = RouteConfigResolver.toWriteBodySchema({\n schema: updateSchema,\n route: 'updateBy',\n serverStampedKeys,\n });\n // A model with a real `where` column keeps it: the body reserves the name only when it is\n // free, and the handler then simply finds no `where` there.\n return 'where' in writableSchema.shape\n ? writableSchema\n : writableSchema.extend({ where: WhereSchema.optional() });\n };\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(z.array(selectSchema));\n return {\n request: {\n query: config?.request?.query ?? defaultQuery,\n body: config?.request?.body ?? buildDefaultBody(),\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Array of updated records',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n private static resolveDeleteByIdConfig<\n C extends ICustomizableRoutes['deleteById'],\n SelectSchema extends TAnyObjectSchema,\n >(opts: { idType: TIdSchemaType; config: C; selectSchema: SelectSchema }) {\n const { config, selectSchema, idType } = opts;\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(selectSchema);\n return {\n request: {\n params: RouteConfigResolver.resolveIdParams({ config, idType }),\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Deleted record data',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n private static resolveDeleteByConfig<\n C extends ICustomizableRoutes['deleteBy'],\n SelectSchema extends TAnyObjectSchema,\n >(opts: { config: C; selectSchema: SelectSchema }) {\n const { config, selectSchema } = opts;\n const defaultQuery = z.object({ where: WhereSchema.optional() }).openapi({\n description:\n 'Where condition selecting the records to delete - here or in the body, not both',\n });\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(z.array(selectSchema));\n return {\n request: {\n query: config?.request?.query ?? defaultQuery,\n // No DEFAULT body schema. Declaring one makes `@hono/zod-openapi` gate the media type, and a\n // client that sends `content-type: application/json` with no body then gets 400 where it used\n // to get 200. The handler reads the body itself; name one here to get the Swagger editor.\n body: config?.request?.body,\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Array of deleted records',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n /**\n * Generates complete route configurations for a CRUD controller. `serverStampedKeys` - what the\n * entity reports from `getServerStampedKeys()`; the default write bodies leave them out.\n */\n static defineControllerRouteConfigs<\n Routes extends ICustomizableRoutes,\n SelectSchema extends TAnyObjectSchema,\n CreateSchema extends TAnyObjectSchema,\n UpdateSchema extends TAnyObjectSchema,\n >(opts: {\n isStrict: boolean;\n idType: TIdSchemaType;\n authenticate?: { strategies?: TAuthStrategy[]; mode?: TAuthMode };\n authorize?: IAuthorizationSpec | IAuthorizationSpec[];\n schema: { select: SelectSchema; create: CreateSchema; update: UpdateSchema };\n serverStampedKeys?: string[];\n routes?: Routes;\n }) {\n const {\n isStrict,\n idType,\n authenticate: controllerAuth = {},\n authorize: controllerAuthorize,\n schema: { select: selectSchema, create: createSchema, update: updateSchema },\n serverStampedKeys = [],\n routes,\n } = opts;\n const { strategies: defaultStrategies = [], mode: defaultMode } = controllerAuth;\n\n // `Routes` is caller-bound but otherwise unconstrained here, so `{}` cannot be proven to satisfy it structurally even though every field ICustomizableRoutes declares is optional.\n const routesConfig = (routes ?? {}) as Routes;\n\n type TAuthenticateConfig = { strategies?: TAuthStrategy[]; mode?: TAuthMode };\n\n /** Priority: endpoint authenticate > controller authenticate. */\n const resolveRouteAuth = (routeKey: keyof ICustomizableRoutes): TAuthenticateConfig => {\n const endpointConfig = routesConfig[routeKey];\n const authConfig = endpointConfig?.authenticate;\n\n if (authConfig == null) {\n return { strategies: defaultStrategies, mode: defaultMode };\n }\n\n if (authConfig.skip === true) {\n return { strategies: [] };\n }\n\n return {\n strategies: authConfig.strategies ?? defaultStrategies,\n mode: authConfig.mode ?? defaultMode,\n };\n };\n\n type TAuthorizeConfig = IAuthorizationSpec | IAuthorizationSpec[] | undefined;\n\n /** Priority: endpoint authenticate.skip > endpoint authorize.skip > endpoint authorize > controller authorize. */\n const resolveRouteAuthorize = (routeKey: keyof ICustomizableRoutes): TAuthorizeConfig => {\n const endpointConfig = routesConfig[routeKey];\n\n if (endpointConfig?.authenticate?.skip === true) {\n return undefined;\n }\n\n const authorize = endpointConfig?.authorize;\n\n if (authorize == null) {\n return controllerAuthorize;\n }\n\n if (Array.isArray(authorize)) {\n return authorize;\n }\n\n if ('skip' in authorize) {\n return undefined;\n }\n\n return authorize;\n };\n\n const count = RouteConfigResolver.resolveCountConfig({ config: routesConfig.count, isStrict });\n const find = RouteConfigResolver.resolveFindConfig({ config: routesConfig.find, selectSchema });\n const findById = RouteConfigResolver.resolveFindByIdConfig({\n config: routesConfig.findById,\n selectSchema,\n idType,\n });\n const findOne = RouteConfigResolver.resolveFindOneConfig({\n config: routesConfig.findOne,\n selectSchema,\n });\n const create = RouteConfigResolver.resolveCreateConfig({\n config: routesConfig.create,\n selectSchema,\n createSchema,\n serverStampedKeys,\n });\n const updateById = RouteConfigResolver.resolveUpdateByIdConfig({\n config: routesConfig.updateById,\n selectSchema,\n updateSchema,\n idType,\n serverStampedKeys,\n });\n const updateBy = RouteConfigResolver.resolveUpdateByConfig({\n config: routesConfig.updateBy,\n selectSchema,\n updateSchema,\n serverStampedKeys,\n });\n const deleteById = RouteConfigResolver.resolveDeleteByIdConfig({\n config: routesConfig.deleteById,\n selectSchema,\n idType,\n });\n const deleteBy = RouteConfigResolver.resolveDeleteByConfig({\n config: routesConfig.deleteBy,\n selectSchema,\n });\n\n const rs = {\n COUNT: {\n method: HTTP.Methods.GET,\n path: RestPaths.COUNT,\n description: 'Count records matching where condition',\n authenticate: resolveRouteAuth('count'),\n authorize: resolveRouteAuthorize('count'),\n request: count.request,\n responses: jsonResponse(count.response),\n },\n\n FIND: {\n method: HTTP.Methods.GET,\n path: RestPaths.ROOT,\n description: 'Find records with filter, pagination, sorting, and relations',\n authenticate: resolveRouteAuth('find'),\n authorize: resolveRouteAuthorize('find'),\n request: find.request,\n responses: jsonResponse(find.response),\n },\n\n FIND_BY_ID: {\n method: HTTP.Methods.GET,\n path: '/{id}',\n description: 'Find single record by ID',\n authenticate: resolveRouteAuth('findById'),\n authorize: resolveRouteAuthorize('findById'),\n request: findById.request,\n responses: jsonResponse(findById.response),\n },\n\n FIND_ONE: {\n method: HTTP.Methods.GET,\n path: RestPaths.FIND_ONE,\n description: 'Find first record matching filter',\n authenticate: resolveRouteAuth('findOne'),\n authorize: resolveRouteAuthorize('findOne'),\n request: findOne.request,\n responses: jsonResponse(findOne.response),\n },\n\n CREATE: {\n method: HTTP.Methods.POST,\n path: RestPaths.ROOT,\n description: 'Create new record',\n authenticate: resolveRouteAuth('create'),\n authorize: resolveRouteAuthorize('create'),\n request: {\n body: jsonContent({\n description: 'Record data (required fields must be provided)',\n schema: create.request.body,\n }),\n headers: create.request.headers,\n },\n responses: jsonResponse(create.response),\n },\n\n UPDATE_BY_ID: {\n method: HTTP.Methods.PATCH,\n path: '/{id}',\n description: 'Partial update record by ID',\n authenticate: resolveRouteAuth('updateById'),\n authorize: resolveRouteAuthorize('updateById'),\n request: {\n params: updateById.request.params,\n body: jsonContent({\n description: 'Partial data (only changed fields)',\n schema: updateById.request.body,\n }),\n headers: updateById.request.headers,\n },\n responses: jsonResponse(updateById.response),\n },\n\n UPDATE_BY: {\n method: HTTP.Methods.PATCH,\n path: RestPaths.ROOT,\n description: 'Bulk update records matching where condition',\n authenticate: resolveRouteAuth('updateBy'),\n authorize: resolveRouteAuthorize('updateBy'),\n request: {\n query: updateBy.request.query,\n body: jsonContent({\n description: 'Partial data to apply to all matches',\n schema: updateBy.request.body,\n }),\n headers: updateBy.request.headers,\n },\n responses: jsonResponse(updateBy.response),\n },\n\n DELETE_BY_ID: {\n method: HTTP.Methods.DELETE,\n path: '/{id}',\n description: 'Delete record by ID (irreversible)',\n authenticate: resolveRouteAuth('deleteById'),\n authorize: resolveRouteAuthorize('deleteById'),\n request: deleteById.request,\n responses: jsonResponse(deleteById.response),\n },\n\n DELETE_BY: {\n method: HTTP.Methods.DELETE,\n path: RestPaths.ROOT,\n description: 'Bulk delete records matching where condition (irreversible)',\n authenticate: resolveRouteAuth('deleteBy'),\n authorize: resolveRouteAuthorize('deleteBy'),\n request: {\n query: deleteBy.request.query,\n ...(deleteBy.request.body\n ? {\n body: jsonContent({\n description: 'Where condition, when it does not fit in the query',\n schema: deleteBy.request.body,\n required: false,\n }),\n }\n : {}),\n headers: deleteBy.request.headers,\n },\n responses: jsonResponse(deleteBy.response),\n },\n } as const;\n\n return rs;\n }\n}\n\nexport const conditionalCountResponse = RouteConfigResolver.conditionalCountResponse;\nexport const resolveCountConfig = RouteConfigResolver.resolveCountConfig;\nexport const resolveFindConfig = RouteConfigResolver.resolveFindConfig;\nexport const resolveFindByIdConfig = RouteConfigResolver.resolveFindByIdConfig;\nexport const resolveFindOneConfig = RouteConfigResolver.resolveFindOneConfig;\nexport const resolveCreateConfig = RouteConfigResolver.resolveCreateConfig;\nexport const defineControllerRouteConfigs = RouteConfigResolver.defineControllerRouteConfigs;\n"]}
1
+ {"version":3,"file":"definition.js","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/definition.ts"],"names":[],"mappings":"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","sourcesContent":["import type { TAuthMode, TAuthStrategy } from '@/base/auth/authenticate/common/constants';\nimport type { IAuthorizationSpec } from '@/base/auth/authorize/common/types';\nimport type { TIdSchemaType } from '@/base/models/common';\nimport { idParamsSchema, jsonContent, jsonResponse } from '@/base/models/common';\nimport { CountSchema } from '@/base/repositories/common';\nimport { FilterQuerySchema, WhereSchema } from '@/base/repositories/query-schemas';\nimport type { TAnyObjectSchema } from '@/base/controllers/common/schema-builders';\nimport { z } from '@hono/zod-openapi';\nimport { HTTP } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\nimport type { ICustomizableRoutes } from '../common';\nimport {\n commonResponseHeaders,\n defaultRequestHeaders,\n findResponseHeaders,\n RestPaths,\n trackableHeaders,\n} from '../common';\n\n/** Picks user-overridden response schema if present (and non-undefined), else the default. */\ntype TResolvedResponseSchema<C, D extends z.ZodType> = C extends {\n response: {\n schema: infer S extends z.ZodType;\n };\n}\n ? S\n : D;\n\n/**\n * Every method here is an unbound static, called from the exported aliases below without a\n * receiver - a method must call another via `RouteConfigResolver.other(...)`, never\n * `this.other(...)`, or `this` is `undefined` at the call site.\n */\nexport class RouteConfigResolver {\n /** Path params always reach the validator as strings, so a number-typed id must be coerced before `z.number()` sees it - `idParamsSchema` alone rejects `/accounts/7`. */\n private static idPathParamsSchema(opts: { idType: TIdSchemaType }) {\n const { idType } = opts;\n\n if (idType !== 'number') {\n return idParamsSchema({ idType });\n }\n\n return z.object({\n id: z.coerce.number().openapi({\n param: { name: 'id', in: 'path', description: 'The unique id of the resource' },\n examples: [1, 2, 3],\n }),\n });\n }\n\n /**\n * The default body of a write route: the entity schema without the keys the entity stamps, and on\n * an update without `id` - the path or `where` names the rows. Zod strips a left-out key a client\n * sends. With nothing to leave out the schema itself is the body, refinements and OpenAPI name kept.\n */\n private static toWriteBodySchema(opts: {\n schema: TAnyObjectSchema;\n route: keyof ICustomizableRoutes;\n serverStampedKeys: string[];\n }): TAnyObjectSchema {\n const { schema, route, serverStampedKeys } = opts;\n const droppedKeys = route === 'create' ? serverStampedKeys : [...serverStampedKeys, 'id'];\n // A `.transform()` pipe has no shape to read, so every key it might hold counts.\n const isObjectSchema = schema instanceof z.ZodObject;\n const omittedKeys = isObjectSchema\n ? droppedKeys.filter((key) => Object.hasOwn(schema.shape, key))\n : droppedKeys;\n\n if (omittedKeys.length === 0) {\n return schema;\n }\n\n if (!isObjectSchema || schema.def.checks?.length) {\n throw getError({\n message: `[defineControllerRouteConfigs] Cannot build the default ${route} body | keys to leave out: ${omittedKeys.join(', ')} | The schema is refined or transformed, so zod cannot remove them | Pass routes.${route}.request.body`,\n });\n }\n\n const mask: Record<string, true> = {};\n for (const key of omittedKeys) {\n mask[key] = true;\n }\n\n return schema.omit(mask);\n }\n\n /** Picks the caller's per-route `request.params` override, else the entity's id path-param schema. */\n private static resolveIdParams<\n C extends { request?: { params?: TAnyObjectSchema } } | undefined,\n >(opts: { config: C; idType: TIdSchemaType }) {\n const { config, idType } = opts;\n return config?.request?.params ?? RouteConfigResolver.idPathParamsSchema({ idType });\n }\n\n /** Creates conditional count response schema. */\n static conditionalCountResponse<T extends z.ZodType>(dataSchema: T) {\n return z.union([\n CountSchema.extend({ data: dataSchema }).openapi({\n description: 'Response with count (when x-request-count header is \"true\" or omitted)',\n }),\n dataSchema.openapi({\n description: 'Data only response (when x-request-count header is \"false\")',\n }),\n ]);\n }\n\n /** Resolves a route's response schema - user override or default. Holds the one cast every `resolve*Config` needs: generic `C` is only known by its wider structural constraint, so it cannot be proven at the value level to collapse to `TResolvedResponseSchema`. */\n private static resolveResponseSchema<\n C extends { response?: { schema?: z.ZodType } } | undefined,\n D extends z.ZodType,\n >(opts: { config: C; defaultSchema: D }): TResolvedResponseSchema<C, D> {\n const { config, defaultSchema } = opts;\n return (config?.response?.schema ?? defaultSchema) as TResolvedResponseSchema<C, D>;\n }\n\n static resolveCountConfig<C extends ICustomizableRoutes['count']>(opts: {\n config: C;\n isStrict: boolean;\n }) {\n const { config, isStrict } = opts;\n const defaultQuery = z\n .object({\n where: isStrict\n ? WhereSchema\n : z.optional(WhereSchema).openapi({ description: 'Filter conditions' }),\n })\n .openapi({ description: 'Count query params' });\n\n return {\n request: {\n query: config?.request?.query ?? defaultQuery,\n headers: config?.request?.headers ?? trackableHeaders,\n },\n response: {\n description: 'Total count of matching records',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema: CountSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n static resolveFindConfig<\n C extends ICustomizableRoutes['find'],\n FindSchema extends TAnyObjectSchema,\n >(opts: { config: C; selectSchema: FindSchema }) {\n const { config, selectSchema } = opts;\n const defaultQuery = FilterQuerySchema;\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(z.array(selectSchema));\n\n return {\n request: {\n query: config?.request?.query ?? defaultQuery,\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Array of matching records (with optional count)',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? findResponseHeaders,\n },\n };\n }\n\n static resolveFindByIdConfig<\n C extends ICustomizableRoutes['findById'],\n FindByIdSchema extends TAnyObjectSchema,\n >(opts: { idType: TIdSchemaType; config: C; selectSchema: FindByIdSchema }) {\n const { config, selectSchema, idType } = opts;\n const defaultQuery = FilterQuerySchema.openapi({\n description: 'Filter with fields, order, include (where ignored)',\n });\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(selectSchema);\n\n return {\n request: {\n params: RouteConfigResolver.resolveIdParams({ config, idType }),\n query: config?.request?.query ?? defaultQuery,\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Single record matching ID or null',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n static resolveFindOneConfig<\n C extends ICustomizableRoutes['findOne'],\n FindOneSchema extends TAnyObjectSchema,\n >(opts: { config: C; selectSchema: FindOneSchema }) {\n const { config, selectSchema } = opts;\n const defaultQuery = FilterQuerySchema.openapi({\n description: 'Filter with where, fields, order, include',\n });\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(selectSchema);\n\n return {\n request: {\n query: config?.request?.query ?? defaultQuery,\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'First matching record or null',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n /** `serverStampedKeys` - what the entity reports from `getServerStampedKeys()`; the default body leaves them out. */\n static resolveCreateConfig<\n C extends ICustomizableRoutes['create'],\n SelectSchema extends TAnyObjectSchema,\n CreateSchema extends TAnyObjectSchema,\n >(opts: {\n config: C;\n selectSchema: SelectSchema;\n createSchema: CreateSchema;\n serverStampedKeys?: string[];\n }) {\n const { config, selectSchema, createSchema, serverStampedKeys = [] } = opts;\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(selectSchema);\n\n return {\n request: {\n body:\n config?.request?.body ??\n RouteConfigResolver.toWriteBodySchema({\n schema: createSchema,\n route: 'create',\n serverStampedKeys,\n }),\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Created record with generated fields (id, createdAt, etc.)',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n private static resolveUpdateByIdConfig<\n C extends ICustomizableRoutes['updateById'],\n SelectSchema extends TAnyObjectSchema,\n UpdateSchema extends TAnyObjectSchema,\n >(opts: {\n idType: TIdSchemaType;\n config: C;\n selectSchema: SelectSchema;\n updateSchema: UpdateSchema;\n serverStampedKeys: string[];\n }) {\n const { config, selectSchema, updateSchema, idType, serverStampedKeys } = opts;\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(selectSchema);\n return {\n request: {\n params: RouteConfigResolver.resolveIdParams({ config, idType }),\n body:\n config?.request?.body ??\n RouteConfigResolver.toWriteBodySchema({\n schema: updateSchema,\n route: 'updateById',\n serverStampedKeys,\n }),\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Updated record with all current fields',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n private static resolveUpdateByConfig<\n C extends ICustomizableRoutes['updateBy'],\n SelectSchema extends TAnyObjectSchema,\n UpdateSchema extends TAnyObjectSchema,\n >(opts: {\n config: C;\n selectSchema: SelectSchema;\n updateSchema: UpdateSchema;\n serverStampedKeys: string[];\n }) {\n const { config, selectSchema, updateSchema, serverStampedKeys } = opts;\n const defaultQuery = z.object({ where: WhereSchema.optional() }).openapi({\n description:\n 'Where condition selecting the records to update - here or in the body, not both',\n });\n // Built only without a custom body: a custom body must not trip the entity schema's checks.\n const buildDefaultBody = () => {\n const writableSchema = RouteConfigResolver.toWriteBodySchema({\n schema: updateSchema,\n route: 'updateBy',\n serverStampedKeys,\n });\n // A model with a real `where` column keeps it: the body reserves the name only when it is\n // free, and the handler then simply finds no `where` there.\n return 'where' in writableSchema.shape\n ? writableSchema\n : writableSchema.extend({ where: WhereSchema.optional() });\n };\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(z.array(selectSchema));\n return {\n request: {\n query: config?.request?.query ?? defaultQuery,\n body: config?.request?.body ?? buildDefaultBody(),\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Array of updated records',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n private static resolveDeleteByIdConfig<\n C extends ICustomizableRoutes['deleteById'],\n SelectSchema extends TAnyObjectSchema,\n >(opts: { idType: TIdSchemaType; config: C; selectSchema: SelectSchema }) {\n const { config, selectSchema, idType } = opts;\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(selectSchema);\n return {\n request: {\n params: RouteConfigResolver.resolveIdParams({ config, idType }),\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Deleted record data',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n private static resolveDeleteByConfig<\n C extends ICustomizableRoutes['deleteBy'],\n SelectSchema extends TAnyObjectSchema,\n >(opts: { config: C; selectSchema: SelectSchema }) {\n const { config, selectSchema } = opts;\n const defaultQuery = z.object({ where: WhereSchema.optional() }).openapi({\n description:\n 'Where condition selecting the records to delete - here or in the body, not both',\n });\n const defaultSchema = RouteConfigResolver.conditionalCountResponse(z.array(selectSchema));\n return {\n request: {\n query: config?.request?.query ?? defaultQuery,\n // No DEFAULT body schema. Declaring one makes `@hono/zod-openapi` gate the media type, and a\n // client that sends `content-type: application/json` with no body then gets 400 where it used\n // to get 200. The handler reads the body itself; name one here to get the Swagger editor.\n body: config?.request?.body,\n headers: config?.request?.headers ?? defaultRequestHeaders,\n },\n response: {\n description: 'Array of deleted records',\n schema: RouteConfigResolver.resolveResponseSchema({ config, defaultSchema }),\n headers: config?.response?.headers ?? commonResponseHeaders,\n },\n };\n }\n\n /**\n * Generates complete route configurations for a CRUD controller. `serverStampedKeys` - what the\n * entity reports from `getServerStampedKeys()`; the default write bodies leave them out.\n */\n static defineControllerRouteConfigs<\n Routes extends ICustomizableRoutes,\n SelectSchema extends TAnyObjectSchema,\n CreateSchema extends TAnyObjectSchema,\n UpdateSchema extends TAnyObjectSchema,\n >(opts: {\n isStrict: boolean;\n idType: TIdSchemaType;\n authenticate?: { strategies?: TAuthStrategy[]; mode?: TAuthMode };\n authorize?: IAuthorizationSpec | IAuthorizationSpec[];\n schema: { select: SelectSchema; create: CreateSchema; update: UpdateSchema };\n serverStampedKeys?: string[];\n routes?: Routes;\n }) {\n const {\n isStrict,\n idType,\n authenticate: controllerAuth = {},\n authorize: controllerAuthorize,\n schema: { select: selectSchema, create: createSchema, update: updateSchema },\n serverStampedKeys = [],\n routes,\n } = opts;\n const { strategies: defaultStrategies = [], mode: defaultMode } = controllerAuth;\n\n // `Routes` is caller-bound but otherwise unconstrained here, so `{}` cannot be proven to satisfy it structurally even though every field ICustomizableRoutes declares is optional.\n const routesConfig = (routes ?? {}) as Routes;\n\n type TAuthenticateConfig = { strategies?: TAuthStrategy[]; mode?: TAuthMode };\n\n /** Priority: endpoint authenticate > controller authenticate. */\n const resolveRouteAuth = (routeKey: keyof ICustomizableRoutes): TAuthenticateConfig => {\n const endpointConfig = routesConfig[routeKey];\n const authConfig = endpointConfig?.authenticate;\n\n if (authConfig == null) {\n return { strategies: defaultStrategies, mode: defaultMode };\n }\n\n if (authConfig.skip === true) {\n return { strategies: [] };\n }\n\n return {\n strategies: authConfig.strategies ?? defaultStrategies,\n mode: authConfig.mode ?? defaultMode,\n };\n };\n\n type TAuthorizeConfig = IAuthorizationSpec | IAuthorizationSpec[] | undefined;\n\n /** Priority: endpoint authenticate.skip > endpoint authorize.skip > endpoint authorize > controller authorize. */\n const resolveRouteAuthorize = (routeKey: keyof ICustomizableRoutes): TAuthorizeConfig => {\n const endpointConfig = routesConfig[routeKey];\n\n if (endpointConfig?.authenticate?.skip === true) {\n return undefined;\n }\n\n const authorize = endpointConfig?.authorize;\n\n if (authorize == null) {\n return controllerAuthorize;\n }\n\n if (Array.isArray(authorize)) {\n return authorize;\n }\n\n if ('skip' in authorize) {\n return undefined;\n }\n\n return authorize;\n };\n\n const count = RouteConfigResolver.resolveCountConfig({ config: routesConfig.count, isStrict });\n const find = RouteConfigResolver.resolveFindConfig({ config: routesConfig.find, selectSchema });\n const findById = RouteConfigResolver.resolveFindByIdConfig({\n config: routesConfig.findById,\n selectSchema,\n idType,\n });\n const findOne = RouteConfigResolver.resolveFindOneConfig({\n config: routesConfig.findOne,\n selectSchema,\n });\n const create = RouteConfigResolver.resolveCreateConfig({\n config: routesConfig.create,\n selectSchema,\n createSchema,\n serverStampedKeys,\n });\n const updateById = RouteConfigResolver.resolveUpdateByIdConfig({\n config: routesConfig.updateById,\n selectSchema,\n updateSchema,\n idType,\n serverStampedKeys,\n });\n const updateBy = RouteConfigResolver.resolveUpdateByConfig({\n config: routesConfig.updateBy,\n selectSchema,\n updateSchema,\n serverStampedKeys,\n });\n const deleteById = RouteConfigResolver.resolveDeleteByIdConfig({\n config: routesConfig.deleteById,\n selectSchema,\n idType,\n });\n const deleteBy = RouteConfigResolver.resolveDeleteByConfig({\n config: routesConfig.deleteBy,\n selectSchema,\n });\n\n const rs = {\n COUNT: {\n method: HTTP.Methods.GET,\n path: RestPaths.COUNT,\n description: 'Count records matching where condition',\n authenticate: resolveRouteAuth('count'),\n authorize: resolveRouteAuthorize('count'),\n request: count.request,\n responses: jsonResponse(count.response),\n },\n\n FIND: {\n method: HTTP.Methods.GET,\n path: RestPaths.ROOT,\n description: 'Find records with filter, pagination, sorting, and relations',\n authenticate: resolveRouteAuth('find'),\n authorize: resolveRouteAuthorize('find'),\n request: find.request,\n responses: jsonResponse(find.response),\n },\n\n FIND_BY_ID: {\n method: HTTP.Methods.GET,\n path: '/{id}',\n description: 'Find single record by ID',\n authenticate: resolveRouteAuth('findById'),\n authorize: resolveRouteAuthorize('findById'),\n request: findById.request,\n responses: jsonResponse(findById.response),\n },\n\n FIND_ONE: {\n method: HTTP.Methods.GET,\n path: RestPaths.FIND_ONE,\n description: 'Find first record matching filter',\n authenticate: resolveRouteAuth('findOne'),\n authorize: resolveRouteAuthorize('findOne'),\n request: findOne.request,\n responses: jsonResponse(findOne.response),\n },\n\n CREATE: {\n method: HTTP.Methods.POST,\n path: RestPaths.ROOT,\n description: 'Create new record',\n authenticate: resolveRouteAuth('create'),\n authorize: resolveRouteAuthorize('create'),\n request: {\n body: jsonContent({\n description: 'Record data (required fields must be provided)',\n schema: create.request.body,\n }),\n headers: create.request.headers,\n },\n responses: jsonResponse(create.response),\n },\n\n UPDATE_BY_ID: {\n method: HTTP.Methods.PATCH,\n path: '/{id}',\n description: 'Partial update record by ID',\n authenticate: resolveRouteAuth('updateById'),\n authorize: resolveRouteAuthorize('updateById'),\n request: {\n params: updateById.request.params,\n body: jsonContent({\n description: 'Partial data (only changed fields)',\n schema: updateById.request.body,\n }),\n headers: updateById.request.headers,\n },\n responses: jsonResponse(updateById.response),\n },\n\n UPDATE_BY: {\n method: HTTP.Methods.PATCH,\n path: RestPaths.ROOT,\n description: 'Bulk update records matching where condition',\n authenticate: resolveRouteAuth('updateBy'),\n authorize: resolveRouteAuthorize('updateBy'),\n request: {\n query: updateBy.request.query,\n body: jsonContent({\n description: 'Partial data to apply to all matches',\n schema: updateBy.request.body,\n }),\n headers: updateBy.request.headers,\n },\n responses: jsonResponse(updateBy.response),\n },\n\n DELETE_BY_ID: {\n method: HTTP.Methods.DELETE,\n path: '/{id}',\n description: 'Delete record by ID (irreversible)',\n authenticate: resolveRouteAuth('deleteById'),\n authorize: resolveRouteAuthorize('deleteById'),\n request: deleteById.request,\n responses: jsonResponse(deleteById.response),\n },\n\n DELETE_BY: {\n method: HTTP.Methods.DELETE,\n path: RestPaths.ROOT,\n description: 'Bulk delete records matching where condition (irreversible)',\n authenticate: resolveRouteAuth('deleteBy'),\n authorize: resolveRouteAuthorize('deleteBy'),\n request: {\n query: deleteBy.request.query,\n ...(deleteBy.request.body\n ? {\n body: jsonContent({\n description: 'Where condition, when it does not fit in the query',\n schema: deleteBy.request.body,\n required: false,\n }),\n }\n : {}),\n headers: deleteBy.request.headers,\n },\n responses: jsonResponse(deleteBy.response),\n },\n } as const;\n\n return rs;\n }\n}\n\nexport const conditionalCountResponse = RouteConfigResolver.conditionalCountResponse;\nexport const resolveCountConfig = RouteConfigResolver.resolveCountConfig;\nexport const resolveFindConfig = RouteConfigResolver.resolveFindConfig;\nexport const resolveFindByIdConfig = RouteConfigResolver.resolveFindByIdConfig;\nexport const resolveFindOneConfig = RouteConfigResolver.resolveFindOneConfig;\nexport const resolveCreateConfig = RouteConfigResolver.resolveCreateConfig;\nexport const defineControllerRouteConfigs = RouteConfigResolver.defineControllerRouteConfigs;\n"]}
@@ -25,9 +25,9 @@ export class ResponseExtras {
25
25
  ? undefined
26
26
  : match[3]
27
27
  .split(',')
28
- .map(key => key.trim())
29
- .filter(key => key.length > 0);
30
- if (keys?.some(key => !IDENTIFIER.test(key))) {
28
+ .map((key) => key.trim())
29
+ .filter((key) => key.length > 0);
30
+ if (keys?.some((key) => !IDENTIFIER.test(key))) {
31
31
  throw ResponseExtras.badRequest({ message: `Malformed key in extra '${raw.trim()}'` });
32
32
  }
33
33
  entries.push({ name, isExcluded: match[1] === '-', keys });
@@ -77,7 +77,7 @@ export class ResponseExtras {
77
77
  message: `Extra '${entry.name}' needs keys: ${definition.keys.join(', ')} | Name them as ${entry.name}(key,key)`,
78
78
  });
79
79
  }
80
- const unknown = entry.keys.filter(key => !definition.keys.includes(key));
80
+ const unknown = entry.keys.filter((key) => !definition.keys.includes(key));
81
81
  if (unknown.length > 0) {
82
82
  throw ResponseExtras.badRequest({
83
83
  message: `Unknown key for extra '${entry.name}': ${unknown.join(', ')} | It offers: ${definition.keys.join(', ')}`,
@@ -137,7 +137,7 @@ export class ResponseExtras {
137
137
  current += character;
138
138
  }
139
139
  parts.push(current);
140
- return parts.filter(part => part.trim().length > 0);
140
+ return parts.filter((part) => part.trim().length > 0);
141
141
  }
142
142
  static badRequest(opts) {
143
143
  return getError({
@@ -1 +1 @@
1
- {"version":3,"file":"extras.js","sourceRoot":"","sources":["../../../../../src/base/controllers/rest/extras.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport { HTTP } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\n\n/**\n * A figure a list route offers beside its rows:\n * - a function runs when the client names it;\n * - `{ isDefault: true, compute }` always runs, unless the client switches it off with `-name`;\n * - `{ keys, compute }` is a group - the client names the keys it wants (`facets(status,tag)`), and\n * `compute` receives exactly those, so one aggregate pass serves them all.\n */\nexport type TResponseExtra =\n | (() => ValueOrPromise<unknown>)\n | { isDefault: boolean; compute: () => ValueOrPromise<unknown>; keys?: never }\n | {\n keys: ReadonlyArray<string>;\n compute: (opts: { keys: Array<string> }) => ValueOrPromise<unknown>;\n isDefault?: never;\n };\n\n/** One entry of `x-request-extra`: `name`, `-name` (a default switched off), `-*` (every default off) or `name(key,key)`. */\nexport interface IRequestedExtra {\n name: string;\n isExcluded: boolean;\n keys?: Array<string>;\n}\n\n/** A name or a key: letters, digits, `_`, `.` and `-` inside. Anything else is refused, never evaluated. */\nconst IDENTIFIER = /^[A-Za-z_][\\w.-]*$/;\nconst ENTRY = /^(-?)([^()\\s]+)(?:\\(([^()]*)\\))?$/;\n\n/** `-*`: every default off - for a read that wants the rows alone. */\nconst ALL_DEFAULTS = '*';\n\n/** Parses `x-request-extra` and resolves it against what a route offers. */\nexport class ResponseExtras {\n /** The entries of the header, in the order written. Malformed input is a 400 naming it. */\n static parse(opts: { header?: string | null }): Array<IRequestedExtra> {\n const header = opts.header?.trim() ?? '';\n if (header === '') {\n return [];\n }\n\n const entries: Array<IRequestedExtra> = [];\n for (const raw of ResponseExtras.splitTopLevel({ header })) {\n const match = raw.trim().match(ENTRY);\n const name = match?.[2];\n\n const isAllDefaultsOff =\n match?.[1] === '-' && name === ALL_DEFAULTS && match[3] === undefined;\n if (!match || !name || (!isAllDefaultsOff && !IDENTIFIER.test(name))) {\n throw ResponseExtras.badRequest({ message: `Malformed extra '${raw.trim()}'` });\n }\n\n const keys =\n match[3] === undefined\n ? undefined\n : match[3]\n .split(',')\n .map(key => key.trim())\n .filter(key => key.length > 0);\n\n if (keys?.some(key => !IDENTIFIER.test(key))) {\n throw ResponseExtras.badRequest({ message: `Malformed key in extra '${raw.trim()}'` });\n }\n\n entries.push({ name, isExcluded: match[1] === '-', keys });\n }\n\n return entries;\n }\n\n /**\n * What to compute: the asked-for extras and the defaults, minus the ones switched off - each with the\n * keys asked for, de-duplicated in the order asked. Every name and key is checked against `offered`.\n */\n static resolve(opts: {\n requested: Array<IRequestedExtra>;\n offered: Record<string, TResponseExtra>;\n }): Map<string, Array<string> | undefined> {\n const { requested, offered } = opts;\n const offeredNames = Object.keys(offered).join(', ') || 'none';\n const plan = new Map<string, Array<string> | undefined>();\n const excluded = new Set<string>();\n\n let isEveryDefaultOff = false;\n\n for (const entry of requested) {\n if (entry.isExcluded && entry.name === ALL_DEFAULTS) {\n isEveryDefaultOff = true;\n continue;\n }\n\n if (!Object.hasOwn(offered, entry.name)) {\n throw ResponseExtras.badRequest({\n message: `Unknown extra requested: ${entry.name} | This route offers: ${offeredNames}`,\n });\n }\n\n if (entry.isExcluded) {\n if (entry.keys !== undefined) {\n throw ResponseExtras.badRequest({\n message: `Switching '${entry.name}' off takes no keys`,\n });\n }\n\n excluded.add(entry.name);\n continue;\n }\n\n const definition = offered[entry.name];\n const isGroup = typeof definition !== 'function' && definition.keys !== undefined;\n\n if (!isGroup) {\n if (entry.keys !== undefined) {\n throw ResponseExtras.badRequest({ message: `Extra '${entry.name}' takes no keys` });\n }\n\n plan.set(entry.name, undefined);\n continue;\n }\n\n if (!entry.keys?.length) {\n throw ResponseExtras.badRequest({\n message: `Extra '${entry.name}' needs keys: ${definition.keys.join(', ')} | Name them as ${entry.name}(key,key)`,\n });\n }\n\n const unknown = entry.keys.filter(key => !definition.keys.includes(key));\n if (unknown.length > 0) {\n throw ResponseExtras.badRequest({\n message: `Unknown key for extra '${entry.name}': ${unknown.join(', ')} | It offers: ${definition.keys.join(', ')}`,\n });\n }\n\n plan.set(entry.name, [...new Set([...(plan.get(entry.name) ?? []), ...entry.keys])]);\n }\n\n for (const [name, definition] of Object.entries(offered)) {\n // A group needs keys, so it never runs unasked, whatever its declaration claims.\n const isDefault =\n typeof definition !== 'function' &&\n definition.keys === undefined &&\n definition.isDefault === true;\n if (isDefault && !isEveryDefaultOff && !plan.has(name)) {\n plan.set(name, undefined);\n }\n }\n\n for (const name of excluded) {\n plan.delete(name);\n }\n\n return plan;\n }\n\n /** Runs the plan in parallel; each value under its name. */\n static async compute(opts: {\n plan: Map<string, Array<string> | undefined>;\n offered: Record<string, TResponseExtra>;\n }): Promise<Record<string, unknown>> {\n const { plan, offered } = opts;\n const names = [...plan.keys()];\n\n // Async, so an extra that throws synchronously becomes a rejection Promise.all owns, never an\n // unhandled one left behind by a sibling already running.\n const values = await Promise.all(\n names.map(async name => {\n const definition = offered[name];\n\n if (typeof definition === 'function') {\n return definition();\n }\n\n if (definition.keys !== undefined) {\n return definition.compute({ keys: plan.get(name) ?? [] });\n }\n\n return definition.compute();\n }),\n );\n\n return Object.fromEntries(names.map((name, index) => [name, values[index]]));\n }\n\n /** Commas inside `( )` belong to the keys, not to the list of extras. */\n private static splitTopLevel(opts: { header: string }): Array<string> {\n const parts: Array<string> = [];\n let depth = 0;\n let current = '';\n\n for (const character of opts.header) {\n if (character === '(') {\n depth++;\n } else if (character === ')') {\n depth--;\n }\n\n if (character === ',' && depth === 0) {\n parts.push(current);\n current = '';\n continue;\n }\n\n current += character;\n }\n\n parts.push(current);\n return parts.filter(part => part.trim().length > 0);\n }\n\n private static badRequest(opts: { message: string }) {\n return getError({\n statusCode: HTTP.ResultCodes.RS_4.BadRequest,\n message: `[x-request-extra] ${opts.message}`,\n });\n }\n}\n"]}
1
+ {"version":3,"file":"extras.js","sourceRoot":"","sources":["../../../../../src/base/controllers/rest/extras.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport { HTTP } from '@venizia/ignis-helpers/common';\nimport { getError } from '@venizia/ignis-helpers/core';\n\n/**\n * A figure a list route offers beside its rows:\n * - a function runs when the client names it;\n * - `{ isDefault: true, compute }` always runs, unless the client switches it off with `-name`;\n * - `{ keys, compute }` is a group - the client names the keys it wants (`facets(status,tag)`), and\n * `compute` receives exactly those, so one aggregate pass serves them all.\n */\nexport type TResponseExtra =\n | (() => ValueOrPromise<unknown>)\n | { isDefault: boolean; compute: () => ValueOrPromise<unknown>; keys?: never }\n | {\n keys: ReadonlyArray<string>;\n compute: (opts: { keys: Array<string> }) => ValueOrPromise<unknown>;\n isDefault?: never;\n };\n\n/** One entry of `x-request-extra`: `name`, `-name` (a default switched off), `-*` (every default off) or `name(key,key)`. */\nexport interface IRequestedExtra {\n name: string;\n isExcluded: boolean;\n keys?: Array<string>;\n}\n\n/** A name or a key: letters, digits, `_`, `.` and `-` inside. Anything else is refused, never evaluated. */\nconst IDENTIFIER = /^[A-Za-z_][\\w.-]*$/;\nconst ENTRY = /^(-?)([^()\\s]+)(?:\\(([^()]*)\\))?$/;\n\n/** `-*`: every default off - for a read that wants the rows alone. */\nconst ALL_DEFAULTS = '*';\n\n/** Parses `x-request-extra` and resolves it against what a route offers. */\nexport class ResponseExtras {\n /** The entries of the header, in the order written. Malformed input is a 400 naming it. */\n static parse(opts: { header?: string | null }): Array<IRequestedExtra> {\n const header = opts.header?.trim() ?? '';\n if (header === '') {\n return [];\n }\n\n const entries: Array<IRequestedExtra> = [];\n for (const raw of ResponseExtras.splitTopLevel({ header })) {\n const match = raw.trim().match(ENTRY);\n const name = match?.[2];\n\n const isAllDefaultsOff =\n match?.[1] === '-' && name === ALL_DEFAULTS && match[3] === undefined;\n if (!match || !name || (!isAllDefaultsOff && !IDENTIFIER.test(name))) {\n throw ResponseExtras.badRequest({ message: `Malformed extra '${raw.trim()}'` });\n }\n\n const keys =\n match[3] === undefined\n ? undefined\n : match[3]\n .split(',')\n .map((key) => key.trim())\n .filter((key) => key.length > 0);\n\n if (keys?.some((key) => !IDENTIFIER.test(key))) {\n throw ResponseExtras.badRequest({ message: `Malformed key in extra '${raw.trim()}'` });\n }\n\n entries.push({ name, isExcluded: match[1] === '-', keys });\n }\n\n return entries;\n }\n\n /**\n * What to compute: the asked-for extras and the defaults, minus the ones switched off - each with the\n * keys asked for, de-duplicated in the order asked. Every name and key is checked against `offered`.\n */\n static resolve(opts: {\n requested: Array<IRequestedExtra>;\n offered: Record<string, TResponseExtra>;\n }): Map<string, Array<string> | undefined> {\n const { requested, offered } = opts;\n const offeredNames = Object.keys(offered).join(', ') || 'none';\n const plan = new Map<string, Array<string> | undefined>();\n const excluded = new Set<string>();\n\n let isEveryDefaultOff = false;\n\n for (const entry of requested) {\n if (entry.isExcluded && entry.name === ALL_DEFAULTS) {\n isEveryDefaultOff = true;\n continue;\n }\n\n if (!Object.hasOwn(offered, entry.name)) {\n throw ResponseExtras.badRequest({\n message: `Unknown extra requested: ${entry.name} | This route offers: ${offeredNames}`,\n });\n }\n\n if (entry.isExcluded) {\n if (entry.keys !== undefined) {\n throw ResponseExtras.badRequest({\n message: `Switching '${entry.name}' off takes no keys`,\n });\n }\n\n excluded.add(entry.name);\n continue;\n }\n\n const definition = offered[entry.name];\n const isGroup = typeof definition !== 'function' && definition.keys !== undefined;\n\n if (!isGroup) {\n if (entry.keys !== undefined) {\n throw ResponseExtras.badRequest({ message: `Extra '${entry.name}' takes no keys` });\n }\n\n plan.set(entry.name, undefined);\n continue;\n }\n\n if (!entry.keys?.length) {\n throw ResponseExtras.badRequest({\n message: `Extra '${entry.name}' needs keys: ${definition.keys.join(', ')} | Name them as ${entry.name}(key,key)`,\n });\n }\n\n const unknown = entry.keys.filter((key) => !definition.keys.includes(key));\n if (unknown.length > 0) {\n throw ResponseExtras.badRequest({\n message: `Unknown key for extra '${entry.name}': ${unknown.join(', ')} | It offers: ${definition.keys.join(', ')}`,\n });\n }\n\n plan.set(entry.name, [...new Set([...(plan.get(entry.name) ?? []), ...entry.keys])]);\n }\n\n for (const [name, definition] of Object.entries(offered)) {\n // A group needs keys, so it never runs unasked, whatever its declaration claims.\n const isDefault =\n typeof definition !== 'function' &&\n definition.keys === undefined &&\n definition.isDefault === true;\n if (isDefault && !isEveryDefaultOff && !plan.has(name)) {\n plan.set(name, undefined);\n }\n }\n\n for (const name of excluded) {\n plan.delete(name);\n }\n\n return plan;\n }\n\n /** Runs the plan in parallel; each value under its name. */\n static async compute(opts: {\n plan: Map<string, Array<string> | undefined>;\n offered: Record<string, TResponseExtra>;\n }): Promise<Record<string, unknown>> {\n const { plan, offered } = opts;\n const names = [...plan.keys()];\n\n // Async, so an extra that throws synchronously becomes a rejection Promise.all owns, never an\n // unhandled one left behind by a sibling already running.\n const values = await Promise.all(\n names.map(async (name) => {\n const definition = offered[name];\n\n if (typeof definition === 'function') {\n return definition();\n }\n\n if (definition.keys !== undefined) {\n return definition.compute({ keys: plan.get(name) ?? [] });\n }\n\n return definition.compute();\n }),\n );\n\n return Object.fromEntries(names.map((name, index) => [name, values[index]]));\n }\n\n /** Commas inside `( )` belong to the keys, not to the list of extras. */\n private static splitTopLevel(opts: { header: string }): Array<string> {\n const parts: Array<string> = [];\n let depth = 0;\n let current = '';\n\n for (const character of opts.header) {\n if (character === '(') {\n depth++;\n } else if (character === ')') {\n depth--;\n }\n\n if (character === ',' && depth === 0) {\n parts.push(current);\n current = '';\n continue;\n }\n\n current += character;\n }\n\n parts.push(current);\n return parts.filter((part) => part.trim().length > 0);\n }\n\n private static badRequest(opts: { message: string }) {\n return getError({\n statusCode: HTTP.ResultCodes.RS_4.BadRequest,\n message: `[x-request-extra] ${opts.message}`,\n });\n }\n}\n"]}
@@ -4,7 +4,7 @@ import { ArtifactBindingKeys } from './artifact-keys.js';
4
4
  import { getError } from '@venizia/ignis-helpers/core';
5
5
  /** The root stereotype: marks a class as an artifact the application registers, with its registration defaults. Every other stereotype calls it. */
6
6
  export const injectable = (opts) => {
7
- return target => {
7
+ return (target) => {
8
8
  if (!ArtifactTypes.isValid(opts.type)) {
9
9
  throw getError({
10
10
  message: `[injectable][${target.name}] Invalid artifact type: '${opts.type}' | Expected one of: ${[...ArtifactTypes.SCHEME_SET].join(', ')}`,
@@ -1 +1 @@
1
- {"version":3,"file":"injectable.js","sourceRoot":"","sources":["../../../../src/base/metadata/injectable.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAEvD,oJAAoJ;AACpJ,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,IAAwC,EACxB,EAAE;IAClB,OAAO,MAAM,CAAC,EAAE;QACd,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACtC,MAAM,QAAQ,CAAC;gBACb,OAAO,EAAE,gBAAgB,MAAM,CAAC,IAAI,6BAA6B,IAAI,CAAC,IAAI,wBAAwB,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;aAC7I,CAAC,CAAC;QACL,CAAC;QAED,kFAAkF;QAClF,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,iBAAiB,CAAC,uBAAuB,CAAC;gBACxC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;gBACjC,QAAQ,EAAE,MAAM,CAAC,IAAI;gBACrB,MAAM,EAAE,YAAY;aACrB,CAAC,CAAC;QACL,CAAC;QAED,MAAM,QAAQ,GAAG,gBAAgB,CAAC,WAAW,EAAE,CAAC;QAChD,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAEzD,4FAA4F;QAC5F,yFAAyF;QACzF,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;QAE3C,8FAA8F;QAC9F,QAAQ,CAAC,aAAa,CAAC;YACrB,MAAM;YACN,GAAG,EAAE,mBAAmB,CAAC,OAAO,CAAC;gBAC/B,MAAM;gBACN,SAAS,EAAE,kBAAkB,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC1D,OAAO,EAAE,IAAI,CAAC,OAAO;aACtB,CAAC,CAAC,GAAG;YACN,aAAa,EAAE,IAAI;SACpB,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAG,CACrB,IAAoD,EACpC,EAAE;IAClB,OAAO,UAAU,CAAkB,EAAE,IAAI,EAAE,aAAa,CAAC,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;AAC/E,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,IAAoD,EACpC,EAAE;IAClB,OAAO,UAAU,CAAkB,EAAE,IAAI,EAAE,aAAa,CAAC,SAAS,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;AACjF,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,IAAoD,EACpC,EAAE;IAClB,OAAO,UAAU,CAAkB,EAAE,IAAI,EAAE,aAAa,CAAC,aAAa,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;AACrF,CAAC,CAAC;AACF,yMAAyM;AACzM,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAA4C,EAAmB,EAAE;IACvF,OAAO,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE;QAC7B,gBAAgB,CAAC,WAAW,EAAE,CAAC,kBAAkB,CAAC;YAChD,MAAM,EAAE,MAAM,CAAC,WAAW;YAC1B,QAAQ,EAAE;gBACR,UAAU,EAAE,WAAW;gBACvB,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC7C;SACF,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,gIAAgI;AAChI,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAA4B,IAElE,EAAiD,EAAE;IAClD,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;IAC5E,MAAM,YAAY,GAAkD,EAAE,CAAC;IAEvE,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,YAAY,CAAC,OAAO,GAAG,OAAO,CAAC;IACjC,CAAC;IAED,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAChC,YAAY,CAAC,aAAa,GAAG,aAAa,CAAC;IAC7C,CAAC;IAED,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC;IAC7B,CAAC;IAED,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC;IAC7B,CAAC;IAED,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,YAAY,CAAC,IAAI,GAAG,IAAI,CAAC;IAC3B,CAAC;IAED,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,YAAY,CAAC,KAAK,GAAG,KAAK,CAAC;IAC7B,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC","sourcesContent":["import type {\n IArtifactMetadata,\n IArtifactRegistrationOptions,\n TBindingScope,\n} from '@/helpers/inversion';\nimport { ArtifactNamespaces, BindingNamespaces } from '@/common/bindings';\nimport { ArtifactTypes, MetadataRegistry } from '@/helpers/inversion';\nimport { ArtifactBindingKeys } from './artifact-keys';\nimport { getError } from '@venizia/ignis-helpers/core';\n\n/** The root stereotype: marks a class as an artifact the application registers, with its registration defaults. Every other stereotype calls it. */\nexport const injectable = <ApplicationType = unknown>(\n opts: IArtifactMetadata<ApplicationType>,\n): ClassDecorator => {\n return target => {\n if (!ArtifactTypes.isValid(opts.type)) {\n throw getError({\n message: `[injectable][${target.name}] Invalid artifact type: '${opts.type}' | Expected one of: ${[...ArtifactTypes.SCHEME_SET].join(', ')}`,\n });\n }\n\n // At import time, so the failure lands where the binding is written, not at boot.\n if (opts.binding) {\n BindingNamespaces.assertArtifactNamespace({\n namespace: opts.binding.namespace,\n artifact: target.name,\n caller: 'injectable',\n });\n }\n\n const registry = MetadataRegistry.getInstance();\n registry.setArtifactMetadata({ target, metadata: opts });\n\n // Discovery happens HERE, at import time. A boot-time filesystem scan cannot see a compiled\n // single-file binary, and a class exists at run time only because something imported it.\n registry.addDiscoveredArtifact({ target });\n\n // The key this class WOULD get; `registerArtifact` overwrites it with the one actually bound.\n registry.setBindingKey({\n target,\n key: ArtifactBindingKeys.resolve({\n target,\n namespace: ArtifactNamespaces.resolve({ type: opts.type }),\n binding: opts.binding,\n }).key,\n isProvisional: true,\n });\n };\n};\n\nexport const service = <ApplicationType = unknown>(\n opts?: IArtifactRegistrationOptions<ApplicationType>,\n): ClassDecorator => {\n return injectable<ApplicationType>({ type: ArtifactTypes.SERVICE, ...opts });\n};\n\nexport const component = <ApplicationType = unknown>(\n opts?: IArtifactRegistrationOptions<ApplicationType>,\n): ClassDecorator => {\n return injectable<ApplicationType>({ type: ArtifactTypes.COMPONENT, ...opts });\n};\n\nexport const configuration = <ApplicationType = unknown>(\n opts?: IArtifactRegistrationOptions<ApplicationType>,\n): ClassDecorator => {\n return injectable<ApplicationType>({ type: ArtifactTypes.CONFIGURATION, ...opts });\n};\n/** Marks a component method as the provider of `key`. `registerArtifacts` binds the key to a lazy provider that resolves the component and calls the method; SINGLETON unless `scope` says otherwise. */\nexport const provide = (opts: { key: string; scope?: TBindingScope }): MethodDecorator => {\n return (target, propertyKey) => {\n MetadataRegistry.getInstance().addProvideMetadata({\n target: target.constructor,\n metadata: {\n methodName: propertyKey,\n key: opts.key,\n ...(opts.scope ? { scope: opts.scope } : {}),\n },\n });\n };\n};\n\n/** The registration defaults a stereotype forwards to `@injectable`, copied field by field so an absent option stays absent. */\nexport const pickRegistrationOptions = <ApplicationType = unknown>(opts: {\n metadata: IArtifactRegistrationOptions<ApplicationType>;\n}): IArtifactRegistrationOptions<ApplicationType> => {\n const { binding, allowOverride, scope, order, when, after } = opts.metadata;\n const registration: IArtifactRegistrationOptions<ApplicationType> = {};\n\n if (binding !== undefined) {\n registration.binding = binding;\n }\n\n if (allowOverride !== undefined) {\n registration.allowOverride = allowOverride;\n }\n\n if (scope !== undefined) {\n registration.scope = scope;\n }\n\n if (order !== undefined) {\n registration.order = order;\n }\n\n if (when !== undefined) {\n registration.when = when;\n }\n\n if (after !== undefined) {\n registration.after = after;\n }\n\n return registration;\n};\n"]}
1
+ {"version":3,"file":"injectable.js","sourceRoot":"","sources":["../../../../src/base/metadata/injectable.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n IArtifactMetadata,\n IArtifactRegistrationOptions,\n TBindingScope,\n} from '@/helpers/inversion';\nimport { ArtifactNamespaces, BindingNamespaces } from '@/common/bindings';\nimport { ArtifactTypes, MetadataRegistry } from '@/helpers/inversion';\nimport { ArtifactBindingKeys } from './artifact-keys';\nimport { getError } from '@venizia/ignis-helpers/core';\n\n/** The root stereotype: marks a class as an artifact the application registers, with its registration defaults. Every other stereotype calls it. */\nexport const injectable = <ApplicationType = unknown>(\n opts: IArtifactMetadata<ApplicationType>,\n): ClassDecorator => {\n return (target) => {\n if (!ArtifactTypes.isValid(opts.type)) {\n throw getError({\n message: `[injectable][${target.name}] Invalid artifact type: '${opts.type}' | Expected one of: ${[...ArtifactTypes.SCHEME_SET].join(', ')}`,\n });\n }\n\n // At import time, so the failure lands where the binding is written, not at boot.\n if (opts.binding) {\n BindingNamespaces.assertArtifactNamespace({\n namespace: opts.binding.namespace,\n artifact: target.name,\n caller: 'injectable',\n });\n }\n\n const registry = MetadataRegistry.getInstance();\n registry.setArtifactMetadata({ target, metadata: opts });\n\n // Discovery happens HERE, at import time. A boot-time filesystem scan cannot see a compiled\n // single-file binary, and a class exists at run time only because something imported it.\n registry.addDiscoveredArtifact({ target });\n\n // The key this class WOULD get; `registerArtifact` overwrites it with the one actually bound.\n registry.setBindingKey({\n target,\n key: ArtifactBindingKeys.resolve({\n target,\n namespace: ArtifactNamespaces.resolve({ type: opts.type }),\n binding: opts.binding,\n }).key,\n isProvisional: true,\n });\n };\n};\n\nexport const service = <ApplicationType = unknown>(\n opts?: IArtifactRegistrationOptions<ApplicationType>,\n): ClassDecorator => {\n return injectable<ApplicationType>({ type: ArtifactTypes.SERVICE, ...opts });\n};\n\nexport const component = <ApplicationType = unknown>(\n opts?: IArtifactRegistrationOptions<ApplicationType>,\n): ClassDecorator => {\n return injectable<ApplicationType>({ type: ArtifactTypes.COMPONENT, ...opts });\n};\n\nexport const configuration = <ApplicationType = unknown>(\n opts?: IArtifactRegistrationOptions<ApplicationType>,\n): ClassDecorator => {\n return injectable<ApplicationType>({ type: ArtifactTypes.CONFIGURATION, ...opts });\n};\n/** Marks a component method as the provider of `key`. `registerArtifacts` binds the key to a lazy provider that resolves the component and calls the method; SINGLETON unless `scope` says otherwise. */\nexport const provide = (opts: { key: string; scope?: TBindingScope }): MethodDecorator => {\n return (target, propertyKey) => {\n MetadataRegistry.getInstance().addProvideMetadata({\n target: target.constructor,\n metadata: {\n methodName: propertyKey,\n key: opts.key,\n ...(opts.scope ? { scope: opts.scope } : {}),\n },\n });\n };\n};\n\n/** The registration defaults a stereotype forwards to `@injectable`, copied field by field so an absent option stays absent. */\nexport const pickRegistrationOptions = <ApplicationType = unknown>(opts: {\n metadata: IArtifactRegistrationOptions<ApplicationType>;\n}): IArtifactRegistrationOptions<ApplicationType> => {\n const { binding, allowOverride, scope, order, when, after } = opts.metadata;\n const registration: IArtifactRegistrationOptions<ApplicationType> = {};\n\n if (binding !== undefined) {\n registration.binding = binding;\n }\n\n if (allowOverride !== undefined) {\n registration.allowOverride = allowOverride;\n }\n\n if (scope !== undefined) {\n registration.scope = scope;\n }\n\n if (order !== undefined) {\n registration.order = order;\n }\n\n if (when !== undefined) {\n registration.when = when;\n }\n\n if (after !== undefined) {\n registration.after = after;\n }\n\n return registration;\n};\n"]}