@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.
- package/CHANGELOG.md +28 -0
- package/README.md +7 -0
- package/db/migrate.mjs +361 -0
- package/db/post-cutover.mjs +136 -0
- package/emit/db-types.mjs +10 -1
- package/lint/run.mjs +1 -1
- package/package.json +4 -1
- package/release/gate.mjs +298 -0
- package/release/index.mjs +103 -0
- package/release/push.mjs +110 -0
- package/runtime/knowledge/hfs/canon-pins.yaml +11 -11
- package/runtime/knowledge/hfs/fe-stack.yaml +22 -1
- package/runtime/knowledge/hfs/rules.yaml +3437 -160
- package/runtime/knowledge/hfs/slots.yaml +430 -92
- package/runtime/knowledge/patterns/be/api.yaml +92 -2
- package/runtime/knowledge/patterns/be/cli.yaml +37 -9
- package/runtime/knowledge/patterns/be/event-bus.yaml +3 -3
- package/runtime/knowledge/patterns/be/jobs.yaml +20 -2
- package/runtime/knowledge/patterns/be/projections.yaml +4 -2
- package/runtime/knowledge/patterns/be/queues.yaml +11 -3
- package/runtime/knowledge/patterns/be/reactors.yaml +20 -1
- package/runtime/knowledge/patterns/be/realtime.yaml +25 -3
- package/runtime/knowledge/patterns/be/saga.yaml +20 -3
- package/runtime/knowledge/patterns/be/webhooks.yaml +210 -36
- package/runtime/knowledge/patterns/fe/folder.yaml +4 -0
- package/runtime/knowledge/sonar-gate.yaml +1 -1
- package/runtime/modules/kernel/failure-codes.yaml +3128 -47
- package/runtime/modules/models/runtimes.yaml +1 -1
- package/runtime/modules/schemas/application-stacks.schema.yaml +663 -0
- package/runtime/packages/cli/src/catalog.generated.mjs +14104 -0
- package/runtime/packages/cli/src/validate-args.mjs +213 -0
- package/runtime/scripts/api/git/add.mjs +5 -0
- package/runtime/scripts/api/git/cat-file.mjs +5 -0
- package/runtime/scripts/api/git/init.mjs +7 -0
- package/runtime/scripts/api/git/lib.mjs +3 -0
- package/runtime/scripts/api/git/tag.mjs +5 -0
- package/runtime/scripts/api/node/lib.mjs +20 -0
- package/runtime/scripts/api/node/run-node.mjs +6 -0
- package/runtime/scripts/api/sops/lib.mjs +41 -0
- package/runtime/scripts/api/sops/resolve-sops.mjs +7 -0
- package/runtime/scripts/api/sops/seal.mjs +1 -1
- package/runtime/scripts/api/sops/selected-age-recipient.mjs +7 -0
- package/runtime/scripts/api/supabase/database-dump.mjs +5 -0
- package/runtime/scripts/api/supabase/database-query.mjs +5 -0
- package/runtime/scripts/api/supabase/lib.mjs +44 -0
- package/runtime/scripts/api/supabase/migration-repair.mjs +5 -0
- package/runtime/scripts/hfs/app-wiring.mjs +201 -0
- package/runtime/scripts/hfs/architecture/backend-app-files.mjs +103 -0
- package/runtime/scripts/hfs/architecture/backend.mjs +22 -10
- package/runtime/scripts/hfs/architecture/background-unowned.mjs +157 -41
- package/runtime/scripts/hfs/architecture/canon-clones.mjs +240 -0
- package/runtime/scripts/hfs/architecture/canon-jsx-clones.mjs +143 -0
- package/runtime/scripts/hfs/architecture/client-reaches-server.mjs +6 -3
- package/runtime/scripts/hfs/architecture/clones.mjs +17 -8
- package/runtime/scripts/hfs/architecture/connection-map.mjs +14 -12
- package/runtime/scripts/hfs/architecture/context-map.mjs +25 -14
- package/runtime/scripts/hfs/architecture/context-owner.mjs +1 -2
- package/runtime/scripts/hfs/architecture/dead-exports-bindings.mjs +149 -0
- package/runtime/scripts/hfs/architecture/dead-exports.mjs +23 -50
- package/runtime/scripts/hfs/architecture/default-deny.mjs +8 -6
- package/runtime/scripts/hfs/architecture/frontend-block-render.mjs +104 -0
- package/runtime/scripts/hfs/architecture/frontend-world-render.mjs +30 -11
- package/runtime/scripts/hfs/architecture/frontend-world.mjs +1 -1
- package/runtime/scripts/hfs/architecture/function-spec-providers.mjs +153 -0
- package/runtime/scripts/hfs/architecture/hfs.mjs +3 -3
- package/runtime/scripts/hfs/architecture/i18n-keys.mjs +16 -3
- package/runtime/scripts/hfs/architecture/machine-ast.mjs +17 -0
- package/runtime/scripts/hfs/architecture/module-per-transport.mjs +49 -25
- package/runtime/scripts/hfs/architecture/next-data-inference.mjs +176 -0
- package/runtime/scripts/hfs/architecture/next-data-symbols.mjs +26 -0
- package/runtime/scripts/hfs/architecture/next-data.mjs +31 -23
- package/runtime/scripts/hfs/architecture/reachability.mjs +14 -0
- package/runtime/scripts/hfs/architecture/register-once.mjs +15 -7
- package/runtime/scripts/hfs/architecture/required-files.mjs +2 -1
- package/runtime/scripts/hfs/architecture/source-names.mjs +48 -3
- package/runtime/scripts/hfs/architecture/staged-consumers.mjs +37 -0
- package/runtime/scripts/hfs/architecture/supabase-ast.mjs +214 -17
- package/runtime/scripts/hfs/architecture/supabase-be.mjs +1 -6
- package/runtime/scripts/hfs/architecture/supabase.mjs +59 -21
- package/runtime/scripts/hfs/architecture/surface.mjs +2 -1
- package/runtime/scripts/hfs/architecture/tiers.mjs +11 -4
- package/runtime/scripts/hfs/architecture/typescript.mjs +1 -8
- package/runtime/scripts/hfs/architecture/unit-spec-providers.mjs +9 -13
- package/runtime/scripts/hfs/check-results.mjs +28 -0
- package/runtime/scripts/hfs/check.mjs +63 -72
- package/runtime/scripts/hfs/coverage-from.mjs +70 -0
- package/runtime/scripts/hfs/db-baseline-verb.mjs +276 -0
- package/runtime/scripts/hfs/db-plan-verb.mjs +254 -0
- package/runtime/scripts/hfs/db-restamp-verb.mjs +60 -0
- package/runtime/scripts/hfs/declaration-shape.mjs +39 -3
- package/runtime/scripts/hfs/doc-commands.mjs +367 -0
- package/runtime/scripts/hfs/edition-slots.mjs +2 -2
- package/runtime/scripts/hfs/example-secrets.mjs +158 -0
- package/runtime/scripts/hfs/manifest-shape.mjs +91 -6
- package/runtime/scripts/hfs/path-findings.mjs +32 -2
- package/runtime/scripts/hfs/refusal-codes.mjs +6 -0
- package/runtime/scripts/hfs/rule-catalog.mjs +156 -11
- package/runtime/scripts/hfs/rule-params-shape.mjs +22 -10
- package/runtime/scripts/hfs/rules/a15-findings.mjs +88 -0
- package/runtime/scripts/hfs/rules/app-env-required.mjs +20 -0
- package/runtime/scripts/hfs/rules/app-root.mjs +2 -2
- package/runtime/scripts/hfs/rules/assets.mjs +79 -0
- package/runtime/scripts/hfs/rules/boot-proof.mjs +16 -0
- package/runtime/scripts/hfs/rules/canon-copy-drift.mjs +59 -0
- package/runtime/scripts/hfs/rules/contract.mjs +66 -5
- package/runtime/scripts/hfs/rules/coverage-below.mjs +230 -0
- package/runtime/scripts/hfs/rules/database-access.mjs +343 -0
- package/runtime/scripts/hfs/rules/database-baseline.mjs +142 -0
- package/runtime/scripts/hfs/rules/database-config.mjs +250 -2
- package/runtime/scripts/hfs/rules/database-constants.mjs +9 -0
- package/runtime/scripts/hfs/rules/database-migrations.mjs +317 -37
- package/runtime/scripts/hfs/rules/database-plpgsql.mjs +119 -9
- package/runtime/scripts/hfs/rules/database-queue-sources.mjs +176 -0
- package/runtime/scripts/hfs/rules/database-queues.mjs +361 -0
- package/runtime/scripts/hfs/rules/database-sql.mjs +91 -9
- package/runtime/scripts/hfs/rules/database.mjs +11 -2
- package/runtime/scripts/hfs/rules/deploy-scan.mjs +192 -0
- package/runtime/scripts/hfs/rules/deploy-workflow.mjs +219 -0
- package/runtime/scripts/hfs/rules/doc-fresh.mjs +286 -0
- package/runtime/scripts/hfs/rules/docker-health.mjs +249 -0
- package/runtime/scripts/hfs/rules/docker.mjs +24 -7
- package/runtime/scripts/hfs/rules/edition.mjs +11 -10
- package/runtime/scripts/hfs/rules/env-parity.mjs +373 -0
- package/runtime/scripts/hfs/rules/env-value-shape.mjs +113 -0
- package/runtime/scripts/hfs/rules/event-bus.mjs +3 -2
- package/runtime/scripts/hfs/rules/event-tables.mjs +100 -0
- package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +115 -15
- package/runtime/scripts/hfs/rules/fe-stack.mjs +57 -0
- package/runtime/scripts/hfs/rules/feature-files.mjs +28 -0
- package/runtime/scripts/hfs/rules/frontend-tree.mjs +54 -35
- package/runtime/scripts/hfs/rules/integration-specs.mjs +3 -2
- package/runtime/scripts/hfs/rules/lexicon.mjs +62 -0
- package/runtime/scripts/hfs/rules/lite-proof-lane.mjs +89 -0
- package/runtime/scripts/hfs/rules/monorepo.mjs +14 -1
- package/runtime/scripts/hfs/rules/pipeline.mjs +8 -1
- package/runtime/scripts/hfs/rules/proof-commands.mjs +2 -0
- package/runtime/scripts/hfs/rules/release-provenance.mjs +211 -0
- package/runtime/scripts/hfs/rules/saga-delivery.mjs +66 -0
- package/runtime/scripts/hfs/rules/saga.mjs +8 -16
- package/runtime/scripts/hfs/rules/script-hygiene.mjs +151 -0
- package/runtime/scripts/hfs/rules/secret-custody-only.mjs +65 -0
- package/runtime/scripts/hfs/rules/secrets.mjs +26 -0
- package/runtime/scripts/hfs/rules/services.mjs +4 -4
- package/runtime/scripts/hfs/rules/stack-tooling.mjs +93 -0
- package/runtime/scripts/hfs/rules/stacks-deploy.mjs +76 -0
- package/runtime/scripts/hfs/rules/stacks-ingress.mjs +87 -0
- package/runtime/scripts/hfs/rules/stacks-lite-backing.mjs +111 -0
- package/runtime/scripts/hfs/rules/stacks-release.mjs +366 -0
- package/runtime/scripts/hfs/rules/stacks-runtime.mjs +168 -0
- package/runtime/scripts/hfs/rules/stacks-swarm.mjs +417 -0
- package/runtime/scripts/hfs/rules/stacks.mjs +13 -8
- package/runtime/scripts/hfs/rules/supabase-secrets.mjs +1 -1
- package/runtime/scripts/hfs/rules/supply-chain.mjs +167 -0
- package/runtime/scripts/hfs/rules/unused-symbol-flow.mjs +101 -0
- package/runtime/scripts/hfs/rules/unused-symbol-ledger.mjs +77 -0
- package/runtime/scripts/hfs/rules/unused-symbol-translators.mjs +165 -0
- package/runtime/scripts/hfs/rules/unused-symbol-values.mjs +103 -0
- package/runtime/scripts/hfs/rules/unused-symbol.mjs +320 -0
- package/runtime/scripts/hfs/runtime-rules/source-ast.mjs +185 -0
- package/runtime/scripts/hfs/runtime-rules/workflow-source.mjs +19 -0
- package/runtime/scripts/hfs/sealed-members.mjs +101 -0
- package/runtime/scripts/hfs/secret-bootstrap-crypto.mjs +200 -0
- package/runtime/scripts/hfs/secret-document.mjs +97 -0
- package/runtime/scripts/hfs/secret-edit.mjs +170 -0
- package/runtime/scripts/hfs/secret-errors.mjs +20 -0
- package/runtime/scripts/hfs/secret-files.mjs +124 -0
- package/runtime/scripts/hfs/secret-init.mjs +300 -0
- package/runtime/scripts/hfs/secret-output.mjs +100 -0
- package/runtime/scripts/hfs/secret-sops.mjs +130 -0
- package/runtime/scripts/hfs/secret-store.mjs +163 -0
- package/runtime/scripts/hfs/secret.mjs +162 -193
- package/runtime/scripts/hfs/slot-imports.mjs +18 -3
- package/runtime/scripts/hfs/slot-required.mjs +13 -0
- package/runtime/scripts/hfs/slot-semantic-problems.mjs +2 -1
- package/runtime/scripts/hfs/slots.mjs +1 -0
- package/runtime/scripts/hfs/stack-config-kit.mjs +34 -0
- package/runtime/scripts/hfs/stack-deploy-config.mjs +313 -0
- package/runtime/scripts/hfs/stack-ingress-config.mjs +237 -0
- package/runtime/scripts/hfs/stacks-gate.mjs +414 -0
- package/runtime/scripts/hfs/starcistacks-runtime.mjs +61 -0
- package/runtime/scripts/hfs/tree-findings.mjs +22 -0
- package/runtime/scripts/lib/command-tokens.mjs +126 -0
- package/runtime/scripts/lib/compose-values.mjs +11 -0
- package/runtime/scripts/lib/deployment-findings.mjs +7 -0
- package/runtime/scripts/lib/json-clone.mjs +61 -0
- package/runtime/scripts/lib/list.mjs +4 -0
- package/runtime/scripts/lib/roots.mjs +59 -0
- package/runtime/scripts/lib/runtime-example.mjs +13 -0
- package/runtime/scripts/lib/secret-patterns.mjs +60 -5
- package/runtime/scripts/lib/sql-ast.mjs +32 -0
- package/runtime/scripts/lib/stack-services.mjs +1 -1
- package/runtime/scripts/lib/swarm-stack.mjs +126 -0
- package/runtime/scripts/lib/trim-end.mjs +8 -0
- package/runtime/scripts/lib/ts-analysis.mjs +23 -0
- package/runtime/scripts/lib/ts-ast.mjs +27 -2
- package/runtime/scripts/lib/workflow-events.mjs +8 -0
- package/scaffold/add-app.mjs +77 -59
- package/scaffold/add-cli-lite.mjs +24 -17
- package/scaffold/add-compose.mjs +79 -0
- package/scaffold/add-database-lite.mjs +14 -0
- package/scaffold/add-fe-overlay.mjs +122 -0
- package/scaffold/add-fe-page.mjs +269 -0
- package/scaffold/add-inbox-lite.mjs +87 -124
- package/scaffold/add-plan.mjs +183 -0
- package/scaffold/add-table.mjs +132 -70
- package/scaffold/add.mjs +186 -204
- package/scaffold/app.mjs +128 -43
- package/scaffold/edition-gate.mjs +3 -3
- package/scaffold/image.mjs +2 -2
- package/scaffold/lite-exports.mjs +2 -1
- package/scaffold/service.mjs +2 -2
- package/src/main.mjs +238 -119
- package/stack/age-install.mjs +37 -0
- package/stack/backup.mjs +100 -0
- package/stack/build-args.mjs +42 -0
- package/stack/build.mjs +173 -0
- package/stack/cli.mjs +130 -0
- package/stack/config.mjs +57 -0
- package/stack/context.mjs +57 -0
- package/stack/converge.mjs +107 -0
- package/stack/deploy.mjs +301 -0
- package/stack/digest.mjs +16 -0
- package/stack/docker-transport.mjs +53 -0
- package/stack/edge-alias.mjs +118 -0
- package/stack/errors.mjs +21 -0
- package/stack/image-scan.mjs +152 -0
- package/stack/ingress-create.mjs +114 -0
- package/stack/ingress-publish.mjs +273 -0
- package/stack/ingress.mjs +706 -0
- package/stack/jobs.mjs +51 -0
- package/stack/live-restore.mjs +177 -0
- package/stack/prepare.mjs +266 -0
- package/stack/private-file.mjs +22 -0
- package/stack/provision.mjs +90 -0
- package/stack/prune.mjs +46 -0
- package/stack/release-store.mjs +87 -0
- package/stack/remote.mjs +205 -0
- package/stack/render.mjs +149 -0
- package/stack/retire.mjs +47 -0
- package/stack/sealed.mjs +149 -0
- package/stack/task.mjs +42 -0
- package/stack/verify.mjs +99 -0
- package/sync/ci-commands.mjs +13 -0
- package/sync/index.mjs +127 -64
- package/sync/stack-images.mjs +127 -0
- package/templates/app/ci-workflows/github/workflows/ci.yml +5 -1
- package/templates/app/ci-workflows/github/workflows/images.yml +15 -3
- package/templates/app/ci-workflows/github/workflows/stack-deploy.yml +148 -0
- package/templates/app/ci-workflows-lite/github/workflows/ci.yml +7 -3
- package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +38 -6
- package/templates/app/ci-workflows-lite/github/workflows/images.yml +14 -2
- package/templates/app/ci-workflows-lite/github/workflows/stack-deploy.yml +148 -0
- package/templates/app/codegen-graphql.mjs.partial +13 -2
- package/templates/app/codegen-lite/scripts/codegen.mjs +6 -1
- package/templates/app/codegen-prelude.mjs.partial +8 -0
- package/templates/app/gitignore +4 -0
- package/templates/app/gitignore-lite +4 -0
- package/templates/app/hooks/husky/pre-commit +7 -12
- package/templates/app/package-scripts/package.json +1 -0
- package/templates/app/package-scripts/supabase.json +7 -0
- package/templates/app/package-scripts-lite/package.json +1 -7
- package/templates/app/skeleton/.editorconfig +1 -0
- package/templates/app/skeleton/.gitattributes +7 -1
- package/templates/app/skeleton/.github/dependabot.yml +17 -0
- package/templates/app/skeleton/.nvmrc +1 -1
- package/templates/app/skeleton/.sops.yaml +1 -1
- package/templates/app/skeleton/.starcistacks/application-stacks.yaml +134 -1
- package/templates/app/skeleton/.starcistacks/dev/README.md +16 -0
- package/templates/app/skeleton/.starcistacks/dev/environment.json +5 -0
- package/templates/app/skeleton/.starcistacks/dev/infra/compose/stack.yaml +71 -0
- package/templates/app/skeleton/.starcistacks/dev/runtime/env/KEYS.md +14 -0
- package/templates/app/skeleton/.starcistacks/production/README.md +37 -0
- package/templates/app/skeleton/.starcistacks/production/environment.json +5 -0
- package/templates/app/skeleton/.starcistacks/production/infra/swarm/Caddyfile +15 -0
- package/templates/app/skeleton/.starcistacks/production/infra/swarm/owner-actions.md +11 -0
- package/templates/app/skeleton/.starcistacks/production/infra/swarm/recovery/restore-proof.md +7 -0
- package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/current.yaml +6 -0
- package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/images.lock.yaml +9 -0
- package/templates/app/skeleton/.starcistacks/production/infra/swarm/releases/previous.yaml +6 -0
- package/templates/app/skeleton/.starcistacks/production/infra/swarm/stack.yaml +142 -0
- package/templates/app/skeleton/.starcistacks/production/runtime/env/KEYS.md +14 -0
- package/templates/app/skeleton/README.md +6 -6
- package/templates/app/skeleton/scripts/codegen.mjs +1 -2
- package/templates/app/skeleton-lite/.editorconfig +16 -0
- package/templates/app/skeleton-lite/.gitattributes +8 -0
- package/templates/app/skeleton-lite/.github/dependabot.yml +17 -0
- package/templates/app/skeleton-lite/.nvmrc +1 -0
- package/templates/app/skeleton-lite/.sops.yaml +3 -2
- package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +193 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/README.md +20 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/environment.json +2 -1
- package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/Caddyfile +16 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/owner-actions.md +11 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/recovery/restore-proof.md +7 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/current.yaml +6 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/images.lock.yaml +8 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/releases/previous.yaml +6 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/stack.yaml +120 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/runtime/env/KEYS.md +18 -0
- package/templates/app/skeleton-lite/.starcistacks/production/README.md +38 -0
- package/templates/app/skeleton-lite/.starcistacks/production/environment.json +6 -0
- package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/Caddyfile +11 -0
- package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/owner-actions.md +11 -0
- package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/recovery/restore-proof.md +7 -0
- package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/current.yaml +6 -0
- package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/images.lock.yaml +8 -0
- package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/releases/previous.yaml +6 -0
- package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/stack.yaml +121 -0
- package/templates/app/skeleton-lite/.starcistacks/production/runtime/env/KEYS.md +21 -0
- package/templates/app/skeleton-lite/.starciwork/brand/index.yaml +12 -0
- package/templates/app/skeleton-lite/.starciwork/workspace.yaml +9 -0
- package/templates/app/skeleton-lite/README.md +8 -4
- package/templates/app/skeleton-lite/supabase/config.toml +8 -1
- package/templates/app/skeleton-lite/supabase/migrations/__timestamp___baseline.sql +15 -6
- package/templates/app/starciwork.gitignore-lite +6 -0
- package/templates/app/upgrade-full/.starcistacks/dev/README.md +13 -7
- package/templates/be/image/worker/Dockerfile +1 -1
- package/templates/be/inbox/database-client.spec.ts.tpl +22 -28
- package/templates/be/inbox/database-client.ts.tpl +14 -28
- package/templates/be/inbox/delivery-recorded.event.ts.tpl +36 -0
- package/templates/be/inbox/event-index.ts.tpl +1 -0
- package/templates/be/inbox/events.json.tpl +10 -0
- package/templates/be/inbox/migration.sql.tpl +1 -0
- package/templates/be/inbox/platform/event-bus/event-bus.contracts.ts.tpl +42 -0
- package/templates/be/inbox/platform/event-bus/event-bus.decorators.ts.tpl +9 -0
- package/templates/be/inbox/platform/event-bus/event-bus.module-definition.ts.tpl +6 -0
- package/templates/be/inbox/platform/event-bus/event-bus.module.ts.tpl +19 -0
- package/templates/be/inbox/platform/event-bus/event-bus.options.ts.tpl +2 -0
- package/templates/be/inbox/platform/event-bus/event-bus.port.ts.tpl +16 -0
- package/templates/be/inbox/platform/event-bus/event-bus.service.spec.ts.tpl +45 -0
- package/templates/be/inbox/platform/event-bus/event-bus.service.ts.tpl +15 -0
- package/templates/be/inbox/platform/event-bus/index.ts.tpl +5 -0
- package/templates/be/inbox/platform/event-bus/persistence/event-bus.sql.ts.tpl +5 -0
- package/templates/be/inbox/platform/inbox/inbox.decorators.ts.tpl +9 -0
- package/templates/be/inbox/platform/inbox/inbox.module-definition.ts.tpl +6 -0
- package/templates/be/inbox/platform/inbox/inbox.module.ts.tpl +19 -0
- package/templates/be/inbox/platform/inbox/inbox.options.ts.tpl +2 -0
- package/templates/be/inbox/platform/inbox/inbox.port.ts.tpl +10 -0
- package/templates/be/inbox/platform/inbox/inbox.service.spec.ts.tpl +41 -0
- package/templates/be/inbox/platform/inbox/inbox.service.ts.tpl +19 -0
- package/templates/be/inbox/platform/inbox/index.ts.tpl +3 -0
- package/templates/be/inbox/platform/inbox/persistence/inbox.sql.ts.tpl +7 -0
- package/templates/be/inbox/platform/migration.sql.tpl +48 -0
- package/templates/be/inbox/service.spec.ts.tpl +49 -20
- package/templates/be/inbox/service.ts.tpl +27 -16
- package/templates/be/inbox/sql.ts.tpl +2 -2
- package/templates/be/inbox/webhook-door.spec.ts.tpl +3 -3
- package/templates/be/inbox/webhook-door.ts.tpl +4 -3
- package/templates/be/patterns/api/feature.module-definition.ts.tpl +6 -0
- package/templates/be/patterns/api/feature.module.ts.tpl +2 -1
- package/templates/be/patterns/api/feature.options.ts.tpl +2 -0
- package/templates/be/patterns/api/graphql.module-definition.ts.tpl +6 -0
- package/templates/be/patterns/api/graphql.module.ts.tpl +3 -2
- package/templates/be/patterns/api/graphql.options.ts.tpl +2 -0
- package/templates/be/patterns/cli/group.module-definition.ts.tpl +6 -0
- package/templates/be/patterns/cli/group.module.ts.tpl +2 -1
- package/templates/be/patterns/cli/group.options.ts.tpl +2 -0
- package/templates/be/patterns/event-bus/platform/errors/event-bus.error.ts.tpl +0 -3
- package/templates/be/patterns/event-bus/platform/messages/event-bus.messages.ts.tpl +0 -2
- package/templates/be/patterns/jobs/job.module-definition.ts.tpl +6 -0
- package/templates/be/patterns/jobs/job.module.ts.tpl +2 -1
- package/templates/be/patterns/jobs/job.options.ts.tpl +2 -0
- package/templates/be/patterns/jobs/job.queue.module-definition.ts.tpl +6 -0
- package/templates/be/patterns/jobs/job.queue.module.ts.tpl +6 -3
- package/templates/be/patterns/jobs/job.queue.options.ts.tpl +2 -0
- package/templates/be/patterns/jobs/platform/fenced.processor.spec.ts.tpl +3 -1
- package/templates/be/patterns/outbox/platform/outbox-relay.policy.spec.ts.tpl +25 -9
- package/templates/be/patterns/queues/platform/queue.config.ts.tpl +1 -1
- package/templates/be/patterns/queues/platform/queue.index.ts.tpl +1 -1
- package/templates/be/patterns/queues/platform/queue.module-definition.ts.tpl +2 -2
- package/templates/be/patterns/queues/platform/queue.module.ts.tpl +11 -0
- package/templates/be/patterns/queues/platform/queue.options.ts.tpl +10 -0
- package/templates/be/patterns/queues/queue.module-definition.ts.tpl +6 -0
- package/templates/be/patterns/queues/queue.module.ts.tpl +2 -1
- package/templates/be/patterns/queues/queue.options.ts.tpl +2 -0
- package/templates/be/patterns/reactors/message.module-definition.ts.tpl +6 -0
- package/templates/be/patterns/reactors/message.module.ts.tpl +6 -3
- package/templates/be/patterns/reactors/message.options.ts.tpl +2 -0
- package/templates/be/patterns/reactors/reactor.module-definition.ts.tpl +6 -0
- package/templates/be/patterns/reactors/reactor.module.ts.tpl +2 -1
- package/templates/be/patterns/reactors/reactor.options.ts.tpl +2 -0
- package/templates/be/patterns/realtime/channel.gateway.spec.ts.tpl +188 -0
- package/templates/be/patterns/realtime/channel.gateway.ts.tpl +22 -0
- package/templates/be/patterns/realtime/channel.graphql.module-definition.ts.tpl +6 -0
- package/templates/be/patterns/realtime/channel.graphql.module.ts.tpl +2 -1
- package/templates/be/patterns/realtime/channel.graphql.options.ts.tpl +2 -0
- package/templates/be/patterns/realtime/channel.websocket.module-definition.ts.tpl +6 -0
- package/templates/be/patterns/realtime/channel.websocket.module.ts.tpl +110 -0
- package/templates/be/patterns/realtime/channel.websocket.options.ts.tpl +7 -0
- package/templates/be/patterns/saga/saga.message.module-definition.ts.tpl +6 -0
- package/templates/be/patterns/saga/saga.message.module.ts.tpl +6 -3
- package/templates/be/patterns/saga/saga.message.options.ts.tpl +2 -0
- package/templates/be/patterns/saga/saga.module-definition.ts.tpl +6 -0
- package/templates/be/patterns/saga/saga.module.ts.tpl +2 -1
- package/templates/be/patterns/saga/saga.options.ts.tpl +2 -0
- package/templates/be/patterns/webhooks/webhook.door.spec.ts.tpl +3 -3
- package/templates/be/patterns/webhooks/webhook.door.ts.tpl +3 -3
- package/templates/be/patterns/webhooks/webhook.http.module-definition.ts.tpl +6 -0
- package/templates/be/patterns/webhooks/webhook.http.module.ts.tpl +2 -1
- package/templates/be/patterns/webhooks/webhook.http.options.ts.tpl +2 -0
- package/templates/be/platform/graphql/localize-errors.mapper.spec.ts +80 -26
- package/templates/be/platform/graphql/localize-errors.mapper.ts +2 -5
- package/templates/be/skeleton/apps/__app__/src/__app__.env.ts +21 -0
- package/templates/be/skeleton/apps/__app__/src/__app__.options.ts +1 -1
- package/templates/be/skeleton/apps/__app__/src/app.module.ts +15 -45
- package/templates/be/skeleton/apps/__app__/src/compose/api.ts +4 -0
- package/templates/be/skeleton/apps/__app__/src/compose/domain.ts +11 -0
- package/templates/be/skeleton/apps/__app__/src/compose/platform.ts +44 -0
- package/templates/be/skeleton/apps/__app__/src/compose/system.ts +5 -0
- package/templates/be/skeleton/apps/__app__/src/compose/webhooks.ts +4 -0
- package/templates/be/skeleton/apps/__app__/src/main.ts +18 -10
- package/templates/be/skeleton/apps/cli/src/app.module.ts +3 -13
- package/templates/be/skeleton/apps/cli/src/cli.env.ts +13 -0
- package/templates/be/skeleton/apps/cli/src/cli.options.ts +7 -17
- package/templates/be/skeleton/apps/cli/src/compose/cli.ts +5 -0
- package/templates/be/skeleton/apps/cli/src/compose/platform.ts +24 -0
- package/templates/be/skeleton/apps/cli/src/main.ts +3 -2
- package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.contracts.ts +2 -0
- package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.handler.ts +22 -0
- package/templates/be/skeleton/src/features/api/system-health/application/check-readiness.query.ts +11 -0
- package/templates/be/skeleton/src/features/api/system-health/system-health.module-definition.ts +6 -0
- package/templates/be/skeleton/src/features/api/system-health/system-health.module.ts +5 -3
- package/templates/be/skeleton/src/features/api/system-health/system-health.options.ts +2 -0
- package/templates/be/skeleton/src/features/api/system-health/transport/http/ready.controller.ts +19 -0
- package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module-definition.ts +6 -0
- package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.module.ts +8 -3
- package/templates/be/skeleton/src/features/api/system-health/transport/http/system-health-http.options.ts +2 -0
- package/templates/be/skeleton/src/features/cli/cli.module-definition.ts +6 -0
- package/templates/be/skeleton/src/features/cli/cli.module.ts +3 -2
- package/templates/be/skeleton/src/features/cli/cli.options.ts +2 -0
- package/templates/be/skeleton/src/features/cli/migrate/migrate.module-definition.ts +6 -0
- package/templates/be/skeleton/src/features/cli/migrate/migrate.module.ts +2 -1
- package/templates/be/skeleton/src/features/cli/migrate/migrate.options.ts +2 -0
- package/templates/be/skeleton/src/features/cli/seed/seed.module-definition.ts +6 -0
- package/templates/be/skeleton/src/features/cli/seed/seed.module.ts +2 -1
- package/templates/be/skeleton/src/features/cli/seed/seed.options.ts +2 -0
- package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.spec.ts +5 -6
- package/templates/be/skeleton/src/modules/domain/identity/admission.policy.spec.ts +56 -4
- package/templates/be/skeleton/src/modules/domain/identity/admission.policy.ts +36 -5
- package/templates/be/skeleton/src/modules/domain/identity/auth.guard.spec.ts +39 -8
- package/templates/be/skeleton/src/modules/domain/identity/auth.guard.ts +14 -8
- package/templates/be/skeleton/src/modules/domain/identity/credential.contracts.ts +26 -0
- package/templates/be/skeleton/src/modules/domain/identity/credential.guard.spec.ts +119 -0
- package/templates/be/skeleton/src/modules/domain/identity/credential.guard.ts +43 -0
- package/templates/be/skeleton/src/modules/domain/identity/identity.contracts.ts +16 -0
- package/templates/be/skeleton/src/modules/domain/identity/identity.decorators.ts +18 -1
- package/templates/be/skeleton/src/modules/domain/identity/identity.module.ts +22 -4
- package/templates/be/skeleton/src/modules/domain/identity/identity.options.ts +8 -2
- package/templates/be/skeleton/src/modules/domain/identity/index.ts +1 -0
- package/templates/be/skeleton/src/modules/platform/config/env-source.config.ts +6 -6
- package/templates/be/skeleton/src/modules/platform/database/connection-source.client.spec.ts +11 -4
- package/templates/be/skeleton/src/modules/platform/database/database-probe.service.spec.ts +32 -0
- package/templates/be/skeleton/src/modules/platform/database/database-probe.service.ts +14 -0
- package/templates/be/skeleton/src/modules/platform/database/database.module.ts +7 -1
- package/templates/be/skeleton/src/modules/platform/database/index.ts +2 -0
- package/templates/be/skeleton/src/modules/platform/database/primary.decorators.ts +8 -0
- package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.spec.ts +25 -6
- package/templates/be/skeleton/src/modules/platform/errors/errors.filter.spec.ts +16 -6
- package/templates/be/skeleton/src/modules/platform/http-security/edge-security.service.spec.ts +130 -0
- package/templates/be/skeleton/src/modules/platform/http-security/edge-security.service.ts +58 -0
- package/templates/be/skeleton/src/modules/platform/http-security/errors/http-security.error.ts +3 -0
- package/templates/be/skeleton/src/modules/platform/http-security/execution-request.mapper.spec.ts +16 -4
- package/templates/be/skeleton/src/modules/platform/http-security/http-security.config.ts +16 -10
- package/templates/be/skeleton/src/modules/platform/http-security/http-security.module.ts +3 -1
- package/templates/be/skeleton/src/modules/platform/http-security/http-security.options.ts +2 -0
- package/templates/be/skeleton/src/modules/platform/http-security/index.ts +5 -0
- package/templates/be/skeleton/src/modules/platform/http-security/messages/http-security.messages.ts +12 -5
- package/templates/be/skeleton/src/modules/platform/http-security/rate-limit.guard.spec.ts +13 -8
- package/templates/be/skeleton/src/modules/platform/http-security/readiness.contracts.ts +5 -0
- package/templates/be/skeleton/src/modules/platform/http-security/readiness.decorators.ts +7 -0
- package/templates/be/skeleton/src/modules/platform/http-security/readiness.service.spec.ts +86 -0
- package/templates/be/skeleton/src/modules/platform/http-security/readiness.service.ts +39 -0
- package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.spec.ts +139 -131
- package/templates/be/skeleton/src/modules/platform/i18n/index.ts +1 -1
- package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.spec.ts +91 -67
- package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.ts +5 -4
- package/templates/be/skeleton/src/modules/platform/logging/logging.log-events.ts +0 -2
- package/templates/be/skeleton/src/modules/platform/primitives/outcome.mapper.spec.ts +20 -6
- package/templates/be/skeleton/src/modules/platform/primitives/sequence.policy.spec.ts +16 -4
- package/templates/be/skeleton/src/modules/platform/retry/index.ts +3 -0
- package/templates/be/skeleton/src/modules/platform/retry/retry.decorators.ts +9 -0
- package/templates/be/skeleton/src/modules/platform/retry/retry.module-definition.ts +7 -0
- package/templates/be/skeleton/src/modules/platform/retry/retry.module.ts +19 -0
- package/templates/be/skeleton/src/modules/platform/retry/retry.options.ts +2 -0
- package/templates/be/skeleton/src/modules/platform/retry/retry.port.ts +11 -0
- package/templates/be/skeleton/src/modules/platform/retry/system-timer.service.spec.ts +36 -0
- package/templates/be/skeleton/src/modules/platform/retry/system-timer.service.ts +10 -0
- package/templates/be/skeleton/src/tests/contract/http-security/http-security.contract-spec.ts +54 -0
- package/templates/be/skeleton-lite/apps/api/src/api.env.ts +25 -0
- package/templates/be/skeleton-lite/apps/api/src/api.options.ts +1 -1
- package/templates/be/skeleton-lite/apps/api/src/app.module.ts +18 -58
- package/templates/be/skeleton-lite/apps/api/src/compose/api.ts +4 -0
- package/templates/be/skeleton-lite/apps/api/src/compose/domain.ts +10 -0
- package/templates/be/skeleton-lite/apps/api/src/compose/integrations.ts +16 -0
- package/templates/be/skeleton-lite/apps/api/src/compose/platform.ts +47 -0
- package/templates/be/skeleton-lite/apps/api/src/compose/system.ts +5 -0
- package/templates/be/skeleton-lite/apps/api/src/compose/webhooks.ts +4 -0
- package/templates/be/skeleton-lite/apps/api/src/main.ts +5 -13
- package/templates/be/skeleton-lite/apps/cli/src/cli.env.ts +17 -0
- package/templates/be/skeleton-lite/apps/cli/src/compose/platform.ts +12 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.spec.ts +71 -5
- package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.ts +29 -2
- package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.spec.ts +68 -15
- package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.ts +14 -9
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.contracts.ts +9 -2
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.decorators.ts +16 -1
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.module.ts +19 -4
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.options.ts +5 -1
- package/templates/be/skeleton-lite/src/modules/domain/identity/index.ts +2 -1
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/errors/supabase.error.ts +0 -3
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.client.spec.ts +17 -5
- package/templates/be/skeleton-lite/src/modules/platform/database/database.module.ts +24 -13
- package/templates/be/skeleton-lite/src/modules/platform/database/database.port.ts +5 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/errors/database.error.ts +16 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +3 -0
- package/templates/be/skeleton-lite/src/modules/platform/http-security/http-security.module.ts +5 -2
- package/templates/be/skeleton-lite/src/modules/platform/http-security/index.ts +4 -1
- package/templates/be/skeleton-lite/src/modules/platform/i18n/index.ts +1 -1
- package/templates/be/skeleton-lite/src/modules/platform/logging/logging.log-events.ts +7 -0
- package/templates/be/skeleton-lite/src/tests/fixtures/builders/api.builder.ts +29 -0
- package/templates/be/skeleton-lite/src/tests/fixtures/builders/cli.builder.ts +16 -0
- package/templates/be/table/api/feature.module-definition.ts.tpl +6 -0
- package/templates/be/table/api/feature.module.ts.tpl +2 -1
- package/templates/be/table/api/feature.options.ts.tpl +2 -0
- package/templates/be/table/api/graphql.module-definition.ts.tpl +6 -0
- package/templates/be/table/api/graphql.module.ts.tpl +3 -2
- package/templates/be/table/api/graphql.options.ts.tpl +2 -0
- package/templates/be/table/migration.sql.tpl +1 -0
- package/templates/be/upgrade-full/apps/cli/src/app.module.ts +4 -6
- package/templates/be/upgrade-full/apps/cli/src/cli.env.ts +7 -0
- package/templates/be/upgrade-full/apps/cli/src/compose/cli.ts +5 -0
- package/templates/be/upgrade-full/apps/cli/src/compose/platform.ts +9 -0
- package/templates/be/upgrade-full/apps/cli/src/main.ts +3 -0
- package/templates/be/upgrade-full/src/features/cli/cli.module.ts +3 -2
- package/templates/fe/auth/supabase-client.ts.tpl +34 -0
- package/templates/fe/skeleton/apps/__app__/src/app/auth/callback/route.ts +11 -0
- package/templates/fe/skeleton/apps/__app__/src/components/blocks/SignInForm/index.tsx +6 -1
- package/templates/fe/skeleton/apps/__app__/src/components/leaves/Icon/index.tsx +4 -0
- package/templates/fe/skeleton/apps/__app__/src/features/overlays/AppGuideOverlay/component.tsx +31 -0
- package/templates/fe/skeleton/apps/__app__/src/features/overlays/AppGuideOverlay/index.tsx +24 -0
- package/templates/fe/skeleton/apps/__app__/src/hooks/auth/useSession.ts +6 -1
- package/templates/fe/skeleton/apps/__app__/src/hooks/auth/useSignOut.ts +3 -4
- package/templates/fe/skeleton/apps/__app__/src/hooks/zustand/appGuide/index.ts +1 -0
- package/templates/fe/skeleton/apps/__app__/src/hooks/zustand/appGuide/store.ts +15 -0
- package/templates/fe/skeleton/apps/__app__/src/modules/auth/pkce-client.ts +18 -0
- package/templates/fe/skeleton/apps/__app__/src/modules/auth/server.ts +19 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/index.tsx +7 -1
- package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/en.json +57 -0
- package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/vi.json +6 -0
- package/templates/fe/skeleton/apps/landing/src/modules/i18n/messages/en.json +31 -0
- package/templates/fe/skeleton/packages/__project__-i18n/src/routing.ts +1 -1
- package/templates/fe/skeleton/packages/__project__-ui/src/index.ts +1 -0
- package/templates/fe/skeleton-lite/apps/__app__/src/modules/auth/client.ts +1 -34
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/index.tsx +7 -1
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/en.json +57 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/vi.json +30 -24
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/routing.ts +1 -1
- package/templates/fe/transport/graphql/clients/clients/auth.ts +1 -1
- package/templates/fe/transport/graphql/clients/links/locale.ts +2 -2
- package/upgrade/check.mjs +3 -1
- package/upgrade/file-state.mjs +68 -0
- package/upgrade/index.mjs +58 -94
- package/runtime/scripts/api/git/log.mjs +0 -5
- package/templates/app/skeleton-lite/.starciwork/shell/index.yaml +0 -55
|
@@ -5,6 +5,7 @@ import type { TypedParameterDecorator } from "@modules/platform/composition"
|
|
|
5
5
|
import type { VerifySupabaseAccessToken } from "@modules/integrations/supabase"
|
|
6
6
|
import { requestOf } from "@modules/platform/http-security"
|
|
7
7
|
import type { Principal } from "@modules/platform/cqrs"
|
|
8
|
+
import type { CredentialAuthenticator, CredentialMetadata } from "./credential.contracts"
|
|
8
9
|
import { IdentityError, IdentityErrorCode } from "./errors/identity.error"
|
|
9
10
|
import type { PublicMetadata } from "./identity.contracts"
|
|
10
11
|
|
|
@@ -18,9 +19,23 @@ export const InjectAccessTokenVerifier = (): TypedParameterDecorator<VerifySupab
|
|
|
18
19
|
/** Metadata key of `@Public`. */
|
|
19
20
|
export const PUBLIC_KEY = "domain.identity.public"
|
|
20
21
|
|
|
21
|
-
/** Opens a door to anonymous callers, stating why; every other door needs a verified Supabase session. */
|
|
22
|
+
/** Opens a door to anonymous callers, stating why; every other door needs a credential or a verified Supabase session. */
|
|
22
23
|
export const Public = (metadata: PublicMetadata): ReturnType<typeof SetMetadata> => SetMetadata(PUBLIC_KEY, metadata)
|
|
23
24
|
|
|
25
|
+
/** Metadata key of `@Credential`. */
|
|
26
|
+
export const CREDENTIAL_KEY: unique symbol = Symbol("domain.identity.credential")
|
|
27
|
+
|
|
28
|
+
/** Token of the identity-owned port that authenticates an API key, run token, tool token or link token. */
|
|
29
|
+
export const CREDENTIAL_AUTHENTICATOR: unique symbol = Symbol("domain.identity.credential-authenticator")
|
|
30
|
+
|
|
31
|
+
/** Injects the credential authenticator identity was registered with. Parameter type: CredentialAuthenticator. */
|
|
32
|
+
export const InjectCredentialAuthenticator = (): TypedParameterDecorator<CredentialAuthenticator> =>
|
|
33
|
+
injector<CredentialAuthenticator>(CREDENTIAL_AUTHENTICATOR)
|
|
34
|
+
|
|
35
|
+
/** Marks a door authenticated by its own credential; `CredentialGuard` authenticates it and `AuthGuard` admits it. */
|
|
36
|
+
export const Credential = (metadata: CredentialMetadata): ReturnType<typeof SetMetadata> =>
|
|
37
|
+
SetMetadata(CREDENTIAL_KEY, metadata)
|
|
38
|
+
|
|
24
39
|
/** The authenticated Supabase caller established by the default-deny guard. */
|
|
25
40
|
export const CurrentPrincipal = createParamDecorator((_data: unknown, context: ExecutionContext): Principal => {
|
|
26
41
|
const principal = requestOf(context).principal
|
|
@@ -1,15 +1,28 @@
|
|
|
1
1
|
import { Module } from "@nestjs/common"
|
|
2
|
-
import type { DynamicModule } from "@nestjs/common"
|
|
2
|
+
import type { DynamicModule, Provider } from "@nestjs/common"
|
|
3
3
|
import { AuthGuard } from "./auth.guard"
|
|
4
|
-
import {
|
|
4
|
+
import { CredentialGuard } from "./credential.guard"
|
|
5
|
+
import { IdentityError, IdentityErrorCode } from "./errors/identity.error"
|
|
6
|
+
import { ACCESS_TOKEN_VERIFIER, CREDENTIAL_AUTHENTICATOR } from "./identity.decorators"
|
|
5
7
|
import { ConfigurableModuleClass, OPTIONS_TYPE } from "./identity.module-definition"
|
|
6
8
|
|
|
9
|
+
const refusingAuthenticator: Provider = {
|
|
10
|
+
provide: CREDENTIAL_AUTHENTICATOR,
|
|
11
|
+
useValue: {
|
|
12
|
+
authenticate: () => Promise.reject(new IdentityError({ code: IdentityErrorCode.Unauthenticated })),
|
|
13
|
+
},
|
|
14
|
+
}
|
|
15
|
+
|
|
7
16
|
@Module({})
|
|
8
|
-
/** The identity capability: its default-deny
|
|
17
|
+
/** The identity capability: the app registers its credential and default-deny guards after the throttler and origin guard. */
|
|
9
18
|
export class IdentityModule extends ConfigurableModuleClass {
|
|
10
19
|
/** Registers identity once per app with the verifier parsed at the composition root. */
|
|
11
20
|
static register(options: typeof OPTIONS_TYPE): DynamicModule {
|
|
12
21
|
const base = super.register(options)
|
|
22
|
+
const authenticator: Provider =
|
|
23
|
+
options.credentialAuthenticator === undefined
|
|
24
|
+
? refusingAuthenticator
|
|
25
|
+
: { provide: CREDENTIAL_AUTHENTICATOR, useClass: options.credentialAuthenticator }
|
|
13
26
|
return {
|
|
14
27
|
...base,
|
|
15
28
|
providers: [
|
|
@@ -18,9 +31,11 @@ export class IdentityModule extends ConfigurableModuleClass {
|
|
|
18
31
|
provide: ACCESS_TOKEN_VERIFIER,
|
|
19
32
|
useValue: options.verifyAccessToken,
|
|
20
33
|
},
|
|
34
|
+
authenticator,
|
|
35
|
+
CredentialGuard,
|
|
21
36
|
AuthGuard,
|
|
22
37
|
],
|
|
23
|
-
exports: [AuthGuard],
|
|
38
|
+
exports: [CredentialGuard, CREDENTIAL_AUTHENTICATOR, AuthGuard, ACCESS_TOKEN_VERIFIER],
|
|
24
39
|
}
|
|
25
40
|
}
|
|
26
41
|
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import type { Type } from "@nestjs/common"
|
|
1
2
|
import type { VerifySupabaseAccessToken } from "@modules/integrations/supabase"
|
|
3
|
+
import type { CredentialAuthenticator } from "./credential.contracts"
|
|
2
4
|
|
|
3
|
-
/** The
|
|
5
|
+
/** The identity capability's credential and session verification options. */
|
|
4
6
|
export interface IdentityOptions {
|
|
7
|
+
/** The app-owned authenticator of alternate credentials; a credential door fails closed while it is absent. */
|
|
8
|
+
readonly credentialAuthenticator?: Type<CredentialAuthenticator>
|
|
5
9
|
/** Cryptographically verifies a Supabase access token before it can become a principal. */
|
|
6
10
|
readonly verifyAccessToken: VerifySupabaseAccessToken
|
|
7
11
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { AuthGuard } from "./auth.guard"
|
|
2
|
+
export { CredentialGuard } from "./credential.guard"
|
|
2
3
|
export { IDENTITY_ERROR_KINDS } from "./errors/identity.error"
|
|
3
4
|
export { IDENTITY_MESSAGES } from "./messages/identity.messages"
|
|
4
5
|
export { PublicReason } from "./identity.contracts"
|
|
5
|
-
export { Public } from "./identity.decorators"
|
|
6
|
+
export { ACCESS_TOKEN_VERIFIER, Public } from "./identity.decorators"
|
|
6
7
|
export { IdentityModule } from "./identity.module"
|
package/templates/be/skeleton-lite/src/modules/integrations/supabase/errors/supabase.error.ts
CHANGED
|
@@ -5,14 +5,11 @@ import type { ErrorKind } from "@modules/platform/errors"
|
|
|
5
5
|
export enum SupabaseErrorCode {
|
|
6
6
|
/** The access token failed signature or required-claim verification. */
|
|
7
7
|
AccessTokenInvalid = "SUPABASE_ACCESS_TOKEN_INVALID",
|
|
8
|
-
/** A privileged Auth or Storage operation could not reach Supabase. */
|
|
9
|
-
ProviderUnavailable = "SUPABASE_PROVIDER_UNAVAILABLE",
|
|
10
8
|
}
|
|
11
9
|
|
|
12
10
|
/** How each Supabase integration code travels. */
|
|
13
11
|
export const SUPABASE_ERROR_KINDS: Record<SupabaseErrorCode, ErrorKind> = {
|
|
14
12
|
[SupabaseErrorCode.AccessTokenInvalid]: "unauthenticated",
|
|
15
|
-
[SupabaseErrorCode.ProviderUnavailable]: "unavailable",
|
|
16
13
|
}
|
|
17
14
|
|
|
18
15
|
/** The one error class of the Supabase integration. */
|
package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.client.spec.ts
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
1
|
+
import { Test } from "@nestjs/testing"
|
|
1
2
|
import { Secret } from "@modules/platform/config"
|
|
2
3
|
import { createSupabaseAdminClient } from "./supabase.client"
|
|
4
|
+
import type { SupabaseAdminClient } from "./supabase.client"
|
|
5
|
+
import { SUPABASE_ADMIN_CLIENT } from "./supabase.decorators"
|
|
3
6
|
|
|
4
7
|
describe("createSupabaseAdminClient", () => {
|
|
5
|
-
it("exposes only the Auth administration and Storage surfaces of a session-less service client", () => {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
it("exposes only the Auth administration and Storage surfaces of a session-less service client", async () => {
|
|
9
|
+
const moduleRef = await Test.createTestingModule({
|
|
10
|
+
providers: [
|
|
11
|
+
{
|
|
12
|
+
provide: SUPABASE_ADMIN_CLIENT,
|
|
13
|
+
useFactory: () =>
|
|
14
|
+
createSupabaseAdminClient({
|
|
15
|
+
url: "http://127.0.0.1:54321",
|
|
16
|
+
serviceRoleKey: new Secret("service-role"),
|
|
17
|
+
}),
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
}).compile()
|
|
21
|
+
const client = moduleRef.get<SupabaseAdminClient>(SUPABASE_ADMIN_CLIENT)
|
|
10
22
|
|
|
11
23
|
expect(Object.keys(client).sort()).toEqual(["auth", "storage"])
|
|
12
24
|
expect(typeof client.auth.createUser).toBe("function")
|
|
@@ -2,10 +2,12 @@ import { Module } from "@nestjs/common"
|
|
|
2
2
|
import type { DynamicModule } from "@nestjs/common"
|
|
3
3
|
import { TypeOrmModule, getDataSourceToken } from "@nestjs/typeorm"
|
|
4
4
|
import type { DataSource } from "typeorm"
|
|
5
|
+
import { DatabaseProbeService } from "./database-probe.service"
|
|
5
6
|
import { DATABASE_OPTIONS } from "./database.port"
|
|
6
7
|
import { ConfigurableModuleClass, OPTIONS_TYPE } from "./database.module-definition"
|
|
8
|
+
import { DatabaseError, DatabaseErrorCode } from "./errors/database.error"
|
|
7
9
|
import { PRIMARY_CONNECTION } from "./primary.connection"
|
|
8
|
-
import { PRIMARY_ENTITY_MANAGER } from "./primary.decorators"
|
|
10
|
+
import { DATABASE_PROBE, PRIMARY_ENTITY_MANAGER } from "./primary.decorators"
|
|
9
11
|
|
|
10
12
|
/** The token each declared connection provides its shared EntityManager under. */
|
|
11
13
|
type EntityManagerToken = typeof PRIMARY_ENTITY_MANAGER
|
|
@@ -20,18 +22,23 @@ export class DatabaseModule extends ConfigurableModuleClass {
|
|
|
20
22
|
/** Registers the capability once per app with the connections it opens. */
|
|
21
23
|
static register(options: typeof OPTIONS_TYPE): DynamicModule {
|
|
22
24
|
const base = super.register(options)
|
|
23
|
-
const managers = options.connections.
|
|
25
|
+
const managers = options.connections.map((connection) => {
|
|
24
26
|
const token = ENTITY_MANAGER_TOKENS.get(connection.name)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
if (token === undefined) {
|
|
28
|
+
throw new DatabaseError({
|
|
29
|
+
code: DatabaseErrorCode.ConnectionUndeclared,
|
|
30
|
+
params: { name: connection.name },
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
provide: token,
|
|
35
|
+
inject: [getDataSourceToken(connection.name)],
|
|
36
|
+
useFactory: (source: DataSource) => source.manager,
|
|
37
|
+
}
|
|
34
38
|
})
|
|
39
|
+
const probes = options.connections.some((connection) => connection.name === PRIMARY_CONNECTION)
|
|
40
|
+
? [{ provide: DATABASE_PROBE, useClass: DatabaseProbeService }]
|
|
41
|
+
: []
|
|
35
42
|
return {
|
|
36
43
|
...base,
|
|
37
44
|
imports: [
|
|
@@ -47,8 +54,12 @@ export class DatabaseModule extends ConfigurableModuleClass {
|
|
|
47
54
|
}),
|
|
48
55
|
),
|
|
49
56
|
],
|
|
50
|
-
providers: [...(base.providers ?? []), ...managers],
|
|
51
|
-
exports: [
|
|
57
|
+
providers: [...(base.providers ?? []), ...managers, ...probes],
|
|
58
|
+
exports: [
|
|
59
|
+
DATABASE_OPTIONS,
|
|
60
|
+
...probes.map((probe) => probe.provide),
|
|
61
|
+
...managers.map((manager) => manager.provide),
|
|
62
|
+
],
|
|
52
63
|
}
|
|
53
64
|
}
|
|
54
65
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import { getDataSourceToken } from "@nestjs/typeorm"
|
|
1
2
|
import { injector } from "@modules/platform/composition"
|
|
2
3
|
import type { TypedParameterDecorator } from "@modules/platform/composition"
|
|
3
4
|
import type { DatabaseOptions } from "./database.options"
|
|
5
|
+
import { PRIMARY_CONNECTION } from "./primary.connection"
|
|
6
|
+
|
|
7
|
+
/** The primary pool's override token for infrastructure fixtures; TypeORM tokens stay owned by this capability. */
|
|
8
|
+
export const PRIMARY_DATA_SOURCE = getDataSourceToken(PRIMARY_CONNECTION)
|
|
4
9
|
|
|
5
10
|
/** Token of the options of the database capability. */
|
|
6
11
|
export const DATABASE_OPTIONS: unique symbol = Symbol("platform.database.options")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DomainError } from "@modules/platform/errors"
|
|
2
|
+
import type { ErrorKind } from "@modules/platform/errors"
|
|
3
|
+
|
|
4
|
+
/** Codes of the database capability. */
|
|
5
|
+
export enum DatabaseErrorCode {
|
|
6
|
+
/** A configured connection has no declared EntityManager injection token. */
|
|
7
|
+
ConnectionUndeclared = "DATABASE_CONNECTION_UNDECLARED",
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** How each database code travels. */
|
|
11
|
+
export const DATABASE_ERROR_KINDS: Record<DatabaseErrorCode, ErrorKind> = {
|
|
12
|
+
[DatabaseErrorCode.ConnectionUndeclared]: "internal",
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** The one error class of the database capability. */
|
|
16
|
+
export class DatabaseError extends DomainError<DatabaseErrorCode> {}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export { DatabaseModule } from "./database.module"
|
|
2
|
+
export { DATABASE_PROBE, InjectDatabaseProbe } from "./primary.decorators"
|
|
3
|
+
export { DatabaseProbeService } from "./database-probe.service"
|
|
2
4
|
export type { DatabaseConnectionOptions } from "./database.options"
|
|
5
|
+
export { PRIMARY_DATA_SOURCE } from "./database.port"
|
|
3
6
|
export { DATABASE_ERROR_KINDS } from "./errors/database.error"
|
|
4
7
|
export { parsePrimaryDatabaseConfig } from "./primary.config"
|
package/templates/be/skeleton-lite/src/modules/platform/http-security/http-security.module.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { Module } from "@nestjs/common"
|
|
2
2
|
import type { DynamicModule } from "@nestjs/common"
|
|
3
|
+
import { APP_PIPE } from "@nestjs/core"
|
|
3
4
|
import { WEBHOOK_SIGNATURE } from "./http-security.decorators"
|
|
4
5
|
import { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } from "./http-security.module-definition"
|
|
6
|
+
import { ReadinessService } from "./readiness.service"
|
|
5
7
|
import { RequestValidationService } from "./request-validation.service"
|
|
6
8
|
import { WebhookSignatureService } from "./webhook-signature.service"
|
|
7
9
|
|
|
@@ -15,11 +17,12 @@ export class HttpSecurityModule extends ConfigurableModuleClass {
|
|
|
15
17
|
...base,
|
|
16
18
|
providers: [
|
|
17
19
|
...(base.providers ?? []),
|
|
18
|
-
RequestValidationService,
|
|
20
|
+
{ provide: APP_PIPE, useClass: RequestValidationService },
|
|
19
21
|
WebhookSignatureService,
|
|
22
|
+
ReadinessService,
|
|
20
23
|
{ provide: WEBHOOK_SIGNATURE, useExisting: WebhookSignatureService },
|
|
21
24
|
],
|
|
22
|
-
exports: [MODULE_OPTIONS_TOKEN,
|
|
25
|
+
exports: [MODULE_OPTIONS_TOKEN, WebhookSignatureService, WEBHOOK_SIGNATURE, ReadinessService],
|
|
23
26
|
}
|
|
24
27
|
}
|
|
25
28
|
}
|
|
@@ -6,4 +6,7 @@ export type { HttpSecurityOptions } from "./http-security.options"
|
|
|
6
6
|
export { HTTP_SECURITY_MESSAGES } from "./messages/http-security.messages"
|
|
7
7
|
export { OriginGuard } from "./origin.guard"
|
|
8
8
|
export { RateLimitGuard } from "./rate-limit.guard"
|
|
9
|
-
export {
|
|
9
|
+
export { applyHttpSecurity } from "./edge-security.service"
|
|
10
|
+
export { ReadinessService } from "./readiness.service"
|
|
11
|
+
export { InjectReadiness } from "./readiness.decorators"
|
|
12
|
+
export type { ReadinessReport } from "./readiness.contracts"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export type { Locale, MessageBundle } from "./i18n.contracts"
|
|
2
|
-
export { InjectMessageCatalog, InjectRequestLocale, MESSAGE_CATALOG } from "./i18n.decorators"
|
|
2
|
+
export { InjectMessageCatalog, InjectRequestLocale, MESSAGE_CATALOG, REQUEST_LOCALE } from "./i18n.decorators"
|
|
3
3
|
export { I18nModule } from "./i18n.module"
|
|
4
4
|
export type { MessageCatalog, RequestLocale } from "./i18n.port"
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Log events of the process lifecycle: the entry points log these. */
|
|
2
|
+
export enum LoggingLogEvent {
|
|
3
|
+
/** The HTTP listener is bound and the service answers requests. */
|
|
4
|
+
ServerStarted = "server.started",
|
|
5
|
+
/** The service failed before it could serve; the process exits non-zero. */
|
|
6
|
+
StartupFailed = "server.startup_failed",
|
|
7
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Secret } from "@modules/platform/config"
|
|
2
|
+
import { PRIMARY_DATA_SOURCE } from "@modules/platform/database"
|
|
3
|
+
import { ACCESS_TOKEN_VERIFIER } from "@modules/domain/identity"
|
|
4
|
+
import { SUPABASE_ACCESS_TOKEN_VERIFIER, SUPABASE_ADMIN_CLIENT } from "@modules/integrations/supabase"
|
|
5
|
+
|
|
6
|
+
/** Compiles the real API root with public configuration and explicit infrastructure doubles. */
|
|
7
|
+
export const buildWiringProof = () => ({
|
|
8
|
+
options: {
|
|
9
|
+
server: { port: 3000 },
|
|
10
|
+
httpSecurity: {
|
|
11
|
+
allowedOrigins: ["https://fixture.example"],
|
|
12
|
+
rateLimit: { windowMs: 60000, defaultLimit: 100, strictLimit: 10 },
|
|
13
|
+
webhooks: {},
|
|
14
|
+
},
|
|
15
|
+
database: {
|
|
16
|
+
name: "primary",
|
|
17
|
+
provider: "supabase",
|
|
18
|
+
url: new Secret("postgresql://app_be@127.0.0.1:5432/postgres"),
|
|
19
|
+
schema: "public",
|
|
20
|
+
},
|
|
21
|
+
supabase: { url: "https://fixture.supabase.co", serviceRoleKey: new Secret("fixture-only") },
|
|
22
|
+
},
|
|
23
|
+
overrides: [
|
|
24
|
+
{ token: PRIMARY_DATA_SOURCE, value: { manager: {} } },
|
|
25
|
+
{ token: SUPABASE_ADMIN_CLIENT, value: { auth: {}, storage: {} } },
|
|
26
|
+
{ token: SUPABASE_ACCESS_TOKEN_VERIFIER, value: () => ({ ok: false }) },
|
|
27
|
+
{ token: ACCESS_TOKEN_VERIFIER, value: () => ({ ok: false }) },
|
|
28
|
+
],
|
|
29
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getDataSourceToken } from "@nestjs/typeorm"
|
|
2
|
+
import { Secret } from "@modules/platform/config"
|
|
3
|
+
import { PRIMARY_CONNECTION } from "@modules/platform/database"
|
|
4
|
+
|
|
5
|
+
/** Public fixture options and the database double for compiling the real CLI AppModule without network access. */
|
|
6
|
+
export const buildWiringProof = () => ({
|
|
7
|
+
options: {
|
|
8
|
+
connections: [{
|
|
9
|
+
name: PRIMARY_CONNECTION,
|
|
10
|
+
provider: "supabase",
|
|
11
|
+
url: new Secret("postgresql://app_be@127.0.0.1:5432/postgres"),
|
|
12
|
+
schema: "public",
|
|
13
|
+
}],
|
|
14
|
+
},
|
|
15
|
+
overrides: [{ token: getDataSourceToken(PRIMARY_CONNECTION), value: { manager: {} } }],
|
|
16
|
+
})
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ConfigurableModuleBuilder } from "@nestjs/common"
|
|
2
|
+
import type { {{Name}}ApiOptions } from "./{{name}}.options"
|
|
3
|
+
|
|
4
|
+
/** The configurable-module base of the {{name}} module. */
|
|
5
|
+
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
|
|
6
|
+
new ConfigurableModuleBuilder<{{Name}}ApiOptions>().setClassMethodName("register").build()
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Module } from "@nestjs/common"
|
|
2
2
|
import { Create{{Singular}}Handler } from "./application/create-{{singular}}.handler"
|
|
3
3
|
import { Get{{Singular}}Handler } from "./application/get-{{singular}}.handler"
|
|
4
|
+
import { ConfigurableModuleClass } from "./{{name}}.module-definition"
|
|
4
5
|
|
|
5
6
|
@Module({ providers: [Get{{Singular}}Handler, Create{{Singular}}Handler] })
|
|
6
7
|
/** The {{name}} feature: the handlers of its application. */
|
|
7
|
-
export class {{Name}}ApiModule {}
|
|
8
|
+
export class {{Name}}ApiModule extends ConfigurableModuleClass {}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ConfigurableModuleBuilder } from "@nestjs/common"
|
|
2
|
+
import type { {{Name}}GraphqlOptions } from "./{{name}}-graphql.options"
|
|
3
|
+
|
|
4
|
+
/** The configurable-module base of the {{name}}-graphql module. */
|
|
5
|
+
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
|
|
6
|
+
new ConfigurableModuleBuilder<{{Name}}GraphqlOptions>().setClassMethodName("register").build()
|
|
@@ -2,7 +2,8 @@ import { Module } from "@nestjs/common"
|
|
|
2
2
|
import { {{Name}}ApiModule } from "../../{{name}}.module"
|
|
3
3
|
import { Create{{Singular}}Resolver } from "./create-{{singular}}.resolver"
|
|
4
4
|
import { Get{{Singular}}Resolver } from "./get-{{singular}}.resolver"
|
|
5
|
+
import { ConfigurableModuleClass } from "./{{name}}-graphql.module-definition"
|
|
5
6
|
|
|
6
|
-
@Module({ imports: [{{Name}}ApiModule], providers: [Get{{Singular}}Resolver, Create{{Singular}}Resolver] })
|
|
7
|
+
@Module({ imports: [{{Name}}ApiModule.register({})], providers: [Get{{Singular}}Resolver, Create{{Singular}}Resolver] })
|
|
7
8
|
/** The GraphQL transport of the {{name}} feature. */
|
|
8
|
-
export class {{Name}}GraphqlModule {}
|
|
9
|
+
export class {{Name}}GraphqlModule extends ConfigurableModuleClass {}
|
|
@@ -8,6 +8,7 @@ create table public.{{tableSql}} (
|
|
|
8
8
|
create index {{table}}_owner_id_idx on public.{{tableSql}} (owner_id);
|
|
9
9
|
|
|
10
10
|
alter table public.{{tableSql}} enable row level security;
|
|
11
|
+
alter table public.{{tableSql}} force row level security;
|
|
11
12
|
|
|
12
13
|
create trigger {{table}}_set_updated_at
|
|
13
14
|
before update on public.{{tableSql}}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { Module } from "@nestjs/common";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { LoggingModule } from "@modules/platform/logging";
|
|
2
|
+
import { cliModules } from "./compose/cli";
|
|
3
|
+
import { platformModules } from "./compose/platform";
|
|
5
4
|
|
|
6
5
|
@Module({
|
|
7
6
|
imports: [
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
CliModule,
|
|
7
|
+
...platformModules(),
|
|
8
|
+
...cliModules(),
|
|
11
9
|
],
|
|
12
10
|
})
|
|
13
11
|
/** The cli composition root; database schema changes remain delegated to the Supabase CLI. */
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { EnvSource } from "@modules/platform/config"
|
|
2
|
+
|
|
3
|
+
/** This command app delegates migration configuration to the managed Supabase CLI. */
|
|
4
|
+
export interface CliEnv {}
|
|
5
|
+
|
|
6
|
+
/** Keeps the command app's environment boundary explicit while no command needs app configuration. */
|
|
7
|
+
export const readCliEnv = (_env: EnvSource): CliEnv => ({})
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DynamicModule } from "@nestjs/common"
|
|
2
|
+
import { ClockModule } from "@modules/platform/clock"
|
|
3
|
+
import { LoggingModule } from "@modules/platform/logging"
|
|
4
|
+
|
|
5
|
+
/** The shared clock and logger; migrations retain their Supabase CLI authority. */
|
|
6
|
+
export const platformModules = (): Array<DynamicModule> => [
|
|
7
|
+
ClockModule.register({ isGlobal: true }),
|
|
8
|
+
LoggingModule.register({ isGlobal: true }),
|
|
9
|
+
]
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
2
|
import { CommandFactory } from "nest-commander";
|
|
3
3
|
import { SystemClockService } from "@modules/platform/clock";
|
|
4
|
+
import { EnvSource } from "@modules/platform/config";
|
|
4
5
|
import { createJsonLogger, LoggingLogEvent } from "@modules/platform/logging";
|
|
5
6
|
import { AppModule } from "./app.module";
|
|
7
|
+
import { readCliEnv } from "./cli.env";
|
|
6
8
|
|
|
7
9
|
/** The one-off command app. Its migrate command delegates schema authority to the Supabase CLI. */
|
|
8
10
|
async function bootstrap(): Promise<void> {
|
|
11
|
+
readCliEnv(EnvSource.fromProcess());
|
|
9
12
|
const logger = createJsonLogger(new SystemClockService());
|
|
10
13
|
await CommandFactory.run(AppModule, {
|
|
11
14
|
logger: false,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Module } from "@nestjs/common";
|
|
2
|
+
import { ConfigurableModuleClass } from "./cli.module-definition";
|
|
2
3
|
import { MigrateModule } from "./migrate/migrate.module";
|
|
3
4
|
|
|
4
|
-
@Module({ imports: [MigrateModule] })
|
|
5
|
+
@Module({ imports: [MigrateModule.register({})] })
|
|
5
6
|
/** The cli feature root of the upgraded app. */
|
|
6
|
-
export class CliModule {}
|
|
7
|
+
export class CliModule extends ConfigurableModuleClass {}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const sessionOf = (session: Session | null): AuthSession | undefined =>
|
|
2
|
+
session === null
|
|
3
|
+
? undefined
|
|
4
|
+
: { userId: session.user.id, ...(session.user.email === undefined ? {} : { email: session.user.email }) }
|
|
5
|
+
|
|
6
|
+
/** A Supabase Auth error as the provider reports it: its HTTP status, its code and its message. */
|
|
7
|
+
type ProviderError = { readonly status?: number; readonly code?: string; readonly message: string }
|
|
8
|
+
|
|
9
|
+
/** The failure kind of a Supabase Auth error: refused credentials, rejected input, or the provider unavailable. */
|
|
10
|
+
const kindOf = (status: number | undefined): string => {
|
|
11
|
+
if (status === 400 || status === 401 || status === 403) return "refused"
|
|
12
|
+
return status === 422 ? "invalid" : "unavailable"
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** The failure of a Supabase Auth call, or undefined when it succeeded. */
|
|
16
|
+
const failureOf = (error: ProviderError | null): AuthFailure | undefined =>
|
|
17
|
+
error === null
|
|
18
|
+
? undefined
|
|
19
|
+
: { code: error.code ?? String(error.status ?? "auth"), kind: kindOf(error.status), message: error.message }
|
|
20
|
+
|
|
21
|
+
/** The Supabase Auth adapter shared by browser and cookie-backed PKCE flows. */
|
|
22
|
+
export const authClient: AuthClient = {
|
|
23
|
+
session: async () => sessionOf((await supabase().auth.getSession()).data.session),
|
|
24
|
+
accessToken: async () => (await supabase().auth.getSession()).data.session?.access_token,
|
|
25
|
+
refreshAccessToken: async () => (await supabase().auth.refreshSession()).data.session?.access_token,
|
|
26
|
+
signInWithPassword: async (email, password) =>
|
|
27
|
+
failureOf((await supabase().auth.signInWithPassword({ email, password })).error),
|
|
28
|
+
signOut: async () => failureOf((await supabase().auth.signOut()).error),
|
|
29
|
+
// Supabase reports INITIAL_SESSION on subscribe, then every change: the subscription alone keeps the session current.
|
|
30
|
+
onChange: (listener) => {
|
|
31
|
+
const { data } = supabase().auth.onAuthStateChange((_event, session) => listener(sessionOf(session)))
|
|
32
|
+
return () => data.subscription.unsubscribe()
|
|
33
|
+
},
|
|
34
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { NextResponse } from "next/server"
|
|
2
|
+
import { exchangeAuthCode } from "@/modules/auth/server"
|
|
3
|
+
import { APP_ROUTES } from "@/modules/routes"
|
|
4
|
+
|
|
5
|
+
/** The opt-in Supabase PKCE callback only exchanges the code and redirects home. */
|
|
6
|
+
export async function GET(request: Request): Promise<NextResponse> {
|
|
7
|
+
const url = new URL(request.url)
|
|
8
|
+
const code = url.searchParams.get("code")
|
|
9
|
+
if (code) await exchangeAuthCode(code)
|
|
10
|
+
return NextResponse.redirect(new URL(APP_ROUTES.home, url.origin))
|
|
11
|
+
}
|
|
@@ -24,6 +24,11 @@ export const SignInForm = () => {
|
|
|
24
24
|
const t = useTranslations("app.signIn")
|
|
25
25
|
const { failure, pending, signIn, reject } = useSignIn()
|
|
26
26
|
if (session.status !== "signed-out") return null
|
|
27
|
+
const failureMessages = {
|
|
28
|
+
refused: t("refused"),
|
|
29
|
+
invalid: t("invalid"),
|
|
30
|
+
unavailable: t("unavailable"),
|
|
31
|
+
} satisfies Record<SignInFailure, string>
|
|
27
32
|
const submit = (input: FormData) => {
|
|
28
33
|
const credentials = credentialsOf(input)
|
|
29
34
|
if (credentials === undefined) reject()
|
|
@@ -37,7 +42,7 @@ export const SignInForm = () => {
|
|
|
37
42
|
emailLabel: t("email"),
|
|
38
43
|
passwordLabel: t("password"),
|
|
39
44
|
submitLabel: pending ? t("working") : t("submit"),
|
|
40
|
-
failure: failure === undefined ? undefined :
|
|
45
|
+
failure: failure === undefined ? undefined : failureMessages[failure],
|
|
41
46
|
}}
|
|
42
47
|
on={{ submit }}
|
|
43
48
|
/>
|
package/templates/fe/skeleton/apps/__app__/src/features/overlays/AppGuideOverlay/component.tsx
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Button, Dialog, Text } from "@starci/grammar/common"
|
|
2
|
+
import { Icon } from "@/components/leaves/Icon"
|
|
3
|
+
|
|
4
|
+
/** The guide's copy, local open state and action supplied by the connected overlay. */
|
|
5
|
+
export type AppGuideOverlayBaseProps = {
|
|
6
|
+
readonly props: {
|
|
7
|
+
readonly isOpen: boolean
|
|
8
|
+
readonly triggerLabel: string
|
|
9
|
+
readonly title: string
|
|
10
|
+
readonly description: string
|
|
11
|
+
readonly closeLabel: string
|
|
12
|
+
}
|
|
13
|
+
readonly on: { readonly openChange: (isOpen: boolean) => void }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** A keyboard-accessible grammar dialog whose trigger and dismiss actions update the same local state. */
|
|
17
|
+
export const AppGuideOverlayBase = (props: AppGuideOverlayBaseProps) => (
|
|
18
|
+
<Dialog
|
|
19
|
+
isOpen={props.props.isOpen}
|
|
20
|
+
onOpenChange={props.on.openChange}
|
|
21
|
+
title={props.props.title}
|
|
22
|
+
closeLabel={props.props.closeLabel}
|
|
23
|
+
trigger={
|
|
24
|
+
<Button variant="secondary" startContent={<Icon />}>
|
|
25
|
+
{props.props.triggerLabel}
|
|
26
|
+
</Button>
|
|
27
|
+
}
|
|
28
|
+
>
|
|
29
|
+
<Text>{props.props.description}</Text>
|
|
30
|
+
</Dialog>
|
|
31
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useTranslations } from "next-intl"
|
|
4
|
+
import { useAppGuideStore } from "@/hooks/zustand/appGuide"
|
|
5
|
+
import { AppGuideOverlayBase } from "./component"
|
|
6
|
+
|
|
7
|
+
/** The home guide connects localized copy to its feature-local zustand store. */
|
|
8
|
+
export const AppGuideOverlay = () => {
|
|
9
|
+
const t = useTranslations("app.guide")
|
|
10
|
+
const isOpen = useAppGuideStore((state) => state.isOpen)
|
|
11
|
+
const setOpen = useAppGuideStore((state) => state.setOpen)
|
|
12
|
+
return (
|
|
13
|
+
<AppGuideOverlayBase
|
|
14
|
+
props={{
|
|
15
|
+
isOpen,
|
|
16
|
+
triggerLabel: t("open"),
|
|
17
|
+
title: t("title"),
|
|
18
|
+
description: t("description"),
|
|
19
|
+
closeLabel: t("close"),
|
|
20
|
+
}}
|
|
21
|
+
on={{ openChange: setOpen }}
|
|
22
|
+
/>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
+
import { useDebugValue } from "react"
|
|
3
4
|
import { useAppSelector } from "@/redux"
|
|
4
5
|
|
|
5
6
|
/** The reader's session as the app shares it (redux, kept by the auth session effect): unknown, signed in or signed out. */
|
|
6
|
-
export const useSession = () =>
|
|
7
|
+
export const useSession = () => {
|
|
8
|
+
const session = useAppSelector((state) => state.session)
|
|
9
|
+
useDebugValue(session.status)
|
|
10
|
+
return session
|
|
11
|
+
}
|