@starci/hfs 4.7.31 → 4.7.33

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 (473) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +13 -6
  3. package/emit/contracts.mjs +4 -3
  4. package/emit/form-bounds-reader.ts.partial +58 -0
  5. package/emit/form-bounds.mjs +155 -0
  6. package/emit/graphql-input-bounds.mjs +97 -0
  7. package/emit/input-bounds.mjs +44 -0
  8. package/emit/operation-schemas.mjs +137 -0
  9. package/emit/operations-worker.mjs +2 -2
  10. package/emit/operations.mjs +52 -16
  11. package/emit/schema-worker.mjs +17 -4
  12. package/emit/type-schema.mjs +17 -5
  13. package/package.json +9 -2
  14. package/release/gate.mjs +18 -23
  15. package/release/index.mjs +1 -1
  16. package/release/push.mjs +4 -5
  17. package/runtime/engine/admission.mjs +331 -0
  18. package/runtime/engine/canonical-json.mjs +14 -0
  19. package/runtime/engine/db/blob.mjs +380 -0
  20. package/runtime/engine/db/event-compact.mjs +73 -0
  21. package/runtime/engine/db/ledger-open.mjs +38 -0
  22. package/runtime/engine/db/ledger-paths.mjs +87 -0
  23. package/runtime/engine/db/ledger.mjs +1068 -0
  24. package/runtime/engine/db/machine-connection.mjs +150 -0
  25. package/runtime/engine/db/machine-open.mjs +60 -0
  26. package/runtime/engine/db/machine-schema.mjs +105 -0
  27. package/runtime/engine/db/machine.mjs +1317 -0
  28. package/runtime/engine/db/provider-reservations.mjs +127 -0
  29. package/runtime/engine/db/provision-authority.mjs +76 -0
  30. package/runtime/engine/db/provision-lock.mjs +29 -0
  31. package/runtime/engine/db/provision-operations.mjs +146 -0
  32. package/runtime/engine/db/ref-value.mjs +67 -0
  33. package/runtime/engine/db/schema/machine.sql +920 -0
  34. package/runtime/engine/db/schema/runtime.sql +1113 -0
  35. package/runtime/engine/refuse.mjs +11 -0
  36. package/runtime/knowledge/hfs/canon-pins.yaml +65 -9
  37. package/runtime/knowledge/hfs/design-truths.yaml +149 -0
  38. package/runtime/knowledge/hfs/fe-stack.yaml +23 -5
  39. package/runtime/knowledge/hfs/rules.yaml +269 -48
  40. package/runtime/knowledge/hfs/slots.yaml +113 -53
  41. package/runtime/knowledge/patterns/be/api.yaml +46 -20
  42. package/runtime/knowledge/patterns/be/event-bus.yaml +19 -12
  43. package/runtime/knowledge/patterns/be/idempotency.yaml +265 -0
  44. package/runtime/knowledge/patterns/be/jobs.yaml +17 -12
  45. package/runtime/knowledge/patterns/be/projections.yaml +2 -2
  46. package/runtime/knowledge/patterns/be/queues.yaml +57 -22
  47. package/runtime/knowledge/patterns/be/reactors.yaml +1 -1
  48. package/runtime/knowledge/patterns/be/realtime.yaml +326 -27
  49. package/runtime/knowledge/patterns/be/saga.yaml +2 -2
  50. package/runtime/knowledge/sonar-gate.yaml +1 -1
  51. package/runtime/modules/kernel/command-policy.yaml +249 -0
  52. package/runtime/modules/kernel/failure-codes.yaml +211 -52
  53. package/runtime/modules/kernel/hook-input.yaml +6 -0
  54. package/runtime/modules/kernel/protected-zone.yaml +81 -0
  55. package/runtime/modules/kernel/removed-vocabulary.yaml +62 -0
  56. package/runtime/modules/kernel/roles.yaml +405 -0
  57. package/runtime/modules/models/registry.yaml +3 -1
  58. package/runtime/modules/models/runtimes.yaml +2 -0
  59. package/runtime/modules/schemas/application-stacks.schema.yaml +10 -2
  60. package/runtime/packages/cli/src/catalog.generated.mjs +46 -59
  61. package/runtime/packages/grammar/scripts/build-stamp.mjs +98 -0
  62. package/runtime/scripts/agent/codex-app-server.mjs +79 -0
  63. package/runtime/scripts/agent/codex-mirror-source.mjs +34 -0
  64. package/runtime/scripts/agent/host-agents.mjs +80 -0
  65. package/runtime/scripts/agent/launch-trust-policy.mjs +53 -0
  66. package/runtime/scripts/agent/trust-launch.mjs +191 -0
  67. package/runtime/scripts/agent/trust.mjs +523 -0
  68. package/runtime/scripts/api/fs/rename-over.mjs +21 -0
  69. package/runtime/scripts/api/fs/temp-path.mjs +8 -0
  70. package/runtime/scripts/api/fs/write-json-file.mjs +10 -0
  71. package/runtime/scripts/api/git/diff-names.mjs +8 -0
  72. package/runtime/scripts/api/git/head-time.mjs +10 -0
  73. package/runtime/scripts/api/git/index-lock.mjs +78 -0
  74. package/runtime/scripts/api/git/is-ancestor.mjs +5 -0
  75. package/runtime/scripts/api/git/log.mjs +5 -0
  76. package/runtime/scripts/api/git/merge-base-query.mjs +5 -0
  77. package/runtime/scripts/api/git/merge-tree.mjs +5 -0
  78. package/runtime/scripts/api/git/rev-list.mjs +5 -0
  79. package/runtime/scripts/api/git/rev-parse.mjs +13 -0
  80. package/runtime/scripts/api/git/status-query.mjs +5 -0
  81. package/runtime/scripts/api/git/worktree-list-query.mjs +5 -0
  82. package/runtime/scripts/api/node/spawn-node.mjs +6 -0
  83. package/runtime/scripts/api/npm/dist-tag.mjs +8 -0
  84. package/runtime/scripts/api/npm/lib.mjs +32 -0
  85. package/runtime/scripts/api/npm/pack-dry-run.mjs +9 -0
  86. package/runtime/scripts/api/npm/run-npm.mjs +6 -0
  87. package/runtime/scripts/api/npm/view.mjs +30 -0
  88. package/runtime/scripts/api/npm/whoami.mjs +8 -0
  89. package/runtime/scripts/api/process/hide-child-windows.mjs +31 -0
  90. package/runtime/scripts/api/process/kill-tree.mjs +22 -0
  91. package/runtime/scripts/api/process/lib.mjs +125 -0
  92. package/runtime/scripts/api/process/probe-guard-command.mjs +74 -0
  93. package/runtime/scripts/api/process/process-list.mjs +28 -0
  94. package/runtime/scripts/api/process/system-tool.mjs +37 -0
  95. package/runtime/scripts/gates/canon-digest.mjs +81 -0
  96. package/runtime/scripts/gates/canon-pins.mjs +16 -0
  97. package/runtime/scripts/gates/commit-proof.mjs +53 -0
  98. package/runtime/scripts/gates/gate-input.mjs +98 -0
  99. package/runtime/scripts/gates/gate.mjs +669 -0
  100. package/runtime/scripts/gates/grammar-dist.mjs +206 -0
  101. package/runtime/scripts/gates/runtime-package-selection.mjs +27 -0
  102. package/runtime/scripts/gates/test-world-run.mjs +254 -0
  103. package/runtime/scripts/gates/type-impact.mjs +277 -0
  104. package/runtime/scripts/gates/type-program.mjs +113 -0
  105. package/runtime/scripts/guards/assigned-command.mjs +12 -0
  106. package/runtime/scripts/guards/call-rights.mjs +47 -0
  107. package/runtime/scripts/guards/command-guard.mjs +468 -0
  108. package/runtime/scripts/guards/command-policy.mjs +342 -0
  109. package/runtime/scripts/guards/critic-reach.mjs +82 -0
  110. package/runtime/scripts/guards/deps-guard.mjs +150 -0
  111. package/runtime/scripts/guards/env-dump-verdict.mjs +89 -0
  112. package/runtime/scripts/guards/git-pathspec.mjs +225 -0
  113. package/runtime/scripts/guards/git-policy.mjs +355 -0
  114. package/runtime/scripts/guards/guards-root.mjs +27 -0
  115. package/runtime/scripts/guards/hook-install.mjs +343 -0
  116. package/runtime/scripts/guards/hook-io.mjs +76 -0
  117. package/runtime/scripts/guards/hook-verdict.mjs +12 -0
  118. package/runtime/scripts/guards/install-verdict.mjs +41 -0
  119. package/runtime/scripts/guards/kernel-seat.mjs +63 -0
  120. package/runtime/scripts/guards/launch-verdict.mjs +74 -0
  121. package/runtime/scripts/guards/op-starci.mjs +16 -0
  122. package/runtime/scripts/guards/op-write-scope.mjs +27 -0
  123. package/runtime/scripts/guards/orca-self-lifecycle.mjs +39 -0
  124. package/runtime/scripts/guards/process-kill-verdict.mjs +106 -0
  125. package/runtime/scripts/guards/protected-zone.mjs +56 -0
  126. package/runtime/scripts/guards/refusals.mjs +27 -0
  127. package/runtime/scripts/guards/release-definition.mjs +185 -0
  128. package/runtime/scripts/guards/release-push-gate.mjs +72 -0
  129. package/runtime/scripts/guards/release-record.mjs +58 -0
  130. package/runtime/scripts/guards/release-suite-mode.mjs +15 -0
  131. package/runtime/scripts/guards/rights.mjs +268 -0
  132. package/runtime/scripts/guards/seat-tools.mjs +47 -0
  133. package/runtime/scripts/guards/shell-commands.mjs +328 -0
  134. package/runtime/scripts/guards/supervisor-seat.mjs +80 -0
  135. package/runtime/scripts/guards/verdict-process.mjs +81 -0
  136. package/runtime/scripts/hfs/architecture/dead-exports.mjs +10 -10
  137. package/runtime/scripts/hfs/architecture/function-spec-providers.mjs +1 -1
  138. package/runtime/scripts/hfs/architecture/operation-contract-roots.mjs +53 -0
  139. package/runtime/scripts/hfs/architecture/reachability.mjs +1 -1
  140. package/runtime/scripts/hfs/architecture/sql-owner.mjs +17 -6
  141. package/runtime/scripts/hfs/architecture/sql-token-forms.mjs +105 -0
  142. package/runtime/scripts/hfs/architecture/sql-tokens.mjs +38 -52
  143. package/runtime/scripts/hfs/architecture/supabase-keys.mjs +261 -0
  144. package/runtime/scripts/hfs/architecture/transport-owner.mjs +49 -3
  145. package/runtime/scripts/hfs/architecture/typescript.mjs +1 -1
  146. package/runtime/scripts/hfs/check.mjs +6 -4
  147. package/runtime/scripts/hfs/coverage-scope.mjs +28 -1
  148. package/runtime/scripts/hfs/db-restamp-verb.mjs +54 -14
  149. package/runtime/scripts/hfs/declaration-shape.mjs +4 -4
  150. package/runtime/scripts/hfs/declaration-slots.mjs +14 -3
  151. package/runtime/scripts/hfs/manifest-shape.mjs +10 -6
  152. package/runtime/scripts/hfs/rule-params-shape.mjs +18 -6
  153. package/runtime/scripts/hfs/rules/a15-findings.mjs +4 -1
  154. package/runtime/scripts/hfs/rules/bypass-markers.mjs +22 -7
  155. package/runtime/scripts/hfs/rules/database-migrations.mjs +69 -14
  156. package/runtime/scripts/hfs/rules/database-queue-sources.mjs +9 -7
  157. package/runtime/scripts/hfs/rules/database-queues.mjs +68 -18
  158. package/runtime/scripts/hfs/rules/edition.mjs +56 -12
  159. package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +1 -10
  160. package/runtime/scripts/hfs/rules/fe-stack.mjs +12 -7
  161. package/runtime/scripts/hfs/rules/lite-proof-lane.mjs +1 -1
  162. package/runtime/scripts/hfs/rules/stacks-lite-backing.mjs +75 -9
  163. package/runtime/scripts/hfs/rules/stacks-runtime.mjs +1 -1
  164. package/runtime/scripts/hfs/rules/stacks-swarm.mjs +15 -4
  165. package/runtime/scripts/hfs/rules/text-integrity.mjs +73 -0
  166. package/runtime/scripts/hfs/runtime-rules/hook-shape.mjs +74 -0
  167. package/runtime/scripts/hfs/runtime-rules/release-notes.mjs +44 -0
  168. package/runtime/scripts/hfs/sealed-members.mjs +3 -3
  169. package/runtime/scripts/hfs/slot-side-problems.mjs +3 -3
  170. package/runtime/scripts/hfs/slots.mjs +2 -1
  171. package/runtime/scripts/hfs/stack-deploy-config.mjs +22 -5
  172. package/runtime/scripts/hfs/stacks-gate.mjs +28 -7
  173. package/runtime/scripts/hfs/view.mjs +2 -1
  174. package/runtime/scripts/lib/app-data.mjs +11 -0
  175. package/runtime/scripts/lib/bypass-markers.mjs +272 -75
  176. package/runtime/scripts/lib/check-format.mjs +7 -0
  177. package/runtime/scripts/lib/cli-arg.mjs +120 -0
  178. package/runtime/scripts/lib/css-rules.mjs +220 -0
  179. package/runtime/scripts/lib/dom-tree.mjs +4 -0
  180. package/runtime/scripts/lib/escape.mjs +16 -0
  181. package/runtime/scripts/lib/event-items.mjs +22 -0
  182. package/runtime/scripts/lib/failure-code-template-errors.mjs +161 -0
  183. package/runtime/scripts/lib/git-dir.mjs +120 -0
  184. package/runtime/scripts/lib/grammar-vendor-parity.mjs +377 -0
  185. package/runtime/scripts/lib/guard-command.mjs +24 -0
  186. package/runtime/scripts/lib/hook-limits.mjs +5 -0
  187. package/runtime/scripts/lib/interrupt-cleanup.mjs +38 -0
  188. package/runtime/scripts/lib/js-lex.mjs +200 -0
  189. package/runtime/scripts/lib/json-formats.mjs +0 -1
  190. package/runtime/scripts/lib/language.mjs +94 -1
  191. package/runtime/scripts/lib/loosening-budgets.mjs +44 -0
  192. package/runtime/scripts/lib/loosening-config.mjs +361 -0
  193. package/runtime/scripts/lib/loosening-state.mjs +223 -0
  194. package/runtime/scripts/lib/menu-parts.mjs +11 -0
  195. package/runtime/scripts/lib/normalize.mjs +25 -0
  196. package/runtime/scripts/lib/op-gate.mjs +15 -0
  197. package/runtime/scripts/lib/redact.mjs +208 -0
  198. package/runtime/scripts/lib/runtime-location.mjs +21 -0
  199. package/runtime/scripts/lib/runtime-package-inventory.mjs +21 -0
  200. package/runtime/scripts/lib/runtime-package-manifests.mjs +84 -0
  201. package/runtime/scripts/lib/runtime-publication-tags.mjs +99 -0
  202. package/runtime/scripts/lib/seat-env.mjs +43 -0
  203. package/runtime/scripts/lib/secret-patterns.mjs +58 -9
  204. package/runtime/scripts/lib/shell-source.mjs +4 -0
  205. package/runtime/scripts/lib/source-phrases.mjs +34 -0
  206. package/runtime/scripts/lib/sqlite.mjs +21 -0
  207. package/runtime/scripts/lib/swarm-stack.mjs +2 -1
  208. package/runtime/scripts/lib/tar-files.mjs +39 -0
  209. package/runtime/scripts/lib/ts-analysis.mjs +10 -0
  210. package/runtime/scripts/lib/worktree-exclude.mjs +35 -0
  211. package/runtime/scripts/lib/worktree-record.mjs +14 -0
  212. package/runtime/scripts/machine/artifact-hold.mjs +52 -0
  213. package/runtime/scripts/machine/ask-receipts.mjs +113 -0
  214. package/runtime/scripts/machine/evidence-store.mjs +223 -0
  215. package/runtime/scripts/machine/home.mjs +216 -0
  216. package/runtime/scripts/machine/host-lock.mjs +184 -0
  217. package/runtime/scripts/machine/lock-recovery.mjs +55 -0
  218. package/runtime/scripts/machine/roles-contract.mjs +90 -0
  219. package/runtime/scripts/machine/runtime-change.mjs +20 -0
  220. package/runtime/scripts/machine/workflow-tree.mjs +122 -0
  221. package/runtime/scripts/reconciler/checklist-items.mjs +7 -0
  222. package/runtime/scripts/reconciler/guard-row.mjs +25 -0
  223. package/runtime/scripts/work/asset-slot.mjs +284 -0
  224. package/runtime/scripts/work/brand/brand-colour.mjs +125 -0
  225. package/runtime/scripts/work/brand/brand-tokens.mjs +167 -0
  226. package/runtime/scripts/work/brand/brand-value-source.mjs +106 -0
  227. package/runtime/scripts/work/brand/brand.mjs +892 -0
  228. package/runtime/scripts/work/draw/draw-dna-anatomy.mjs +60 -0
  229. package/runtime/scripts/work/draw/draw-dna-findings.mjs +256 -0
  230. package/runtime/scripts/work/draw/draw-dna-selector.mjs +38 -0
  231. package/runtime/scripts/work/draw/draw-dna.mjs +483 -0
  232. package/runtime/scripts/work/draw/draw-layer.mjs +305 -0
  233. package/runtime/scripts/work/draw/draw-rationale-page.mjs +237 -0
  234. package/runtime/scripts/work/draw/draw-rationale-ref.mjs +14 -0
  235. package/runtime/scripts/work/draw/draw-rationale.mjs +353 -0
  236. package/runtime/scripts/work/draw/draw-source.mjs +412 -0
  237. package/runtime/scripts/work/draw/draw-taste.mjs +278 -0
  238. package/runtime/scripts/work/draw/draw-typecheck.mjs +72 -0
  239. package/runtime/scripts/work/draw/rationale-findings.mjs +205 -0
  240. package/runtime/scripts/work/draw-grammar.mjs +175 -0
  241. package/runtime/scripts/work/draw-render-page.mjs +188 -0
  242. package/runtime/scripts/work/draw-render.mjs +626 -0
  243. package/runtime/scripts/work/grammar-proposal.mjs +279 -0
  244. package/runtime/scripts/work/png.mjs +237 -0
  245. package/runtime/scripts/work/render-tools.mjs +64 -0
  246. package/runtime/scripts/work/work-io.mjs +119 -0
  247. package/scaffold/add-inbox-lite.mjs +2 -2
  248. package/scaffold/add-plan.mjs +40 -13
  249. package/scaffold/add-queue-lite.mjs +372 -0
  250. package/scaffold/add.mjs +5 -2
  251. package/scaffold/app.mjs +1 -2
  252. package/scaffold/edition-gate.mjs +11 -7
  253. package/scaffold/lite-exports.mjs +10 -0
  254. package/scaffold/pattern-file-slots.mjs +33 -0
  255. package/scaffold/test-world.mjs +1 -1
  256. package/scaffold/yaml-block-edit.mjs +117 -0
  257. package/src/main.mjs +5 -4
  258. package/stack/deploy.mjs +7 -3
  259. package/stack/post-deploy.mjs +48 -0
  260. package/sync/index.mjs +10 -0
  261. package/templates/app/ci-workflows/github/workflows/stack-deploy.yml +1 -1
  262. package/templates/app/ci-workflows-lite/github/workflows/stack-deploy.yml +1 -1
  263. package/templates/app/codegen-graphql.mjs.partial +59 -12
  264. package/templates/app/hooks/husky/pre-commit +2 -2
  265. package/templates/app/hooks/husky/pre-push +10 -3
  266. package/templates/app/package-scripts/redis-dev.json +3 -0
  267. package/templates/app/package-scripts-lite/package.json +1 -0
  268. package/templates/app/skeleton/.starcistacks/application-stacks.yaml +36 -8
  269. package/templates/app/skeleton/.starcistacks/dev/README.md +1 -1
  270. package/templates/app/skeleton/.starcistacks/production/README.md +10 -9
  271. package/templates/app/skeleton/.starcistacks/production/infra/swarm/postgres-init.sh +21 -0
  272. package/templates/app/skeleton/.starcistacks/production/infra/swarm/recovery/restore-proof.md +1 -1
  273. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/images.lock.yaml +1 -0
  274. package/templates/app/skeleton/.starcistacks/production/infra/swarm/stack.yaml +47 -5
  275. package/templates/app/skeleton/.starcistacks/production/runtime/env/KEYS.md +5 -3
  276. package/templates/app/skeleton/README.md +2 -0
  277. package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +5 -0
  278. package/templates/app/skeleton-lite/.starcistacks/dev/README.md +2 -2
  279. package/templates/app/skeleton-lite/.starcistacks/production/README.md +1 -1
  280. package/templates/app/skeleton-lite/README.md +1 -1
  281. package/templates/be/inbox/platform/client-operation-outcomes.sql.tpl +18 -0
  282. package/templates/be/inbox/platform/event-bus/errors/event-bus.error.ts.tpl +16 -0
  283. package/templates/be/inbox/platform/event-bus/event-bus.contracts.ts.tpl +10 -0
  284. package/templates/be/inbox/platform/event-bus/event-bus.port.ts.tpl +1 -1
  285. package/templates/be/inbox/platform/event-bus/event-bus.service.spec.ts.tpl +15 -3
  286. package/templates/be/inbox/platform/event-bus/event-bus.service.ts.tpl +11 -3
  287. package/templates/be/inbox/platform/event-bus/index.ts.tpl +2 -0
  288. package/templates/be/inbox/platform/event-bus/messages/event-bus.messages.ts.tpl +7 -0
  289. package/templates/be/inbox/platform/event-bus/persistence/event-bus.sql.ts.tpl +2 -2
  290. package/templates/be/inbox/platform/idempotency/errors/idempotency.error.ts.tpl +19 -0
  291. package/templates/be/inbox/platform/idempotency/index.ts.tpl +2 -0
  292. package/templates/be/inbox/platform/idempotency/messages/idempotency.messages.ts.tpl +13 -0
  293. package/templates/be/inbox/platform/inbox/client-operation.policy.spec.ts.tpl +32 -0
  294. package/templates/be/inbox/platform/inbox/client-operation.policy.ts.tpl +17 -0
  295. package/templates/be/inbox/platform/inbox/errors/inbox.error.ts.tpl +22 -0
  296. package/templates/be/inbox/platform/inbox/inbox.port.ts.tpl +21 -0
  297. package/templates/be/inbox/platform/inbox/inbox.service.spec.ts.tpl +334 -11
  298. package/templates/be/inbox/platform/inbox/inbox.service.ts.tpl +55 -4
  299. package/templates/be/inbox/platform/inbox/index.ts.tpl +2 -0
  300. package/templates/be/inbox/platform/inbox/messages/inbox.messages.ts.tpl +15 -0
  301. package/templates/be/inbox/platform/inbox/persistence/inbox.rows.ts.tpl +33 -0
  302. package/templates/be/inbox/platform/inbox/persistence/inbox.sql.ts.tpl +26 -0
  303. package/templates/be/inbox/platform/inbox/request-fingerprint.policy.spec.ts.tpl +76 -0
  304. package/templates/be/inbox/platform/inbox/request-fingerprint.policy.ts.tpl +36 -0
  305. package/templates/be/inbox/platform/migration.sql.tpl +1 -0
  306. package/templates/be/inbox/service.spec.ts.tpl +4 -4
  307. package/templates/be/inbox/service.ts.tpl +3 -1
  308. package/templates/be/inbox/webhook-door.spec.ts.tpl +3 -2
  309. package/templates/be/inbox/webhook-door.ts.tpl +3 -2
  310. package/templates/be/patterns/event-bus/platform/errors/event-bus.error.ts.tpl +3 -0
  311. package/templates/be/patterns/event-bus/platform/event-bus.contracts.ts.tpl +10 -0
  312. package/templates/be/patterns/event-bus/platform/event-bus.port.ts.tpl +2 -2
  313. package/templates/be/patterns/event-bus/platform/event-bus.service.spec.ts.tpl +16 -3
  314. package/templates/be/patterns/event-bus/platform/event-bus.service.ts.tpl +11 -3
  315. package/templates/be/patterns/event-bus/platform/event-envelope.policy.spec.ts.tpl +139 -50
  316. package/templates/be/patterns/event-bus/platform/event-envelope.policy.ts.tpl +25 -2
  317. package/templates/be/patterns/event-bus/platform/event-relay.service.spec.ts.tpl +139 -78
  318. package/templates/be/patterns/event-bus/platform/event-relay.service.ts.tpl +10 -6
  319. package/templates/be/patterns/event-bus/platform/event-runner.service.spec.ts.tpl +262 -159
  320. package/templates/be/patterns/event-bus/platform/event-runner.service.ts.tpl +32 -5
  321. package/templates/be/patterns/event-bus/platform/messages/event-bus.messages.ts.tpl +2 -0
  322. package/templates/be/patterns/event-bus/platform/persistence/entities/event-outbox.entity.ts.tpl +5 -1
  323. package/templates/be/patterns/event-bus/platform/persistence/event-bus.rows.ts.tpl +2 -0
  324. package/templates/be/patterns/event-bus/platform/persistence/event-bus.sql.ts.tpl +4 -4
  325. package/templates/be/patterns/event-bus/platform/persistence/migrations/1789800009000-create-event-outbox.ts.tpl +1 -0
  326. package/templates/be/patterns/idempotency/platform/idempotency/errors/idempotency.error.ts.tpl +19 -0
  327. package/templates/be/patterns/idempotency/platform/idempotency/index.ts.tpl +2 -0
  328. package/templates/be/patterns/idempotency/platform/idempotency/messages/idempotency.messages.ts.tpl +13 -0
  329. package/templates/be/patterns/idempotency/platform/inbox/client-operation.policy.spec.ts.tpl +32 -0
  330. package/templates/be/patterns/idempotency/platform/inbox/client-operation.policy.ts.tpl +17 -0
  331. package/templates/be/patterns/idempotency/platform/inbox/client-outcome-backfill.client.spec.ts.tpl +66 -0
  332. package/templates/be/patterns/idempotency/platform/inbox/client-outcome-backfill.client.ts.tpl +24 -0
  333. package/templates/be/patterns/idempotency/platform/inbox/delivery-claim-backfill.client.spec.ts.tpl +60 -0
  334. package/templates/be/patterns/idempotency/platform/inbox/delivery-claim-backfill.client.ts.tpl +12 -0
  335. package/templates/be/patterns/idempotency/platform/inbox/delivery-claim-release.client.spec.ts.tpl +49 -0
  336. package/templates/be/patterns/idempotency/platform/inbox/delivery-claim-release.client.ts.tpl +12 -0
  337. package/templates/be/patterns/idempotency/platform/inbox/effectful.decorators.ts.tpl +7 -0
  338. package/templates/be/patterns/idempotency/platform/inbox/errors/inbox.error.ts.tpl +22 -0
  339. package/templates/be/patterns/idempotency/platform/inbox/inbox.decorators.ts.tpl +17 -0
  340. package/templates/be/patterns/idempotency/platform/inbox/inbox.module-definition.ts.tpl +7 -0
  341. package/templates/be/patterns/idempotency/platform/inbox/inbox.module.ts.tpl +28 -0
  342. package/templates/be/patterns/idempotency/platform/inbox/inbox.options.ts.tpl +7 -0
  343. package/templates/be/patterns/idempotency/platform/inbox/inbox.port.ts.tpl +44 -0
  344. package/templates/be/patterns/idempotency/platform/inbox/inbox.service.spec.ts.tpl +388 -0
  345. package/templates/be/patterns/idempotency/platform/inbox/inbox.service.ts.tpl +77 -0
  346. package/templates/be/patterns/idempotency/platform/inbox/index.ts.tpl +10 -0
  347. package/templates/be/patterns/idempotency/platform/inbox/messages/inbox.messages.ts.tpl +15 -0
  348. package/templates/be/patterns/idempotency/platform/inbox/persistence/connection.ts.tpl +9 -0
  349. package/templates/be/patterns/idempotency/platform/inbox/persistence/entities/inbox-claim.entity.ts.tpl +25 -0
  350. package/templates/be/patterns/idempotency/platform/inbox/persistence/inbox.rows.ts.tpl +33 -0
  351. package/templates/be/patterns/idempotency/platform/inbox/persistence/inbox.sql.ts.tpl +39 -0
  352. package/templates/be/patterns/idempotency/platform/inbox/persistence/migrations/1789800005000-create-inbox-claims.ts.tpl +21 -0
  353. package/templates/be/patterns/idempotency/platform/inbox/persistence/migrations/1792800000000-client-operation-outcomes.ts.tpl +21 -0
  354. package/templates/be/patterns/idempotency/platform/inbox/request-fingerprint.policy.spec.ts.tpl +76 -0
  355. package/templates/be/patterns/idempotency/platform/inbox/request-fingerprint.policy.ts.tpl +36 -0
  356. package/templates/be/patterns/jobs/platform/fenced.processor.spec.ts.tpl +1 -0
  357. package/templates/be/patterns/jobs/platform/job-claim.service.spec.ts.tpl +4 -3
  358. package/templates/be/patterns/jobs/platform/job-claim.service.ts.tpl +2 -0
  359. package/templates/be/patterns/jobs/platform/job-runner.service.spec.ts.tpl +20 -2
  360. package/templates/be/patterns/jobs/platform/job-runner.service.ts.tpl +1 -0
  361. package/templates/be/patterns/jobs/platform/jobs.contracts.ts.tpl +4 -0
  362. package/templates/be/patterns/jobs/platform-lite/jobs.index.ts.tpl +10 -0
  363. package/templates/be/patterns/jobs/platform-lite/jobs.sql.tpl +44 -0
  364. package/templates/be/patterns/jobs/platform-lite/persistence.jobs.sql.ts.tpl +33 -0
  365. package/templates/be/patterns/queues/platform/bullmq-queue-transport.client.spec.ts.tpl +203 -18
  366. package/templates/be/patterns/queues/platform/bullmq-queue-transport.client.ts.tpl +78 -22
  367. package/templates/be/patterns/queues/platform/errors/queue.error.ts.tpl +19 -0
  368. package/templates/be/patterns/queues/platform/messages/queue.messages.ts.tpl +13 -0
  369. package/templates/be/patterns/queues/platform/persistence.migration.ts.tpl +1 -0
  370. package/templates/be/patterns/queues/platform/persistence.queue-outbox.entity.ts.tpl +4 -0
  371. package/templates/be/patterns/queues/platform/persistence.queue.rows.ts.tpl +2 -0
  372. package/templates/be/patterns/queues/platform/persistence.queue.sql.ts.tpl +4 -4
  373. package/templates/be/patterns/queues/platform/queue-outbox.service.spec.ts.tpl +14 -2
  374. package/templates/be/patterns/queues/platform/queue-outbox.service.ts.tpl +5 -2
  375. package/templates/be/patterns/queues/platform/queue-relay.service.spec.ts.tpl +72 -74
  376. package/templates/be/patterns/queues/platform/queue-relay.service.ts.tpl +1 -1
  377. package/templates/be/patterns/queues/platform/queue-transport.port.ts.tpl +23 -8
  378. package/templates/be/patterns/queues/platform/queue-worker.service.spec.ts.tpl +29 -8
  379. package/templates/be/patterns/queues/platform/queue-worker.service.ts.tpl +7 -3
  380. package/templates/be/patterns/queues/platform/queue.contracts.ts.tpl +5 -0
  381. package/templates/be/patterns/queues/platform/queue.index.ts.tpl +2 -0
  382. package/templates/be/patterns/queues/platform/queue.log-events.ts.tpl +4 -0
  383. package/templates/be/patterns/queues/platform/queue.module.ts.tpl +2 -1
  384. package/templates/be/patterns/queues/platform/queue.port.ts.tpl +1 -1
  385. package/templates/be/patterns/queues/platform-lite/bullmq-queue-transport.client.spec.ts.tpl +417 -0
  386. package/templates/be/patterns/queues/platform-lite/bullmq-queue-transport.client.ts.tpl +172 -0
  387. package/templates/be/patterns/queues/platform-lite/persistence.queue.sql.ts.tpl +12 -0
  388. package/templates/be/patterns/queues/platform-lite/queue-outbox.sql.tpl +32 -0
  389. package/templates/be/patterns/queues/platform-lite/queue-relay.service.spec.ts.tpl +148 -0
  390. package/templates/be/patterns/queues/platform-lite/queue-relay.service.ts.tpl +51 -0
  391. package/templates/be/patterns/queues/platform-lite/queue-transport.port.ts.tpl +163 -0
  392. package/templates/be/patterns/queues/platform-lite/queue.config.ts.tpl +17 -0
  393. package/templates/be/patterns/queues/platform-lite/queue.error.ts.tpl +25 -0
  394. package/templates/be/patterns/queues/platform-lite/queue.index.ts.tpl +8 -0
  395. package/templates/be/patterns/queues/platform-lite/queue.messages.ts.tpl +21 -0
  396. package/templates/be/patterns/queues/platform-lite/queue.module.ts.tpl +74 -0
  397. package/templates/be/patterns/queues/platform-lite/queue.options.ts.tpl +38 -0
  398. package/templates/be/patterns/queues/queue.queue.ts.tpl +2 -2
  399. package/templates/be/patterns/reactors/application.contracts.ts.tpl +2 -0
  400. package/templates/be/patterns/reactors/consumer.ts.tpl +5 -1
  401. package/templates/be/platform/graphql/graphql.contracts.ts +2 -1
  402. package/templates/be/platform/graphql/localize-errors.mapper.spec.ts +1 -1
  403. package/templates/be/skeleton/apps/__app__/src/compose/platform.ts +6 -1
  404. package/templates/be/skeleton/apps/__app__/src/main.ts +7 -4
  405. package/templates/be/skeleton/apps/cli/src/compose/platform.ts +4 -0
  406. package/templates/be/skeleton/apps/cli/src/main.ts +7 -4
  407. package/templates/be/skeleton/src/modules/platform/database/index.ts +1 -1
  408. package/templates/be/skeleton/src/modules/platform/http/errors/http.error.ts +22 -0
  409. package/templates/be/skeleton/src/modules/platform/http/fetch-http-client.client.spec.ts +235 -0
  410. package/templates/be/skeleton/src/modules/platform/http/fetch-http-client.client.ts +85 -0
  411. package/templates/be/skeleton/src/modules/platform/http/graphql-call.mapper.spec.ts +92 -0
  412. package/templates/be/skeleton/src/modules/platform/http/graphql-call.mapper.ts +52 -0
  413. package/templates/be/skeleton/src/modules/platform/http/http.decorators.ts +9 -0
  414. package/templates/be/skeleton/src/modules/platform/http/http.module-definition.ts +7 -0
  415. package/templates/be/skeleton/src/modules/platform/http/http.module.ts +19 -0
  416. package/templates/be/skeleton/src/modules/platform/http/http.options.ts +2 -0
  417. package/templates/be/skeleton/src/modules/platform/http/http.port.ts +40 -0
  418. package/templates/be/skeleton/src/modules/platform/http/index.ts +7 -0
  419. package/templates/be/skeleton/src/modules/platform/http/messages/http.messages.ts +15 -0
  420. package/templates/be/skeleton/src/modules/platform/ids/ids.decorators.ts +9 -0
  421. package/templates/be/skeleton/src/modules/platform/ids/ids.module-definition.ts +7 -0
  422. package/templates/be/skeleton/src/modules/platform/ids/ids.module.ts +19 -0
  423. package/templates/be/skeleton/src/modules/platform/ids/ids.options.ts +2 -0
  424. package/templates/be/skeleton/src/modules/platform/ids/ids.port.ts +5 -0
  425. package/templates/be/skeleton/src/modules/platform/ids/index.ts +4 -0
  426. package/templates/be/skeleton/src/modules/platform/ids/system-ids.service.spec.ts +15 -0
  427. package/templates/be/skeleton/src/modules/platform/ids/system-ids.service.ts +10 -0
  428. package/templates/be/skeleton/src/modules/platform/logging/correlation-request.policy.spec.ts +59 -0
  429. package/templates/be/skeleton/src/modules/platform/logging/correlation-request.policy.ts +21 -0
  430. package/templates/be/skeleton/src/modules/platform/logging/correlation.contracts.ts +16 -0
  431. package/templates/be/skeleton/src/modules/platform/logging/correlation.policy.spec.ts +150 -0
  432. package/templates/be/skeleton/src/modules/platform/logging/correlation.policy.ts +42 -0
  433. package/templates/be/skeleton/src/modules/platform/logging/correlation.port.ts +15 -0
  434. package/templates/be/skeleton/src/modules/platform/logging/correlation.service.spec.ts +23 -0
  435. package/templates/be/skeleton/src/modules/platform/logging/correlation.service.ts +28 -0
  436. package/templates/be/skeleton/src/modules/platform/logging/index.ts +14 -1
  437. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.spec.ts +39 -6
  438. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.ts +15 -3
  439. package/templates/be/skeleton/src/modules/platform/logging/logging.decorators.ts +17 -2
  440. package/templates/be/skeleton/src/modules/platform/logging/logging.log-events.ts +13 -1
  441. package/templates/be/skeleton/src/modules/platform/logging/logging.module.ts +13 -3
  442. package/templates/be/skeleton/src/modules/platform/logging/nest-logger.service.spec.ts +69 -0
  443. package/templates/be/skeleton/src/modules/platform/logging/nest-logger.service.ts +48 -0
  444. package/templates/be/skeleton/src/modules/platform/primitives/index.ts +1 -0
  445. package/templates/be/skeleton/src/modules/platform/primitives/record.policy.spec.ts +12 -0
  446. package/templates/be/skeleton/src/modules/platform/primitives/record.policy.ts +3 -0
  447. package/templates/be/skeleton-lite/apps/api/src/compose/platform.ts +6 -1
  448. package/templates/be/skeleton-lite/apps/cli/src/compose/platform.ts +4 -0
  449. package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +1 -0
  450. package/templates/be/skeleton-lite/src/modules/platform/logging/index.ts +14 -1
  451. package/templates/be/skeleton-lite/src/modules/platform/logging/logging.log-events.ts +12 -0
  452. package/templates/be/skeleton-lite/src/modules/platform/primitives/index.ts +2 -0
  453. package/templates/be/test-world/world/test-apps.options.ts.tpl +2 -0
  454. package/templates/be/test-world/world/test-world.config.ts.tpl +1 -0
  455. package/upgrade/check.mjs +12 -135
  456. package/upgrade/file-state.mjs +1 -16
  457. package/upgrade/index.mjs +34 -361
  458. package/runtime/scripts/lib/check-code-loosening.mjs +0 -128
  459. package/runtime/scripts/lib/gate-loosening.mjs +0 -292
  460. package/templates/app/upgrade-full/.starcistacks/application-stacks.yaml +0 -89
  461. package/templates/app/upgrade-full/.starcistacks/dev/README.md +0 -16
  462. package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/api.yaml +0 -13
  463. package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/compose.yaml +0 -3
  464. package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/postgres.yaml +0 -12
  465. package/templates/app/upgrade-full/.starcistacks/dev/infra/metadata.json +0 -7
  466. package/templates/be/skeleton-lite/apps/api/src/main.ts +0 -26
  467. package/templates/be/upgrade-full/apps/cli/src/app.module.ts +0 -12
  468. package/templates/be/upgrade-full/apps/cli/src/cli.env.ts +0 -7
  469. package/templates/be/upgrade-full/apps/cli/src/compose/cli.ts +0 -5
  470. package/templates/be/upgrade-full/apps/cli/src/compose/platform.ts +0 -9
  471. package/templates/be/upgrade-full/apps/cli/src/main.ts +0 -29
  472. package/templates/be/upgrade-full/src/features/cli/cli.module.ts +0 -7
  473. package/templates/be/upgrade-full/src/features/cli/migrate/subs/run.cli.ts +0 -23
@@ -1,6 +1,9 @@
1
1
  import type { Writable } from "node:stream"
2
2
  import { InjectClock } from "@modules/platform/clock"
3
3
  import type { Clock } from "@modules/platform/clock"
4
+ import { InjectIds } from "@modules/platform/ids"
5
+ import type { Ids } from "@modules/platform/ids"
6
+ import { stampLogFields } from "./correlation.policy"
4
7
  import { InjectLogErr, InjectLogOut } from "./logging.decorators"
5
8
  import type { LogFields, Logger } from "./logging.port"
6
9
 
@@ -8,11 +11,17 @@ type Level = "info" | "warn" | "error"
8
11
 
9
12
  /** The default adapter: one JSON object per line, stamped by the Clock; info goes to `out`, warn and error to `err`. */
10
13
  export class JsonLoggerService implements Logger {
14
+ /** The identity of lines written outside any correlation scope: drawn once, so such lines of one process share it. */
15
+ private readonly rootId: string
16
+
11
17
  constructor(
12
18
  @InjectClock() private readonly clock: Clock,
13
19
  @InjectLogOut() private readonly out: Writable,
14
20
  @InjectLogErr() private readonly err: Writable,
15
- ) {}
21
+ @InjectIds() ids: Ids,
22
+ ) {
23
+ this.rootId = ids.next()
24
+ }
16
25
 
17
26
  /** Writes an info line. */
18
27
  info(event: string, fields?: LogFields): void {
@@ -35,9 +44,12 @@ export class JsonLoggerService implements Logger {
35
44
  }
36
45
 
37
46
  private write(level: Level, sink: Writable, event: string, fields?: LogFields): void {
38
- sink.write(`${JSON.stringify({ ...fields, level, event, time: this.clock.now().toISOString() })}\n`)
47
+ sink.write(
48
+ `${JSON.stringify({ ...stampLogFields(fields, this.rootId), level, event, time: this.clock.now().toISOString() })}\n`,
49
+ )
39
50
  }
40
51
  }
41
52
 
42
53
  /** Builds the JSON logger stamping lines with `clock` on stdout and stderr; main.ts uses it before the DI container exists. */
43
- export const createJsonLogger = (clock: Clock): Logger => new JsonLoggerService(clock, process.stdout, process.stderr)
54
+ export const createJsonLogger = (clock: Clock, ids: Ids): Logger =>
55
+ new JsonLoggerService(clock, process.stdout, process.stderr, ids)
@@ -2,12 +2,24 @@ import type { Writable } from "node:stream"
2
2
  import { injector } from "@modules/platform/composition"
3
3
  import type { TypedParameterDecorator } from "@modules/platform/composition"
4
4
  import type { Logger } from "./logging.port"
5
+ import type { CorrelationIds, CorrelationRunner } from "./correlation.port"
5
6
 
6
7
  /** Token of the Logger port. */
7
8
  export const LOGGER: unique symbol = Symbol("platform.logging.logger")
8
9
 
9
- /** Injects the Logger port. Parameter type: Logger. */
10
- export const InjectLogger = (): TypedParameterDecorator<Logger> => injector<Logger>(LOGGER)
10
+ /** Token of the inbound identity resolver. */
11
+ export const CORRELATION_IDS: unique symbol = Symbol("platform.logging.correlation-ids")
12
+
13
+ /** Token of the logger's async scope runner. */
14
+ export const CORRELATION_RUNNER: unique symbol = Symbol("platform.logging.correlation-runner")
15
+
16
+ /** Injects explicit inbound identity resolution. Parameter type: CorrelationIds. */
17
+ export const InjectCorrelationIds = (): TypedParameterDecorator<CorrelationIds> =>
18
+ injector<CorrelationIds>(CORRELATION_IDS)
19
+
20
+ /** Injects infrastructure logging scopes. Parameter type: CorrelationRunner. */
21
+ export const InjectCorrelationRunner = (): TypedParameterDecorator<CorrelationRunner> =>
22
+ injector<CorrelationRunner>(CORRELATION_RUNNER)
11
23
 
12
24
  /** Token of the stream info lines go to. */
13
25
  export const LOG_OUT: unique symbol = Symbol("platform.logging.out")
@@ -15,6 +27,9 @@ export const LOG_OUT: unique symbol = Symbol("platform.logging.out")
15
27
  /** Token of the stream warn and error lines go to. */
16
28
  export const LOG_ERR: unique symbol = Symbol("platform.logging.err")
17
29
 
30
+ /** Injects the Logger port. Parameter type: Logger. */
31
+ export const InjectLogger = (): TypedParameterDecorator<Logger> => injector<Logger>(LOGGER)
32
+
18
33
  /** Injects the stream info lines go to. Parameter type: Writable. */
19
34
  export const InjectLogOut = (): TypedParameterDecorator<Writable> => injector<Writable>(LOG_OUT)
20
35
 
@@ -1,4 +1,4 @@
1
- /** Log events of the process lifecycle: the entry points (main.ts of each app) log these. */
1
+ /** Log events owned by logging: process lifecycle and framework messages routed through the JSON port. */
2
2
  export enum LoggingLogEvent {
3
3
  /** The HTTP listener is bound and the service answers requests. */
4
4
  ServerStarted = "server.started",
@@ -8,4 +8,16 @@ export enum LoggingLogEvent {
8
8
  MigrationsApplied = "migrations.applied",
9
9
  /** The seed command finished; the seed files it ran ride in the fields, by connection. */
10
10
  SeedsApplied = "seeds.applied",
11
+ /** An ordinary Nest framework lifecycle message. */
12
+ FrameworkLog = "platform.logging.framework.log",
13
+ /** A Nest framework warning. */
14
+ FrameworkWarning = "platform.logging.framework.warning",
15
+ /** A Nest framework error. */
16
+ FrameworkError = "platform.logging.framework.error",
17
+ /** A Nest framework debug message. */
18
+ FrameworkDebug = "platform.logging.framework.debug",
19
+ /** A Nest framework verbose message. */
20
+ FrameworkVerbose = "platform.logging.framework.verbose",
21
+ /** A fatal Nest framework failure. */
22
+ FrameworkFatal = "platform.logging.framework.fatal",
11
23
  }
@@ -2,8 +2,11 @@ import { Module } from "@nestjs/common"
2
2
  import type { DynamicModule } from "@nestjs/common"
3
3
  import { CLOCK } from "@modules/platform/clock"
4
4
  import type { Clock } from "@modules/platform/clock"
5
+ import { IDS } from "@modules/platform/ids"
6
+ import type { Ids } from "@modules/platform/ids"
7
+ import { CorrelationService } from "./correlation.service"
5
8
  import { createJsonLogger } from "./json-logger.service"
6
- import { LOGGER } from "./logging.decorators"
9
+ import { CORRELATION_IDS, CORRELATION_RUNNER, LOGGER } from "./logging.decorators"
7
10
  import { ConfigurableModuleClass, OPTIONS_TYPE } from "./logging.module-definition"
8
11
 
9
12
  @Module({})
@@ -16,9 +19,16 @@ export class LoggingModule extends ConfigurableModuleClass {
16
19
  ...base,
17
20
  providers: [
18
21
  ...(base.providers ?? []),
19
- { provide: LOGGER, inject: [CLOCK], useFactory: (clock: Clock) => createJsonLogger(clock) },
22
+ CorrelationService,
23
+ { provide: CORRELATION_IDS, useExisting: CorrelationService },
24
+ { provide: CORRELATION_RUNNER, useExisting: CorrelationService },
25
+ {
26
+ provide: LOGGER,
27
+ inject: [CLOCK, IDS],
28
+ useFactory: (clock: Clock, ids: Ids) => createJsonLogger(clock, ids),
29
+ },
20
30
  ],
21
- exports: [LOGGER],
31
+ exports: [LOGGER, CORRELATION_IDS, CORRELATION_RUNNER],
22
32
  }
23
33
  }
24
34
  }
@@ -0,0 +1,69 @@
1
+ import { FakeClock, fakeIds, mock } from "@starci/jest-preset"
2
+ import { Test } from "@nestjs/testing"
3
+ import { runWithCorrelation } from "./correlation.policy"
4
+ import { createJsonLogger } from "./json-logger.service"
5
+ import { LoggingLogEvent } from "./logging.log-events"
6
+ import type { Logger } from "./logging.port"
7
+ import { LOGGER } from "./logging.decorators"
8
+ import { createNestLogger, NestLoggerService } from "./nest-logger.service"
9
+
10
+ const build = async () => {
11
+ const logger = mock<Logger>()
12
+ const moduleRef = await Test.createTestingModule({
13
+ providers: [NestLoggerService, { provide: LOGGER, useValue: logger }],
14
+ }).compile()
15
+ return { logger, adapter: moduleRef.get<NestLoggerService>(NestLoggerService) }
16
+ }
17
+
18
+ describe("NestLoggerService", () => {
19
+ it("maps all framework levels to owned enum identities through the logging port", async () => {
20
+ const { logger, adapter } = await build()
21
+ const failure = new Error("bootstrap failed")
22
+
23
+ adapter.log("started", "NestApplication")
24
+ adapter.warn("recovering", "Injector")
25
+ adapter.debug(42)
26
+ adapter.verbose({ operation: "bootstrap" }, { ignored: "unstructured" })
27
+ adapter.error(failure, failure.stack, "ExceptionHandler")
28
+ adapter.fatal("stopping")
29
+
30
+ expect(logger.info).toHaveBeenNthCalledWith(1, LoggingLogEvent.FrameworkLog, {
31
+ message: "started",
32
+ context: "NestApplication",
33
+ })
34
+ expect(logger.info).toHaveBeenNthCalledWith(2, LoggingLogEvent.FrameworkDebug, { message: "42" })
35
+ expect(logger.info).toHaveBeenNthCalledWith(3, LoggingLogEvent.FrameworkVerbose, { message: "[object Object]" })
36
+ expect(logger.warn).toHaveBeenCalledWith(LoggingLogEvent.FrameworkWarning, {
37
+ message: "recovering",
38
+ context: "Injector",
39
+ })
40
+ expect(logger.error).toHaveBeenNthCalledWith(1, LoggingLogEvent.FrameworkError, failure, {
41
+ message: "Error: bootstrap failed",
42
+ context: "ExceptionHandler",
43
+ })
44
+ expect(logger.error).toHaveBeenNthCalledWith(2, LoggingLogEvent.FrameworkFatal, "stopping", {
45
+ message: "stopping",
46
+ })
47
+ })
48
+
49
+ it("stamps bootstrap lines and uses the active request identity during framework logging", () => {
50
+ const lines: Array<string> = []
51
+ const output = jest.spyOn(process.stdout, "write").mockImplementation((chunk) => lines.push(String(chunk)) > 0)
52
+ try {
53
+ const adapter = createNestLogger(createJsonLogger(new FakeClock("2026-10-24T00:00:00Z"), fakeIds()))
54
+ adapter.log("booting", "NestFactory")
55
+ runWithCorrelation("request-id", () => {
56
+ adapter.log("handling", "Router")
57
+ })
58
+
59
+ expect(lines).toHaveLength(2)
60
+ expect(lines[0]).toContain('"correlationId":"00000000-0000-4000-8000-000000000001"')
61
+ expect(lines[1]).toContain('"correlationId":"request-id"')
62
+ expect(lines[0]).toContain('"context":"NestFactory"')
63
+ expect(lines[1]).toContain('"context":"Router"')
64
+ expect(lines.every((line) => line.includes(`"event":"${LoggingLogEvent.FrameworkLog}"`))).toBe(true)
65
+ } finally {
66
+ output.mockRestore()
67
+ }
68
+ })
69
+ })
@@ -0,0 +1,48 @@
1
+ import type { LoggerService } from "@nestjs/common"
2
+ import { InjectLogger } from "./logging.decorators"
3
+ import { LoggingLogEvent } from "./logging.log-events"
4
+ import type { LogFields, Logger } from "./logging.port"
5
+
6
+ /** Keeps the framework's message and optional textual context without dumping unstructured extra arguments. */
7
+ const fieldsOf = (message: unknown, optionalParams: ReadonlyArray<unknown>): LogFields => {
8
+ const context = optionalParams.at(-1)
9
+ return { message: String(message), ...(typeof context === "string" ? { context } : {}) }
10
+ }
11
+
12
+ /** Routes Nest's own bootstrap and runtime messages through the app's correlation-stamped logging port. */
13
+ export class NestLoggerService implements LoggerService {
14
+ constructor(@InjectLogger() private readonly logger: Logger) {}
15
+
16
+ /** Records an ordinary framework lifecycle message. */
17
+ log(message: unknown, ...optionalParams: Array<unknown>): void {
18
+ this.logger.info(LoggingLogEvent.FrameworkLog, fieldsOf(message, optionalParams))
19
+ }
20
+
21
+ /** Keeps the framework's error as the cause for the logging adapter's structured serialization. */
22
+ error(message: unknown, ...optionalParams: Array<unknown>): void {
23
+ this.logger.error(LoggingLogEvent.FrameworkError, message, fieldsOf(message, optionalParams))
24
+ }
25
+
26
+ /** Records a recoverable framework warning. */
27
+ warn(message: unknown, ...optionalParams: Array<unknown>): void {
28
+ this.logger.warn(LoggingLogEvent.FrameworkWarning, fieldsOf(message, optionalParams))
29
+ }
30
+
31
+ /** Preserves debug identity on the JSON port's informational stream. */
32
+ debug(message: unknown, ...optionalParams: Array<unknown>): void {
33
+ this.logger.info(LoggingLogEvent.FrameworkDebug, fieldsOf(message, optionalParams))
34
+ }
35
+
36
+ /** Preserves verbose identity on the JSON port's informational stream. */
37
+ verbose(message: unknown, ...optionalParams: Array<unknown>): void {
38
+ this.logger.info(LoggingLogEvent.FrameworkVerbose, fieldsOf(message, optionalParams))
39
+ }
40
+
41
+ /** Records a fatal framework failure through the error stream. */
42
+ fatal(message: unknown, ...optionalParams: Array<unknown>): void {
43
+ this.logger.error(LoggingLogEvent.FrameworkFatal, message, fieldsOf(message, optionalParams))
44
+ }
45
+ }
46
+
47
+ /** Supplies NestFactory or CommandFactory with the same Logger port used by application code. */
48
+ export const createNestLogger = (logger: Logger): LoggerService => new NestLoggerService(logger)
@@ -1,3 +1,4 @@
1
1
  export type { Outcome } from "./outcome.contracts"
2
2
  export { ok, refused, unwrapOutcome } from "./outcome.mapper"
3
3
  export { eachInOrder } from "./sequence.policy"
4
+ export { isRecord } from "./record.policy"
@@ -0,0 +1,12 @@
1
+ import { isRecord } from "./record.policy"
2
+
3
+ describe("isRecord", () => {
4
+ it("narrows non-null objects before provider fields are read", () => {
5
+ expect(isRecord({ status: 200 })).toBe(true)
6
+ expect(isRecord([])).toBe(true)
7
+ expect(isRecord(null)).toBe(false)
8
+ expect(isRecord(undefined)).toBe(false)
9
+ expect(isRecord("response")).toBe(false)
10
+ expect(isRecord(200)).toBe(false)
11
+ })
12
+ })
@@ -0,0 +1,3 @@
1
+ /** True for a non-null object, so untrusted parsed data can be narrowed before any key is read. */
2
+ export const isRecord = (value: unknown): value is Record<string, unknown> =>
3
+ typeof value === "object" && value !== null
@@ -8,6 +8,8 @@ import { DATABASE_ERROR_KINDS, DatabaseModule } from "@modules/platform/database
8
8
  import { ERRORS_MESSAGES, ErrorsModule } from "@modules/platform/errors"
9
9
  import { HTTP_SECURITY_ERROR_KINDS, HTTP_SECURITY_MESSAGES, HttpSecurityModule } from "@modules/platform/http-security"
10
10
  import { I18nModule } from "@modules/platform/i18n"
11
+ import { IdsModule } from "@modules/platform/ids"
12
+ import { HTTP_ERROR_KINDS, HTTP_MESSAGES, HttpModule } from "@modules/platform/http"
11
13
  import { LoggingModule } from "@modules/platform/logging"
12
14
  import { RetryModule } from "@modules/platform/retry"
13
15
  import type { ApiOptions } from "../api.options"
@@ -20,14 +22,17 @@ import type { ApiOptions } from "../api.options"
20
22
  export const platformModules = (options: ApiOptions): Array<DynamicModule> => [
21
23
  ClockModule.register({ isGlobal: true }),
22
24
  RetryModule.register({ isGlobal: true }),
25
+ IdsModule.register({ isGlobal: true }),
23
26
  LoggingModule.register({ isGlobal: true }),
27
+ HttpModule.register({ isGlobal: true }),
24
28
  I18nModule.register({
25
29
  isGlobal: true,
26
- bundles: [ERRORS_MESSAGES, HTTP_SECURITY_MESSAGES, IDENTITY_MESSAGES],
30
+ bundles: [HTTP_MESSAGES, ERRORS_MESSAGES, HTTP_SECURITY_MESSAGES, IDENTITY_MESSAGES],
27
31
  }),
28
32
  ErrorsModule.register({
29
33
  isGlobal: true,
30
34
  kinds: [
35
+ HTTP_ERROR_KINDS,
31
36
  CONFIG_ERROR_KINDS,
32
37
  DATABASE_ERROR_KINDS,
33
38
  HTTP_SECURITY_ERROR_KINDS,
@@ -1,12 +1,16 @@
1
1
  import type { DynamicModule } from "@nestjs/common"
2
2
  import { ClockModule } from "@modules/platform/clock"
3
3
  import { DatabaseModule } from "@modules/platform/database"
4
+ import { IdsModule } from "@modules/platform/ids"
5
+ import { HTTP_ERROR_KINDS, HTTP_MESSAGES, HttpModule } from "@modules/platform/http"
4
6
  import { LoggingModule } from "@modules/platform/logging"
5
7
  import type { CliAppOptions } from "../cli.options"
6
8
 
7
9
  /** The shared clock, logger and least-privilege connection used by Supabase CLI commands. */
8
10
  export const platformModules = (options: CliAppOptions): Array<DynamicModule> => [
9
11
  ClockModule.register({ isGlobal: true }),
12
+ IdsModule.register({ isGlobal: true }),
10
13
  LoggingModule.register({ isGlobal: true }),
14
+ HttpModule.register({ isGlobal: true }),
11
15
  DatabaseModule.register({ isGlobal: true, connections: options.connections }),
12
16
  ]
@@ -5,3 +5,4 @@ export type { DatabaseConnectionOptions } from "./database.options"
5
5
  export { PRIMARY_DATA_SOURCE } from "./database.port"
6
6
  export { DATABASE_ERROR_KINDS } from "./errors/database.error"
7
7
  export { parsePrimaryDatabaseConfig } from "./primary.config"
8
+ export { BATCH_ROWS } from "./database.sql"
@@ -1,5 +1,18 @@
1
1
  export { createJsonLogger } from "./json-logger.service"
2
- export { InjectLogger, LOGGER } from "./logging.decorators"
2
+ export {
3
+ InjectLogger,
4
+ LOGGER,
5
+ CORRELATION_IDS,
6
+ CORRELATION_RUNNER,
7
+ InjectCorrelationIds,
8
+ InjectCorrelationRunner,
9
+ } from "./logging.decorators"
10
+ export { applyCorrelation, correlationMiddleware } from "./correlation-request.policy"
11
+ export type { CorrelationIds, CorrelationRunner } from "./correlation.port"
12
+ export type { CorrelationHeaders, CorrelationRequest } from "./correlation.contracts"
13
+ export { createCorrelationRunner } from "./correlation.service"
14
+ export { isCorrelationId } from "./correlation.policy"
3
15
  export { LoggingLogEvent } from "./logging.log-events"
4
16
  export { LoggingModule } from "./logging.module"
5
17
  export type { Logger } from "./logging.port"
18
+ export { createNestLogger } from "./nest-logger.service"
@@ -4,4 +4,16 @@ export enum LoggingLogEvent {
4
4
  ServerStarted = "server.started",
5
5
  /** The service failed before it could serve; the process exits non-zero. */
6
6
  StartupFailed = "server.startup_failed",
7
+ /** An ordinary Nest framework lifecycle message. */
8
+ FrameworkLog = "platform.logging.framework.log",
9
+ /** A Nest framework warning. */
10
+ FrameworkWarning = "platform.logging.framework.warning",
11
+ /** A Nest framework error. */
12
+ FrameworkError = "platform.logging.framework.error",
13
+ /** A Nest framework debug message. */
14
+ FrameworkDebug = "platform.logging.framework.debug",
15
+ /** A Nest framework verbose message. */
16
+ FrameworkVerbose = "platform.logging.framework.verbose",
17
+ /** A fatal Nest framework failure. */
18
+ FrameworkFatal = "platform.logging.framework.fatal",
7
19
  }
@@ -1,2 +1,4 @@
1
1
  export type { Outcome } from "./outcome.contracts"
2
2
  export { ok, refused, unwrapOutcome } from "./outcome.mapper"
3
+ export { eachInOrder } from "./sequence.policy"
4
+ export { isRecord } from "./record.policy"
@@ -11,6 +11,7 @@ import { EnvSource } from "@modules/platform/config"
11
11
  import { DatabaseModule, MigrationRunnerService } from "@modules/platform/database"
12
12
  import { parseHttpSecurityConfig } from "@modules/platform/http-security"
13
13
  import type { HttpSecurityOptions } from "@modules/platform/http-security"
14
+ import { IdsModule } from "@modules/platform/ids"
14
15
  import { LoggingModule } from "@modules/platform/logging"
15
16
  import { RetryModule } from "@modules/platform/retry"
16
17
  import { AppModule as CliApp } from "../../../apps/cli/src/app.module"
@@ -54,6 +55,7 @@ export const migrateCli = async (options: CliAppOptions): Promise<void> => {
54
55
  export const platformBase = (w: AppWiring): ReadonlyArray<DynamicModule> => [
55
56
  ClockModule.register({ isGlobal: true }),
56
57
  RetryModule.register({ isGlobal: true }),
58
+ IdsModule.register({ isGlobal: true }),
57
59
  LoggingModule.register({ isGlobal: true }),
58
60
  DatabaseModule.register({
59
61
  isGlobal: true,
@@ -3,6 +3,7 @@
3
3
  * definition (`.starcistacks/dev`); the library runs the Postgres of every connection real behind toxiproxy, migrates it once per
4
4
  * run through the cli app and boots the api apps in process.
5
5
  */
6
+ import { applyCorrelation } from "@modules/platform/logging"
6
7
  import { defineTestWorld } from "@starci/test-world"
7
8
  {{appModuleImports}}
8
9
  import { {{optionsImports}} } from "./test-apps.options"
package/upgrade/check.mjs CHANGED
@@ -1,139 +1,16 @@
1
- // The `starci app check --edition full` view of a lite app. The app stays byte-for-byte untouched: its declaration is cloned without
2
- // `edition`, then passed to the existing slot resolver, rule filter and architecture engine as an injected declaration.
3
- import fs from "node:fs";
4
- import path from "node:path";
5
- import { checkArchitecture } from "../runtime/scripts/hfs/architecture/index.mjs";
6
- import {
7
- checkDatabase,
8
- checkRepo,
9
- trackedFiles,
10
- } from "../runtime/scripts/hfs/check.mjs";
11
- import { loadSlotManifest, openHfs } from "../runtime/scripts/hfs/slots.mjs";
12
- import { formatFindings } from "../sync/format.mjs";
13
- import {
14
- appSource,
15
- checkTargets,
16
- loadHfs,
17
- renderTargets,
18
- } from "../sync/index.mjs";
19
- import { readDeclaredStack } from "../sync/stack-images.mjs";
20
- import {
21
- UPGRADE_PRESETS,
22
- UpgradeError,
23
- fullEditionDeclaration,
24
- } from "./index.mjs";
1
+ // The edition selector of `starci app check --edition <edition>`. Editions are fixed at scaffold: the selector names the edition hfs.json
2
+ // declares or the check refuses. There is no preview of a lite app as a full one.
3
+ import { loadSlotManifest } from "../runtime/scripts/hfs/slots.mjs";
4
+ import { loadHfs } from "../sync/index.mjs";
5
+ import { UpgradeError } from "./index.mjs";
25
6
 
26
- const ONE_LINER = new Set(["eslint.config.mjs", "stylelint.config.mjs"]);
27
-
28
- function fullManagedFindings(repoRoot, targets) {
29
- const findings = [];
30
- for (const result of checkTargets(repoRoot, targets)) {
31
- if (
32
- result.status === "ok" ||
33
- !fs.existsSync(path.join(repoRoot, ...result.path.split("/")))
34
- )
35
- continue;
36
- const target = targets.find((candidate) => candidate.path === result.path);
37
- const code =
38
- target.mode === "block"
39
- ? "HFS_GITIGNORE_BLOCK_DRIFT"
40
- : ONE_LINER.has(path.posix.basename(result.path))
41
- ? "HFS_RULE_OFF_WITHOUT_REPLACEMENT"
42
- : result.path === "sonar-project.properties"
43
- ? "HFS_SONAR_CONFIG"
44
- : "HFS_MANAGED_FILE_DRIFT";
45
- findings.push({
46
- code,
47
- level: "error",
48
- path: result.path,
49
- message: `${result.path} is not its full-edition render (expected sha256 ${result.expectedHash.slice(0, 12)}${result.actualHash ? `, found ${result.actualHash.slice(0, 12)}` : ""}); run starci app upgrade --edition full`,
50
- });
51
- }
52
- return findings;
53
- }
54
-
55
- const machineFinding = (side, item) => ({
56
- code: item.ruleId,
57
- level: "error",
58
- ...(item.path ? { path: `${side}/${item.path}` } : {}),
59
- ...(item.line ? { line: item.line, column: item.column } : {}),
60
- source: "machine",
61
- message: `${item.path ? `${side}/${item.path}${item.line ? `:${item.line}` : ""}: ` : ""}${item.message}`,
62
- });
63
-
64
- /**
65
- * Runs the normal check when the requested edition matches hfs.json. The sole override is lite -> full; every other mismatch is
66
- * a usage refusal. `normal` is the CLI's ordinary check closure, which keeps the existing full and lite paths unchanged.
67
- */
68
- export async function checkEdition({
69
- repoRoot,
70
- edition,
71
- normal,
72
- presets,
73
- prettier,
74
- manifest = loadSlotManifest(),
75
- }) {
7
+ /** Runs the normal check when the requested edition is the declared one; any other edition is a usage refusal. `normal` is the CLI's ordinary check closure. */
8
+ export async function checkEdition({ repoRoot, edition, normal, manifest = loadSlotManifest() }) {
76
9
  if (edition === undefined) return normal();
77
10
  if (!["full", "lite"].includes(edition))
78
- throw new UpgradeError(
79
- "HFS_EDITION_INVALID",
80
- `--edition is ${JSON.stringify(edition)}; expected full or lite`,
81
- );
82
- const declaration = loadHfs(repoRoot, manifest);
83
- const actual = declaration.edition ?? "full";
84
- if (edition === actual) return normal();
85
- if (!(actual === "lite" && edition === "full"))
86
- throw new UpgradeError(
87
- "HFS_EDITION_INVALID",
88
- `hfs.json edition is ${actual}; check may override only an edition lite app to full`,
89
- );
90
-
91
- const full = fullEditionDeclaration(declaration, manifest);
92
- const tracked = trackedFiles(repoRoot);
93
- // A lite app scaffolded before the 2026-10-12 ruling has no Jest preset installed. The upgrade model carries the preset's public sync inputs
94
- // specifically so both the dry full-edition view and the upgrade plan render the same targets before dependencies are added.
95
- const resolvedPresets = presets ?? UPGRADE_PRESETS;
96
- const managed = renderTargets(full, resolvedPresets, { manifest, source: { ...appSource(repoRoot), stack: readDeclaredStack(repoRoot) } });
97
- const extra = [
98
- ...fullManagedFindings(repoRoot, managed),
99
- ...(await checkDatabase({ repoRoot, files: tracked })),
100
- ...(await formatFindings({ repoRoot, files: tracked, prettier })),
101
- ];
102
- const runs = [];
103
- for (const side of ["be", "fe"]) {
104
- const report = checkArchitecture({
105
- repositoryRoot: path.join(repoRoot, side),
106
- hfs: openHfs({ manifest, declaration: full, side }),
107
- surface: "check",
108
- });
109
- runs.push({
110
- side,
111
- status: "ran",
112
- files: report.files,
113
- kinds: report.kinds,
114
- });
115
- extra.push(
116
- ...report.errors.map((item) => machineFinding(side, item)),
117
- ...report.violations.map((item) => machineFinding(side, item)),
118
- );
119
- }
120
- const result = checkRepo({
121
- repoRoot,
122
- declaration: full,
123
- files: tracked,
124
- extraFindings: extra,
125
- manifest,
126
- surface: "check",
127
- tree: true,
128
- });
129
- return {
130
- ...result,
131
- machine: {
132
- status: "ran",
133
- files: runs.reduce((sum, run) => sum + run.files, 0),
134
- kinds: [...new Set(runs.flatMap((run) => run.kinds))],
135
- sides: runs,
136
- },
137
- editionOverride: { declared: actual, judged: edition },
138
- };
11
+ throw new UpgradeError("HFS_EDITION_INVALID", `--edition is ${JSON.stringify(edition)}; expected full or lite`);
12
+ const actual = loadHfs(repoRoot, manifest).edition ?? "full";
13
+ if (edition !== actual)
14
+ throw new UpgradeError("HFS_EDITION_INVALID", `hfs.json edition is ${actual}; editions are fixed at scaffold, so check judges only the declared edition`);
15
+ return normal();
139
16
  }
@@ -1,21 +1,6 @@
1
- // Authored-file preservation, snapshots and rollback for an additive edition upgrade.
1
+ // Snapshots and rollback for the additive completion of a full app.
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
- import { dockerfilePath } from "../runtime/scripts/hfs/rules/docker.mjs";
5
-
6
- /** App-owned additions are preserved; only declared regular optional front-end images receive that treatment. */
7
- export function authoredAdditionReasons(declaration, source) {
8
- const reasons = new Map([[
9
- ".starcistacks/application-stacks.yaml",
10
- "The app already declares its stacks; the declaration stays as the app wrote it.",
11
- ]]);
12
- for (const app of declaration.sides.fe.apps) {
13
- const file = dockerfilePath("fe", app.name);
14
- if (source.hasImage(file)) reasons.set(file,
15
- "The lite app already authors this optional front-end image; its Dockerfile stays as the app wrote it.");
16
- }
17
- return reasons;
18
- }
19
4
 
20
5
  export function remember(snapshot, target) {
21
6
  if (snapshot.has(target)) return;