@endora-commerce/platform 0.100.0

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 (657) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/cli/dispatch.d.ts +146 -0
  4. package/dist/cli/dispatch.d.ts.map +1 -0
  5. package/dist/cli/dispatch.js +259 -0
  6. package/dist/cli/dispatch.js.map +1 -0
  7. package/dist/cli/index.d.ts +58 -0
  8. package/dist/cli/index.d.ts.map +1 -0
  9. package/dist/cli/index.js +58 -0
  10. package/dist/cli/index.js.map +1 -0
  11. package/dist/cli/module-commands.d.ts +118 -0
  12. package/dist/cli/module-commands.d.ts.map +1 -0
  13. package/dist/cli/module-commands.js +120 -0
  14. package/dist/cli/module-commands.js.map +1 -0
  15. package/dist/commands/actor.d.ts +19 -0
  16. package/dist/commands/actor.d.ts.map +1 -0
  17. package/dist/commands/actor.js +45 -0
  18. package/dist/commands/actor.js.map +1 -0
  19. package/dist/commands/audit-from-context.d.ts +24 -0
  20. package/dist/commands/audit-from-context.d.ts.map +1 -0
  21. package/dist/commands/audit-from-context.js +28 -0
  22. package/dist/commands/audit-from-context.js.map +1 -0
  23. package/dist/commands/command-bus.d.ts +40 -0
  24. package/dist/commands/command-bus.d.ts.map +1 -0
  25. package/dist/commands/command-bus.js +46 -0
  26. package/dist/commands/command-bus.js.map +1 -0
  27. package/dist/commands/command.d.ts +76 -0
  28. package/dist/commands/command.d.ts.map +1 -0
  29. package/dist/commands/command.js +2 -0
  30. package/dist/commands/command.js.map +1 -0
  31. package/dist/commands/index.d.ts +65 -0
  32. package/dist/commands/index.d.ts.map +1 -0
  33. package/dist/commands/index.js +57 -0
  34. package/dist/commands/index.js.map +1 -0
  35. package/dist/commands/reversible.d.ts +66 -0
  36. package/dist/commands/reversible.d.ts.map +1 -0
  37. package/dist/commands/reversible.js +41 -0
  38. package/dist/commands/reversible.js.map +1 -0
  39. package/dist/composition/compose-app.d.ts +305 -0
  40. package/dist/composition/compose-app.d.ts.map +1 -0
  41. package/dist/composition/compose-app.js +939 -0
  42. package/dist/composition/compose-app.js.map +1 -0
  43. package/dist/composition/index.d.ts +92 -0
  44. package/dist/composition/index.d.ts.map +1 -0
  45. package/dist/composition/index.js +175 -0
  46. package/dist/composition/index.js.map +1 -0
  47. package/dist/composition/newsletter-token-secret.d.ts +19 -0
  48. package/dist/composition/newsletter-token-secret.d.ts.map +1 -0
  49. package/dist/composition/newsletter-token-secret.js +24 -0
  50. package/dist/composition/newsletter-token-secret.js.map +1 -0
  51. package/dist/composition/process-runs-workers.d.ts +17 -0
  52. package/dist/composition/process-runs-workers.d.ts.map +1 -0
  53. package/dist/composition/process-runs-workers.js +19 -0
  54. package/dist/composition/process-runs-workers.js.map +1 -0
  55. package/dist/db/baseline-migration-inventory.d.ts +15 -0
  56. package/dist/db/baseline-migration-inventory.d.ts.map +1 -0
  57. package/dist/db/baseline-migration-inventory.js +115 -0
  58. package/dist/db/baseline-migration-inventory.js.map +1 -0
  59. package/dist/db/configured-entities.d.ts +74 -0
  60. package/dist/db/configured-entities.d.ts.map +1 -0
  61. package/dist/db/configured-entities.js +20 -0
  62. package/dist/db/configured-entities.js.map +1 -0
  63. package/dist/db/configured-migrations.d.ts +199 -0
  64. package/dist/db/configured-migrations.d.ts.map +1 -0
  65. package/dist/db/configured-migrations.js +181 -0
  66. package/dist/db/configured-migrations.js.map +1 -0
  67. package/dist/db/index.d.ts +54 -0
  68. package/dist/db/index.d.ts.map +1 -0
  69. package/dist/db/index.js +54 -0
  70. package/dist/db/index.js.map +1 -0
  71. package/dist/db/migrate.d.ts +21 -0
  72. package/dist/db/migrate.d.ts.map +1 -0
  73. package/dist/db/migrate.js +48 -0
  74. package/dist/db/migrate.js.map +1 -0
  75. package/dist/db/migration-order.d.ts +159 -0
  76. package/dist/db/migration-order.d.ts.map +1 -0
  77. package/dist/db/migration-order.js +273 -0
  78. package/dist/db/migration-order.js.map +1 -0
  79. package/dist/db/mikro-orm.config.d.ts +51 -0
  80. package/dist/db/mikro-orm.config.d.ts.map +1 -0
  81. package/dist/db/mikro-orm.config.js +64 -0
  82. package/dist/db/mikro-orm.config.js.map +1 -0
  83. package/dist/db/orm.d.ts +40 -0
  84. package/dist/db/orm.d.ts.map +1 -0
  85. package/dist/db/orm.js +25 -0
  86. package/dist/db/orm.js.map +1 -0
  87. package/dist/db/platform-schema.d.ts +102 -0
  88. package/dist/db/platform-schema.d.ts.map +1 -0
  89. package/dist/db/platform-schema.js +79 -0
  90. package/dist/db/platform-schema.js.map +1 -0
  91. package/dist/db/pluralizing-naming-strategy.d.ts +16 -0
  92. package/dist/db/pluralizing-naming-strategy.d.ts.map +1 -0
  93. package/dist/db/pluralizing-naming-strategy.js +66 -0
  94. package/dist/db/pluralizing-naming-strategy.js.map +1 -0
  95. package/dist/demo/guard.d.ts +101 -0
  96. package/dist/demo/guard.d.ts.map +1 -0
  97. package/dist/demo/guard.js +168 -0
  98. package/dist/demo/guard.js.map +1 -0
  99. package/dist/demo/host-command.d.ts +133 -0
  100. package/dist/demo/host-command.d.ts.map +1 -0
  101. package/dist/demo/host-command.js +113 -0
  102. package/dist/demo/host-command.js.map +1 -0
  103. package/dist/demo/index.d.ts +82 -0
  104. package/dist/demo/index.d.ts.map +1 -0
  105. package/dist/demo/index.js +82 -0
  106. package/dist/demo/index.js.map +1 -0
  107. package/dist/demo/packages.d.ts +67 -0
  108. package/dist/demo/packages.d.ts.map +1 -0
  109. package/dist/demo/packages.js +132 -0
  110. package/dist/demo/packages.js.map +1 -0
  111. package/dist/demo/plan.d.ts +111 -0
  112. package/dist/demo/plan.d.ts.map +1 -0
  113. package/dist/demo/plan.js +74 -0
  114. package/dist/demo/plan.js.map +1 -0
  115. package/dist/demo/report.d.ts +17 -0
  116. package/dist/demo/report.d.ts.map +1 -0
  117. package/dist/demo/report.js +85 -0
  118. package/dist/demo/report.js.map +1 -0
  119. package/dist/demo/runner.d.ts +207 -0
  120. package/dist/demo/runner.d.ts.map +1 -0
  121. package/dist/demo/runner.js +169 -0
  122. package/dist/demo/runner.js.map +1 -0
  123. package/dist/demo/scope.d.ts +44 -0
  124. package/dist/demo/scope.d.ts.map +1 -0
  125. package/dist/demo/scope.js +44 -0
  126. package/dist/demo/scope.js.map +1 -0
  127. package/dist/env/index.d.ts +68 -0
  128. package/dist/env/index.d.ts.map +1 -0
  129. package/dist/env/index.js +427 -0
  130. package/dist/env/index.js.map +1 -0
  131. package/dist/events/bus.d.ts +29 -0
  132. package/dist/events/bus.d.ts.map +1 -0
  133. package/dist/events/bus.js +67 -0
  134. package/dist/events/bus.js.map +1 -0
  135. package/dist/events/index.d.ts +19 -0
  136. package/dist/events/index.d.ts.map +1 -0
  137. package/dist/events/index.js +19 -0
  138. package/dist/events/index.js.map +1 -0
  139. package/dist/http/cursor.d.ts +10 -0
  140. package/dist/http/cursor.d.ts.map +1 -0
  141. package/dist/http/cursor.js +20 -0
  142. package/dist/http/cursor.js.map +1 -0
  143. package/dist/http/error-envelope.d.ts +127 -0
  144. package/dist/http/error-envelope.d.ts.map +1 -0
  145. package/dist/http/error-envelope.js +402 -0
  146. package/dist/http/error-envelope.js.map +1 -0
  147. package/dist/http/health.d.ts +88 -0
  148. package/dist/http/health.d.ts.map +1 -0
  149. package/dist/http/health.js +77 -0
  150. package/dist/http/health.js.map +1 -0
  151. package/dist/http/index.d.ts +50 -0
  152. package/dist/http/index.d.ts.map +1 -0
  153. package/dist/http/index.js +50 -0
  154. package/dist/http/index.js.map +1 -0
  155. package/dist/http/interceptors/dispatch.d.ts +14 -0
  156. package/dist/http/interceptors/dispatch.d.ts.map +1 -0
  157. package/dist/http/interceptors/dispatch.js +113 -0
  158. package/dist/http/interceptors/dispatch.js.map +1 -0
  159. package/dist/http/interceptors/index.d.ts +6 -0
  160. package/dist/http/interceptors/index.d.ts.map +1 -0
  161. package/dist/http/interceptors/index.js +5 -0
  162. package/dist/http/interceptors/index.js.map +1 -0
  163. package/dist/http/interceptors/registry.d.ts +44 -0
  164. package/dist/http/interceptors/registry.d.ts.map +1 -0
  165. package/dist/http/interceptors/registry.js +123 -0
  166. package/dist/http/interceptors/registry.js.map +1 -0
  167. package/dist/http/interceptors/route-table.d.ts +33 -0
  168. package/dist/http/interceptors/route-table.d.ts.map +1 -0
  169. package/dist/http/interceptors/route-table.js +39 -0
  170. package/dist/http/interceptors/route-table.js.map +1 -0
  171. package/dist/http/interceptors/types.d.ts +101 -0
  172. package/dist/http/interceptors/types.d.ts.map +1 -0
  173. package/dist/http/interceptors/types.js +2 -0
  174. package/dist/http/interceptors/types.js.map +1 -0
  175. package/dist/http/interceptors/validation.d.ts +22 -0
  176. package/dist/http/interceptors/validation.d.ts.map +1 -0
  177. package/dist/http/interceptors/validation.js +39 -0
  178. package/dist/http/interceptors/validation.js.map +1 -0
  179. package/dist/http/logger.d.ts +9 -0
  180. package/dist/http/logger.d.ts.map +1 -0
  181. package/dist/http/logger.js +25 -0
  182. package/dist/http/logger.js.map +1 -0
  183. package/dist/http/openapi.d.ts +21 -0
  184. package/dist/http/openapi.d.ts.map +1 -0
  185. package/dist/http/openapi.js +114 -0
  186. package/dist/http/openapi.js.map +1 -0
  187. package/dist/http/product-audience.d.ts +78 -0
  188. package/dist/http/product-audience.d.ts.map +1 -0
  189. package/dist/http/product-audience.js +92 -0
  190. package/dist/http/product-audience.js.map +1 -0
  191. package/dist/http/request-actor.d.ts +82 -0
  192. package/dist/http/request-actor.d.ts.map +1 -0
  193. package/dist/http/request-actor.js +2 -0
  194. package/dist/http/request-actor.js.map +1 -0
  195. package/dist/http/server.d.ts +60 -0
  196. package/dist/http/server.d.ts.map +1 -0
  197. package/dist/http/server.js +117 -0
  198. package/dist/http/server.js.map +1 -0
  199. package/dist/http/storefront-revalidator.d.ts +29 -0
  200. package/dist/http/storefront-revalidator.d.ts.map +1 -0
  201. package/dist/http/storefront-revalidator.js +34 -0
  202. package/dist/http/storefront-revalidator.js.map +1 -0
  203. package/dist/http/test-actor-carrier.d.ts +28 -0
  204. package/dist/http/test-actor-carrier.d.ts.map +1 -0
  205. package/dist/http/test-actor-carrier.js +10 -0
  206. package/dist/http/test-actor-carrier.js.map +1 -0
  207. package/dist/http/trusted-proxy.d.ts +48 -0
  208. package/dist/http/trusted-proxy.d.ts.map +1 -0
  209. package/dist/http/trusted-proxy.js +136 -0
  210. package/dist/http/trusted-proxy.js.map +1 -0
  211. package/dist/kernel/audit/audit-log-entry.entity.d.ts +33 -0
  212. package/dist/kernel/audit/audit-log-entry.entity.d.ts.map +1 -0
  213. package/dist/kernel/audit/audit-log-entry.entity.js +102 -0
  214. package/dist/kernel/audit/audit-log-entry.entity.js.map +1 -0
  215. package/dist/kernel/audit/audit-log-service.d.ts +63 -0
  216. package/dist/kernel/audit/audit-log-service.d.ts.map +1 -0
  217. package/dist/kernel/audit/audit-log-service.js +107 -0
  218. package/dist/kernel/audit/audit-log-service.js.map +1 -0
  219. package/dist/kernel/cache/in-process-cache-registry.d.ts +93 -0
  220. package/dist/kernel/cache/in-process-cache-registry.d.ts.map +1 -0
  221. package/dist/kernel/cache/in-process-cache-registry.js +78 -0
  222. package/dist/kernel/cache/in-process-cache-registry.js.map +1 -0
  223. package/dist/kernel/cache/shared-drop-marks.d.ts +39 -0
  224. package/dist/kernel/cache/shared-drop-marks.d.ts.map +1 -0
  225. package/dist/kernel/cache/shared-drop-marks.js +68 -0
  226. package/dist/kernel/cache/shared-drop-marks.js.map +1 -0
  227. package/dist/kernel/compose.d.ts +234 -0
  228. package/dist/kernel/compose.d.ts.map +1 -0
  229. package/dist/kernel/compose.js +279 -0
  230. package/dist/kernel/compose.js.map +1 -0
  231. package/dist/kernel/container.d.ts +95 -0
  232. package/dist/kernel/container.d.ts.map +1 -0
  233. package/dist/kernel/container.js +90 -0
  234. package/dist/kernel/container.js.map +1 -0
  235. package/dist/kernel/contribution-sinks.d.ts +106 -0
  236. package/dist/kernel/contribution-sinks.d.ts.map +1 -0
  237. package/dist/kernel/contribution-sinks.js +153 -0
  238. package/dist/kernel/contribution-sinks.js.map +1 -0
  239. package/dist/kernel/crypto/password-hasher.d.ts +3 -0
  240. package/dist/kernel/crypto/password-hasher.d.ts.map +1 -0
  241. package/dist/kernel/crypto/password-hasher.js +44 -0
  242. package/dist/kernel/crypto/password-hasher.js.map +1 -0
  243. package/dist/kernel/i18n/error-envelope-options.d.ts +56 -0
  244. package/dist/kernel/i18n/error-envelope-options.d.ts.map +1 -0
  245. package/dist/kernel/i18n/error-envelope-options.js +46 -0
  246. package/dist/kernel/i18n/error-envelope-options.js.map +1 -0
  247. package/dist/kernel/i18n/error-translation.d.ts +144 -0
  248. package/dist/kernel/i18n/error-translation.d.ts.map +1 -0
  249. package/dist/kernel/i18n/error-translation.js +84 -0
  250. package/dist/kernel/i18n/error-translation.js.map +1 -0
  251. package/dist/kernel/i18n/request-language.d.ts +80 -0
  252. package/dist/kernel/i18n/request-language.d.ts.map +1 -0
  253. package/dist/kernel/i18n/request-language.js +168 -0
  254. package/dist/kernel/i18n/request-language.js.map +1 -0
  255. package/dist/kernel/index.d.ts +142 -0
  256. package/dist/kernel/index.d.ts.map +1 -0
  257. package/dist/kernel/index.js +160 -0
  258. package/dist/kernel/index.js.map +1 -0
  259. package/dist/kernel/lazy-port.d.ts +59 -0
  260. package/dist/kernel/lazy-port.d.ts.map +1 -0
  261. package/dist/kernel/lazy-port.js +78 -0
  262. package/dist/kernel/lazy-port.js.map +1 -0
  263. package/dist/kernel/lifecycle/activation-resolver.d.ts +63 -0
  264. package/dist/kernel/lifecycle/activation-resolver.d.ts.map +1 -0
  265. package/dist/kernel/lifecycle/activation-resolver.js +70 -0
  266. package/dist/kernel/lifecycle/activation-resolver.js.map +1 -0
  267. package/dist/kernel/lifecycle/capability-registry.d.ts +145 -0
  268. package/dist/kernel/lifecycle/capability-registry.d.ts.map +1 -0
  269. package/dist/kernel/lifecycle/capability-registry.js +170 -0
  270. package/dist/kernel/lifecycle/capability-registry.js.map +1 -0
  271. package/dist/kernel/lifecycle/effective-state.d.ts +126 -0
  272. package/dist/kernel/lifecycle/effective-state.d.ts.map +1 -0
  273. package/dist/kernel/lifecycle/effective-state.js +111 -0
  274. package/dist/kernel/lifecycle/effective-state.js.map +1 -0
  275. package/dist/kernel/lifecycle/module-registration.entity.d.ts +57 -0
  276. package/dist/kernel/lifecycle/module-registration.entity.d.ts.map +1 -0
  277. package/dist/kernel/lifecycle/module-registration.entity.js +111 -0
  278. package/dist/kernel/lifecycle/module-registration.entity.js.map +1 -0
  279. package/dist/kernel/lifecycle/plugin-helpers.d.ts +165 -0
  280. package/dist/kernel/lifecycle/plugin-helpers.d.ts.map +1 -0
  281. package/dist/kernel/lifecycle/plugin-helpers.js +395 -0
  282. package/dist/kernel/lifecycle/plugin-helpers.js.map +1 -0
  283. package/dist/kernel/lifecycle/registry-cache.d.ts +318 -0
  284. package/dist/kernel/lifecycle/registry-cache.d.ts.map +1 -0
  285. package/dist/kernel/lifecycle/registry-cache.js +509 -0
  286. package/dist/kernel/lifecycle/registry-cache.js.map +1 -0
  287. package/dist/kernel/lifecycle/required-modules.d.ts +137 -0
  288. package/dist/kernel/lifecycle/required-modules.d.ts.map +1 -0
  289. package/dist/kernel/lifecycle/required-modules.js +80 -0
  290. package/dist/kernel/lifecycle/required-modules.js.map +1 -0
  291. package/dist/kernel/lifecycle/unique-module-ids.d.ts +58 -0
  292. package/dist/kernel/lifecycle/unique-module-ids.d.ts.map +1 -0
  293. package/dist/kernel/lifecycle/unique-module-ids.js +82 -0
  294. package/dist/kernel/lifecycle/unique-module-ids.js.map +1 -0
  295. package/dist/kernel/logging.d.ts +116 -0
  296. package/dist/kernel/logging.d.ts.map +1 -0
  297. package/dist/kernel/logging.js +71 -0
  298. package/dist/kernel/logging.js.map +1 -0
  299. package/dist/kernel/module-context.d.ts +563 -0
  300. package/dist/kernel/module-context.d.ts.map +1 -0
  301. package/dist/kernel/module-context.js +670 -0
  302. package/dist/kernel/module-context.js.map +1 -0
  303. package/dist/kernel/ports/audit.d.ts +115 -0
  304. package/dist/kernel/ports/audit.d.ts.map +1 -0
  305. package/dist/kernel/ports/audit.js +2 -0
  306. package/dist/kernel/ports/audit.js.map +1 -0
  307. package/dist/kernel/ports/organizations.d.ts +56 -0
  308. package/dist/kernel/ports/organizations.d.ts.map +1 -0
  309. package/dist/kernel/ports/organizations.js +2 -0
  310. package/dist/kernel/ports/organizations.js.map +1 -0
  311. package/dist/kernel/ports/provide.d.ts +14 -0
  312. package/dist/kernel/ports/provide.d.ts.map +1 -0
  313. package/dist/kernel/ports/provide.js +50 -0
  314. package/dist/kernel/ports/provide.js.map +1 -0
  315. package/dist/kernel/ports/require-admin.d.ts +61 -0
  316. package/dist/kernel/ports/require-admin.d.ts.map +1 -0
  317. package/dist/kernel/ports/require-admin.js +2 -0
  318. package/dist/kernel/ports/require-admin.js.map +1 -0
  319. package/dist/kernel/ports/require-customer.d.ts +17 -0
  320. package/dist/kernel/ports/require-customer.d.ts.map +1 -0
  321. package/dist/kernel/ports/require-customer.js +2 -0
  322. package/dist/kernel/ports/require-customer.js.map +1 -0
  323. package/dist/kernel/ports/sales-channel.d.ts +84 -0
  324. package/dist/kernel/ports/sales-channel.d.ts.map +1 -0
  325. package/dist/kernel/ports/sales-channel.js +2 -0
  326. package/dist/kernel/ports/sales-channel.js.map +1 -0
  327. package/dist/kernel/ports/settings.d.ts +59 -0
  328. package/dist/kernel/ports/settings.d.ts.map +1 -0
  329. package/dist/kernel/ports/settings.js +2 -0
  330. package/dist/kernel/ports/settings.js.map +1 -0
  331. package/dist/kernel/public-api-base-url.d.ts +98 -0
  332. package/dist/kernel/public-api-base-url.d.ts.map +1 -0
  333. package/dist/kernel/public-api-base-url.js +144 -0
  334. package/dist/kernel/public-api-base-url.js.map +1 -0
  335. package/dist/kernel/request-scope-hook.d.ts +63 -0
  336. package/dist/kernel/request-scope-hook.d.ts.map +1 -0
  337. package/dist/kernel/request-scope-hook.js +67 -0
  338. package/dist/kernel/request-scope-hook.js.map +1 -0
  339. package/dist/kernel/sales-channels/channel-bridge-registry.d.ts +109 -0
  340. package/dist/kernel/sales-channels/channel-bridge-registry.d.ts.map +1 -0
  341. package/dist/kernel/sales-channels/channel-bridge-registry.js +75 -0
  342. package/dist/kernel/sales-channels/channel-bridge-registry.js.map +1 -0
  343. package/dist/kernel/sales-channels/compose.d.ts +69 -0
  344. package/dist/kernel/sales-channels/compose.d.ts.map +1 -0
  345. package/dist/kernel/sales-channels/compose.js +43 -0
  346. package/dist/kernel/sales-channels/compose.js.map +1 -0
  347. package/dist/kernel/sales-channels/default-channel-reconciler.d.ts +66 -0
  348. package/dist/kernel/sales-channels/default-channel-reconciler.d.ts.map +1 -0
  349. package/dist/kernel/sales-channels/default-channel-reconciler.js +91 -0
  350. package/dist/kernel/sales-channels/default-channel-reconciler.js.map +1 -0
  351. package/dist/kernel/sales-channels/no-system-default-channel.error.d.ts +28 -0
  352. package/dist/kernel/sales-channels/no-system-default-channel.error.d.ts.map +1 -0
  353. package/dist/kernel/sales-channels/no-system-default-channel.error.js +33 -0
  354. package/dist/kernel/sales-channels/no-system-default-channel.error.js.map +1 -0
  355. package/dist/kernel/sales-channels/request-channel-assortment.d.ts +72 -0
  356. package/dist/kernel/sales-channels/request-channel-assortment.d.ts.map +1 -0
  357. package/dist/kernel/sales-channels/request-channel-assortment.js +83 -0
  358. package/dist/kernel/sales-channels/request-channel-assortment.js.map +1 -0
  359. package/dist/kernel/sales-channels/sales-channel-membership.service.d.ts +157 -0
  360. package/dist/kernel/sales-channels/sales-channel-membership.service.d.ts.map +1 -0
  361. package/dist/kernel/sales-channels/sales-channel-membership.service.js +302 -0
  362. package/dist/kernel/sales-channels/sales-channel-membership.service.js.map +1 -0
  363. package/dist/kernel/sales-channels/sales-channel-resolver.middleware.d.ts +76 -0
  364. package/dist/kernel/sales-channels/sales-channel-resolver.middleware.d.ts.map +1 -0
  365. package/dist/kernel/sales-channels/sales-channel-resolver.middleware.js +184 -0
  366. package/dist/kernel/sales-channels/sales-channel-resolver.middleware.js.map +1 -0
  367. package/dist/kernel/sales-channels/sales-channel-resolver.service.d.ts +82 -0
  368. package/dist/kernel/sales-channels/sales-channel-resolver.service.d.ts.map +1 -0
  369. package/dist/kernel/sales-channels/sales-channel-resolver.service.js +126 -0
  370. package/dist/kernel/sales-channels/sales-channel-resolver.service.js.map +1 -0
  371. package/dist/kernel/sales-channels/sales-channel.entity.d.ts +50 -0
  372. package/dist/kernel/sales-channels/sales-channel.entity.d.ts.map +1 -0
  373. package/dist/kernel/sales-channels/sales-channel.entity.js +132 -0
  374. package/dist/kernel/sales-channels/sales-channel.entity.js.map +1 -0
  375. package/dist/kernel/sales-channels/sales-channels-cache.d.ts +170 -0
  376. package/dist/kernel/sales-channels/sales-channels-cache.d.ts.map +1 -0
  377. package/dist/kernel/sales-channels/sales-channels-cache.js +243 -0
  378. package/dist/kernel/sales-channels/sales-channels-cache.js.map +1 -0
  379. package/dist/kernel/scope.d.ts +153 -0
  380. package/dist/kernel/scope.d.ts.map +1 -0
  381. package/dist/kernel/scope.js +172 -0
  382. package/dist/kernel/scope.js.map +1 -0
  383. package/dist/kernel/settings/compose.d.ts +49 -0
  384. package/dist/kernel/settings/compose.d.ts.map +1 -0
  385. package/dist/kernel/settings/compose.js +21 -0
  386. package/dist/kernel/settings/compose.js.map +1 -0
  387. package/dist/kernel/settings/manifest-reconciler.d.ts +78 -0
  388. package/dist/kernel/settings/manifest-reconciler.d.ts.map +1 -0
  389. package/dist/kernel/settings/manifest-reconciler.js +343 -0
  390. package/dist/kernel/settings/manifest-reconciler.js.map +1 -0
  391. package/dist/kernel/settings/secret-value-codec.d.ts +52 -0
  392. package/dist/kernel/settings/secret-value-codec.d.ts.map +1 -0
  393. package/dist/kernel/settings/secret-value-codec.js +102 -0
  394. package/dist/kernel/settings/secret-value-codec.js.map +1 -0
  395. package/dist/kernel/settings/setting-group.entity.d.ts +25 -0
  396. package/dist/kernel/settings/setting-group.entity.d.ts.map +1 -0
  397. package/dist/kernel/settings/setting-group.entity.js +79 -0
  398. package/dist/kernel/settings/setting-group.entity.js.map +1 -0
  399. package/dist/kernel/settings/setting-value.entity.d.ts +23 -0
  400. package/dist/kernel/settings/setting-value.entity.d.ts.map +1 -0
  401. package/dist/kernel/settings/setting-value.entity.js +66 -0
  402. package/dist/kernel/settings/setting-value.entity.js.map +1 -0
  403. package/dist/kernel/settings/setting.entity.d.ts +56 -0
  404. package/dist/kernel/settings/setting.entity.d.ts.map +1 -0
  405. package/dist/kernel/settings/setting.entity.js +147 -0
  406. package/dist/kernel/settings/setting.entity.js.map +1 -0
  407. package/dist/kernel/settings/settings-cache.d.ts +158 -0
  408. package/dist/kernel/settings/settings-cache.d.ts.map +1 -0
  409. package/dist/kernel/settings/settings-cache.js +253 -0
  410. package/dist/kernel/settings/settings-cache.js.map +1 -0
  411. package/dist/kernel/settings/settings.service.d.ts +142 -0
  412. package/dist/kernel/settings/settings.service.d.ts.map +1 -0
  413. package/dist/kernel/settings/settings.service.js +294 -0
  414. package/dist/kernel/settings/settings.service.js.map +1 -0
  415. package/dist/lifecycle/backend.d.ts +51 -0
  416. package/dist/lifecycle/backend.d.ts.map +1 -0
  417. package/dist/lifecycle/backend.js +40 -0
  418. package/dist/lifecycle/backend.js.map +1 -0
  419. package/dist/lifecycle/commands/activation.commands.d.ts +97 -0
  420. package/dist/lifecycle/commands/activation.commands.d.ts.map +1 -0
  421. package/dist/lifecycle/commands/activation.commands.js +142 -0
  422. package/dist/lifecycle/commands/activation.commands.js.map +1 -0
  423. package/dist/lifecycle/commands/disable.d.ts +3 -0
  424. package/dist/lifecycle/commands/disable.d.ts.map +1 -0
  425. package/dist/lifecycle/commands/disable.js +126 -0
  426. package/dist/lifecycle/commands/disable.js.map +1 -0
  427. package/dist/lifecycle/commands/enable.d.ts +3 -0
  428. package/dist/lifecycle/commands/enable.d.ts.map +1 -0
  429. package/dist/lifecycle/commands/enable.js +102 -0
  430. package/dist/lifecycle/commands/enable.js.map +1 -0
  431. package/dist/lifecycle/commands/install.d.ts +3 -0
  432. package/dist/lifecycle/commands/install.d.ts.map +1 -0
  433. package/dist/lifecycle/commands/install.js +263 -0
  434. package/dist/lifecycle/commands/install.js.map +1 -0
  435. package/dist/lifecycle/commands/operator-entry.d.ts +104 -0
  436. package/dist/lifecycle/commands/operator-entry.d.ts.map +1 -0
  437. package/dist/lifecycle/commands/operator-entry.js +127 -0
  438. package/dist/lifecycle/commands/operator-entry.js.map +1 -0
  439. package/dist/lifecycle/commands/operator-runtime.d.ts +147 -0
  440. package/dist/lifecycle/commands/operator-runtime.d.ts.map +1 -0
  441. package/dist/lifecycle/commands/operator-runtime.js +40 -0
  442. package/dist/lifecycle/commands/operator-runtime.js.map +1 -0
  443. package/dist/lifecycle/commands/status.d.ts +3 -0
  444. package/dist/lifecycle/commands/status.d.ts.map +1 -0
  445. package/dist/lifecycle/commands/status.js +108 -0
  446. package/dist/lifecycle/commands/status.js.map +1 -0
  447. package/dist/lifecycle/commands/uninstall.d.ts +3 -0
  448. package/dist/lifecycle/commands/uninstall.d.ts.map +1 -0
  449. package/dist/lifecycle/commands/uninstall.js +223 -0
  450. package/dist/lifecycle/commands/uninstall.js.map +1 -0
  451. package/dist/lifecycle/divergence-declaration.d.ts +74 -0
  452. package/dist/lifecycle/divergence-declaration.d.ts.map +1 -0
  453. package/dist/lifecycle/divergence-declaration.js +92 -0
  454. package/dist/lifecycle/divergence-declaration.js.map +1 -0
  455. package/dist/lifecycle/i18n/en.json +4 -0
  456. package/dist/lifecycle/i18n/pl.json +4 -0
  457. package/dist/lifecycle/index.d.ts +110 -0
  458. package/dist/lifecycle/index.d.ts.map +1 -0
  459. package/dist/lifecycle/index.js +189 -0
  460. package/dist/lifecycle/index.js.map +1 -0
  461. package/dist/lifecycle/manifest-registry.d.ts +244 -0
  462. package/dist/lifecycle/manifest-registry.d.ts.map +1 -0
  463. package/dist/lifecycle/manifest-registry.js +223 -0
  464. package/dist/lifecycle/manifest-registry.js.map +1 -0
  465. package/dist/lifecycle/manifest.d.ts +166 -0
  466. package/dist/lifecycle/manifest.d.ts.map +1 -0
  467. package/dist/lifecycle/manifest.js +121 -0
  468. package/dist/lifecycle/manifest.js.map +1 -0
  469. package/dist/lifecycle/plugin.d.ts +56 -0
  470. package/dist/lifecycle/plugin.d.ts.map +1 -0
  471. package/dist/lifecycle/plugin.js +59 -0
  472. package/dist/lifecycle/plugin.js.map +1 -0
  473. package/dist/lifecycle/resident.d.ts +16 -0
  474. package/dist/lifecycle/resident.d.ts.map +1 -0
  475. package/dist/lifecycle/resident.js +59 -0
  476. package/dist/lifecycle/resident.js.map +1 -0
  477. package/dist/lifecycle/routes.admin.d.ts +57 -0
  478. package/dist/lifecycle/routes.admin.d.ts.map +1 -0
  479. package/dist/lifecycle/routes.admin.js +162 -0
  480. package/dist/lifecycle/routes.admin.js.map +1 -0
  481. package/dist/lifecycle/routes.storefront.d.ts +26 -0
  482. package/dist/lifecycle/routes.storefront.d.ts.map +1 -0
  483. package/dist/lifecycle/routes.storefront.js +36 -0
  484. package/dist/lifecycle/routes.storefront.js.map +1 -0
  485. package/dist/lifecycle/services/deactivation-ledger.d.ts +216 -0
  486. package/dist/lifecycle/services/deactivation-ledger.d.ts.map +1 -0
  487. package/dist/lifecycle/services/deactivation-ledger.js +171 -0
  488. package/dist/lifecycle/services/deactivation-ledger.js.map +1 -0
  489. package/dist/lifecycle/services/dep-graph.d.ts +119 -0
  490. package/dist/lifecycle/services/dep-graph.d.ts.map +1 -0
  491. package/dist/lifecycle/services/dep-graph.js +334 -0
  492. package/dist/lifecycle/services/dep-graph.js.map +1 -0
  493. package/dist/lifecycle/services/gating-graph.d.ts +164 -0
  494. package/dist/lifecycle/services/gating-graph.d.ts.map +1 -0
  495. package/dist/lifecycle/services/gating-graph.js +203 -0
  496. package/dist/lifecycle/services/gating-graph.js.map +1 -0
  497. package/dist/lifecycle/services/lock.d.ts +27 -0
  498. package/dist/lifecycle/services/lock.d.ts.map +1 -0
  499. package/dist/lifecycle/services/lock.js +82 -0
  500. package/dist/lifecycle/services/lock.js.map +1 -0
  501. package/dist/lifecycle/services/manifest-loader.d.ts +125 -0
  502. package/dist/lifecycle/services/manifest-loader.d.ts.map +1 -0
  503. package/dist/lifecycle/services/manifest-loader.js +210 -0
  504. package/dist/lifecycle/services/manifest-loader.js.map +1 -0
  505. package/dist/lifecycle/services/migration-ownership.d.ts +36 -0
  506. package/dist/lifecycle/services/migration-ownership.d.ts.map +1 -0
  507. package/dist/lifecycle/services/migration-ownership.js +15 -0
  508. package/dist/lifecycle/services/migration-ownership.js.map +1 -0
  509. package/dist/lifecycle/services/module-id-claims.d.ts +38 -0
  510. package/dist/lifecycle/services/module-id-claims.d.ts.map +1 -0
  511. package/dist/lifecycle/services/module-id-claims.js +123 -0
  512. package/dist/lifecycle/services/module-id-claims.js.map +1 -0
  513. package/dist/lifecycle/services/module-origin.d.ts +55 -0
  514. package/dist/lifecycle/services/module-origin.d.ts.map +1 -0
  515. package/dist/lifecycle/services/module-origin.js +47 -0
  516. package/dist/lifecycle/services/module-origin.js.map +1 -0
  517. package/dist/lifecycle/services/orchestrator.d.ts +235 -0
  518. package/dist/lifecycle/services/orchestrator.d.ts.map +1 -0
  519. package/dist/lifecycle/services/orchestrator.js +954 -0
  520. package/dist/lifecycle/services/orchestrator.js.map +1 -0
  521. package/dist/lifecycle/services/presence-load.d.ts +281 -0
  522. package/dist/lifecycle/services/presence-load.d.ts.map +1 -0
  523. package/dist/lifecycle/services/presence-load.js +437 -0
  524. package/dist/lifecycle/services/presence-load.js.map +1 -0
  525. package/dist/lifecycle/services/static-registry.d.ts +47 -0
  526. package/dist/lifecycle/services/static-registry.d.ts.map +1 -0
  527. package/dist/lifecycle/services/static-registry.js +41 -0
  528. package/dist/lifecycle/services/static-registry.js.map +1 -0
  529. package/dist/migrations/20260424T165847_core_foundation_init.d.ts +25 -0
  530. package/dist/migrations/20260424T165847_core_foundation_init.d.ts.map +1 -0
  531. package/dist/migrations/20260424T165847_core_foundation_init.js +238 -0
  532. package/dist/migrations/20260424T165847_core_foundation_init.js.map +1 -0
  533. package/dist/migrations/20260425T050720_core_commerce_init.d.ts +19 -0
  534. package/dist/migrations/20260425T050720_core_commerce_init.d.ts.map +1 -0
  535. package/dist/migrations/20260425T050720_core_commerce_init.js +200 -0
  536. package/dist/migrations/20260425T050720_core_commerce_init.js.map +1 -0
  537. package/dist/migrations/20260430T101450_core_settings_init.d.ts +25 -0
  538. package/dist/migrations/20260430T101450_core_settings_init.d.ts.map +1 -0
  539. package/dist/migrations/20260430T101450_core_settings_init.js +113 -0
  540. package/dist/migrations/20260430T101450_core_settings_init.js.map +1 -0
  541. package/dist/migrations/20260430T170044_core_sales_channels_promote.d.ts +67 -0
  542. package/dist/migrations/20260430T170044_core_sales_channels_promote.d.ts.map +1 -0
  543. package/dist/migrations/20260430T170044_core_sales_channels_promote.js +101 -0
  544. package/dist/migrations/20260430T170044_core_sales_channels_promote.js.map +1 -0
  545. package/dist/migrations/20260506T200657_core_module_lifecycle_init.d.ts +21 -0
  546. package/dist/migrations/20260506T200657_core_module_lifecycle_init.d.ts.map +1 -0
  547. package/dist/migrations/20260506T200657_core_module_lifecycle_init.js +41 -0
  548. package/dist/migrations/20260506T200657_core_module_lifecycle_init.js.map +1 -0
  549. package/dist/migrations/20260514T111329_core_settings_global_value.d.ts +30 -0
  550. package/dist/migrations/20260514T111329_core_settings_global_value.d.ts.map +1 -0
  551. package/dist/migrations/20260514T111329_core_settings_global_value.js +34 -0
  552. package/dist/migrations/20260514T111329_core_settings_global_value.js.map +1 -0
  553. package/dist/migrations/20260611T140411_core_settings_secret_value_type.d.ts +26 -0
  554. package/dist/migrations/20260611T140411_core_settings_secret_value_type.d.ts.map +1 -0
  555. package/dist/migrations/20260611T140411_core_settings_secret_value_type.js +63 -0
  556. package/dist/migrations/20260611T140411_core_settings_secret_value_type.js.map +1 -0
  557. package/dist/migrations/20260611T140419_core_settings_enum_options.d.ts +19 -0
  558. package/dist/migrations/20260611T140419_core_settings_enum_options.d.ts.map +1 -0
  559. package/dist/migrations/20260611T140419_core_settings_enum_options.js +23 -0
  560. package/dist/migrations/20260611T140419_core_settings_enum_options.js.map +1 -0
  561. package/dist/migrations/20260629T090100_core_settings_hidden_flag.d.ts +20 -0
  562. package/dist/migrations/20260629T090100_core_settings_hidden_flag.d.ts.map +1 -0
  563. package/dist/migrations/20260629T090100_core_settings_hidden_flag.js +24 -0
  564. package/dist/migrations/20260629T090100_core_settings_hidden_flag.js.map +1 -0
  565. package/dist/migrations/20260717T134752_core_tenant_scope_indexes.d.ts +27 -0
  566. package/dist/migrations/20260717T134752_core_tenant_scope_indexes.d.ts.map +1 -0
  567. package/dist/migrations/20260717T134752_core_tenant_scope_indexes.js +32 -0
  568. package/dist/migrations/20260717T134752_core_tenant_scope_indexes.js.map +1 -0
  569. package/dist/migrations/20260721T011510_core_settings_credential_ref_value_type.d.ts +24 -0
  570. package/dist/migrations/20260721T011510_core_settings_credential_ref_value_type.d.ts.map +1 -0
  571. package/dist/migrations/20260721T011510_core_settings_credential_ref_value_type.js +57 -0
  572. package/dist/migrations/20260721T011510_core_settings_credential_ref_value_type.js.map +1 -0
  573. package/dist/migrations/20260816T203339_core_retire_core_activation_settings.d.ts +39 -0
  574. package/dist/migrations/20260816T203339_core_retire_core_activation_settings.d.ts.map +1 -0
  575. package/dist/migrations/20260816T203339_core_retire_core_activation_settings.js +59 -0
  576. package/dist/migrations/20260816T203339_core_retire_core_activation_settings.js.map +1 -0
  577. package/dist/migrations/20260919T101500_core_module_registrations_boot_converged.d.ts +34 -0
  578. package/dist/migrations/20260919T101500_core_module_registrations_boot_converged.d.ts.map +1 -0
  579. package/dist/migrations/20260919T101500_core_module_registrations_boot_converged.js +38 -0
  580. package/dist/migrations/20260919T101500_core_module_registrations_boot_converged.js.map +1 -0
  581. package/dist/migrations/baseline-migrations.generated.d.ts +2 -0
  582. package/dist/migrations/baseline-migrations.generated.d.ts.map +1 -0
  583. package/dist/migrations/baseline-migrations.generated.js +136 -0
  584. package/dist/migrations/baseline-migrations.generated.js.map +1 -0
  585. package/dist/migrations/index.d.ts +62 -0
  586. package/dist/migrations/index.d.ts.map +1 -0
  587. package/dist/migrations/index.js +75 -0
  588. package/dist/migrations/index.js.map +1 -0
  589. package/dist/overlay/deployment-roots.d.ts +37 -0
  590. package/dist/overlay/deployment-roots.d.ts.map +1 -0
  591. package/dist/overlay/deployment-roots.js +90 -0
  592. package/dist/overlay/deployment-roots.js.map +1 -0
  593. package/dist/overlay/index.d.ts +62 -0
  594. package/dist/overlay/index.d.ts.map +1 -0
  595. package/dist/overlay/index.js +62 -0
  596. package/dist/overlay/index.js.map +1 -0
  597. package/dist/overlay/overlay-runtime.d.ts +173 -0
  598. package/dist/overlay/overlay-runtime.d.ts.map +1 -0
  599. package/dist/overlay/overlay-runtime.js +281 -0
  600. package/dist/overlay/overlay-runtime.js.map +1 -0
  601. package/dist/overlay/resolve-overlay.d.ts +41 -0
  602. package/dist/overlay/resolve-overlay.d.ts.map +1 -0
  603. package/dist/overlay/resolve-overlay.js +72 -0
  604. package/dist/overlay/resolve-overlay.js.map +1 -0
  605. package/dist/packages/index.d.ts +57 -0
  606. package/dist/packages/index.d.ts.map +1 -0
  607. package/dist/packages/index.js +57 -0
  608. package/dist/packages/index.js.map +1 -0
  609. package/dist/packages/installed-packages.d.ts +79 -0
  610. package/dist/packages/installed-packages.d.ts.map +1 -0
  611. package/dist/packages/installed-packages.js +312 -0
  612. package/dist/packages/installed-packages.js.map +1 -0
  613. package/dist/packages/package-entity-lookup.d.ts +120 -0
  614. package/dist/packages/package-entity-lookup.d.ts.map +1 -0
  615. package/dist/packages/package-entity-lookup.js +17 -0
  616. package/dist/packages/package-entity-lookup.js.map +1 -0
  617. package/dist/packages/package-runtime.d.ts +177 -0
  618. package/dist/packages/package-runtime.d.ts.map +1 -0
  619. package/dist/packages/package-runtime.js +386 -0
  620. package/dist/packages/package-runtime.js.map +1 -0
  621. package/dist/tenancy/derived-scope.d.ts +43 -0
  622. package/dist/tenancy/derived-scope.d.ts.map +1 -0
  623. package/dist/tenancy/derived-scope.js +76 -0
  624. package/dist/tenancy/derived-scope.js.map +1 -0
  625. package/dist/tenancy/escape-hatch.d.ts +30 -0
  626. package/dist/tenancy/escape-hatch.d.ts.map +1 -0
  627. package/dist/tenancy/escape-hatch.js +50 -0
  628. package/dist/tenancy/escape-hatch.js.map +1 -0
  629. package/dist/tenancy/filters.d.ts +87 -0
  630. package/dist/tenancy/filters.d.ts.map +1 -0
  631. package/dist/tenancy/filters.js +126 -0
  632. package/dist/tenancy/filters.js.map +1 -0
  633. package/dist/tenancy/index.d.ts +63 -0
  634. package/dist/tenancy/index.d.ts.map +1 -0
  635. package/dist/tenancy/index.js +61 -0
  636. package/dist/tenancy/index.js.map +1 -0
  637. package/dist/tenancy/org-scoped.decorator.d.ts +150 -0
  638. package/dist/tenancy/org-scoped.decorator.d.ts.map +1 -0
  639. package/dist/tenancy/org-scoped.decorator.js +339 -0
  640. package/dist/tenancy/org-scoped.decorator.js.map +1 -0
  641. package/dist/tenancy/org-write-guard.d.ts +106 -0
  642. package/dist/tenancy/org-write-guard.d.ts.map +1 -0
  643. package/dist/tenancy/org-write-guard.js +141 -0
  644. package/dist/tenancy/org-write-guard.js.map +1 -0
  645. package/dist/tenancy/resolve-tenant-context.d.ts +91 -0
  646. package/dist/tenancy/resolve-tenant-context.d.ts.map +1 -0
  647. package/dist/tenancy/resolve-tenant-context.js +85 -0
  648. package/dist/tenancy/resolve-tenant-context.js.map +1 -0
  649. package/dist/tenancy/scoped-em.d.ts +10 -0
  650. package/dist/tenancy/scoped-em.d.ts.map +1 -0
  651. package/dist/tenancy/scoped-em.js +11 -0
  652. package/dist/tenancy/scoped-em.js.map +1 -0
  653. package/dist/tenancy/tenant-context.d.ts +154 -0
  654. package/dist/tenancy/tenant-context.d.ts.map +1 -0
  655. package/dist/tenancy/tenant-context.js +109 -0
  656. package/dist/tenancy/tenant-context.js.map +1 -0
  657. package/package.json +123 -0
@@ -0,0 +1,939 @@
1
+ /**
2
+ * `composeApp` — the production half of what `composeTestServer` already is
3
+ * (`specs/110-instance-repository/` T118; `contracts/instance-repository.md`
4
+ * R1.4 and R2.4).
5
+ *
6
+ * ## What "the platform's" means here, precisely
7
+ *
8
+ * Everything in a deployment's composition that is true of **any** Endora
9
+ * platform and mentions no module: refuse a boot with no public origin, open the
10
+ * ORM, build the container, register the ORM-derived names and the host values,
11
+ * construct the audit writer, the event bus, the command bus and the two Redis
12
+ * clients, load presence from the database, compose the settings and
13
+ * sales-channel kernels, run `composeModules` once, open the contribution window
14
+ * once, install the request-scope hook, reconcile the settings manifests, run
15
+ * the boot phase once, assemble the error envelope, and give back a handle that
16
+ * can take all of it down again.
17
+ *
18
+ * Everything else — which modules, which ORM configuration, which manifests,
19
+ * which contributions, which actor a request carries — is the caller's, and
20
+ * reaches this function either as {@link AppComposition} or as one of the hooks
21
+ * below.
22
+ *
23
+ * ## The contribution wiring is the point, and it is a callback
24
+ *
25
+ * R1.4 puts *the contribution wiring* in this package; it does **not** put the
26
+ * 61 values `backend/src/composition.ts` contributes here. 41 of them carry a
27
+ * module's type or a value built out of a module's services, which D-52/D-53
28
+ * refuses from inside this package — so what moves is the *slot*, and the values
29
+ * arrive through {@link ComposeAppOptions.contribute}. Twenty do move, and every
30
+ * one of them is a kernel sub-kernel's object, a host value or an environment
31
+ * read; they are contributed **before** the caller's callback, so a deployment
32
+ * can still overwrite one.
33
+ *
34
+ * That is what makes R2.4 true the day this lands rather than after a sweep: an
35
+ * instance supplies no callback, so no file in a client's tree contributes over
36
+ * a name a module defaults, while this repository's `composition.ts` keeps its
37
+ * own as the **reference deployment's** — which is what it is, and not an
38
+ * instance.
39
+ *
40
+ * ## The one ordering rule, and why it is a shape rather than a comment
41
+ *
42
+ * `composeModules` runs once and `runBootHooks` runs once, immediately before
43
+ * this function returns, so a boot hook may resolve anything. A contribution
44
+ * over a name a module defaults goes in the single slot between them — earlier
45
+ * and the module's own registration overwrites it, later and a boot hook has
46
+ * already read the default (D-45). That slot is
47
+ * {@link ComposeAppOptions.contribute}, and both edges are enforced by the
48
+ * platform rather than remembered: the early one because `ComposedModules` does
49
+ * not exist until every module has registered, the late one because `contribute`
50
+ * throws `ContributionWindowClosedError` once `runBootHooks` has started
51
+ * (issue #52).
52
+ *
53
+ * ## Why no module may name this file
54
+ *
55
+ * It is on `./composition`, the host-internal subpath D-160.14 rules: declared
56
+ * by the `exports` map, carried by no published barrel, and answered for a
57
+ * module's reach with `host-internal-subpath`.
58
+ */
59
+ import { Redis } from 'ioredis';
60
+ import { ERROR_CODES } from '@endora-commerce/contracts';
61
+ import { CommandBus } from '../commands/index.js';
62
+ import { configuredEntitiesFrom } from '../db/configured-entities.js';
63
+ import { discoverConfiguredMigrations } from '../db/configured-migrations.js';
64
+ import { mikroOrmConfigFrom } from '../db/mikro-orm.config.js';
65
+ import { createOrmBootstrap } from '../db/orm.js';
66
+ import { EventBus } from '../events/bus.js';
67
+ import { HttpError } from '../http/error-envelope.js';
68
+ import { healthRoutePlugin } from '../http/health.js';
69
+ import { ApiInterceptorRegistry } from '../http/interceptors/index.js';
70
+ import { StorefrontRevalidator } from '../http/storefront-revalidator.js';
71
+ import { AuditLogService } from '../kernel/audit/audit-log-service.js';
72
+ import { composeModules } from '../kernel/compose.js';
73
+ import { createRootContainer, registerOrm, registerValues, } from '../kernel/container.js';
74
+ import { composeErrorEnvelopeOptions } from '../kernel/i18n/error-envelope-options.js';
75
+ import { buildErrorTranslationTargets, describeErrorCodeCollisions, } from '../kernel/i18n/error-translation.js';
76
+ import { effectiveState } from '../kernel/lifecycle/effective-state.js';
77
+ import { publishStateChanged, registryCache } from '../kernel/lifecycle/registry-cache.js';
78
+ import { requiredModulesFrom } from '../kernel/lifecycle/required-modules.js';
79
+ import { platformLogger } from '../kernel/logging.js';
80
+ import { createRegistrationOwnership } from '../kernel/module-context.js';
81
+ import { assertPublicApiBaseUrlConfigured, resolvePublicApiBaseUrl, } from '../kernel/public-api-base-url.js';
82
+ import { registerRequestScopeHook } from '../kernel/request-scope-hook.js';
83
+ import { composeSalesChannelsKernel, } from '../kernel/sales-channels/compose.js';
84
+ import { DefaultChannelReconciler } from '../kernel/sales-channels/default-channel-reconciler.js';
85
+ import { enterSystemScope } from '../kernel/scope.js';
86
+ import { composeSettingsKernel } from '../kernel/settings/compose.js';
87
+ import { ManifestReconciler } from '../kernel/settings/manifest-reconciler.js';
88
+ import { buildStaticRegistry, deploymentShippedEntries, loadModulePresence, manifest as lifecycleManifest, registerModule as registerLifecycleModule, resolveManifestEntries, } from '../lifecycle/index.js';
89
+ import { activeOverlayModulesRoot } from '../overlay/deployment-roots.js';
90
+ import { overlayModulesUnder } from '../overlay/overlay-runtime.js';
91
+ import { discoverPackageModuleManifests, installedPackageModuleIdClaims, loadPackageModuleEntries, } from '../packages/package-runtime.js';
92
+ import { nodeModulesRootsFor } from '../packages/installed-packages.js';
93
+ import { newsletterTokenSecretFrom } from './newsletter-token-secret.js';
94
+ import { processRunsWorkersFor } from './process-runs-workers.js';
95
+ import { forkScopedEm } from '../tenancy/scoped-em.js';
96
+ import { systemTenantContext } from '../tenancy/resolve-tenant-context.js';
97
+ /**
98
+ * The actor id an audit record carries when its writer could not name an admin
99
+ * (T118b).
100
+ *
101
+ * Three modules' audit contexts owe a non-null `actorAdminUserId` and are
102
+ * reached only behind an admin gate, so this is unreachable by design. It is a
103
+ * sentinel rather than a throw because the alternative is failing the write the
104
+ * record exists to describe, and it was the literal all three spelled inline
105
+ * before the nine moved here.
106
+ */
107
+ const NON_ADMIN_AUDIT_ACTOR = '00000000-0000-0000-0000-000000000000';
108
+ /**
109
+ * The cookie an anonymous shopper's cart is keyed by.
110
+ *
111
+ * Spelled here because `cartActorResolver` reads it and `@endora-commerce/contracts`
112
+ * publishes no constant for it — unlike the two session cookies, which it does.
113
+ * `carts` owns the name and sets it; `organizations` clears it on sign-out.
114
+ * Deliberately not "fixed" by publishing a fourth cookie constant in the same
115
+ * change: that is a contract addition with three other call sites to convert,
116
+ * and this move is not the place to decide it.
117
+ */
118
+ const ANONYMOUS_CART_COOKIE = 'b2b_cart_anon';
119
+ /**
120
+ * The default {@link AppComposition} — the compiled-in half empty.
121
+ *
122
+ * An instance ships no generated manifest index and no committed registry, so
123
+ * its modules are its overlay modules plus the packages it installed, its
124
+ * entities are those packages' entities, and its migrations are those packages'
125
+ * migrations. Each is the same platform function the application's own binding
126
+ * calls, with `core` empty, so there is no second derivation of any of them.
127
+ *
128
+ * **Exported for its own test and named by no barrel.** Every other seam that
129
+ * could reach it needs a PostgreSQL, a Redis and an installed module set —
130
+ * `composeApp` opens all three before it composes anything — while the property
131
+ * this function has to hold is decided entirely by what it reads off disk: the
132
+ * modules it composes and the manifests it resolves must be one set.
133
+ * `default-composition-overlay.test.ts` is that assertion and it runs against a
134
+ * fixture deployment root with no service behind it. `./composition` does not
135
+ * carry the name, so nothing outside this package can call it.
136
+ */
137
+ export async function defaultComposition(deploymentRoot, env) {
138
+ // Both overlay seams off one reader, over one id set
139
+ // (`specs/124-instance-customisation-gap/` FR-001, FR-002). The registration
140
+ // half used to be composed here while the manifest half was passed
141
+ // `async () => []` four lines below, so an instance's overlay module reached
142
+ // the container, the permission gate and the presence projection and never
143
+ // `lifecycleManifestRegistry`: the boot reconcile accounted for one module
144
+ // fewer than the presence projection enumerated, which is A4's own
145
+ // arithmetic, and no operator could switch the module off because there was
146
+ // no manifest to gate it against (Principle XVII).
147
+ const overlayModules = overlayModulesUnder(activeOverlayModulesRoot(deploymentRoot, env), () => installedPackageModuleIdClaims(nodeModulesRootsFor(env)));
148
+ const overlay = await overlayModules.entries();
149
+ const packages = await loadPackageModuleEntries(env);
150
+ const manifests = await resolveManifestEntries({
151
+ core: [],
152
+ overlay: () => overlayModules.manifests(),
153
+ packages: () => discoverPackageModuleManifests(env),
154
+ });
155
+ const bootstrap = createOrmBootstrap(async () => {
156
+ const [entities, migrations] = await Promise.all([
157
+ configuredEntitiesFrom({ coreEntities: [], env }),
158
+ discoverConfiguredMigrations({ coreEntries: [], manifests: [] }, env),
159
+ ]);
160
+ return mikroOrmConfigFrom({ entities, migrations });
161
+ });
162
+ return {
163
+ // `_lifecycle` first, and it is the platform's own rather than the
164
+ // instance's (`specs/110-instance-repository/` T141). Its sources are in
165
+ // this package, so the only tree that could compose it is one carrying a
166
+ // generated composition — and an instance carries none, which is what left
167
+ // every instance refusing its own boot with `not-shipped: _lifecycle`,
168
+ // needed by five modules of the default set. `resolveManifestEntries`
169
+ // supplies the manifest half from the same declaration; this is the
170
+ // registration half, which cannot go there because `ModuleEntry` is this
171
+ // directory's and `lifecycle/` may not name it.
172
+ //
173
+ // Nothing is contributed here when the caller supplied its own
174
+ // `composition.modules`: this whole function is the fallback, so a host with
175
+ // a generated composition of its own is untouched.
176
+ modules: [
177
+ { id: lifecycleManifest.id, version: lifecycleManifest.version, registerModule: registerLifecycleModule },
178
+ ...overlay,
179
+ ...packages,
180
+ ],
181
+ manifests,
182
+ orm: { open: bootstrap.initOrm, close: bootstrap.closeOrm },
183
+ };
184
+ }
185
+ /**
186
+ * Every environment value below is read as `process.env['NAME']` at its own
187
+ * site, and never through a local alias.
188
+ *
189
+ * That is a rule about `check:env-inputs`, not about style: its walk reconciles
190
+ * `ENVIRONMENT_INPUTS` against the `process.env` reads it can **see**, and an
191
+ * alias hides every read behind it. Measured on the first draft of this file,
192
+ * which bound `const env = process.env` once: the check's site count fell from
193
+ * 67 to 58 and `REDIS_URL` and `REVALIDATE_SECRET` were reported as
194
+ * `unread-input` — an operator asked for two values that appeared to change
195
+ * nothing, on the merge request that made them load-bearing for every
196
+ * deployment at once.
197
+ */
198
+ export async function composeApp(options) {
199
+ const { deploymentRoot } = options;
200
+ // Issue #218 — before anything is opened, refuse a production boot with no
201
+ // public origin. `PUBLIC_API_BASE_URL` is what every payment-gateway callback
202
+ // URL, public product-feed URL and newsletter confirmation link is built on,
203
+ // and its old `http://localhost:3001` default produced a wrong-but-plausible
204
+ // URL nothing logged and nothing refused. Every deployment entry point goes
205
+ // through this function, so one line covers all of them — and an application's
206
+ // `index.ts` turns a throw from here into a "this is almost always a
207
+ // configuration problem" message plus `exit(1)`.
208
+ assertPublicApiBaseUrlConfigured();
209
+ // Resolved once, and only for the members the caller did not supply: the
210
+ // default builds an ORM bootstrap and scans `node_modules`, and doing that
211
+ // beside a caller that already handed over both would be two answers to one
212
+ // question.
213
+ const supplied = options.composition ?? {};
214
+ const fallback = supplied.modules !== undefined && supplied.manifests !== undefined && supplied.orm !== undefined
215
+ ? undefined
216
+ : await defaultComposition(deploymentRoot, process.env);
217
+ const moduleEntries = supplied.modules ?? fallback?.modules ?? [];
218
+ const resolvedRegistry = supplied.manifests ?? fallback?.manifests ?? [];
219
+ const ormLifecycle = supplied.orm ?? fallback?.orm;
220
+ const orm = await ormLifecycle.open();
221
+ // Feature 050 — the single EM-injection seam. `forkScopedEm` is a bare
222
+ // `orm.em.fork()`: it stamps NOTHING, because the tenant filters read the
223
+ // ambient TenantContext from AsyncLocalStorage **when the query is built**
224
+ // (`tenancy/filters.ts`), not when the manager is forked. That is what makes
225
+ // the EntityManager stateless with respect to tenancy, and it is the property
226
+ // the whole request seam rests on.
227
+ const em = () => forkScopedEm(orm);
228
+ // Feature 072 — the kernel container. Modules composed through
229
+ // `composeModules` register into it; the deployment values assembled below
230
+ // are handed to that call and register nothing themselves.
231
+ //
232
+ // It is deliberately **not** installed as the process root
233
+ // (`setRootContainer`). Doing so makes every `enterPlatformScope` branch a
234
+ // child off this graph, and a scope is what lives in an `AsyncLocalStorage`
235
+ // store — so every retained store starts pinning a whole composed
236
+ // application. Phase 4 measured the cost: the suite died with `JavaScript
237
+ // heap out of memory` at file 78 of 930 with the root installed.
238
+ const container = createRootContainer();
239
+ registerOrm(container, orm);
240
+ // One ledger for the whole boot, so two modules composed in different
241
+ // `composeModules` calls still collide loudly on a shared registration name.
242
+ const registrationOwnership = createRegistrationOwnership();
243
+ const redisUrl = process.env['REDIS_URL'] ?? 'redis://localhost:6379';
244
+ const redis = new Redis(redisUrl, { maxRetriesPerRequest: null, lazyConnect: false });
245
+ // Principle X deployment dial. BACKEND_ROLE controls whether this process
246
+ // runs queue consumers (workers):
247
+ // - unset / 'all' → API + co-located workers (default single-VPS)
248
+ // - 'api' → HTTP only; workers run in a separate `pnpm worker`
249
+ // - 'worker' → workers only (set by `worker.ts`; no HTTP listen)
250
+ const runWorkers = processRunsWorkersFor(process.env['BACKEND_ROLE']);
251
+ // Feature 018 — separate ioredis client for the module-state pub/sub
252
+ // channel. ioredis multiplexes commands and subscriptions on different
253
+ // sockets, so we keep them on different clients to avoid the "subscribed
254
+ // mode" command restriction on the main client.
255
+ const redisSubscriber = new Redis(redisUrl, {
256
+ maxRetriesPerRequest: null,
257
+ lazyConnect: false,
258
+ });
259
+ const auditLogService = new AuditLogService(em);
260
+ // Feature 090 Phase 2 — which bundle holds which error code's sentence,
261
+ // derived from the manifests this deployment resolved rather than from a table
262
+ // (`specs/090-module-owned-error-codes/contracts/error-code-declaration.md` §4).
263
+ // Activation is deliberately not consulted: a code owned by a switchable
264
+ // module is raised by other modules too, so a switched-off `carts` must not
265
+ // cost `orders` its checkout sentence.
266
+ //
267
+ // Reported here rather than at the injection site because a collision is a
268
+ // fact about the composition and an operator has to be able to read it before
269
+ // the first request that renders wrong — and it is `warn` rather than a
270
+ // refusal: §3.3's severity gradient reserves a refused boot for the
271
+ // irreversible, and the blast radius of a contested code is one sentence.
272
+ const errorTranslation = buildErrorTranslationTargets(resolvedRegistry);
273
+ if (errorTranslation.collisions.length > 0) {
274
+ platformLogger().warn({ collisions: errorTranslation.collisions.length }, 'error codes are claimed by more than one module and therefore route to none of ' +
275
+ `them:\n${describeErrorCodeCollisions(errorTranslation.collisions)}`);
276
+ }
277
+ // Feature 072 (D-38) — module presence is a **composition input**, so it is
278
+ // loaded here: before the first module registers, and therefore before any
279
+ // boot hook, plugin body or worker registration asks for it. It used to be
280
+ // warmed inside `_lifecycle`'s plugin body, which runs in `buildServer` —
281
+ // after all of them — and the platform stopped booting the moment a boot hook
282
+ // resolved a gated port, because the cache still answered "not installed" for
283
+ // everything.
284
+ //
285
+ // Awaited and fatal, and that costs nothing new: opening the ORM above
286
+ // already makes a reachable PostgreSQL a boot precondition. Arming the Redis
287
+ // pub/sub side is separate (`registryCache.watch()`, from `_lifecycle`'s
288
+ // plugin) and must never fail a boot — a lost notification channel means
289
+ // stale, not off.
290
+ await enterSystemScope('boot: load module presence',
291
+ // The **entries**, not their manifests: `loadModulePresence` narrows the
292
+ // first-boot insert to what this build ships (D-157.6(b)), and `filePath` is
293
+ // what says which entry that is.
294
+ async () => loadModulePresence({
295
+ em,
296
+ entries: resolvedRegistry,
297
+ declaredOmissions: options.declaredOmissions ?? [],
298
+ }), { entryPoint: 'boot' });
299
+ const eventBus = new EventBus();
300
+ // Feature 054 (Principle XIII) — the Command Bus: the single, guaranteed audit
301
+ // writer for sensitive writes. It forks the scoped EM, runs the write + one
302
+ // audit insert co-transactionally, and dispatches the domain event on commit.
303
+ const commandBus = new CommandBus(orm, auditLogService, eventBus);
304
+ // Feature 060 — API interceptor registry. Modules register pre/post
305
+ // interceptors against endpoints owned by other modules; execution is
306
+ // lifecycle-gated per interceptor via the enabled-set cache predicate.
307
+ const apiInterceptors = new ApiInterceptorRegistry({
308
+ isModuleEnabled: (moduleId) => registryCache.isEnabled(moduleId),
309
+ });
310
+ // Feature 072 — the **host values** a composition owns outright. No module
311
+ // registers a default for any of them, so they have no contribution window
312
+ // (D-45's one-slot rule is about overwriting a module's default) and are
313
+ // registered where the value comes into existence rather than after
314
+ // `composeModules`. Everything a module does default is contributed below,
315
+ // between that call and `runBootHooks()`.
316
+ registerValues(container, {
317
+ redis,
318
+ // Feature 072 (T125) — the interceptor registry, so `_lifecycle` can serve
319
+ // the read-only diagnostics screen over it.
320
+ apiInterceptors,
321
+ // Whether this process runs queue consumers: the one module-agnostic
322
+ // answer, read by every module that starts one — at construction and from
323
+ // its `ctx.onBoot` reconcile — so no module reads `BACKEND_ROLE` itself and
324
+ // no module needs a flag of its own here
325
+ // (`specs/134-paid-module-extraction/` research D16, contract W1.1). The six
326
+ // values named after paid modules that stood beside it were removed in
327
+ // T124, and `product_feeds`' own worker flag with them once that module
328
+ // read this instead. Its two values below are D16 §6's free-side
329
+ // remainder, not a pattern to follow.
330
+ processRunsWorkers: runWorkers,
331
+ productFeedsPublicBaseUrl: resolvePublicApiBaseUrl(),
332
+ productFeedsTokenEncryptionKey: process.env['SETTINGS_SECRET_ENCRYPTION_KEY'],
333
+ // The key newsletter confirmation and unsubscribe links are signed with
334
+ // (`specs/117-instance-bring-up/` Phase 6, T6-B1).
335
+ //
336
+ // A **value** rather than a read inside the module, because
337
+ // `NEWSLETTER_TOKEN_SECRET` is declared in this package's own environment
338
+ // declaration. It is a module-named value in a composition root, which
339
+ // `specs/134-paid-module-extraction/` research D16 §2(d) names as the target
340
+ // to converge away from — the module registering it itself, with a default
341
+ // computed from platform-published inputs — and D16 §6 records as a free-side
342
+ // question rather than that feature's. It is not a precedent: the six
343
+ // module-named values that once stood beside it were removed (T124).
344
+ //
345
+ // The fallback chain is the declaration's own sentence: absent, *"newsletter
346
+ // links are signed with the session key instead"* — and an empty value is
347
+ // absent (`./newsletter-token-secret.ts`). The **third** fallback
348
+ // the reference deployment carried — a literal `'newsletter-dev-secret'` —
349
+ // is deliberately not reproduced. It is a shipped default signing key,
350
+ // nothing declares it, and a deployment that reached it signed every
351
+ // confirmation link with a secret that is in this repository.
352
+ newsletterTokenSecret: newsletterTokenSecretFrom(process.env['NEWSLETTER_TOKEN_SECRET'], process.env['SESSION_COOKIE_SECRET']),
353
+ // The one connection ioredis has put into subscriber mode. Shared, because
354
+ // a subscriber connection cannot serve commands: a per-module one would
355
+ // cost a socket per module and buy nothing.
356
+ redisSubscriber,
357
+ // Modules announce on it; `ctx.subscribe` receives on it. A module that
358
+ // publishes needs it as a registration, not just as a composer option.
359
+ eventBus,
360
+ // The audited write path (Principle XIII). A converted module resolves it
361
+ // like any other platform service.
362
+ commandBus,
363
+ // The resolved registry — core manifests plus this deployment's overlay
364
+ // modules plus every installed package. `admin_roles` builds the permission
365
+ // catalogue from it and cannot see it itself: which modules a deployment
366
+ // ships is a composition input, not something a module decides.
367
+ resolvedModuleRegistry: resolvedRegistry,
368
+ auditLogService,
369
+ storefrontBaseUrl: process.env['STOREFRONT_BASE_URL'] ?? 'http://localhost:3000',
370
+ // No verification-token probe outside a harness.
371
+ organizationsExposeTestProbe: false,
372
+ ...options.values,
373
+ });
374
+ /**
375
+ * The container reads this function makes, against
376
+ * {@link PlatformContainerReads}.
377
+ *
378
+ * A function rather than a captured object, for the reason every accessor in
379
+ * a composition root is one: a gated name resolves per call, so a switched-off
380
+ * owner answers at the call site instead of through a handle this composition
381
+ * is holding.
382
+ */
383
+ const reads = () => container.cradle;
384
+ // Where this call sits no longer decides whether a cache is fresh, and that
385
+ // is the point of D-93. Channel *resolution* is kernel infrastructure for the
386
+ // reason T110 gave: every channel-scoped read depends on it (Principle XII),
387
+ // so it must keep working whether or not an operator wants the administration
388
+ // screens. The module owns the admin CRUD service and its routes.
389
+ const salesChannels = composeSalesChannelsKernel({
390
+ emFactory: em,
391
+ eventBus,
392
+ redis,
393
+ auditLogService,
394
+ });
395
+ // Feature 005 / `specs/117-instance-bring-up/` — and the invariant is this
396
+ // root's because the middleware above is.
397
+ //
398
+ // `registerSalesChannelResolverMiddleware` installs a **global `onRequest`
399
+ // hook** that falls back to `resolver.getSystemDefault()` for every
400
+ // `/api/v1/*` path except `/api/v1/_health`, and that call throws
401
+ // `NoSystemDefaultChannel` — an `HttpError(500, INTERNAL)`, which the error
402
+ // envelope answers *without logging*. So a composition that mounts the
403
+ // resolver and does not guarantee the flagged row serves `500 INTERNAL` to
404
+ // every request and writes nothing about any of them.
405
+ //
406
+ // It stood in the reference deployment's contribution callback until
407
+ // 2026-09-13, which made it a step only a root that *supplies* one performed.
408
+ // An instance supplies none (`contracts/instance-repository.md` R2.4), so
409
+ // every scaffolded instance answered 500 on `/api/v1/_openapi.json` — a route
410
+ // that touches no module and no database — from its first served request.
411
+ // `harness-parity.test.ts` could not see it: production and the harness both
412
+ // ran the reconciler, and the root that did not is the one this repository
413
+ // never composes.
414
+ //
415
+ // **Before `composeModules`**, for the reason the reference deployment's own
416
+ // comment gave: a module registration or an `ctx.onBoot` hook may read the
417
+ // system default (`inventory`'s warehouse/channel pairing,
418
+ // `mfaDefaultChannelIdResolver`), and none of them may observe the registry
419
+ // mid-repair.
420
+ //
421
+ // Feature 072 (T036) — boot reconcilers establish their own scope. This one
422
+ // ran with no ambient tenant context for a long time and survived only
423
+ // because the rows it touches carry no automatic filter; that was an accident
424
+ // of entity classification, not a guarantee.
425
+ const defaultChannelReconciliation = await enterSystemScope('boot: reconcile the default sales channel', () => new DefaultChannelReconciler(em, auditLogService).run(), { entryPoint: 'boot' });
426
+ if (defaultChannelReconciliation.action === 'warning' && defaultChannelReconciliation.warning) {
427
+ platformLogger().warn({ action: defaultChannelReconciliation.action }, defaultChannelReconciliation.warning);
428
+ }
429
+ // Feature 072 (T118) — the universal settings *reader* is kernel
430
+ // infrastructure: almost every module calls `SettingsService.get`, so it
431
+ // cannot be gated on whether an operator wants the settings screens.
432
+ const settings = composeSettingsKernel({
433
+ emFactory: em,
434
+ redis,
435
+ ...(process.env['SETTINGS_SECRET_ENCRYPTION_KEY']
436
+ ? { secretEncryptionKey: process.env['SETTINGS_SECRET_ENCRYPTION_KEY'] }
437
+ : {}),
438
+ });
439
+ // Secret settings (e.g. prompt_actions API keys) are AES-256-GCM encrypted at
440
+ // rest with SETTINGS_SECRET_ENCRYPTION_KEY. The key is read from the
441
+ // environment once at boot, so a value added to `.env` only takes effect
442
+ // after a restart. Warn loudly here so a missing key is obvious instead of
443
+ // surfacing only as a 500 when an operator tries to save a secret.
444
+ if (!process.env['SETTINGS_SECRET_ENCRYPTION_KEY']) {
445
+ // Boot-time logging path; the Fastify logger is not yet available here.
446
+ console.warn('[settings] SETTINGS_SECRET_ENCRYPTION_KEY is not set — secret settings ' +
447
+ '(e.g. prompt_actions API keys) cannot be saved. Set a base64 32-byte key ' +
448
+ '(openssl rand -base64 32) in the deployment environment and restart the backend.');
449
+ }
450
+ // Feature 072 — the module list, composed in one pass (D-45). Registration
451
+ // resolves nothing, so this call has no opinion about the order the caller
452
+ // assembled; the boot hooks it collects run once, at the bottom of this
453
+ // function, after every contribution below.
454
+ const composedModules = composeModules(moduleEntries, {
455
+ container,
456
+ eventBus,
457
+ // Issue #269 — composition runs before `buildServer`, so there is no
458
+ // `app.log` yet. This is late-bound rather than a snapshot: `buildServer`
459
+ // attaches the application's own pino instance the moment it exists.
460
+ log: platformLogger(),
461
+ interceptorRegistry: apiInterceptors,
462
+ ownership: registrationOwnership,
463
+ // Issue #258 — the modules this deployment is required to have, derived
464
+ // from the manifest set it resolved above rather than written down (D-100).
465
+ requiredModules: requiredModulesFrom(resolvedRegistry.map((entry) => entry.manifest)),
466
+ // Feature 107 (FR-040/FR-041) — **checked, never applied.** The composer
467
+ // emits in its own order and drains decorations once; this asserts that the
468
+ // resulting order was the intended one and refuses when the two disagree.
469
+ decorationOrder: options.decorationOrder,
470
+ });
471
+ const composedContext = {
472
+ orm,
473
+ em,
474
+ container,
475
+ eventBus,
476
+ commandBus,
477
+ auditLogService,
478
+ apiInterceptors,
479
+ redis,
480
+ redisSubscriber,
481
+ settings,
482
+ salesChannels,
483
+ resolvedModules: resolvedRegistry,
484
+ composed: composedModules,
485
+ };
486
+ // --- the platform's own contributions ------------------------------------
487
+ //
488
+ // The twenty of `composition.ts`' sixty-one whose value expression names no
489
+ // module: a sub-kernel's object, a host value or an environment read. They
490
+ // are contributed here rather than by a caller because a deployment that had
491
+ // to write them would be writing the platform's own wiring — R1.4 — and an
492
+ // instance that forgot one would compose a platform missing a name eleven
493
+ // modules resolve.
494
+ //
495
+ // They go **before** `options.contribute`, so a deployment that genuinely
496
+ // wants a different answer for one of them can still say so.
497
+ // Feature 072 (T110) — the channel-resolution names. The kernel itself is
498
+ // composed above `composeModules`, for the subscriber ordering; what belongs
499
+ // here is the registration, in the one contribution slot.
500
+ composedModules.contribute({
501
+ salesChannelsCache: salesChannels.cache,
502
+ // Feature 120 (FR-015) — the channel-bridge contribution registry. Each
503
+ // module owning a channel-scoped entity type resolves this name from its
504
+ // own boot hook and declares the one bridge table its migrations create;
505
+ // the platform holds no map of the nine. A member nothing registered
506
+ // refuses at the membership call instead of reaching a relation an
507
+ // instance that omits that module does not have.
508
+ salesChannelBridgeRegistry: salesChannels.bridgeRegistry,
509
+ // The kernel-reserved membership port. `payment_methods` and
510
+ // `delivery_methods` resolve it to auto-bind a new method to the system
511
+ // default channel; both read it when their routes register.
512
+ salesChannelMembershipPort: salesChannels.membershipService,
513
+ // The channel resolver itself. `inventory` has resolved this name since
514
+ // T129 and neither root registered it, so the channel-scoped storefront
515
+ // stock read threw `AwilixResolutionError` on its first call.
516
+ salesChannelResolutionPort: salesChannels.resolver,
517
+ /**
518
+ * The channel a **channel-scoped** settings read resolves against outside a
519
+ * request (worker, boot hook, CLI): the deployment's system-default sales
520
+ * channel.
521
+ *
522
+ * D-48 removed the `?? null` — the resolver cannot fail to find a default,
523
+ * so this cannot answer "none". The return type stays `string | null`
524
+ * because the *seam* still admits one: a composition may register a
525
+ * resolver of its own that has no channel to offer.
526
+ */
527
+ settingsChannelResolver: async () => (await salesChannels.resolver.getSystemDefault()).id,
528
+ // Feature 072 (wave 2) — the sales-channel code⇄id lookup
529
+ // `google_analytics` resolves. `idByCode` is the kernel resolver's;
530
+ // `codeById` reads the module's own gated `salesChannelsService` port by
531
+ // container name, against the one method it calls.
532
+ salesChannelCodeIdPort: {
533
+ idByCode: async (code) => (await salesChannels.resolver.getByCode(code))?.id ?? null,
534
+ codeById: async (id) => {
535
+ const { items } = await reads().salesChannelsService.list({});
536
+ return items.find((c) => c.id === id)?.code ?? null;
537
+ },
538
+ },
539
+ // Feature 042 / D-96 — the default channel an MFA challenge is scoped to.
540
+ mfaDefaultChannelIdResolver: async () => (await salesChannels.resolver.getSystemDefault()).id,
541
+ });
542
+ // Feature 072 (T118) — the settings names. The kernel itself is composed
543
+ // above `composeModules`, for the subscriber ordering; what belongs here is
544
+ // the registration, in the one contribution slot.
545
+ composedModules.contribute({
546
+ // The kernel's `SettingsService` already implements the read port.
547
+ settingsReadPort: settings.settingsService,
548
+ // The same cache, seen from the writing side (issue #45). The `settings`
549
+ // module owns the one write seam, so it is the one place that can drop the
550
+ // cache *as part of* the write instead of announcing the write and hoping a
551
+ // subscriber gets there first.
552
+ settingsCache: settings.cache,
553
+ settingsSecretEncryptionKey: process.env['SETTINGS_SECRET_ENCRYPTION_KEY'],
554
+ // Feature 073 — the effective-state reader. Registered here rather than
555
+ // imported inside the module so the dependency direction stays declared in
556
+ // a composition: `_lifecycle` reads this module's `Setting` rows, and this
557
+ // module reads nothing of `_lifecycle`'s.
558
+ settingsModulePresence: {
559
+ presenceOf: (moduleId) => effectiveState.presenceOf(moduleId),
560
+ activationControlOwner: (code) => effectiveState.activationControlOwner(code),
561
+ },
562
+ // US2 — the delete-integrity guard reaches settings only through this port
563
+ // (Principle I): `SettingsService.listReferencesToConfiguration`.
564
+ credentialsSettingsPort: settings.settingsService,
565
+ });
566
+ // The lazily built manifest registry the contribution below hands `_i18n`.
567
+ let manifestRegistry;
568
+ composedModules.contribute({
569
+ // Principle X — whether this process runs each module's queue consumers.
570
+ // Only the *flag* was ever a deployment decision; the workers themselves
571
+ // are their modules' own (T143a).
572
+ webhooksRunWorkers: runWorkers,
573
+ pwaRunWorkers: runWorkers,
574
+ catalogRunBulkOperationWorker: runWorkers,
575
+ searchRunWorkers: runWorkers,
576
+ // Feature 072 (T127) — whether a wall-clock status sweeper runs.
577
+ priceListsEnableStatusSweeper: true,
578
+ // Feature 072 (wave 2) — the connection a module may build a BullMQ
579
+ // producer queue on. Deliberately a different name from `redis`: "no queue
580
+ // in this composition" is a statement a composition should be able to make
581
+ // rather than something inferred from a missing option.
582
+ moduleQueueRedis: redis,
583
+ // Blog ships no storefront ports today — the factory defaulted this to `{}`
584
+ // and no composition ever passed one.
585
+ blogStorefrontDeps: undefined,
586
+ // Issue #225 — the reading and its generation, contributed as one value.
587
+ // The palette memoises what the reading produced, so a composition that
588
+ // handed over the reading alone would hand over a cache nothing can drop.
589
+ modulePresenceProbe: {
590
+ // Issue #187 — the platform axis, which the palette used to read by
591
+ // joining `module_registrations` itself. `?? false` where the operator
592
+ // axis defaults `true`, and the asymmetry is the tri-state rather than an
593
+ // oversight.
594
+ isPlatformAvailable: (moduleId) => effectiveState.presence(moduleId)?.platformAvailable ?? false,
595
+ isActivated: (moduleId) => effectiveState.presence(moduleId)?.operatorActivated ?? true,
596
+ version: () => effectiveState.presenceVersion(),
597
+ },
598
+ // The accessor `_i18n` walks to reconcile every module's translation
599
+ // bundles (`specs/110-instance-repository/` T141). It is a **default**:
600
+ // both roots in this repository contribute their own below, through
601
+ // `options.contribute`, and an instance contributes nothing at all — R2.4 —
602
+ // so before this it resolved to nothing and the boot died inside `_i18n`'s
603
+ // reconcile with `Could not resolve 'lifecycleManifestRegistry'`.
604
+ //
605
+ // Built lazily and once: a composition that never reads the name pays for
606
+ // no registry, and `buildStaticRegistry` refuses a duplicate module id,
607
+ // which the resolved set cannot hold.
608
+ lifecycleManifestRegistry: () => (manifestRegistry ??= buildStaticRegistry(resolvedRegistry)),
609
+ // Feature 072 (T125) — how a committed activation flip propagates: the
610
+ // writing process refreshes itself rather than waiting on its own pub/sub
611
+ // round trip, so the very next request it serves sees the new state.
612
+ lifecycleActivationPropagation: {
613
+ commandBus,
614
+ propagation: {
615
+ refreshLocalState: () => registryCache.refreshFromDb(em),
616
+ publishStateChanged: (payload) => publishStateChanged(redis, payload),
617
+ revalidateStorefront: (tags) => new StorefrontRevalidator({
618
+ baseUrl: process.env['STOREFRONT_BASE_URL'],
619
+ secret: process.env['REVALIDATE_SECRET'],
620
+ }).revalidate(tags),
621
+ },
622
+ },
623
+ });
624
+ // --- the actor-shaped ten (T118b, completed by feature 117's Phase 6) -----
625
+ //
626
+ // Nine names that answer one question — *who is asking?* — off `request.actor`
627
+ // and nothing else. They stayed in `backend/src/composition.ts` through T118
628
+ // for a single reason: the `declare module 'fastify'` block that puts `actor`
629
+ // on `FastifyRequest` was `auth`'s, so a platform file reading it would have
630
+ // been a platform file depending on a module (D-52/D-53). T118b moved that
631
+ // declaration to `../http/request-actor.ts` and the shape to
632
+ // `@endora-commerce/contracts`, and the nine came with it. Their value
633
+ // expressions name no module, which is T118's criterion unchanged.
634
+ //
635
+ // **The tenth arrived with `specs/117-instance-bring-up/` Phase 6** and is
636
+ // `customerOrganizationIdResolver`, below. T118b left it in the deployment's
637
+ // `values` saying it stayed because it reads `request.actor` — the very thing
638
+ // T118b moved — so the reason expired in the commit that wrote it, and four
639
+ // modules went on reading a name only two compositions in the world supplied.
640
+ //
641
+ // `ordersAdminScopeResolver` was called the tenth and is not on this list at
642
+ // all: its body decides on `admin_roles.code === 'sales_representative'` over
643
+ // a row it reads from `admin_users`, which is a module's business rule over a
644
+ // module's table. That is a correct reason not to put it here, and the home
645
+ // it points at is `orders`, which registers it since the same phase.
646
+ //
647
+ // **Where a widening appears below it is that site's own.** `request.actor` is
648
+ // decorated by `auth`'s `onRequest` hook; the three audit-context resolvers
649
+ // are called from surfaces a composition can mount without one, and answering
650
+ // the nil-UUID sentinel is what they already did. The five that throw already
651
+ // threw.
652
+ composedModules.contribute({
653
+ // Feature 072 (T143a) — how this platform resolves the acting admin for a
654
+ // module that takes one as an option. `credentials` is the original
655
+ // consumer; the shape is `{ adminUserId }` and the refusal is a 401.
656
+ adminContextResolver: (request) => {
657
+ if (request.actor.kind !== 'admin') {
658
+ throw new HttpError(401, ERROR_CODES.UNAUTHORIZED, 'Admin session required.');
659
+ }
660
+ return { adminUserId: request.actor.adminUserId };
661
+ },
662
+ // Feature 072 (wave 2) — how this platform names the acting admin on an
663
+ // audit record: the admin's id, or `null` for a non-admin caller. Six
664
+ // modules each declared an identically-shaped `resolveAuditContext` option
665
+ // and both roots spelled the same closure once per module.
666
+ adminAuditActorResolver: (request) => ({
667
+ actorAdminUserId: request.actor.kind === 'admin' ? request.actor.adminUserId : null,
668
+ }),
669
+ // Feature 072 (T127) — `price_lists`' audit context. Unlike
670
+ // `adminAuditActorResolver` this one owes a non-null id, so a caller the
671
+ // admin gate should already have refused falls back to the nil UUID rather
672
+ // than to `null`.
673
+ priceListsAdminAuditContext: (request) => {
674
+ const actor = request.actor;
675
+ if (actor?.kind !== 'admin') {
676
+ return { actorAdminUserId: NON_ADMIN_AUDIT_ACTOR };
677
+ }
678
+ return { actorAdminUserId: actor.adminUserId };
679
+ },
680
+ // Feature 072 (T142) — `catalog`'s audit context. Same sentinel, plus the
681
+ // impersonation field that module's record carries.
682
+ catalogAdminAuditContext: (request) => {
683
+ const actor = request.actor;
684
+ if (actor?.kind !== 'admin') {
685
+ // Auditing an anonymous mutation shouldn't happen — the admin gate
686
+ // refuses these — but if it ever does, fall back to a sentinel.
687
+ return { actorAdminUserId: NON_ADMIN_AUDIT_ACTOR };
688
+ }
689
+ return {
690
+ actorAdminUserId: actor.adminUserId,
691
+ impersonatedCustomerAccountId: null,
692
+ };
693
+ },
694
+ // Feature 072 (T129) — `inventory`'s audit context.
695
+ inventoryAdminAuditContext: (request) => {
696
+ const actor = request.actor;
697
+ if (actor?.kind !== 'admin') {
698
+ return { actorAdminUserId: NON_ADMIN_AUDIT_ACTOR };
699
+ }
700
+ return { actorAdminUserId: actor.adminUserId };
701
+ },
702
+ /**
703
+ * Feature 072 (wave 2) — how this platform resolves the calling customer,
704
+ * for the five modules that take one as an option.
705
+ *
706
+ * **The refusal below asserts an invariant; it does not describe a business
707
+ * state** (D-178). It was a 422 `organization_required`, introduced by
708
+ * feature 026 US2 for accounts that were allowed to have no Organization.
709
+ * Every transacting customer has one — `customer_accounts.organization_id`
710
+ * is `NOT NULL` and an individual is backed by a personal organisation — so
711
+ * a caller reaching this branch is a broken invariant, and a 422 telling a
712
+ * buyer to attach an Organization they have no way to attach is a lie with
713
+ * a remedy attached.
714
+ *
715
+ * The guard is **kept** rather than deleted: `Actor`'s `organizationId` is
716
+ * `string | null` at this seam and the consumers' input type is
717
+ * `organizationId: string`, so removing the check would push `undefined`
718
+ * through silently. Routes that work *without* an Organization
719
+ * (cart-add, browsing, profile-read) take `cartActorResolver` or read
720
+ * `request.actor` themselves.
721
+ */
722
+ customerContextResolver: (request) => {
723
+ if (request.actor.kind !== 'customer') {
724
+ throw new HttpError(401, ERROR_CODES.UNAUTHORIZED, 'Customer session required.');
725
+ }
726
+ if (!request.actor.organizationId) {
727
+ throw new HttpError(500, ERROR_CODES.INTERNAL, 'Invariant violated: a customer account has no Organization (Principle XI).', { code: 'customer_account_organization_missing' });
728
+ }
729
+ return {
730
+ customerAccountId: request.actor.customerAccountId,
731
+ organizationId: request.actor.organizationId,
732
+ impersonatorAdminUserId: request.actor.impersonatorAdminUserId ?? null,
733
+ };
734
+ },
735
+ // Feature 072 (wave 3) — how this platform names the calling customer as an
736
+ // id. Unlike `customerContextResolver` it does not require an Organization:
737
+ // it asserts a customer session and nothing more. The four payment gateways
738
+ // each declared an identically-shaped `resolveCustomerAccountId` option.
739
+ customerAccountIdResolver: (request) => {
740
+ if (request.actor.kind !== 'customer') {
741
+ throw new HttpError(401, ERROR_CODES.UNAUTHORIZED, 'Customer session required.');
742
+ }
743
+ return request.actor.customerAccountId;
744
+ },
745
+ // Feature 072 — `carts`' actor, which is the one that answers for an
746
+ // anonymous shopper too: a signed-in customer, else the anonymous cart
747
+ // cookie, else nothing at all. The empty answer is a cart the caller may
748
+ // still create.
749
+ cartActorResolver: (request) => {
750
+ if (request.actor.kind === 'customer') {
751
+ return {
752
+ customer: {
753
+ customerAccountId: request.actor.customerAccountId,
754
+ organizationId: request.actor.organizationId,
755
+ },
756
+ };
757
+ }
758
+ const cookies = request.cookies;
759
+ const anon = cookies?.[ANONYMOUS_CART_COOKIE];
760
+ if (anon)
761
+ return { anonymousToken: anon };
762
+ return {};
763
+ },
764
+ // Feature 072 (T138) — the actor half of what used to be
765
+ // `buildOrgAllowListResolver`: who is asking, as a bare Organization id.
766
+ //
767
+ // **The tenth actor-shaped name, and it arrived three features late**
768
+ // (`specs/117-instance-bring-up/` Phase 6). It was a `values` entry of
769
+ // `backend/src/composition.ts`, and the comment beside it said why: *"it
770
+ // reads `request.actor`, which is `auth`'s `declare module 'fastify'`
771
+ // block — T118b's subject"*. T118b is the merge request that moved the
772
+ // augmentation to `../http/request-actor.ts` and brought the nine above
773
+ // with it; this one was left behind and its stated blocker expired in the
774
+ // same commit. Its value expression names no module, which is T118's
775
+ // criterion unchanged.
776
+ //
777
+ // Four modules read it — `delivery_methods`, `inventory`, `orders` and
778
+ // `payment_methods` — and nothing defaulted it, so a composition that was
779
+ // not `backend/src/composition.ts` did not have it. That is not an
780
+ // override a client declines; it is a name a scaffolded instance cannot
781
+ // resolve, met as a 500 on the first restriction check rather than at boot.
782
+ //
783
+ // **Soft by contract, and the softness is the reason it is its own name.**
784
+ // It answers `null` for anonymous traffic *and* for a Customer with no
785
+ // Organization, where `customerContextResolver` above throws. It is read on
786
+ // restriction checks, and catching that throw to mean "unrestricted" is how
787
+ // a fail-closed gate becomes fail-open. Do not merge the two.
788
+ customerOrganizationIdResolver: (request) => {
789
+ const actor = request.actor;
790
+ return actor?.kind === 'customer' ? (actor.organizationId ?? null) : null;
791
+ },
792
+ // Feature 072 (T140) — `customers`' own view of the calling customer:
793
+ // the account and its Organization, the second nullable. It is not
794
+ // `customerContextResolver` — self-service profile reads work for an
795
+ // account with no Organization, which is why this one does not assert one.
796
+ customerActorResolver: (request) => {
797
+ if (request.actor.kind !== 'customer') {
798
+ throw new HttpError(401, ERROR_CODES.UNAUTHORIZED, 'Customer session required.');
799
+ }
800
+ return {
801
+ customerAccountId: request.actor.customerAccountId,
802
+ organizationId: request.actor.organizationId ?? null,
803
+ };
804
+ },
805
+ });
806
+ // The caller's own, in the same window and after the platform's.
807
+ await options.contribute?.(composedContext);
808
+ const buildTenantContext = options.buildTenantContext ??
809
+ (async (request) => systemTenantContext(`${request.method} ${request.url}`));
810
+ // Assembled here rather than above the contribution window, and that is a
811
+ // guarantee rather than a placement: a caller adds to `options.plugins` or
812
+ // `options.scopedPlugins` from inside `contribute`, where the value a plugin
813
+ // needs finally exists.
814
+ const modules = [
815
+ // D-229 — the liveness and readiness probe, which is the platform's own
816
+ // surface and not a module's. It is first so that a reader looking for the
817
+ // one route an orchestrator polls finds it without reading the composer,
818
+ // and the position claims nothing about hooks: Fastify assembles a route's
819
+ // hook chain when the application is readied rather than when the route is
820
+ // registered (D-45), so the request-scope and sales-channel hooks below
821
+ // still see it — and both already exempt this path by name.
822
+ //
823
+ // It goes through `modules` rather than through `buildServer` because the
824
+ // probes close over `orm` and `redis`, which exist here and not there, and
825
+ // every composition root already passes `composition.modules` — including
826
+ // the one `endora new instance` writes. Nothing was asked of a root.
827
+ healthRoutePlugin({ orm, redis }),
828
+ // Feature 072 — every module's route contribution, in the composer's order.
829
+ //
830
+ // They sit ahead of the root plugins, and that is not an ordering claim:
831
+ // `buildServer` calls each of these with the root instance, so an
832
+ // `onRequest` hook any of them adds is a root hook, and Fastify assembles a
833
+ // route's hook chain when the application is readied rather than when the
834
+ // route is registered (D-45).
835
+ ...composedModules.sink.plugins,
836
+ // Feature 072 (T078) — the auth plugin is `auth`'s own contribution,
837
+ // collected by `ctx.rootPlugin` because it decorates `request.actor` for
838
+ // the whole application rather than contributing routes.
839
+ async (app) => {
840
+ for (const plugin of composedModules.sink.rootPlugins)
841
+ await plugin(app);
842
+ },
843
+ ...(options.plugins ?? []),
844
+ // Feature 050 / 072 (T027) — establish the ambient TenantContext for every
845
+ // request from the already-authenticated actor (never from request
846
+ // inputs), and open the request's resolution scope. One hook factory,
847
+ // shared with the test kit, so the two cannot drift.
848
+ async (app) => {
849
+ await registerRequestScopeHook(app, { buildTenantContext });
850
+ },
851
+ // Feature 005 — the sales-channel resolver middleware writes the resolved
852
+ // channel into the open request scope, so it mounts after the hook.
853
+ salesChannels.plugin,
854
+ ...(options.scopedPlugins ?? []),
855
+ ];
856
+ // Feature 004 / T024 — boot-time manifest reconciliation. Walks every
857
+ // module's settings manifest and inserts any missing groups/settings
858
+ // idempotently before the HTTP layer starts serving requests. NEVER deletes
859
+ // (R-1); destructive uninstall is CLI-only.
860
+ //
861
+ // Feature 080 (T046) — the population is `deploymentShippedEntries`, the same
862
+ // core-plus-overlay split D-157.6(b) ruled for the first-boot presence
863
+ // insert. A **package** is excluded for a reason of its own rather than for
864
+ // symmetry: since D-157.6(b) `install` is its only author, and reconciling a
865
+ // stranger's manifest here would let a `SettingCodeConflict` in something an
866
+ // operator merely `pnpm add`ed abort this boot.
867
+ const settingsManifests = reads()
868
+ .settingsManifestCollectionPort.collect(deploymentShippedEntries(resolvedRegistry));
869
+ const reconciler = new ManifestReconciler(em());
870
+ const reconciliation = await enterSystemScope('boot: reconcile module settings manifests', () => reconciler.apply(settingsManifests), { entryPoint: 'boot' });
871
+ for (const perModule of reconciliation.perModule) {
872
+ if (perModule.orphanSettings.length > 0 || perModule.orphanGroups.length > 0) {
873
+ // Boot-time logging path; the Fastify logger is not yet available here.
874
+ console.warn(`[settings] orphan rows for module "${perModule.moduleCode}": ` +
875
+ `${perModule.orphanSettings.length} settings, ${perModule.orphanGroups.length} groups`);
876
+ }
877
+ eventBus.emit('settings.module_reconciled', {
878
+ eventId: `settings.module_reconciled:${perModule.moduleCode}:${Date.now()}`,
879
+ occurredAt: new Date().toISOString(),
880
+ moduleCode: perModule.moduleCode,
881
+ addedCount: perModule.addedGroups + perModule.addedSettings,
882
+ updatedCount: perModule.updatedGroups + perModule.updatedSettings,
883
+ orphanCount: perModule.orphanGroups.length + perModule.orphanSettings.length,
884
+ });
885
+ }
886
+ // The explicit boot phase (FR-021), run **once**, after every registration
887
+ // and every contribution above and before an entry point calls `buildServer`
888
+ // (D-45). That is what makes the rule statable in one sentence: a boot hook
889
+ // may resolve anything, and a contribution goes between `composeModules` and
890
+ // this line.
891
+ //
892
+ // Why one phase rather than several: a contribution registered *after* a boot
893
+ // hook has already run is invisible to that hook, which reads the owning
894
+ // module's default instead and reports nothing — no error, no warning, a
895
+ // value that is simply the wrong one.
896
+ //
897
+ // Issue #52 — and this line is what closes the slot: every `contribute(…)`
898
+ // below it throws `ContributionWindowClosedError` naming the rule, rather
899
+ // than landing somewhere no hook will read.
900
+ await composedModules.runBootHooks();
901
+ return {
902
+ orm,
903
+ redis,
904
+ modules,
905
+ commandBus,
906
+ apiInterceptors,
907
+ container,
908
+ // Bound to the composed object rather than re-implemented: a second way to
909
+ // build a module's context is a second answer about what that module
910
+ // resolves (T042b).
911
+ contextFor: (moduleId) => composedModules.contextFor(moduleId),
912
+ resolvedModules: resolvedRegistry,
913
+ // The assembly is one function's, and what a composition supplies is the
914
+ // three things only a composition holds: its own resolved routing table and
915
+ // the two gated ports the envelope's callbacks read. The twenty lines that
916
+ // used to stand in each root stood character-for-character in both, which
917
+ // is the drift `harness-parity.test.ts` exists for and which issue #234
918
+ // already paid for once.
919
+ errorEnvelope: composeErrorEnvelopeOptions({
920
+ errorTranslationTargets: errorTranslation.targets,
921
+ adminUserReadPort: () => reads().adminUserReadPort,
922
+ translate: () => reads().adminI18nService,
923
+ }),
924
+ dispose: async () => {
925
+ // Feature 062 — drain the webhook delivery pipeline before dropping the
926
+ // Redis connections (graceful shutdown). Every part of that is the
927
+ // container's job since T143a: `ctx.subscribe` unsubscribes with the
928
+ // module, the queue registration carries its own disposer, and the
929
+ // delivery worker is `webhooks`' own. Disposing the container runs those
930
+ // disposers — for every module, not only one — and it runs *before* the
931
+ // Redis sockets go, which is the ordering the drain needs.
932
+ await container.dispose();
933
+ redis.disconnect();
934
+ redisSubscriber.disconnect();
935
+ await ormLifecycle.close();
936
+ },
937
+ };
938
+ }
939
+ //# sourceMappingURL=compose-app.js.map