@starci/hfs 4.0.7 → 4.0.9

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 (704) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +86 -43
  3. package/emit/contracts.mjs +56 -9
  4. package/emit/db-types.mjs +169 -0
  5. package/emit/events.mjs +41 -0
  6. package/emit/operations-worker.mjs +1 -1
  7. package/emit/operations.mjs +2 -2
  8. package/emit/schema-worker.mjs +1 -1
  9. package/lint/bound-sys.cjs +50 -0
  10. package/lint/run.mjs +54 -20
  11. package/package.json +14 -9
  12. package/report/sonar.mjs +8 -8
  13. package/runtime/engine/config.mjs +494 -0
  14. package/runtime/engine/invalid-config.mjs +15 -0
  15. package/runtime/engine/orca-config.mjs +27 -0
  16. package/runtime/engine/runtime-root.mjs +5 -0
  17. package/runtime/engine/yaml.mjs +3 -3
  18. package/runtime/knowledge/hfs/canon-pins.yaml +163 -32
  19. package/runtime/knowledge/hfs/peer-integrations.yaml +2 -2
  20. package/runtime/knowledge/hfs/rules.yaml +2059 -0
  21. package/runtime/knowledge/hfs/slots.yaml +915 -123
  22. package/runtime/knowledge/patterns/be/api.yaml +369 -0
  23. package/runtime/knowledge/patterns/be/cli.yaml +297 -0
  24. package/runtime/knowledge/patterns/be/domain.yaml +113 -0
  25. package/runtime/knowledge/patterns/be/event-bus.yaml +285 -0
  26. package/runtime/knowledge/patterns/be/jobs.yaml +261 -0
  27. package/runtime/knowledge/patterns/be/projections.yaml +178 -0
  28. package/runtime/knowledge/patterns/be/queues.yaml +236 -0
  29. package/runtime/knowledge/patterns/be/reactors.yaml +140 -0
  30. package/runtime/knowledge/patterns/be/realtime.yaml +222 -0
  31. package/runtime/knowledge/patterns/be/saga.yaml +248 -0
  32. package/runtime/knowledge/patterns/be/webhooks.yaml +221 -0
  33. package/runtime/knowledge/patterns/fe/folder.yaml +133 -27
  34. package/runtime/knowledge/sonar-gate.yaml +53 -19
  35. package/runtime/modules/kernel/failure-codes.yaml +580 -50
  36. package/runtime/modules/models/registry.yaml +591 -0
  37. package/runtime/modules/models/runtimes.yaml +701 -0
  38. package/runtime/scripts/api/fs/forbidden-root.mjs +51 -0
  39. package/runtime/scripts/api/fs/is-link-like.mjs +25 -0
  40. package/runtime/scripts/api/fs/lib.mjs +14 -0
  41. package/runtime/scripts/api/fs/safe-remove.mjs +104 -0
  42. package/runtime/scripts/api/git/config-get.mjs +10 -0
  43. package/runtime/scripts/api/git/diff.mjs +5 -0
  44. package/runtime/scripts/api/git/lib.mjs +17 -27
  45. package/runtime/scripts/api/git/log.mjs +5 -0
  46. package/runtime/scripts/api/git/ls-files.mjs +6 -0
  47. package/runtime/scripts/api/git/ls-tree.mjs +5 -0
  48. package/runtime/scripts/api/git/merge-base.mjs +9 -0
  49. package/runtime/scripts/api/git/remote.mjs +5 -0
  50. package/runtime/scripts/api/git/rev-parse-query.mjs +5 -0
  51. package/runtime/scripts/api/git/show.mjs +6 -0
  52. package/runtime/scripts/api/sops/decrypt.mjs +10 -6
  53. package/runtime/scripts/api/sops/lib.mjs +35 -0
  54. package/runtime/scripts/api/sops/seal.mjs +18 -0
  55. package/runtime/scripts/{lib/hfs-allows.mjs → hfs/allows.mjs} +3 -3
  56. package/runtime/scripts/hfs/architecture/ast-walks.mjs +220 -0
  57. package/runtime/scripts/{checks → hfs}/architecture/backend.mjs +17 -24
  58. package/runtime/scripts/{checks → hfs}/architecture/background-unowned.mjs +16 -34
  59. package/runtime/scripts/{checks → hfs}/architecture/client-reaches-server.mjs +3 -1
  60. package/runtime/scripts/{checks → hfs}/architecture/clones.mjs +4 -4
  61. package/runtime/scripts/{checks → hfs}/architecture/config.mjs +11 -8
  62. package/runtime/scripts/{checks → hfs}/architecture/connection-map.mjs +21 -9
  63. package/runtime/scripts/hfs/architecture/context-coupling.mjs +88 -0
  64. package/runtime/scripts/hfs/architecture/context-map.mjs +237 -0
  65. package/runtime/scripts/hfs/architecture/context-owner.mjs +82 -0
  66. package/runtime/scripts/hfs/architecture/context-platform-tables.mjs +47 -0
  67. package/runtime/scripts/hfs/architecture/context-transaction.mjs +60 -0
  68. package/runtime/scripts/{checks → hfs}/architecture/contract-fixture-guard.mjs +5 -11
  69. package/runtime/scripts/{checks → hfs}/architecture/contracts.mjs +33 -162
  70. package/runtime/scripts/{checks → hfs}/architecture/dead-exports.mjs +58 -29
  71. package/runtime/scripts/{checks → hfs}/architecture/doc-language.mjs +1 -1
  72. package/runtime/scripts/{checks → hfs}/architecture/entrypoint.mjs +2 -1
  73. package/runtime/scripts/{checks → hfs}/architecture/fe-slot-allows.mjs +4 -4
  74. package/runtime/scripts/{checks → hfs}/architecture/feature-shape.mjs +6 -3
  75. package/runtime/scripts/{checks → hfs}/architecture/framework-pinned.mjs +1 -1
  76. package/runtime/scripts/{checks → hfs}/architecture/frontend.mjs +17 -43
  77. package/runtime/scripts/{checks → hfs}/architecture/hfs-graph.mjs +1 -1
  78. package/runtime/scripts/{checks → hfs}/architecture/hfs.mjs +27 -42
  79. package/runtime/scripts/{checks → hfs}/architecture/i18n-keys.mjs +1 -1
  80. package/runtime/scripts/{checks → hfs}/architecture/index.mjs +17 -4
  81. package/runtime/scripts/{checks → hfs}/architecture/machine-ast.mjs +44 -11
  82. package/runtime/scripts/hfs/architecture/managed-scripts.mjs +27 -0
  83. package/runtime/scripts/{checks → hfs}/architecture/module-per-transport.mjs +30 -6
  84. package/runtime/scripts/hfs/architecture/next-data-contract.mjs +96 -0
  85. package/runtime/scripts/{checks → hfs}/architecture/next-data.mjs +40 -168
  86. package/runtime/scripts/{checks → hfs}/architecture/owners.mjs +35 -15
  87. package/runtime/scripts/{checks → hfs}/architecture/register-once.mjs +2 -1
  88. package/runtime/scripts/{checks → hfs}/architecture/registration.mjs +23 -81
  89. package/runtime/scripts/{checks → hfs}/architecture/required-files.mjs +21 -13
  90. package/runtime/scripts/{checks → hfs}/architecture/schema-owner.mjs +17 -114
  91. package/runtime/scripts/hfs/architecture/server-action.mjs +24 -0
  92. package/runtime/scripts/hfs/architecture/side-boundary.mjs +16 -0
  93. package/runtime/scripts/{checks → hfs}/architecture/source-names.mjs +27 -147
  94. package/runtime/scripts/{checks → hfs}/architecture/sql-owner.mjs +59 -18
  95. package/runtime/scripts/hfs/architecture/sql-returning.mjs +64 -0
  96. package/runtime/scripts/hfs/architecture/supabase-ast.mjs +111 -0
  97. package/runtime/scripts/hfs/architecture/supabase-be.mjs +131 -0
  98. package/runtime/scripts/hfs/architecture/supabase-tables.mjs +42 -0
  99. package/runtime/scripts/hfs/architecture/supabase.mjs +434 -0
  100. package/runtime/scripts/{checks → hfs}/architecture/surface.mjs +10 -4
  101. package/runtime/scripts/{checks → hfs}/architecture/test-world-files.mjs +11 -21
  102. package/runtime/scripts/{checks → hfs}/architecture/tiers.mjs +47 -5
  103. package/runtime/scripts/{checks → hfs}/architecture/transport-owner.mjs +3 -3
  104. package/runtime/scripts/{checks → hfs}/architecture/typescript.mjs +13 -27
  105. package/runtime/scripts/{checks → hfs}/architecture.mjs +5 -5
  106. package/runtime/scripts/{lib/hfs-check.mjs → hfs/check.mjs} +95 -84
  107. package/runtime/scripts/hfs/coverage-scope.mjs +162 -0
  108. package/runtime/scripts/hfs/declaration-shape.mjs +62 -0
  109. package/runtime/scripts/hfs/declaration-slots.mjs +75 -0
  110. package/runtime/scripts/hfs/edition-slots.mjs +66 -0
  111. package/runtime/scripts/hfs/manifest-shape.mjs +247 -0
  112. package/runtime/scripts/hfs/param-names.mjs +18 -0
  113. package/runtime/scripts/{lib/hfs-path-findings.mjs → hfs/path-findings.mjs} +7 -7
  114. package/runtime/scripts/{lib → hfs}/repo-identity.mjs +9 -6
  115. package/runtime/scripts/hfs/rule-params-shape.mjs +50 -0
  116. package/runtime/scripts/hfs/rules/app-root.mjs +51 -0
  117. package/runtime/scripts/hfs/rules/cli.mjs +37 -0
  118. package/runtime/scripts/hfs/rules/contract-compat.mjs +71 -0
  119. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/contract.mjs +11 -9
  120. package/runtime/scripts/hfs/rules/database-config.mjs +102 -0
  121. package/runtime/scripts/hfs/rules/database-constants.mjs +13 -0
  122. package/runtime/scripts/hfs/rules/database-migrations.mjs +111 -0
  123. package/runtime/scripts/hfs/rules/database-plpgsql.mjs +233 -0
  124. package/runtime/scripts/hfs/rules/database-sql.mjs +336 -0
  125. package/runtime/scripts/hfs/rules/database.mjs +68 -0
  126. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/deps.mjs +1 -1
  127. package/runtime/scripts/hfs/rules/docker.mjs +259 -0
  128. package/runtime/scripts/hfs/rules/edition.mjs +111 -0
  129. package/runtime/scripts/hfs/rules/event-bus.mjs +153 -0
  130. package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +66 -0
  131. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/fe-no-tests.mjs +6 -5
  132. package/runtime/scripts/{lib/hfs-rules/frontend.mjs → hfs/rules/frontend-tree.mjs} +9 -9
  133. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/integration-specs.mjs +3 -6
  134. package/runtime/scripts/hfs/rules/kinds.mjs +84 -0
  135. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/lint-suppression.mjs +1 -1
  136. package/runtime/scripts/hfs/rules/monorepo.mjs +179 -0
  137. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/peer-integrations.mjs +3 -3
  138. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/pipeline.mjs +11 -21
  139. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/proof-commands.mjs +2 -2
  140. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/read.mjs +1 -1
  141. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/repo-local-checks.mjs +2 -2
  142. package/runtime/scripts/hfs/rules/saga.mjs +170 -0
  143. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/secrets.mjs +4 -4
  144. package/runtime/scripts/hfs/rules/services.mjs +220 -0
  145. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/spec-placement.mjs +1 -1
  146. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/stacks.mjs +5 -5
  147. package/runtime/scripts/hfs/rules/supabase-secrets.mjs +89 -0
  148. package/runtime/scripts/{lib/hfs-rules → hfs/rules}/test-topology.mjs +2 -2
  149. package/runtime/scripts/hfs/secret.mjs +175 -0
  150. package/runtime/scripts/{lib/hfs-slots.mjs → hfs/slots.mjs} +114 -150
  151. package/runtime/scripts/hfs/sql/pg-parse.mjs +46 -0
  152. package/runtime/scripts/hfs/test-world-slot.mjs +6 -0
  153. package/runtime/scripts/{lib/hfs-tree.mjs → hfs/tree.mjs} +6 -5
  154. package/runtime/scripts/{checks → hfs}/typescript-programs.mjs +0 -5
  155. package/runtime/scripts/{lib/hfs-view.mjs → hfs/view.mjs} +6 -5
  156. package/runtime/scripts/lib/dockerfile.mjs +124 -0
  157. package/runtime/scripts/lib/env.mjs +10 -0
  158. package/runtime/scripts/lib/event-contract.mjs +103 -0
  159. package/runtime/scripts/lib/git.mjs +36 -0
  160. package/runtime/scripts/lib/graphql-contract.mjs +429 -0
  161. package/runtime/scripts/lib/i18n.mjs +86 -0
  162. package/runtime/scripts/lib/is-main.mjs +13 -0
  163. package/runtime/scripts/lib/json.mjs +13 -3
  164. package/runtime/scripts/lib/language.mjs +26 -7
  165. package/runtime/scripts/lib/list.mjs +20 -0
  166. package/runtime/scripts/lib/package-at.mjs +37 -0
  167. package/runtime/scripts/lib/path-key.mjs +59 -2
  168. package/runtime/scripts/lib/read-text.mjs +34 -0
  169. package/runtime/scripts/lib/regex.mjs +4 -0
  170. package/runtime/scripts/lib/same-text.mjs +5 -0
  171. package/runtime/scripts/lib/secret-patterns.mjs +4 -3
  172. package/runtime/scripts/lib/sleep-sync.mjs +2 -1
  173. package/runtime/scripts/lib/sops-envelope.mjs +58 -0
  174. package/runtime/scripts/lib/stack-declaration.mjs +2 -2
  175. package/runtime/scripts/lib/stack-services.mjs +7 -31
  176. package/runtime/scripts/lib/ts-ast.mjs +35 -0
  177. package/runtime/scripts/{checks/common.mjs → lib/walk.mjs} +5 -15
  178. package/scaffold/add-app.mjs +174 -0
  179. package/scaffold/add-cli-lite.mjs +257 -0
  180. package/scaffold/add-inbox-lite.mjs +314 -0
  181. package/scaffold/add-table.mjs +344 -0
  182. package/scaffold/add.mjs +299 -0
  183. package/scaffold/app.mjs +359 -70
  184. package/scaffold/edition-gate.mjs +25 -0
  185. package/scaffold/image.mjs +19 -0
  186. package/scaffold/lite-exports.mjs +186 -0
  187. package/scaffold/service.mjs +33 -27
  188. package/scaffold/supabase-ports.mjs +26 -0
  189. package/src/main.mjs +327 -0
  190. package/sync/cli.mjs +6 -9
  191. package/sync/format.mjs +1 -1
  192. package/sync/hygiene.mjs +17 -17
  193. package/sync/index.mjs +171 -71
  194. package/sync/managed.mjs +19 -11
  195. package/sync/sonar-key.mjs +5 -0
  196. package/templates/app/ci-workflows/github/workflows/ci.yml +14 -14
  197. package/templates/app/ci-workflows/github/workflows/images.yml +37 -0
  198. package/templates/app/ci-workflows/sonar-steps.yml +9 -0
  199. package/templates/app/ci-workflows-lite/github/workflows/ci.yml +66 -0
  200. package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +31 -0
  201. package/templates/app/ci-workflows-lite/github/workflows/images.yml +37 -0
  202. package/templates/app/codegen-lite/scripts/codegen.mjs +32 -0
  203. package/templates/app/docker-ignore/dockerignore +50 -0
  204. package/templates/app/gitignore-lite +35 -0
  205. package/templates/app/hooks/husky/pre-commit +3 -8
  206. package/templates/app/hooks/husky/pre-push +45 -6
  207. package/templates/app/package-scripts/core.json +8 -0
  208. package/templates/app/package-scripts/package.json +3 -10
  209. package/templates/app/package-scripts-lite/package.json +15 -0
  210. package/templates/app/quality-config/codecov.yml +15 -3
  211. package/templates/app/quality-config/sonar-base.properties +4 -0
  212. package/templates/app/quality-config/sonar-project.properties +2 -5
  213. package/templates/app/quality-config-lite/sonar-project.properties +5 -0
  214. package/templates/app/skeleton/.starcistacks/dev/seeds/primary-notes.sql +5 -0
  215. package/templates/app/skeleton/.starciwork/features/system-health/index.yaml +4 -0
  216. package/templates/app/skeleton/.starciwork/{features/index.yaml → index.yaml} +2 -2
  217. package/templates/app/skeleton/README.md +7 -5
  218. package/templates/app/skeleton-lite/.sops.yaml +3 -0
  219. package/templates/app/skeleton-lite/.starcistacks/dev/environment.json +5 -0
  220. package/templates/app/skeleton-lite/.starcistacks/dev/secrets/.gitkeep +1 -0
  221. package/templates/app/skeleton-lite/.starciwork/shell/index.yaml +55 -0
  222. package/templates/app/skeleton-lite/README.md +40 -0
  223. package/templates/app/skeleton-lite/supabase/config.toml +41 -0
  224. package/templates/app/skeleton-lite/supabase/migrations/__timestamp___baseline.sql +56 -0
  225. package/templates/app/skeleton-lite/supabase/seed.sql +0 -0
  226. package/templates/app/task-graph/turbo.json +23 -0
  227. package/templates/app/tool-config-lite/prettierignore +2 -0
  228. package/templates/app/tool-config-lite/prettierrc +1 -0
  229. package/templates/app/upgrade-full/.starcistacks/application-stacks.yaml +38 -0
  230. package/templates/app/upgrade-full/.starcistacks/dev/README.md +10 -0
  231. package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/api.yaml +13 -0
  232. package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/compose.yaml +3 -0
  233. package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/postgres.yaml +12 -0
  234. package/templates/app/upgrade-full/.starcistacks/dev/infra/metadata.json +7 -0
  235. package/templates/be/common/main-listen.ts.partial +14 -0
  236. package/templates/be/common/sql-ident.ts.partial +7 -0
  237. package/templates/be/common/sql-tag.ts.partial +5 -0
  238. package/templates/be/image/api/Dockerfile +38 -0
  239. package/templates/be/image/cli/Dockerfile +38 -0
  240. package/templates/be/image/worker/Dockerfile +36 -0
  241. package/templates/be/inbox/database-client.ts.tpl +50 -0
  242. package/templates/be/inbox/index.ts.tpl +2 -0
  243. package/templates/be/inbox/migration.sql.tpl +29 -0
  244. package/templates/be/inbox/module-definition.ts.tpl +6 -0
  245. package/templates/be/inbox/module.ts.tpl +14 -0
  246. package/templates/be/inbox/options.ts.tpl +2 -0
  247. package/templates/be/inbox/service.ts.tpl +33 -0
  248. package/templates/be/inbox/sql.ts.tpl +16 -0
  249. package/templates/be/inbox/webhook-door.ts.tpl +36 -0
  250. package/templates/be/patterns/api/application.command.http.ts.tpl +10 -0
  251. package/templates/be/patterns/api/application.command.ts.tpl +10 -0
  252. package/templates/be/patterns/api/application.contracts.ts.tpl +11 -0
  253. package/templates/be/patterns/api/application.handler.http.ts.tpl +22 -0
  254. package/templates/be/patterns/api/application.handler.ts.tpl +22 -0
  255. package/templates/be/patterns/api/feature.index.http.ts.tpl +1 -0
  256. package/templates/be/patterns/api/feature.index.ts.tpl +1 -0
  257. package/templates/be/patterns/api/feature.module.ts.tpl +6 -0
  258. package/templates/be/patterns/api/graphql.input.ts.tpl +13 -0
  259. package/templates/be/patterns/api/graphql.mapper.ts.tpl +9 -0
  260. package/templates/be/patterns/api/graphql.module.ts.tpl +7 -0
  261. package/templates/be/patterns/api/graphql.resolver.ts.tpl +27 -0
  262. package/templates/be/patterns/api/graphql.type.ts.tpl +9 -0
  263. package/templates/be/patterns/api/http.controller.ts.tpl +27 -0
  264. package/templates/be/patterns/api/http.mapper.ts.tpl +9 -0
  265. package/templates/be/patterns/api/http.module.ts.tpl +7 -0
  266. package/templates/be/patterns/api/http.request.ts.tpl +10 -0
  267. package/templates/be/patterns/api/http.response.ts.tpl +5 -0
  268. package/templates/be/patterns/cli/group.cli.spec.ts.tpl +15 -0
  269. package/templates/be/patterns/cli/group.cli.ts.tpl +11 -0
  270. package/templates/be/patterns/cli/group.module.ts.tpl +7 -0
  271. package/templates/be/patterns/cli/sub.run.cli.spec.ts.tpl +17 -0
  272. package/templates/be/patterns/cli/sub.run.cli.ts.tpl +15 -0
  273. package/templates/be/patterns/event-bus/platform/errors/event-bus.error.ts.tpl +22 -0
  274. package/templates/be/patterns/event-bus/platform/event-bus.config.ts.tpl +19 -0
  275. package/templates/be/patterns/event-bus/platform/event-bus.contracts.ts.tpl +58 -0
  276. package/templates/be/patterns/event-bus/platform/event-bus.decorators.ts.tpl +46 -0
  277. package/templates/be/patterns/event-bus/platform/event-bus.log-events.ts.tpl +12 -0
  278. package/templates/be/patterns/event-bus/platform/event-bus.module-definition.ts.tpl +10 -0
  279. package/templates/be/patterns/event-bus/platform/event-bus.module.ts.tpl +52 -0
  280. package/templates/be/patterns/event-bus/platform/event-bus.options.ts.tpl +19 -0
  281. package/templates/be/patterns/event-bus/platform/event-bus.port.ts.tpl +28 -0
  282. package/templates/be/patterns/event-bus/platform/event-bus.service.spec.ts.tpl +165 -0
  283. package/templates/be/patterns/event-bus/platform/event-bus.service.ts.tpl +93 -0
  284. package/templates/be/patterns/event-bus/platform/event-envelope.policy.spec.ts.tpl +90 -0
  285. package/templates/be/patterns/event-bus/platform/event-envelope.policy.ts.tpl +58 -0
  286. package/templates/be/patterns/event-bus/platform/event-relay.service.spec.ts.tpl +136 -0
  287. package/templates/be/patterns/event-bus/platform/event-relay.service.ts.tpl +56 -0
  288. package/templates/be/patterns/event-bus/platform/event-runner.service.spec.ts.tpl +272 -0
  289. package/templates/be/patterns/event-bus/platform/event-runner.service.ts.tpl +128 -0
  290. package/templates/be/patterns/event-bus/platform/event-transport.port.ts.tpl +180 -0
  291. package/templates/be/patterns/event-bus/platform/event.policy.spec.ts.tpl +67 -0
  292. package/templates/be/patterns/event-bus/platform/event.policy.ts.tpl +38 -0
  293. package/templates/be/patterns/event-bus/platform/index.ts.tpl +11 -0
  294. package/templates/be/patterns/event-bus/platform/kafka-event-transport.client.spec.ts.tpl +348 -0
  295. package/templates/be/patterns/event-bus/platform/kafka-event-transport.client.ts.tpl +241 -0
  296. package/templates/be/patterns/event-bus/platform/messages/event-bus.messages.ts.tpl +15 -0
  297. package/templates/be/patterns/event-bus/platform/persistence/connection.ts.tpl +8 -0
  298. package/templates/be/patterns/event-bus/platform/persistence/entities/event-outbox.entity.ts.tpl +37 -0
  299. package/templates/be/patterns/event-bus/platform/persistence/event-bus.rows.ts.tpl +11 -0
  300. package/templates/be/patterns/event-bus/platform/persistence/event-bus.sql.ts.tpl +12 -0
  301. package/templates/be/patterns/event-bus/platform/persistence/migrations/1789800009000-create-event-outbox.ts.tpl +26 -0
  302. package/templates/be/patterns/jobs/job.index.ts.tpl +1 -0
  303. package/templates/be/patterns/jobs/job.module.ts.tpl +6 -0
  304. package/templates/be/patterns/jobs/job.processor.ts.tpl +20 -0
  305. package/templates/be/patterns/jobs/job.queue.module.ts.tpl +20 -0
  306. package/templates/be/patterns/jobs/job.step.ts.tpl +19 -0
  307. package/templates/be/patterns/jobs/platform/fenced.processor.spec.ts.tpl +31 -0
  308. package/templates/be/patterns/jobs/platform/fenced.processor.ts.tpl +13 -0
  309. package/templates/be/patterns/jobs/platform/job-claim.service.spec.ts.tpl +150 -0
  310. package/templates/be/patterns/jobs/platform/job-claim.service.ts.tpl +100 -0
  311. package/templates/be/patterns/jobs/platform/job-runner.service.spec.ts.tpl +138 -0
  312. package/templates/be/patterns/jobs/platform/job-runner.service.ts.tpl +69 -0
  313. package/templates/be/patterns/jobs/platform/jobs.config.ts.tpl +11 -0
  314. package/templates/be/patterns/jobs/platform/jobs.contracts.ts.tpl +62 -0
  315. package/templates/be/patterns/jobs/platform/jobs.decorators.ts.tpl +31 -0
  316. package/templates/be/patterns/jobs/platform/jobs.error.ts.tpl +22 -0
  317. package/templates/be/patterns/jobs/platform/jobs.index.ts.tpl +11 -0
  318. package/templates/be/patterns/jobs/platform/jobs.log-events.ts.tpl +9 -0
  319. package/templates/be/patterns/jobs/platform/jobs.messages.ts.tpl +15 -0
  320. package/templates/be/patterns/jobs/platform/jobs.module-definition.ts.tpl +10 -0
  321. package/templates/be/patterns/jobs/platform/jobs.module.ts.tpl +32 -0
  322. package/templates/be/patterns/jobs/platform/jobs.options.ts.tpl +11 -0
  323. package/templates/be/patterns/jobs/platform/jobs.port.ts.tpl +36 -0
  324. package/templates/be/patterns/jobs/platform/persistence.connection.ts.tpl +8 -0
  325. package/templates/be/patterns/jobs/platform/persistence.job.entity.ts.tpl +53 -0
  326. package/templates/be/patterns/jobs/platform/persistence.jobs.rows.ts.tpl +13 -0
  327. package/templates/be/patterns/jobs/platform/persistence.jobs.sql.ts.tpl +33 -0
  328. package/templates/be/patterns/jobs/platform/persistence.migration.ts.tpl +29 -0
  329. package/templates/be/patterns/outbox/platform/index.ts.tpl +2 -0
  330. package/templates/be/patterns/outbox/platform/outbox-relay.policy.spec.ts.tpl +96 -0
  331. package/templates/be/patterns/outbox/platform/outbox-relay.policy.ts.tpl +78 -0
  332. package/templates/be/patterns/outbox/platform/outbox.log-events.ts.tpl +5 -0
  333. package/templates/be/patterns/projections/migration.ts.tpl +18 -0
  334. package/templates/be/patterns/projections/persistence.connection.ts.tpl +8 -0
  335. package/templates/be/patterns/projections/projection.entity.ts.tpl +9 -0
  336. package/templates/be/patterns/projections/projection.index.ts.tpl +3 -0
  337. package/templates/be/patterns/projections/projection.module-definition.ts.tpl +7 -0
  338. package/templates/be/patterns/projections/projection.module.ts.tpl +18 -0
  339. package/templates/be/patterns/projections/projection.options.ts.tpl +2 -0
  340. package/templates/be/patterns/projections/projection.projection.spec.ts.tpl +55 -0
  341. package/templates/be/patterns/projections/projection.projection.ts.tpl +21 -0
  342. package/templates/be/patterns/queues/platform/bullmq-queue-transport.client.spec.ts.tpl +142 -0
  343. package/templates/be/patterns/queues/platform/bullmq-queue-transport.client.ts.tpl +81 -0
  344. package/templates/be/patterns/queues/platform/persistence.connection.ts.tpl +8 -0
  345. package/templates/be/patterns/queues/platform/persistence.migration.ts.tpl +25 -0
  346. package/templates/be/patterns/queues/platform/persistence.queue-outbox.entity.ts.tpl +25 -0
  347. package/templates/be/patterns/queues/platform/persistence.queue.rows.ts.tpl +9 -0
  348. package/templates/be/patterns/queues/platform/persistence.queue.sql.ts.tpl +12 -0
  349. package/templates/be/patterns/queues/platform/queue-outbox.service.spec.ts.tpl +48 -0
  350. package/templates/be/patterns/queues/platform/queue-outbox.service.ts.tpl +17 -0
  351. package/templates/be/patterns/queues/platform/queue-relay.service.spec.ts.tpl +128 -0
  352. package/templates/be/patterns/queues/platform/queue-relay.service.ts.tpl +48 -0
  353. package/templates/be/patterns/queues/platform/queue-transport.port.ts.tpl +115 -0
  354. package/templates/be/patterns/queues/platform/queue-worker.service.spec.ts.tpl +91 -0
  355. package/templates/be/patterns/queues/platform/queue-worker.service.ts.tpl +45 -0
  356. package/templates/be/patterns/queues/platform/queue.config.ts.tpl +15 -0
  357. package/templates/be/patterns/queues/platform/queue.contracts.ts.tpl +31 -0
  358. package/templates/be/patterns/queues/platform/queue.decorators.ts.tpl +45 -0
  359. package/templates/be/patterns/queues/platform/queue.index.ts.tpl +7 -0
  360. package/templates/be/patterns/queues/platform/queue.log-events.ts.tpl +5 -0
  361. package/templates/be/patterns/queues/platform/queue.module-definition.ts.tpl +10 -0
  362. package/templates/be/patterns/queues/platform/queue.module.ts.tpl +62 -0
  363. package/templates/be/patterns/queues/platform/queue.options.ts.tpl +22 -0
  364. package/templates/be/patterns/queues/platform/queue.policy.spec.ts.tpl +19 -0
  365. package/templates/be/patterns/queues/platform/queue.policy.ts.tpl +11 -0
  366. package/templates/be/patterns/queues/platform/queue.port.ts.tpl +14 -0
  367. package/templates/be/patterns/queues/queue.index.ts.tpl +3 -0
  368. package/templates/be/patterns/queues/queue.module.ts.tpl +6 -0
  369. package/templates/be/patterns/queues/queue.queue.ts.tpl +23 -0
  370. package/templates/be/patterns/reactors/application.command.ts.tpl +10 -0
  371. package/templates/be/patterns/reactors/application.contracts.ts.tpl +12 -0
  372. package/templates/be/patterns/reactors/application.handler.ts.tpl +22 -0
  373. package/templates/be/patterns/reactors/consumer.ts.tpl +19 -0
  374. package/templates/be/patterns/reactors/message.module.ts.tpl +20 -0
  375. package/templates/be/patterns/reactors/reactor.index.ts.tpl +1 -0
  376. package/templates/be/patterns/reactors/reactor.module.ts.tpl +6 -0
  377. package/templates/be/patterns/realtime/channel.graphql.module.ts.tpl +6 -0
  378. package/templates/be/patterns/realtime/channel.index.ts.tpl +1 -0
  379. package/templates/be/patterns/realtime/channel.input.ts.tpl +12 -0
  380. package/templates/be/patterns/realtime/channel.subscription.spec.ts.tpl +51 -0
  381. package/templates/be/patterns/realtime/channel.subscription.ts.tpl +32 -0
  382. package/templates/be/patterns/realtime/channel.type.ts.tpl +9 -0
  383. package/templates/be/patterns/saga/saga.compensate.command.ts.tpl +11 -0
  384. package/templates/be/patterns/saga/saga.compensate.contracts.ts.tpl +7 -0
  385. package/templates/be/patterns/saga/saga.compensate.handler.ts.tpl +22 -0
  386. package/templates/be/patterns/saga/saga.compensation.ts.tpl +21 -0
  387. package/templates/be/patterns/saga/saga.complete.command.ts.tpl +11 -0
  388. package/templates/be/patterns/saga/saga.complete.contracts.ts.tpl +7 -0
  389. package/templates/be/patterns/saga/saga.complete.handler.ts.tpl +22 -0
  390. package/templates/be/patterns/saga/saga.done.consumer.ts.tpl +21 -0
  391. package/templates/be/patterns/saga/saga.failed.consumer.ts.tpl +21 -0
  392. package/templates/be/patterns/saga/saga.index.ts.tpl +1 -0
  393. package/templates/be/patterns/saga/saga.message.module.ts.tpl +23 -0
  394. package/templates/be/patterns/saga/saga.module.ts.tpl +20 -0
  395. package/templates/be/patterns/saga/saga.service.spec.ts.tpl +70 -0
  396. package/templates/be/patterns/saga/saga.service.ts.tpl +44 -0
  397. package/templates/be/patterns/saga/saga.state.ts.tpl +14 -0
  398. package/templates/be/patterns/saga/saga.step.ts.tpl +11 -0
  399. package/templates/be/patterns/saga/saga.undo.command.ts.tpl +10 -0
  400. package/templates/be/patterns/saga/saga.undo.contracts.ts.tpl +5 -0
  401. package/templates/be/patterns/saga/saga.undo.handler.ts.tpl +21 -0
  402. package/templates/be/patterns/webhooks/webhook.door.spec.ts.tpl +72 -0
  403. package/templates/be/patterns/webhooks/webhook.door.ts.tpl +36 -0
  404. package/templates/be/patterns/webhooks/webhook.http.module.ts.tpl +6 -0
  405. package/templates/be/patterns/webhooks/webhook.index.ts.tpl +1 -0
  406. package/templates/be/patterns/webhooks/webhook.request.ts.tpl +9 -0
  407. package/templates/be/skeleton/apps/__app__/src/__app__.options.ts +3 -0
  408. package/templates/be/skeleton/apps/__app__/src/app.module.ts +15 -2
  409. package/templates/be/skeleton/apps/__app__/src/main.ts +7 -15
  410. package/templates/be/skeleton/apps/cli/src/app.module.ts +30 -0
  411. package/templates/be/skeleton/apps/cli/src/cli.options.ts +22 -0
  412. package/templates/be/skeleton/apps/cli/src/main.ts +24 -0
  413. package/templates/be/skeleton/src/features/cli/cli.module.ts +7 -0
  414. package/templates/be/skeleton/src/features/cli/index.ts +1 -0
  415. package/templates/be/skeleton/src/features/cli/migrate/migrate.cli.spec.ts +17 -0
  416. package/templates/be/skeleton/src/features/cli/migrate/migrate.cli.ts +15 -0
  417. package/templates/be/skeleton/src/features/cli/migrate/migrate.module.ts +7 -0
  418. package/templates/be/skeleton/src/features/cli/migrate/subs/run.cli.spec.ts +17 -0
  419. package/templates/be/skeleton/src/features/cli/migrate/subs/run.cli.ts +18 -0
  420. package/templates/be/skeleton/src/features/cli/seed/seed.cli.spec.ts +17 -0
  421. package/templates/be/skeleton/src/features/cli/seed/seed.cli.ts +15 -0
  422. package/templates/be/skeleton/src/features/cli/seed/seed.module.ts +7 -0
  423. package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.spec.ts +33 -0
  424. package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.ts +34 -0
  425. package/templates/be/skeleton/src/modules/domain/identity/admission.policy.spec.ts +13 -0
  426. package/templates/be/skeleton/src/modules/domain/identity/auth.guard.spec.ts +40 -0
  427. package/templates/be/skeleton/src/modules/domain/identity/messages/identity.messages.ts +1 -1
  428. package/templates/be/skeleton/src/modules/domain/note/errors/note.error.ts +16 -0
  429. package/templates/be/skeleton/src/modules/domain/note/index.ts +3 -0
  430. package/templates/be/skeleton/src/modules/domain/note/note.contracts.ts +19 -0
  431. package/templates/be/skeleton/src/modules/domain/note/note.decorators.ts +9 -0
  432. package/templates/be/skeleton/src/modules/domain/note/note.module-definition.ts +7 -0
  433. package/templates/be/skeleton/src/modules/domain/note/note.module.ts +19 -0
  434. package/templates/be/skeleton/src/modules/domain/note/note.options.ts +2 -0
  435. package/templates/be/skeleton/src/modules/domain/note/note.service.spec.ts +76 -0
  436. package/templates/be/skeleton/src/modules/domain/note/note.service.ts +37 -0
  437. package/templates/be/skeleton/src/modules/domain/note/persistence/connection.ts +8 -0
  438. package/templates/be/skeleton/src/modules/domain/note/persistence/entities/note.entity.ts +17 -0
  439. package/templates/be/skeleton/src/modules/domain/note/persistence/migrations/1790000000000-init-note.ts +22 -0
  440. package/templates/be/skeleton/src/modules/domain/note/persistence/note.rows.ts +17 -0
  441. package/templates/be/skeleton/src/modules/domain/note/persistence/note.sql.ts +4 -0
  442. package/templates/be/skeleton/src/modules/platform/config/env-source.config.ts +20 -0
  443. package/templates/be/skeleton/src/modules/platform/config/index.ts +1 -1
  444. package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.contracts.ts +18 -0
  445. package/templates/be/skeleton/src/modules/platform/database/connection-source.client.spec.ts +41 -0
  446. package/templates/be/skeleton/src/modules/platform/database/connection-source.client.ts +17 -0
  447. package/templates/be/skeleton/src/modules/platform/database/database.module-definition.ts +13 -0
  448. package/templates/be/skeleton/src/modules/platform/database/database.module.ts +77 -0
  449. package/templates/be/skeleton/src/modules/platform/database/database.options.ts +30 -0
  450. package/templates/be/skeleton/src/modules/platform/database/database.port.ts +65 -0
  451. package/templates/be/skeleton/src/modules/platform/database/database.sql.ts +47 -0
  452. package/templates/be/skeleton/src/modules/platform/database/errors/database.error.ts +16 -0
  453. package/templates/be/skeleton/src/modules/platform/database/index.ts +9 -0
  454. package/templates/be/skeleton/src/modules/platform/database/migrate-connections.client.ts +30 -0
  455. package/templates/be/skeleton/src/modules/platform/database/migration-runner.service.spec.ts +84 -0
  456. package/templates/be/skeleton/src/modules/platform/database/migration-runner.service.ts +23 -0
  457. package/templates/be/skeleton/src/modules/platform/database/primary.config.ts +9 -0
  458. package/templates/be/skeleton/src/modules/platform/database/primary.connection.ts +2 -0
  459. package/templates/be/skeleton/src/modules/platform/database/primary.decorators.ts +10 -0
  460. package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.spec.ts +108 -0
  461. package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.ts +75 -0
  462. package/templates/be/skeleton/src/modules/platform/database/seed-runner.service.spec.ts +88 -0
  463. package/templates/be/skeleton/src/modules/platform/database/seed-runner.service.ts +29 -0
  464. package/templates/be/skeleton/src/modules/platform/errors/errors.filter.spec.ts +48 -0
  465. package/templates/be/skeleton/src/modules/platform/errors/messages/errors.messages.ts +1 -1
  466. package/templates/be/skeleton/src/modules/platform/http-security/errors/http-security.error.ts +12 -0
  467. package/templates/be/skeleton/src/modules/platform/http-security/execution-request.mapper.spec.ts +16 -0
  468. package/templates/be/skeleton/src/modules/platform/http-security/http-security.config.ts +8 -1
  469. package/templates/be/skeleton/src/modules/platform/http-security/http-security.decorators.ts +8 -0
  470. package/templates/be/skeleton/src/modules/platform/http-security/http-security.module.ts +14 -1
  471. package/templates/be/skeleton/src/modules/platform/http-security/http-security.options.ts +12 -0
  472. package/templates/be/skeleton/src/modules/platform/http-security/messages/http-security.messages.ts +10 -2
  473. package/templates/be/skeleton/src/modules/platform/http-security/origin.guard.spec.ts +63 -0
  474. package/templates/be/skeleton/src/modules/platform/http-security/origin.guard.ts +2 -2
  475. package/templates/be/skeleton/src/modules/platform/http-security/rate-limit.guard.spec.ts +108 -0
  476. package/templates/be/skeleton/src/modules/platform/http-security/request-validation.service.spec.ts +39 -0
  477. package/templates/be/skeleton/src/modules/platform/http-security/request-validation.service.ts +25 -0
  478. package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.spec.ts +172 -0
  479. package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.ts +66 -0
  480. package/templates/be/skeleton/src/modules/platform/logging/logging.log-events.ts +3 -1
  481. package/templates/be/skeleton/src/modules/platform/primitives/outcome.mapper.spec.ts +52 -0
  482. package/templates/be/skeleton-lite/apps/api/Dockerfile +37 -0
  483. package/templates/be/skeleton-lite/apps/api/src/api.options.ts +16 -0
  484. package/templates/be/skeleton-lite/apps/api/src/app.module.ts +81 -0
  485. package/templates/be/skeleton-lite/apps/api/src/main.ts +34 -0
  486. package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.ts +14 -0
  487. package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.ts +50 -0
  488. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.contracts.ts +26 -0
  489. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.decorators.ts +19 -0
  490. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.module.ts +26 -0
  491. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.options.ts +7 -0
  492. package/templates/be/skeleton-lite/src/modules/domain/identity/index.ts +6 -0
  493. package/templates/be/skeleton-lite/src/modules/integrations/supabase/errors/supabase.error.ts +19 -0
  494. package/templates/be/skeleton-lite/src/modules/integrations/supabase/index.ts +10 -0
  495. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.client.ts +24 -0
  496. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.config.ts +8 -0
  497. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.decorators.ts +17 -0
  498. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.jwks.ts +32 -0
  499. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.options.ts +24 -0
  500. package/templates/be/skeleton-lite/src/modules/platform/cqrs/index.ts +4 -0
  501. package/templates/be/skeleton-lite/src/modules/platform/database/database.module.ts +54 -0
  502. package/templates/be/skeleton-lite/src/modules/platform/database/database.options.ts +23 -0
  503. package/templates/be/skeleton-lite/src/modules/platform/database/database.port.ts +10 -0
  504. package/templates/be/skeleton-lite/src/modules/platform/database/database.sql.ts +49 -0
  505. package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +4 -0
  506. package/templates/be/skeleton-lite/src/modules/platform/database/migration-runner.service.ts +21 -0
  507. package/templates/be/skeleton-lite/src/modules/platform/database/primary.config.ts +11 -0
  508. package/templates/be/skeleton-lite/src/modules/platform/database/seed-runner.service.ts +28 -0
  509. package/templates/be/skeleton-lite/src/modules/platform/http-security/http-security.module.ts +25 -0
  510. package/templates/be/skeleton-lite/src/modules/platform/http-security/index.ts +9 -0
  511. package/templates/be/skeleton-lite/src/modules/platform/i18n/index.ts +4 -0
  512. package/templates/be/skeleton-lite/src/modules/platform/logging/index.ts +5 -0
  513. package/templates/be/table/error.ts.tpl +16 -0
  514. package/templates/be/table/index.ts.tpl +2 -0
  515. package/templates/be/table/migration.sql.tpl +51 -0
  516. package/templates/be/table/module-definition.ts.tpl +7 -0
  517. package/templates/be/table/module.ts.tpl +14 -0
  518. package/templates/be/table/options.ts.tpl +2 -0
  519. package/templates/be/table/rows.ts.tpl +4 -0
  520. package/templates/be/table/service.ts.tpl +23 -0
  521. package/templates/be/table/sql.ts.tpl +4 -0
  522. package/templates/be/tool-config/jest.config.js +3 -1
  523. package/templates/be/upgrade-full/apps/cli/src/app.module.ts +14 -0
  524. package/templates/be/upgrade-full/apps/cli/src/main.ts +26 -0
  525. package/templates/be/upgrade-full/src/features/cli/cli.module.ts +6 -0
  526. package/templates/be/upgrade-full/src/features/cli/migrate/subs/run.cli.ts +23 -0
  527. package/templates/common/gitignore.base +1 -2
  528. package/templates/fe/app/package.json.tpl +1 -0
  529. package/templates/fe/app/tsconfig.json +12 -0
  530. package/templates/fe/common/app-layout.tsx.partial +8 -0
  531. package/templates/fe/common/site-shell.tsx.partial +9 -0
  532. package/templates/fe/image/next/Dockerfile +42 -0
  533. package/templates/fe/skeleton/apps/app/next.config.ts +23 -0
  534. package/templates/fe/skeleton/apps/app/postcss.config.mjs +7 -0
  535. package/templates/fe/skeleton/apps/{__app__ → app}/src/app/[locale]/error.tsx +3 -3
  536. package/templates/fe/skeleton/apps/app/src/app/[locale]/layout.tsx +22 -0
  537. package/templates/fe/skeleton/apps/{__app__ → app}/src/app/[locale]/loading.tsx +2 -2
  538. package/templates/fe/skeleton/apps/{__app__ → app}/src/app/[locale]/not-found.tsx +2 -2
  539. package/templates/fe/skeleton/apps/app/src/app/[locale]/page.tsx +9 -0
  540. package/templates/fe/skeleton/apps/{__app__ → app}/src/app/global-error.tsx +2 -2
  541. package/templates/fe/skeleton/apps/app/src/app/globals.css +10 -0
  542. package/templates/fe/skeleton/apps/app/src/features/layouts/AppLayout/index.tsx +18 -0
  543. package/templates/fe/skeleton/apps/app/src/features/pages/AppErrorPage/component.tsx +19 -0
  544. package/templates/fe/skeleton/apps/app/src/features/pages/AppErrorPage/index.tsx +11 -0
  545. package/templates/fe/skeleton/apps/app/src/features/pages/AppGlobalErrorPage/index.tsx +16 -0
  546. package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/component.tsx +10 -0
  547. package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/index.tsx +15 -0
  548. package/templates/fe/skeleton/apps/app/src/features/pages/AppLoadingPage/index.tsx +8 -0
  549. package/templates/fe/skeleton/apps/app/src/features/pages/AppNotFoundPage/index.tsx +9 -0
  550. package/templates/fe/skeleton/apps/app/src/modules/i18n/index.ts +4 -0
  551. package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/vi.json +28 -0
  552. package/templates/fe/skeleton/apps/app/src/modules/i18n/request.ts +4 -0
  553. package/templates/fe/skeleton/apps/app/src/modules/routes/index.ts +4 -0
  554. package/templates/fe/skeleton/apps/app/src/proxy.ts +1 -0
  555. package/templates/fe/skeleton/apps/landing/next.config.ts +21 -0
  556. package/templates/fe/skeleton/apps/landing/postcss.config.mjs +7 -0
  557. package/templates/fe/skeleton/apps/landing/src/app/[locale]/error.tsx +10 -0
  558. package/templates/fe/skeleton/apps/landing/src/app/[locale]/layout.tsx +22 -0
  559. package/templates/fe/skeleton/apps/landing/src/app/[locale]/loading.tsx +6 -0
  560. package/templates/fe/skeleton/apps/landing/src/app/[locale]/not-found.tsx +6 -0
  561. package/templates/fe/skeleton/apps/landing/src/app/[locale]/page.tsx +9 -0
  562. package/templates/fe/skeleton/apps/landing/src/app/global-error.tsx +10 -0
  563. package/templates/fe/skeleton/apps/landing/src/app/globals.css +10 -0
  564. package/templates/fe/skeleton/apps/landing/src/features/layouts/LandingLayout/index.tsx +24 -0
  565. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingErrorPage/component.tsx +18 -0
  566. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingErrorPage/index.tsx +11 -0
  567. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingGlobalErrorPage/index.tsx +16 -0
  568. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingLoadingPage/index.tsx +8 -0
  569. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingNotFoundPage/index.tsx +9 -0
  570. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingPage/component.tsx +24 -0
  571. package/templates/fe/skeleton/apps/landing/src/features/pages/LandingPage/index.tsx +16 -0
  572. package/templates/fe/skeleton/apps/landing/src/modules/config/index.ts +12 -0
  573. package/templates/fe/skeleton/apps/landing/src/modules/i18n/index.ts +7 -0
  574. package/templates/fe/skeleton/apps/landing/src/modules/i18n/messages/vi.json +31 -0
  575. package/templates/fe/skeleton/apps/landing/src/modules/i18n/request.ts +4 -0
  576. package/templates/fe/skeleton/apps/landing/src/modules/routes/index.ts +4 -0
  577. package/templates/fe/skeleton/apps/landing/src/proxy.ts +1 -0
  578. package/templates/fe/skeleton/packages/__project__-i18n/src/index.ts +49 -0
  579. package/templates/fe/skeleton/packages/__project__-i18n/src/proxy.ts +24 -0
  580. package/templates/fe/skeleton/packages/__project__-i18n/src/routing.ts +20 -0
  581. package/templates/fe/skeleton/packages/__project__-ui/src/branches/Providers/index.tsx +23 -0
  582. package/templates/fe/skeleton/packages/__project__-ui/src/composites/ErrorNotice/index.tsx +14 -0
  583. package/templates/fe/skeleton/packages/__project__-ui/src/composites/GlobalErrorNotice/index.tsx +25 -0
  584. package/templates/fe/skeleton/packages/__project__-ui/src/composites/LoadingNotice/index.tsx +9 -0
  585. package/templates/fe/skeleton/packages/__project__-ui/src/composites/LocaleShell/index.tsx +21 -0
  586. package/templates/fe/skeleton/packages/__project__-ui/src/composites/NotFoundNotice/index.tsx +19 -0
  587. package/templates/fe/skeleton/packages/__project__-ui/src/composites/SiteShell/classNames.ts +4 -0
  588. package/templates/fe/skeleton/packages/__project__-ui/src/composites/SiteShell/index.tsx +19 -0
  589. package/templates/fe/skeleton/packages/__project__-ui/src/index.ts +6 -0
  590. package/templates/fe/skeleton-lite/apps/web/next.config.ts +22 -0
  591. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/error.tsx +10 -0
  592. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/layout.tsx +37 -0
  593. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/loading.tsx +6 -0
  594. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/not-found.tsx +6 -0
  595. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/page.tsx +9 -0
  596. package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/providers.tsx +26 -0
  597. package/templates/fe/skeleton-lite/apps/web/src/app/auth/callback/route.ts +24 -0
  598. package/templates/fe/skeleton-lite/apps/web/src/app/global-error.tsx +10 -0
  599. package/templates/fe/{skeleton/apps/__app__ → skeleton-lite/apps/web}/src/app/globals.css +1 -1
  600. package/templates/fe/skeleton-lite/apps/web/src/app/health/live/route.ts +5 -0
  601. package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignInForm/component.tsx +29 -0
  602. package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignInForm/index.tsx +41 -0
  603. package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignOutButton/component.tsx +17 -0
  604. package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignOutButton/index.tsx +38 -0
  605. package/templates/fe/skeleton-lite/apps/web/src/components/composites/ErrorNotice/index.tsx +13 -0
  606. package/templates/fe/skeleton-lite/apps/web/src/components/composites/GlobalErrorNotice/index.tsx +24 -0
  607. package/templates/fe/skeleton-lite/apps/web/src/components/composites/LoadingNotice/index.tsx +7 -0
  608. package/templates/fe/skeleton-lite/apps/web/src/components/composites/NotFoundNotice/index.tsx +18 -0
  609. package/templates/fe/skeleton-lite/apps/web/src/components/composites/SiteShell/classNames.ts +4 -0
  610. package/templates/fe/skeleton-lite/apps/web/src/components/composites/SiteShell/index.tsx +13 -0
  611. package/templates/fe/skeleton-lite/apps/web/src/features/layouts/AppLayout/index.tsx +31 -0
  612. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppErrorPage/component.tsx +12 -0
  613. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppErrorPage/index.tsx +10 -0
  614. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppGlobalErrorPage/index.tsx +15 -0
  615. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/component.tsx +14 -0
  616. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/index.tsx +30 -0
  617. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppLoadingPage/index.tsx +8 -0
  618. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppNotFoundPage/index.tsx +9 -0
  619. package/templates/fe/skeleton-lite/apps/web/src/modules/brand/brand.css +20 -0
  620. package/templates/fe/skeleton-lite/apps/web/src/modules/brand/index.ts +2 -0
  621. package/templates/fe/skeleton-lite/apps/web/src/modules/config/index.ts +20 -0
  622. package/templates/fe/skeleton-lite/apps/web/src/modules/db/auth/read-session.ts +25 -0
  623. package/templates/fe/skeleton-lite/apps/web/src/modules/db/auth/write-sign-in.ts +25 -0
  624. package/templates/fe/skeleton-lite/apps/web/src/modules/db/auth/write-sign-out.ts +17 -0
  625. package/templates/fe/skeleton-lite/apps/web/src/modules/db/browser.ts +14 -0
  626. package/templates/fe/skeleton-lite/apps/web/src/modules/db/index.ts +3 -0
  627. package/templates/fe/skeleton-lite/apps/web/src/modules/db/outcome.ts +59 -0
  628. package/templates/fe/skeleton-lite/apps/web/src/modules/db/principal.ts +29 -0
  629. package/templates/fe/skeleton-lite/apps/web/src/modules/db/server.ts +70 -0
  630. package/templates/fe/skeleton-lite/apps/web/src/modules/db/validation/validation.mapper.ts +50 -0
  631. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/index.ts +8 -0
  632. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/vi.json +48 -0
  633. package/templates/fe/{skeleton/apps/__app__ → skeleton-lite/apps/web}/src/modules/i18n/request.ts +4 -2
  634. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/routing.ts +14 -0
  635. package/templates/fe/skeleton-lite/apps/web/src/modules/routes/index.ts +7 -0
  636. package/templates/fe/skeleton-lite/apps/web/src/modules/routes/safe-next-path.ts +26 -0
  637. package/templates/fe/skeleton-lite/apps/web/src/proxy.ts +43 -0
  638. package/templates/fe/table/read.ts.tpl +16 -0
  639. package/templates/fe/table/write.ts.tpl +16 -0
  640. package/upgrade/check.mjs +137 -0
  641. package/upgrade/index.mjs +524 -0
  642. package/bin/hfs.mjs +0 -233
  643. package/runtime/engine/admission.mjs +0 -284
  644. package/runtime/engine/digest.mjs +0 -10
  645. package/runtime/engine/ledger-db.mjs +0 -1245
  646. package/runtime/engine/machine-db.mjs +0 -1565
  647. package/runtime/engine/migrations/machine/0001-init.sql +0 -887
  648. package/runtime/engine/migrations/machine/0002-worktrees-no-workflow-kind.sql +0 -13
  649. package/runtime/engine/migrations/machine/0003-worktrees-workflow-orca.sql +0 -21
  650. package/runtime/engine/migrations/runtime/0001-init.sql +0 -1072
  651. package/runtime/engine/migrations/runtime/0003-usage-unavailable.sql +0 -13
  652. package/runtime/engine/migrations/runtime/0004-attempt-why.sql +0 -43
  653. package/runtime/engine/migrations/runtime/0005-ended-workflow-views.sql +0 -93
  654. package/runtime/scripts/api/fs/rmdir-link.mjs +0 -12
  655. package/runtime/scripts/lib/artifact-hold.mjs +0 -89
  656. package/runtime/scripts/lib/artifact-store.mjs +0 -103
  657. package/runtime/scripts/lib/redact.mjs +0 -148
  658. package/runtime/scripts/lib/safe-remove.mjs +0 -275
  659. package/runtime/scripts/lib/test-secrets.mjs +0 -116
  660. package/templates/fe/skeleton/apps/__app__/next.config.ts +0 -11
  661. package/templates/fe/skeleton/apps/__app__/src/app/[locale]/layout.tsx +0 -20
  662. package/templates/fe/skeleton/apps/__app__/src/app/[locale]/page.tsx +0 -9
  663. package/templates/fe/skeleton/apps/__app__/src/components/composites/FailureScreen/index.tsx +0 -28
  664. package/templates/fe/skeleton/apps/__app__/src/features/layouts/LocaleShell/index.tsx +0 -35
  665. package/templates/fe/skeleton/apps/__app__/src/features/pages/ErrorPage/component.tsx +0 -21
  666. package/templates/fe/skeleton/apps/__app__/src/features/pages/ErrorPage/index.tsx +0 -17
  667. package/templates/fe/skeleton/apps/__app__/src/features/pages/GlobalErrorPage/component.tsx +0 -26
  668. package/templates/fe/skeleton/apps/__app__/src/features/pages/GlobalErrorPage/index.tsx +0 -15
  669. package/templates/fe/skeleton/apps/__app__/src/features/pages/HomePage/component.tsx +0 -25
  670. package/templates/fe/skeleton/apps/__app__/src/features/pages/HomePage/index.tsx +0 -15
  671. package/templates/fe/skeleton/apps/__app__/src/features/pages/LoadingPage/component.tsx +0 -27
  672. package/templates/fe/skeleton/apps/__app__/src/features/pages/LoadingPage/index.tsx +0 -8
  673. package/templates/fe/skeleton/apps/__app__/src/features/pages/NotFoundPage/component.tsx +0 -32
  674. package/templates/fe/skeleton/apps/__app__/src/features/pages/NotFoundPage/index.tsx +0 -8
  675. package/templates/fe/skeleton/apps/__app__/src/modules/i18n/config.ts +0 -8
  676. package/templates/fe/skeleton/apps/__app__/src/modules/i18n/index.ts +0 -2
  677. package/templates/fe/skeleton/apps/__app__/src/modules/i18n/messages/vi.json +0 -25
  678. package/templates/fe/skeleton/apps/__app__/src/modules/i18n/routing.ts +0 -9
  679. package/templates/fe/skeleton/apps/__app__/src/modules/routes/index.ts +0 -4
  680. package/templates/fe/skeleton/apps/__app__/src/proxy.ts +0 -10
  681. /package/runtime/scripts/{checks → hfs}/architecture/config-unread.mjs +0 -0
  682. /package/runtime/scripts/{checks → hfs}/architecture/constructor-deps.mjs +0 -0
  683. /package/runtime/scripts/{checks → hfs}/architecture/cross-app-duplicate.mjs +0 -0
  684. /package/runtime/scripts/{checks → hfs}/architecture/default-deny.mjs +0 -0
  685. /package/runtime/scripts/{checks → hfs}/architecture/error-codes.mjs +0 -0
  686. /package/runtime/scripts/{checks → hfs}/architecture/error-masked.mjs +0 -0
  687. /package/runtime/scripts/{checks → hfs}/architecture/hooks-are-hooks.mjs +0 -0
  688. /package/runtime/scripts/{checks → hfs}/architecture/injection-token-exported.mjs +0 -0
  689. /package/runtime/scripts/{checks → hfs}/architecture/package-shape.mjs +0 -0
  690. /package/runtime/scripts/{checks → hfs}/architecture/reachability.mjs +0 -0
  691. /package/runtime/scripts/{checks → hfs}/architecture/route-files-thin.mjs +0 -0
  692. /package/runtime/scripts/{checks → hfs}/architecture/sql-tokens.mjs +0 -0
  693. /package/runtime/scripts/{checks → hfs}/architecture/symbols.mjs +0 -0
  694. /package/runtime/scripts/{checks → hfs}/architecture/unit-spec-providers.mjs +0 -0
  695. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/application/check-liveness.contracts.ts +0 -0
  696. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/application/check-liveness.handler.ts +0 -0
  697. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/application/check-liveness.query.ts +0 -0
  698. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/index.ts +0 -0
  699. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/system-health.module.ts +0 -0
  700. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/transport/http/live.controller.ts +0 -0
  701. /package/templates/be/skeleton/src/features/{system-health → api/system-health}/transport/http/system-health-http.module.ts +0 -0
  702. /package/templates/fe/skeleton/apps/{__app__ → app}/src/app/health/live/route.ts +0 -0
  703. /package/templates/fe/skeleton/apps/{__app__ → app}/src/modules/config/index.ts +0 -0
  704. /package/templates/fe/{skeleton/apps/__app__ → skeleton-lite/apps/web}/postcss.config.mjs +0 -0
@@ -1,6 +1,8 @@
1
1
  import path from 'node:path';
2
2
  import { canonical } from './config.mjs';
3
- import { isUnshadowedCommonJsRequire, referencedExports, relativePath, sourceLocation, unwrapExpression } from './typescript.mjs';
3
+ import { referencedExports, relativePath, unwrapExpression } from './typescript.mjs';
4
+ import { commonJsRequireReasons, decoratorCallee, moduleExportsOf, mutableDecoratorKind, normalizedSymbol, normalizedSymbolValue, programSourcesOf, selectedNode, valueSymbol } from './ast-walks.mjs';
5
+ import { sourceLocation } from '../../lib/ts-ast.mjs';
4
6
 
5
7
  const REGISTRATION_RULE_IDS = ['BE_MODULE_HANDLER_REGISTRATION', 'BE_MODULE_PROVIDER_REREGISTRATION'];
6
8
  const FRAMEWORK = new Map([
@@ -9,106 +11,46 @@ const FRAMEWORK = new Map([
9
11
  ['QueryHandler', '@nestjs/cqrs'],
10
12
  ]);
11
13
 
12
- function normalizedSymbolValue(ts, checker, value) {
13
- let symbol = value ?? null;
14
- const seen = new Set();
15
- while (symbol && (symbol.flags & ts.SymbolFlags.Alias) && !seen.has(symbol)) {
16
- seen.add(symbol);
17
- const target = checker.getAliasedSymbol(symbol);
18
- if (!target || target === symbol) break;
19
- symbol = target;
20
- }
21
- return symbol;
22
- }
23
-
24
- function normalizedSymbol(ts, checker, node) {
25
- return normalizedSymbolValue(ts, checker, checker?.getSymbolAtLocation(node) ?? null);
26
- }
27
-
28
- function valueSymbol(ts, checker, node, seen = new Set()) {
29
- const selected = selectedNode(ts, node) ?? node;
30
- const symbol = normalizedSymbol(ts, checker, selected);
31
- if (!symbol || seen.has(symbol)) return symbol;
32
- seen.add(symbol);
33
- const declarations = symbol.getDeclarations?.() ?? [];
34
- if (declarations.length === 1 && ts.isVariableDeclaration(declarations[0]) && declarations[0].initializer
35
- && (ts.getCombinedNodeFlags(declarations[0].parent) & ts.NodeFlags.Const)) {
36
- return valueSymbol(ts, checker, declarations[0].initializer, seen);
37
- }
38
- return symbol;
39
- }
40
-
41
- function calledExpression(ts, decorator) {
42
- const expression = decorator.expression;
43
- return ts.isCallExpression(expression) ? expression.expression : expression;
44
- }
45
-
46
- function selectedNode(ts, expression) {
47
- expression = unwrapExpression(ts, expression);
48
- if (ts.isIdentifier(expression)) return expression;
49
- if (ts.isPropertyAccessExpression(expression)) return expression.name;
50
- if (ts.isElementAccessExpression(expression) && ts.isStringLiteralLike(expression.argumentExpression)) return expression.argumentExpression;
51
- return null;
52
- }
53
-
54
14
  function frameworkDecorator(ts, checker, decorator, targets) {
55
- const selected = selectedNode(ts, calledExpression(ts, decorator));
15
+ const selected = selectedNode(ts, decoratorCallee(ts, decorator));
56
16
  if (!selected) return null;
57
17
  const symbol = valueSymbol(ts, checker, selected);
58
18
  for (const [name, target] of targets) if (symbol === target) return name;
59
19
  return null;
60
20
  }
61
21
 
62
- function mutableFrameworkAlias(ts, checker, decorator, targets) {
63
- const selected = selectedNode(ts, calledExpression(ts, decorator));
64
- const symbol = selected ? normalizedSymbol(ts, checker, selected) : null;
65
- const declarations = symbol?.getDeclarations?.() ?? [];
66
- if (declarations.length !== 1 || !ts.isVariableDeclaration(declarations[0]) || !declarations[0].initializer
67
- || (ts.getCombinedNodeFlags(declarations[0].parent) & ts.NodeFlags.Const)) return null;
68
- const target = valueSymbol(ts, checker, declarations[0].initializer);
69
- for (const [name, expected] of targets) if (target === expected) return name;
70
- return null;
71
- }
22
+ /* This module's framework map keys decorator names, not symbols - invert it (first name wins, as the old
23
+ * `for...of` scan did) for the shared symbol-keyed lookup. */
24
+ const mutableFrameworkAlias = (ts, checker, decorator, targets) => {
25
+ const bySymbol = new Map();
26
+ for (const [name, symbol] of targets) if (!bySymbol.has(symbol)) bySymbol.set(symbol, name);
27
+ return mutableDecoratorKind(ts, checker, decorator, bySymbol);
28
+ };
72
29
 
73
30
  function frameworkTargets(config, context, checker, localFiles) {
74
31
  const targets = new Map();
75
32
  const reasons = [];
76
- const program = context.programs.find(candidate => candidate.getTypeChecker() === checker);
77
- if (!program) return { targets, reasons: ['a TypeScript program checker could not be associated with its source'] };
78
- for (const sourceFile of program.getSourceFiles()) {
79
- if (!localFiles.has(canonical(sourceFile.fileName))) continue;
33
+ const files = programSourcesOf(context, checker, localFiles);
34
+ if (!files) return { targets, reasons: ['a TypeScript program checker could not be associated with its source'] };
35
+ for (const sourceFile of files) {
80
36
  for (const statement of sourceFile.statements) {
81
- const moduleSpecifier = (context.ts.isImportDeclaration(statement) || context.ts.isExportDeclaration(statement))
82
- && statement.moduleSpecifier && context.ts.isStringLiteralLike(statement.moduleSpecifier) ? statement.moduleSpecifier : null;
83
- const importEquals = context.ts.isImportEqualsDeclaration(statement) && context.ts.isExternalModuleReference(statement.moduleReference)
84
- && statement.moduleReference.expression && context.ts.isStringLiteralLike(statement.moduleReference.expression)
85
- ? statement.moduleReference.expression : null;
86
- const specifier = (moduleSpecifier ?? importEquals)?.text;
87
- if (!specifier || ![...FRAMEWORK.values()].includes(specifier)) continue;
88
- const expected = new Set([...FRAMEWORK].filter(([, packageName]) => packageName === specifier).map(([name]) => name));
37
+ const bound = moduleExportsOf(context.ts, checker, statement);
38
+ if (!bound || ![...FRAMEWORK.values()].includes(bound.specifier)) continue;
39
+ const expected = new Set([...FRAMEWORK].filter(([, packageName]) => packageName === bound.specifier).map(([name]) => name));
89
40
  const selected = referencedExports(context.ts, statement, expected);
90
41
  if (!selected.length) continue;
91
- const moduleSymbol = checker.getSymbolAtLocation(moduleSpecifier ?? importEquals);
92
- if (!moduleSymbol) {
93
- reasons.push(`${relativePath(config.root, sourceFile.fileName)} cannot resolve ${specifier}`);
42
+ if (!bound.symbol) {
43
+ reasons.push(`${relativePath(config.root, sourceFile.fileName)} cannot resolve ${bound.specifier}`);
94
44
  continue;
95
45
  }
96
- const exports = new Map(checker.getExportsOfModule(moduleSymbol).map(symbol => [symbol.getName(), normalizedSymbolValue(context.ts, checker, symbol)]));
97
46
  for (const name of selected) {
98
- const target = exports.get(name);
47
+ const target = bound.exports.get(name);
99
48
  if (target) targets.set(name, target);
100
- else reasons.push(`${relativePath(config.root, sourceFile.fileName)} cannot resolve ${name} from ${specifier}`);
49
+ else reasons.push(`${relativePath(config.root, sourceFile.fileName)} cannot resolve ${name} from ${bound.specifier}`);
101
50
  }
102
51
  }
103
- const visitRequire = node => {
104
- if (context.ts.isCallExpression(node) && isUnshadowedCommonJsRequire(context.ts, checker, node.expression)
105
- && node.arguments.length === 1 && context.ts.isStringLiteralLike(node.arguments[0])
106
- && [...FRAMEWORK.values()].includes(node.arguments[0].text)) {
107
- reasons.push(`${relativePath(config.root, sourceFile.fileName)} uses a CommonJS Nest framework binding whose decorator identity cannot be proved`);
108
- }
109
- context.ts.forEachChild(node, visitRequire);
110
- };
111
- visitRequire(sourceFile);
52
+ commonJsRequireReasons(context.ts, checker, sourceFile, (specifier) => [...FRAMEWORK.values()].includes(specifier),
53
+ reasons, relativePath(config.root, sourceFile.fileName), 'whose decorator identity cannot be proved', 'Nest framework binding');
112
54
  }
113
55
  return { targets, reasons };
114
56
  }
@@ -1,35 +1,35 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { gitOutput } from '../../api/git/lib.mjs';
3
+ import { lsFiles } from '../../api/git/ls-files.mjs';
4
+ import { revParseQuery } from '../../api/git/rev-parse-query.mjs';
5
+ import { gitOutputOf } from '../../lib/git.mjs';
4
6
 
5
7
  /**
6
8
  * HFS check 5: the files and directories the slot manifest requires (knowledge/hfs/slots.yaml `requires`,
7
9
  * `requiredInstances`, `minInstances`, required app kinds) must exist in the repository tree. Everything is read through the
8
- * resolver of scripts/lib/hfs-slots.mjs; nothing here names a path.
10
+ * resolver of scripts/hfs/slots.mjs; nothing here names a path.
9
11
  *
10
- * BE_REQUIRED_MODULE_MISSING a backend app, feature, domain, integrations or platform instance lacks a required file or
11
- * directory, or a required platform instance (config, logging, errors, primitives) is absent
12
12
  * FE_ERROR_BOUNDARY_MISSING a fe.app.next app lacks global-error, error, not-found or loading under src/app
13
- * HFS_REQUIRED_FILE_MISSING any other required file or directory (packages, fe modules, i18n, api ...), and a minimum
14
- * (no api app, no feature, no next app) which is reported once at hfs.json
13
+ * HFS_REQUIRED_FILE_MISSING any other required file or directory of any slot (backend app, feature, domain, integrations and
14
+ * platform instances, a required platform instance such as config or logging, packages, fe modules,
15
+ * i18n, api ...), and a minimum (no api app, no feature, no next app) which is reported once at hfs.json
15
16
  *
16
17
  * Slots of tier none (README, root config, .starciwork, .starcistacks) belong to the slot check; fe.app.next is the one
17
18
  * tier-none slot judged here. The tree is the tracked one (`git ls-files` from the repository root, minus files deleted
18
19
  * on disk), else the filesystem without node_modules, .git, dist and .next.
19
20
  */
20
- export const REQUIRED_FILE_RULE_IDS = ['BE_REQUIRED_MODULE_MISSING', 'FE_ERROR_BOUNDARY_MISSING', 'HFS_REQUIRED_FILE_MISSING'];
21
+ export const REQUIRED_FILE_RULE_IDS = ['FE_ERROR_BOUNDARY_MISSING', 'HFS_REQUIRED_FILE_MISSING'];
21
22
 
22
23
  const SKIPPED_DIRECTORIES = new Set(['node_modules', '.git', 'dist', '.next']);
23
24
  const ERROR_BOUNDARY_FILE = /^(?:global-error|error|not-found|loading)\.tsx$/u;
24
- const BACKEND_MODULE_SLOT = /^be\.(?:app|feature|transport|domain|integrations|platform)(?:\.|$)/u;
25
25
  const ALSO_JUDGED_TIER_NONE = new Set(['fe.app.next']);
26
26
 
27
27
  function gitFiles(root) {
28
28
  try {
29
- const run = args => gitOutput(args, { cwd: root, maxBuffer: 256 * 1024 * 1024 });
30
- run(['rev-parse', '--is-inside-work-tree']);
31
- const deleted = new Set(run(['ls-files', '--deleted', '-z', '--', '.']).split('\0').filter(Boolean));
32
- return run(['ls-files', '--cached', '-z', '--', '.']).split('\0').filter(file => file && !deleted.has(file));
29
+ const run = (call, args) => gitOutputOf(call(args, { cwd: root, maxBuffer: 256 * 1024 * 1024 }));
30
+ run(revParseQuery, ['--is-inside-work-tree']);
31
+ const deleted = new Set(run(lsFiles, ['--deleted', '-z', '--', '.']).split('\0').filter(Boolean));
32
+ return run(lsFiles, ['--cached', '-z', '--', '.']).split('\0').filter(file => file && !deleted.has(file));
33
33
  } catch {
34
34
  return null;
35
35
  }
@@ -60,12 +60,20 @@ export function treeOf(root) {
60
60
  return { files, directories };
61
61
  }
62
62
 
63
+ /**
64
+ * The prelude every tree-walking architecture checker shares: the input's config/graph/context, the compiler,
65
+ * the slot resolver and the tracked repository tree.
66
+ */
67
+ export function checkerScope({ config, graph, context }) {
68
+ return { config, graph, context, ts: context.ts, resolver: graph.resolver, tree: treeOf(config.root) };
69
+ }
70
+
63
71
  const strip = entry => entry.replace(/\/+$/u, '');
64
72
  const rootOfTarget = target => (target.endsWith('/') ? strip(target) : (path.posix.dirname(target) === '.' ? '' : path.posix.dirname(target)));
65
73
 
66
74
  function ruleFor(slotId, target, rootExists) {
67
75
  if (slotId === 'fe.app.next' && rootExists && ERROR_BOUNDARY_FILE.test(path.posix.basename(strip(target)))) return 'FE_ERROR_BOUNDARY_MISSING';
68
- return BACKEND_MODULE_SLOT.test(slotId) ? 'BE_REQUIRED_MODULE_MISSING' : 'HFS_REQUIRED_FILE_MISSING';
76
+ return 'HFS_REQUIRED_FILE_MISSING';
69
77
  }
70
78
 
71
79
  export function checkRequiredFiles({ config, graph }) {
@@ -2,6 +2,7 @@ import path from 'node:path';
2
2
  import { machineKit, pascal } from './machine-ast.mjs';
3
3
  import { treeOf } from './required-files.mjs';
4
4
  import { DATABASE_DIR } from './connection-map.mjs';
5
+ import { collectRegistrations, isPerConnection, persistenceOfFactory } from './context-map.mjs';
5
6
 
6
7
  /**
7
8
  * R35 `schema-owner` (BE_SCHEMA_OWNER, BE-CONVENTION 1.4.6). Schema lives with the capability that owns the table:
@@ -11,7 +12,7 @@ import { DATABASE_DIR } from './connection-map.mjs';
11
12
  * folder named `entities` or `migrations` outside be.persistence is refused too;
12
13
  * - `persistence/connection.ts` declares `<c>Entities` / `<c>Migrations`, the arrays the apps register; a capability has no
13
14
  * `CONNECTION` alias (C0 lead decision 2026-09-30): its connection is the one those arrays are REGISTERED on, in the
14
- * `entities` / `migrations` of a connection literal of `DatabaseModule.register` and of the migrate app. The arrays are
15
+ * `entities` / `migrations` of a connection literal of `DatabaseModule.register` and of the cli app. The arrays are
15
16
  * registered under exactly one connection across all apps, that connection is declared in hfs.json, and every
16
17
  * `Inject<Conn>EntityManager()` used inside the capability is that same connection;
17
18
  * - the capability's `index.ts` exports `<c>Entities` when it has entities and `<c>Migrations` when it has migrations
@@ -36,13 +37,7 @@ export function checkSchemaOwner(input) {
36
37
  const report = (file, node, message, extra = {}) => violations.push({ ruleId: RULE, path: file.rel, ...kit.at(file.rel, file.sourceFile, node), message, ...extra });
37
38
  const plain = (rel, message, extra = {}) => violations.push({ ruleId: RULE, path: rel, line: 1, column: 1, message, ...extra });
38
39
 
39
- /** {root, capability, folder, below} of a be.persistence file: `folder` is the directory below persistence/ ('' at its root). */
40
- const persistenceOf = rel => {
41
- const classified = resolver.classifyPath(rel);
42
- if (classified.slot !== PERSISTENCE_SLOT) return null;
43
- const below = rel.slice(classified.root.length + 1).split('/');
44
- return { root: classified.root, capability: path.posix.basename(path.posix.dirname(classified.root)), folder: below.length > 1 ? below[0] : '', below };
45
- };
40
+ const persistenceOf = persistenceOfFactory(resolver);
46
41
 
47
42
  let entities = 0;
48
43
  let migrations = 0;
@@ -80,7 +75,10 @@ export function checkSchemaOwner(input) {
80
75
  const isMigration = heritage(statement).some(expression => kit.isImportOf(checker, expression, 'MigrationInterface', 'typeorm'));
81
76
  if (isEntity) {
82
77
  entities += 1;
83
- if (persistence?.folder !== 'entities') report(file, statement.name, `Entity ${statement.name.text} is declared outside persistence/entities/ of a domain or platform capability; an entity lives with the capability that owns its table, in src/modules/{domain,platform}/<capability>/persistence/entities/<table>.entity.ts.`, { class: statement.name.text });
78
+ // The table of a projection belongs to the projection that alone writes it: `<name>.projection-entity.ts` of slot be.projections.
79
+ const ownProjectionTable = resolver.classifyPath(file.rel).slot === 'be.projections' && file.rel.endsWith('.projection-entity.ts');
80
+ if (ownProjectionTable) note({ root: path.posix.join(path.posix.dirname(file.rel), 'persistence'), capability: path.posix.basename(path.posix.dirname(file.rel)) }, 'entities');
81
+ else if (persistence?.folder !== 'entities') report(file, statement.name, `Entity ${statement.name.text} is declared outside persistence/entities/ of a domain or platform capability; an entity lives with the capability that owns its table, in src/modules/{domain,platform}/<capability>/persistence/entities/<table>.entity.ts.`, { class: statement.name.text });
84
82
  else note(persistence, 'entities');
85
83
  }
86
84
  if (!isMigration) continue;
@@ -100,124 +98,28 @@ export function checkSchemaOwner(input) {
100
98
  }
101
99
  }
102
100
 
103
- // The connection of a capability is where its arrays are registered (no CONNECTION alias in persistence/connection.ts).
104
- const unparen = node => { let current = node; while (current && (ts.isParenthesizedExpression(current) || ts.isAsExpression(current) || ts.isSatisfiesExpression?.(current) || ts.isNonNullExpression(current))) current = current.expression; return current; };
105
- const returned = declaration => {
106
- const fn = ts.isVariableDeclaration(declaration) && declaration.initializer ? unparen(declaration.initializer) : declaration;
107
- if (!(ts.isArrowFunction(fn) || ts.isFunctionDeclaration(fn) || ts.isFunctionExpression(fn) || ts.isMethodDeclaration(fn)) || !fn.body) return null;
108
- if (!ts.isBlock(fn.body)) return fn.body;
109
- const statements = fn.body.statements.filter(ts.isReturnStatement);
110
- return statements.length === 1 ? statements[0].expression ?? null : null;
111
- };
112
- const propertySources = new Map(); // property name -> [{declaration, initializer, checker}] over the program
113
- const assignmentsOf = name => {
114
- if (propertySources.has(name)) return propertySources.get(name);
115
- const list = [];
116
- for (const file of graph.files.values()) {
117
- if (!file.sourceFile.text.includes(name)) continue;
118
- const checker = kit.checkerOf(file.sourceFile);
119
- kit.walk(file.sourceFile, node => {
120
- if (ts.isPropertyAssignment(node) && kit.propertyNameText(node.name) === name && ts.isObjectLiteralExpression(node.parent)) {
121
- // the property of the type the literal is checked against, so a typed const and a typed return meet the same declaration
122
- const contextual = checker.getContextualType(node.parent)?.getProperty(name);
123
- const symbol = contextual ?? checker.getSymbolAtLocation(node.name);
124
- list.push({ declaration: symbol?.declarations?.[0] ?? null, initializer: node.initializer, checker });
125
- }
126
- return true;
127
- });
128
- }
129
- propertySources.set(name, list);
130
- return list;
131
- };
132
- const nameOfLiteral = (checker, literal, depth) => {
133
- const own = kit.propertyOf(literal, 'name');
134
- if (own) return kit.stringValue(checker, kit.valueOfProperty(own));
135
- for (const property of literal.properties) {
136
- if (!ts.isSpreadAssignment(property)) continue;
137
- const value = nameOfExpression(checker, property.expression, depth + 1);
138
- if (value) return value;
139
- }
140
- return null;
141
- };
142
- const nameOfExpression = (checker, expression, depth) => {
143
- const node = unparen(expression);
144
- if (!node || depth > 5) return null;
145
- if (ts.isObjectLiteralExpression(node)) return nameOfLiteral(checker, node, depth);
146
- if (ts.isCallExpression(node)) {
147
- for (const declaration of kit.declarationsOf(checker, node.expression)) {
148
- const body = returned(declaration);
149
- const value = body ? nameOfExpression(kit.checkerOf(declaration.getSourceFile()), body, depth + 1) : null;
150
- if (value) return value;
151
- }
152
- return null;
153
- }
154
- if (ts.isIdentifier(node)) {
155
- const declaration = kit.declarationsOf(checker, node)[0];
156
- return declaration && ts.isVariableDeclaration(declaration) && declaration.initializer ? nameOfExpression(kit.checkerOf(declaration.getSourceFile()), declaration.initializer, depth + 1) : null;
157
- }
158
- if (ts.isPropertyAccessExpression(node)) {
159
- const target = kit.declarationsOf(checker, node.name)[0];
160
- if (!target) return null;
161
- const names = new Set(assignmentsOf(node.name.text).filter(item => item.declaration === target).map(item => nameOfExpression(item.checker, item.initializer, depth + 1)).filter(Boolean));
162
- return names.size === 1 ? [...names][0] : null;
163
- }
164
- return null;
165
- };
166
- /** The capability arrays (`<c>Entities` / `<c>Migrations` of persistence/connection.ts) an expression lists. */
167
- const arraysIn = (checker, expression, out, depth) => {
168
- const node = unparen(expression);
169
- if (!node || depth > 6) return;
170
- if (ts.isArrayLiteralExpression(node)) { for (const element of node.elements) arraysIn(checker, ts.isSpreadElement(element) ? element.expression : element, out, depth + 1); return; }
171
- if (!ts.isIdentifier(node) && !ts.isPropertyAccessExpression(node)) return;
172
- const declaration = kit.declarationsOf(checker, ts.isPropertyAccessExpression(node) ? node.name : node)[0];
173
- if (!declaration || !ts.isVariableDeclaration(declaration) || !ts.isIdentifier(declaration.name)) return;
174
- const rel = kit.graphPath(declaration);
175
- const owner = rel ? persistenceOf(rel) : null;
176
- if (owner && owner.below.length === 1 && owner.below[0] === 'connection.ts' && [`${camel(owner.capability)}Entities`, `${camel(owner.capability)}Migrations`].includes(declaration.name.text)) {
177
- out.push({ key: path.posix.dirname(owner.root), name: owner.capability });
178
- } else if (declaration.initializer) arraysIn(kit.checkerOf(declaration.getSourceFile()), declaration.initializer, out, depth + 1);
179
- };
180
- const registered = new Map(); // capability root -> {name, connections: Map(connection -> first site)}
181
- let registrations = 0;
182
- for (const file of graph.files.values()) {
183
- const checker = kit.checkerOf(file.sourceFile);
184
- kit.walk(file.sourceFile, node => {
185
- if (!ts.isObjectLiteralExpression(node)) return true;
186
- const arrays = [];
187
- for (const key of ['entities', 'migrations']) {
188
- const property = kit.propertyOf(node, key);
189
- if (property) arraysIn(checker, kit.valueOfProperty(property), arrays, 0);
190
- }
191
- if (!arrays.length) return true;
192
- registrations += 1;
193
- const connection = nameOfLiteral(checker, node, 0);
194
- if (connection === null) return true;
195
- for (const { key, name } of new Map(arrays.map(item => [item.key, item])).values()) {
196
- if (!registered.has(key)) registered.set(key, { name, connections: new Map() });
197
- const sites = registered.get(key).connections;
198
- if (!sites.has(connection)) sites.set(connection, { file, node });
199
- }
200
- return true;
201
- });
202
- }
203
- for (const { name, connections: sites } of registered.values()) {
101
+ const { registered, registrations } = collectRegistrations({ kit, graph, persistenceOf });
102
+ for (const [key, { name, connections: sites }] of registered) {
204
103
  for (const [connection, site] of sites) {
205
104
  if (!connections.has(connection)) report(site.file, site.node, `The ${name} capability is registered on connection "${connection}", which hfs.json does not declare (declared: ${[...connections].sort().join(', ') || 'none'}); the tables of a capability live on one declared connection.`, { connection, capability: name });
206
105
  }
207
- if (sites.size > 1) {
106
+ if (sites.size > 1 && !isPerConnection(resolver, key, name)) {
208
107
  const all = [...sites.keys()].sort().join(' and ');
209
108
  for (const [connection, site] of [...sites].slice(1)) report(site.file, site.node, `The ${name} capability's entities and migrations are registered on connections ${all}; a capability's tables live on exactly one connection, so register its arrays under one connection across every app.`, { connection, capability: name });
210
109
  }
211
110
  }
212
111
  for (const [key, kinds] of found) {
213
- if (!registered.get(key)?.connections.size) plain(`${key}/persistence/connection.ts`, `The ${kinds.name} capability has entities or migrations but no app registers them; add ${camel(kinds.name)}Entities and ${camel(kinds.name)}Migrations to a connection of DatabaseModule.register and of the migrate app.`, { capability: kinds.name });
112
+ if (!registered.get(key)?.connections.size) plain(`${key}/persistence/connection.ts`, `The ${kinds.name} capability has entities or migrations but no app registers them; add ${camel(kinds.name)}Entities and ${camel(kinds.name)}Migrations to a connection of DatabaseModule.register and of the cli app.`, { capability: kinds.name });
214
113
  const connectionFile = graph.files.get(`${key}/persistence/connection.ts`);
215
114
  const declared = new Set((connectionFile?.sourceFile.statements.filter(ts.isVariableStatement).flatMap(statement => statement.declarationList.declarations) ?? []).map(item => item.name.text));
216
115
  for (const [kind, has] of [['Entities', kinds.entities], ['Migrations', kinds.migrations]]) {
217
116
  if (has && !declared.has(`${camel(kinds.name)}${kind}`)) plain(`${key}/persistence/connection.ts`, `${key}/persistence/connection.ts must export ${camel(kinds.name)}${kind}, the ${kind.toLowerCase()} of the ${kinds.name} capability, the one file that lists them for the apps.`, { capability: kinds.name });
218
117
  }
219
118
  const only = registered.get(key)?.connections;
220
- if (!only || only.size !== 1) continue;
119
+ if (!only || only.size < 1) continue;
120
+ // A per-connection platform capability (event-bus, jobs) lives on every connection that uses it; any other on exactly one (reported above).
121
+ const perConnection = only.size > 1 && isPerConnection(resolver, key, kinds.name);
122
+ if (only.size > 1 && !perConnection) continue;
221
123
  const home = [...only.keys()][0];
222
124
  for (const file of graph.files.values()) {
223
125
  if (!file.rel.startsWith(`${key}/`)) continue;
@@ -227,7 +129,8 @@ export function checkSchemaOwner(input) {
227
129
  const declaration = kit.declarationsOf(checker, node.expression)[0];
228
130
  const rel = declaration ? kit.graphPath(declaration) : null;
229
131
  const used = rel ? [...connections].find(name => rel === `${DATABASE_DIR}/${name}.decorators.ts`) : null;
230
- if (used && used !== home) report(file, node, `${file.rel} injects the entity manager of connection ${used}, but the ${kinds.name} capability's tables are registered on ${home}; a capability reads only its own database, so use Inject${pascal(home)}EntityManager or move the tables.`, { connection: used, expected: home, capability: kinds.name });
132
+ if (used && perConnection && !only.has(used)) report(file, node, `${file.rel} injects the entity manager of connection ${used}, but the ${kinds.name} capability's tables are registered on ${[...only.keys()].sort().join(' and ')}; register the capability on ${used} too or inject one of its connections.`, { connection: used, expected: [...only.keys()].sort().join(','), capability: kinds.name });
133
+ else if (used && !perConnection && used !== home) report(file, node, `${file.rel} injects the entity manager of connection ${used}, but the ${kinds.name} capability's tables are registered on ${home}; a capability reads only its own database, so use Inject${pascal(home)}EntityManager or move the tables.`, { connection: used, expected: home, capability: kinds.name });
231
134
  return true;
232
135
  });
233
136
  }
@@ -0,0 +1,24 @@
1
+ /** The value of a directive-prologue statement, or null once the prologue has ended. */
2
+ function directiveValue(ts, sourceFile, statement) {
3
+ const expressionStatement = ts?.isExpressionStatement
4
+ ? ts.isExpressionStatement(statement)
5
+ : Boolean(statement?.expression);
6
+ if (!expressionStatement) return null;
7
+ const expression = statement.expression;
8
+ if (ts?.isStringLiteral) return ts.isStringLiteral(expression) ? expression.text : null;
9
+ const raw = expression?.getText?.(sourceFile);
10
+ const quote = raw?.[0];
11
+ return typeof expression?.text === 'string' && (quote === "'" || quote === '"') && raw.at(-1) === quote
12
+ ? expression.text
13
+ : null;
14
+ }
15
+
16
+ /** True when a TypeScript source file declares `"use server"` in its directive prologue. */
17
+ export function isServerActionModule(ts, sourceFile) {
18
+ for (const statement of sourceFile?.statements ?? []) {
19
+ const value = directiveValue(ts, sourceFile, statement);
20
+ if (value === null) return false;
21
+ if (value === 'use server') return true;
22
+ }
23
+ return false;
24
+ }
@@ -0,0 +1,16 @@
1
+ // side-boundary.mjs - what counts as an import that leaves a side of an app (ARCH_INTERNAL_IMPORT_OUTSIDE).
2
+ // A side (be/ or fe/) imports nothing of the app outside itself: the root holds no source and the other side is another program; a
3
+ // declared read of the OTHER side (be/contracts/) is codegen input, never an import. A declared read of a tree the APP ROOT owns
4
+ // (supabase/types/, sides.<side>.reads of the slot manifest) is the one thing both sides do import: the generated database types.
5
+ import path from 'node:path';
6
+ import { isInside, slash } from './config.mjs';
7
+
8
+ const OTHER_SIDE = /^(be|fe)\//;
9
+
10
+ /** True when `target` (an absolute path) lies in a tree of the app root that the side declares it reads (`reads` of the side declaration). */
11
+ const readsAppTree = (config, target) => (config.hfs?.repo?.reads ?? [])
12
+ .some((read) => !OTHER_SIDE.test(read) && isInside(path.join(config.packageRoot, read), target));
13
+
14
+ /** Whether an import of `target` leaves the side the machine judges (config.root) for the app (config.packageRoot), declared app-root reads excepted. */
15
+ export const crossesSide = (config, target) => config.packageRoot !== undefined && config.packageRoot !== config.root
16
+ && isInside(config.packageRoot, target) && !isInside(config.root, target) && !slash(target).includes('/node_modules/') && !readsAppTree(config, target);