@starci/hfs 4.0.8 → 4.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -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 +53 -19
- package/package.json +14 -9
- package/report/sonar.mjs +8 -8
- package/runtime/engine/config.mjs +494 -0
- package/runtime/engine/invalid-config.mjs +15 -0
- package/runtime/engine/orca-config.mjs +27 -0
- package/runtime/knowledge/hfs/canon-pins.yaml +160 -29
- 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 +571 -51
- package/runtime/modules/models/registry.yaml +591 -0
- package/runtime/modules/models/runtimes.yaml +701 -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 +10 -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 +16 -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/sops/decrypt.mjs +9 -5
- package/runtime/scripts/api/sops/lib.mjs +35 -0
- package/runtime/scripts/api/sops/seal.mjs +18 -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 +1 -1
- 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 +175 -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/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/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.mjs +13 -3
- package/runtime/scripts/lib/language.mjs +24 -5
- package/runtime/scripts/lib/list.mjs +20 -0
- package/runtime/scripts/lib/package-at.mjs +37 -0
- package/runtime/scripts/lib/path-key.mjs +57 -2
- package/runtime/scripts/lib/read-text.mjs +34 -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/sops-envelope.mjs +58 -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 @@
|
|
|
1
|
+
export { @@Feature@@GraphqlModule } from "./transport/graphql/@@feature@@-graphql.module"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Field, ID, InputType } from "@nestjs/graphql"
|
|
2
|
+
import { IsNotEmpty, IsString, MaxLength } from "class-validator"
|
|
3
|
+
|
|
4
|
+
@InputType()
|
|
5
|
+
/** The @@actionCamel@@ arguments: the id of the subject. */
|
|
6
|
+
export class @@Action@@Input {
|
|
7
|
+
/** The id of the subject. */
|
|
8
|
+
@Field(() => ID)
|
|
9
|
+
@IsString()
|
|
10
|
+
@IsNotEmpty()
|
|
11
|
+
@MaxLength(64)
|
|
12
|
+
id!: string
|
|
13
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { @@Action@@Request, @@Action@@Result } from "../../application/@@action@@.contracts"
|
|
2
|
+
import type { @@Action@@Input } from "./dto/@@action@@.input"
|
|
3
|
+
import type { @@Action@@Type } from "./dto/@@action@@.type"
|
|
4
|
+
|
|
5
|
+
/** Maps the GraphQL input to the command request. */
|
|
6
|
+
export const to@@Action@@Request = (input: @@Action@@Input): @@Action@@Request => ({ id: input.id })
|
|
7
|
+
|
|
8
|
+
/** Maps the result to the GraphQL type. */
|
|
9
|
+
export const to@@Action@@Type = (result: @@Action@@Result): @@Action@@Type => ({ id: result.id })
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Module } from "@nestjs/common"
|
|
2
|
+
import { @@Feature@@Module } from "../../@@feature@@.module"
|
|
3
|
+
import { @@Action@@Resolver } from "./@@action@@.resolver"
|
|
4
|
+
|
|
5
|
+
@Module({ imports: [@@Feature@@Module], providers: [@@Action@@Resolver] })
|
|
6
|
+
/** The GraphQL transport of the @@feature@@ feature. */
|
|
7
|
+
export class @@Feature@@GraphqlModule {}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Args, Mutation, Resolver } from "@nestjs/graphql"
|
|
2
|
+
import type { CommandBus } from "@nestjs/cqrs"
|
|
3
|
+
import { CurrentPrincipal } from "@modules/domain/identity"
|
|
4
|
+
import { InjectCommandBus } from "@modules/platform/cqrs"
|
|
5
|
+
import type { Principal } from "@modules/platform/cqrs"
|
|
6
|
+
import { @@Action@@Command } from "../../application/@@action@@.command"
|
|
7
|
+
import { to@@Action@@Request, to@@Action@@Type } from "./@@action@@.mapper"
|
|
8
|
+
import { @@Action@@Input } from "./dto/@@action@@.input"
|
|
9
|
+
import { @@Action@@Type } from "./dto/@@action@@.type"
|
|
10
|
+
|
|
11
|
+
@Resolver()
|
|
12
|
+
/** GraphQL door of @@actionCamel@@. */
|
|
13
|
+
export class @@Action@@Resolver {
|
|
14
|
+
constructor(@InjectCommandBus() private readonly commandBus: CommandBus) {}
|
|
15
|
+
|
|
16
|
+
/** Runs @@action@@ for the caller. */
|
|
17
|
+
@Mutation(() => @@Action@@Type, { name: "@@actionCamel@@" })
|
|
18
|
+
async @@actionCamel@@(
|
|
19
|
+
@CurrentPrincipal() principal: Principal,
|
|
20
|
+
@Args("input") input: @@Action@@Input,
|
|
21
|
+
): Promise<@@Action@@Type> {
|
|
22
|
+
const result = await this.commandBus.execute(
|
|
23
|
+
new @@Action@@Command({ request: to@@Action@@Request(input), principal }),
|
|
24
|
+
)
|
|
25
|
+
return to@@Action@@Type(result)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Body, Controller, Post } from "@nestjs/common"
|
|
2
|
+
import type { CommandBus } from "@nestjs/cqrs"
|
|
3
|
+
import { CurrentPrincipal } from "@modules/domain/identity"
|
|
4
|
+
import { InjectCommandBus } from "@modules/platform/cqrs"
|
|
5
|
+
import type { Principal } from "@modules/platform/cqrs"
|
|
6
|
+
import { @@Action@@Command } from "../../application/@@action@@.command"
|
|
7
|
+
import { to@@Action@@Request, to@@Action@@Response } from "./@@action@@.mapper"
|
|
8
|
+
import { @@Action@@Request } from "./dto/@@action@@.request"
|
|
9
|
+
import { @@Action@@Response } from "./dto/@@action@@.response"
|
|
10
|
+
|
|
11
|
+
@Controller("@@feature@@")
|
|
12
|
+
/** HTTP door of @@actionCamel@@. */
|
|
13
|
+
export class @@Action@@Controller {
|
|
14
|
+
constructor(@InjectCommandBus() private readonly commandBus: CommandBus) {}
|
|
15
|
+
|
|
16
|
+
/** Runs @@action@@ for the authenticated caller. */
|
|
17
|
+
@Post()
|
|
18
|
+
async @@actionCamel@@(
|
|
19
|
+
@CurrentPrincipal() principal: Principal,
|
|
20
|
+
@Body() input: @@Action@@Request,
|
|
21
|
+
): Promise<@@Action@@Response> {
|
|
22
|
+
const result = await this.commandBus.execute(
|
|
23
|
+
new @@Action@@Command({ request: to@@Action@@Request(input), principal }),
|
|
24
|
+
)
|
|
25
|
+
return to@@Action@@Response(result)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { @@Action@@Request, @@Action@@Result } from "../../application/@@action@@.contracts"
|
|
2
|
+
import type { @@Action@@Request as @@Action@@HttpRequest } from "./dto/@@action@@.request"
|
|
3
|
+
import type { @@Action@@Response } from "./dto/@@action@@.response"
|
|
4
|
+
|
|
5
|
+
/** Maps the HTTP request to the command request. */
|
|
6
|
+
export const to@@Action@@Request = (input: @@Action@@HttpRequest): @@Action@@Request => ({ id: input.id })
|
|
7
|
+
|
|
8
|
+
/** Maps the command result to the HTTP response. */
|
|
9
|
+
export const to@@Action@@Response = (result: @@Action@@Result): @@Action@@Response => ({ id: result.id })
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Module } from "@nestjs/common"
|
|
2
|
+
import { @@Feature@@ApiModule } from "../../@@feature@@.module"
|
|
3
|
+
import { @@Action@@Controller } from "./@@action@@.controller"
|
|
4
|
+
|
|
5
|
+
@Module({ imports: [@@Feature@@ApiModule], controllers: [@@Action@@Controller] })
|
|
6
|
+
/** The HTTP transport of the @@feature@@ feature. */
|
|
7
|
+
export class @@Feature@@HttpModule {}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Test } from "@nestjs/testing"
|
|
2
|
+
import { @@Group@@Cli } from "./@@group@@.cli"
|
|
3
|
+
|
|
4
|
+
describe("@@Group@@Cli", () => {
|
|
5
|
+
it("shows the help of the group, and runs nothing else, when no sub-command is named", async () => {
|
|
6
|
+
const moduleRef = await Test.createTestingModule({ providers: [@@Group@@Cli] }).compile()
|
|
7
|
+
const group = moduleRef.get(@@Group@@Cli)
|
|
8
|
+
const help = jest.fn()
|
|
9
|
+
Object.defineProperty(group, "command", { value: { help } })
|
|
10
|
+
|
|
11
|
+
await expect(group.run()).resolves.toBeUndefined()
|
|
12
|
+
|
|
13
|
+
expect(help).toHaveBeenCalledTimes(1)
|
|
14
|
+
})
|
|
15
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Command, CommandRunner } from "nest-commander"
|
|
2
|
+
import { RunCli } from "./subs/run.cli"
|
|
3
|
+
|
|
4
|
+
@Command({ name: "@@group@@", description: "The @@group@@ commands", subCommands: [RunCli] })
|
|
5
|
+
/** `cli @@group@@`: the @@group@@ group; its commands are the sub-commands (`cli @@group@@ run`). */
|
|
6
|
+
export class @@Group@@Cli extends CommandRunner {
|
|
7
|
+
/** Without a sub-command the group shows its help. */
|
|
8
|
+
async run(): Promise<void> {
|
|
9
|
+
this.command.help()
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Module } from "@nestjs/common"
|
|
2
|
+
import { @@Group@@Cli } from "./@@group@@.cli"
|
|
3
|
+
import { RunCli } from "./subs/run.cli"
|
|
4
|
+
|
|
5
|
+
@Module({ providers: [@@Group@@Cli, RunCli] })
|
|
6
|
+
/** The @@group@@ group: its command and its sub-commands; the work is the runner service the sub-command delegates to. */
|
|
7
|
+
export class @@Group@@Module {}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { mock } from "@starci/jest-preset"
|
|
2
|
+
import { Test } from "@nestjs/testing"
|
|
3
|
+
import { @@service@@ } from "@@serviceModule@@"
|
|
4
|
+
import { RunCli } from "./run.cli"
|
|
5
|
+
|
|
6
|
+
describe("RunCli", () => {
|
|
7
|
+
it("delegates the @@group@@ run to the runner service once", async () => {
|
|
8
|
+
const @@serviceCamel@@ = mock<@@service@@>()
|
|
9
|
+
const moduleRef = await Test.createTestingModule({
|
|
10
|
+
providers: [RunCli, { provide: @@service@@, useValue: @@serviceCamel@@ }],
|
|
11
|
+
}).compile()
|
|
12
|
+
|
|
13
|
+
await expect(moduleRef.get(RunCli).run()).resolves.toBeUndefined()
|
|
14
|
+
|
|
15
|
+
expect(@@serviceCamel@@.run).toHaveBeenCalledTimes(1)
|
|
16
|
+
})
|
|
17
|
+
})
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CommandRunner, SubCommand } from "nest-commander"
|
|
2
|
+
import { @@service@@ } from "@@serviceModule@@"
|
|
3
|
+
|
|
4
|
+
@SubCommand({ name: "run", description: "Run @@group@@" })
|
|
5
|
+
/** `cli @@group@@ run`: delegates the run to the injected runner service; no decision here. */
|
|
6
|
+
export class RunCli extends CommandRunner {
|
|
7
|
+
constructor(private readonly @@serviceCamel@@: @@service@@) {
|
|
8
|
+
super()
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Runs @@group@@ through the runner service. */
|
|
12
|
+
async run(): Promise<void> {
|
|
13
|
+
await this.@@serviceCamel@@.run()
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { DomainError } from "@modules/platform/errors"
|
|
2
|
+
import type { ErrorKind } from "@modules/platform/errors"
|
|
3
|
+
|
|
4
|
+
/** Codes of the event-bus capability. */
|
|
5
|
+
export enum EventBusErrorCode {
|
|
6
|
+
/** A delivered envelope does not have the shape its consumer's event class reads. */
|
|
7
|
+
EnvelopeInvalid = "EVENT_BUS_ENVELOPE_INVALID",
|
|
8
|
+
/** The broker did not answer a call within its deadline, or refused it. */
|
|
9
|
+
BrokerUnavailable = "EVENT_BUS_BROKER_UNAVAILABLE",
|
|
10
|
+
/** A dead letter id does not name a message the dead-letter topic holds. */
|
|
11
|
+
DeadLetterUnknown = "EVENT_BUS_DEAD_LETTER_UNKNOWN",
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** How each event-bus code travels. */
|
|
15
|
+
export const EVENT_BUS_ERROR_KINDS: Record<EventBusErrorCode, ErrorKind> = {
|
|
16
|
+
[EventBusErrorCode.EnvelopeInvalid]: "internal",
|
|
17
|
+
[EventBusErrorCode.BrokerUnavailable]: "unavailable",
|
|
18
|
+
[EventBusErrorCode.DeadLetterUnknown]: "not-found",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** The one error class of the event-bus capability. */
|
|
22
|
+
export class EventBusError extends DomainError<EventBusErrorCode> {}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { EnvSource } from "@modules/platform/config"
|
|
2
|
+
import type { EventBusOptions } from "./event-bus.options"
|
|
3
|
+
|
|
4
|
+
/** What the app's `main.ts` reads for the bus; the connection token is the app root's choice. */
|
|
5
|
+
export type EventBusConfig = Omit<EventBusOptions, "connections">
|
|
6
|
+
|
|
7
|
+
/** Reads the event bus options: the brokers and the group are required, the rest are tunables with literal defaults. */
|
|
8
|
+
export const parseEventBusConfig = (env: EnvSource): EventBusConfig => ({
|
|
9
|
+
brokers: env
|
|
10
|
+
.string("EVENT_BUS_BROKERS")
|
|
11
|
+
.split(",")
|
|
12
|
+
.map((broker) => broker.trim())
|
|
13
|
+
.filter((broker) => broker.length > 0),
|
|
14
|
+
groupId: env.string("EVENT_BUS_GROUP_ID"),
|
|
15
|
+
topicPrefix: env.optional("EVENT_BUS_TOPIC_PREFIX") ?? "",
|
|
16
|
+
relayIntervalMs: env.duration("EVENT_BUS_RELAY_INTERVAL", 200),
|
|
17
|
+
relayBatch: env.int("EVENT_BUS_RELAY_BATCH", 50),
|
|
18
|
+
timeoutMs: env.duration("EVENT_BUS_TIMEOUT", 3000),
|
|
19
|
+
})
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** The base of every typed event (`modules/events/<service>/<event>.event.ts`): who it is and what it carries. */
|
|
2
|
+
export abstract class BaseEvent {
|
|
3
|
+
/** The stable event id: the same logical event always carries the same id, so a receiver can dedupe. */
|
|
4
|
+
abstract readonly eventId: string
|
|
5
|
+
|
|
6
|
+
/** The event name, `<service>.<what>`: an entry of the vendored contract `be/contracts/<service>/events.json`. */
|
|
7
|
+
abstract readonly eventName: string
|
|
8
|
+
|
|
9
|
+
/** The data of the event. */
|
|
10
|
+
abstract readonly payload: object
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** What reading a received envelope answers: the event, or null when the envelope does not have the shape of the event. */
|
|
14
|
+
export type ParsedEvent<Event extends BaseEvent> = Event | null
|
|
15
|
+
|
|
16
|
+
/** The class side of a typed event: its name and version (the vendored contract), and how a received envelope is read back. */
|
|
17
|
+
export interface EventClass<Event extends BaseEvent> {
|
|
18
|
+
/** The event name. */
|
|
19
|
+
readonly eventName: string
|
|
20
|
+
/** The contract version of the payload. */
|
|
21
|
+
readonly version: number
|
|
22
|
+
/** Reads a received envelope `{ eventId, payload }` back into the event; null when it does not have the shape. */
|
|
23
|
+
parse(envelope: unknown): ParsedEvent<Event>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** An event as a consumer receives it. */
|
|
27
|
+
export interface EventDelivery<Event extends BaseEvent> {
|
|
28
|
+
/** The stable event id: the dedupe key of the receiver. */
|
|
29
|
+
readonly eventId: string
|
|
30
|
+
/** The event. */
|
|
31
|
+
readonly event: Event
|
|
32
|
+
/** How many deliveries were started, this one included. */
|
|
33
|
+
readonly attempt: number
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** An event that ran out of attempts and waits for an operator. */
|
|
37
|
+
export interface EventDeadLetter {
|
|
38
|
+
/** The id of the dead letter, what `requeue` takes. */
|
|
39
|
+
readonly id: string
|
|
40
|
+
/** The event name. */
|
|
41
|
+
readonly eventName: string
|
|
42
|
+
/** The stable event id. */
|
|
43
|
+
readonly eventId: string
|
|
44
|
+
/** Why the last delivery failed. */
|
|
45
|
+
readonly reason: string
|
|
46
|
+
/** How many deliveries were tried. */
|
|
47
|
+
readonly attempts: number
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** The envelope of an event on the wire: what the outbox row stores and a consumer reads back. */
|
|
51
|
+
export interface EventEnvelope {
|
|
52
|
+
/** The stable event id. */
|
|
53
|
+
readonly eventId: string
|
|
54
|
+
/** The event name. */
|
|
55
|
+
readonly eventName: string
|
|
56
|
+
/** The data of the event. */
|
|
57
|
+
readonly payload: object
|
|
58
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { EntityManager } from "typeorm"
|
|
2
|
+
import { injector } from "@modules/platform/composition"
|
|
3
|
+
import type { TypedParameterDecorator } from "@modules/platform/composition"
|
|
4
|
+
import type { EventBusOptions } from "./event-bus.options"
|
|
5
|
+
import type { EventBus, EventConsumerRegistry } from "./event-bus.port"
|
|
6
|
+
import type { EventTransport, KafkaFactory } from "./event-transport.port"
|
|
7
|
+
|
|
8
|
+
/** Token of the options of the event bus, exported so a spec can provide it. */
|
|
9
|
+
export const EVENT_BUS_OPTIONS: unique symbol = Symbol("platform.event-bus.options")
|
|
10
|
+
|
|
11
|
+
/** Token of the EventBus port. */
|
|
12
|
+
export const EVENT_BUS: unique symbol = Symbol("platform.event-bus")
|
|
13
|
+
|
|
14
|
+
/** Token of the consumer registry of the bus. */
|
|
15
|
+
export const EVENT_CONSUMER_REGISTRY: unique symbol = Symbol("platform.event-bus.registry")
|
|
16
|
+
|
|
17
|
+
/** Token of the broker port; it is also the health probe token of the bus. */
|
|
18
|
+
export const EVENT_TRANSPORT: unique symbol = Symbol("platform.event-bus.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 EVENT_RELAY_MANAGERS: unique symbol = Symbol("platform.event-bus.relay-managers")
|
|
22
|
+
|
|
23
|
+
/** Token of the factory that builds the Kafka driver, exported so a spec can provide it. */
|
|
24
|
+
export const KAFKA_FACTORY: unique symbol = Symbol("platform.event-bus.kafka-factory")
|
|
25
|
+
|
|
26
|
+
/** Injects the options of the event bus. Parameter type: EventBusOptions. */
|
|
27
|
+
export const InjectEventBusOptions = (): TypedParameterDecorator<EventBusOptions> =>
|
|
28
|
+
injector<EventBusOptions>(EVENT_BUS_OPTIONS)
|
|
29
|
+
|
|
30
|
+
/** Injects the EventBus port. Parameter type: EventBus. */
|
|
31
|
+
export const InjectEventBus = (): TypedParameterDecorator<EventBus> => injector<EventBus>(EVENT_BUS)
|
|
32
|
+
|
|
33
|
+
/** Injects the consumer registry a message transport registers its consumers with. Parameter type: EventConsumerRegistry. */
|
|
34
|
+
export const InjectEventConsumerRegistry = (): TypedParameterDecorator<EventConsumerRegistry> =>
|
|
35
|
+
injector<EventConsumerRegistry>(EVENT_CONSUMER_REGISTRY)
|
|
36
|
+
|
|
37
|
+
/** Injects the broker port. Parameter type: EventTransport. */
|
|
38
|
+
export const InjectEventTransport = (): TypedParameterDecorator<EventTransport> =>
|
|
39
|
+
injector<EventTransport>(EVENT_TRANSPORT)
|
|
40
|
+
|
|
41
|
+
/** Injects the entity managers the relay reads the outbox of. Parameter type: ReadonlyArray<EntityManager>. */
|
|
42
|
+
export const InjectEventRelayManagers = (): TypedParameterDecorator<ReadonlyArray<EntityManager>> =>
|
|
43
|
+
injector<ReadonlyArray<EntityManager>>(EVENT_RELAY_MANAGERS)
|
|
44
|
+
|
|
45
|
+
/** Injects the factory that builds the Kafka driver. Parameter type: KafkaFactory. */
|
|
46
|
+
export const InjectKafkaFactory = (): TypedParameterDecorator<KafkaFactory> => injector<KafkaFactory>(KAFKA_FACTORY)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Log events of the event bus. */
|
|
2
|
+
export enum EventBusLogEvent {
|
|
3
|
+
/** A consumer threw for a delivery; the cause rides with the event and the attempt. */
|
|
4
|
+
DeliveryFailed = "event-bus.delivery.failed",
|
|
5
|
+
/** A delivery failed and the event waits on the retry topic; the event and the attempt ride in the fields. */
|
|
6
|
+
DeliveryRetried = "event-bus.delivery.retried",
|
|
7
|
+
/** An event ran out of attempts and was put on the dead-letter topic. */
|
|
8
|
+
DeliveryBuried = "event-bus.delivery.buried",
|
|
9
|
+
/** A relay pass over the outbox failed; the next pass tries again. */
|
|
10
|
+
/** A received message is not an envelope of a registered event and was left alone. */
|
|
11
|
+
MessageSkipped = "event-bus.message.skipped",
|
|
12
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ConfigurableModuleBuilder } from "@nestjs/common"
|
|
2
|
+
import { EVENT_BUS_OPTIONS } from "./event-bus.decorators"
|
|
3
|
+
import type { EventBusOptions } from "./event-bus.options"
|
|
4
|
+
|
|
5
|
+
/** The configurable-module base of the event bus; `isGlobal` is decided by the app root. */
|
|
6
|
+
export const { ConfigurableModuleClass, OPTIONS_TYPE } = new ConfigurableModuleBuilder<EventBusOptions>({
|
|
7
|
+
optionsInjectionToken: EVENT_BUS_OPTIONS,
|
|
8
|
+
})
|
|
9
|
+
.setExtras({ isGlobal: false }, (definition, extras) => ({ ...definition, global: extras.isGlobal }))
|
|
10
|
+
.build()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Module } from "@nestjs/common"
|
|
2
|
+
import type { DynamicModule } from "@nestjs/common"
|
|
3
|
+
import { Kafka, logLevel } from "kafkajs"
|
|
4
|
+
import type { EntityManager } from "typeorm"
|
|
5
|
+
import {
|
|
6
|
+
EVENT_BUS,
|
|
7
|
+
EVENT_RELAY_MANAGERS,
|
|
8
|
+
EVENT_CONSUMER_REGISTRY,
|
|
9
|
+
EVENT_TRANSPORT,
|
|
10
|
+
KAFKA_FACTORY,
|
|
11
|
+
} from "./event-bus.decorators"
|
|
12
|
+
import { ConfigurableModuleClass, OPTIONS_TYPE } from "./event-bus.module-definition"
|
|
13
|
+
import { EventBusService } from "./event-bus.service"
|
|
14
|
+
import { EventRelayService } from "./event-relay.service"
|
|
15
|
+
import { EventRunnerService } from "./event-runner.service"
|
|
16
|
+
import type { KafkaDriver, KafkaDriverConfig } from "./event-transport.port"
|
|
17
|
+
import { KafkaEventTransportClient } from "./kafka-event-transport.client"
|
|
18
|
+
|
|
19
|
+
@Module({})
|
|
20
|
+
/** The event bus of a service: the outbox writer, its relay, the consumer runner and the Kafka transport, registered once per app over the connection that holds its outbox. */
|
|
21
|
+
export class EventBusModule extends ConfigurableModuleClass {
|
|
22
|
+
/** Registers the capability once per app that publishes or consumes events. */
|
|
23
|
+
static register(options: typeof OPTIONS_TYPE): DynamicModule {
|
|
24
|
+
const base = super.register(options)
|
|
25
|
+
return {
|
|
26
|
+
...base,
|
|
27
|
+
providers: [
|
|
28
|
+
...(base.providers ?? []),
|
|
29
|
+
{
|
|
30
|
+
provide: EVENT_RELAY_MANAGERS,
|
|
31
|
+
useFactory: (...managers: Array<EntityManager>) => managers,
|
|
32
|
+
inject: [...options.connections],
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
provide: KAFKA_FACTORY,
|
|
36
|
+
useValue: {
|
|
37
|
+
create: (config: KafkaDriverConfig): KafkaDriver =>
|
|
38
|
+
new Kafka({ ...config, brokers: [...config.brokers], logLevel: logLevel.NOTHING }),
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
KafkaEventTransportClient,
|
|
42
|
+
{ provide: EVENT_TRANSPORT, useExisting: KafkaEventTransportClient },
|
|
43
|
+
EventBusService,
|
|
44
|
+
EventRelayService,
|
|
45
|
+
EventRunnerService,
|
|
46
|
+
{ provide: EVENT_BUS, useExisting: EventBusService },
|
|
47
|
+
{ provide: EVENT_CONSUMER_REGISTRY, useExisting: EventRunnerService },
|
|
48
|
+
],
|
|
49
|
+
exports: [EVENT_BUS, EVENT_CONSUMER_REGISTRY, EVENT_TRANSPORT],
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { InjectionToken } from "@nestjs/common"
|
|
2
|
+
|
|
3
|
+
/** What the event bus of one app needs: where the broker is, who the app is to it, and the connection whose outbox it relays. */
|
|
4
|
+
export interface EventBusOptions {
|
|
5
|
+
/** The broker addresses, `host:port`. */
|
|
6
|
+
readonly brokers: ReadonlyArray<string>
|
|
7
|
+
/** The consumer group of the app: every instance of one app shares it. */
|
|
8
|
+
readonly groupId: string
|
|
9
|
+
/** What every topic name starts with: empty in a deployment, the run prefix of a test world. */
|
|
10
|
+
readonly topicPrefix: string
|
|
11
|
+
/** The pause between two relay passes over the outbox. */
|
|
12
|
+
readonly relayIntervalMs: number
|
|
13
|
+
/** The most outbox rows one relay pass hands to the broker. */
|
|
14
|
+
readonly relayBatch: number
|
|
15
|
+
/** The deadline of one broker call. */
|
|
16
|
+
readonly timeoutMs: number
|
|
17
|
+
/** The tokens of the shared entity managers of the connections that hold an outbox of the app: the relay reads each of them. */
|
|
18
|
+
readonly connections: ReadonlyArray<InjectionToken>
|
|
19
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { EntityManager } from "typeorm"
|
|
2
|
+
import type { BaseEvent, EventClass, EventDeadLetter, EventDelivery } from "./event-bus.contracts"
|
|
3
|
+
|
|
4
|
+
/** The event bus of a service: events leave it through `publish`, called by a domain service in the transaction of the change they report. */
|
|
5
|
+
export interface EventBus {
|
|
6
|
+
/** Writes the event in the outbox of the transaction `tx` carries; the relay hands it to the broker once the transaction commits. */
|
|
7
|
+
publish(event: BaseEvent, tx: EntityManager): Promise<void>
|
|
8
|
+
/** How many deliveries of the class wait on the retry topic for their backoff to pass. */
|
|
9
|
+
pendingRetries(event: EventClass<BaseEvent>): Promise<number>
|
|
10
|
+
/** The events of the class that ran out of attempts. */
|
|
11
|
+
deadLetters(event: EventClass<BaseEvent>): Promise<ReadonlyArray<EventDeadLetter>>
|
|
12
|
+
/** Puts a dead letter back to be delivered again. */
|
|
13
|
+
requeue(deadLetterId: string): Promise<void>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** One consumer of one event; a transport class in `transport/message` implements it. */
|
|
17
|
+
export interface EventConsumer<Event extends BaseEvent> {
|
|
18
|
+
/** The class of the event this consumer reads. */
|
|
19
|
+
readonly event: EventClass<Event>
|
|
20
|
+
/** Handles one delivery; a throw schedules a retry with the backoff of the bus, a return acknowledges it. */
|
|
21
|
+
handle(delivery: EventDelivery<Event>): Promise<void>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Where a message transport module registers its consumers. */
|
|
25
|
+
export interface EventConsumerRegistry {
|
|
26
|
+
/** Registers the consumer of its event. */
|
|
27
|
+
add<Event extends BaseEvent>(consumer: EventConsumer<Event>): void
|
|
28
|
+
}
|