@starci/hfs 4.3.0 → 4.4.1
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 +14 -0
- package/README.md +1 -1
- package/db/migrate.mjs +361 -0
- package/db/post-cutover.mjs +136 -0
- package/emit/contracts.mjs +2 -2
- package/emit/db-types.mjs +12 -3
- package/lint/run.mjs +3 -3
- package/package.json +4 -1
- package/release/gate.mjs +298 -0
- package/release/index.mjs +103 -0
- package/release/push.mjs +110 -0
- package/report/sonar.mjs +1 -1
- package/runtime/config.example.yaml +7 -6
- package/runtime/engine/config.mjs +10 -18
- package/runtime/engine/removed-vocabulary.mjs +0 -2
- package/runtime/knowledge/hfs/canon-pins.yaml +11 -11
- package/runtime/knowledge/hfs/fe-stack.yaml +22 -1
- package/runtime/knowledge/hfs/rules.yaml +2855 -163
- package/runtime/knowledge/hfs/slots.yaml +333 -62
- package/runtime/knowledge/patterns/be/api.yaml +32 -5
- package/runtime/knowledge/patterns/be/cli.yaml +14 -4
- 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 +23 -4
- package/runtime/knowledge/patterns/fe/folder.yaml +1 -0
- package/runtime/knowledge/sonar-gate.yaml +1 -1
- package/runtime/modules/kernel/failure-codes.yaml +3091 -43
- package/runtime/modules/kernel/removed-vocabulary.yaml +30 -0
- package/runtime/modules/models/runtimes.yaml +5 -7
- package/runtime/modules/schemas/application-stacks.schema.yaml +663 -0
- package/runtime/packages/cli/src/catalog.generated.mjs +13769 -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/init.mjs +7 -0
- package/runtime/scripts/api/git/lib.mjs +4 -1
- 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 +42 -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 +1 -8
- package/runtime/scripts/hfs/architecture/backend.mjs +2 -7
- package/runtime/scripts/hfs/architecture/client-reaches-server.mjs +6 -3
- package/runtime/scripts/hfs/architecture/config.mjs +1 -1
- package/runtime/scripts/hfs/architecture/dead-exports-bindings.mjs +149 -0
- package/runtime/scripts/hfs/architecture/dead-exports.mjs +9 -41
- package/runtime/scripts/hfs/architecture/default-deny.mjs +8 -6
- 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/index.mjs +1 -1
- package/runtime/scripts/hfs/architecture/module-per-transport.mjs +28 -13
- 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 +2 -2
- package/runtime/scripts/hfs/architecture/source-names.mjs +48 -3
- package/runtime/scripts/hfs/architecture/supabase-ast.mjs +211 -11
- package/runtime/scripts/hfs/architecture/supabase-be.mjs +1 -1
- 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 +4 -4
- package/runtime/scripts/hfs/architecture/unit-spec-providers.mjs +8 -2
- package/runtime/scripts/hfs/architecture.mjs +1 -1
- package/runtime/scripts/hfs/check-results.mjs +28 -0
- package/runtime/scripts/hfs/check.mjs +46 -47
- package/runtime/scripts/hfs/coverage-from.mjs +70 -0
- package/runtime/scripts/hfs/coverage-scope.mjs +1 -1
- 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 +69 -9
- package/runtime/scripts/hfs/param-names.mjs +1 -1
- package/runtime/scripts/hfs/refusal-codes.mjs +6 -0
- package/runtime/scripts/hfs/rule-catalog.mjs +158 -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/cli.mjs +1 -1
- package/runtime/scripts/hfs/rules/contract-compat.mjs +1 -1
- package/runtime/scripts/hfs/rules/contract.mjs +67 -6
- 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 +286 -7
- 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 +9 -0
- 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 +9 -8
- 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/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 +13 -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 +41 -1
- package/runtime/scripts/hfs/rules/stacks-swarm.mjs +417 -0
- package/runtime/scripts/hfs/rules/supabase-secrets.mjs +2 -2
- 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-edit.mjs +170 -0
- package/runtime/scripts/hfs/secret-init.mjs +127 -19
- package/runtime/scripts/hfs/secret-sops.mjs +38 -6
- package/runtime/scripts/hfs/secret-store.mjs +56 -54
- package/runtime/scripts/hfs/secret.mjs +34 -5
- package/runtime/scripts/hfs/slot-imports.mjs +18 -5
- package/runtime/scripts/hfs/slots.mjs +3 -2
- 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/typescript-programs.mjs +0 -8
- 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/env.mjs +2 -2
- package/runtime/scripts/lib/git.mjs +1 -1
- package/runtime/scripts/lib/i18n.mjs +0 -2
- package/runtime/scripts/lib/json-clone.mjs +61 -0
- package/runtime/scripts/lib/language.mjs +1 -1
- package/runtime/scripts/lib/list.mjs +4 -0
- package/runtime/scripts/lib/roots.mjs +2 -4
- 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 +5 -18
- package/runtime/scripts/lib/trim-end.mjs +8 -0
- package/runtime/scripts/lib/ts-analysis.mjs +5 -2
- 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 +14 -6
- package/scaffold/add-compose.mjs +79 -0
- package/scaffold/add-database-lite.mjs +14 -0
- package/scaffold/add-fe-overlay.mjs +1 -0
- package/scaffold/add-fe-page.mjs +1 -0
- package/scaffold/add-inbox-lite.mjs +74 -42
- package/scaffold/add-table.mjs +110 -87
- package/scaffold/add.mjs +159 -44
- package/scaffold/app.mjs +124 -39
- package/scaffold/edition-gate.mjs +3 -3
- package/scaffold/lite-exports.mjs +2 -1
- package/scaffold/service.mjs +2 -2
- package/scaffold/supabase-ports.mjs +1 -1
- package/src/main.mjs +229 -116
- 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/format.mjs +1 -1
- package/sync/hygiene.mjs +1 -1
- package/sync/index.mjs +110 -54
- 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 +3 -0
- package/templates/app/gitignore-lite +3 -0
- 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/.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 +178 -1
- 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/README.md +5 -3
- 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/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 +17 -18
- package/templates/be/inbox/database-client.ts.tpl +12 -11
- 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 +42 -9
- package/templates/be/inbox/service.ts.tpl +23 -8
- package/templates/be/inbox/webhook-door.spec.ts.tpl +1 -1
- package/templates/be/inbox/webhook-door.ts.tpl +2 -2
- 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.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.module.ts +11 -9
- 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 +2 -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 +15 -1
- package/templates/be/skeleton/apps/cli/src/app.module.ts +3 -13
- package/templates/be/skeleton/apps/cli/src/cli.options.ts +6 -14
- 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/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/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/app.module.ts +14 -18
- 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 +2 -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 +2 -3
- 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/index.mjs +54 -41
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ConfigurableModuleBuilder } from "@nestjs/common"
|
|
2
2
|
import { QUEUE_OPTIONS } from "./queue.decorators"
|
|
3
|
-
import type {
|
|
3
|
+
import type { QueueRegistrationOptions } from "./queue.options"
|
|
4
4
|
|
|
5
5
|
/** The configurable-module base of the queues; `isGlobal` is decided by the app root. */
|
|
6
|
-
export const { ConfigurableModuleClass, OPTIONS_TYPE } = new ConfigurableModuleBuilder<
|
|
6
|
+
export const { ConfigurableModuleClass, OPTIONS_TYPE } = new ConfigurableModuleBuilder<QueueRegistrationOptions>({
|
|
7
7
|
optionsInjectionToken: QUEUE_OPTIONS,
|
|
8
8
|
})
|
|
9
9
|
.setExtras({ isGlobal: false }, (definition, extras) => ({ ...definition, global: extras.isGlobal }))
|
|
@@ -28,6 +28,17 @@ export class QueueModule extends ConfigurableModuleClass {
|
|
|
28
28
|
/** Registers the capability once per app that enqueues or processes jobs. */
|
|
29
29
|
static register(options: typeof OPTIONS_TYPE): DynamicModule {
|
|
30
30
|
const base = super.register(options)
|
|
31
|
+
if (options.outboxOnly === true) {
|
|
32
|
+
return {
|
|
33
|
+
...base,
|
|
34
|
+
providers: [
|
|
35
|
+
...(base.providers ?? []),
|
|
36
|
+
QueueOutboxService,
|
|
37
|
+
{ provide: QUEUE_OUTBOX, useExisting: QueueOutboxService },
|
|
38
|
+
],
|
|
39
|
+
exports: [QUEUE_OUTBOX],
|
|
40
|
+
}
|
|
41
|
+
}
|
|
31
42
|
return {
|
|
32
43
|
...base,
|
|
33
44
|
providers: [
|
|
@@ -3,6 +3,8 @@ import type { QueueSchedulerDefinition } from "./queue.contracts"
|
|
|
3
3
|
|
|
4
4
|
/** What the queues of one app need: where Redis is, how the relay and the workers run, which connections hold an outbox, and the schedulers it registers. */
|
|
5
5
|
export interface QueueOptions {
|
|
6
|
+
/** The runtime registration owns the relay, workers and schedulers. */
|
|
7
|
+
readonly outboxOnly?: false
|
|
6
8
|
/** The Redis host BullMQ talks to. */
|
|
7
9
|
readonly redisHost: string
|
|
8
10
|
/** The Redis port. */
|
|
@@ -22,3 +24,11 @@ export interface QueueOptions {
|
|
|
22
24
|
/** The job schedulers the app registers at boot; BullMQ upserts them by id, so a pool of replicas fires each one once per interval. */
|
|
23
25
|
readonly schedulers: ReadonlyArray<QueueSchedulerDefinition>
|
|
24
26
|
}
|
|
27
|
+
|
|
28
|
+
/** A one-off producer writes an outbox row and exits; the running app owns delivery. */
|
|
29
|
+
export interface QueueOutboxOnlyOptions {
|
|
30
|
+
readonly outboxOnly: true
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Registers either the running queue capability or only its transactional writer. */
|
|
34
|
+
export type QueueRegistrationOptions = QueueOptions | QueueOutboxOnlyOptions
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ConfigurableModuleBuilder } from "@nestjs/common"
|
|
2
|
+
import type { @@Queue@@Options } from "./@@queue@@.options"
|
|
3
|
+
|
|
4
|
+
/** The configurable-module base of the @@queue@@ module. */
|
|
5
|
+
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
|
|
6
|
+
new ConfigurableModuleBuilder<@@Queue@@Options>().setClassMethodName("register").build()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Module } from "@nestjs/common"
|
|
2
|
+
import { ConfigurableModuleClass } from "./@@queue@@.module-definition"
|
|
2
3
|
import { @@Queue@@Queue } from "./@@queue@@.queue"
|
|
3
4
|
|
|
4
5
|
@Module({ providers: [@@Queue@@Queue], exports: [@@Queue@@Queue] })
|
|
5
6
|
/** The @@queue@@ queue: its typed producer, imported by the domain module whose service enqueues. */
|
|
6
|
-
export class @@Queue@@Module {}
|
|
7
|
+
export class @@Queue@@Module extends ConfigurableModuleClass {}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ConfigurableModuleBuilder } from "@nestjs/common"
|
|
2
|
+
import type { @@Reactor@@MessageOptions } from "./@@reactor@@-message.options"
|
|
3
|
+
|
|
4
|
+
/** The configurable-module base of the @@reactor@@-message module. */
|
|
5
|
+
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
|
|
6
|
+
new ConfigurableModuleBuilder<@@Reactor@@MessageOptions>().setClassMethodName("register").build()
|
|
@@ -4,14 +4,17 @@ import { InjectEventConsumerRegistry } from "@modules/platform/event-bus"
|
|
|
4
4
|
import type { EventConsumerRegistry } from "@modules/platform/event-bus"
|
|
5
5
|
import { @@Reactor@@Module } from "../../@@reactor@@.module"
|
|
6
6
|
import { @@Event@@Consumer } from "./@@event@@.consumer"
|
|
7
|
+
import { ConfigurableModuleClass } from "./@@reactor@@-message.module-definition"
|
|
7
8
|
|
|
8
|
-
@Module({ imports: [@@Reactor@@Module], providers: [@@Event@@Consumer] })
|
|
9
|
+
@Module({ imports: [@@Reactor@@Module.register({})], providers: [@@Event@@Consumer] })
|
|
9
10
|
/** The message transport of the @@reactor@@ reactor: registers its consumers with the event bus; a worker or api app composes it. */
|
|
10
|
-
export class @@Reactor@@MessageModule implements OnModuleInit {
|
|
11
|
+
export class @@Reactor@@MessageModule extends ConfigurableModuleClass implements OnModuleInit {
|
|
11
12
|
constructor(
|
|
12
13
|
@InjectEventConsumerRegistry() private readonly registry: EventConsumerRegistry,
|
|
13
14
|
private readonly @@eventCamel@@Consumer: @@Event@@Consumer,
|
|
14
|
-
) {
|
|
15
|
+
) {
|
|
16
|
+
super()
|
|
17
|
+
}
|
|
15
18
|
|
|
16
19
|
/** Hands every consumer to the registry. */
|
|
17
20
|
onModuleInit(): void {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ConfigurableModuleBuilder } from "@nestjs/common"
|
|
2
|
+
import type { @@Reactor@@Options } from "./@@reactor@@.options"
|
|
3
|
+
|
|
4
|
+
/** The configurable-module base of the @@reactor@@ module. */
|
|
5
|
+
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
|
|
6
|
+
new ConfigurableModuleBuilder<@@Reactor@@Options>().setClassMethodName("register").build()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Module } from "@nestjs/common"
|
|
2
|
+
import { ConfigurableModuleClass } from "./@@reactor@@.module-definition"
|
|
2
3
|
import { @@Action@@Handler } from "./application/@@action@@.handler"
|
|
3
4
|
|
|
4
5
|
@Module({ providers: [@@Action@@Handler] })
|
|
5
6
|
/** The @@reactor@@ reactor: the handler its consumers dispatch to. */
|
|
6
|
-
export class @@Reactor@@Module {}
|
|
7
|
+
export class @@Reactor@@Module extends ConfigurableModuleClass {}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { Test } from "@nestjs/testing"
|
|
2
|
+
import { MESSAGE_MAPPING_METADATA } from "@nestjs/websockets/constants"
|
|
3
|
+
import { @@service@@ } from "@@serviceModule@@"
|
|
4
|
+
import type { VerifySupabaseAccessToken } from "@modules/integrations/supabase"
|
|
5
|
+
import { SupabaseErrorCode } from "@modules/integrations/supabase"
|
|
6
|
+
import type { Principal } from "@modules/platform/cqrs"
|
|
7
|
+
import { ok, refused } from "@modules/platform/primitives"
|
|
8
|
+
import { REALTIME_HUB } from "@modules/platform/realtime"
|
|
9
|
+
import type { RealtimeHub, RealtimeTopic } from "@modules/platform/realtime"
|
|
10
|
+
import { @@Channel@@Gateway } from "./@@channel@@.gateway"
|
|
11
|
+
import { @@Channel@@WebsocketModule } from "./@@channel@@-websocket.module"
|
|
12
|
+
import type { @@Channel@@Namespace, @@Channel@@Socket } from "./@@channel@@-websocket.module"
|
|
13
|
+
|
|
14
|
+
const principal: Principal = { id: "p-1", role: "authenticated" }
|
|
15
|
+
|
|
16
|
+
/** A recording hub whose stream ends when the transport returns its iterator. */
|
|
17
|
+
const hubAnswering = (frame: unknown = undefined) => {
|
|
18
|
+
const topics: Array<string> = []
|
|
19
|
+
const released: Array<string> = []
|
|
20
|
+
const hub: RealtimeHub = {
|
|
21
|
+
publish: () => undefined,
|
|
22
|
+
subscriberCount: () => 0,
|
|
23
|
+
subscribe: <T extends object>(topic: RealtimeTopic<T>): AsyncIterable<T> => {
|
|
24
|
+
topics.push(topic.name)
|
|
25
|
+
let release: () => void = () => undefined
|
|
26
|
+
const closed = new Promise<void>((resolve) => { release = resolve })
|
|
27
|
+
let sent = false
|
|
28
|
+
return {
|
|
29
|
+
[Symbol.asyncIterator]: () => ({
|
|
30
|
+
next: async (): Promise<IteratorResult<T>> => {
|
|
31
|
+
if (!sent && topic.accepts(frame)) {
|
|
32
|
+
sent = true
|
|
33
|
+
return { done: false, value: frame }
|
|
34
|
+
}
|
|
35
|
+
await closed
|
|
36
|
+
return { done: true, value: undefined }
|
|
37
|
+
},
|
|
38
|
+
return: async (): Promise<IteratorResult<T>> => {
|
|
39
|
+
released.push(topic.name)
|
|
40
|
+
release()
|
|
41
|
+
return { done: true, value: undefined }
|
|
42
|
+
},
|
|
43
|
+
}),
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
return { hub, topics, released }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** The adapter calls middleware first and only then announces a connection. */
|
|
51
|
+
const namespaceAnswering = () => {
|
|
52
|
+
let middleware: Parameters<@@Channel@@Namespace["use"]>[0] = (_client, next) => next(new Error("Uninitialized"))
|
|
53
|
+
let connect: Parameters<@@Channel@@Namespace["on"]>[1] = () => undefined
|
|
54
|
+
const namespace: @@Channel@@Namespace = {
|
|
55
|
+
use: (listener) => { middleware = listener },
|
|
56
|
+
on: (_event, listener) => { connect = listener },
|
|
57
|
+
}
|
|
58
|
+
const authenticate = (client: @@Channel@@Socket) => new Promise<void>((resolve, reject) => {
|
|
59
|
+
middleware(client, (error) => error === undefined ? resolve() : reject(error))
|
|
60
|
+
})
|
|
61
|
+
return { namespace, authenticate, connect: (client: @@Channel@@Socket) => connect(client) }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const socketOf = (id: string, auth: Readonly<Record<string, unknown>> = { accessToken: "signed-token" }) => {
|
|
65
|
+
let connected = true
|
|
66
|
+
let disconnect: () => void = () => undefined
|
|
67
|
+
let delivered: () => void = () => undefined
|
|
68
|
+
const pushed = new Promise<void>((resolve) => { delivered = resolve })
|
|
69
|
+
const data: { principal?: Principal } = {}
|
|
70
|
+
const socket = {
|
|
71
|
+
id,
|
|
72
|
+
get connected(): boolean { return connected },
|
|
73
|
+
handshake: { auth },
|
|
74
|
+
data,
|
|
75
|
+
emit: jest.fn(() => delivered()),
|
|
76
|
+
once: (_event: "disconnect", listener: () => void) => { disconnect = listener },
|
|
77
|
+
disconnect: jest.fn((_close: boolean) => { connected = false; disconnect() }),
|
|
78
|
+
} satisfies @@Channel@@Socket
|
|
79
|
+
return { socket, pushed }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const build = async (hub: RealtimeHub, verify: VerifySupabaseAccessToken) => {
|
|
83
|
+
const moduleRef = await Test.createTestingModule({
|
|
84
|
+
imports: [@@Channel@@WebsocketModule.register({ verifyAccessToken: verify })],
|
|
85
|
+
})
|
|
86
|
+
.useMocker((token) => token === REALTIME_HUB ? hub : undefined)
|
|
87
|
+
.compile()
|
|
88
|
+
const door = moduleRef.get(@@Channel@@Gateway)
|
|
89
|
+
const transport = moduleRef.get(@@Channel@@WebsocketModule)
|
|
90
|
+
const adapter = namespaceAnswering()
|
|
91
|
+
door.namespace = adapter.namespace
|
|
92
|
+
transport.onModuleInit()
|
|
93
|
+
return { door, transport, adapter }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
describe("@@Channel@@Gateway", () => {
|
|
97
|
+
it("builds the topic only from the verified principal, ignoring handshake principal and topic claims", async () => {
|
|
98
|
+
const { hub, topics } = hubAnswering()
|
|
99
|
+
const verify: VerifySupabaseAccessToken = jest.fn().mockResolvedValue(ok(principal))
|
|
100
|
+
const { transport, adapter } = await build(hub, verify)
|
|
101
|
+
const { socket } = socketOf("socket-1", { accessToken: "signed-token", principal: { id: "p-2" }, topic: "foreign" })
|
|
102
|
+
|
|
103
|
+
await adapter.authenticate(socket)
|
|
104
|
+
adapter.connect(socket)
|
|
105
|
+
|
|
106
|
+
expect(verify).toHaveBeenCalledWith("signed-token")
|
|
107
|
+
expect(socket.data.principal).toEqual(principal)
|
|
108
|
+
expect(topics).toEqual([@@service@@(principal.id).name])
|
|
109
|
+
await transport.onModuleDestroy()
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it("isolates another authenticated principal's topic", async () => {
|
|
113
|
+
const { hub, topics } = hubAnswering()
|
|
114
|
+
const verify: VerifySupabaseAccessToken = jest.fn().mockResolvedValue(ok({ id: "p-2", role: "authenticated" }))
|
|
115
|
+
const { transport, adapter } = await build(hub, verify)
|
|
116
|
+
const { socket } = socketOf("socket-2")
|
|
117
|
+
|
|
118
|
+
await adapter.authenticate(socket)
|
|
119
|
+
adapter.connect(socket)
|
|
120
|
+
|
|
121
|
+
expect(topics).toEqual([@@service@@("p-2").name])
|
|
122
|
+
expect(topics).not.toContain(@@service@@(principal.id).name)
|
|
123
|
+
await transport.onModuleDestroy()
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it("pushes a hub frame automatically and releases the iterator on disconnect", async () => {
|
|
127
|
+
const frame = { id: "x-1" }
|
|
128
|
+
const { hub, released } = hubAnswering(frame)
|
|
129
|
+
const verify: VerifySupabaseAccessToken = jest.fn().mockResolvedValue(ok(principal))
|
|
130
|
+
const { transport, adapter } = await build(hub, verify)
|
|
131
|
+
const { socket, pushed } = socketOf("socket-1")
|
|
132
|
+
|
|
133
|
+
await adapter.authenticate(socket)
|
|
134
|
+
adapter.connect(socket)
|
|
135
|
+
await pushed
|
|
136
|
+
socket.disconnect(true)
|
|
137
|
+
|
|
138
|
+
expect(socket.emit).toHaveBeenCalledWith("@@channelCamel@@Changed", frame)
|
|
139
|
+
expect(released).toEqual([@@service@@(principal.id).name])
|
|
140
|
+
await transport.onModuleDestroy()
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it.each([{}, { accessToken: "" }, { accessToken: 42 }])("refuses a missing or malformed access token without invoking the verifier", async (auth) => {
|
|
144
|
+
const { hub, topics } = hubAnswering()
|
|
145
|
+
const verify: VerifySupabaseAccessToken = jest.fn()
|
|
146
|
+
const { adapter } = await build(hub, verify)
|
|
147
|
+
const { socket } = socketOf("socket-1", auth)
|
|
148
|
+
socket.data.principal = principal
|
|
149
|
+
|
|
150
|
+
await expect(adapter.authenticate(socket)).rejects.toThrow("Unauthorized")
|
|
151
|
+
|
|
152
|
+
expect(verify).not.toHaveBeenCalled()
|
|
153
|
+
expect(socket.data.principal).toBeUndefined()
|
|
154
|
+
expect(topics).toEqual([])
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
it("refuses a rejected token and clears a prior principal", async () => {
|
|
158
|
+
const { hub, topics } = hubAnswering()
|
|
159
|
+
const verify: VerifySupabaseAccessToken = jest.fn().mockResolvedValue(refused(SupabaseErrorCode.AccessTokenInvalid))
|
|
160
|
+
const { adapter } = await build(hub, verify)
|
|
161
|
+
const { socket } = socketOf("socket-1")
|
|
162
|
+
socket.data.principal = principal
|
|
163
|
+
|
|
164
|
+
await expect(adapter.authenticate(socket)).rejects.toThrow("Unauthorized")
|
|
165
|
+
|
|
166
|
+
expect(socket.data.principal).toBeUndefined()
|
|
167
|
+
expect(topics).toEqual([])
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it("refuses a connection that bypasses authentication without opening a hub stream", async () => {
|
|
171
|
+
const { hub, topics } = hubAnswering()
|
|
172
|
+
const { adapter } = await build(hub, jest.fn())
|
|
173
|
+
const { socket } = socketOf("socket-1")
|
|
174
|
+
|
|
175
|
+
adapter.connect(socket)
|
|
176
|
+
|
|
177
|
+
expect(socket.disconnect).toHaveBeenCalledWith(true)
|
|
178
|
+
expect(topics).toEqual([])
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
it("has no inbound application message handler", async () => {
|
|
182
|
+
const { hub } = hubAnswering()
|
|
183
|
+
const { door } = await build(hub, jest.fn())
|
|
184
|
+
|
|
185
|
+
expect(Reflect.getMetadata(MESSAGE_MAPPING_METADATA, door.frames)).toBeUndefined()
|
|
186
|
+
expect(Object.getOwnPropertyNames(@@Channel@@Gateway.prototype)).toEqual(["constructor", "frames"])
|
|
187
|
+
})
|
|
188
|
+
})
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { WebSocketGateway, WebSocketServer } from "@nestjs/websockets"
|
|
2
|
+
import { @@service@@ } from "@@serviceModule@@"
|
|
3
|
+
import type { @@Channel@@Frame } from "@@serviceModule@@"
|
|
4
|
+
import type { Principal } from "@modules/platform/cqrs"
|
|
5
|
+
import { InjectRealtimeHub } from "@modules/platform/realtime"
|
|
6
|
+
import type { RealtimeHub } from "@modules/platform/realtime"
|
|
7
|
+
import type { @@Channel@@Namespace } from "./@@channel@@-websocket.module"
|
|
8
|
+
|
|
9
|
+
@WebSocketGateway({ namespace: "/@@channel@@", transports: ["websocket"] })
|
|
10
|
+
/** The push-only @@channel@@ door: its module authenticates each connection before opening the principal's stream. */
|
|
11
|
+
export class @@Channel@@Gateway {
|
|
12
|
+
/** The namespace created by the app's socket.io adapter; the module installs authentication before the app listens. */
|
|
13
|
+
@WebSocketServer()
|
|
14
|
+
namespace!: @@Channel@@Namespace
|
|
15
|
+
|
|
16
|
+
constructor(@InjectRealtimeHub() private readonly hub: RealtimeHub) {}
|
|
17
|
+
|
|
18
|
+
/** The domain contract builds this principal-wide topic; the reactor publishes through the same builder. */
|
|
19
|
+
frames(principal: Principal): AsyncIterable<@@Channel@@Frame> {
|
|
20
|
+
return this.hub.subscribe(@@service@@(principal.id))
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ConfigurableModuleBuilder } from "@nestjs/common"
|
|
2
|
+
import type { @@Channel@@GraphqlOptions } from "./@@channel@@-graphql.options"
|
|
3
|
+
|
|
4
|
+
/** The configurable-module base of the @@channel@@-graphql module. */
|
|
5
|
+
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
|
|
6
|
+
new ConfigurableModuleBuilder<@@Channel@@GraphqlOptions>().setClassMethodName("register").build()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Module } from "@nestjs/common"
|
|
2
|
+
import { ConfigurableModuleClass } from "./@@channel@@-graphql.module-definition"
|
|
2
3
|
import { @@Channel@@Subscription } from "./@@channel@@.subscription"
|
|
3
4
|
|
|
4
5
|
@Module({ providers: [@@Channel@@Subscription] })
|
|
5
6
|
/** The GraphQL transport of the @@channel@@ channel: its subscription door; the hub comes from the app's realtime capability. */
|
|
6
|
-
export class @@Channel@@GraphqlModule {}
|
|
7
|
+
export class @@Channel@@GraphqlModule extends ConfigurableModuleClass {}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ConfigurableModuleBuilder } from "@nestjs/common"
|
|
2
|
+
import type { @@Channel@@WebsocketOptions } from "./@@channel@@-websocket.options"
|
|
3
|
+
|
|
4
|
+
/** The configurable-module base of the @@channel@@-websocket module. */
|
|
5
|
+
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
|
|
6
|
+
new ConfigurableModuleBuilder<@@Channel@@WebsocketOptions>().setClassMethodName("register").build()
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Module } from "@nestjs/common"
|
|
2
|
+
import type { OnModuleDestroy, OnModuleInit } from "@nestjs/common"
|
|
3
|
+
import type { @@Channel@@Frame } from "@@serviceModule@@"
|
|
4
|
+
import type { VerifySupabaseAccessToken } from "@modules/integrations/supabase"
|
|
5
|
+
import { injector } from "@modules/platform/composition"
|
|
6
|
+
import type { Principal } from "@modules/platform/cqrs"
|
|
7
|
+
import { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } from "./@@channel@@-websocket.module-definition"
|
|
8
|
+
import type { @@Channel@@WebsocketOptions } from "./@@channel@@-websocket.options"
|
|
9
|
+
import { @@Channel@@Gateway } from "./@@channel@@.gateway"
|
|
10
|
+
|
|
11
|
+
const ACCESS_TOKEN_VERIFIER: unique symbol = Symbol("@@channel@@.access-token-verifier")
|
|
12
|
+
|
|
13
|
+
/** The socket.io surface used here; the adapter and the socket library remain owned by platform/realtime. */
|
|
14
|
+
export interface @@Channel@@Socket {
|
|
15
|
+
/** The adapter's connection identifier. */
|
|
16
|
+
readonly id: string
|
|
17
|
+
/** Whether the connection is still open. */
|
|
18
|
+
readonly connected: boolean
|
|
19
|
+
/** Untrusted handshake input: only its access token is read. */
|
|
20
|
+
readonly handshake: { readonly auth: Readonly<Record<string, unknown>> }
|
|
21
|
+
/** Server-side state: middleware replaces any previous principal with verified claims. */
|
|
22
|
+
readonly data: { principal?: Principal }
|
|
23
|
+
/** Sends one frame to this authenticated socket. */
|
|
24
|
+
emit(event: "@@channelCamel@@Changed", frame: @@Channel@@Frame): void
|
|
25
|
+
/** Releases the stream when the connection ends. */
|
|
26
|
+
once(event: "disconnect", listener: () => void): void
|
|
27
|
+
/** Closes a refused or failed connection. */
|
|
28
|
+
disconnect(close: boolean): void
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** A namespace from the app's socket.io adapter. No inbound application events are registered. */
|
|
32
|
+
export interface @@Channel@@Namespace {
|
|
33
|
+
/** Runs authentication before the connection event. */
|
|
34
|
+
use(middleware: (client: @@Channel@@Socket, next: (error?: Error) => void) => void): void
|
|
35
|
+
/** Automatically opens the authenticated client's push stream. */
|
|
36
|
+
on(event: "connection", listener: (client: @@Channel@@Socket) => void): void
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Module({
|
|
40
|
+
providers: [
|
|
41
|
+
@@Channel@@Gateway,
|
|
42
|
+
{ provide: ACCESS_TOKEN_VERIFIER, useFactory: (options: @@Channel@@WebsocketOptions) => options.verifyAccessToken, inject: [MODULE_OPTIONS_TOKEN] },
|
|
43
|
+
],
|
|
44
|
+
})
|
|
45
|
+
/** The socket transport: verifies each connection, forwards hub frames and releases every disconnected subscription. */
|
|
46
|
+
export class @@Channel@@WebsocketModule extends ConfigurableModuleClass implements OnModuleInit, OnModuleDestroy {
|
|
47
|
+
private readonly streams = new Map<string, AsyncIterator<@@Channel@@Frame>>()
|
|
48
|
+
|
|
49
|
+
constructor(
|
|
50
|
+
private readonly gateway: @@Channel@@Gateway,
|
|
51
|
+
@injector<VerifySupabaseAccessToken>(ACCESS_TOKEN_VERIFIER)
|
|
52
|
+
private readonly verifyAccessToken: VerifySupabaseAccessToken,
|
|
53
|
+
) {
|
|
54
|
+
super()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Nest creates gateway namespaces before module initialization and starts listening afterwards. */
|
|
58
|
+
onModuleInit(): void {
|
|
59
|
+
this.gateway.namespace.use((client, next) => {
|
|
60
|
+
void this.authenticate(client).then(() => next(), () => next(new Error("Unauthorized")))
|
|
61
|
+
})
|
|
62
|
+
this.gateway.namespace.on("connection", (client) => {
|
|
63
|
+
void this.push(client).catch(() => client.disconnect(true))
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Releases all hub iterators when the app shuts down. */
|
|
68
|
+
async onModuleDestroy(): Promise<void> {
|
|
69
|
+
await Promise.all([...this.streams.keys()].map((id) => this.release(id)))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private async authenticate(client: @@Channel@@Socket): Promise<void> {
|
|
73
|
+
client.data.principal = undefined
|
|
74
|
+
const token = client.handshake.auth.accessToken
|
|
75
|
+
if (typeof token !== "string" || token.length === 0) throw new Error("Unauthorized")
|
|
76
|
+
const verified = await this.verifyAccessToken(token)
|
|
77
|
+
if (verified.kind !== "ok" || verified.value.role !== "authenticated" || verified.value.id.length === 0) {
|
|
78
|
+
throw new Error("Unauthorized")
|
|
79
|
+
}
|
|
80
|
+
client.data.principal = verified.value
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private async push(client: @@Channel@@Socket): Promise<void> {
|
|
84
|
+
const principal = client.data.principal
|
|
85
|
+
if (principal === undefined) {
|
|
86
|
+
client.disconnect(true)
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
const iterator = this.gateway.frames(principal)[Symbol.asyncIterator]()
|
|
90
|
+
this.streams.set(client.id, iterator)
|
|
91
|
+
client.once("disconnect", () => {
|
|
92
|
+
void this.release(client.id).catch(() => client.disconnect(true))
|
|
93
|
+
})
|
|
94
|
+
try {
|
|
95
|
+
while (client.connected) {
|
|
96
|
+
const frame = await iterator.next()
|
|
97
|
+
if (frame.done || !client.connected) break
|
|
98
|
+
client.emit("@@channelCamel@@Changed", frame.value)
|
|
99
|
+
}
|
|
100
|
+
} finally {
|
|
101
|
+
await this.release(client.id)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private async release(id: string): Promise<void> {
|
|
106
|
+
const iterator = this.streams.get(id)
|
|
107
|
+
this.streams.delete(id)
|
|
108
|
+
await iterator?.return?.()
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { VerifySupabaseAccessToken } from "@modules/integrations/supabase"
|
|
2
|
+
|
|
3
|
+
/** The options of the @@channel@@ socket transport: the cryptographic verifier that authenticates each connection. */
|
|
4
|
+
export interface @@Channel@@WebsocketOptions {
|
|
5
|
+
/** Verifies the access token of a handshake with the same verifier identity uses. */
|
|
6
|
+
readonly verifyAccessToken: VerifySupabaseAccessToken
|
|
7
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ConfigurableModuleBuilder } from "@nestjs/common"
|
|
2
|
+
import type { @@Saga@@MessageOptions } from "./@@saga@@-message.options"
|
|
3
|
+
|
|
4
|
+
/** The configurable-module base of the @@saga@@-message module. */
|
|
5
|
+
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
|
|
6
|
+
new ConfigurableModuleBuilder<@@Saga@@MessageOptions>().setClassMethodName("register").build()
|
|
@@ -5,15 +5,18 @@ import type { EventConsumerRegistry } from "@modules/platform/event-bus"
|
|
|
5
5
|
import { @@Saga@@Module } from "../../@@saga@@.module"
|
|
6
6
|
import { @@Done@@Consumer } from "./@@done@@.consumer"
|
|
7
7
|
import { @@Failed@@Consumer } from "./@@failed@@.consumer"
|
|
8
|
+
import { ConfigurableModuleClass } from "./@@saga@@-message.module-definition"
|
|
8
9
|
|
|
9
|
-
@Module({ imports: [@@Saga@@Module], providers: [@@Done@@Consumer, @@Failed@@Consumer] })
|
|
10
|
+
@Module({ imports: [@@Saga@@Module.register({})], providers: [@@Done@@Consumer, @@Failed@@Consumer] })
|
|
10
11
|
/** The message transport of the @@saga@@ saga: registers its consumers with the event bus. */
|
|
11
|
-
export class @@Saga@@MessageModule implements OnModuleInit {
|
|
12
|
+
export class @@Saga@@MessageModule extends ConfigurableModuleClass implements OnModuleInit {
|
|
12
13
|
constructor(
|
|
13
14
|
@InjectEventConsumerRegistry() private readonly registry: EventConsumerRegistry,
|
|
14
15
|
private readonly @@doneCamel@@Consumer: @@Done@@Consumer,
|
|
15
16
|
private readonly @@failedCamel@@Consumer: @@Failed@@Consumer,
|
|
16
|
-
) {
|
|
17
|
+
) {
|
|
18
|
+
super()
|
|
19
|
+
}
|
|
17
20
|
|
|
18
21
|
/** Hands every consumer to the registry. */
|
|
19
22
|
onModuleInit(): void {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ConfigurableModuleBuilder } from "@nestjs/common"
|
|
2
|
+
import type { @@Saga@@Options } from "./@@saga@@.options"
|
|
3
|
+
|
|
4
|
+
/** The configurable-module base of the @@saga@@ module. */
|
|
5
|
+
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
|
|
6
|
+
new ConfigurableModuleBuilder<@@Saga@@Options>().setClassMethodName("register").build()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Module } from "@nestjs/common"
|
|
2
|
+
import { ConfigurableModuleClass } from "./@@saga@@.module-definition"
|
|
2
3
|
import { Compensate@@Saga@@Handler } from "./application/compensate-@@saga@@.handler"
|
|
3
4
|
import { Complete@@Saga@@Handler } from "./application/complete-@@saga@@.handler"
|
|
4
5
|
import { Undo@@Saga@@Handler } from "./application/undo-@@saga@@.handler"
|
|
@@ -17,4 +18,4 @@ import { @@Step@@Step } from "./steps/@@step@@.saga-step"
|
|
|
17
18
|
],
|
|
18
19
|
})
|
|
19
20
|
/** The @@saga@@ saga: its orchestrator, its step and compensation, and the handlers of the commands the consumers dispatch. */
|
|
20
|
-
export class @@Saga@@Module {}
|
|
21
|
+
export class @@Saga@@Module extends ConfigurableModuleClass {}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ConfigurableModuleBuilder } from "@nestjs/common"
|
|
2
|
+
import type { @@Provider@@HttpOptions } from "./@@provider@@-http.options"
|
|
3
|
+
|
|
4
|
+
/** The configurable-module base of the @@provider@@-http module. */
|
|
5
|
+
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN, OPTIONS_TYPE } =
|
|
6
|
+
new ConfigurableModuleBuilder<@@Provider@@HttpOptions>().setClassMethodName("register").build()
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Module } from "@nestjs/common"
|
|
2
|
+
import { ConfigurableModuleClass } from "./@@provider@@-http.module-definition"
|
|
2
3
|
import { @@Provider@@Webhook } from "./@@provider@@.webhook"
|
|
3
4
|
|
|
4
5
|
@Module({ controllers: [@@Provider@@Webhook] })
|
|
5
6
|
/** The HTTP transport of the @@provider@@ notifier: its webhook door; the intake service and the signature service come from the app's capabilities. */
|
|
6
|
-
export class @@Provider@@HttpModule {}
|
|
7
|
+
export class @@Provider@@HttpModule extends ConfigurableModuleClass {}
|