@starci/hfs 4.2.17 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (564) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +7 -0
  3. package/db/migrate.mjs +361 -0
  4. package/db/post-cutover.mjs +136 -0
  5. package/emit/db-types.mjs +10 -1
  6. package/lint/run.mjs +1 -1
  7. package/package.json +4 -1
  8. package/release/gate.mjs +298 -0
  9. package/release/index.mjs +103 -0
  10. package/release/push.mjs +110 -0
  11. package/runtime/knowledge/hfs/canon-pins.yaml +11 -11
  12. package/runtime/knowledge/hfs/fe-stack.yaml +22 -1
  13. package/runtime/knowledge/hfs/rules.yaml +3437 -160
  14. package/runtime/knowledge/hfs/slots.yaml +430 -92
  15. package/runtime/knowledge/patterns/be/api.yaml +92 -2
  16. package/runtime/knowledge/patterns/be/cli.yaml +37 -9
  17. package/runtime/knowledge/patterns/be/event-bus.yaml +3 -3
  18. package/runtime/knowledge/patterns/be/jobs.yaml +20 -2
  19. package/runtime/knowledge/patterns/be/projections.yaml +4 -2
  20. package/runtime/knowledge/patterns/be/queues.yaml +11 -3
  21. package/runtime/knowledge/patterns/be/reactors.yaml +20 -1
  22. package/runtime/knowledge/patterns/be/realtime.yaml +25 -3
  23. package/runtime/knowledge/patterns/be/saga.yaml +20 -3
  24. package/runtime/knowledge/patterns/be/webhooks.yaml +210 -36
  25. package/runtime/knowledge/patterns/fe/folder.yaml +4 -0
  26. package/runtime/knowledge/sonar-gate.yaml +1 -1
  27. package/runtime/modules/kernel/failure-codes.yaml +3128 -47
  28. package/runtime/modules/models/runtimes.yaml +1 -1
  29. package/runtime/modules/schemas/application-stacks.schema.yaml +663 -0
  30. package/runtime/packages/cli/src/catalog.generated.mjs +14104 -0
  31. package/runtime/packages/cli/src/validate-args.mjs +213 -0
  32. package/runtime/scripts/api/git/add.mjs +5 -0
  33. package/runtime/scripts/api/git/cat-file.mjs +5 -0
  34. package/runtime/scripts/api/git/init.mjs +7 -0
  35. package/runtime/scripts/api/git/lib.mjs +3 -0
  36. package/runtime/scripts/api/git/tag.mjs +5 -0
  37. package/runtime/scripts/api/node/lib.mjs +20 -0
  38. package/runtime/scripts/api/node/run-node.mjs +6 -0
  39. package/runtime/scripts/api/sops/lib.mjs +41 -0
  40. package/runtime/scripts/api/sops/resolve-sops.mjs +7 -0
  41. package/runtime/scripts/api/sops/seal.mjs +1 -1
  42. package/runtime/scripts/api/sops/selected-age-recipient.mjs +7 -0
  43. package/runtime/scripts/api/supabase/database-dump.mjs +5 -0
  44. package/runtime/scripts/api/supabase/database-query.mjs +5 -0
  45. package/runtime/scripts/api/supabase/lib.mjs +44 -0
  46. package/runtime/scripts/api/supabase/migration-repair.mjs +5 -0
  47. package/runtime/scripts/hfs/app-wiring.mjs +201 -0
  48. package/runtime/scripts/hfs/architecture/backend-app-files.mjs +103 -0
  49. package/runtime/scripts/hfs/architecture/backend.mjs +22 -10
  50. package/runtime/scripts/hfs/architecture/background-unowned.mjs +157 -41
  51. package/runtime/scripts/hfs/architecture/canon-clones.mjs +240 -0
  52. package/runtime/scripts/hfs/architecture/canon-jsx-clones.mjs +143 -0
  53. package/runtime/scripts/hfs/architecture/client-reaches-server.mjs +6 -3
  54. package/runtime/scripts/hfs/architecture/clones.mjs +17 -8
  55. package/runtime/scripts/hfs/architecture/connection-map.mjs +14 -12
  56. package/runtime/scripts/hfs/architecture/context-map.mjs +25 -14
  57. package/runtime/scripts/hfs/architecture/context-owner.mjs +1 -2
  58. package/runtime/scripts/hfs/architecture/dead-exports-bindings.mjs +149 -0
  59. package/runtime/scripts/hfs/architecture/dead-exports.mjs +23 -50
  60. package/runtime/scripts/hfs/architecture/default-deny.mjs +8 -6
  61. package/runtime/scripts/hfs/architecture/frontend-block-render.mjs +104 -0
  62. package/runtime/scripts/hfs/architecture/frontend-world-render.mjs +30 -11
  63. package/runtime/scripts/hfs/architecture/frontend-world.mjs +1 -1
  64. package/runtime/scripts/hfs/architecture/function-spec-providers.mjs +153 -0
  65. package/runtime/scripts/hfs/architecture/hfs.mjs +3 -3
  66. package/runtime/scripts/hfs/architecture/i18n-keys.mjs +16 -3
  67. package/runtime/scripts/hfs/architecture/machine-ast.mjs +17 -0
  68. package/runtime/scripts/hfs/architecture/module-per-transport.mjs +49 -25
  69. package/runtime/scripts/hfs/architecture/next-data-inference.mjs +176 -0
  70. package/runtime/scripts/hfs/architecture/next-data-symbols.mjs +26 -0
  71. package/runtime/scripts/hfs/architecture/next-data.mjs +31 -23
  72. package/runtime/scripts/hfs/architecture/reachability.mjs +14 -0
  73. package/runtime/scripts/hfs/architecture/register-once.mjs +15 -7
  74. package/runtime/scripts/hfs/architecture/required-files.mjs +2 -1
  75. package/runtime/scripts/hfs/architecture/source-names.mjs +48 -3
  76. package/runtime/scripts/hfs/architecture/staged-consumers.mjs +37 -0
  77. package/runtime/scripts/hfs/architecture/supabase-ast.mjs +214 -17
  78. package/runtime/scripts/hfs/architecture/supabase-be.mjs +1 -6
  79. package/runtime/scripts/hfs/architecture/supabase.mjs +59 -21
  80. package/runtime/scripts/hfs/architecture/surface.mjs +2 -1
  81. package/runtime/scripts/hfs/architecture/tiers.mjs +11 -4
  82. package/runtime/scripts/hfs/architecture/typescript.mjs +1 -8
  83. package/runtime/scripts/hfs/architecture/unit-spec-providers.mjs +9 -13
  84. package/runtime/scripts/hfs/check-results.mjs +28 -0
  85. package/runtime/scripts/hfs/check.mjs +63 -72
  86. package/runtime/scripts/hfs/coverage-from.mjs +70 -0
  87. package/runtime/scripts/hfs/db-baseline-verb.mjs +276 -0
  88. package/runtime/scripts/hfs/db-plan-verb.mjs +254 -0
  89. package/runtime/scripts/hfs/db-restamp-verb.mjs +60 -0
  90. package/runtime/scripts/hfs/declaration-shape.mjs +39 -3
  91. package/runtime/scripts/hfs/doc-commands.mjs +367 -0
  92. package/runtime/scripts/hfs/edition-slots.mjs +2 -2
  93. package/runtime/scripts/hfs/example-secrets.mjs +158 -0
  94. package/runtime/scripts/hfs/manifest-shape.mjs +91 -6
  95. package/runtime/scripts/hfs/path-findings.mjs +32 -2
  96. package/runtime/scripts/hfs/refusal-codes.mjs +6 -0
  97. package/runtime/scripts/hfs/rule-catalog.mjs +156 -11
  98. package/runtime/scripts/hfs/rule-params-shape.mjs +22 -10
  99. package/runtime/scripts/hfs/rules/a15-findings.mjs +88 -0
  100. package/runtime/scripts/hfs/rules/app-env-required.mjs +20 -0
  101. package/runtime/scripts/hfs/rules/app-root.mjs +2 -2
  102. package/runtime/scripts/hfs/rules/assets.mjs +79 -0
  103. package/runtime/scripts/hfs/rules/boot-proof.mjs +16 -0
  104. package/runtime/scripts/hfs/rules/canon-copy-drift.mjs +59 -0
  105. package/runtime/scripts/hfs/rules/contract.mjs +66 -5
  106. package/runtime/scripts/hfs/rules/coverage-below.mjs +230 -0
  107. package/runtime/scripts/hfs/rules/database-access.mjs +343 -0
  108. package/runtime/scripts/hfs/rules/database-baseline.mjs +142 -0
  109. package/runtime/scripts/hfs/rules/database-config.mjs +250 -2
  110. package/runtime/scripts/hfs/rules/database-constants.mjs +9 -0
  111. package/runtime/scripts/hfs/rules/database-migrations.mjs +317 -37
  112. package/runtime/scripts/hfs/rules/database-plpgsql.mjs +119 -9
  113. package/runtime/scripts/hfs/rules/database-queue-sources.mjs +176 -0
  114. package/runtime/scripts/hfs/rules/database-queues.mjs +361 -0
  115. package/runtime/scripts/hfs/rules/database-sql.mjs +91 -9
  116. package/runtime/scripts/hfs/rules/database.mjs +11 -2
  117. package/runtime/scripts/hfs/rules/deploy-scan.mjs +192 -0
  118. package/runtime/scripts/hfs/rules/deploy-workflow.mjs +219 -0
  119. package/runtime/scripts/hfs/rules/doc-fresh.mjs +286 -0
  120. package/runtime/scripts/hfs/rules/docker-health.mjs +249 -0
  121. package/runtime/scripts/hfs/rules/docker.mjs +24 -7
  122. package/runtime/scripts/hfs/rules/edition.mjs +11 -10
  123. package/runtime/scripts/hfs/rules/env-parity.mjs +373 -0
  124. package/runtime/scripts/hfs/rules/env-value-shape.mjs +113 -0
  125. package/runtime/scripts/hfs/rules/event-bus.mjs +3 -2
  126. package/runtime/scripts/hfs/rules/event-tables.mjs +100 -0
  127. package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +115 -15
  128. package/runtime/scripts/hfs/rules/fe-stack.mjs +57 -0
  129. package/runtime/scripts/hfs/rules/feature-files.mjs +28 -0
  130. package/runtime/scripts/hfs/rules/frontend-tree.mjs +54 -35
  131. package/runtime/scripts/hfs/rules/integration-specs.mjs +3 -2
  132. package/runtime/scripts/hfs/rules/lexicon.mjs +62 -0
  133. package/runtime/scripts/hfs/rules/lite-proof-lane.mjs +89 -0
  134. package/runtime/scripts/hfs/rules/monorepo.mjs +14 -1
  135. package/runtime/scripts/hfs/rules/pipeline.mjs +8 -1
  136. package/runtime/scripts/hfs/rules/proof-commands.mjs +2 -0
  137. package/runtime/scripts/hfs/rules/release-provenance.mjs +211 -0
  138. package/runtime/scripts/hfs/rules/saga-delivery.mjs +66 -0
  139. package/runtime/scripts/hfs/rules/saga.mjs +8 -16
  140. package/runtime/scripts/hfs/rules/script-hygiene.mjs +151 -0
  141. package/runtime/scripts/hfs/rules/secret-custody-only.mjs +65 -0
  142. package/runtime/scripts/hfs/rules/secrets.mjs +26 -0
  143. package/runtime/scripts/hfs/rules/services.mjs +4 -4
  144. package/runtime/scripts/hfs/rules/stack-tooling.mjs +93 -0
  145. package/runtime/scripts/hfs/rules/stacks-deploy.mjs +76 -0
  146. package/runtime/scripts/hfs/rules/stacks-ingress.mjs +87 -0
  147. package/runtime/scripts/hfs/rules/stacks-lite-backing.mjs +111 -0
  148. package/runtime/scripts/hfs/rules/stacks-release.mjs +366 -0
  149. package/runtime/scripts/hfs/rules/stacks-runtime.mjs +168 -0
  150. package/runtime/scripts/hfs/rules/stacks-swarm.mjs +417 -0
  151. package/runtime/scripts/hfs/rules/stacks.mjs +13 -8
  152. package/runtime/scripts/hfs/rules/supabase-secrets.mjs +1 -1
  153. package/runtime/scripts/hfs/rules/supply-chain.mjs +167 -0
  154. package/runtime/scripts/hfs/rules/unused-symbol-flow.mjs +101 -0
  155. package/runtime/scripts/hfs/rules/unused-symbol-ledger.mjs +77 -0
  156. package/runtime/scripts/hfs/rules/unused-symbol-translators.mjs +165 -0
  157. package/runtime/scripts/hfs/rules/unused-symbol-values.mjs +103 -0
  158. package/runtime/scripts/hfs/rules/unused-symbol.mjs +320 -0
  159. package/runtime/scripts/hfs/runtime-rules/source-ast.mjs +185 -0
  160. package/runtime/scripts/hfs/runtime-rules/workflow-source.mjs +19 -0
  161. package/runtime/scripts/hfs/sealed-members.mjs +101 -0
  162. package/runtime/scripts/hfs/secret-bootstrap-crypto.mjs +200 -0
  163. package/runtime/scripts/hfs/secret-document.mjs +97 -0
  164. package/runtime/scripts/hfs/secret-edit.mjs +170 -0
  165. package/runtime/scripts/hfs/secret-errors.mjs +20 -0
  166. package/runtime/scripts/hfs/secret-files.mjs +124 -0
  167. package/runtime/scripts/hfs/secret-init.mjs +300 -0
  168. package/runtime/scripts/hfs/secret-output.mjs +100 -0
  169. package/runtime/scripts/hfs/secret-sops.mjs +130 -0
  170. package/runtime/scripts/hfs/secret-store.mjs +163 -0
  171. package/runtime/scripts/hfs/secret.mjs +162 -193
  172. package/runtime/scripts/hfs/slot-imports.mjs +18 -3
  173. package/runtime/scripts/hfs/slot-required.mjs +13 -0
  174. package/runtime/scripts/hfs/slot-semantic-problems.mjs +2 -1
  175. package/runtime/scripts/hfs/slots.mjs +1 -0
  176. package/runtime/scripts/hfs/stack-config-kit.mjs +34 -0
  177. package/runtime/scripts/hfs/stack-deploy-config.mjs +313 -0
  178. package/runtime/scripts/hfs/stack-ingress-config.mjs +237 -0
  179. package/runtime/scripts/hfs/stacks-gate.mjs +414 -0
  180. package/runtime/scripts/hfs/starcistacks-runtime.mjs +61 -0
  181. package/runtime/scripts/hfs/tree-findings.mjs +22 -0
  182. package/runtime/scripts/lib/command-tokens.mjs +126 -0
  183. package/runtime/scripts/lib/compose-values.mjs +11 -0
  184. package/runtime/scripts/lib/deployment-findings.mjs +7 -0
  185. package/runtime/scripts/lib/json-clone.mjs +61 -0
  186. package/runtime/scripts/lib/list.mjs +4 -0
  187. package/runtime/scripts/lib/roots.mjs +59 -0
  188. package/runtime/scripts/lib/runtime-example.mjs +13 -0
  189. package/runtime/scripts/lib/secret-patterns.mjs +60 -5
  190. package/runtime/scripts/lib/sql-ast.mjs +32 -0
  191. package/runtime/scripts/lib/stack-services.mjs +1 -1
  192. package/runtime/scripts/lib/swarm-stack.mjs +126 -0
  193. package/runtime/scripts/lib/trim-end.mjs +8 -0
  194. package/runtime/scripts/lib/ts-analysis.mjs +23 -0
  195. package/runtime/scripts/lib/ts-ast.mjs +27 -2
  196. package/runtime/scripts/lib/workflow-events.mjs +8 -0
  197. package/scaffold/add-app.mjs +77 -59
  198. package/scaffold/add-cli-lite.mjs +24 -17
  199. package/scaffold/add-compose.mjs +79 -0
  200. package/scaffold/add-database-lite.mjs +14 -0
  201. package/scaffold/add-fe-overlay.mjs +122 -0
  202. package/scaffold/add-fe-page.mjs +269 -0
  203. package/scaffold/add-inbox-lite.mjs +87 -124
  204. package/scaffold/add-plan.mjs +183 -0
  205. package/scaffold/add-table.mjs +132 -70
  206. package/scaffold/add.mjs +186 -204
  207. package/scaffold/app.mjs +128 -43
  208. package/scaffold/edition-gate.mjs +3 -3
  209. package/scaffold/image.mjs +2 -2
  210. package/scaffold/lite-exports.mjs +2 -1
  211. package/scaffold/service.mjs +2 -2
  212. package/src/main.mjs +238 -119
  213. package/stack/age-install.mjs +37 -0
  214. package/stack/backup.mjs +100 -0
  215. package/stack/build-args.mjs +42 -0
  216. package/stack/build.mjs +173 -0
  217. package/stack/cli.mjs +130 -0
  218. package/stack/config.mjs +57 -0
  219. package/stack/context.mjs +57 -0
  220. package/stack/converge.mjs +107 -0
  221. package/stack/deploy.mjs +301 -0
  222. package/stack/digest.mjs +16 -0
  223. package/stack/docker-transport.mjs +53 -0
  224. package/stack/edge-alias.mjs +118 -0
  225. package/stack/errors.mjs +21 -0
  226. package/stack/image-scan.mjs +152 -0
  227. package/stack/ingress-create.mjs +114 -0
  228. package/stack/ingress-publish.mjs +273 -0
  229. package/stack/ingress.mjs +706 -0
  230. package/stack/jobs.mjs +51 -0
  231. package/stack/live-restore.mjs +177 -0
  232. package/stack/prepare.mjs +266 -0
  233. package/stack/private-file.mjs +22 -0
  234. package/stack/provision.mjs +90 -0
  235. package/stack/prune.mjs +46 -0
  236. package/stack/release-store.mjs +87 -0
  237. package/stack/remote.mjs +205 -0
  238. package/stack/render.mjs +149 -0
  239. package/stack/retire.mjs +47 -0
  240. package/stack/sealed.mjs +149 -0
  241. package/stack/task.mjs +42 -0
  242. package/stack/verify.mjs +99 -0
  243. package/sync/ci-commands.mjs +13 -0
  244. package/sync/index.mjs +127 -64
  245. package/sync/stack-images.mjs +127 -0
  246. package/templates/app/ci-workflows/github/workflows/ci.yml +5 -1
  247. package/templates/app/ci-workflows/github/workflows/images.yml +15 -3
  248. package/templates/app/ci-workflows/github/workflows/stack-deploy.yml +148 -0
  249. package/templates/app/ci-workflows-lite/github/workflows/ci.yml +7 -3
  250. package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +38 -6
  251. package/templates/app/ci-workflows-lite/github/workflows/images.yml +14 -2
  252. package/templates/app/ci-workflows-lite/github/workflows/stack-deploy.yml +148 -0
  253. package/templates/app/codegen-graphql.mjs.partial +13 -2
  254. package/templates/app/codegen-lite/scripts/codegen.mjs +6 -1
  255. package/templates/app/codegen-prelude.mjs.partial +8 -0
  256. package/templates/app/gitignore +4 -0
  257. package/templates/app/gitignore-lite +4 -0
  258. package/templates/app/hooks/husky/pre-commit +7 -12
  259. package/templates/app/package-scripts/package.json +1 -0
  260. package/templates/app/package-scripts/supabase.json +7 -0
  261. package/templates/app/package-scripts-lite/package.json +1 -7
  262. package/templates/app/skeleton/.editorconfig +1 -0
  263. package/templates/app/skeleton/.gitattributes +7 -1
  264. package/templates/app/skeleton/.github/dependabot.yml +17 -0
  265. package/templates/app/skeleton/.nvmrc +1 -1
  266. package/templates/app/skeleton/.sops.yaml +1 -1
  267. package/templates/app/skeleton/.starcistacks/application-stacks.yaml +134 -1
  268. package/templates/app/skeleton/.starcistacks/dev/README.md +16 -0
  269. package/templates/app/skeleton/.starcistacks/dev/environment.json +5 -0
  270. package/templates/app/skeleton/.starcistacks/dev/infra/compose/stack.yaml +71 -0
  271. package/templates/app/skeleton/.starcistacks/dev/runtime/env/KEYS.md +14 -0
  272. package/templates/app/skeleton/.starcistacks/production/README.md +37 -0
  273. package/templates/app/skeleton/.starcistacks/production/environment.json +5 -0
  274. package/templates/app/skeleton/.starcistacks/production/infra/swarm/Caddyfile +15 -0
  275. package/templates/app/skeleton/.starcistacks/production/infra/swarm/owner-actions.md +11 -0
  276. package/templates/app/skeleton/.starcistacks/production/infra/swarm/recovery/restore-proof.md +7 -0
  277. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/current.yaml +6 -0
  278. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/images.lock.yaml +9 -0
  279. package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/previous.yaml +6 -0
  280. package/templates/app/skeleton/.starcistacks/production/infra/swarm/stack.yaml +142 -0
  281. package/templates/app/skeleton/.starcistacks/production/runtime/env/KEYS.md +14 -0
  282. package/templates/app/skeleton/README.md +6 -6
  283. package/templates/app/skeleton/scripts/codegen.mjs +1 -2
  284. package/templates/app/skeleton-lite/.editorconfig +16 -0
  285. package/templates/app/skeleton-lite/.gitattributes +8 -0
  286. package/templates/app/skeleton-lite/.github/dependabot.yml +17 -0
  287. package/templates/app/skeleton-lite/.nvmrc +1 -0
  288. package/templates/app/skeleton-lite/.sops.yaml +3 -2
  289. package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +193 -0
  290. package/templates/app/skeleton-lite/.starcistacks/dev/README.md +20 -0
  291. package/templates/app/skeleton-lite/.starcistacks/dev/environment.json +2 -1
  292. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/Caddyfile +16 -0
  293. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/owner-actions.md +11 -0
  294. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/recovery/restore-proof.md +7 -0
  295. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/current.yaml +6 -0
  296. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/images.lock.yaml +8 -0
  297. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/previous.yaml +6 -0
  298. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/stack.yaml +120 -0
  299. package/templates/app/skeleton-lite/.starcistacks/dev/runtime/env/KEYS.md +18 -0
  300. package/templates/app/skeleton-lite/.starcistacks/production/README.md +38 -0
  301. package/templates/app/skeleton-lite/.starcistacks/production/environment.json +6 -0
  302. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/Caddyfile +11 -0
  303. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/owner-actions.md +11 -0
  304. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/recovery/restore-proof.md +7 -0
  305. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/current.yaml +6 -0
  306. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/images.lock.yaml +8 -0
  307. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/previous.yaml +6 -0
  308. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/stack.yaml +121 -0
  309. package/templates/app/skeleton-lite/.starcistacks/production/runtime/env/KEYS.md +21 -0
  310. package/templates/app/skeleton-lite/.starciwork/brand/index.yaml +12 -0
  311. package/templates/app/skeleton-lite/.starciwork/workspace.yaml +9 -0
  312. package/templates/app/skeleton-lite/README.md +8 -4
  313. package/templates/app/skeleton-lite/supabase/config.toml +8 -1
  314. package/templates/app/skeleton-lite/supabase/migrations/__timestamp___baseline.sql +15 -6
  315. package/templates/app/starciwork.gitignore-lite +6 -0
  316. package/templates/app/upgrade-full/.starcistacks/dev/README.md +13 -7
  317. package/templates/be/image/worker/Dockerfile +1 -1
  318. package/templates/be/inbox/database-client.spec.ts.tpl +22 -28
  319. package/templates/be/inbox/database-client.ts.tpl +14 -28
  320. package/templates/be/inbox/delivery-recorded.event.ts.tpl +36 -0
  321. package/templates/be/inbox/event-index.ts.tpl +1 -0
  322. package/templates/be/inbox/events.json.tpl +10 -0
  323. package/templates/be/inbox/migration.sql.tpl +1 -0
  324. package/templates/be/inbox/platform/event-bus/event-bus.contracts.ts.tpl +42 -0
  325. package/templates/be/inbox/platform/event-bus/event-bus.decorators.ts.tpl +9 -0
  326. package/templates/be/inbox/platform/event-bus/event-bus.module-definition.ts.tpl +6 -0
  327. package/templates/be/inbox/platform/event-bus/event-bus.module.ts.tpl +19 -0
  328. package/templates/be/inbox/platform/event-bus/event-bus.options.ts.tpl +2 -0
  329. package/templates/be/inbox/platform/event-bus/event-bus.port.ts.tpl +16 -0
  330. package/templates/be/inbox/platform/event-bus/event-bus.service.spec.ts.tpl +45 -0
  331. package/templates/be/inbox/platform/event-bus/event-bus.service.ts.tpl +15 -0
  332. package/templates/be/inbox/platform/event-bus/index.ts.tpl +5 -0
  333. package/templates/be/inbox/platform/event-bus/persistence/event-bus.sql.ts.tpl +5 -0
  334. package/templates/be/inbox/platform/inbox/inbox.decorators.ts.tpl +9 -0
  335. package/templates/be/inbox/platform/inbox/inbox.module-definition.ts.tpl +6 -0
  336. package/templates/be/inbox/platform/inbox/inbox.module.ts.tpl +19 -0
  337. package/templates/be/inbox/platform/inbox/inbox.options.ts.tpl +2 -0
  338. package/templates/be/inbox/platform/inbox/inbox.port.ts.tpl +10 -0
  339. package/templates/be/inbox/platform/inbox/inbox.service.spec.ts.tpl +41 -0
  340. package/templates/be/inbox/platform/inbox/inbox.service.ts.tpl +19 -0
  341. package/templates/be/inbox/platform/inbox/index.ts.tpl +3 -0
  342. package/templates/be/inbox/platform/inbox/persistence/inbox.sql.ts.tpl +7 -0
  343. package/templates/be/inbox/platform/migration.sql.tpl +48 -0
  344. package/templates/be/inbox/service.spec.ts.tpl +49 -20
  345. package/templates/be/inbox/service.ts.tpl +27 -16
  346. package/templates/be/inbox/sql.ts.tpl +2 -2
  347. package/templates/be/inbox/webhook-door.spec.ts.tpl +3 -3
  348. package/templates/be/inbox/webhook-door.ts.tpl +4 -3
  349. package/templates/be/patterns/api/feature.module-definition.ts.tpl +6 -0
  350. package/templates/be/patterns/api/feature.module.ts.tpl +2 -1
  351. package/templates/be/patterns/api/feature.options.ts.tpl +2 -0
  352. package/templates/be/patterns/api/graphql.module-definition.ts.tpl +6 -0
  353. package/templates/be/patterns/api/graphql.module.ts.tpl +3 -2
  354. package/templates/be/patterns/api/graphql.options.ts.tpl +2 -0
  355. package/templates/be/patterns/cli/group.module-definition.ts.tpl +6 -0
  356. package/templates/be/patterns/cli/group.module.ts.tpl +2 -1
  357. package/templates/be/patterns/cli/group.options.ts.tpl +2 -0
  358. package/templates/be/patterns/event-bus/platform/errors/event-bus.error.ts.tpl +0 -3
  359. package/templates/be/patterns/event-bus/platform/messages/event-bus.messages.ts.tpl +0 -2
  360. package/templates/be/patterns/jobs/job.module-definition.ts.tpl +6 -0
  361. package/templates/be/patterns/jobs/job.module.ts.tpl +2 -1
  362. package/templates/be/patterns/jobs/job.options.ts.tpl +2 -0
  363. package/templates/be/patterns/jobs/job.queue.module-definition.ts.tpl +6 -0
  364. package/templates/be/patterns/jobs/job.queue.module.ts.tpl +6 -3
  365. package/templates/be/patterns/jobs/job.queue.options.ts.tpl +2 -0
  366. package/templates/be/patterns/jobs/platform/fenced.processor.spec.ts.tpl +3 -1
  367. package/templates/be/patterns/outbox/platform/outbox-relay.policy.spec.ts.tpl +25 -9
  368. package/templates/be/patterns/queues/platform/queue.config.ts.tpl +1 -1
  369. package/templates/be/patterns/queues/platform/queue.index.ts.tpl +1 -1
  370. package/templates/be/patterns/queues/platform/queue.module-definition.ts.tpl +2 -2
  371. package/templates/be/patterns/queues/platform/queue.module.ts.tpl +11 -0
  372. package/templates/be/patterns/queues/platform/queue.options.ts.tpl +10 -0
  373. package/templates/be/patterns/queues/queue.module-definition.ts.tpl +6 -0
  374. package/templates/be/patterns/queues/queue.module.ts.tpl +2 -1
  375. package/templates/be/patterns/queues/queue.options.ts.tpl +2 -0
  376. package/templates/be/patterns/reactors/message.module-definition.ts.tpl +6 -0
  377. package/templates/be/patterns/reactors/message.module.ts.tpl +6 -3
  378. package/templates/be/patterns/reactors/message.options.ts.tpl +2 -0
  379. package/templates/be/patterns/reactors/reactor.module-definition.ts.tpl +6 -0
  380. package/templates/be/patterns/reactors/reactor.module.ts.tpl +2 -1
  381. package/templates/be/patterns/reactors/reactor.options.ts.tpl +2 -0
  382. package/templates/be/patterns/realtime/channel.gateway.spec.ts.tpl +188 -0
  383. package/templates/be/patterns/realtime/channel.gateway.ts.tpl +22 -0
  384. package/templates/be/patterns/realtime/channel.graphql.module-definition.ts.tpl +6 -0
  385. package/templates/be/patterns/realtime/channel.graphql.module.ts.tpl +2 -1
  386. package/templates/be/patterns/realtime/channel.graphql.options.ts.tpl +2 -0
  387. package/templates/be/patterns/realtime/channel.websocket.module-definition.ts.tpl +6 -0
  388. package/templates/be/patterns/realtime/channel.websocket.module.ts.tpl +110 -0
  389. package/templates/be/patterns/realtime/channel.websocket.options.ts.tpl +7 -0
  390. package/templates/be/patterns/saga/saga.message.module-definition.ts.tpl +6 -0
  391. package/templates/be/patterns/saga/saga.message.module.ts.tpl +6 -3
  392. package/templates/be/patterns/saga/saga.message.options.ts.tpl +2 -0
  393. package/templates/be/patterns/saga/saga.module-definition.ts.tpl +6 -0
  394. package/templates/be/patterns/saga/saga.module.ts.tpl +2 -1
  395. package/templates/be/patterns/saga/saga.options.ts.tpl +2 -0
  396. package/templates/be/patterns/webhooks/webhook.door.spec.ts.tpl +3 -3
  397. package/templates/be/patterns/webhooks/webhook.door.ts.tpl +3 -3
  398. package/templates/be/patterns/webhooks/webhook.http.module-definition.ts.tpl +6 -0
  399. package/templates/be/patterns/webhooks/webhook.http.module.ts.tpl +2 -1
  400. package/templates/be/patterns/webhooks/webhook.http.options.ts.tpl +2 -0
  401. package/templates/be/platform/graphql/localize-errors.mapper.spec.ts +80 -26
  402. package/templates/be/platform/graphql/localize-errors.mapper.ts +2 -5
  403. package/templates/be/skeleton/apps/__app__/src/__app__.env.ts +21 -0
  404. package/templates/be/skeleton/apps/__app__/src/__app__.options.ts +1 -1
  405. package/templates/be/skeleton/apps/__app__/src/app.module.ts +15 -45
  406. package/templates/be/skeleton/apps/__app__/src/compose/api.ts +4 -0
  407. package/templates/be/skeleton/apps/__app__/src/compose/domain.ts +11 -0
  408. package/templates/be/skeleton/apps/__app__/src/compose/platform.ts +44 -0
  409. package/templates/be/skeleton/apps/__app__/src/compose/system.ts +5 -0
  410. package/templates/be/skeleton/apps/__app__/src/compose/webhooks.ts +4 -0
  411. package/templates/be/skeleton/apps/__app__/src/main.ts +18 -10
  412. package/templates/be/skeleton/apps/cli/src/app.module.ts +3 -13
  413. package/templates/be/skeleton/apps/cli/src/cli.env.ts +13 -0
  414. package/templates/be/skeleton/apps/cli/src/cli.options.ts +7 -17
  415. package/templates/be/skeleton/apps/cli/src/compose/cli.ts +5 -0
  416. package/templates/be/skeleton/apps/cli/src/compose/platform.ts +24 -0
  417. package/templates/be/skeleton/apps/cli/src/main.ts +3 -2
  418. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.contracts.ts +2 -0
  419. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.handler.ts +22 -0
  420. package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.query.ts +11 -0
  421. package/templates/be/skeleton/src/features/api/system-health/system-health.module-definition.ts +6 -0
  422. package/templates/be/skeleton/src/features/api/system-health/system-health.module.ts +5 -3
  423. package/templates/be/skeleton/src/features/api/system-health/system-health.options.ts +2 -0
  424. package/templates/be/skeleton/src/features/api/system-health/transport/http/ready.controller.ts +19 -0
  425. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module-definition.ts +6 -0
  426. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module.ts +8 -3
  427. package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.options.ts +2 -0
  428. package/templates/be/skeleton/src/features/cli/cli.module-definition.ts +6 -0
  429. package/templates/be/skeleton/src/features/cli/cli.module.ts +3 -2
  430. package/templates/be/skeleton/src/features/cli/cli.options.ts +2 -0
  431. package/templates/be/skeleton/src/features/cli/migrate/migrate.module-definition.ts +6 -0
  432. package/templates/be/skeleton/src/features/cli/migrate/migrate.module.ts +2 -1
  433. package/templates/be/skeleton/src/features/cli/migrate/migrate.options.ts +2 -0
  434. package/templates/be/skeleton/src/features/cli/seed/seed.module-definition.ts +6 -0
  435. package/templates/be/skeleton/src/features/cli/seed/seed.module.ts +2 -1
  436. package/templates/be/skeleton/src/features/cli/seed/seed.options.ts +2 -0
  437. package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.spec.ts +5 -6
  438. package/templates/be/skeleton/src/modules/domain/identity/admission.policy.spec.ts +56 -4
  439. package/templates/be/skeleton/src/modules/domain/identity/admission.policy.ts +36 -5
  440. package/templates/be/skeleton/src/modules/domain/identity/auth.guard.spec.ts +39 -8
  441. package/templates/be/skeleton/src/modules/domain/identity/auth.guard.ts +14 -8
  442. package/templates/be/skeleton/src/modules/domain/identity/credential.contracts.ts +26 -0
  443. package/templates/be/skeleton/src/modules/domain/identity/credential.guard.spec.ts +119 -0
  444. package/templates/be/skeleton/src/modules/domain/identity/credential.guard.ts +43 -0
  445. package/templates/be/skeleton/src/modules/domain/identity/identity.contracts.ts +16 -0
  446. package/templates/be/skeleton/src/modules/domain/identity/identity.decorators.ts +18 -1
  447. package/templates/be/skeleton/src/modules/domain/identity/identity.module.ts +22 -4
  448. package/templates/be/skeleton/src/modules/domain/identity/identity.options.ts +8 -2
  449. package/templates/be/skeleton/src/modules/domain/identity/index.ts +1 -0
  450. package/templates/be/skeleton/src/modules/platform/config/env-source.config.ts +6 -6
  451. package/templates/be/skeleton/src/modules/platform/database/connection-source.client.spec.ts +11 -4
  452. package/templates/be/skeleton/src/modules/platform/database/database-probe.service.spec.ts +32 -0
  453. package/templates/be/skeleton/src/modules/platform/database/database-probe.service.ts +14 -0
  454. package/templates/be/skeleton/src/modules/platform/database/database.module.ts +7 -1
  455. package/templates/be/skeleton/src/modules/platform/database/index.ts +2 -0
  456. package/templates/be/skeleton/src/modules/platform/database/primary.decorators.ts +8 -0
  457. package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.spec.ts +25 -6
  458. package/templates/be/skeleton/src/modules/platform/errors/errors.filter.spec.ts +16 -6
  459. package/templates/be/skeleton/src/modules/platform/http-security/edge-security.service.spec.ts +130 -0
  460. package/templates/be/skeleton/src/modules/platform/http-security/edge-security.service.ts +58 -0
  461. package/templates/be/skeleton/src/modules/platform/http-security/errors/http-security.error.ts +3 -0
  462. package/templates/be/skeleton/src/modules/platform/http-security/execution-request.mapper.spec.ts +16 -4
  463. package/templates/be/skeleton/src/modules/platform/http-security/http-security.config.ts +16 -10
  464. package/templates/be/skeleton/src/modules/platform/http-security/http-security.module.ts +3 -1
  465. package/templates/be/skeleton/src/modules/platform/http-security/http-security.options.ts +2 -0
  466. package/templates/be/skeleton/src/modules/platform/http-security/index.ts +5 -0
  467. package/templates/be/skeleton/src/modules/platform/http-security/messages/http-security.messages.ts +12 -5
  468. package/templates/be/skeleton/src/modules/platform/http-security/rate-limit.guard.spec.ts +13 -8
  469. package/templates/be/skeleton/src/modules/platform/http-security/readiness.contracts.ts +5 -0
  470. package/templates/be/skeleton/src/modules/platform/http-security/readiness.decorators.ts +7 -0
  471. package/templates/be/skeleton/src/modules/platform/http-security/readiness.service.spec.ts +86 -0
  472. package/templates/be/skeleton/src/modules/platform/http-security/readiness.service.ts +39 -0
  473. package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.spec.ts +139 -131
  474. package/templates/be/skeleton/src/modules/platform/i18n/index.ts +1 -1
  475. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.spec.ts +91 -67
  476. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.ts +5 -4
  477. package/templates/be/skeleton/src/modules/platform/logging/logging.log-events.ts +0 -2
  478. package/templates/be/skeleton/src/modules/platform/primitives/outcome.mapper.spec.ts +20 -6
  479. package/templates/be/skeleton/src/modules/platform/primitives/sequence.policy.spec.ts +16 -4
  480. package/templates/be/skeleton/src/modules/platform/retry/index.ts +3 -0
  481. package/templates/be/skeleton/src/modules/platform/retry/retry.decorators.ts +9 -0
  482. package/templates/be/skeleton/src/modules/platform/retry/retry.module-definition.ts +7 -0
  483. package/templates/be/skeleton/src/modules/platform/retry/retry.module.ts +19 -0
  484. package/templates/be/skeleton/src/modules/platform/retry/retry.options.ts +2 -0
  485. package/templates/be/skeleton/src/modules/platform/retry/retry.port.ts +11 -0
  486. package/templates/be/skeleton/src/modules/platform/retry/system-timer.service.spec.ts +36 -0
  487. package/templates/be/skeleton/src/modules/platform/retry/system-timer.service.ts +10 -0
  488. package/templates/be/skeleton/src/tests/contract/http-security/http-security.contract-spec.ts +54 -0
  489. package/templates/be/skeleton-lite/apps/api/src/api.env.ts +25 -0
  490. package/templates/be/skeleton-lite/apps/api/src/api.options.ts +1 -1
  491. package/templates/be/skeleton-lite/apps/api/src/app.module.ts +18 -58
  492. package/templates/be/skeleton-lite/apps/api/src/compose/api.ts +4 -0
  493. package/templates/be/skeleton-lite/apps/api/src/compose/domain.ts +10 -0
  494. package/templates/be/skeleton-lite/apps/api/src/compose/integrations.ts +16 -0
  495. package/templates/be/skeleton-lite/apps/api/src/compose/platform.ts +47 -0
  496. package/templates/be/skeleton-lite/apps/api/src/compose/system.ts +5 -0
  497. package/templates/be/skeleton-lite/apps/api/src/compose/webhooks.ts +4 -0
  498. package/templates/be/skeleton-lite/apps/api/src/main.ts +5 -13
  499. package/templates/be/skeleton-lite/apps/cli/src/cli.env.ts +17 -0
  500. package/templates/be/skeleton-lite/apps/cli/src/compose/platform.ts +12 -0
  501. package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.spec.ts +71 -5
  502. package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.ts +29 -2
  503. package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.spec.ts +68 -15
  504. package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.ts +14 -9
  505. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.contracts.ts +9 -2
  506. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.decorators.ts +16 -1
  507. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.module.ts +19 -4
  508. package/templates/be/skeleton-lite/src/modules/domain/identity/identity.options.ts +5 -1
  509. package/templates/be/skeleton-lite/src/modules/domain/identity/index.ts +2 -1
  510. package/templates/be/skeleton-lite/src/modules/integrations/supabase/errors/supabase.error.ts +0 -3
  511. package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.client.spec.ts +17 -5
  512. package/templates/be/skeleton-lite/src/modules/platform/database/database.module.ts +24 -13
  513. package/templates/be/skeleton-lite/src/modules/platform/database/database.port.ts +5 -0
  514. package/templates/be/skeleton-lite/src/modules/platform/database/errors/database.error.ts +16 -0
  515. package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +3 -0
  516. package/templates/be/skeleton-lite/src/modules/platform/http-security/http-security.module.ts +5 -2
  517. package/templates/be/skeleton-lite/src/modules/platform/http-security/index.ts +4 -1
  518. package/templates/be/skeleton-lite/src/modules/platform/i18n/index.ts +1 -1
  519. package/templates/be/skeleton-lite/src/modules/platform/logging/logging.log-events.ts +7 -0
  520. package/templates/be/skeleton-lite/src/tests/fixtures/builders/api.builder.ts +29 -0
  521. package/templates/be/skeleton-lite/src/tests/fixtures/builders/cli.builder.ts +16 -0
  522. package/templates/be/table/api/feature.module-definition.ts.tpl +6 -0
  523. package/templates/be/table/api/feature.module.ts.tpl +2 -1
  524. package/templates/be/table/api/feature.options.ts.tpl +2 -0
  525. package/templates/be/table/api/graphql.module-definition.ts.tpl +6 -0
  526. package/templates/be/table/api/graphql.module.ts.tpl +3 -2
  527. package/templates/be/table/api/graphql.options.ts.tpl +2 -0
  528. package/templates/be/table/migration.sql.tpl +1 -0
  529. package/templates/be/upgrade-full/apps/cli/src/app.module.ts +4 -6
  530. package/templates/be/upgrade-full/apps/cli/src/cli.env.ts +7 -0
  531. package/templates/be/upgrade-full/apps/cli/src/compose/cli.ts +5 -0
  532. package/templates/be/upgrade-full/apps/cli/src/compose/platform.ts +9 -0
  533. package/templates/be/upgrade-full/apps/cli/src/main.ts +3 -0
  534. package/templates/be/upgrade-full/src/features/cli/cli.module.ts +3 -2
  535. package/templates/fe/auth/supabase-client.ts.tpl +34 -0
  536. package/templates/fe/skeleton/apps/__app__/src/app/auth/callback/route.ts +11 -0
  537. package/templates/fe/skeleton/apps/__app__/src/components/blocks/SignInForm/index.tsx +6 -1
  538. package/templates/fe/skeleton/apps/__app__/src/components/leaves/Icon/index.tsx +4 -0
  539. package/templates/fe/skeleton/apps/__app__/src/features/overlays/AppGuideOverlay/component.tsx +31 -0
  540. package/templates/fe/skeleton/apps/__app__/src/features/overlays/AppGuideOverlay/index.tsx +24 -0
  541. package/templates/fe/skeleton/apps/__app__/src/hooks/auth/useSession.ts +6 -1
  542. package/templates/fe/skeleton/apps/__app__/src/hooks/auth/useSignOut.ts +3 -4
  543. package/templates/fe/skeleton/apps/__app__/src/hooks/zustand/appGuide/index.ts +1 -0
  544. package/templates/fe/skeleton/apps/__app__/src/hooks/zustand/appGuide/store.ts +15 -0
  545. package/templates/fe/skeleton/apps/__app__/src/modules/auth/pkce-client.ts +18 -0
  546. package/templates/fe/skeleton/apps/__app__/src/modules/auth/server.ts +19 -0
  547. package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/index.tsx +7 -1
  548. package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/en.json +57 -0
  549. package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/vi.json +6 -0
  550. package/templates/fe/skeleton/apps/landing/src/modules/i18n/messages/en.json +31 -0
  551. package/templates/fe/skeleton/packages/__project__-i18n/src/routing.ts +1 -1
  552. package/templates/fe/skeleton/packages/__project__-ui/src/index.ts +1 -0
  553. package/templates/fe/skeleton-lite/apps/__app__/src/modules/auth/client.ts +1 -34
  554. package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/index.tsx +7 -1
  555. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/en.json +57 -0
  556. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/vi.json +30 -24
  557. package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/routing.ts +1 -1
  558. package/templates/fe/transport/graphql/clients/clients/auth.ts +1 -1
  559. package/templates/fe/transport/graphql/clients/links/locale.ts +2 -2
  560. package/upgrade/check.mjs +3 -1
  561. package/upgrade/file-state.mjs +68 -0
  562. package/upgrade/index.mjs +58 -94
  563. package/runtime/scripts/api/git/log.mjs +0 -5
  564. package/templates/app/skeleton-lite/.starciwork/shell/index.yaml +0 -55
@@ -1,16 +1,15 @@
1
1
  "use client"
2
2
 
3
3
  import { useTransition } from "react"
4
- import type { GraphQLResponse } from "@/modules/api"
5
4
  import { authClient } from "@/modules/auth"
6
5
  import type { AuthFailure } from "@/modules/auth"
7
6
  import { useGraphQLWithToast } from "@/modules/toast"
8
7
 
9
8
  /** The app's one outcome of an auth call, so modules/toast reports it like any other write. */
10
- const responseOf = (failure: AuthFailure | undefined): GraphQLResponse<null> =>
9
+ const responseOf = (failure: AuthFailure | undefined) =>
11
10
  failure === undefined
12
- ? { success: true, data: null }
13
- : { success: false, error: failure.code, kind: failure.kind, message: failure.message }
11
+ ? { success: true as const, data: null }
12
+ : { success: false as const, error: failure.code, kind: failure.kind, message: failure.message }
14
13
 
15
14
  /**
16
15
  * Ends the reader's session through modules/auth: whether the request runs and the sign-out itself. A failure is reported by
@@ -0,0 +1 @@
1
+ export { useAppGuideStore } from "./store"
@@ -0,0 +1,15 @@
1
+ "use client"
2
+
3
+ import { create } from "zustand"
4
+
5
+ /** The home guide's local UI state; it carries no session or server data. */
6
+ type AppGuideState = {
7
+ readonly isOpen: boolean
8
+ readonly setOpen: (isOpen: boolean) => void
9
+ }
10
+
11
+ /** One feature-local store, shared by the guide trigger and its controlled dialog. */
12
+ export const useAppGuideStore = create<AppGuideState>()((set) => ({
13
+ isOpen: false,
14
+ setOpen: (isOpen) => set({ isOpen }),
15
+ }))
@@ -0,0 +1,18 @@
1
+ import { createBrowserClient } from "@supabase/ssr"
2
+ import type { Session, SupabaseClient } from "@supabase/supabase-js"
3
+ import { supabaseAnonKey, supabaseUrl } from "@/modules/config"
4
+ import type { AuthClient, AuthFailure, AuthSession } from "./contracts"
5
+
6
+ let client: SupabaseClient | undefined
7
+
8
+ /**
9
+ * The cookie-backed browser client of the opt-in server PKCE flow, used for Supabase Auth only.
10
+ * The callback exchanges the code; this client shares its verifier and session cookies. It never calls `.from()`, `.rpc()` or storage:
11
+ * data goes through modules/api to the back end, which verifies the access token.
12
+ */
13
+ const supabase = (): SupabaseClient =>
14
+ (client ??= createBrowserClient(supabaseUrl(), supabaseAnonKey(), {
15
+ auth: { flowType: "pkce", detectSessionInUrl: false, persistSession: true, autoRefreshToken: true },
16
+ }))
17
+
18
+ // {{> fe/auth/supabase-client.ts.tpl}}
@@ -0,0 +1,19 @@
1
+ import "server-only"
2
+ import { createServerClient } from "@supabase/ssr"
3
+ import { cookies } from "next/headers"
4
+ import { supabaseAnonKey, supabaseUrl } from "@/modules/config"
5
+
6
+ /** The server auth owner reads the PKCE verifier and persists the exchanged session in cookies. */
7
+ export async function exchangeAuthCode(code: string): Promise<void> {
8
+ const cookieStore = await cookies()
9
+ const client = createServerClient(supabaseUrl(), supabaseAnonKey(), {
10
+ cookies: {
11
+ getAll: () => cookieStore.getAll(),
12
+ setAll: (values) => {
13
+ for (const { name, value, options } of values) cookieStore.set(name, value, options)
14
+ },
15
+ },
16
+ })
17
+ const { error } = await client.auth.exchangeCodeForSession(code)
18
+ if (error) throw error
19
+ }
@@ -1,5 +1,6 @@
1
1
  import type { Metadata } from "next"
2
2
  import { getTranslations } from "next-intl/server"
3
+ import { AppGuideOverlay } from "@/features/overlays/AppGuideOverlay"
3
4
  import { AppHomePageBase } from "./component"
4
5
 
5
6
  /** The document title of the home page, from the catalog of the requested locale. */
@@ -11,5 +12,10 @@ export const appHomeMetadata = async (): Promise<Metadata> => {
11
12
  /** The first page of the product app: a server component; the session surface it draws runs on the client. */
12
13
  export const AppHomePage = async () => {
13
14
  const t = await getTranslations("app.home")
14
- return <AppHomePageBase props={{ title: t("title") }} />
15
+ return (
16
+ <>
17
+ <AppHomePageBase props={{ title: t("title") }} />
18
+ <AppGuideOverlay />
19
+ </>
20
+ )
15
21
  }
@@ -0,0 +1,57 @@
1
+ {
2
+ "app": {
3
+ "title": "{{project}}",
4
+ "shell": {
5
+ "brand": "{{project}}"
6
+ },
7
+ "home": {
8
+ "title": "Home"
9
+ },
10
+ "signIn": {
11
+ "title": "Sign in",
12
+ "email": "Email",
13
+ "password": "Password",
14
+ "submit": "Continue",
15
+ "working": "Signing in",
16
+ "refused": "The credentials were refused.",
17
+ "invalid": "Enter a valid email and password.",
18
+ "unavailable": "Sign-in is unavailable. Try again shortly."
19
+ },
20
+ "signOut": {
21
+ "signedIn": "Signed in",
22
+ "submit": "Sign out",
23
+ "working": "Signing out"
24
+ },
25
+ "toast": {
26
+ "successTitle": "Done",
27
+ "errorTitle": "Error",
28
+ "unauthorizedTitle": "Not signed in",
29
+ "unauthorizedDescription": "Sign in to continue.",
30
+ "defaultSuccess": "The change was saved.",
31
+ "defaultError": "Something went wrong."
32
+ },
33
+ "loading": {
34
+ "message": "Loading"
35
+ },
36
+ "notFound": {
37
+ "title": "Page not found",
38
+ "home": "Return home"
39
+ },
40
+ "errors": {
41
+ "page": {
42
+ "title": "Something went wrong",
43
+ "retry": "Try again"
44
+ },
45
+ "global": {
46
+ "title": "The application could not continue",
47
+ "retry": "Try again"
48
+ }
49
+ },
50
+ "guide": {
51
+ "open": "View guide",
52
+ "title": "Getting started",
53
+ "description": "Sign in to use the application. You can close this guide and open it again at any time.",
54
+ "close": "Close"
55
+ }
56
+ }
57
+ }
@@ -46,6 +46,12 @@
46
46
  "title": "Đã xảy ra lỗi nghiêm trọng",
47
47
  "retry": "Thử lại"
48
48
  }
49
+ },
50
+ "guide": {
51
+ "open": "Xem hướng dẫn",
52
+ "title": "Bắt đầu",
53
+ "description": "Đăng nhập để sử dụng ứng dụng. Bạn có thể đóng hướng dẫn này và mở lại bất cứ lúc nào.",
54
+ "close": "Đóng"
49
55
  }
50
56
  }
51
57
  }
@@ -0,0 +1,31 @@
1
+ {
2
+ "landing": {
3
+ "title": "{{project}}",
4
+ "description": "The introduction to {{project}}.",
5
+ "shell": {
6
+ "brand": "{{project}}"
7
+ },
8
+ "home": {
9
+ "title": "Welcome to {{project}}",
10
+ "lede": "Everything you need is in the application.",
11
+ "openApp": "Open the application"
12
+ },
13
+ "loading": {
14
+ "message": "Loading"
15
+ },
16
+ "notFound": {
17
+ "title": "Page not found",
18
+ "home": "Return home"
19
+ },
20
+ "errors": {
21
+ "page": {
22
+ "title": "Something went wrong",
23
+ "retry": "Try again"
24
+ },
25
+ "global": {
26
+ "title": "The application could not continue",
27
+ "retry": "Try again"
28
+ }
29
+ }
30
+ }
31
+ }
@@ -1,7 +1,7 @@
1
1
  import { defineRouting } from "next-intl/routing"
2
2
 
3
3
  /** The locales every app of the product serves; every catalog of an app has the same keys in each. */
4
- const LOCALES = ["vi"] as const
4
+ const LOCALES = ["vi", "en"] as const
5
5
 
6
6
  /** The locale served at the unprefixed path, and the language of a document no locale reached (the global error boundary). */
7
7
  export const DEFAULT_LOCALE = "vi"
@@ -4,3 +4,4 @@ export { LoadingNotice } from "./composites/LoadingNotice"
4
4
  export { LocaleShell } from "./composites/LocaleShell"
5
5
  export { NotFoundNotice } from "./composites/NotFoundNotice"
6
6
  export { SiteShell } from "./composites/SiteShell"
7
+ export { Icon } from "./leaves/Icon"
@@ -15,37 +15,4 @@ const supabase = (): SupabaseClient =>
15
15
  auth: { flowType: "pkce", detectSessionInUrl: true, persistSession: true, autoRefreshToken: true },
16
16
  }))
17
17
 
18
- const sessionOf = (session: Session | null): AuthSession | undefined =>
19
- session === null
20
- ? undefined
21
- : { userId: session.user.id, ...(session.user.email === undefined ? {} : { email: session.user.email }) }
22
-
23
- /** A Supabase Auth error as the provider reports it: its HTTP status, its code and its message. */
24
- type ProviderError = { readonly status?: number; readonly code?: string; readonly message: string }
25
-
26
- /** The failure kind of a Supabase Auth error: refused credentials, rejected input, or the provider unavailable. */
27
- const kindOf = (status: number | undefined): string => {
28
- if (status === 400 || status === 401 || status === 403) return "refused"
29
- return status === 422 ? "invalid" : "unavailable"
30
- }
31
-
32
- /** The failure of a Supabase Auth call, or undefined when it succeeded. */
33
- const failureOf = (error: ProviderError | null): AuthFailure | undefined =>
34
- error === null
35
- ? undefined
36
- : { code: error.code ?? String(error.status ?? "auth"), kind: kindOf(error.status), message: error.message }
37
-
38
- /** The identity-provider client of a lite app: Supabase Auth in the browser. */
39
- export const authClient: AuthClient = {
40
- session: async () => sessionOf((await supabase().auth.getSession()).data.session),
41
- accessToken: async () => (await supabase().auth.getSession()).data.session?.access_token,
42
- refreshAccessToken: async () => (await supabase().auth.refreshSession()).data.session?.access_token,
43
- signInWithPassword: async (email, password) =>
44
- failureOf((await supabase().auth.signInWithPassword({ email, password })).error),
45
- signOut: async () => failureOf((await supabase().auth.signOut()).error),
46
- // Supabase reports INITIAL_SESSION on subscribe, then every change: the subscription alone keeps the session current.
47
- onChange: (listener) => {
48
- const { data } = supabase().auth.onAuthStateChange((_event, session) => listener(sessionOf(session)))
49
- return () => data.subscription.unsubscribe()
50
- },
51
- }
18
+ // {{> fe/auth/supabase-client.ts.tpl}}
@@ -1,5 +1,6 @@
1
1
  import type { Metadata } from "next"
2
2
  import { getTranslations } from "next-intl/server"
3
+ import { AppGuideOverlay } from "@/features/overlays/AppGuideOverlay"
3
4
  import { AppHomePageBase } from "./component"
4
5
 
5
6
  /** The document title of the home page. */
@@ -11,5 +12,10 @@ export const appHomeMetadata = async (): Promise<Metadata> => {
11
12
  /** The front door (the session is client-side, drawn by the blocks the page composes). */
12
13
  export const AppHomePage = async () => {
13
14
  const t = await getTranslations("app.home")
14
- return <AppHomePageBase props={{ title: t("title") }} />
15
+ return (
16
+ <>
17
+ <AppHomePageBase props={{ title: t("title") }} />
18
+ <AppGuideOverlay />
19
+ </>
20
+ )
15
21
  }
@@ -0,0 +1,57 @@
1
+ {
2
+ "app": {
3
+ "title": "{{project}}",
4
+ "shell": {
5
+ "brand": "{{project}}"
6
+ },
7
+ "home": {
8
+ "title": "Home"
9
+ },
10
+ "signIn": {
11
+ "title": "Sign in",
12
+ "email": "Email",
13
+ "password": "Password",
14
+ "submit": "Continue",
15
+ "working": "Signing in",
16
+ "refused": "The credentials were refused.",
17
+ "invalid": "Enter a valid email and password.",
18
+ "unavailable": "Sign-in is unavailable. Try again shortly."
19
+ },
20
+ "signOut": {
21
+ "signedIn": "Signed in",
22
+ "submit": "Sign out",
23
+ "working": "Signing out"
24
+ },
25
+ "toast": {
26
+ "successTitle": "Done",
27
+ "errorTitle": "Error",
28
+ "unauthorizedTitle": "Not signed in",
29
+ "unauthorizedDescription": "Sign in to continue.",
30
+ "defaultSuccess": "The change was saved.",
31
+ "defaultError": "Something went wrong."
32
+ },
33
+ "loading": {
34
+ "message": "Loading"
35
+ },
36
+ "notFound": {
37
+ "title": "Page not found",
38
+ "home": "Return home"
39
+ },
40
+ "errors": {
41
+ "page": {
42
+ "title": "Something went wrong",
43
+ "retry": "Try again"
44
+ },
45
+ "global": {
46
+ "title": "The application could not continue",
47
+ "retry": "Try again"
48
+ }
49
+ },
50
+ "guide": {
51
+ "open": "View guide",
52
+ "title": "Getting started",
53
+ "description": "Sign in to use the application. You can close this guide and open it again at any time.",
54
+ "close": "Close"
55
+ }
56
+ }
57
+ }
@@ -5,47 +5,53 @@
5
5
  "brand": "{{project}}"
6
6
  },
7
7
  "home": {
8
- "title": "Home"
8
+ "title": "Trang chủ"
9
9
  },
10
10
  "signIn": {
11
- "title": "Sign in",
11
+ "title": "Đăng nhập",
12
12
  "email": "Email",
13
- "password": "Password",
14
- "submit": "Continue",
15
- "working": "Signing in",
16
- "refused": "The credentials were refused.",
17
- "invalid": "Enter a valid email and password.",
18
- "unavailable": "Sign-in is unavailable. Try again shortly."
13
+ "password": "Mật khẩu",
14
+ "submit": "Tiếp tục",
15
+ "working": "Đang đăng nhập",
16
+ "refused": "Thông tin đăng nhập không đúng.",
17
+ "invalid": "Hãy nhập email và mật khẩu hợp lệ.",
18
+ "unavailable": "Chưa thể đăng nhập. Hãy thử lại sau."
19
19
  },
20
20
  "signOut": {
21
- "signedIn": "Signed in",
22
- "submit": "Sign out",
23
- "working": "Signing out"
21
+ "signedIn": "Đã đăng nhập",
22
+ "submit": "Đăng xuất",
23
+ "working": "Đang đăng xuất"
24
24
  },
25
25
  "toast": {
26
- "successTitle": "Done",
27
- "errorTitle": "Error",
28
- "unauthorizedTitle": "Not signed in",
29
- "unauthorizedDescription": "Sign in to continue.",
30
- "defaultSuccess": "The change was saved.",
31
- "defaultError": "Something went wrong."
26
+ "successTitle": "Thành công",
27
+ "errorTitle": "Lỗi",
28
+ "unauthorizedTitle": "Chưa đăng nhập",
29
+ "unauthorizedDescription": "Hãy đăng nhập để tiếp tục.",
30
+ "defaultSuccess": "Đã hoàn tất.",
31
+ "defaultError": "Đã xảy ra lỗi."
32
32
  },
33
33
  "loading": {
34
- "message": "Loading"
34
+ "message": "Đang tải"
35
35
  },
36
36
  "notFound": {
37
- "title": "Page not found",
38
- "home": "Return home"
37
+ "title": "Không tìm thấy trang",
38
+ "home": "Về trang chủ"
39
39
  },
40
40
  "errors": {
41
41
  "page": {
42
- "title": "Something went wrong",
43
- "retry": "Try again"
42
+ "title": "Đã xảy ra lỗi",
43
+ "retry": "Thử lại"
44
44
  },
45
45
  "global": {
46
- "title": "The application could not continue",
47
- "retry": "Try again"
46
+ "title": "Đã xảy ra lỗi nghiêm trọng",
47
+ "retry": "Thử lại"
48
48
  }
49
+ },
50
+ "guide": {
51
+ "open": "Xem hướng dẫn",
52
+ "title": "Bắt đầu",
53
+ "description": "Đăng nhập để sử dụng ứng dụng. Bạn có thể đóng hướng dẫn này và mở lại bất cứ lúc nào.",
54
+ "close": "Đóng"
49
55
  }
50
56
  }
51
57
  }
@@ -1,4 +1,4 @@
1
- const LOCALES = ["vi"] as const
1
+ const LOCALES = ["vi", "en"] as const
2
2
 
3
3
  /** The locale served at the unprefixed path. */
4
4
  export const DEFAULT_LOCALE = "vi" as const
@@ -21,7 +21,7 @@ export interface CreateAuthApolloClientOptions {
21
21
  /**
22
22
  * The authenticated Apollo client. The link chain runs outer to inner:
23
23
  * retry (transient network failures) -> error (report) -> timeout -> refresh (one token refresh and replay on
24
- * UNAUTHENTICATED) -> locale (`x-locale`) -> access token (`Authorization: Bearer`, from modules/auth) -> http (terminal).
24
+ * UNAUTHENTICATED) -> locale (`Accept-Language`) -> access token (`Authorization: Bearer`, from modules/auth) -> http (terminal).
25
25
  */
26
26
  export const createAuthApolloClient = ({ signal, report }: CreateAuthApolloClientOptions = {}) =>
27
27
  new ApolloClient({
@@ -4,10 +4,10 @@ import { SetContextLink } from "@apollo/client/link/context"
4
4
  const documentLocale = (): string | undefined =>
5
5
  typeof document === "undefined" || document.documentElement.lang === "" ? undefined : document.documentElement.lang
6
6
 
7
- /** The one writer of `x-locale`: every operation declares the language the back end answers and localizes its errors in. */
7
+ /** The one writer of `Accept-Language`: every operation declares the language the back end answers and localizes its errors in. */
8
8
  export const createAttachLocaleLink = (locale: () => string | undefined = documentLocale) =>
9
9
  new SetContextLink((context) => {
10
10
  const value = locale()
11
11
  if (value === undefined) return {}
12
- return { headers: { ...context.headers, "x-locale": value } }
12
+ return { headers: { ...context.headers, "Accept-Language": value } }
13
13
  })
package/upgrade/check.mjs CHANGED
@@ -11,10 +11,12 @@ import {
11
11
  import { loadSlotManifest, openHfs } from "../runtime/scripts/hfs/slots.mjs";
12
12
  import { formatFindings } from "../sync/format.mjs";
13
13
  import {
14
+ appSource,
14
15
  checkTargets,
15
16
  loadHfs,
16
17
  renderTargets,
17
18
  } from "../sync/index.mjs";
19
+ import { readDeclaredStack } from "../sync/stack-images.mjs";
18
20
  import {
19
21
  UPGRADE_PRESETS,
20
22
  UpgradeError,
@@ -91,7 +93,7 @@ export async function checkEdition({
91
93
  // A lite app scaffolded before the 2026-10-12 ruling has no Jest preset installed. The upgrade model carries the preset's public sync inputs
92
94
  // specifically so both the dry full-edition view and the upgrade plan render the same targets before dependencies are added.
93
95
  const resolvedPresets = presets ?? UPGRADE_PRESETS;
94
- const managed = renderTargets(full, resolvedPresets, { manifest });
96
+ const managed = renderTargets(full, resolvedPresets, { manifest, source: { ...appSource(repoRoot), stack: readDeclaredStack(repoRoot) } });
95
97
  const extra = [
96
98
  ...fullManagedFindings(repoRoot, managed),
97
99
  ...(await checkDatabase({ repoRoot, files: tracked })),
@@ -0,0 +1,68 @@
1
+ // Authored-file preservation, snapshots and rollback for an additive edition upgrade.
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { dockerfilePath } from "../runtime/scripts/hfs/rules/docker.mjs";
5
+
6
+ /** App-owned additions are preserved; only declared regular optional front-end images receive that treatment. */
7
+ export function authoredAdditionReasons(declaration, source) {
8
+ const reasons = new Map([[
9
+ ".starcistacks/application-stacks.yaml",
10
+ "The app already declares its stacks; the declaration stays as the app wrote it.",
11
+ ]]);
12
+ for (const app of declaration.sides.fe.apps) {
13
+ const file = dockerfilePath("fe", app.name);
14
+ if (source.hasImage(file)) reasons.set(file,
15
+ "The lite app already authors this optional front-end image; its Dockerfile stays as the app wrote it.");
16
+ }
17
+ return reasons;
18
+ }
19
+
20
+ export function remember(snapshot, target) {
21
+ if (snapshot.has(target)) return;
22
+ snapshot.set(
23
+ target,
24
+ fs.existsSync(target) && fs.statSync(target).isFile()
25
+ ? fs.readFileSync(target)
26
+ : null,
27
+ );
28
+ }
29
+
30
+ export function ensureParent(root, target, directories) {
31
+ const missing = [];
32
+ for (
33
+ let at = path.dirname(target);
34
+ at.startsWith(root) && at !== root && !fs.existsSync(at);
35
+ at = path.dirname(at)
36
+ )
37
+ missing.push(at);
38
+ for (const directory of missing.reverse()) {
39
+ fs.mkdirSync(directory);
40
+ directories.push(directory);
41
+ }
42
+ }
43
+
44
+ export function writeFile(root, file, content, snapshot, directories) {
45
+ const target = path.join(root, ...file.split("/"));
46
+ remember(snapshot, target);
47
+ ensureParent(root, target, directories);
48
+ fs.writeFileSync(target, content);
49
+ }
50
+
51
+ export function restore(snapshot, directories) {
52
+ for (const [target, content] of [...snapshot.entries()].reverse()) {
53
+ if (content === null) {
54
+ if (fs.existsSync(target) && fs.statSync(target).isFile())
55
+ fs.unlinkSync(target);
56
+ } else {
57
+ fs.mkdirSync(path.dirname(target), { recursive: true });
58
+ fs.writeFileSync(target, content);
59
+ }
60
+ }
61
+ for (const directory of [...directories].reverse()) {
62
+ try {
63
+ fs.rmdirSync(directory);
64
+ } catch {
65
+ /* It is non-empty or already absent: preserve it. */
66
+ }
67
+ }
68
+ }