@starci/hfs 4.3.0 → 4.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (538) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +1 -1
  3. package/db/migrate.mjs +361 -0
  4. package/db/post-cutover.mjs +136 -0
  5. package/emit/contracts.mjs +2 -2
  6. package/emit/db-types.mjs +12 -3
  7. package/lint/run.mjs +3 -3
  8. package/package.json +4 -1
  9. package/release/gate.mjs +298 -0
  10. package/release/index.mjs +103 -0
  11. package/release/push.mjs +110 -0
  12. package/report/sonar.mjs +1 -1
  13. package/runtime/config.example.yaml +7 -6
  14. package/runtime/engine/config.mjs +10 -18
  15. package/runtime/engine/removed-vocabulary.mjs +0 -2
  16. package/runtime/knowledge/hfs/canon-pins.yaml +11 -11
  17. package/runtime/knowledge/hfs/fe-stack.yaml +22 -1
  18. package/runtime/knowledge/hfs/rules.yaml +2855 -163
  19. package/runtime/knowledge/hfs/slots.yaml +333 -62
  20. package/runtime/knowledge/patterns/be/api.yaml +32 -5
  21. package/runtime/knowledge/patterns/be/cli.yaml +14 -4
  22. package/runtime/knowledge/patterns/be/event-bus.yaml +3 -3
  23. package/runtime/knowledge/patterns/be/jobs.yaml +20 -2
  24. package/runtime/knowledge/patterns/be/projections.yaml +4 -2
  25. package/runtime/knowledge/patterns/be/queues.yaml +11 -3
  26. package/runtime/knowledge/patterns/be/reactors.yaml +20 -1
  27. package/runtime/knowledge/patterns/be/realtime.yaml +25 -3
  28. package/runtime/knowledge/patterns/be/saga.yaml +20 -3
  29. package/runtime/knowledge/patterns/be/webhooks.yaml +23 -4
  30. package/runtime/knowledge/patterns/fe/folder.yaml +1 -0
  31. package/runtime/knowledge/sonar-gate.yaml +1 -1
  32. package/runtime/modules/kernel/failure-codes.yaml +3091 -43
  33. package/runtime/modules/kernel/removed-vocabulary.yaml +30 -0
  34. package/runtime/modules/models/runtimes.yaml +5 -7
  35. package/runtime/modules/schemas/application-stacks.schema.yaml +663 -0
  36. package/runtime/packages/cli/src/catalog.generated.mjs +13769 -0
  37. package/runtime/packages/cli/src/validate-args.mjs +213 -0
  38. package/runtime/scripts/api/git/add.mjs +5 -0
  39. package/runtime/scripts/api/git/init.mjs +7 -0
  40. package/runtime/scripts/api/git/lib.mjs +4 -1
  41. package/runtime/scripts/api/git/tag.mjs +5 -0
  42. package/runtime/scripts/api/node/lib.mjs +20 -0
  43. package/runtime/scripts/api/node/run-node.mjs +6 -0
  44. package/runtime/scripts/api/sops/lib.mjs +42 -1
  45. package/runtime/scripts/api/sops/selected-age-recipient.mjs +7 -0
  46. package/runtime/scripts/api/supabase/database-dump.mjs +5 -0
  47. package/runtime/scripts/api/supabase/database-query.mjs +5 -0
  48. package/runtime/scripts/api/supabase/lib.mjs +44 -0
  49. package/runtime/scripts/api/supabase/migration-repair.mjs +5 -0
  50. package/runtime/scripts/hfs/app-wiring.mjs +201 -0
  51. package/runtime/scripts/hfs/architecture/backend-app-files.mjs +1 -8
  52. package/runtime/scripts/hfs/architecture/backend.mjs +2 -7
  53. package/runtime/scripts/hfs/architecture/client-reaches-server.mjs +6 -3
  54. package/runtime/scripts/hfs/architecture/config.mjs +1 -1
  55. package/runtime/scripts/hfs/architecture/dead-exports-bindings.mjs +149 -0
  56. package/runtime/scripts/hfs/architecture/dead-exports.mjs +9 -41
  57. package/runtime/scripts/hfs/architecture/default-deny.mjs +8 -6
  58. package/runtime/scripts/hfs/architecture/frontend-world.mjs +1 -1
  59. package/runtime/scripts/hfs/architecture/function-spec-providers.mjs +153 -0
  60. package/runtime/scripts/hfs/architecture/hfs.mjs +3 -3
  61. package/runtime/scripts/hfs/architecture/index.mjs +1 -1
  62. package/runtime/scripts/hfs/architecture/module-per-transport.mjs +28 -13
  63. package/runtime/scripts/hfs/architecture/next-data-inference.mjs +176 -0
  64. package/runtime/scripts/hfs/architecture/next-data-symbols.mjs +26 -0
  65. package/runtime/scripts/hfs/architecture/next-data.mjs +31 -23
  66. package/runtime/scripts/hfs/architecture/reachability.mjs +14 -0
  67. package/runtime/scripts/hfs/architecture/register-once.mjs +2 -2
  68. package/runtime/scripts/hfs/architecture/source-names.mjs +48 -3
  69. package/runtime/scripts/hfs/architecture/supabase-ast.mjs +211 -11
  70. package/runtime/scripts/hfs/architecture/supabase-be.mjs +1 -1
  71. package/runtime/scripts/hfs/architecture/supabase.mjs +59 -21
  72. package/runtime/scripts/hfs/architecture/surface.mjs +2 -1
  73. package/runtime/scripts/hfs/architecture/tiers.mjs +4 -4
  74. package/runtime/scripts/hfs/architecture/unit-spec-providers.mjs +8 -2
  75. package/runtime/scripts/hfs/architecture.mjs +1 -1
  76. package/runtime/scripts/hfs/check-results.mjs +28 -0
  77. package/runtime/scripts/hfs/check.mjs +46 -47
  78. package/runtime/scripts/hfs/coverage-from.mjs +70 -0
  79. package/runtime/scripts/hfs/coverage-scope.mjs +1 -1
  80. package/runtime/scripts/hfs/db-baseline-verb.mjs +276 -0
  81. package/runtime/scripts/hfs/db-plan-verb.mjs +254 -0
  82. package/runtime/scripts/hfs/db-restamp-verb.mjs +60 -0
  83. package/runtime/scripts/hfs/declaration-shape.mjs +39 -3
  84. package/runtime/scripts/hfs/doc-commands.mjs +367 -0
  85. package/runtime/scripts/hfs/edition-slots.mjs +2 -2
  86. package/runtime/scripts/hfs/example-secrets.mjs +158 -0
  87. package/runtime/scripts/hfs/manifest-shape.mjs +69 -9
  88. package/runtime/scripts/hfs/param-names.mjs +1 -1
  89. package/runtime/scripts/hfs/refusal-codes.mjs +6 -0
  90. package/runtime/scripts/hfs/rule-catalog.mjs +158 -11
  91. package/runtime/scripts/hfs/rule-params-shape.mjs +22 -10
  92. package/runtime/scripts/hfs/rules/a15-findings.mjs +88 -0
  93. package/runtime/scripts/hfs/rules/app-env-required.mjs +20 -0
  94. package/runtime/scripts/hfs/rules/app-root.mjs +2 -2
  95. package/runtime/scripts/hfs/rules/assets.mjs +79 -0
  96. package/runtime/scripts/hfs/rules/boot-proof.mjs +16 -0
  97. package/runtime/scripts/hfs/rules/canon-copy-drift.mjs +59 -0
  98. package/runtime/scripts/hfs/rules/cli.mjs +1 -1
  99. package/runtime/scripts/hfs/rules/contract-compat.mjs +1 -1
  100. package/runtime/scripts/hfs/rules/contract.mjs +67 -6
  101. package/runtime/scripts/hfs/rules/coverage-below.mjs +230 -0
  102. package/runtime/scripts/hfs/rules/database-access.mjs +343 -0
  103. package/runtime/scripts/hfs/rules/database-baseline.mjs +142 -0
  104. package/runtime/scripts/hfs/rules/database-config.mjs +250 -2
  105. package/runtime/scripts/hfs/rules/database-constants.mjs +9 -0
  106. package/runtime/scripts/hfs/rules/database-migrations.mjs +286 -7
  107. package/runtime/scripts/hfs/rules/database-plpgsql.mjs +119 -9
  108. package/runtime/scripts/hfs/rules/database-queue-sources.mjs +176 -0
  109. package/runtime/scripts/hfs/rules/database-queues.mjs +361 -0
  110. package/runtime/scripts/hfs/rules/database-sql.mjs +91 -9
  111. package/runtime/scripts/hfs/rules/database.mjs +9 -0
  112. package/runtime/scripts/hfs/rules/deploy-scan.mjs +192 -0
  113. package/runtime/scripts/hfs/rules/deploy-workflow.mjs +219 -0
  114. package/runtime/scripts/hfs/rules/doc-fresh.mjs +286 -0
  115. package/runtime/scripts/hfs/rules/docker-health.mjs +249 -0
  116. package/runtime/scripts/hfs/rules/docker.mjs +24 -7
  117. package/runtime/scripts/hfs/rules/edition.mjs +9 -8
  118. package/runtime/scripts/hfs/rules/env-parity.mjs +373 -0
  119. package/runtime/scripts/hfs/rules/env-value-shape.mjs +113 -0
  120. package/runtime/scripts/hfs/rules/event-bus.mjs +3 -2
  121. package/runtime/scripts/hfs/rules/event-tables.mjs +100 -0
  122. package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +115 -15
  123. package/runtime/scripts/hfs/rules/fe-stack.mjs +57 -0
  124. package/runtime/scripts/hfs/rules/feature-files.mjs +28 -0
  125. package/runtime/scripts/hfs/rules/frontend-tree.mjs +54 -35
  126. package/runtime/scripts/hfs/rules/integration-specs.mjs +3 -2
  127. package/runtime/scripts/hfs/rules/lexicon.mjs +62 -0
  128. package/runtime/scripts/hfs/rules/lite-proof-lane.mjs +89 -0
  129. package/runtime/scripts/hfs/rules/monorepo.mjs +14 -1
  130. package/runtime/scripts/hfs/rules/pipeline.mjs +8 -1
  131. package/runtime/scripts/hfs/rules/release-provenance.mjs +211 -0
  132. package/runtime/scripts/hfs/rules/saga-delivery.mjs +66 -0
  133. package/runtime/scripts/hfs/rules/saga.mjs +8 -16
  134. package/runtime/scripts/hfs/rules/script-hygiene.mjs +151 -0
  135. package/runtime/scripts/hfs/rules/secret-custody-only.mjs +65 -0
  136. package/runtime/scripts/hfs/rules/secrets.mjs +13 -0
  137. package/runtime/scripts/hfs/rules/services.mjs +4 -4
  138. package/runtime/scripts/hfs/rules/stack-tooling.mjs +93 -0
  139. package/runtime/scripts/hfs/rules/stacks-deploy.mjs +76 -0
  140. package/runtime/scripts/hfs/rules/stacks-ingress.mjs +87 -0
  141. package/runtime/scripts/hfs/rules/stacks-lite-backing.mjs +111 -0
  142. package/runtime/scripts/hfs/rules/stacks-release.mjs +366 -0
  143. package/runtime/scripts/hfs/rules/stacks-runtime.mjs +41 -1
  144. package/runtime/scripts/hfs/rules/stacks-swarm.mjs +417 -0
  145. package/runtime/scripts/hfs/rules/supabase-secrets.mjs +2 -2
  146. package/runtime/scripts/hfs/rules/supply-chain.mjs +167 -0
  147. package/runtime/scripts/hfs/rules/unused-symbol-flow.mjs +101 -0
  148. package/runtime/scripts/hfs/rules/unused-symbol-ledger.mjs +77 -0
  149. package/runtime/scripts/hfs/rules/unused-symbol-translators.mjs +165 -0
  150. package/runtime/scripts/hfs/rules/unused-symbol-values.mjs +103 -0
  151. package/runtime/scripts/hfs/rules/unused-symbol.mjs +320 -0
  152. package/runtime/scripts/hfs/runtime-rules/source-ast.mjs +185 -0
  153. package/runtime/scripts/hfs/runtime-rules/workflow-source.mjs +19 -0
  154. package/runtime/scripts/hfs/sealed-members.mjs +101 -0
  155. package/runtime/scripts/hfs/secret-bootstrap-crypto.mjs +200 -0
  156. package/runtime/scripts/hfs/secret-edit.mjs +170 -0
  157. package/runtime/scripts/hfs/secret-init.mjs +127 -19
  158. package/runtime/scripts/hfs/secret-sops.mjs +38 -6
  159. package/runtime/scripts/hfs/secret-store.mjs +56 -54
  160. package/runtime/scripts/hfs/secret.mjs +34 -5
  161. package/runtime/scripts/hfs/slot-imports.mjs +18 -5
  162. package/runtime/scripts/hfs/slots.mjs +3 -2
  163. package/runtime/scripts/hfs/stack-config-kit.mjs +34 -0
  164. package/runtime/scripts/hfs/stack-deploy-config.mjs +313 -0
  165. package/runtime/scripts/hfs/stack-ingress-config.mjs +237 -0
  166. package/runtime/scripts/hfs/stacks-gate.mjs +414 -0
  167. package/runtime/scripts/hfs/starcistacks-runtime.mjs +61 -0
  168. package/runtime/scripts/hfs/typescript-programs.mjs +0 -8
  169. package/runtime/scripts/lib/command-tokens.mjs +126 -0
  170. package/runtime/scripts/lib/compose-values.mjs +11 -0
  171. package/runtime/scripts/lib/deployment-findings.mjs +7 -0
  172. package/runtime/scripts/lib/env.mjs +2 -2
  173. package/runtime/scripts/lib/git.mjs +1 -1
  174. package/runtime/scripts/lib/i18n.mjs +0 -2
  175. package/runtime/scripts/lib/json-clone.mjs +61 -0
  176. package/runtime/scripts/lib/language.mjs +1 -1
  177. package/runtime/scripts/lib/list.mjs +4 -0
  178. package/runtime/scripts/lib/roots.mjs +2 -4
  179. package/runtime/scripts/lib/runtime-example.mjs +13 -0
  180. package/runtime/scripts/lib/secret-patterns.mjs +60 -5
  181. package/runtime/scripts/lib/sql-ast.mjs +32 -0
  182. package/runtime/scripts/lib/stack-services.mjs +1 -1
  183. package/runtime/scripts/lib/swarm-stack.mjs +5 -18
  184. package/runtime/scripts/lib/trim-end.mjs +8 -0
  185. package/runtime/scripts/lib/ts-analysis.mjs +5 -2
  186. package/runtime/scripts/lib/ts-ast.mjs +27 -2
  187. package/runtime/scripts/lib/workflow-events.mjs +8 -0
  188. package/scaffold/add-app.mjs +77 -59
  189. package/scaffold/add-cli-lite.mjs +14 -6
  190. package/scaffold/add-compose.mjs +79 -0
  191. package/scaffold/add-database-lite.mjs +14 -0
  192. package/scaffold/add-fe-overlay.mjs +1 -0
  193. package/scaffold/add-fe-page.mjs +1 -0
  194. package/scaffold/add-inbox-lite.mjs +74 -42
  195. package/scaffold/add-table.mjs +110 -87
  196. package/scaffold/add.mjs +159 -44
  197. package/scaffold/app.mjs +124 -39
  198. package/scaffold/edition-gate.mjs +3 -3
  199. package/scaffold/lite-exports.mjs +2 -1
  200. package/scaffold/service.mjs +2 -2
  201. package/scaffold/supabase-ports.mjs +1 -1
  202. package/src/main.mjs +229 -116
  203. package/stack/age-install.mjs +37 -0
  204. package/stack/backup.mjs +100 -0
  205. package/stack/build-args.mjs +42 -0
  206. package/stack/build.mjs +173 -0
  207. package/stack/cli.mjs +130 -0
  208. package/stack/config.mjs +57 -0
  209. package/stack/context.mjs +57 -0
  210. package/stack/converge.mjs +107 -0
  211. package/stack/deploy.mjs +301 -0
  212. package/stack/digest.mjs +16 -0
  213. package/stack/docker-transport.mjs +53 -0
  214. package/stack/edge-alias.mjs +118 -0
  215. package/stack/errors.mjs +21 -0
  216. package/stack/image-scan.mjs +152 -0
  217. package/stack/ingress-create.mjs +114 -0
  218. package/stack/ingress-publish.mjs +273 -0
  219. package/stack/ingress.mjs +706 -0
  220. package/stack/jobs.mjs +51 -0
  221. package/stack/live-restore.mjs +177 -0
  222. package/stack/prepare.mjs +266 -0
  223. package/stack/private-file.mjs +22 -0
  224. package/stack/provision.mjs +90 -0
  225. package/stack/prune.mjs +46 -0
  226. package/stack/release-store.mjs +87 -0
  227. package/stack/remote.mjs +205 -0
  228. package/stack/render.mjs +149 -0
  229. package/stack/retire.mjs +47 -0
  230. package/stack/sealed.mjs +149 -0
  231. package/stack/task.mjs +42 -0
  232. package/stack/verify.mjs +99 -0
  233. package/sync/ci-commands.mjs +13 -0
  234. package/sync/format.mjs +1 -1
  235. package/sync/hygiene.mjs +1 -1
  236. package/sync/index.mjs +110 -54
  237. package/sync/stack-images.mjs +127 -0
  238. package/templates/app/ci-workflows/github/workflows/ci.yml +5 -1
  239. package/templates/app/ci-workflows/github/workflows/images.yml +15 -3
  240. package/templates/app/ci-workflows/github/workflows/stack-deploy.yml +148 -0
  241. package/templates/app/ci-workflows-lite/github/workflows/ci.yml +7 -3
  242. package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +38 -6
  243. package/templates/app/ci-workflows-lite/github/workflows/images.yml +14 -2
  244. package/templates/app/ci-workflows-lite/github/workflows/stack-deploy.yml +148 -0
  245. package/templates/app/codegen-graphql.mjs.partial +13 -2
  246. package/templates/app/codegen-lite/scripts/codegen.mjs +6 -1
  247. package/templates/app/codegen-prelude.mjs.partial +8 -0
  248. package/templates/app/gitignore +3 -0
  249. package/templates/app/gitignore-lite +3 -0
  250. package/templates/app/package-scripts/package.json +1 -0
  251. package/templates/app/package-scripts/supabase.json +7 -0
  252. package/templates/app/package-scripts-lite/package.json +1 -7
  253. package/templates/app/skeleton/.editorconfig +1 -0
  254. package/templates/app/skeleton/.gitattributes +7 -1
  255. package/templates/app/skeleton/.github/dependabot.yml +17 -0
  256. package/templates/app/skeleton/.nvmrc +1 -1
  257. package/templates/app/skeleton/.starcistacks/application-stacks.yaml +134 -1
  258. package/templates/app/skeleton/.starcistacks/dev/README.md +16 -0
  259. package/templates/app/skeleton/.starcistacks/dev/environment.json +5 -0
  260. package/templates/app/skeleton/.starcistacks/dev/infra/compose/stack.yaml +71 -0
  261. package/templates/app/skeleton/.starcistacks/dev/runtime/env/KEYS.md +14 -0
  262. package/templates/app/skeleton/.starcistacks/production/README.md +37 -0
  263. package/templates/app/skeleton/.starcistacks/production/environment.json +5 -0
  264. package/templates/app/skeleton/.starcistacks/production/infra/swarm/Caddyfile +15 -0
  265. package/templates/app/skeleton/.starcistacks/production/infra/swarm/owner-actions.md +11 -0
  266. package/templates/app/skeleton/.starcistacks/production/infra/swarm/recovery/restore-proof.md +7 -0
  267. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/current.yaml +6 -0
  268. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/images.lock.yaml +9 -0
  269. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/previous.yaml +6 -0
  270. package/templates/app/skeleton/.starcistacks/production/infra/swarm/stack.yaml +142 -0
  271. package/templates/app/skeleton/.starcistacks/production/runtime/env/KEYS.md +14 -0
  272. package/templates/app/skeleton/README.md +6 -6
  273. package/templates/app/skeleton/scripts/codegen.mjs +1 -2
  274. package/templates/app/skeleton-lite/.editorconfig +16 -0
  275. package/templates/app/skeleton-lite/.gitattributes +8 -0
  276. package/templates/app/skeleton-lite/.github/dependabot.yml +17 -0
  277. package/templates/app/skeleton-lite/.nvmrc +1 -0
  278. package/templates/app/skeleton-lite/.sops.yaml +3 -2
  279. package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +178 -1
  280. package/templates/app/skeleton-lite/.starcistacks/dev/README.md +20 -0
  281. package/templates/app/skeleton-lite/.starcistacks/dev/environment.json +2 -1
  282. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/Caddyfile +16 -0
  283. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/owner-actions.md +11 -0
  284. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/recovery/restore-proof.md +7 -0
  285. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/current.yaml +6 -0
  286. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/images.lock.yaml +8 -0
  287. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/previous.yaml +6 -0
  288. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/stack.yaml +120 -0
  289. package/templates/app/skeleton-lite/.starcistacks/dev/runtime/env/KEYS.md +18 -0
  290. package/templates/app/skeleton-lite/.starcistacks/production/README.md +38 -0
  291. package/templates/app/skeleton-lite/.starcistacks/production/environment.json +6 -0
  292. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/Caddyfile +11 -0
  293. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/owner-actions.md +11 -0
  294. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/recovery/restore-proof.md +7 -0
  295. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/current.yaml +6 -0
  296. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/images.lock.yaml +8 -0
  297. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/previous.yaml +6 -0
  298. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/stack.yaml +121 -0
  299. package/templates/app/skeleton-lite/.starcistacks/production/runtime/env/KEYS.md +21 -0
  300. package/templates/app/skeleton-lite/.starciwork/brand/index.yaml +12 -0
  301. package/templates/app/skeleton-lite/README.md +5 -3
  302. package/templates/app/skeleton-lite/supabase/config.toml +8 -1
  303. package/templates/app/skeleton-lite/supabase/migrations/__timestamp___baseline.sql +15 -6
  304. package/templates/app/upgrade-full/.starcistacks/dev/README.md +13 -7
  305. package/templates/be/image/worker/Dockerfile +1 -1
  306. package/templates/be/inbox/database-client.spec.ts.tpl +17 -18
  307. package/templates/be/inbox/database-client.ts.tpl +12 -11
  308. package/templates/be/inbox/delivery-recorded.event.ts.tpl +36 -0
  309. package/templates/be/inbox/event-index.ts.tpl +1 -0
  310. package/templates/be/inbox/events.json.tpl +10 -0
  311. package/templates/be/inbox/migration.sql.tpl +1 -0
  312. package/templates/be/inbox/platform/event-bus/event-bus.contracts.ts.tpl +42 -0
  313. package/templates/be/inbox/platform/event-bus/event-bus.decorators.ts.tpl +9 -0
  314. package/templates/be/inbox/platform/event-bus/event-bus.module-definition.ts.tpl +6 -0
  315. package/templates/be/inbox/platform/event-bus/event-bus.module.ts.tpl +19 -0
  316. package/templates/be/inbox/platform/event-bus/event-bus.options.ts.tpl +2 -0
  317. package/templates/be/inbox/platform/event-bus/event-bus.port.ts.tpl +16 -0
  318. package/templates/be/inbox/platform/event-bus/event-bus.service.spec.ts.tpl +45 -0
  319. package/templates/be/inbox/platform/event-bus/event-bus.service.ts.tpl +15 -0
  320. package/templates/be/inbox/platform/event-bus/index.ts.tpl +5 -0
  321. package/templates/be/inbox/platform/event-bus/persistence/event-bus.sql.ts.tpl +5 -0
  322. package/templates/be/inbox/platform/inbox/inbox.decorators.ts.tpl +9 -0
  323. package/templates/be/inbox/platform/inbox/inbox.module-definition.ts.tpl +6 -0
  324. package/templates/be/inbox/platform/inbox/inbox.module.ts.tpl +19 -0
  325. package/templates/be/inbox/platform/inbox/inbox.options.ts.tpl +2 -0
  326. package/templates/be/inbox/platform/inbox/inbox.port.ts.tpl +10 -0
  327. package/templates/be/inbox/platform/inbox/inbox.service.spec.ts.tpl +41 -0
  328. package/templates/be/inbox/platform/inbox/inbox.service.ts.tpl +19 -0
  329. package/templates/be/inbox/platform/inbox/index.ts.tpl +3 -0
  330. package/templates/be/inbox/platform/inbox/persistence/inbox.sql.ts.tpl +7 -0
  331. package/templates/be/inbox/platform/migration.sql.tpl +48 -0
  332. package/templates/be/inbox/service.spec.ts.tpl +42 -9
  333. package/templates/be/inbox/service.ts.tpl +23 -8
  334. package/templates/be/inbox/webhook-door.spec.ts.tpl +1 -1
  335. package/templates/be/inbox/webhook-door.ts.tpl +2 -2
  336. package/templates/be/patterns/api/feature.module-definition.ts.tpl +6 -0
  337. package/templates/be/patterns/api/feature.module.ts.tpl +2 -1
  338. package/templates/be/patterns/api/feature.options.ts.tpl +2 -0
  339. package/templates/be/patterns/api/graphql.module-definition.ts.tpl +6 -0
  340. package/templates/be/patterns/api/graphql.module.ts.tpl +3 -2
  341. package/templates/be/patterns/api/graphql.options.ts.tpl +2 -0
  342. package/templates/be/patterns/cli/group.module-definition.ts.tpl +6 -0
  343. package/templates/be/patterns/cli/group.module.ts.tpl +2 -1
  344. package/templates/be/patterns/cli/group.options.ts.tpl +2 -0
  345. package/templates/be/patterns/event-bus/platform/errors/event-bus.error.ts.tpl +0 -3
  346. package/templates/be/patterns/event-bus/platform/messages/event-bus.messages.ts.tpl +0 -2
  347. package/templates/be/patterns/jobs/job.module-definition.ts.tpl +6 -0
  348. package/templates/be/patterns/jobs/job.module.ts.tpl +2 -1
  349. package/templates/be/patterns/jobs/job.options.ts.tpl +2 -0
  350. package/templates/be/patterns/jobs/job.queue.module-definition.ts.tpl +6 -0
  351. package/templates/be/patterns/jobs/job.queue.module.ts.tpl +6 -3
  352. package/templates/be/patterns/jobs/job.queue.options.ts.tpl +2 -0
  353. package/templates/be/patterns/jobs/platform/fenced.processor.spec.ts.tpl +3 -1
  354. package/templates/be/patterns/outbox/platform/outbox-relay.policy.spec.ts.tpl +25 -9
  355. package/templates/be/patterns/queues/platform/queue.config.ts.tpl +1 -1
  356. package/templates/be/patterns/queues/platform/queue.index.ts.tpl +1 -1
  357. package/templates/be/patterns/queues/platform/queue.module-definition.ts.tpl +2 -2
  358. package/templates/be/patterns/queues/platform/queue.module.ts.tpl +11 -0
  359. package/templates/be/patterns/queues/platform/queue.options.ts.tpl +10 -0
  360. package/templates/be/patterns/queues/queue.module-definition.ts.tpl +6 -0
  361. package/templates/be/patterns/queues/queue.module.ts.tpl +2 -1
  362. package/templates/be/patterns/queues/queue.options.ts.tpl +2 -0
  363. package/templates/be/patterns/reactors/message.module-definition.ts.tpl +6 -0
  364. package/templates/be/patterns/reactors/message.module.ts.tpl +6 -3
  365. package/templates/be/patterns/reactors/message.options.ts.tpl +2 -0
  366. package/templates/be/patterns/reactors/reactor.module-definition.ts.tpl +6 -0
  367. package/templates/be/patterns/reactors/reactor.module.ts.tpl +2 -1
  368. package/templates/be/patterns/reactors/reactor.options.ts.tpl +2 -0
  369. package/templates/be/patterns/realtime/channel.gateway.spec.ts.tpl +188 -0
  370. package/templates/be/patterns/realtime/channel.gateway.ts.tpl +22 -0
  371. package/templates/be/patterns/realtime/channel.graphql.module-definition.ts.tpl +6 -0
  372. package/templates/be/patterns/realtime/channel.graphql.module.ts.tpl +2 -1
  373. package/templates/be/patterns/realtime/channel.graphql.options.ts.tpl +2 -0
  374. package/templates/be/patterns/realtime/channel.websocket.module-definition.ts.tpl +6 -0
  375. package/templates/be/patterns/realtime/channel.websocket.module.ts.tpl +110 -0
  376. package/templates/be/patterns/realtime/channel.websocket.options.ts.tpl +7 -0
  377. package/templates/be/patterns/saga/saga.message.module-definition.ts.tpl +6 -0
  378. package/templates/be/patterns/saga/saga.message.module.ts.tpl +6 -3
  379. package/templates/be/patterns/saga/saga.message.options.ts.tpl +2 -0
  380. package/templates/be/patterns/saga/saga.module-definition.ts.tpl +6 -0
  381. package/templates/be/patterns/saga/saga.module.ts.tpl +2 -1
  382. package/templates/be/patterns/saga/saga.options.ts.tpl +2 -0
  383. package/templates/be/patterns/webhooks/webhook.http.module-definition.ts.tpl +6 -0
  384. package/templates/be/patterns/webhooks/webhook.http.module.ts.tpl +2 -1
  385. package/templates/be/patterns/webhooks/webhook.http.options.ts.tpl +2 -0
  386. package/templates/be/platform/graphql/localize-errors.mapper.spec.ts +80 -26
  387. package/templates/be/platform/graphql/localize-errors.mapper.ts +2 -5
  388. package/templates/be/skeleton/apps/__app__/src/app.module.ts +11 -9
  389. package/templates/be/skeleton/apps/__app__/src/compose/api.ts +4 -0
  390. package/templates/be/skeleton/apps/__app__/src/compose/domain.ts +11 -0
  391. package/templates/be/skeleton/apps/__app__/src/compose/platform.ts +2 -0
  392. package/templates/be/skeleton/apps/__app__/src/compose/system.ts +5 -0
  393. package/templates/be/skeleton/apps/__app__/src/compose/webhooks.ts +4 -0
  394. package/templates/be/skeleton/apps/__app__/src/main.ts +15 -1
  395. package/templates/be/skeleton/apps/cli/src/app.module.ts +3 -13
  396. package/templates/be/skeleton/apps/cli/src/cli.options.ts +6 -14
  397. package/templates/be/skeleton/apps/cli/src/compose/cli.ts +5 -0
  398. package/templates/be/skeleton/apps/cli/src/compose/platform.ts +24 -0
  399. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.contracts.ts +2 -0
  400. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.handler.ts +22 -0
  401. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.query.ts +11 -0
  402. package/templates/be/skeleton/src/features/api/system-health/system-health.module-definition.ts +6 -0
  403. package/templates/be/skeleton/src/features/api/system-health/system-health.module.ts +5 -3
  404. package/templates/be/skeleton/src/features/api/system-health/system-health.options.ts +2 -0
  405. package/templates/be/skeleton/src/features/api/system-health/transport/http/ready.controller.ts +19 -0
  406. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module-definition.ts +6 -0
  407. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module.ts +8 -3
  408. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.options.ts +2 -0
  409. package/templates/be/skeleton/src/features/cli/cli.module-definition.ts +6 -0
  410. package/templates/be/skeleton/src/features/cli/cli.module.ts +3 -2
  411. package/templates/be/skeleton/src/features/cli/cli.options.ts +2 -0
  412. package/templates/be/skeleton/src/features/cli/migrate/migrate.module-definition.ts +6 -0
  413. package/templates/be/skeleton/src/features/cli/migrate/migrate.module.ts +2 -1
  414. package/templates/be/skeleton/src/features/cli/migrate/migrate.options.ts +2 -0
  415. package/templates/be/skeleton/src/features/cli/seed/seed.module-definition.ts +6 -0
  416. package/templates/be/skeleton/src/features/cli/seed/seed.module.ts +2 -1
  417. package/templates/be/skeleton/src/features/cli/seed/seed.options.ts +2 -0
  418. package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.spec.ts +5 -6
  419. package/templates/be/skeleton/src/modules/domain/identity/admission.policy.spec.ts +56 -4
  420. package/templates/be/skeleton/src/modules/domain/identity/admission.policy.ts +36 -5
  421. package/templates/be/skeleton/src/modules/domain/identity/auth.guard.spec.ts +39 -8
  422. package/templates/be/skeleton/src/modules/domain/identity/auth.guard.ts +14 -8
  423. package/templates/be/skeleton/src/modules/domain/identity/credential.contracts.ts +26 -0
  424. package/templates/be/skeleton/src/modules/domain/identity/credential.guard.spec.ts +119 -0
  425. package/templates/be/skeleton/src/modules/domain/identity/credential.guard.ts +43 -0
  426. package/templates/be/skeleton/src/modules/domain/identity/identity.contracts.ts +16 -0
  427. package/templates/be/skeleton/src/modules/domain/identity/identity.decorators.ts +18 -1
  428. package/templates/be/skeleton/src/modules/domain/identity/identity.module.ts +22 -4
  429. package/templates/be/skeleton/src/modules/domain/identity/identity.options.ts +8 -2
  430. package/templates/be/skeleton/src/modules/domain/identity/index.ts +1 -0
  431. package/templates/be/skeleton/src/modules/platform/database/connection-source.client.spec.ts +11 -4
  432. package/templates/be/skeleton/src/modules/platform/database/database-probe.service.spec.ts +32 -0
  433. package/templates/be/skeleton/src/modules/platform/database/database-probe.service.ts +14 -0
  434. package/templates/be/skeleton/src/modules/platform/database/database.module.ts +7 -1
  435. package/templates/be/skeleton/src/modules/platform/database/index.ts +2 -0
  436. package/templates/be/skeleton/src/modules/platform/database/primary.decorators.ts +8 -0
  437. package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.spec.ts +25 -6
  438. package/templates/be/skeleton/src/modules/platform/errors/errors.filter.spec.ts +16 -6
  439. package/templates/be/skeleton/src/modules/platform/http-security/edge-security.service.spec.ts +130 -0
  440. package/templates/be/skeleton/src/modules/platform/http-security/edge-security.service.ts +58 -0
  441. package/templates/be/skeleton/src/modules/platform/http-security/errors/http-security.error.ts +3 -0
  442. package/templates/be/skeleton/src/modules/platform/http-security/execution-request.mapper.spec.ts +16 -4
  443. package/templates/be/skeleton/src/modules/platform/http-security/http-security.config.ts +16 -10
  444. package/templates/be/skeleton/src/modules/platform/http-security/http-security.module.ts +3 -1
  445. package/templates/be/skeleton/src/modules/platform/http-security/http-security.options.ts +2 -0
  446. package/templates/be/skeleton/src/modules/platform/http-security/index.ts +5 -0
  447. package/templates/be/skeleton/src/modules/platform/http-security/messages/http-security.messages.ts +12 -5
  448. package/templates/be/skeleton/src/modules/platform/http-security/rate-limit.guard.spec.ts +13 -8
  449. package/templates/be/skeleton/src/modules/platform/http-security/readiness.contracts.ts +5 -0
  450. package/templates/be/skeleton/src/modules/platform/http-security/readiness.decorators.ts +7 -0
  451. package/templates/be/skeleton/src/modules/platform/http-security/readiness.service.spec.ts +86 -0
  452. package/templates/be/skeleton/src/modules/platform/http-security/readiness.service.ts +39 -0
  453. package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.spec.ts +139 -131
  454. package/templates/be/skeleton/src/modules/platform/i18n/index.ts +1 -1
  455. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.spec.ts +91 -67
  456. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.ts +5 -4
  457. package/templates/be/skeleton/src/modules/platform/logging/logging.log-events.ts +0 -2
  458. package/templates/be/skeleton/src/modules/platform/primitives/outcome.mapper.spec.ts +20 -6
  459. package/templates/be/skeleton/src/modules/platform/primitives/sequence.policy.spec.ts +16 -4
  460. package/templates/be/skeleton/src/modules/platform/retry/index.ts +3 -0
  461. package/templates/be/skeleton/src/modules/platform/retry/retry.decorators.ts +9 -0
  462. package/templates/be/skeleton/src/modules/platform/retry/retry.module-definition.ts +7 -0
  463. package/templates/be/skeleton/src/modules/platform/retry/retry.module.ts +19 -0
  464. package/templates/be/skeleton/src/modules/platform/retry/retry.options.ts +2 -0
  465. package/templates/be/skeleton/src/modules/platform/retry/retry.port.ts +11 -0
  466. package/templates/be/skeleton/src/modules/platform/retry/system-timer.service.spec.ts +36 -0
  467. package/templates/be/skeleton/src/modules/platform/retry/system-timer.service.ts +10 -0
  468. package/templates/be/skeleton/src/tests/contract/http-security/http-security.contract-spec.ts +54 -0
  469. package/templates/be/skeleton-lite/apps/api/src/app.module.ts +14 -18
  470. package/templates/be/skeleton-lite/apps/api/src/compose/api.ts +4 -0
  471. package/templates/be/skeleton-lite/apps/api/src/compose/domain.ts +10 -0
  472. package/templates/be/skeleton-lite/apps/api/src/compose/integrations.ts +16 -0
  473. package/templates/be/skeleton-lite/apps/api/src/compose/platform.ts +2 -0
  474. package/templates/be/skeleton-lite/apps/api/src/compose/system.ts +5 -0
  475. package/templates/be/skeleton-lite/apps/api/src/compose/webhooks.ts +4 -0
  476. package/templates/be/skeleton-lite/apps/api/src/main.ts +2 -3
  477. package/templates/be/skeleton-lite/apps/cli/src/compose/platform.ts +12 -0
  478. package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.spec.ts +71 -5
  479. package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.ts +29 -2
  480. package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.spec.ts +68 -15
  481. package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.ts +14 -9
  482. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.contracts.ts +9 -2
  483. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.decorators.ts +16 -1
  484. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.module.ts +19 -4
  485. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.options.ts +5 -1
  486. package/templates/be/skeleton-lite/src/modules/domain/identity/index.ts +2 -1
  487. package/templates/be/skeleton-lite/src/modules/integrations/supabase/errors/supabase.error.ts +0 -3
  488. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.client.spec.ts +17 -5
  489. package/templates/be/skeleton-lite/src/modules/platform/database/database.module.ts +24 -13
  490. package/templates/be/skeleton-lite/src/modules/platform/database/database.port.ts +5 -0
  491. package/templates/be/skeleton-lite/src/modules/platform/database/errors/database.error.ts +16 -0
  492. package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +3 -0
  493. package/templates/be/skeleton-lite/src/modules/platform/http-security/http-security.module.ts +5 -2
  494. package/templates/be/skeleton-lite/src/modules/platform/http-security/index.ts +4 -1
  495. package/templates/be/skeleton-lite/src/modules/platform/i18n/index.ts +1 -1
  496. package/templates/be/skeleton-lite/src/modules/platform/logging/logging.log-events.ts +7 -0
  497. package/templates/be/skeleton-lite/src/tests/fixtures/builders/api.builder.ts +29 -0
  498. package/templates/be/skeleton-lite/src/tests/fixtures/builders/cli.builder.ts +16 -0
  499. package/templates/be/table/api/feature.module-definition.ts.tpl +6 -0
  500. package/templates/be/table/api/feature.module.ts.tpl +2 -1
  501. package/templates/be/table/api/feature.options.ts.tpl +2 -0
  502. package/templates/be/table/api/graphql.module-definition.ts.tpl +6 -0
  503. package/templates/be/table/api/graphql.module.ts.tpl +3 -2
  504. package/templates/be/table/api/graphql.options.ts.tpl +2 -0
  505. package/templates/be/table/migration.sql.tpl +1 -0
  506. package/templates/be/upgrade-full/apps/cli/src/app.module.ts +4 -6
  507. package/templates/be/upgrade-full/apps/cli/src/cli.env.ts +7 -0
  508. package/templates/be/upgrade-full/apps/cli/src/compose/cli.ts +5 -0
  509. package/templates/be/upgrade-full/apps/cli/src/compose/platform.ts +9 -0
  510. package/templates/be/upgrade-full/apps/cli/src/main.ts +3 -0
  511. package/templates/be/upgrade-full/src/features/cli/cli.module.ts +3 -2
  512. package/templates/fe/auth/supabase-client.ts.tpl +34 -0
  513. package/templates/fe/skeleton/apps/__app__/src/app/auth/callback/route.ts +11 -0
  514. package/templates/fe/skeleton/apps/__app__/src/components/blocks/SignInForm/index.tsx +6 -1
  515. package/templates/fe/skeleton/apps/__app__/src/components/leaves/Icon/index.tsx +4 -0
  516. package/templates/fe/skeleton/apps/__app__/src/features/overlays/AppGuideOverlay/component.tsx +31 -0
  517. package/templates/fe/skeleton/apps/__app__/src/features/overlays/AppGuideOverlay/index.tsx +24 -0
  518. package/templates/fe/skeleton/apps/__app__/src/hooks/auth/useSession.ts +6 -1
  519. package/templates/fe/skeleton/apps/__app__/src/hooks/auth/useSignOut.ts +3 -4
  520. package/templates/fe/skeleton/apps/__app__/src/hooks/zustand/appGuide/index.ts +1 -0
  521. package/templates/fe/skeleton/apps/__app__/src/hooks/zustand/appGuide/store.ts +15 -0
  522. package/templates/fe/skeleton/apps/__app__/src/modules/auth/pkce-client.ts +18 -0
  523. package/templates/fe/skeleton/apps/__app__/src/modules/auth/server.ts +19 -0
  524. package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/index.tsx +7 -1
  525. package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/en.json +57 -0
  526. package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/vi.json +6 -0
  527. package/templates/fe/skeleton/apps/landing/src/modules/i18n/messages/en.json +31 -0
  528. package/templates/fe/skeleton/packages/__project__-i18n/src/routing.ts +1 -1
  529. package/templates/fe/skeleton/packages/__project__-ui/src/index.ts +1 -0
  530. package/templates/fe/skeleton-lite/apps/__app__/src/modules/auth/client.ts +1 -34
  531. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/index.tsx +7 -1
  532. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/en.json +57 -0
  533. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/vi.json +30 -24
  534. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/routing.ts +1 -1
  535. package/templates/fe/transport/graphql/clients/clients/auth.ts +1 -1
  536. package/templates/fe/transport/graphql/clients/links/locale.ts +2 -2
  537. package/upgrade/check.mjs +3 -1
  538. package/upgrade/index.mjs +54 -41
@@ -1,9 +1,9 @@
1
1
  import { ConfigurableModuleBuilder } from "@nestjs/common"
2
2
  import { QUEUE_OPTIONS } from "./queue.decorators"
3
- import type { QueueOptions } from "./queue.options"
3
+ import type { QueueRegistrationOptions } from "./queue.options"
4
4
 
5
5
  /** The configurable-module base of the queues; `isGlobal` is decided by the app root. */
6
- export const { ConfigurableModuleClass, OPTIONS_TYPE } = new ConfigurableModuleBuilder<QueueOptions>({
6
+ export const { ConfigurableModuleClass, OPTIONS_TYPE } = new ConfigurableModuleBuilder<QueueRegistrationOptions>({
7
7
  optionsInjectionToken: QUEUE_OPTIONS,
8
8
  })
9
9
  .setExtras({ isGlobal: false }, (definition, extras) => ({ ...definition, global: extras.isGlobal }))
@@ -28,6 +28,17 @@ export class QueueModule extends ConfigurableModuleClass {
28
28
  /** Registers the capability once per app that enqueues or processes jobs. */
29
29
  static register(options: typeof OPTIONS_TYPE): DynamicModule {
30
30
  const base = super.register(options)
31
+ if (options.outboxOnly === true) {
32
+ return {
33
+ ...base,
34
+ providers: [
35
+ ...(base.providers ?? []),
36
+ QueueOutboxService,
37
+ { provide: QUEUE_OUTBOX, useExisting: QueueOutboxService },
38
+ ],
39
+ exports: [QUEUE_OUTBOX],
40
+ }
41
+ }
31
42
  return {
32
43
  ...base,
33
44
  providers: [
@@ -3,6 +3,8 @@ import type { QueueSchedulerDefinition } from "./queue.contracts"
3
3
 
4
4
  /** What the queues of one app need: where Redis is, how the relay and the workers run, which connections hold an outbox, and the schedulers it registers. */
5
5
  export interface QueueOptions {
6
+ /** The runtime registration owns the relay, workers and schedulers. */
7
+ readonly outboxOnly?: false
6
8
  /** The Redis host BullMQ talks to. */
7
9
  readonly redisHost: string
8
10
  /** The Redis port. */
@@ -22,3 +24,11 @@ export interface QueueOptions {
22
24
  /** The job schedulers the app registers at boot; BullMQ upserts them by id, so a pool of replicas fires each one once per interval. */
23
25
  readonly schedulers: ReadonlyArray<QueueSchedulerDefinition>
24
26
  }
27
+
28
+ /** A one-off producer writes an outbox row and exits; the running app owns delivery. */
29
+ export interface QueueOutboxOnlyOptions {
30
+ readonly outboxOnly: true
31
+ }
32
+
33
+ /** Registers either the running queue capability or only its transactional writer. */
34
+ export type QueueRegistrationOptions = QueueOptions | QueueOutboxOnlyOptions
@@ -0,0 +1,6 @@
1
+ import { ConfigurableModuleBuilder } from "@nestjs/common"
2
+ import type { @@Queue@@Options } from "./@@queue@@.options"
3
+
4
+ /** The configurable-module base of the @@queue@@ module. */
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ new ConfigurableModuleBuilder<@@Queue@@Options>().setClassMethodName("register").build()
@@ -1,6 +1,7 @@
1
1
  import { Module } from "@nestjs/common"
2
+ import { ConfigurableModuleClass } from "./@@queue@@.module-definition"
2
3
  import { @@Queue@@Queue } from "./@@queue@@.queue"
3
4
 
4
5
  @Module({ providers: [@@Queue@@Queue], exports: [@@Queue@@Queue] })
5
6
  /** The @@queue@@ queue: its typed producer, imported by the domain module whose service enqueues. */
6
- export class @@Queue@@Module {}
7
+ export class @@Queue@@Module extends ConfigurableModuleClass {}
@@ -0,0 +1,2 @@
1
+ /** The @@queue@@ module takes no options yet. */
2
+ export type @@Queue@@Options = Record<string, never>
@@ -0,0 +1,6 @@
1
+ import { ConfigurableModuleBuilder } from "@nestjs/common"
2
+ import type { @@Reactor@@MessageOptions } from "./@@reactor@@-message.options"
3
+
4
+ /** The configurable-module base of the @@reactor@@-message module. */
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ new ConfigurableModuleBuilder<@@Reactor@@MessageOptions>().setClassMethodName("register").build()
@@ -4,14 +4,17 @@ import { InjectEventConsumerRegistry } from "@modules/platform/event-bus"
4
4
  import type { EventConsumerRegistry } from "@modules/platform/event-bus"
5
5
  import { @@Reactor@@Module } from "../../@@reactor@@.module"
6
6
  import { @@Event@@Consumer } from "./@@event@@.consumer"
7
+ import { ConfigurableModuleClass } from "./@@reactor@@-message.module-definition"
7
8
 
8
- @Module({ imports: [@@Reactor@@Module], providers: [@@Event@@Consumer] })
9
+ @Module({ imports: [@@Reactor@@Module.register({})], providers: [@@Event@@Consumer] })
9
10
  /** The message transport of the @@reactor@@ reactor: registers its consumers with the event bus; a worker or api app composes it. */
10
- export class @@Reactor@@MessageModule implements OnModuleInit {
11
+ export class @@Reactor@@MessageModule extends ConfigurableModuleClass implements OnModuleInit {
11
12
  constructor(
12
13
  @InjectEventConsumerRegistry() private readonly registry: EventConsumerRegistry,
13
14
  private readonly @@eventCamel@@Consumer: @@Event@@Consumer,
14
- ) {}
15
+ ) {
16
+ super()
17
+ }
15
18
 
16
19
  /** Hands every consumer to the registry. */
17
20
  onModuleInit(): void {
@@ -0,0 +1,2 @@
1
+ /** The @@reactor@@-message module takes no options yet. */
2
+ export type @@Reactor@@MessageOptions = Record<string, never>
@@ -0,0 +1,6 @@
1
+ import { ConfigurableModuleBuilder } from "@nestjs/common"
2
+ import type { @@Reactor@@Options } from "./@@reactor@@.options"
3
+
4
+ /** The configurable-module base of the @@reactor@@ module. */
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ new ConfigurableModuleBuilder<@@Reactor@@Options>().setClassMethodName("register").build()
@@ -1,6 +1,7 @@
1
1
  import { Module } from "@nestjs/common"
2
+ import { ConfigurableModuleClass } from "./@@reactor@@.module-definition"
2
3
  import { @@Action@@Handler } from "./application/@@action@@.handler"
3
4
 
4
5
  @Module({ providers: [@@Action@@Handler] })
5
6
  /** The @@reactor@@ reactor: the handler its consumers dispatch to. */
6
- export class @@Reactor@@Module {}
7
+ export class @@Reactor@@Module extends ConfigurableModuleClass {}
@@ -0,0 +1,2 @@
1
+ /** The @@reactor@@ module takes no options yet. */
2
+ export type @@Reactor@@Options = Record<string, never>
@@ -0,0 +1,188 @@
1
+ import { Test } from "@nestjs/testing"
2
+ import { MESSAGE_MAPPING_METADATA } from "@nestjs/websockets/constants"
3
+ import { @@service@@ } from "@@serviceModule@@"
4
+ import type { VerifySupabaseAccessToken } from "@modules/integrations/supabase"
5
+ import { SupabaseErrorCode } from "@modules/integrations/supabase"
6
+ import type { Principal } from "@modules/platform/cqrs"
7
+ import { ok, refused } from "@modules/platform/primitives"
8
+ import { REALTIME_HUB } from "@modules/platform/realtime"
9
+ import type { RealtimeHub, RealtimeTopic } from "@modules/platform/realtime"
10
+ import { @@Channel@@Gateway } from "./@@channel@@.gateway"
11
+ import { @@Channel@@WebsocketModule } from "./@@channel@@-websocket.module"
12
+ import type { @@Channel@@Namespace, @@Channel@@Socket } from "./@@channel@@-websocket.module"
13
+
14
+ const principal: Principal = { id: "p-1", role: "authenticated" }
15
+
16
+ /** A recording hub whose stream ends when the transport returns its iterator. */
17
+ const hubAnswering = (frame: unknown = undefined) => {
18
+ const topics: Array<string> = []
19
+ const released: Array<string> = []
20
+ const hub: RealtimeHub = {
21
+ publish: () => undefined,
22
+ subscriberCount: () => 0,
23
+ subscribe: <T extends object>(topic: RealtimeTopic<T>): AsyncIterable<T> => {
24
+ topics.push(topic.name)
25
+ let release: () => void = () => undefined
26
+ const closed = new Promise<void>((resolve) => { release = resolve })
27
+ let sent = false
28
+ return {
29
+ [Symbol.asyncIterator]: () => ({
30
+ next: async (): Promise<IteratorResult<T>> => {
31
+ if (!sent && topic.accepts(frame)) {
32
+ sent = true
33
+ return { done: false, value: frame }
34
+ }
35
+ await closed
36
+ return { done: true, value: undefined }
37
+ },
38
+ return: async (): Promise<IteratorResult<T>> => {
39
+ released.push(topic.name)
40
+ release()
41
+ return { done: true, value: undefined }
42
+ },
43
+ }),
44
+ }
45
+ },
46
+ }
47
+ return { hub, topics, released }
48
+ }
49
+
50
+ /** The adapter calls middleware first and only then announces a connection. */
51
+ const namespaceAnswering = () => {
52
+ let middleware: Parameters<@@Channel@@Namespace["use"]>[0] = (_client, next) => next(new Error("Uninitialized"))
53
+ let connect: Parameters<@@Channel@@Namespace["on"]>[1] = () => undefined
54
+ const namespace: @@Channel@@Namespace = {
55
+ use: (listener) => { middleware = listener },
56
+ on: (_event, listener) => { connect = listener },
57
+ }
58
+ const authenticate = (client: @@Channel@@Socket) => new Promise<void>((resolve, reject) => {
59
+ middleware(client, (error) => error === undefined ? resolve() : reject(error))
60
+ })
61
+ return { namespace, authenticate, connect: (client: @@Channel@@Socket) => connect(client) }
62
+ }
63
+
64
+ const socketOf = (id: string, auth: Readonly<Record<string, unknown>> = { accessToken: "signed-token" }) => {
65
+ let connected = true
66
+ let disconnect: () => void = () => undefined
67
+ let delivered: () => void = () => undefined
68
+ const pushed = new Promise<void>((resolve) => { delivered = resolve })
69
+ const data: { principal?: Principal } = {}
70
+ const socket = {
71
+ id,
72
+ get connected(): boolean { return connected },
73
+ handshake: { auth },
74
+ data,
75
+ emit: jest.fn(() => delivered()),
76
+ once: (_event: "disconnect", listener: () => void) => { disconnect = listener },
77
+ disconnect: jest.fn((_close: boolean) => { connected = false; disconnect() }),
78
+ } satisfies @@Channel@@Socket
79
+ return { socket, pushed }
80
+ }
81
+
82
+ const build = async (hub: RealtimeHub, verify: VerifySupabaseAccessToken) => {
83
+ const moduleRef = await Test.createTestingModule({
84
+ imports: [@@Channel@@WebsocketModule.register({ verifyAccessToken: verify })],
85
+ })
86
+ .useMocker((token) => token === REALTIME_HUB ? hub : undefined)
87
+ .compile()
88
+ const door = moduleRef.get(@@Channel@@Gateway)
89
+ const transport = moduleRef.get(@@Channel@@WebsocketModule)
90
+ const adapter = namespaceAnswering()
91
+ door.namespace = adapter.namespace
92
+ transport.onModuleInit()
93
+ return { door, transport, adapter }
94
+ }
95
+
96
+ describe("@@Channel@@Gateway", () => {
97
+ it("builds the topic only from the verified principal, ignoring handshake principal and topic claims", async () => {
98
+ const { hub, topics } = hubAnswering()
99
+ const verify: VerifySupabaseAccessToken = jest.fn().mockResolvedValue(ok(principal))
100
+ const { transport, adapter } = await build(hub, verify)
101
+ const { socket } = socketOf("socket-1", { accessToken: "signed-token", principal: { id: "p-2" }, topic: "foreign" })
102
+
103
+ await adapter.authenticate(socket)
104
+ adapter.connect(socket)
105
+
106
+ expect(verify).toHaveBeenCalledWith("signed-token")
107
+ expect(socket.data.principal).toEqual(principal)
108
+ expect(topics).toEqual([@@service@@(principal.id).name])
109
+ await transport.onModuleDestroy()
110
+ })
111
+
112
+ it("isolates another authenticated principal's topic", async () => {
113
+ const { hub, topics } = hubAnswering()
114
+ const verify: VerifySupabaseAccessToken = jest.fn().mockResolvedValue(ok({ id: "p-2", role: "authenticated" }))
115
+ const { transport, adapter } = await build(hub, verify)
116
+ const { socket } = socketOf("socket-2")
117
+
118
+ await adapter.authenticate(socket)
119
+ adapter.connect(socket)
120
+
121
+ expect(topics).toEqual([@@service@@("p-2").name])
122
+ expect(topics).not.toContain(@@service@@(principal.id).name)
123
+ await transport.onModuleDestroy()
124
+ })
125
+
126
+ it("pushes a hub frame automatically and releases the iterator on disconnect", async () => {
127
+ const frame = { id: "x-1" }
128
+ const { hub, released } = hubAnswering(frame)
129
+ const verify: VerifySupabaseAccessToken = jest.fn().mockResolvedValue(ok(principal))
130
+ const { transport, adapter } = await build(hub, verify)
131
+ const { socket, pushed } = socketOf("socket-1")
132
+
133
+ await adapter.authenticate(socket)
134
+ adapter.connect(socket)
135
+ await pushed
136
+ socket.disconnect(true)
137
+
138
+ expect(socket.emit).toHaveBeenCalledWith("@@channelCamel@@Changed", frame)
139
+ expect(released).toEqual([@@service@@(principal.id).name])
140
+ await transport.onModuleDestroy()
141
+ })
142
+
143
+ it.each([{}, { accessToken: "" }, { accessToken: 42 }])("refuses a missing or malformed access token without invoking the verifier", async (auth) => {
144
+ const { hub, topics } = hubAnswering()
145
+ const verify: VerifySupabaseAccessToken = jest.fn()
146
+ const { adapter } = await build(hub, verify)
147
+ const { socket } = socketOf("socket-1", auth)
148
+ socket.data.principal = principal
149
+
150
+ await expect(adapter.authenticate(socket)).rejects.toThrow("Unauthorized")
151
+
152
+ expect(verify).not.toHaveBeenCalled()
153
+ expect(socket.data.principal).toBeUndefined()
154
+ expect(topics).toEqual([])
155
+ })
156
+
157
+ it("refuses a rejected token and clears a prior principal", async () => {
158
+ const { hub, topics } = hubAnswering()
159
+ const verify: VerifySupabaseAccessToken = jest.fn().mockResolvedValue(refused(SupabaseErrorCode.AccessTokenInvalid))
160
+ const { adapter } = await build(hub, verify)
161
+ const { socket } = socketOf("socket-1")
162
+ socket.data.principal = principal
163
+
164
+ await expect(adapter.authenticate(socket)).rejects.toThrow("Unauthorized")
165
+
166
+ expect(socket.data.principal).toBeUndefined()
167
+ expect(topics).toEqual([])
168
+ })
169
+
170
+ it("refuses a connection that bypasses authentication without opening a hub stream", async () => {
171
+ const { hub, topics } = hubAnswering()
172
+ const { adapter } = await build(hub, jest.fn())
173
+ const { socket } = socketOf("socket-1")
174
+
175
+ adapter.connect(socket)
176
+
177
+ expect(socket.disconnect).toHaveBeenCalledWith(true)
178
+ expect(topics).toEqual([])
179
+ })
180
+
181
+ it("has no inbound application message handler", async () => {
182
+ const { hub } = hubAnswering()
183
+ const { door } = await build(hub, jest.fn())
184
+
185
+ expect(Reflect.getMetadata(MESSAGE_MAPPING_METADATA, door.frames)).toBeUndefined()
186
+ expect(Object.getOwnPropertyNames(@@Channel@@Gateway.prototype)).toEqual(["constructor", "frames"])
187
+ })
188
+ })
@@ -0,0 +1,22 @@
1
+ import { WebSocketGateway, WebSocketServer } from "@nestjs/websockets"
2
+ import { @@service@@ } from "@@serviceModule@@"
3
+ import type { @@Channel@@Frame } from "@@serviceModule@@"
4
+ import type { Principal } from "@modules/platform/cqrs"
5
+ import { InjectRealtimeHub } from "@modules/platform/realtime"
6
+ import type { RealtimeHub } from "@modules/platform/realtime"
7
+ import type { @@Channel@@Namespace } from "./@@channel@@-websocket.module"
8
+
9
+ @WebSocketGateway({ namespace: "/@@channel@@", transports: ["websocket"] })
10
+ /** The push-only @@channel@@ door: its module authenticates each connection before opening the principal's stream. */
11
+ export class @@Channel@@Gateway {
12
+ /** The namespace created by the app's socket.io adapter; the module installs authentication before the app listens. */
13
+ @WebSocketServer()
14
+ namespace!: @@Channel@@Namespace
15
+
16
+ constructor(@InjectRealtimeHub() private readonly hub: RealtimeHub) {}
17
+
18
+ /** The domain contract builds this principal-wide topic; the reactor publishes through the same builder. */
19
+ frames(principal: Principal): AsyncIterable<@@Channel@@Frame> {
20
+ return this.hub.subscribe(@@service@@(principal.id))
21
+ }
22
+ }
@@ -0,0 +1,6 @@
1
+ import { ConfigurableModuleBuilder } from "@nestjs/common"
2
+ import type { @@Channel@@GraphqlOptions } from "./@@channel@@-graphql.options"
3
+
4
+ /** The configurable-module base of the @@channel@@-graphql module. */
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ new ConfigurableModuleBuilder<@@Channel@@GraphqlOptions>().setClassMethodName("register").build()
@@ -1,6 +1,7 @@
1
1
  import { Module } from "@nestjs/common"
2
+ import { ConfigurableModuleClass } from "./@@channel@@-graphql.module-definition"
2
3
  import { @@Channel@@Subscription } from "./@@channel@@.subscription"
3
4
 
4
5
  @Module({ providers: [@@Channel@@Subscription] })
5
6
  /** The GraphQL transport of the @@channel@@ channel: its subscription door; the hub comes from the app's realtime capability. */
6
- export class @@Channel@@GraphqlModule {}
7
+ export class @@Channel@@GraphqlModule extends ConfigurableModuleClass {}
@@ -0,0 +1,2 @@
1
+ /** The @@channel@@-graphql module takes no options yet. */
2
+ export type @@Channel@@GraphqlOptions = Record<string, never>
@@ -0,0 +1,6 @@
1
+ import { ConfigurableModuleBuilder } from "@nestjs/common"
2
+ import type { @@Channel@@WebsocketOptions } from "./@@channel@@-websocket.options"
3
+
4
+ /** The configurable-module base of the @@channel@@-websocket module. */
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ new ConfigurableModuleBuilder<@@Channel@@WebsocketOptions>().setClassMethodName("register").build()
@@ -0,0 +1,110 @@
1
+ import { Module } from "@nestjs/common"
2
+ import type { OnModuleDestroy, OnModuleInit } from "@nestjs/common"
3
+ import type { @@Channel@@Frame } from "@@serviceModule@@"
4
+ import type { VerifySupabaseAccessToken } from "@modules/integrations/supabase"
5
+ import { injector } from "@modules/platform/composition"
6
+ import type { Principal } from "@modules/platform/cqrs"
7
+ import { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } from "./@@channel@@-websocket.module-definition"
8
+ import type { @@Channel@@WebsocketOptions } from "./@@channel@@-websocket.options"
9
+ import { @@Channel@@Gateway } from "./@@channel@@.gateway"
10
+
11
+ const ACCESS_TOKEN_VERIFIER: unique symbol = Symbol("@@channel@@.access-token-verifier")
12
+
13
+ /** The socket.io surface used here; the adapter and the socket library remain owned by platform/realtime. */
14
+ export interface @@Channel@@Socket {
15
+ /** The adapter's connection identifier. */
16
+ readonly id: string
17
+ /** Whether the connection is still open. */
18
+ readonly connected: boolean
19
+ /** Untrusted handshake input: only its access token is read. */
20
+ readonly handshake: { readonly auth: Readonly<Record<string, unknown>> }
21
+ /** Server-side state: middleware replaces any previous principal with verified claims. */
22
+ readonly data: { principal?: Principal }
23
+ /** Sends one frame to this authenticated socket. */
24
+ emit(event: "@@channelCamel@@Changed", frame: @@Channel@@Frame): void
25
+ /** Releases the stream when the connection ends. */
26
+ once(event: "disconnect", listener: () => void): void
27
+ /** Closes a refused or failed connection. */
28
+ disconnect(close: boolean): void
29
+ }
30
+
31
+ /** A namespace from the app's socket.io adapter. No inbound application events are registered. */
32
+ export interface @@Channel@@Namespace {
33
+ /** Runs authentication before the connection event. */
34
+ use(middleware: (client: @@Channel@@Socket, next: (error?: Error) => void) => void): void
35
+ /** Automatically opens the authenticated client's push stream. */
36
+ on(event: "connection", listener: (client: @@Channel@@Socket) => void): void
37
+ }
38
+
39
+ @Module({
40
+ providers: [
41
+ @@Channel@@Gateway,
42
+ { provide: ACCESS_TOKEN_VERIFIER, useFactory: (options: @@Channel@@WebsocketOptions) => options.verifyAccessToken, inject: [MODULE_OPTIONS_TOKEN] },
43
+ ],
44
+ })
45
+ /** The socket transport: verifies each connection, forwards hub frames and releases every disconnected subscription. */
46
+ export class @@Channel@@WebsocketModule extends ConfigurableModuleClass implements OnModuleInit, OnModuleDestroy {
47
+ private readonly streams = new Map<string, AsyncIterator<@@Channel@@Frame>>()
48
+
49
+ constructor(
50
+ private readonly gateway: @@Channel@@Gateway,
51
+ @injector<VerifySupabaseAccessToken>(ACCESS_TOKEN_VERIFIER)
52
+ private readonly verifyAccessToken: VerifySupabaseAccessToken,
53
+ ) {
54
+ super()
55
+ }
56
+
57
+ /** Nest creates gateway namespaces before module initialization and starts listening afterwards. */
58
+ onModuleInit(): void {
59
+ this.gateway.namespace.use((client, next) => {
60
+ void this.authenticate(client).then(() => next(), () => next(new Error("Unauthorized")))
61
+ })
62
+ this.gateway.namespace.on("connection", (client) => {
63
+ void this.push(client).catch(() => client.disconnect(true))
64
+ })
65
+ }
66
+
67
+ /** Releases all hub iterators when the app shuts down. */
68
+ async onModuleDestroy(): Promise<void> {
69
+ await Promise.all([...this.streams.keys()].map((id) => this.release(id)))
70
+ }
71
+
72
+ private async authenticate(client: @@Channel@@Socket): Promise<void> {
73
+ client.data.principal = undefined
74
+ const token = client.handshake.auth.accessToken
75
+ if (typeof token !== "string" || token.length === 0) throw new Error("Unauthorized")
76
+ const verified = await this.verifyAccessToken(token)
77
+ if (verified.kind !== "ok" || verified.value.role !== "authenticated" || verified.value.id.length === 0) {
78
+ throw new Error("Unauthorized")
79
+ }
80
+ client.data.principal = verified.value
81
+ }
82
+
83
+ private async push(client: @@Channel@@Socket): Promise<void> {
84
+ const principal = client.data.principal
85
+ if (principal === undefined) {
86
+ client.disconnect(true)
87
+ return
88
+ }
89
+ const iterator = this.gateway.frames(principal)[Symbol.asyncIterator]()
90
+ this.streams.set(client.id, iterator)
91
+ client.once("disconnect", () => {
92
+ void this.release(client.id).catch(() => client.disconnect(true))
93
+ })
94
+ try {
95
+ while (client.connected) {
96
+ const frame = await iterator.next()
97
+ if (frame.done || !client.connected) break
98
+ client.emit("@@channelCamel@@Changed", frame.value)
99
+ }
100
+ } finally {
101
+ await this.release(client.id)
102
+ }
103
+ }
104
+
105
+ private async release(id: string): Promise<void> {
106
+ const iterator = this.streams.get(id)
107
+ this.streams.delete(id)
108
+ await iterator?.return?.()
109
+ }
110
+ }
@@ -0,0 +1,7 @@
1
+ import type { VerifySupabaseAccessToken } from "@modules/integrations/supabase"
2
+
3
+ /** The options of the @@channel@@ socket transport: the cryptographic verifier that authenticates each connection. */
4
+ export interface @@Channel@@WebsocketOptions {
5
+ /** Verifies the access token of a handshake with the same verifier identity uses. */
6
+ readonly verifyAccessToken: VerifySupabaseAccessToken
7
+ }
@@ -0,0 +1,6 @@
1
+ import { ConfigurableModuleBuilder } from "@nestjs/common"
2
+ import type { @@Saga@@MessageOptions } from "./@@saga@@-message.options"
3
+
4
+ /** The configurable-module base of the @@saga@@-message module. */
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ new ConfigurableModuleBuilder<@@Saga@@MessageOptions>().setClassMethodName("register").build()
@@ -5,15 +5,18 @@ import type { EventConsumerRegistry } from "@modules/platform/event-bus"
5
5
  import { @@Saga@@Module } from "../../@@saga@@.module"
6
6
  import { @@Done@@Consumer } from "./@@done@@.consumer"
7
7
  import { @@Failed@@Consumer } from "./@@failed@@.consumer"
8
+ import { ConfigurableModuleClass } from "./@@saga@@-message.module-definition"
8
9
 
9
- @Module({ imports: [@@Saga@@Module], providers: [@@Done@@Consumer, @@Failed@@Consumer] })
10
+ @Module({ imports: [@@Saga@@Module.register({})], providers: [@@Done@@Consumer, @@Failed@@Consumer] })
10
11
  /** The message transport of the @@saga@@ saga: registers its consumers with the event bus. */
11
- export class @@Saga@@MessageModule implements OnModuleInit {
12
+ export class @@Saga@@MessageModule extends ConfigurableModuleClass implements OnModuleInit {
12
13
  constructor(
13
14
  @InjectEventConsumerRegistry() private readonly registry: EventConsumerRegistry,
14
15
  private readonly @@doneCamel@@Consumer: @@Done@@Consumer,
15
16
  private readonly @@failedCamel@@Consumer: @@Failed@@Consumer,
16
- ) {}
17
+ ) {
18
+ super()
19
+ }
17
20
 
18
21
  /** Hands every consumer to the registry. */
19
22
  onModuleInit(): void {
@@ -0,0 +1,2 @@
1
+ /** The @@saga@@-message module takes no options yet. */
2
+ export type @@Saga@@MessageOptions = Record<string, never>
@@ -0,0 +1,6 @@
1
+ import { ConfigurableModuleBuilder } from "@nestjs/common"
2
+ import type { @@Saga@@Options } from "./@@saga@@.options"
3
+
4
+ /** The configurable-module base of the @@saga@@ module. */
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ new ConfigurableModuleBuilder<@@Saga@@Options>().setClassMethodName("register").build()
@@ -1,4 +1,5 @@
1
1
  import { Module } from "@nestjs/common"
2
+ import { ConfigurableModuleClass } from "./@@saga@@.module-definition"
2
3
  import { Compensate@@Saga@@Handler } from "./application/compensate-@@saga@@.handler"
3
4
  import { Complete@@Saga@@Handler } from "./application/complete-@@saga@@.handler"
4
5
  import { Undo@@Saga@@Handler } from "./application/undo-@@saga@@.handler"
@@ -17,4 +18,4 @@ import { @@Step@@Step } from "./steps/@@step@@.saga-step"
17
18
  ],
18
19
  })
19
20
  /** The @@saga@@ saga: its orchestrator, its step and compensation, and the handlers of the commands the consumers dispatch. */
20
- export class @@Saga@@Module {}
21
+ export class @@Saga@@Module extends ConfigurableModuleClass {}
@@ -0,0 +1,2 @@
1
+ /** The @@saga@@ module takes no options yet. */
2
+ export type @@Saga@@Options = Record<string, never>
@@ -0,0 +1,6 @@
1
+ import { ConfigurableModuleBuilder } from "@nestjs/common"
2
+ import type { @@Provider@@HttpOptions } from "./@@provider@@-http.options"
3
+
4
+ /** The configurable-module base of the @@provider@@-http module. */
5
+ export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
6
+ new ConfigurableModuleBuilder<@@Provider@@HttpOptions>().setClassMethodName("register").build()
@@ -1,6 +1,7 @@
1
1
  import { Module } from "@nestjs/common"
2
+ import { ConfigurableModuleClass } from "./@@provider@@-http.module-definition"
2
3
  import { @@Provider@@Webhook } from "./@@provider@@.webhook"
3
4
 
4
5
  @Module({ controllers: [@@Provider@@Webhook] })
5
6
  /** The HTTP transport of the @@provider@@ notifier: its webhook door; the intake service and the signature service come from the app's capabilities. */
6
- export class @@Provider@@HttpModule {}
7
+ export class @@Provider@@HttpModule extends ConfigurableModuleClass {}
@@ -0,0 +1,2 @@
1
+ /** The @@provider@@-http module takes no options yet. */
2
+ export type @@Provider@@HttpOptions = Record<string, never>