@starci/hfs 4.0.8 → 4.0.10
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 +9 -0
- package/LICENSE +21 -0
- package/README.md +81 -39
- package/emit/contracts.mjs +56 -9
- package/emit/db-types.mjs +169 -0
- package/emit/events.mjs +41 -0
- package/emit/operations-worker.mjs +1 -1
- package/emit/operations.mjs +2 -2
- package/emit/schema-worker.mjs +1 -1
- package/lint/bound-sys.cjs +50 -0
- package/lint/run.mjs +131 -24
- package/package.json +16 -10
- package/report/sonar.mjs +8 -8
- package/runtime/engine/admission.mjs +308 -0
- package/runtime/engine/canonical-json.mjs +10 -0
- package/runtime/engine/config.mjs +486 -0
- package/runtime/engine/db/blob.mjs +315 -0
- package/runtime/engine/db/ledger-paths.mjs +83 -0
- package/runtime/engine/db/ledger.mjs +1118 -0
- package/runtime/engine/db/machine-connection.mjs +135 -0
- package/runtime/engine/db/machine-schema.mjs +84 -0
- package/runtime/engine/db/machine.mjs +1367 -0
- package/runtime/engine/db/migrations/machine/0001-init.sql +924 -0
- package/runtime/engine/db/migrations/runtime/0001-init.sql +1108 -0
- package/runtime/engine/db/provider-reservations.mjs +101 -0
- package/runtime/engine/digest.mjs +16 -0
- package/runtime/engine/invalid-config.mjs +15 -0
- package/runtime/engine/orca-config.mjs +27 -0
- package/runtime/engine/refuse.mjs +11 -0
- package/runtime/engine/secrets.mjs +130 -0
- package/runtime/knowledge/hfs/canon-pins.yaml +162 -31
- package/runtime/knowledge/hfs/peer-integrations.yaml +2 -2
- package/runtime/knowledge/hfs/rules.yaml +2059 -0
- package/runtime/knowledge/hfs/slots.yaml +912 -120
- package/runtime/knowledge/patterns/be/api.yaml +369 -0
- package/runtime/knowledge/patterns/be/cli.yaml +297 -0
- package/runtime/knowledge/patterns/be/domain.yaml +113 -0
- package/runtime/knowledge/patterns/be/event-bus.yaml +285 -0
- package/runtime/knowledge/patterns/be/jobs.yaml +261 -0
- package/runtime/knowledge/patterns/be/projections.yaml +178 -0
- package/runtime/knowledge/patterns/be/queues.yaml +236 -0
- package/runtime/knowledge/patterns/be/reactors.yaml +140 -0
- package/runtime/knowledge/patterns/be/realtime.yaml +222 -0
- package/runtime/knowledge/patterns/be/saga.yaml +248 -0
- package/runtime/knowledge/patterns/be/webhooks.yaml +221 -0
- package/runtime/knowledge/patterns/fe/folder.yaml +131 -25
- package/runtime/knowledge/sonar-gate.yaml +52 -18
- package/runtime/modules/kernel/failure-codes.yaml +611 -51
- package/runtime/modules/models/registry.yaml +553 -0
- package/runtime/modules/models/runtimes.yaml +695 -0
- package/runtime/modules/ops/_labels.yaml +53 -0
- package/runtime/scripts/api/fs/forbidden-root.mjs +51 -0
- package/runtime/scripts/api/fs/is-link-like.mjs +25 -0
- package/runtime/scripts/api/fs/lib.mjs +16 -2
- package/runtime/scripts/api/fs/safe-remove.mjs +12 -132
- package/runtime/scripts/api/git/config-get.mjs +10 -0
- package/runtime/scripts/api/git/diff.mjs +5 -0
- package/runtime/scripts/api/git/lib.mjs +18 -26
- package/runtime/scripts/api/git/log.mjs +5 -0
- package/runtime/scripts/api/git/ls-files.mjs +6 -0
- package/runtime/scripts/api/git/ls-tree.mjs +5 -0
- package/runtime/scripts/api/git/merge-base.mjs +9 -0
- package/runtime/scripts/api/git/remote.mjs +5 -0
- package/runtime/scripts/api/git/rev-parse-query.mjs +5 -0
- package/runtime/scripts/api/git/show.mjs +6 -0
- package/runtime/scripts/api/node/lib.mjs +14 -0
- package/runtime/scripts/api/node/spawn-node.mjs +6 -0
- package/runtime/scripts/api/process/lib.mjs +111 -0
- package/runtime/scripts/api/process/owned-process.mjs +78 -0
- package/runtime/scripts/api/process/resolve-real-tool.mjs +46 -0
- package/runtime/scripts/api/process/run-program.mjs +7 -0
- package/runtime/scripts/api/process/stop-owned-process.mjs +9 -0
- package/runtime/scripts/api/sops/decrypt.mjs +9 -12
- package/runtime/scripts/api/sops/lib.mjs +255 -0
- package/runtime/scripts/api/sops/seal.mjs +22 -0
- package/runtime/scripts/connectors/lib.mjs +488 -0
- package/runtime/scripts/hfs/architecture/ast-walks.mjs +220 -0
- package/runtime/scripts/hfs/architecture/backend.mjs +16 -23
- package/runtime/scripts/hfs/architecture/background-unowned.mjs +16 -34
- package/runtime/scripts/hfs/architecture/client-reaches-server.mjs +3 -1
- package/runtime/scripts/hfs/architecture/clones.mjs +4 -4
- package/runtime/scripts/hfs/architecture/config.mjs +9 -6
- package/runtime/scripts/hfs/architecture/connection-map.mjs +20 -8
- package/runtime/scripts/hfs/architecture/context-coupling.mjs +88 -0
- package/runtime/scripts/hfs/architecture/context-map.mjs +237 -0
- package/runtime/scripts/hfs/architecture/context-owner.mjs +82 -0
- package/runtime/scripts/hfs/architecture/context-platform-tables.mjs +47 -0
- package/runtime/scripts/hfs/architecture/context-transaction.mjs +60 -0
- package/runtime/scripts/hfs/architecture/contract-fixture-guard.mjs +4 -10
- package/runtime/scripts/hfs/architecture/contracts.mjs +33 -162
- package/runtime/scripts/hfs/architecture/dead-exports.mjs +58 -29
- package/runtime/scripts/hfs/architecture/doc-language.mjs +1 -1
- package/runtime/scripts/hfs/architecture/entrypoint.mjs +2 -1
- package/runtime/scripts/hfs/architecture/fe-slot-allows.mjs +2 -2
- package/runtime/scripts/hfs/architecture/feature-shape.mjs +5 -2
- package/runtime/scripts/hfs/architecture/framework-pinned.mjs +1 -1
- package/runtime/scripts/hfs/architecture/frontend.mjs +17 -43
- package/runtime/scripts/hfs/architecture/hfs.mjs +24 -39
- package/runtime/scripts/hfs/architecture/i18n-keys.mjs +1 -1
- package/runtime/scripts/hfs/architecture/index.mjs +17 -4
- package/runtime/scripts/hfs/architecture/machine-ast.mjs +44 -11
- package/runtime/scripts/hfs/architecture/managed-scripts.mjs +27 -0
- package/runtime/scripts/hfs/architecture/module-per-transport.mjs +30 -6
- package/runtime/scripts/hfs/architecture/next-data.mjs +22 -63
- package/runtime/scripts/hfs/architecture/owners.mjs +35 -15
- package/runtime/scripts/hfs/architecture/register-once.mjs +2 -1
- package/runtime/scripts/hfs/architecture/registration.mjs +23 -81
- package/runtime/scripts/hfs/architecture/required-files.mjs +20 -12
- package/runtime/scripts/hfs/architecture/schema-owner.mjs +17 -114
- package/runtime/scripts/hfs/architecture/server-action.mjs +24 -0
- package/runtime/scripts/hfs/architecture/side-boundary.mjs +16 -0
- package/runtime/scripts/hfs/architecture/source-names.mjs +27 -147
- package/runtime/scripts/hfs/architecture/sql-owner.mjs +59 -18
- package/runtime/scripts/hfs/architecture/sql-returning.mjs +64 -0
- package/runtime/scripts/hfs/architecture/supabase-ast.mjs +111 -0
- package/runtime/scripts/hfs/architecture/supabase-be.mjs +131 -0
- package/runtime/scripts/hfs/architecture/supabase-tables.mjs +42 -0
- package/runtime/scripts/hfs/architecture/supabase.mjs +434 -0
- package/runtime/scripts/hfs/architecture/surface.mjs +9 -3
- package/runtime/scripts/hfs/architecture/test-world-files.mjs +9 -19
- package/runtime/scripts/hfs/architecture/tiers.mjs +47 -5
- package/runtime/scripts/hfs/architecture/transport-owner.mjs +3 -3
- package/runtime/scripts/hfs/architecture/typescript.mjs +12 -26
- package/runtime/scripts/hfs/architecture.mjs +4 -4
- package/runtime/scripts/hfs/check.mjs +75 -72
- package/runtime/scripts/hfs/coverage-scope.mjs +162 -0
- package/runtime/scripts/hfs/declaration-shape.mjs +62 -0
- package/runtime/scripts/hfs/declaration-slots.mjs +75 -0
- package/runtime/scripts/hfs/edition-slots.mjs +66 -0
- package/runtime/scripts/hfs/manifest-shape.mjs +109 -32
- package/runtime/scripts/hfs/param-names.mjs +18 -0
- package/runtime/scripts/hfs/path-findings.mjs +1 -1
- package/runtime/scripts/hfs/repo-identity.mjs +9 -6
- package/runtime/scripts/hfs/rule-params-shape.mjs +50 -0
- package/runtime/scripts/hfs/rules/app-root.mjs +51 -0
- package/runtime/scripts/hfs/rules/cli.mjs +37 -0
- package/runtime/scripts/hfs/rules/contract-compat.mjs +71 -0
- package/runtime/scripts/hfs/rules/contract.mjs +10 -9
- package/runtime/scripts/hfs/rules/database-config.mjs +102 -0
- package/runtime/scripts/hfs/rules/database-constants.mjs +13 -0
- package/runtime/scripts/hfs/rules/database-migrations.mjs +111 -0
- package/runtime/scripts/hfs/rules/database-plpgsql.mjs +233 -0
- package/runtime/scripts/hfs/rules/database-sql.mjs +336 -0
- package/runtime/scripts/hfs/rules/database.mjs +68 -0
- package/runtime/scripts/hfs/rules/deps.mjs +1 -1
- package/runtime/scripts/hfs/rules/docker.mjs +259 -0
- package/runtime/scripts/hfs/rules/edition.mjs +111 -0
- package/runtime/scripts/hfs/rules/event-bus.mjs +153 -0
- package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +1 -1
- package/runtime/scripts/hfs/rules/fe-no-tests.mjs +6 -5
- package/runtime/scripts/hfs/rules/frontend-tree.mjs +9 -9
- package/runtime/scripts/hfs/rules/integration-specs.mjs +3 -6
- package/runtime/scripts/hfs/rules/kinds.mjs +84 -0
- package/runtime/scripts/hfs/rules/lint-suppression.mjs +1 -1
- package/runtime/scripts/hfs/rules/monorepo.mjs +179 -0
- package/runtime/scripts/hfs/rules/peer-integrations.mjs +3 -3
- package/runtime/scripts/hfs/rules/pipeline.mjs +11 -21
- package/runtime/scripts/hfs/rules/proof-commands.mjs +2 -2
- package/runtime/scripts/hfs/rules/read.mjs +1 -1
- package/runtime/scripts/hfs/rules/repo-local-checks.mjs +2 -2
- package/runtime/scripts/hfs/rules/saga.mjs +170 -0
- package/runtime/scripts/hfs/rules/secrets.mjs +3 -3
- package/runtime/scripts/hfs/rules/services.mjs +220 -0
- package/runtime/scripts/hfs/rules/spec-placement.mjs +1 -1
- package/runtime/scripts/hfs/rules/stacks.mjs +3 -3
- package/runtime/scripts/hfs/rules/supabase-secrets.mjs +89 -0
- package/runtime/scripts/hfs/rules/test-topology.mjs +2 -2
- package/runtime/scripts/hfs/secret.mjs +209 -0
- package/runtime/scripts/hfs/slots.mjs +78 -108
- package/runtime/scripts/hfs/sql/pg-parse.mjs +46 -0
- package/runtime/scripts/hfs/test-world-slot.mjs +6 -0
- package/runtime/scripts/hfs/tree.mjs +5 -4
- package/runtime/scripts/hfs/typescript-programs.mjs +0 -5
- package/runtime/scripts/hfs/view.mjs +3 -2
- package/runtime/scripts/lib/clip.mjs +19 -0
- package/runtime/scripts/lib/display-names.mjs +259 -0
- package/runtime/scripts/lib/dockerfile.mjs +124 -0
- package/runtime/scripts/lib/env.mjs +10 -0
- package/runtime/scripts/lib/event-contract.mjs +103 -0
- package/runtime/scripts/lib/example-refs.mjs +158 -0
- package/runtime/scripts/lib/fs-kind.mjs +14 -4
- package/runtime/scripts/lib/git.mjs +36 -0
- package/runtime/scripts/lib/graphql-contract.mjs +1 -1
- package/runtime/scripts/lib/i18n.mjs +86 -0
- package/runtime/scripts/lib/json-schema.mjs +52 -0
- package/runtime/scripts/lib/json.mjs +13 -3
- package/runtime/scripts/lib/language.mjs +24 -5
- package/runtime/scripts/lib/list.mjs +20 -0
- package/runtime/scripts/lib/mutation-fence.mjs +15 -0
- package/runtime/scripts/lib/package-at.mjs +37 -0
- package/runtime/scripts/lib/path-key.mjs +57 -2
- package/runtime/scripts/lib/process-identity.mjs +6 -0
- package/runtime/scripts/lib/read-text.mjs +34 -0
- package/runtime/scripts/lib/read-yaml.mjs +18 -0
- package/runtime/scripts/lib/redact.mjs +161 -0
- package/runtime/scripts/lib/regex.mjs +4 -0
- package/runtime/scripts/lib/same-text.mjs +5 -0
- package/runtime/scripts/lib/secret-patterns.mjs +4 -3
- package/runtime/scripts/lib/sleep-sync.mjs +2 -1
- package/runtime/scripts/lib/sleep.mjs +7 -0
- package/runtime/scripts/lib/sops-envelope.mjs +112 -0
- package/runtime/scripts/lib/source-phrases.mjs +34 -0
- package/runtime/scripts/lib/sqlite.mjs +21 -0
- package/runtime/scripts/lib/stack-services.mjs +7 -31
- package/runtime/scripts/lib/ts-ast.mjs +35 -0
- package/runtime/scripts/lib/walk.mjs +4 -3
- package/scaffold/add-app.mjs +174 -0
- package/scaffold/add-cli-lite.mjs +257 -0
- package/scaffold/add-inbox-lite.mjs +314 -0
- package/scaffold/add-table.mjs +344 -0
- package/scaffold/add.mjs +299 -0
- package/scaffold/app.mjs +358 -69
- package/scaffold/edition-gate.mjs +25 -0
- package/scaffold/image.mjs +19 -0
- package/scaffold/lite-exports.mjs +186 -0
- package/scaffold/service.mjs +32 -26
- package/scaffold/supabase-ports.mjs +26 -0
- package/src/main.mjs +327 -0
- package/sync/cli.mjs +6 -9
- package/sync/format.mjs +1 -1
- package/sync/hygiene.mjs +10 -10
- package/sync/index.mjs +167 -104
- package/sync/managed.mjs +19 -11
- package/sync/sonar-key.mjs +5 -0
- package/templates/app/ci-workflows/github/workflows/ci.yml +14 -14
- package/templates/app/ci-workflows/github/workflows/images.yml +37 -0
- package/templates/app/ci-workflows/sonar-steps.yml +9 -0
- package/templates/app/ci-workflows-lite/github/workflows/ci.yml +66 -0
- package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +31 -0
- package/templates/app/ci-workflows-lite/github/workflows/images.yml +37 -0
- package/templates/app/codegen-lite/scripts/codegen.mjs +32 -0
- package/templates/app/docker-ignore/dockerignore +50 -0
- package/templates/app/gitignore-lite +35 -0
- package/templates/app/hooks/husky/pre-commit +3 -8
- package/templates/app/hooks/husky/pre-push +45 -6
- package/templates/app/package-scripts/core.json +8 -0
- package/templates/app/package-scripts/package.json +3 -10
- package/templates/app/package-scripts-lite/package.json +15 -0
- package/templates/app/quality-config/codecov.yml +15 -3
- package/templates/app/quality-config/sonar-base.properties +4 -0
- package/templates/app/quality-config/sonar-project.properties +1 -4
- package/templates/app/quality-config-lite/sonar-project.properties +5 -0
- package/templates/app/skeleton/.starcistacks/dev/seeds/primary-notes.sql +5 -0
- package/templates/app/skeleton/.starciwork/features/system-health/index.yaml +4 -0
- package/templates/app/skeleton/.starciwork/{features/index.yaml → index.yaml} +2 -2
- package/templates/app/skeleton/README.md +7 -5
- package/templates/app/skeleton-lite/.sops.yaml +3 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/environment.json +5 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/secrets/.gitkeep +1 -0
- package/templates/app/skeleton-lite/.starciwork/shell/index.yaml +55 -0
- package/templates/app/skeleton-lite/README.md +40 -0
- package/templates/app/skeleton-lite/supabase/config.toml +41 -0
- package/templates/app/skeleton-lite/supabase/migrations/__timestamp___baseline.sql +56 -0
- package/templates/app/skeleton-lite/supabase/seed.sql +0 -0
- package/templates/app/task-graph/turbo.json +23 -0
- package/templates/app/tool-config-lite/prettierignore +2 -0
- package/templates/app/tool-config-lite/prettierrc +1 -0
- package/templates/app/upgrade-full/.starcistacks/application-stacks.yaml +38 -0
- package/templates/app/upgrade-full/.starcistacks/dev/README.md +10 -0
- package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/api.yaml +13 -0
- package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/compose.yaml +3 -0
- package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/postgres.yaml +12 -0
- package/templates/app/upgrade-full/.starcistacks/dev/infra/metadata.json +7 -0
- package/templates/be/common/main-listen.ts.partial +14 -0
- package/templates/be/common/sql-ident.ts.partial +7 -0
- package/templates/be/common/sql-tag.ts.partial +5 -0
- package/templates/be/image/api/Dockerfile +38 -0
- package/templates/be/image/cli/Dockerfile +38 -0
- package/templates/be/image/worker/Dockerfile +36 -0
- package/templates/be/inbox/database-client.ts.tpl +50 -0
- package/templates/be/inbox/index.ts.tpl +2 -0
- package/templates/be/inbox/migration.sql.tpl +29 -0
- package/templates/be/inbox/module-definition.ts.tpl +6 -0
- package/templates/be/inbox/module.ts.tpl +14 -0
- package/templates/be/inbox/options.ts.tpl +2 -0
- package/templates/be/inbox/service.ts.tpl +33 -0
- package/templates/be/inbox/sql.ts.tpl +16 -0
- package/templates/be/inbox/webhook-door.ts.tpl +36 -0
- package/templates/be/patterns/api/application.command.http.ts.tpl +10 -0
- package/templates/be/patterns/api/application.command.ts.tpl +10 -0
- package/templates/be/patterns/api/application.contracts.ts.tpl +11 -0
- package/templates/be/patterns/api/application.handler.http.ts.tpl +22 -0
- package/templates/be/patterns/api/application.handler.ts.tpl +22 -0
- package/templates/be/patterns/api/feature.index.http.ts.tpl +1 -0
- package/templates/be/patterns/api/feature.index.ts.tpl +1 -0
- package/templates/be/patterns/api/feature.module.ts.tpl +6 -0
- package/templates/be/patterns/api/graphql.input.ts.tpl +13 -0
- package/templates/be/patterns/api/graphql.mapper.ts.tpl +9 -0
- package/templates/be/patterns/api/graphql.module.ts.tpl +7 -0
- package/templates/be/patterns/api/graphql.resolver.ts.tpl +27 -0
- package/templates/be/patterns/api/graphql.type.ts.tpl +9 -0
- package/templates/be/patterns/api/http.controller.ts.tpl +27 -0
- package/templates/be/patterns/api/http.mapper.ts.tpl +9 -0
- package/templates/be/patterns/api/http.module.ts.tpl +7 -0
- package/templates/be/patterns/api/http.request.ts.tpl +10 -0
- package/templates/be/patterns/api/http.response.ts.tpl +5 -0
- package/templates/be/patterns/cli/group.cli.spec.ts.tpl +15 -0
- package/templates/be/patterns/cli/group.cli.ts.tpl +11 -0
- package/templates/be/patterns/cli/group.module.ts.tpl +7 -0
- package/templates/be/patterns/cli/sub.run.cli.spec.ts.tpl +17 -0
- package/templates/be/patterns/cli/sub.run.cli.ts.tpl +15 -0
- package/templates/be/patterns/event-bus/platform/errors/event-bus.error.ts.tpl +22 -0
- package/templates/be/patterns/event-bus/platform/event-bus.config.ts.tpl +19 -0
- package/templates/be/patterns/event-bus/platform/event-bus.contracts.ts.tpl +58 -0
- package/templates/be/patterns/event-bus/platform/event-bus.decorators.ts.tpl +46 -0
- package/templates/be/patterns/event-bus/platform/event-bus.log-events.ts.tpl +12 -0
- package/templates/be/patterns/event-bus/platform/event-bus.module-definition.ts.tpl +10 -0
- package/templates/be/patterns/event-bus/platform/event-bus.module.ts.tpl +52 -0
- package/templates/be/patterns/event-bus/platform/event-bus.options.ts.tpl +19 -0
- package/templates/be/patterns/event-bus/platform/event-bus.port.ts.tpl +28 -0
- package/templates/be/patterns/event-bus/platform/event-bus.service.spec.ts.tpl +165 -0
- package/templates/be/patterns/event-bus/platform/event-bus.service.ts.tpl +93 -0
- package/templates/be/patterns/event-bus/platform/event-envelope.policy.spec.ts.tpl +90 -0
- package/templates/be/patterns/event-bus/platform/event-envelope.policy.ts.tpl +58 -0
- package/templates/be/patterns/event-bus/platform/event-relay.service.spec.ts.tpl +136 -0
- package/templates/be/patterns/event-bus/platform/event-relay.service.ts.tpl +56 -0
- package/templates/be/patterns/event-bus/platform/event-runner.service.spec.ts.tpl +272 -0
- package/templates/be/patterns/event-bus/platform/event-runner.service.ts.tpl +128 -0
- package/templates/be/patterns/event-bus/platform/event-transport.port.ts.tpl +180 -0
- package/templates/be/patterns/event-bus/platform/event.policy.spec.ts.tpl +67 -0
- package/templates/be/patterns/event-bus/platform/event.policy.ts.tpl +38 -0
- package/templates/be/patterns/event-bus/platform/index.ts.tpl +11 -0
- package/templates/be/patterns/event-bus/platform/kafka-event-transport.client.spec.ts.tpl +348 -0
- package/templates/be/patterns/event-bus/platform/kafka-event-transport.client.ts.tpl +241 -0
- package/templates/be/patterns/event-bus/platform/messages/event-bus.messages.ts.tpl +15 -0
- package/templates/be/patterns/event-bus/platform/persistence/connection.ts.tpl +8 -0
- package/templates/be/patterns/event-bus/platform/persistence/entities/event-outbox.entity.ts.tpl +37 -0
- package/templates/be/patterns/event-bus/platform/persistence/event-bus.rows.ts.tpl +11 -0
- package/templates/be/patterns/event-bus/platform/persistence/event-bus.sql.ts.tpl +12 -0
- package/templates/be/patterns/event-bus/platform/persistence/migrations/1789800009000-create-event-outbox.ts.tpl +26 -0
- package/templates/be/patterns/jobs/job.index.ts.tpl +1 -0
- package/templates/be/patterns/jobs/job.module.ts.tpl +6 -0
- package/templates/be/patterns/jobs/job.processor.ts.tpl +20 -0
- package/templates/be/patterns/jobs/job.queue.module.ts.tpl +20 -0
- package/templates/be/patterns/jobs/job.step.ts.tpl +19 -0
- package/templates/be/patterns/jobs/platform/fenced.processor.spec.ts.tpl +31 -0
- package/templates/be/patterns/jobs/platform/fenced.processor.ts.tpl +13 -0
- package/templates/be/patterns/jobs/platform/job-claim.service.spec.ts.tpl +150 -0
- package/templates/be/patterns/jobs/platform/job-claim.service.ts.tpl +100 -0
- package/templates/be/patterns/jobs/platform/job-runner.service.spec.ts.tpl +138 -0
- package/templates/be/patterns/jobs/platform/job-runner.service.ts.tpl +69 -0
- package/templates/be/patterns/jobs/platform/jobs.config.ts.tpl +11 -0
- package/templates/be/patterns/jobs/platform/jobs.contracts.ts.tpl +62 -0
- package/templates/be/patterns/jobs/platform/jobs.decorators.ts.tpl +31 -0
- package/templates/be/patterns/jobs/platform/jobs.error.ts.tpl +22 -0
- package/templates/be/patterns/jobs/platform/jobs.index.ts.tpl +11 -0
- package/templates/be/patterns/jobs/platform/jobs.log-events.ts.tpl +9 -0
- package/templates/be/patterns/jobs/platform/jobs.messages.ts.tpl +15 -0
- package/templates/be/patterns/jobs/platform/jobs.module-definition.ts.tpl +10 -0
- package/templates/be/patterns/jobs/platform/jobs.module.ts.tpl +32 -0
- package/templates/be/patterns/jobs/platform/jobs.options.ts.tpl +11 -0
- package/templates/be/patterns/jobs/platform/jobs.port.ts.tpl +36 -0
- package/templates/be/patterns/jobs/platform/persistence.connection.ts.tpl +8 -0
- package/templates/be/patterns/jobs/platform/persistence.job.entity.ts.tpl +53 -0
- package/templates/be/patterns/jobs/platform/persistence.jobs.rows.ts.tpl +13 -0
- package/templates/be/patterns/jobs/platform/persistence.jobs.sql.ts.tpl +33 -0
- package/templates/be/patterns/jobs/platform/persistence.migration.ts.tpl +29 -0
- package/templates/be/patterns/outbox/platform/index.ts.tpl +2 -0
- package/templates/be/patterns/outbox/platform/outbox-relay.policy.spec.ts.tpl +96 -0
- package/templates/be/patterns/outbox/platform/outbox-relay.policy.ts.tpl +78 -0
- package/templates/be/patterns/outbox/platform/outbox.log-events.ts.tpl +5 -0
- package/templates/be/patterns/projections/migration.ts.tpl +18 -0
- package/templates/be/patterns/projections/persistence.connection.ts.tpl +8 -0
- package/templates/be/patterns/projections/projection.entity.ts.tpl +9 -0
- package/templates/be/patterns/projections/projection.index.ts.tpl +3 -0
- package/templates/be/patterns/projections/projection.module-definition.ts.tpl +7 -0
- package/templates/be/patterns/projections/projection.module.ts.tpl +18 -0
- package/templates/be/patterns/projections/projection.options.ts.tpl +2 -0
- package/templates/be/patterns/projections/projection.projection.spec.ts.tpl +55 -0
- package/templates/be/patterns/projections/projection.projection.ts.tpl +21 -0
- package/templates/be/patterns/queues/platform/bullmq-queue-transport.client.spec.ts.tpl +142 -0
- package/templates/be/patterns/queues/platform/bullmq-queue-transport.client.ts.tpl +81 -0
- package/templates/be/patterns/queues/platform/persistence.connection.ts.tpl +8 -0
- package/templates/be/patterns/queues/platform/persistence.migration.ts.tpl +25 -0
- package/templates/be/patterns/queues/platform/persistence.queue-outbox.entity.ts.tpl +25 -0
- package/templates/be/patterns/queues/platform/persistence.queue.rows.ts.tpl +9 -0
- package/templates/be/patterns/queues/platform/persistence.queue.sql.ts.tpl +12 -0
- package/templates/be/patterns/queues/platform/queue-outbox.service.spec.ts.tpl +48 -0
- package/templates/be/patterns/queues/platform/queue-outbox.service.ts.tpl +17 -0
- package/templates/be/patterns/queues/platform/queue-relay.service.spec.ts.tpl +128 -0
- package/templates/be/patterns/queues/platform/queue-relay.service.ts.tpl +48 -0
- package/templates/be/patterns/queues/platform/queue-transport.port.ts.tpl +115 -0
- package/templates/be/patterns/queues/platform/queue-worker.service.spec.ts.tpl +91 -0
- package/templates/be/patterns/queues/platform/queue-worker.service.ts.tpl +45 -0
- package/templates/be/patterns/queues/platform/queue.config.ts.tpl +15 -0
- package/templates/be/patterns/queues/platform/queue.contracts.ts.tpl +31 -0
- package/templates/be/patterns/queues/platform/queue.decorators.ts.tpl +45 -0
- package/templates/be/patterns/queues/platform/queue.index.ts.tpl +7 -0
- package/templates/be/patterns/queues/platform/queue.log-events.ts.tpl +5 -0
- package/templates/be/patterns/queues/platform/queue.module-definition.ts.tpl +10 -0
- package/templates/be/patterns/queues/platform/queue.module.ts.tpl +62 -0
- package/templates/be/patterns/queues/platform/queue.options.ts.tpl +22 -0
- package/templates/be/patterns/queues/platform/queue.policy.spec.ts.tpl +19 -0
- package/templates/be/patterns/queues/platform/queue.policy.ts.tpl +11 -0
- package/templates/be/patterns/queues/platform/queue.port.ts.tpl +14 -0
- package/templates/be/patterns/queues/queue.index.ts.tpl +3 -0
- package/templates/be/patterns/queues/queue.module.ts.tpl +6 -0
- package/templates/be/patterns/queues/queue.queue.ts.tpl +23 -0
- package/templates/be/patterns/reactors/application.command.ts.tpl +10 -0
- package/templates/be/patterns/reactors/application.contracts.ts.tpl +12 -0
- package/templates/be/patterns/reactors/application.handler.ts.tpl +22 -0
- package/templates/be/patterns/reactors/consumer.ts.tpl +19 -0
- package/templates/be/patterns/reactors/message.module.ts.tpl +20 -0
- package/templates/be/patterns/reactors/reactor.index.ts.tpl +1 -0
- package/templates/be/patterns/reactors/reactor.module.ts.tpl +6 -0
- package/templates/be/patterns/realtime/channel.graphql.module.ts.tpl +6 -0
- package/templates/be/patterns/realtime/channel.index.ts.tpl +1 -0
- package/templates/be/patterns/realtime/channel.input.ts.tpl +12 -0
- package/templates/be/patterns/realtime/channel.subscription.spec.ts.tpl +51 -0
- package/templates/be/patterns/realtime/channel.subscription.ts.tpl +32 -0
- package/templates/be/patterns/realtime/channel.type.ts.tpl +9 -0
- package/templates/be/patterns/saga/saga.compensate.command.ts.tpl +11 -0
- package/templates/be/patterns/saga/saga.compensate.contracts.ts.tpl +7 -0
- package/templates/be/patterns/saga/saga.compensate.handler.ts.tpl +22 -0
- package/templates/be/patterns/saga/saga.compensation.ts.tpl +21 -0
- package/templates/be/patterns/saga/saga.complete.command.ts.tpl +11 -0
- package/templates/be/patterns/saga/saga.complete.contracts.ts.tpl +7 -0
- package/templates/be/patterns/saga/saga.complete.handler.ts.tpl +22 -0
- package/templates/be/patterns/saga/saga.done.consumer.ts.tpl +21 -0
- package/templates/be/patterns/saga/saga.failed.consumer.ts.tpl +21 -0
- package/templates/be/patterns/saga/saga.index.ts.tpl +1 -0
- package/templates/be/patterns/saga/saga.message.module.ts.tpl +23 -0
- package/templates/be/patterns/saga/saga.module.ts.tpl +20 -0
- package/templates/be/patterns/saga/saga.service.spec.ts.tpl +70 -0
- package/templates/be/patterns/saga/saga.service.ts.tpl +44 -0
- package/templates/be/patterns/saga/saga.state.ts.tpl +14 -0
- package/templates/be/patterns/saga/saga.step.ts.tpl +11 -0
- package/templates/be/patterns/saga/saga.undo.command.ts.tpl +10 -0
- package/templates/be/patterns/saga/saga.undo.contracts.ts.tpl +5 -0
- package/templates/be/patterns/saga/saga.undo.handler.ts.tpl +21 -0
- package/templates/be/patterns/webhooks/webhook.door.spec.ts.tpl +72 -0
- package/templates/be/patterns/webhooks/webhook.door.ts.tpl +36 -0
- package/templates/be/patterns/webhooks/webhook.http.module.ts.tpl +6 -0
- package/templates/be/patterns/webhooks/webhook.index.ts.tpl +1 -0
- package/templates/be/patterns/webhooks/webhook.request.ts.tpl +9 -0
- package/templates/be/skeleton/apps/__app__/src/__app__.options.ts +3 -0
- package/templates/be/skeleton/apps/__app__/src/app.module.ts +15 -2
- package/templates/be/skeleton/apps/__app__/src/main.ts +7 -15
- package/templates/be/skeleton/apps/cli/src/app.module.ts +30 -0
- package/templates/be/skeleton/apps/cli/src/cli.options.ts +22 -0
- package/templates/be/skeleton/apps/cli/src/main.ts +24 -0
- package/templates/be/skeleton/src/features/cli/cli.module.ts +7 -0
- package/templates/be/skeleton/src/features/cli/index.ts +1 -0
- package/templates/be/skeleton/src/features/cli/migrate/migrate.cli.spec.ts +17 -0
- package/templates/be/skeleton/src/features/cli/migrate/migrate.cli.ts +15 -0
- package/templates/be/skeleton/src/features/cli/migrate/migrate.module.ts +7 -0
- package/templates/be/skeleton/src/features/cli/migrate/subs/run.cli.spec.ts +17 -0
- package/templates/be/skeleton/src/features/cli/migrate/subs/run.cli.ts +18 -0
- package/templates/be/skeleton/src/features/cli/seed/seed.cli.spec.ts +17 -0
- package/templates/be/skeleton/src/features/cli/seed/seed.cli.ts +15 -0
- package/templates/be/skeleton/src/features/cli/seed/seed.module.ts +7 -0
- package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.spec.ts +33 -0
- package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.ts +34 -0
- package/templates/be/skeleton/src/modules/domain/identity/admission.policy.spec.ts +13 -0
- package/templates/be/skeleton/src/modules/domain/identity/auth.guard.spec.ts +40 -0
- package/templates/be/skeleton/src/modules/domain/identity/messages/identity.messages.ts +1 -1
- package/templates/be/skeleton/src/modules/domain/note/errors/note.error.ts +16 -0
- package/templates/be/skeleton/src/modules/domain/note/index.ts +3 -0
- package/templates/be/skeleton/src/modules/domain/note/note.contracts.ts +19 -0
- package/templates/be/skeleton/src/modules/domain/note/note.decorators.ts +9 -0
- package/templates/be/skeleton/src/modules/domain/note/note.module-definition.ts +7 -0
- package/templates/be/skeleton/src/modules/domain/note/note.module.ts +19 -0
- package/templates/be/skeleton/src/modules/domain/note/note.options.ts +2 -0
- package/templates/be/skeleton/src/modules/domain/note/note.service.spec.ts +76 -0
- package/templates/be/skeleton/src/modules/domain/note/note.service.ts +37 -0
- package/templates/be/skeleton/src/modules/domain/note/persistence/connection.ts +8 -0
- package/templates/be/skeleton/src/modules/domain/note/persistence/entities/note.entity.ts +17 -0
- package/templates/be/skeleton/src/modules/domain/note/persistence/migrations/1790000000000-init-note.ts +22 -0
- package/templates/be/skeleton/src/modules/domain/note/persistence/note.rows.ts +17 -0
- package/templates/be/skeleton/src/modules/domain/note/persistence/note.sql.ts +4 -0
- package/templates/be/skeleton/src/modules/platform/config/env-source.config.ts +20 -0
- package/templates/be/skeleton/src/modules/platform/config/index.ts +1 -1
- package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.contracts.ts +18 -0
- package/templates/be/skeleton/src/modules/platform/database/connection-source.client.spec.ts +41 -0
- package/templates/be/skeleton/src/modules/platform/database/connection-source.client.ts +17 -0
- package/templates/be/skeleton/src/modules/platform/database/database.module-definition.ts +13 -0
- package/templates/be/skeleton/src/modules/platform/database/database.module.ts +77 -0
- package/templates/be/skeleton/src/modules/platform/database/database.options.ts +30 -0
- package/templates/be/skeleton/src/modules/platform/database/database.port.ts +65 -0
- package/templates/be/skeleton/src/modules/platform/database/database.sql.ts +47 -0
- package/templates/be/skeleton/src/modules/platform/database/errors/database.error.ts +16 -0
- package/templates/be/skeleton/src/modules/platform/database/index.ts +9 -0
- package/templates/be/skeleton/src/modules/platform/database/migrate-connections.client.ts +30 -0
- package/templates/be/skeleton/src/modules/platform/database/migration-runner.service.spec.ts +84 -0
- package/templates/be/skeleton/src/modules/platform/database/migration-runner.service.ts +23 -0
- package/templates/be/skeleton/src/modules/platform/database/primary.config.ts +9 -0
- package/templates/be/skeleton/src/modules/platform/database/primary.connection.ts +2 -0
- package/templates/be/skeleton/src/modules/platform/database/primary.decorators.ts +10 -0
- package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.spec.ts +108 -0
- package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.ts +75 -0
- package/templates/be/skeleton/src/modules/platform/database/seed-runner.service.spec.ts +88 -0
- package/templates/be/skeleton/src/modules/platform/database/seed-runner.service.ts +29 -0
- package/templates/be/skeleton/src/modules/platform/errors/errors.filter.spec.ts +48 -0
- package/templates/be/skeleton/src/modules/platform/errors/messages/errors.messages.ts +1 -1
- package/templates/be/skeleton/src/modules/platform/http-security/errors/http-security.error.ts +12 -0
- package/templates/be/skeleton/src/modules/platform/http-security/execution-request.mapper.spec.ts +16 -0
- package/templates/be/skeleton/src/modules/platform/http-security/http-security.config.ts +8 -1
- package/templates/be/skeleton/src/modules/platform/http-security/http-security.decorators.ts +8 -0
- package/templates/be/skeleton/src/modules/platform/http-security/http-security.module.ts +14 -1
- package/templates/be/skeleton/src/modules/platform/http-security/http-security.options.ts +12 -0
- package/templates/be/skeleton/src/modules/platform/http-security/messages/http-security.messages.ts +10 -2
- package/templates/be/skeleton/src/modules/platform/http-security/origin.guard.spec.ts +63 -0
- package/templates/be/skeleton/src/modules/platform/http-security/rate-limit.guard.spec.ts +108 -0
- package/templates/be/skeleton/src/modules/platform/http-security/request-validation.service.spec.ts +39 -0
- package/templates/be/skeleton/src/modules/platform/http-security/request-validation.service.ts +25 -0
- package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.spec.ts +172 -0
- package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.ts +66 -0
- package/templates/be/skeleton/src/modules/platform/logging/logging.log-events.ts +3 -1
- package/templates/be/skeleton/src/modules/platform/primitives/outcome.mapper.spec.ts +52 -0
- package/templates/be/skeleton-lite/apps/api/Dockerfile +37 -0
- package/templates/be/skeleton-lite/apps/api/src/api.options.ts +16 -0
- package/templates/be/skeleton-lite/apps/api/src/app.module.ts +81 -0
- package/templates/be/skeleton-lite/apps/api/src/main.ts +34 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.ts +14 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.ts +50 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.contracts.ts +26 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.decorators.ts +19 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.module.ts +26 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.options.ts +7 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/index.ts +6 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/errors/supabase.error.ts +19 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/index.ts +10 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.client.ts +24 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.config.ts +8 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.decorators.ts +17 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.jwks.ts +32 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.options.ts +24 -0
- package/templates/be/skeleton-lite/src/modules/platform/cqrs/index.ts +4 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/database.module.ts +54 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/database.options.ts +23 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/database.port.ts +10 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/database.sql.ts +49 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +4 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/migration-runner.service.ts +21 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/primary.config.ts +11 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/seed-runner.service.ts +28 -0
- package/templates/be/skeleton-lite/src/modules/platform/http-security/http-security.module.ts +25 -0
- package/templates/be/skeleton-lite/src/modules/platform/http-security/index.ts +9 -0
- package/templates/be/skeleton-lite/src/modules/platform/i18n/index.ts +4 -0
- package/templates/be/skeleton-lite/src/modules/platform/logging/index.ts +5 -0
- package/templates/be/table/error.ts.tpl +16 -0
- package/templates/be/table/index.ts.tpl +2 -0
- package/templates/be/table/migration.sql.tpl +51 -0
- package/templates/be/table/module-definition.ts.tpl +7 -0
- package/templates/be/table/module.ts.tpl +14 -0
- package/templates/be/table/options.ts.tpl +2 -0
- package/templates/be/table/rows.ts.tpl +4 -0
- package/templates/be/table/service.ts.tpl +23 -0
- package/templates/be/table/sql.ts.tpl +4 -0
- package/templates/be/tool-config/jest.config.js +3 -1
- package/templates/be/upgrade-full/apps/cli/src/app.module.ts +14 -0
- package/templates/be/upgrade-full/apps/cli/src/main.ts +26 -0
- package/templates/be/upgrade-full/src/features/cli/cli.module.ts +6 -0
- package/templates/be/upgrade-full/src/features/cli/migrate/subs/run.cli.ts +23 -0
- package/templates/common/gitignore.base +1 -2
- package/templates/fe/app/package.json.tpl +1 -0
- package/templates/fe/app/tsconfig.json +12 -0
- package/templates/fe/common/app-layout.tsx.partial +8 -0
- package/templates/fe/common/site-shell.tsx.partial +9 -0
- package/templates/fe/image/next/Dockerfile +42 -0
- package/templates/fe/skeleton/apps/app/next.config.ts +23 -0
- package/templates/fe/skeleton/apps/app/postcss.config.mjs +7 -0
- package/templates/fe/skeleton/apps/{__app__ → app}/src/app/[locale]/error.tsx +2 -2
- package/templates/fe/skeleton/apps/app/src/app/[locale]/layout.tsx +22 -0
- package/templates/fe/skeleton/apps/{__app__ → app}/src/app/[locale]/loading.tsx +2 -2
- package/templates/fe/skeleton/apps/{__app__ → app}/src/app/[locale]/not-found.tsx +2 -2
- package/templates/fe/skeleton/apps/app/src/app/[locale]/page.tsx +9 -0
- package/templates/fe/skeleton/apps/{__app__ → app}/src/app/global-error.tsx +2 -2
- package/templates/fe/skeleton/apps/app/src/app/globals.css +10 -0
- package/templates/fe/skeleton/apps/app/src/features/layouts/AppLayout/index.tsx +18 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppErrorPage/component.tsx +19 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppErrorPage/index.tsx +11 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppGlobalErrorPage/index.tsx +16 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/component.tsx +10 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/index.tsx +15 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppLoadingPage/index.tsx +8 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppNotFoundPage/index.tsx +9 -0
- package/templates/fe/skeleton/apps/app/src/modules/i18n/index.ts +4 -0
- package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/vi.json +28 -0
- package/templates/fe/skeleton/apps/app/src/modules/i18n/request.ts +4 -0
- package/templates/fe/skeleton/apps/app/src/modules/routes/index.ts +4 -0
- package/templates/fe/skeleton/apps/app/src/proxy.ts +1 -0
- package/templates/fe/skeleton/apps/{__app__ → landing}/next.config.ts +4 -2
- package/templates/fe/skeleton/apps/landing/postcss.config.mjs +7 -0
- package/templates/fe/skeleton/apps/landing/src/app/[locale]/error.tsx +10 -0
- package/templates/fe/skeleton/apps/landing/src/app/[locale]/layout.tsx +22 -0
- package/templates/fe/skeleton/apps/landing/src/app/[locale]/loading.tsx +6 -0
- package/templates/fe/skeleton/apps/landing/src/app/[locale]/not-found.tsx +6 -0
- package/templates/fe/skeleton/apps/landing/src/app/[locale]/page.tsx +9 -0
- package/templates/fe/skeleton/apps/landing/src/app/global-error.tsx +10 -0
- package/templates/fe/skeleton/apps/landing/src/app/globals.css +10 -0
- package/templates/fe/skeleton/apps/landing/src/features/layouts/LandingLayout/index.tsx +24 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingErrorPage/component.tsx +18 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingErrorPage/index.tsx +11 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingGlobalErrorPage/index.tsx +16 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingLoadingPage/index.tsx +8 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingNotFoundPage/index.tsx +9 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingPage/component.tsx +24 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingPage/index.tsx +16 -0
- package/templates/fe/skeleton/apps/landing/src/modules/config/index.ts +12 -0
- package/templates/fe/skeleton/apps/landing/src/modules/i18n/index.ts +7 -0
- package/templates/fe/skeleton/apps/landing/src/modules/i18n/messages/vi.json +31 -0
- package/templates/fe/skeleton/apps/landing/src/modules/i18n/request.ts +4 -0
- package/templates/fe/skeleton/apps/landing/src/modules/routes/index.ts +4 -0
- package/templates/fe/skeleton/apps/landing/src/proxy.ts +1 -0
- package/templates/fe/skeleton/packages/__project__-i18n/src/index.ts +49 -0
- package/templates/fe/skeleton/packages/__project__-i18n/src/proxy.ts +24 -0
- package/templates/fe/skeleton/packages/__project__-i18n/src/routing.ts +20 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/branches/Providers/index.tsx +23 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/ErrorNotice/index.tsx +14 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/GlobalErrorNotice/index.tsx +25 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/LoadingNotice/index.tsx +9 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/LocaleShell/index.tsx +21 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/NotFoundNotice/index.tsx +19 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/SiteShell/classNames.ts +4 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/SiteShell/index.tsx +19 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/index.ts +6 -0
- package/templates/fe/skeleton-lite/apps/web/next.config.ts +22 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/error.tsx +10 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/layout.tsx +37 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/loading.tsx +6 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/not-found.tsx +6 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/page.tsx +9 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/providers.tsx +26 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/auth/callback/route.ts +24 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/global-error.tsx +10 -0
- package/templates/fe/{skeleton/apps/__app__ → skeleton-lite/apps/web}/src/app/globals.css +1 -1
- package/templates/fe/skeleton-lite/apps/web/src/app/health/live/route.ts +5 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignInForm/component.tsx +29 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignInForm/index.tsx +41 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignOutButton/component.tsx +17 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignOutButton/index.tsx +38 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/composites/ErrorNotice/index.tsx +13 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/composites/GlobalErrorNotice/index.tsx +24 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/composites/LoadingNotice/index.tsx +7 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/composites/NotFoundNotice/index.tsx +18 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/composites/SiteShell/classNames.ts +4 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/composites/SiteShell/index.tsx +13 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/layouts/AppLayout/index.tsx +31 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppErrorPage/component.tsx +12 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppErrorPage/index.tsx +10 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppGlobalErrorPage/index.tsx +15 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/component.tsx +14 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/index.tsx +30 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppLoadingPage/index.tsx +8 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppNotFoundPage/index.tsx +9 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/brand/brand.css +20 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/brand/index.ts +2 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/config/index.ts +20 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/auth/read-session.ts +25 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/auth/write-sign-in.ts +25 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/auth/write-sign-out.ts +17 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/browser.ts +14 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/index.ts +3 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/outcome.ts +59 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/principal.ts +29 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/server.ts +70 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/validation/validation.mapper.ts +50 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/index.ts +8 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/vi.json +48 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/request.ts +16 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/routing.ts +14 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/routes/index.ts +7 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/routes/safe-next-path.ts +26 -0
- package/templates/fe/skeleton-lite/apps/web/src/proxy.ts +43 -0
- package/templates/fe/table/read.ts.tpl +16 -0
- package/templates/fe/table/write.ts.tpl +16 -0
- package/upgrade/check.mjs +137 -0
- package/upgrade/index.mjs +524 -0
- package/bin/hfs.mjs +0 -233
- package/runtime/scripts/api/fs/rmdir-link.mjs +0 -12
- package/runtime/scripts/lib/test-secrets.mjs +0 -116
- package/templates/fe/skeleton/apps/__app__/src/app/[locale]/layout.tsx +0 -20
- package/templates/fe/skeleton/apps/__app__/src/app/[locale]/page.tsx +0 -9
- package/templates/fe/skeleton/apps/__app__/src/components/composites/FailureScreen/index.tsx +0 -28
- package/templates/fe/skeleton/apps/__app__/src/features/layouts/LocaleShell/index.tsx +0 -35
- package/templates/fe/skeleton/apps/__app__/src/features/pages/ErrorPage/component.tsx +0 -19
- package/templates/fe/skeleton/apps/__app__/src/features/pages/ErrorPage/index.tsx +0 -11
- package/templates/fe/skeleton/apps/__app__/src/features/pages/GlobalErrorPage/component.tsx +0 -24
- package/templates/fe/skeleton/apps/__app__/src/features/pages/GlobalErrorPage/index.tsx +0 -14
- package/templates/fe/skeleton/apps/__app__/src/features/pages/HomePage/component.tsx +0 -21
- package/templates/fe/skeleton/apps/__app__/src/features/pages/HomePage/index.tsx +0 -15
- package/templates/fe/skeleton/apps/__app__/src/features/pages/LoadingPage/component.tsx +0 -23
- package/templates/fe/skeleton/apps/__app__/src/features/pages/LoadingPage/index.tsx +0 -8
- package/templates/fe/skeleton/apps/__app__/src/features/pages/NotFoundPage/component.tsx +0 -28
- package/templates/fe/skeleton/apps/__app__/src/features/pages/NotFoundPage/index.tsx +0 -8
- package/templates/fe/skeleton/apps/__app__/src/modules/i18n/config.ts +0 -8
- package/templates/fe/skeleton/apps/__app__/src/modules/i18n/index.ts +0 -2
- package/templates/fe/skeleton/apps/__app__/src/modules/i18n/messages/vi.json +0 -25
- package/templates/fe/skeleton/apps/__app__/src/modules/i18n/request.ts +0 -19
- package/templates/fe/skeleton/apps/__app__/src/modules/i18n/routing.ts +0 -9
- package/templates/fe/skeleton/apps/__app__/src/modules/routes/index.ts +0 -4
- package/templates/fe/skeleton/apps/__app__/src/proxy.ts +0 -10
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/application/check-liveness.contracts.ts +0 -0
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/application/check-liveness.handler.ts +0 -0
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/application/check-liveness.query.ts +0 -0
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/index.ts +0 -0
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/system-health.module.ts +0 -0
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/transport/http/live.controller.ts +0 -0
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/transport/http/system-health-http.module.ts +0 -0
- /package/templates/fe/skeleton/apps/{__app__ → app}/src/app/health/live/route.ts +0 -0
- /package/templates/fe/skeleton/apps/{__app__ → app}/src/modules/config/index.ts +0 -0
- /package/templates/fe/{skeleton/apps/__app__ → skeleton-lite/apps/web}/postcss.config.mjs +0 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { QueueHandler, QueueSchedulerDefinition } from "./queue.contracts"
|
|
2
|
+
|
|
3
|
+
/** BullMQ as the queue capability sees it: the one port the BullMQ client implements. */
|
|
4
|
+
export interface QueueTransport {
|
|
5
|
+
/** Adds the job to its queue with `jobId`; adding an id BullMQ already holds changes nothing, so a repeated relay pass is harmless. */
|
|
6
|
+
add(queue: string, jobId: string, payload: object): Promise<void>
|
|
7
|
+
/** Creates or updates a job scheduler by its id. */
|
|
8
|
+
upsertScheduler(scheduler: QueueSchedulerDefinition): Promise<void>
|
|
9
|
+
/** Starts a worker of the queue the handler names that runs it for every job, `concurrency` at a time. */
|
|
10
|
+
work(handler: QueueHandler, concurrency: number): Promise<void>
|
|
11
|
+
/** Resolves after `ms` milliseconds: the only clock of the relay loop. */
|
|
12
|
+
wait(ms: number): Promise<void>
|
|
13
|
+
/** Closes every queue and worker. */
|
|
14
|
+
close(): Promise<void>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** The Redis a driver object connects to. */
|
|
18
|
+
export interface BullmqRedis {
|
|
19
|
+
/** The host. */
|
|
20
|
+
readonly host: string
|
|
21
|
+
/** The port. */
|
|
22
|
+
readonly port: number
|
|
23
|
+
/** BullMQ answers to commands only through a client that does not retry on its own. */
|
|
24
|
+
readonly maxRetriesPerRequest: number | null
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** The Redis options every queue and worker of the app shares. */
|
|
28
|
+
export interface BullmqConnection {
|
|
29
|
+
/** The key prefix of the app. */
|
|
30
|
+
readonly prefix: string
|
|
31
|
+
/** The Redis the driver connects to. */
|
|
32
|
+
readonly connection: BullmqRedis
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The options a worker is built with: the shared connection plus its concurrency. */
|
|
36
|
+
export interface BullmqWorkerOptions extends BullmqConnection {
|
|
37
|
+
/** How many jobs the worker runs at a time. */
|
|
38
|
+
readonly concurrency: number
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** The wait between two tries of a job. */
|
|
42
|
+
export interface BullmqBackoff {
|
|
43
|
+
/** The backoff shape. */
|
|
44
|
+
readonly type: string
|
|
45
|
+
/** The first wait, in milliseconds. */
|
|
46
|
+
readonly delay: number
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** How long a finished job is kept. */
|
|
50
|
+
export interface BullmqRetention {
|
|
51
|
+
/** The seconds a finished job is kept. */
|
|
52
|
+
readonly age: number
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The options the transport fixes on every job it adds. */
|
|
56
|
+
export interface BullmqJobOptions {
|
|
57
|
+
/** The id BullMQ dedupes on: the outbox row id. */
|
|
58
|
+
readonly jobId: string
|
|
59
|
+
/** How many times BullMQ tries the job. */
|
|
60
|
+
readonly attempts: number
|
|
61
|
+
/** The wait between two tries. */
|
|
62
|
+
readonly backoff: BullmqBackoff
|
|
63
|
+
/** How long a finished job is kept. */
|
|
64
|
+
readonly removeOnComplete: BullmqRetention
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** The options a scheduler fixes on the jobs it fires. */
|
|
68
|
+
export interface BullmqSchedulerJobOptions {
|
|
69
|
+
/** How many times BullMQ tries the tick. */
|
|
70
|
+
readonly attempts: number
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** The job a scheduler fires. */
|
|
74
|
+
export interface BullmqJobTemplate {
|
|
75
|
+
/** The job name, which is the queue name. */
|
|
76
|
+
readonly name: string
|
|
77
|
+
/** The payload of every tick. */
|
|
78
|
+
readonly data: object
|
|
79
|
+
/** The options of every tick. */
|
|
80
|
+
readonly opts: BullmqSchedulerJobOptions
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** A queue as the transport uses it. */
|
|
84
|
+
export interface BullmqQueue {
|
|
85
|
+
/** Adds the job; an id BullMQ already holds makes the add a no-op. */
|
|
86
|
+
add(name: string, payload: object, options: BullmqJobOptions): Promise<unknown>
|
|
87
|
+
/** Creates or updates the scheduler by its id. */
|
|
88
|
+
upsertJobScheduler(id: string, repeat: { readonly every: number }, template: BullmqJobTemplate): Promise<unknown>
|
|
89
|
+
/** Closes the queue. */
|
|
90
|
+
close(): Promise<void>
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** A job as a worker receives it: the fields the transport translates into a QueueDelivery. */
|
|
94
|
+
export interface BullmqJob {
|
|
95
|
+
/** The job id; a tick the scheduler fires can have none. */
|
|
96
|
+
readonly id?: string
|
|
97
|
+
/** The payload the producer wrote. */
|
|
98
|
+
readonly data: object
|
|
99
|
+
/** How many deliveries were started before this one. */
|
|
100
|
+
readonly attemptsMade: number
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** A worker as the transport uses it. */
|
|
104
|
+
export interface BullmqWorker {
|
|
105
|
+
/** Stops the worker; `force` drops the jobs it is still running. */
|
|
106
|
+
close(force?: boolean): Promise<void>
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Builds the BullMQ objects; the module provides it so a spec can double it through the injection token. */
|
|
110
|
+
export interface QueueFactory {
|
|
111
|
+
/** The queue of the name over the shared connection. */
|
|
112
|
+
queue(name: string, options: BullmqConnection): BullmqQueue
|
|
113
|
+
/** A worker that runs the processor for every job of the queue. */
|
|
114
|
+
worker(name: string, processor: (job: BullmqJob) => Promise<void>, options: BullmqWorkerOptions): BullmqWorker
|
|
115
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Test } from "@nestjs/testing"
|
|
2
|
+
import { mock } from "@starci/jest-preset"
|
|
3
|
+
import { LOGGER } from "@modules/platform/logging"
|
|
4
|
+
import type { Logger } from "@modules/platform/logging"
|
|
5
|
+
import type { QueueHandler } from "./queue.contracts"
|
|
6
|
+
import { QUEUE_OPTIONS, QUEUE_TRANSPORT } from "./queue.decorators"
|
|
7
|
+
import { QueueLogEvent } from "./queue.log-events"
|
|
8
|
+
import type { QueueOptions } from "./queue.options"
|
|
9
|
+
import type { QueueTransport } from "./queue-transport.port"
|
|
10
|
+
import { QueueWorkerService } from "./queue-worker.service"
|
|
11
|
+
|
|
12
|
+
const options: QueueOptions = {
|
|
13
|
+
redisHost: "localhost",
|
|
14
|
+
redisPort: 6379,
|
|
15
|
+
prefix: "test",
|
|
16
|
+
relayIntervalMs: 100,
|
|
17
|
+
relayBatch: 2,
|
|
18
|
+
concurrency: 3,
|
|
19
|
+
connections: [],
|
|
20
|
+
schedulers: [{ queue: "sweep", id: "sweep-every-minute", everyMs: 60000 }],
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const handlerOf = (queue: string): QueueHandler => ({ queue, handle: () => Promise.resolve() })
|
|
24
|
+
|
|
25
|
+
const build = async () => {
|
|
26
|
+
const transport = mock<QueueTransport>()
|
|
27
|
+
transport.upsertScheduler.mockResolvedValue(undefined)
|
|
28
|
+
const logger = mock<Logger>()
|
|
29
|
+
const moduleRef = await Test.createTestingModule({
|
|
30
|
+
providers: [
|
|
31
|
+
QueueWorkerService,
|
|
32
|
+
{ provide: QUEUE_OPTIONS, useValue: options },
|
|
33
|
+
{ provide: QUEUE_TRANSPORT, useValue: transport },
|
|
34
|
+
{ provide: LOGGER, useValue: logger },
|
|
35
|
+
],
|
|
36
|
+
}).compile()
|
|
37
|
+
return { workers: moduleRef.get(QueueWorkerService), transport, logger }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
describe("QueueWorkerService", () => {
|
|
41
|
+
describe("onApplicationBootstrap", () => {
|
|
42
|
+
it("starts one worker per registered queue with the configured concurrency and registers the schedulers", async () => {
|
|
43
|
+
const { workers, transport } = await build()
|
|
44
|
+
const mailHandler = handlerOf("mail")
|
|
45
|
+
const sweepHandler = handlerOf("sweep")
|
|
46
|
+
workers.add(mailHandler)
|
|
47
|
+
workers.add(sweepHandler)
|
|
48
|
+
|
|
49
|
+
await workers.onApplicationBootstrap()
|
|
50
|
+
|
|
51
|
+
expect(transport.work).toHaveBeenCalledWith(mailHandler, 3)
|
|
52
|
+
expect(transport.work).toHaveBeenCalledWith(sweepHandler, 3)
|
|
53
|
+
expect(transport.upsertScheduler).toHaveBeenCalledWith(options.schedulers[0])
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it("keeps the last handler registered for a queue", async () => {
|
|
57
|
+
const { workers, transport } = await build()
|
|
58
|
+
const first = handlerOf("mail")
|
|
59
|
+
const second = handlerOf("mail")
|
|
60
|
+
workers.add(first)
|
|
61
|
+
workers.add(second)
|
|
62
|
+
|
|
63
|
+
await workers.onApplicationBootstrap()
|
|
64
|
+
|
|
65
|
+
expect(transport.work).toHaveBeenCalledTimes(1)
|
|
66
|
+
expect(transport.work).toHaveBeenCalledWith(second, 3)
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it("logs a scheduler that cannot be registered and still starts the app", async () => {
|
|
70
|
+
const { workers, transport, logger } = await build()
|
|
71
|
+
const failure = new Error("redis down")
|
|
72
|
+
transport.upsertScheduler.mockRejectedValue(failure)
|
|
73
|
+
|
|
74
|
+
await expect(workers.onApplicationBootstrap()).resolves.toBeUndefined()
|
|
75
|
+
|
|
76
|
+
expect(logger.error).toHaveBeenCalledWith(QueueLogEvent.SchedulerFailed, failure, {
|
|
77
|
+
scheduler: "sweep-every-minute",
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
describe("onApplicationShutdown", () => {
|
|
83
|
+
it("closes the workers and the queues", async () => {
|
|
84
|
+
const { workers, transport } = await build()
|
|
85
|
+
|
|
86
|
+
await workers.onApplicationShutdown()
|
|
87
|
+
|
|
88
|
+
expect(transport.close).toHaveBeenCalledTimes(1)
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
})
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Injectable } from "@nestjs/common"
|
|
2
|
+
import type { OnApplicationBootstrap, OnApplicationShutdown } from "@nestjs/common"
|
|
3
|
+
import { InjectLogger } from "@modules/platform/logging"
|
|
4
|
+
import type { Logger } from "@modules/platform/logging"
|
|
5
|
+
import type { QueueHandler } from "./queue.contracts"
|
|
6
|
+
import { InjectQueueOptions, InjectQueueTransport } from "./queue.decorators"
|
|
7
|
+
import { QueueLogEvent } from "./queue.log-events"
|
|
8
|
+
import type { QueueOptions } from "./queue.options"
|
|
9
|
+
import type { QueueWorkerRegistry } from "./queue.port"
|
|
10
|
+
import type { QueueTransport } from "./queue-transport.port"
|
|
11
|
+
|
|
12
|
+
@Injectable()
|
|
13
|
+
/**
|
|
14
|
+
* The consuming side of the queues: the registry the processors fill, and the workers and schedulers started when the app has
|
|
15
|
+
* registered every handler. A scheduler that cannot be registered is logged and does not stop the app: the next boot upserts it again.
|
|
16
|
+
*/
|
|
17
|
+
export class QueueWorkerService implements QueueWorkerRegistry, OnApplicationBootstrap, OnApplicationShutdown {
|
|
18
|
+
private readonly handlers = new Map<string, QueueHandler>()
|
|
19
|
+
|
|
20
|
+
constructor(
|
|
21
|
+
@InjectQueueOptions() private readonly options: QueueOptions,
|
|
22
|
+
@InjectQueueTransport() private readonly transport: QueueTransport,
|
|
23
|
+
@InjectLogger() private readonly logger: Logger,
|
|
24
|
+
) {}
|
|
25
|
+
|
|
26
|
+
/** Registers the handler under the queue it names; a second handler for the same queue replaces the first. */
|
|
27
|
+
add(handler: QueueHandler): void {
|
|
28
|
+
this.handlers.set(handler.queue, handler)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Starts one worker per registered queue, then registers the schedulers of the options. */
|
|
32
|
+
async onApplicationBootstrap(): Promise<void> {
|
|
33
|
+
for (const handler of this.handlers.values()) await this.transport.work(handler, this.options.concurrency)
|
|
34
|
+
for (const scheduler of this.options.schedulers) {
|
|
35
|
+
await this.transport.upsertScheduler(scheduler).catch((cause: unknown) => {
|
|
36
|
+
this.logger.error(QueueLogEvent.SchedulerFailed, cause, { scheduler: scheduler.id })
|
|
37
|
+
})
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Closes the workers and the queues. */
|
|
42
|
+
async onApplicationShutdown(): Promise<void> {
|
|
43
|
+
await this.transport.close()
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { EnvSource } from "@modules/platform/config"
|
|
2
|
+
import type { QueueOptions } from "./queue.options"
|
|
3
|
+
|
|
4
|
+
/** What the app's `main.ts` reads for the queues; the connections and the schedulers are the app root's choice. */
|
|
5
|
+
export type QueueConfig = Omit<QueueOptions, "connections" | "schedulers">
|
|
6
|
+
|
|
7
|
+
/** Reads the queue options: the Redis address is required, the rest are tunables with literal defaults. */
|
|
8
|
+
export const parseQueueConfig = (env: EnvSource): QueueConfig => ({
|
|
9
|
+
redisHost: env.string("QUEUE_REDIS_HOST"),
|
|
10
|
+
redisPort: env.int("QUEUE_REDIS_PORT", 6379),
|
|
11
|
+
prefix: env.optional("QUEUE_PREFIX") ?? "queue",
|
|
12
|
+
relayIntervalMs: env.duration("QUEUE_RELAY_INTERVAL", 200),
|
|
13
|
+
relayBatch: env.int("QUEUE_RELAY_BATCH", 50),
|
|
14
|
+
concurrency: env.int("QUEUE_CONCURRENCY", 5),
|
|
15
|
+
})
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** A recurring task: BullMQ upserts it by `id`, so every replica of an app may register it and the deployment still fires it once per interval. */
|
|
2
|
+
export interface QueueSchedulerDefinition {
|
|
3
|
+
/** The queue the ticks go to; its processor handles every tick like any other job. */
|
|
4
|
+
readonly queue: string
|
|
5
|
+
/** The stable id of the scheduler. */
|
|
6
|
+
readonly id: string
|
|
7
|
+
/** The interval between two ticks, in milliseconds. */
|
|
8
|
+
readonly everyMs: number
|
|
9
|
+
/** The payload of every tick. */
|
|
10
|
+
readonly payload?: object
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** One job as a handler receives it. */
|
|
14
|
+
export interface QueueDelivery {
|
|
15
|
+
/** The BullMQ job id: the outbox row id of an enqueued job, the tick id of a scheduled one. */
|
|
16
|
+
readonly id: string
|
|
17
|
+
/** The queue. */
|
|
18
|
+
readonly queue: string
|
|
19
|
+
/** The payload the producer wrote. */
|
|
20
|
+
readonly payload: object
|
|
21
|
+
/** How many deliveries were started, this one included. */
|
|
22
|
+
readonly attempt: number
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** The handler of one queue: it receives every delivery of the queue; a return completes the BullMQ job and a throw lets BullMQ retry it. */
|
|
26
|
+
export interface QueueHandler {
|
|
27
|
+
/** The queue this handler consumes. */
|
|
28
|
+
readonly queue: string
|
|
29
|
+
/** Handles one delivery. */
|
|
30
|
+
handle(delivery: QueueDelivery): Promise<void>
|
|
31
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { EntityManager } from "typeorm"
|
|
2
|
+
import { injector } from "@modules/platform/composition"
|
|
3
|
+
import type { TypedParameterDecorator } from "@modules/platform/composition"
|
|
4
|
+
import type { QueueOptions } from "./queue.options"
|
|
5
|
+
import type { QueueOutbox, QueueWorkerRegistry } from "./queue.port"
|
|
6
|
+
import type { QueueFactory, QueueTransport } from "./queue-transport.port"
|
|
7
|
+
|
|
8
|
+
/** Token of the options of the queues, exported so a spec can provide it. */
|
|
9
|
+
export const QUEUE_OPTIONS: unique symbol = Symbol("platform.queue.options")
|
|
10
|
+
|
|
11
|
+
/** Token of the QueueOutbox port. */
|
|
12
|
+
export const QUEUE_OUTBOX: unique symbol = Symbol("platform.queue.outbox")
|
|
13
|
+
|
|
14
|
+
/** Token of the registry a processor registers its queue handler with. */
|
|
15
|
+
export const QUEUE_WORKER_REGISTRY: unique symbol = Symbol("platform.queue.worker-registry")
|
|
16
|
+
|
|
17
|
+
/** Token of the BullMQ port; it is also the health probe token of the queues. */
|
|
18
|
+
export const QUEUE_TRANSPORT: unique symbol = Symbol("platform.queue.transport")
|
|
19
|
+
|
|
20
|
+
/** Token of the entity managers of the connections whose outbox the relay reads, in the order the options name them. */
|
|
21
|
+
export const QUEUE_RELAY_MANAGERS: unique symbol = Symbol("platform.queue.relay-managers")
|
|
22
|
+
|
|
23
|
+
/** Token of the factory that builds the BullMQ objects, exported so a spec can provide it. */
|
|
24
|
+
export const QUEUE_FACTORY: unique symbol = Symbol("platform.queue.factory")
|
|
25
|
+
|
|
26
|
+
/** Injects the options of the queues. Parameter type: QueueOptions. */
|
|
27
|
+
export const InjectQueueOptions = (): TypedParameterDecorator<QueueOptions> => injector<QueueOptions>(QUEUE_OPTIONS)
|
|
28
|
+
|
|
29
|
+
/** Injects the QueueOutbox port. Parameter type: QueueOutbox. */
|
|
30
|
+
export const InjectQueueOutbox = (): TypedParameterDecorator<QueueOutbox> => injector<QueueOutbox>(QUEUE_OUTBOX)
|
|
31
|
+
|
|
32
|
+
/** Injects the worker registry. Parameter type: QueueWorkerRegistry. */
|
|
33
|
+
export const InjectQueueWorkerRegistry = (): TypedParameterDecorator<QueueWorkerRegistry> =>
|
|
34
|
+
injector<QueueWorkerRegistry>(QUEUE_WORKER_REGISTRY)
|
|
35
|
+
|
|
36
|
+
/** Injects the BullMQ port. Parameter type: QueueTransport. */
|
|
37
|
+
export const InjectQueueTransport = (): TypedParameterDecorator<QueueTransport> =>
|
|
38
|
+
injector<QueueTransport>(QUEUE_TRANSPORT)
|
|
39
|
+
|
|
40
|
+
/** Injects the entity managers the relay reads the outbox of. Parameter type: ReadonlyArray<EntityManager>. */
|
|
41
|
+
export const InjectQueueRelayManagers = (): TypedParameterDecorator<ReadonlyArray<EntityManager>> =>
|
|
42
|
+
injector<ReadonlyArray<EntityManager>>(QUEUE_RELAY_MANAGERS)
|
|
43
|
+
|
|
44
|
+
/** Injects the factory that builds the BullMQ objects. Parameter type: QueueFactory. */
|
|
45
|
+
export const InjectQueueFactory = (): TypedParameterDecorator<QueueFactory> => injector<QueueFactory>(QUEUE_FACTORY)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { parseQueueConfig } from "./queue.config"
|
|
2
|
+
export type { QueueConfig } from "./queue.config"
|
|
3
|
+
export type { QueueDelivery, QueueSchedulerDefinition } from "./queue.contracts"
|
|
4
|
+
export { InjectQueueOutbox, InjectQueueWorkerRegistry, QUEUE_WORKER_REGISTRY } from "./queue.decorators"
|
|
5
|
+
export { QueueModule } from "./queue.module"
|
|
6
|
+
export type { QueueOutbox, QueueWorkerRegistry } from "./queue.port"
|
|
7
|
+
export { queueEntities, queueMigrations } from "./persistence/connection"
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ConfigurableModuleBuilder } from "@nestjs/common"
|
|
2
|
+
import { QUEUE_OPTIONS } from "./queue.decorators"
|
|
3
|
+
import type { QueueOptions } from "./queue.options"
|
|
4
|
+
|
|
5
|
+
/** The configurable-module base of the queues; `isGlobal` is decided by the app root. */
|
|
6
|
+
export const { ConfigurableModuleClass, OPTIONS_TYPE } = new ConfigurableModuleBuilder<QueueOptions>({
|
|
7
|
+
optionsInjectionToken: QUEUE_OPTIONS,
|
|
8
|
+
})
|
|
9
|
+
.setExtras({ isGlobal: false }, (definition, extras) => ({ ...definition, global: extras.isGlobal }))
|
|
10
|
+
.build()
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Module } from "@nestjs/common"
|
|
2
|
+
import type { DynamicModule } from "@nestjs/common"
|
|
3
|
+
import { Queue, Worker } from "bullmq"
|
|
4
|
+
import type { EntityManager } from "typeorm"
|
|
5
|
+
import {
|
|
6
|
+
QUEUE_FACTORY,
|
|
7
|
+
QUEUE_OUTBOX,
|
|
8
|
+
QUEUE_RELAY_MANAGERS,
|
|
9
|
+
QUEUE_TRANSPORT,
|
|
10
|
+
QUEUE_WORKER_REGISTRY,
|
|
11
|
+
} from "./queue.decorators"
|
|
12
|
+
import { ConfigurableModuleClass, OPTIONS_TYPE } from "./queue.module-definition"
|
|
13
|
+
import { BullmqQueueTransportClient } from "./bullmq-queue-transport.client"
|
|
14
|
+
import type {
|
|
15
|
+
BullmqConnection,
|
|
16
|
+
BullmqJob,
|
|
17
|
+
BullmqQueue,
|
|
18
|
+
BullmqWorker,
|
|
19
|
+
BullmqWorkerOptions,
|
|
20
|
+
} from "./queue-transport.port"
|
|
21
|
+
import { QueueOutboxService } from "./queue-outbox.service"
|
|
22
|
+
import { QueueRelayService } from "./queue-relay.service"
|
|
23
|
+
import { QueueWorkerService } from "./queue-worker.service"
|
|
24
|
+
|
|
25
|
+
@Module({})
|
|
26
|
+
/** The queues of a service: the outbox writer, its relay into BullMQ, the workers and the schedulers, registered once per app over the connections that hold an outbox. */
|
|
27
|
+
export class QueueModule extends ConfigurableModuleClass {
|
|
28
|
+
/** Registers the capability once per app that enqueues or processes jobs. */
|
|
29
|
+
static register(options: typeof OPTIONS_TYPE): DynamicModule {
|
|
30
|
+
const base = super.register(options)
|
|
31
|
+
return {
|
|
32
|
+
...base,
|
|
33
|
+
providers: [
|
|
34
|
+
...(base.providers ?? []),
|
|
35
|
+
{
|
|
36
|
+
provide: QUEUE_RELAY_MANAGERS,
|
|
37
|
+
useFactory: (...managers: Array<EntityManager>) => managers,
|
|
38
|
+
inject: [...options.connections],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
provide: QUEUE_FACTORY,
|
|
42
|
+
useValue: {
|
|
43
|
+
queue: (name: string, options: BullmqConnection): BullmqQueue => new Queue(name, options),
|
|
44
|
+
worker: (
|
|
45
|
+
name: string,
|
|
46
|
+
processor: (job: BullmqJob) => Promise<void>,
|
|
47
|
+
options: BullmqWorkerOptions,
|
|
48
|
+
): BullmqWorker => new Worker<object>(name, processor, options),
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
BullmqQueueTransportClient,
|
|
52
|
+
{ provide: QUEUE_TRANSPORT, useExisting: BullmqQueueTransportClient },
|
|
53
|
+
QueueOutboxService,
|
|
54
|
+
QueueRelayService,
|
|
55
|
+
QueueWorkerService,
|
|
56
|
+
{ provide: QUEUE_OUTBOX, useExisting: QueueOutboxService },
|
|
57
|
+
{ provide: QUEUE_WORKER_REGISTRY, useExisting: QueueWorkerService },
|
|
58
|
+
],
|
|
59
|
+
exports: [QUEUE_OUTBOX, QUEUE_WORKER_REGISTRY, QUEUE_TRANSPORT],
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { InjectionToken } from "@nestjs/common"
|
|
2
|
+
import type { QueueSchedulerDefinition } from "./queue.contracts"
|
|
3
|
+
|
|
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
|
+
export interface QueueOptions {
|
|
6
|
+
/** The Redis host BullMQ talks to. */
|
|
7
|
+
readonly redisHost: string
|
|
8
|
+
/** The Redis port. */
|
|
9
|
+
readonly redisPort: number
|
|
10
|
+
/** What every BullMQ key starts with: the shared default in a deployment, the run prefix of a test world. */
|
|
11
|
+
readonly prefix: string
|
|
12
|
+
/** The pause between two relay passes over an empty outbox. */
|
|
13
|
+
readonly relayIntervalMs: number
|
|
14
|
+
/** The most outbox rows one relay pass hands to BullMQ. */
|
|
15
|
+
readonly relayBatch: number
|
|
16
|
+
/** How many jobs one worker of the app runs at once. */
|
|
17
|
+
readonly concurrency: number
|
|
18
|
+
/** The tokens of the shared entity managers of the connections that hold a queue outbox of the app: the relay reads each of them. */
|
|
19
|
+
readonly connections: ReadonlyArray<InjectionToken>
|
|
20
|
+
/** The job schedulers the app registers at boot; BullMQ upserts them by id, so a pool of replicas fires each one once per interval. */
|
|
21
|
+
readonly schedulers: ReadonlyArray<QueueSchedulerDefinition>
|
|
22
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ATTEMPTS, BACKOFF_MS, KEEP_COMPLETED_SECONDS, jobNameOf } from "./queue.policy"
|
|
2
|
+
|
|
3
|
+
describe("queue policy", () => {
|
|
4
|
+
it("declares the retry and retention budget of every job", () => {
|
|
5
|
+
expect({
|
|
6
|
+
attempts: ATTEMPTS,
|
|
7
|
+
backoffMs: BACKOFF_MS,
|
|
8
|
+
keepCompletedSeconds: KEEP_COMPLETED_SECONDS,
|
|
9
|
+
}).toEqual({
|
|
10
|
+
attempts: 5,
|
|
11
|
+
backoffMs: 1000,
|
|
12
|
+
keepCompletedSeconds: 3600,
|
|
13
|
+
})
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it("uses the queue name as the BullMQ job name", () => {
|
|
17
|
+
expect(jobNameOf("orders")).toBe("orders")
|
|
18
|
+
})
|
|
19
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** How many deliveries BullMQ gives a job before it keeps it as failed. */
|
|
2
|
+
export const ATTEMPTS = 5
|
|
3
|
+
|
|
4
|
+
/** The pause after the first failed delivery; BullMQ doubles it with every further failure. */
|
|
5
|
+
export const BACKOFF_MS = 1000
|
|
6
|
+
|
|
7
|
+
/** How long BullMQ keeps a completed job (seconds): long enough that a repeated relay pass finds its job id and adds nothing. */
|
|
8
|
+
export const KEEP_COMPLETED_SECONDS = 3600
|
|
9
|
+
|
|
10
|
+
/** The name the jobs of every queue carry inside their queue. */
|
|
11
|
+
export const jobNameOf = (queue: string): string => queue
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EntityManager } from "typeorm"
|
|
2
|
+
import type { QueueHandler } from "./queue.contracts"
|
|
3
|
+
|
|
4
|
+
/** The queue outbox: a typed producer writes a job row in the transaction of the caller, the relay hands it to BullMQ after commit. */
|
|
5
|
+
export interface QueueOutbox {
|
|
6
|
+
/** Writes the job in the outbox of the transaction `tx`, so it exists exactly when the change that needs it commits. */
|
|
7
|
+
write(tx: EntityManager, queue: string, payload: object): Promise<void>
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Where a processor registers the handler of its queue; the workers start when the app has registered every handler. */
|
|
11
|
+
export interface QueueWorkerRegistry {
|
|
12
|
+
/** Registers the handler under the queue it names; a second handler for the same queue replaces the first. */
|
|
13
|
+
add(handler: QueueHandler): void
|
|
14
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Module } from "@nestjs/common"
|
|
2
|
+
import { @@Queue@@Queue } from "./@@queue@@.queue"
|
|
3
|
+
|
|
4
|
+
@Module({ providers: [@@Queue@@Queue], exports: [@@Queue@@Queue] })
|
|
5
|
+
/** The @@queue@@ queue: its typed producer, imported by the domain module whose service enqueues. */
|
|
6
|
+
export class @@Queue@@Module {}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Injectable } from "@nestjs/common"
|
|
2
|
+
import type { EntityManager } from "typeorm"
|
|
3
|
+
import { InjectQueueOutbox } from "@modules/platform/queue"
|
|
4
|
+
import type { QueueOutbox } from "@modules/platform/queue"
|
|
5
|
+
|
|
6
|
+
/** The queue name: the contract between this producer and the processor of the job. */
|
|
7
|
+
export const @@queueUpper@@_QUEUE = "@@queue@@"
|
|
8
|
+
|
|
9
|
+
/** The payload of one @@queue@@ job: ids only. */
|
|
10
|
+
export interface @@Queue@@Payload {
|
|
11
|
+
readonly id: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@Injectable()
|
|
15
|
+
/** The typed producer of the @@queue@@ queue. */
|
|
16
|
+
export class @@Queue@@Queue {
|
|
17
|
+
constructor(@InjectQueueOutbox() private readonly outbox: QueueOutbox) {}
|
|
18
|
+
|
|
19
|
+
/** Enqueues one @@queue@@ job in the transaction of the caller: the job exists exactly when the change that needs it commits. */
|
|
20
|
+
enqueue@@Queue@@(payload: @@Queue@@Payload, tx: EntityManager): Promise<void> {
|
|
21
|
+
return this.outbox.write(tx, @@queueUpper@@_QUEUE, payload)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from "@nestjs/cqrs"
|
|
2
|
+
import type { PublicExecuteParams } from "@modules/platform/cqrs"
|
|
3
|
+
import type { @@Action@@Request, @@Action@@Result } from "./@@action@@.contracts"
|
|
4
|
+
|
|
5
|
+
/** Asks to apply one delivered @@event@@ event; the @@event@@ consumer sends it for every delivery. */
|
|
6
|
+
export class @@Action@@Command extends Command<@@Action@@Result> {
|
|
7
|
+
constructor(readonly params: PublicExecuteParams<@@Action@@Request>) {
|
|
8
|
+
super()
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { @@Event@@Event } from "@modules/events/@@from@@"
|
|
2
|
+
|
|
3
|
+
/** What applying one delivered @@event@@ event takes. */
|
|
4
|
+
export interface @@Action@@Request {
|
|
5
|
+
/** The id of the delivered event; the domain service claims it in the inbox inside its own transaction. */
|
|
6
|
+
readonly eventId: string
|
|
7
|
+
/** The delivered event. */
|
|
8
|
+
readonly event: @@Event@@Event
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Applying an event answers nothing: a redelivery is a no-op. */
|
|
12
|
+
export type @@Action@@Result = void
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CommandHandler } from "@nestjs/cqrs"
|
|
2
|
+
import { @@service@@ } from "@@serviceModule@@"
|
|
3
|
+
import { ICQRSHandler } from "@modules/platform/cqrs"
|
|
4
|
+
import { InjectLogger } from "@modules/platform/logging"
|
|
5
|
+
import type { Logger } from "@modules/platform/logging"
|
|
6
|
+
import type { @@Action@@Result } from "./@@action@@.contracts"
|
|
7
|
+
import { @@Action@@Command } from "./@@action@@.command"
|
|
8
|
+
|
|
9
|
+
@CommandHandler(@@Action@@Command)
|
|
10
|
+
/** Hands the delivered @@event@@ event to the domain service, which claims the event id and applies the change in one transaction. */
|
|
11
|
+
export class @@Action@@Handler extends ICQRSHandler<@@Action@@Command, @@Action@@Result> {
|
|
12
|
+
constructor(
|
|
13
|
+
@InjectLogger() logger: Logger,
|
|
14
|
+
private readonly @@serviceCamel@@: @@service@@,
|
|
15
|
+
) {
|
|
16
|
+
super(logger)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
protected override process(command: @@Action@@Command): Promise<@@Action@@Result> {
|
|
20
|
+
return this.@@serviceCamel@@.apply(command.params.request)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Injectable } from "@nestjs/common"
|
|
2
|
+
import type { CommandBus } from "@nestjs/cqrs"
|
|
3
|
+
import { @@Event@@Event } from "@modules/events/@@from@@"
|
|
4
|
+
import { InjectCommandBus } from "@modules/platform/cqrs"
|
|
5
|
+
import type { EventConsumer, EventDelivery } from "@modules/platform/event-bus"
|
|
6
|
+
import { @@Action@@Command } from "../../application/@@action@@.command"
|
|
7
|
+
|
|
8
|
+
@Injectable()
|
|
9
|
+
/** The consumer door of the @@event@@ event in the @@reactor@@ reactor: it dispatches one command and forwards the event id. */
|
|
10
|
+
export class @@Event@@Consumer implements EventConsumer<@@Event@@Event> {
|
|
11
|
+
readonly event = @@Event@@Event
|
|
12
|
+
|
|
13
|
+
constructor(@InjectCommandBus() private readonly commandBus: CommandBus) {}
|
|
14
|
+
|
|
15
|
+
/** Delivery is at least once: the domain service the command reaches claims `eventId` in the inbox inside its own transaction. */
|
|
16
|
+
async handle(delivery: EventDelivery<@@Event@@Event>): Promise<void> {
|
|
17
|
+
await this.commandBus.execute(new @@Action@@Command({ request: { eventId: delivery.eventId, event: delivery.event } }))
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Module } from "@nestjs/common"
|
|
2
|
+
import type { OnModuleInit } from "@nestjs/common"
|
|
3
|
+
import { InjectEventConsumerRegistry } from "@modules/platform/event-bus"
|
|
4
|
+
import type { EventConsumerRegistry } from "@modules/platform/event-bus"
|
|
5
|
+
import { @@Reactor@@Module } from "../../@@reactor@@.module"
|
|
6
|
+
import { @@Event@@Consumer } from "./@@event@@.consumer"
|
|
7
|
+
|
|
8
|
+
@Module({ imports: [@@Reactor@@Module], providers: [@@Event@@Consumer] })
|
|
9
|
+
/** 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
|
+
constructor(
|
|
12
|
+
@InjectEventConsumerRegistry() private readonly registry: EventConsumerRegistry,
|
|
13
|
+
private readonly @@eventCamel@@Consumer: @@Event@@Consumer,
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
/** Hands every consumer to the registry. */
|
|
17
|
+
onModuleInit(): void {
|
|
18
|
+
this.registry.add(this.@@eventCamel@@Consumer)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { @@Reactor@@MessageModule } from "./transport/message/@@reactor@@-message.module"
|