@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 { isInside } from './config.mjs';
3
- import { isUnshadowedCommonJsRequire, referencedExports, relativePath, sourceLocation, UNPROVEN_FRAMEWORK, unwrapExpression } from './typescript.mjs';
3
+ import { referencedExports, relativePath, UNPROVEN_FRAMEWORK, unwrapExpression } from './typescript.mjs';
4
+ import { anyDescendant, commonJsRequireReasons, constructedDecoratorKind as sharedConstructedDecoratorKind, decoratorCallee, moduleExportsOf, nodeDecorators, normalizedSymbol, normalizedSymbolValue, programSourcesOf, returnedExpressions, selectedNode, valueSymbol, violation } from './ast-walks.mjs';
5
+ import { sourceLocation } from '../../lib/ts-ast.mjs';
4
6
 
5
7
  export const PUBLIC_CONTRACT_RULE_ID = 'BE_PUBLIC_CONTRACT_FORM';
6
8
  export const READONLY_BOUNDARY_RULE_ID = 'BE_READONLY_BOUNDARY';
@@ -19,42 +21,7 @@ function canonical(file) {
19
21
  return path.resolve(file);
20
22
  }
21
23
 
22
- function normalizedSymbolValue(ts, checker, value) {
23
- let symbol = value ?? null;
24
- const seen = new Set();
25
- while (symbol && (symbol.flags & ts.SymbolFlags.Alias) && !seen.has(symbol)) {
26
- seen.add(symbol);
27
- const target = checker.getAliasedSymbol(symbol);
28
- if (!target || target === symbol) break;
29
- symbol = target;
30
- }
31
- return symbol;
32
- }
33
-
34
- function normalizedSymbol(ts, checker, node) {
35
- return normalizedSymbolValue(ts, checker, checker?.getSymbolAtLocation(node) ?? null);
36
- }
37
-
38
- function selectedNode(ts, expression) {
39
- expression = unwrapExpression(ts, expression);
40
- if (ts.isIdentifier(expression)) return expression;
41
- if (ts.isPropertyAccessExpression(expression)) return expression.name;
42
- if (ts.isElementAccessExpression(expression) && ts.isStringLiteralLike(expression.argumentExpression)) return expression.argumentExpression;
43
- return null;
44
- }
45
24
 
46
- function valueSymbol(ts, checker, node, seen = new Set()) {
47
- const selected = selectedNode(ts, node) ?? node;
48
- const symbol = normalizedSymbol(ts, checker, selected);
49
- if (!symbol || seen.has(symbol)) return symbol;
50
- seen.add(symbol);
51
- const declarations = symbol.getDeclarations?.() ?? [];
52
- if (declarations.length === 1 && ts.isVariableDeclaration(declarations[0]) && declarations[0].initializer
53
- && (ts.getCombinedNodeFlags(declarations[0].parent) & ts.NodeFlags.Const)) {
54
- return valueSymbol(ts, checker, declarations[0].initializer, seen);
55
- }
56
- return symbol;
57
- }
58
25
 
59
26
  function frameworkKindForSymbol(symbol, targets) {
60
27
  const selected = targets.get(symbol);
@@ -69,125 +36,42 @@ function frameworkKindForSymbol(symbol, targets) {
69
36
  return null;
70
37
  }
71
38
 
72
- function returnedExpressions(ts, declaration) {
73
- if ((ts.isArrowFunction(declaration) || ts.isFunctionExpression(declaration)) && !ts.isBlock(declaration.body)) return [declaration.body];
74
- const body = ts.isFunctionDeclaration(declaration) || ts.isMethodDeclaration(declaration)
75
- || ts.isArrowFunction(declaration) || ts.isFunctionExpression(declaration) ? declaration.body : null;
76
- if (!body || !ts.isBlock(body)) return [];
77
- const returned = [];
78
- const visit = node => {
79
- if (node !== body && (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)
80
- || ts.isArrowFunction(node) || ts.isMethodDeclaration(node))) return;
81
- if (ts.isReturnStatement(node) && node.expression) returned.push(node.expression);
82
- else ts.forEachChild(node, visit);
83
- };
84
- visit(body);
85
- return returned;
86
- }
87
-
88
- function tracedFrameworkKinds(ts, checker, expression, targets, seen = new Set(), depth = 0) {
89
- if (!expression) return new Set();
90
- if (depth > 10) return new Set([UNPROVEN_FRAMEWORK]);
91
- expression = unwrapExpression(ts, expression);
92
- const selected = selectedNode(ts, expression);
93
- const symbol = selected ? normalizedSymbol(ts, checker, selected) : null;
94
- const direct = symbol ? frameworkKindForSymbol(valueSymbol(ts, checker, selected), targets) : null;
95
- if (direct) return new Set([direct]);
96
- if (ts.isArrowFunction(expression) || ts.isFunctionExpression(expression)) {
97
- const kinds = new Set();
98
- for (const returned of returnedExpressions(ts, expression)) {
99
- for (const kind of tracedFrameworkKinds(ts, checker, returned, targets, seen, depth + 1)) kinds.add(kind);
100
- }
101
- return kinds;
102
- }
103
- if (ts.isCallExpression(expression)) {
104
- const kinds = tracedFrameworkKinds(ts, checker, expression.expression, targets, seen, depth + 1);
105
- if (kinds.size) return kinds;
106
- }
107
- if (!symbol || seen.has(symbol)) return new Set();
108
- const nextSeen = new Set(seen).add(symbol);
109
- const kinds = new Set();
110
- for (const declaration of symbol.getDeclarations?.() ?? []) {
111
- if (ts.isVariableDeclaration(declaration) && declaration.initializer) {
112
- for (const kind of tracedFrameworkKinds(ts, checker, declaration.initializer, targets, nextSeen, depth + 1)) kinds.add(kind);
113
- }
114
- if (ts.isShorthandPropertyAssignment(declaration)) {
115
- const target = normalizedSymbolValue(ts, checker, checker.getShorthandAssignmentValueSymbol?.(declaration));
116
- const kind = frameworkKindForSymbol(target, targets);
117
- if (kind) kinds.add(kind);
118
- }
119
- if (ts.isPropertyAssignment(declaration)) {
120
- for (const kind of tracedFrameworkKinds(ts, checker, declaration.initializer, targets, nextSeen, depth + 1)) kinds.add(kind);
121
- }
122
- for (const returned of returnedExpressions(ts, declaration)) {
123
- for (const kind of tracedFrameworkKinds(ts, checker, returned, targets, nextSeen, depth + 1)) kinds.add(kind);
124
- }
125
- }
126
- return kinds;
127
- }
39
+ /* This module's trace through frameworkKindForSymbol (name lookup and node_modules marker) instead of the
40
+ * default symbol->kind map, plus the shorthand/property-assignment descent. */
41
+ const FRAMEWORK_TRACE = {
42
+ directOf: (ts, checker, { selected, targets }) => frameworkKindForSymbol(valueSymbol(ts, checker, selected), targets),
43
+ shorthandOf: (ts, checker, target, targets) => frameworkKindForSymbol(target, targets),
44
+ };
128
45
 
129
46
  function frameworkTargets(config, context, checker, localFiles) {
130
47
  const bySymbol = new Map();
131
48
  const reasons = [];
132
- const program = context.programs.find(candidate => candidate.getTypeChecker() === checker);
133
- if (!program) return { bySymbol, reasons: ['a TypeScript program checker could not be associated with its source'] };
134
- for (const sourceFile of program.getSourceFiles()) {
135
- if (!localFiles.has(canonical(sourceFile.fileName))
136
- && !(sourceFile.isDeclarationFile && isInside(config.root, sourceFile.fileName)
137
- && !sourceFile.fileName.replaceAll('\\', '/').includes('/node_modules/'))) continue;
49
+ const files = programSourcesOf(context, checker, localFiles, { root: config.root });
50
+ if (!files) return { bySymbol, reasons: ['a TypeScript program checker could not be associated with its source'] };
51
+ for (const sourceFile of files) {
138
52
  for (const statement of sourceFile.statements) {
139
- const moduleSpecifier = (context.ts.isImportDeclaration(statement) || context.ts.isExportDeclaration(statement))
140
- && statement.moduleSpecifier && context.ts.isStringLiteralLike(statement.moduleSpecifier) ? statement.moduleSpecifier : null;
141
- const importEquals = context.ts.isImportEqualsDeclaration(statement) && context.ts.isExternalModuleReference(statement.moduleReference)
142
- && statement.moduleReference.expression && context.ts.isStringLiteralLike(statement.moduleReference.expression)
143
- ? statement.moduleReference.expression : null;
144
- const specifierNode = moduleSpecifier ?? importEquals;
145
- const specifier = specifierNode?.text;
146
- if (!specifier || !FRAMEWORK_EXPORTS.has(specifier)) continue;
147
- const moduleSymbol = checker.getSymbolAtLocation(specifierNode);
148
- if (!moduleSymbol) {
149
- reasons.push(`${relativePath(config.root, sourceFile.fileName)} cannot resolve ${specifier}`);
150
- continue;
151
- }
152
- const selected = FRAMEWORK_EXPORTS.get(specifier);
153
- const exports = new Map(checker.getExportsOfModule(moduleSymbol).map(symbol => [symbol.getName(), normalizedSymbolValue(context.ts, checker, symbol)]));
154
- for (const name of referencedExports(context.ts, statement, selected)) {
155
- const target = exports.get(name);
53
+ const bound = moduleExportsOf(context.ts, checker, statement);
54
+ if (!bound || !FRAMEWORK_EXPORTS.has(bound.specifier)) continue;
55
+ if (!bound.symbol) { reasons.push(`${relativePath(config.root, sourceFile.fileName)} cannot resolve ${bound.specifier}`); continue; }
56
+ for (const name of referencedExports(context.ts, statement, FRAMEWORK_EXPORTS.get(bound.specifier))) {
57
+ const target = bound.exports.get(name);
156
58
  if (target) bySymbol.set(target, name);
157
- else reasons.push(`${relativePath(config.root, sourceFile.fileName)} cannot resolve ${name} from ${specifier}`);
59
+ else reasons.push(`${relativePath(config.root, sourceFile.fileName)} cannot resolve ${name} from ${bound.specifier}`);
158
60
  }
159
61
  }
160
- const visitRequire = node => {
161
- if (context.ts.isCallExpression(node) && isUnshadowedCommonJsRequire(context.ts, checker, node.expression)
162
- && node.arguments.length === 1 && context.ts.isStringLiteralLike(node.arguments[0])
163
- && FRAMEWORK_EXPORTS.has(node.arguments[0].text)) {
164
- reasons.push(`${relativePath(config.root, sourceFile.fileName)} uses a CommonJS ${node.arguments[0].text} binding whose contract role cannot be proved`);
165
- }
166
- context.ts.forEachChild(node, visitRequire);
167
- };
168
- visitRequire(sourceFile);
62
+ commonJsRequireReasons(context.ts, checker, sourceFile, (specifier) => FRAMEWORK_EXPORTS.has(specifier),
63
+ reasons, relativePath(config.root, sourceFile.fileName), 'binding whose contract role cannot be proved');
169
64
  }
170
65
  return { bySymbol, reasons };
171
66
  }
172
67
 
173
- function calledExpression(ts, decorator) {
174
- return ts.isCallExpression(decorator.expression) ? decorator.expression.expression : decorator.expression;
175
- }
176
-
177
68
  function decoratorKind(ts, checker, decorator, targets) {
178
- const selected = selectedNode(ts, calledExpression(ts, decorator));
69
+ const selected = selectedNode(ts, decoratorCallee(ts, decorator));
179
70
  return selected ? frameworkKindForSymbol(valueSymbol(ts, checker, selected), targets) : null;
180
71
  }
181
72
 
182
- function constructedDecoratorKind(ts, checker, decorator, targets) {
183
- const kinds = tracedFrameworkKinds(ts, checker, calledExpression(ts, decorator), targets);
184
- if (kinds.has(UNPROVEN_FRAMEWORK)) return 'unproven framework';
185
- return kinds.size === 1 ? [...kinds][0] : kinds.size ? 'multiple framework' : null;
186
- }
187
-
188
- function decorators(ts, node) {
189
- return ts.canHaveDecorators(node) ? ts.getDecorators(node) ?? [] : node.decorators ?? [];
190
- }
73
+ const constructedDecoratorKind = (ts, checker, decorator, targets) =>
74
+ sharedConstructedDecoratorKind(ts, checker, decorator, targets, FRAMEWORK_TRACE);
191
75
 
192
76
  function modifiers(ts, node) {
193
77
  return ts.canHaveModifiers(node) ? ts.getModifiers(node) ?? [] : node.modifiers ?? [];
@@ -205,9 +89,7 @@ function readonlyMember(ts, node) {
205
89
  return hasModifier(ts, node, ts.SyntaxKind.ReadonlyKeyword);
206
90
  }
207
91
 
208
- function violation(config, sourceFile, node, ruleId, message, extra = {}) {
209
- return { ruleId, path: relativePath(config.root, sourceFile.fileName), ...sourceLocation(sourceFile, node), message, ...extra };
210
- }
92
+
211
93
 
212
94
  function sourceRole(sourceFile) {
213
95
  const normalized = sourceFile.fileName.replaceAll('\\', '/');
@@ -221,7 +103,7 @@ function isFrameworkHelper(sourceFile, declaration, framework) {
221
103
  const role = sourceRole(sourceFile);
222
104
  if (role.transport || NON_API_SOURCE_ROLES.has(role.role) || NON_API_SOURCE_ROLES.has(role.base)) return true;
223
105
  if (declaration && declaration.name && /Module$/.test(declaration.name.text ?? '')) {
224
- return decorators(framework.ts, declaration).some(decorator => decoratorKind(framework.ts, framework.checker, decorator, framework.targets) === 'Module');
106
+ return nodeDecorators(framework.ts, declaration).some(decorator => decoratorKind(framework.ts, framework.checker, decorator, framework.targets) === 'Module');
225
107
  }
226
108
  return false;
227
109
  }
@@ -442,19 +324,8 @@ function expressionOrigin(ts, checker, expression, seen = new Set(), depth = 0)
442
324
  return symbol;
443
325
  }
444
326
 
445
- function expressionReferencesOrigin(ts, checker, expression, expected) {
446
- let found = false;
447
- const visit = node => {
448
- if (found) return;
449
- if (expressionOrigin(ts, checker, node) === expected) {
450
- found = true;
451
- return;
452
- }
453
- ts.forEachChild(node, visit);
454
- };
455
- visit(expression);
456
- return found;
457
- }
327
+ const expressionReferencesOrigin = (ts, checker, expression, expected) =>
328
+ anyDescendant(ts, expression, (node) => expressionOrigin(ts, checker, node) === expected);
458
329
 
459
330
  function isSafePrimitiveProjection(ts, checker, expression, expected) {
460
331
  expression = unwrapExpression(ts, expression);
@@ -626,13 +497,13 @@ function checkInjectedClass(config, context, checker, declaration, classKind, ta
626
497
  .map(member => [propertyName(ts, member), member]).filter(([name]) => name));
627
498
  for (const member of declaration.members) {
628
499
  if (ts.isPropertyDeclaration(member)) {
629
- const injected = decorators(ts, member).some(decorator => decoratorKind(ts, checker, decorator, targets) === 'Inject');
500
+ const injected = nodeDecorators(ts, member).some(decorator => decoratorKind(ts, checker, decorator, targets) === 'Inject');
630
501
  if (injected) checkReadonlyProperty(config, context, sourceFile, member, `Injected property ${propertyName(ts, member) ?? '(computed)'}`, violations);
631
502
  continue;
632
503
  }
633
504
  if (!ts.isConstructorDeclaration(member)) continue;
634
505
  for (const parameter of member.parameters) {
635
- const explicitInject = decorators(ts, parameter).some(decorator => decoratorKind(ts, checker, decorator, targets) === 'Inject');
506
+ const explicitInject = nodeDecorators(ts, parameter).some(decorator => decoratorKind(ts, checker, decorator, targets) === 'Inject');
636
507
  if (!classKind && !explicitInject) continue;
637
508
  const parameterProperty = modifiers(ts, parameter).some(modifier => [ts.SyntaxKind.PublicKeyword, ts.SyntaxKind.PrivateKeyword,
638
509
  ts.SyntaxKind.ProtectedKeyword, ts.SyntaxKind.ReadonlyKeyword].includes(modifier.kind));
@@ -729,7 +600,7 @@ export function checkBackendContracts(config, context) {
729
600
  };
730
601
  collectClasses(sourceFile);
731
602
  for (const statement of classes) {
732
- const classDecorators = decorators(ts, statement);
603
+ const classDecorators = nodeDecorators(ts, statement);
733
604
  const kindsByDecorator = classDecorators.map(decorator => decoratorKind(ts, checker, decorator, framework.targets));
734
605
  const directKinds = kindsByDecorator.filter(Boolean);
735
606
  for (const [index, decorator] of classDecorators.entries()) if (!kindsByDecorator[index]) {
@@ -740,15 +611,15 @@ export function checkBackendContracts(config, context) {
740
611
  }
741
612
  const classKind = directKinds.find(kind => NEST_CREATED.has(kind)) ?? null;
742
613
  for (const member of statement.members) for (const decorated of [member, ...(ts.isConstructorDeclaration(member) ? member.parameters : [])]) {
743
- for (const decorator of decorators(ts, decorated)) if (!decoratorKind(ts, checker, decorator, framework.targets)) {
614
+ for (const decorator of nodeDecorators(ts, decorated)) if (!decoratorKind(ts, checker, decorator, framework.targets)) {
744
615
  const constructed = constructedDecoratorKind(ts, checker, decorator, framework.targets);
745
616
  if (constructed === 'Inject' || constructed === 'unproven framework') {
746
617
  readonlyReasons.push(`${relativePath(config.root, sourceFile.fileName)} has a constructed ${constructed} injection decorator identity`);
747
618
  }
748
619
  }
749
620
  }
750
- const hasInjectedMember = statement.members.some(member => decorators(ts, member).some(decorator => decoratorKind(ts, checker, decorator, framework.targets) === 'Inject')
751
- || (ts.isConstructorDeclaration(member) && member.parameters.some(parameter => decorators(ts, parameter)
621
+ const hasInjectedMember = statement.members.some(member => nodeDecorators(ts, member).some(decorator => decoratorKind(ts, checker, decorator, framework.targets) === 'Inject')
622
+ || (ts.isConstructorDeclaration(member) && member.parameters.some(parameter => nodeDecorators(ts, parameter)
752
623
  .some(decorator => decoratorKind(ts, checker, decorator, framework.targets) === 'Inject'))));
753
624
  if (classKind || hasInjectedMember) {
754
625
  injectedClasses += 1;
@@ -8,7 +8,8 @@
8
8
  * so a file only a spec imports is dead, on purpose. Type-only imports reach a file.
9
9
  *
10
10
  * Owner = every graph.ownerRoots unit whose tier is not `app` and whose public entry file is in the graph (index.ts or
11
- * index.tsx, a package's src/index.ts). The exported names of the entry are its named exports, `export { a as b }`,
11
+ * index.tsx, a package's src/index.ts). The `entries` its slot declares (slot data, e.g. fe.modules.db browser.ts) are further
12
+ * public entries of the same owner, judged exactly like the entry. The exported names of an entry are its named exports, `export { a as b }`,
12
13
  * `export { x } from`, declarations with `export`, and `default` for `export default`. `export *` is refused by owners.mjs
13
14
  * and contributes no name here.
14
15
  *
@@ -16,13 +17,17 @@
16
17
  * namespace import, `import x = require`, a dynamic import()/require(), an `export *` or `export * as` of the entry make
17
18
  * every name used. A file outside the owner that re-exports the name (`export { n as m } from`) uses it when `m` is itself
18
19
  * used by the importers of that file; a re-exporting file nobody imports is a framework entry (a route file) and uses it.
19
- * Specs and tests are not in the graph, so an export used only by a spec is dead, on purpose, with one exception (unit test
20
- * standard): a `<name>.service.spec.ts` (the only unit spec kind) and a `*.builder.ts` under src/tests/fixtures/builders read from
21
- * disk count as consumers, because a spec can only provide an Inject*() token or a param type the entry exports. An integration
20
+ * Specs and tests are not in the graph, so an export used only by a spec is dead, on purpose, with these exceptions (unit test
21
+ * standard): the unit spec of every unit role (ruleParams.be.unitRoles: `<name>.service.spec.ts`, `<name>.cli.spec.ts`) and of every logic role
22
+ * (ruleParams.be.logicRoles: `<name>.policy.spec.ts`, `<name>.client.spec.ts`, ...), a
23
+ * unit spec of a webhook, gateway or subscription door (`.webhook.spec.ts`, `.gateway.spec.ts`, `.subscription.spec.ts`: a door has no service of its own), a
24
+ * `*.builder.ts` under src/tests/fixtures/builders, and a file of the test world (slots be.tests.world and be.tests.world.kit, which
25
+ * open and migrate the real databases of the e2e run) read from disk count as consumers, because a spec can only provide an
26
+ * Inject*() token or a param type the entry exports, and the world wires the same capabilities the apps do. An integration
22
27
  * spec (slot be.tests.integration, `src/tests/integration/<capability>/*.integration-spec.ts`) counts as a consumer of exactly one
23
28
  * owner: the integration (slot be.integrations, `src/modules/integrations/<provider>/`) whose provider folder is its capability
24
29
  * folder, because R112 makes that spec register the integration module and reference its ErrorCode enum. Specs of any other kind,
25
- * an integration spec importing another owner, e2e specs and world files still do not count. A consumer inside the owner is
30
+ * an integration spec importing another owner, and e2e specs still do not count. A consumer inside the owner is
26
31
  * skipped like any inside consumer.
27
32
  */
28
33
  import fs from 'node:fs';
@@ -51,6 +56,12 @@ export function entryOf(graph, config, key, owner) {
51
56
  return null;
52
57
  }
53
58
 
59
+ /** The additional public entry files (repository-relative, in the graph) the slot manifest declares for the owner (slot field `entries`, on the slot that holds its entry file). */
60
+ function extraEntries(graph, entry) {
61
+ const found = graph.resolver.classifyPath(entry);
62
+ return (found.slot ? graph.resolver.slot(found.slot)?.entries ?? [] : []).map(name => `${found.root}/${name}`).filter(rel => graph.files.has(rel));
63
+ }
64
+
54
65
  /** Names an import/export declaration takes from its target: {all} or {pairs: [{imported, exported}]}. */
55
66
  function bindingsOf(ts, declaration) {
56
67
  const kind = ts.SyntaxKind;
@@ -171,7 +182,22 @@ function deadFiles(graph, config) {
171
182
  return { violations, judged, roots: roots.size };
172
183
  }
173
184
 
174
- const TEST_CONSUMER = /^(?:(?:src|apps)\/.+\.service\.spec\.ts|src\/tests\/fixtures\/builders\/.+\.builder\.ts)$/u;
185
+ /** The unit spec of a webhook, gateway or subscription door: a door has no service of its own, so its spec is the only unit spec of its kind. */
186
+ const DOOR_SPEC = /^src\/features\/(?:webhooks|realtime)\/.+\.(?:webhook|gateway|subscription)\.spec\.ts$/u;
187
+ const BUILDER_CONSUMER = /^src\/tests\/fixtures\/builders\/.+\.builder\.ts$/u;
188
+ /** The test world slots (knowledge/hfs/slots.yaml): their files wire the real capabilities of the e2e run. */
189
+ const WORLD_SLOTS = new Set(['be.tests.world', 'be.tests.world.kit']);
190
+
191
+ /** Whether `rel` is a test file that counts as a consumer of any owner: a unit role spec, a fixture builder, a world file. */
192
+ function testConsumer(graph, rel) {
193
+ const params = graph.resolver.ruleParams();
194
+ const specs = [...(params.unitRoles ?? []).map(role => role.spec), ...(params.logicRoles ?? []).map(role => `${role}.spec`)];
195
+ if (/^(?:src|apps)\//u.test(rel) && specs.some(spec => rel.endsWith(`.${spec}.ts`))) return true;
196
+ if (DOOR_SPEC.test(rel)) return true;
197
+ if (BUILDER_CONSUMER.test(rel)) return true;
198
+ const classified = graph.resolver.classifyPath(rel);
199
+ return WORLD_SLOTS.has(classified.slot) && classified.status !== 'forbidden' && /\.tsx?$/u.test(rel);
200
+ }
175
201
  /** The slot of integration specs and the slot of the integrations they pair with by folder (knowledge/hfs/slots.yaml). */
176
202
  const INTEGRATION_SPEC_SLOT = 'be.tests.integration';
177
203
  const INTEGRATION_SLOT = 'be.integrations';
@@ -189,16 +215,17 @@ function inIntegrationOf(graph, to, provider) {
189
215
  }
190
216
 
191
217
  /**
192
- * Pseudo edges (read from disk, outside the production program) to graph files: from the unit specs of services and the fixture
193
- * builders to anything, and from an integration spec only to the integration of its own provider folder.
218
+ * Pseudo edges (read from disk, outside the production program) to graph files: from the unit role specs, the fixture builders and
219
+ * the test world files to anything, and from an integration spec only to the integration of its own provider folder.
194
220
  */
195
221
  function testConsumerEdges({ context, graph, config }) {
196
222
  const { ts } = context;
197
223
  const options = context.projects?.[0]?.options ?? {};
198
224
  const edges = [];
199
225
  const consumers = [...treeOf(config.root).files]
200
- .map(file => ({ file, provider: TEST_CONSUMER.test(file) ? null : integrationSpecProvider(graph, file) }))
201
- .filter(({ file, provider }) => provider !== null || TEST_CONSUMER.test(file))
226
+ .map(file => ({ file, any: testConsumer(graph, file) }))
227
+ .map(({ file, any }) => ({ file, provider: any ? null : integrationSpecProvider(graph, file), any }))
228
+ .filter(({ any, provider }) => any || provider !== null)
202
229
  .sort((a, b) => a.file.localeCompare(b.file));
203
230
  for (const { file: rel, provider } of consumers) {
204
231
  const abs = path.join(config.root, ...rel.split('/'));
@@ -263,25 +290,27 @@ export function checkDeadExports({ context, graph, config }) {
263
290
  const entry = entryOf(graph, config, key, owner);
264
291
  if (!entry) continue;
265
292
  owners += 1;
266
- const names = exportedNames(ts, graph.files.get(entry).sourceFile);
267
- const used = consumed(entry, key, 0, new Set([entry]));
268
- // A consumer outside the owner that imports a file the entry re-exports by name reaches the entry's export of that name.
269
- for (const edge of graph.edges) {
270
- if (edge.from !== entry || !edge.reexport || graph.unit(edge.to) !== key) continue;
271
- const reexport = bindingsOf(ts, edge.edge.declaration);
272
- const inner = consumed(edge.to, key, 0, new Set([entry, edge.to]));
273
- if (reexport.all) continue;
274
- for (const pair of reexport.pairs) if (inner.all || inner.names.has(pair.imported)) used.names.add(pair.exported);
275
- }
276
- for (const [name, line] of names) {
277
- exports += 1;
278
- if (used.all || used.names.has(name)) continue;
279
- violations.push({
280
- ruleId: 'HFS_UNUSED_EXPORT',
281
- path: entry, line, column: 1,
282
- name, owner: owner.root, slot: owner.slot,
283
- message: `${entry} exports ${name}, but no production file outside ${owner.root || 'the repository root'} imports it; remove the export (only a service unit spec, a fixture builder, or an integration spec of this integration's own provider folder counts besides production files).`,
284
- });
293
+ for (const publicEntry of [entry, ...extraEntries(graph, entry)]) {
294
+ const names = exportedNames(ts, graph.files.get(publicEntry).sourceFile);
295
+ const used = consumed(publicEntry, key, 0, new Set([publicEntry]));
296
+ // A consumer outside the owner that imports a file the entry re-exports by name reaches the entry's export of that name.
297
+ for (const edge of graph.edges) {
298
+ if (edge.from !== publicEntry || !edge.reexport || graph.unit(edge.to) !== key) continue;
299
+ const reexport = bindingsOf(ts, edge.edge.declaration);
300
+ const inner = consumed(edge.to, key, 0, new Set([publicEntry, edge.to]));
301
+ if (reexport.all) continue;
302
+ for (const pair of reexport.pairs) if (inner.all || inner.names.has(pair.imported)) used.names.add(pair.exported);
303
+ }
304
+ for (const [name, line] of names) {
305
+ exports += 1;
306
+ if (used.all || used.names.has(name)) continue;
307
+ violations.push({
308
+ ruleId: 'HFS_UNUSED_EXPORT',
309
+ path: publicEntry, line, column: 1,
310
+ name, owner: owner.root, slot: owner.slot,
311
+ message: `${publicEntry} exports ${name}, but no production file outside ${owner.root || 'the repository root'} imports it; remove the export (only a unit role spec, a fixture builder, a test world file, or an integration spec of this integration's own provider folder counts besides production files).`,
312
+ });
313
+ }
285
314
  }
286
315
  }
287
316
  const files = deadFiles(graph, config);
@@ -16,7 +16,7 @@ export const DOC_LANGUAGE_RULE_IDS = ['HFS_DOC_NOT_ENGLISH'];
16
16
 
17
17
  const RULE = 'HFS_DOC_NOT_ENGLISH';
18
18
  /** The top-level folders whose documents this check reads. */
19
- export const DOCUMENT_ROOTS = Object.freeze(['knowledge', 'docs', 'src', 'apps']);
19
+ const DOCUMENT_ROOTS = Object.freeze(['knowledge', 'docs', 'src', 'apps']);
20
20
 
21
21
  export function checkDocLanguage({ config, graph }) {
22
22
  const resolver = graph.resolver;
@@ -1,5 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { machineKit } from './machine-ast.mjs';
3
+ import { isTestWorldSlot } from '../test-world-slot.mjs';
3
4
 
4
5
  /**
5
6
  * R33 `entrypoint-only-in-apps` (BE_ENTRYPOINT_ONLY_IN_APPS). A process starts in `apps/<app>/src/main.ts` only:
@@ -34,7 +35,7 @@ export function checkEntrypoints(input) {
34
35
  }
35
36
  };
36
37
  for (const file of graph.files.values()) {
37
- const isMain = (Boolean(file.slot?.startsWith('be.app.')) && path.posix.basename(file.rel) === 'main.ts') || file.slot === 'be.tests.world';
38
+ const isMain = (Boolean(file.slot?.startsWith('be.app.')) && path.posix.basename(file.rel) === 'main.ts') || isTestWorldSlot(file.slot);
38
39
  const checker = kit.checkerOf(file.sourceFile);
39
40
  const report = (node, message) => violations.push({ ruleId: RULE, path: file.rel, ...kit.at(file.rel, file.sourceFile, node), message });
40
41
  kit.walk(file.sourceFile, node => {
@@ -1,6 +1,6 @@
1
1
  import { treeOf } from './required-files.mjs';
2
- import { allowsFile } from '../../lib/hfs-allows.mjs';
3
- import { isFeTestPath } from '../../lib/hfs-rules/fe-no-tests.mjs';
2
+ import { allowsFile } from '../allows.mjs';
3
+ import { isFeTestPath } from '../rules/fe-no-tests.mjs';
4
4
 
5
5
  /**
6
6
  * R94 `fe-slot-allows` (FE_SLOT_FILE_ROLE). A front-end slot that owns a whole directory (`fe.route`, `fe.feature`,
@@ -8,10 +8,10 @@ import { isFeTestPath } from '../../lib/hfs-rules/fe-no-tests.mjs';
8
8
  * Every tracked file of such a slot is matched against the `requires` and `allows` entries of its slot; a file no entry names is a
9
9
  * finding - `page.tsx` in a hooks domain, a `[lang]` segment under `app/`, a stray file beside a component or at a feature
10
10
  * root. A file that sits where the slot expects a folder (`hooks/useX.ts`, so the "domain" is a file name) is one too.
11
- * Files no slot owns are HFS_PATH_NO_SLOT's (`hfs check`), so together every front-end file is placed by exactly one slot and
11
+ * Files no slot owns are HFS_PATH_NO_SLOT's (`starci app check`), so together every front-end file is placed by exactly one slot and
12
12
  * named by it. A test path (a `.spec.tsx` or `.test.tsx` beside a component, a test directory or test tooling) is FE_NO_TESTS's
13
13
  * (R97, contract-change fe-no-tests): that rule is the one finding of such a file, so this check leaves it alone, as
14
- * HFS_PATH_NO_SLOT does (scripts/lib/hfs-path-findings.mjs).
14
+ * HFS_PATH_NO_SLOT does (scripts/hfs/path-findings.mjs).
15
15
  */
16
16
  export const FE_SLOT_ALLOWS_RULE_IDS = ['FE_SLOT_FILE_ROLE'];
17
17
 
@@ -1,11 +1,11 @@
1
1
  import path from 'node:path';
2
2
  import { treeOf } from './required-files.mjs';
3
- import { allowsFile } from '../../lib/hfs-allows.mjs';
3
+ import { allowsFile } from '../allows.mjs';
4
4
 
5
5
  /**
6
6
  * R29 `feature-shape` (BE_FEATURE_SHAPE). A feature root holds `index.ts`, `<feature>.module.ts`, `application/`,
7
7
  * `transport/<protocol>/` and `messages/` only, and each of those folders holds only what its slot `allows` (knowledge/hfs/
8
- * slots.yaml: be.feature, be.feature.application, be.feature.application.support, be.transport.*, be.feature.transport.cli,
8
+ * slots.yaml: be.feature, be.feature.application, be.feature.application.support, be.transport.*,
9
9
  * be.feature.messages). Every tracked file below a feature root is classified by the slot resolver and matched against
10
10
  * the `requires` and `allows` entries of the slot that owns it; a directory that no slot owns (an unknown protocol under
11
11
  * `transport/`, a `graphql/` folder under `application/`) is refused because its files fall back to the feature root slot.
@@ -31,7 +31,10 @@ export function checkFeatureShape({ config, graph }) {
31
31
  const feature = path.posix.basename(owner.root);
32
32
  const where = `${verdict.slot} (${verdict.root})`;
33
33
  if (verdict.slot === owner.slot) {
34
- // The feature root slot owns only the files at the root; anything deeper sits in a directory no slot claims.
34
+ // A file the feature root slot itself allows is in place (the cli feature root allows its <group>/ folders); any other file
35
+ // deeper than the root sits in a directory no slot claims.
36
+ // A directory entry (`transport/`, `application/`) is held by its own slots: below it, only those slots admit a file.
37
+ if (verdict.allowed && !String(verdict.entry ?? '').endsWith('/')) continue;
35
38
  if (verdict.relative.includes('/')) {
36
39
  const folder = verdict.relative.split('/')[0];
37
40
  report(file, `${file} sits in ${owner.root}/${folder}/, which no slot owns; a feature root holds only ${verdict.allows.join(', ')}, and transport/ holds one folder per protocol a slot names. Move it to application/ or a transport/<protocol>/ folder, or delete it.`,
@@ -1,6 +1,6 @@
1
1
  // framework-pinned.mjs - the Next.js files that only load from a source root (the directory holding
2
2
  // app/). Authored once in knowledge/patterns/fe/folder.yaml FE-FOLDER-1 (frameworkPinnedRootFiles), never
3
- // hard-coded here (supervisor ruling, nivo wf-nivo-fe-debt-mug06w7h inc-2e42a24b74e4). Read by the architecture
3
+ // hard-coded here (a supervisor ruling). Read by the architecture
4
4
  // check (FE_SOURCE_LAYOUT_INVALID).
5
5
  //
6
6
  // An unreadable or malformed list is a broken install, not "no pinned files": the reader throws