@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,10 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
@import "@heroui/styles/css";
|
|
3
|
+
@import "@starci/grammar/common.css";
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* The grammar's renderers spell their layout in Tailwind utilities inside node_modules, which Tailwind never scans by default;
|
|
7
|
+
* the ui package's own utilities are scanned the same way.
|
|
8
|
+
*/
|
|
9
|
+
@source "../../../../../node_modules/@starci/grammar/dist";
|
|
10
|
+
@source "../../../../packages/{{project}}-ui/src";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Metadata } from "next"
|
|
2
|
+
import { getTranslations } from "next-intl/server"
|
|
3
|
+
import type { ReactNode } from "react"
|
|
4
|
+
import { SiteShell } from "@{{project}}/ui"
|
|
5
|
+
import { LANDING_ROUTES } from "@/modules/routes"
|
|
6
|
+
|
|
7
|
+
/** Framework-layout boundary input: the routed page body and nothing else. */
|
|
8
|
+
type LandingLayoutProps = { readonly content: ReactNode }
|
|
9
|
+
|
|
10
|
+
/** The document title and description of the landing, for the language in the address. */
|
|
11
|
+
export const landingLayoutMetadata = async (locale: string): Promise<Metadata> => {
|
|
12
|
+
const t = await getTranslations({ locale, namespace: "landing" })
|
|
13
|
+
return { title: t("title"), description: t("description") }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** The landing's chrome, resolved on the server: the shared brand shell with the wordmark linking home, around the routed body. */
|
|
17
|
+
export const LandingLayout = async (props: LandingLayoutProps) => {
|
|
18
|
+
const t = await getTranslations("landing.shell")
|
|
19
|
+
return (
|
|
20
|
+
<SiteShell brand={t("brand")} homeHref={LANDING_ROUTES.home}>
|
|
21
|
+
{props.content}
|
|
22
|
+
</SiteShell>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ErrorNotice } from "@{{project}}/ui"
|
|
2
|
+
|
|
3
|
+
/** The error page's resolved words. */
|
|
4
|
+
type LandingErrorPageBaseProps = {
|
|
5
|
+
readonly title: string
|
|
6
|
+
readonly retryLabel: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** What the error page reads: its resolved words and its one command, retry the segment. */
|
|
10
|
+
type LandingErrorPageBaseContract = {
|
|
11
|
+
readonly props: LandingErrorPageBaseProps
|
|
12
|
+
readonly on: { readonly retry: () => void }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** The pure error page of the landing: the screen a render failure shows, drawn from resolved words and one retry. */
|
|
16
|
+
export const LandingErrorPageBase = (props: LandingErrorPageBaseContract) => (
|
|
17
|
+
<ErrorNotice title={props.props.title} retryLabel={props.props.retryLabel} onRetry={props.on.retry} />
|
|
18
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useTranslations } from "next-intl"
|
|
2
|
+
import { LandingErrorPageBase } from "./component"
|
|
3
|
+
|
|
4
|
+
/** The public props of the landing's locale error page: the boundary hands it the retry. */
|
|
5
|
+
type LandingErrorPageProps = { readonly onRetry: () => void }
|
|
6
|
+
|
|
7
|
+
/** A render failure in the landing shows this instead of a blank page; retry re-renders the segment. */
|
|
8
|
+
export const LandingErrorPage = (props: LandingErrorPageProps) => {
|
|
9
|
+
const t = useTranslations("landing.errors.page")
|
|
10
|
+
return <LandingErrorPageBase props={{ title: t("title"), retryLabel: t("retry") }} on={{ retry: props.onRetry }} />
|
|
11
|
+
}
|
package/templates/fe/skeleton/apps/landing/src/features/pages/LandingGlobalErrorPage/index.tsx
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DEFAULT_LOCALE } from "@{{project}}/i18n/routing"
|
|
2
|
+
import { GlobalErrorNotice } from "@{{project}}/ui"
|
|
3
|
+
import messages from "@/modules/i18n/messages/vi.json"
|
|
4
|
+
|
|
5
|
+
/** The public props of the landing's last-resort error page: the boundary hands it the retry. */
|
|
6
|
+
type LandingGlobalErrorPageProps = { readonly onRetry: () => void }
|
|
7
|
+
|
|
8
|
+
/** The last-resort boundary above the locale layout of the landing: it has no provider, so it reads the default catalog directly. */
|
|
9
|
+
export const LandingGlobalErrorPage = (props: LandingGlobalErrorPageProps) => (
|
|
10
|
+
<GlobalErrorNotice
|
|
11
|
+
lang={DEFAULT_LOCALE}
|
|
12
|
+
title={messages.landing.errors.global.title}
|
|
13
|
+
retryLabel={messages.landing.errors.global.retry}
|
|
14
|
+
onRetry={props.onRetry}
|
|
15
|
+
/>
|
|
16
|
+
)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { getTranslations } from "next-intl/server"
|
|
2
|
+
import { LoadingNotice } from "@{{project}}/ui"
|
|
3
|
+
|
|
4
|
+
/** Shown while a route of the landing resolves. */
|
|
5
|
+
export const LandingLoadingPage = async () => {
|
|
6
|
+
const t = await getTranslations("landing.loading")
|
|
7
|
+
return <LoadingNotice label={t("message")} />
|
|
8
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { getTranslations } from "next-intl/server"
|
|
2
|
+
import { NotFoundNotice } from "@{{project}}/ui"
|
|
3
|
+
import { LANDING_ROUTES } from "@/modules/routes"
|
|
4
|
+
|
|
5
|
+
/** Shown when a route of the landing calls `notFound()`. */
|
|
6
|
+
export const LandingNotFoundPage = async () => {
|
|
7
|
+
const t = await getTranslations("landing.notFound")
|
|
8
|
+
return <NotFoundNotice title={t("title")} homeLabel={t("home")} homeHref={LANDING_ROUTES.home} />
|
|
9
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Button, Heading, Text } from "@starci/grammar/common"
|
|
2
|
+
|
|
3
|
+
/** Props for {@link LandingPageBase}. */
|
|
4
|
+
export type LandingPageBaseProps = {
|
|
5
|
+
/** The words and the link the page shows, already resolved. */
|
|
6
|
+
readonly props: {
|
|
7
|
+
readonly title: string
|
|
8
|
+
readonly lede: string
|
|
9
|
+
readonly openApp: string
|
|
10
|
+
/** The product app's origin: the landing hands the reader over to it. */
|
|
11
|
+
readonly appHref: string
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Draw the public front door: the welcome, one sentence about the product and the way into the product app. */
|
|
16
|
+
export const LandingPageBase = (props: LandingPageBaseProps) => (
|
|
17
|
+
<>
|
|
18
|
+
<Heading level={1}>{props.props.title}</Heading>
|
|
19
|
+
<Text tone="muted">{props.props.lede}</Text>
|
|
20
|
+
<Button href={props.props.appHref} variant="primary">
|
|
21
|
+
{props.props.openApp}
|
|
22
|
+
</Button>
|
|
23
|
+
</>
|
|
24
|
+
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Metadata } from "next"
|
|
2
|
+
import { getTranslations } from "next-intl/server"
|
|
3
|
+
import { appUrl } from "@/modules/config"
|
|
4
|
+
import { LandingPageBase } from "./component"
|
|
5
|
+
|
|
6
|
+
/** The document title of the landing page, from the catalog of the requested locale. */
|
|
7
|
+
export const landingMetadata = async (): Promise<Metadata> => {
|
|
8
|
+
const t = await getTranslations("landing.home")
|
|
9
|
+
return { title: t("title") }
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** The landing page, resolved on the server: its copy from the catalog and the product app's origin from the config module. */
|
|
13
|
+
export const LandingPage = async () => {
|
|
14
|
+
const t = await getTranslations("landing.home")
|
|
15
|
+
return <LandingPageBase props={{ title: t("title"), lede: t("lede"), openApp: t("openApp"), appHref: appUrl() }} />
|
|
16
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The only reader of `process.env` in the landing. A value is read when it is asked for, not when the file loads, and a missing
|
|
3
|
+
* value stops the caller with a named error: there is no localhost fallback.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const required = (name: string, value: string | undefined): string => {
|
|
7
|
+
if (value === undefined || value === "") throw new Error(`${name} is not set`)
|
|
8
|
+
return value
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** The public origin of the product app the landing hands the reader over to; throws when `NEXT_PUBLIC_APP_URL` is not set. */
|
|
12
|
+
export const appUrl = (): string => required("NEXT_PUBLIC_APP_URL", process.env.NEXT_PUBLIC_APP_URL)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createAppI18n } from "@{{project}}/i18n"
|
|
2
|
+
|
|
3
|
+
/** The landing's i18n: the product's one next-intl stack (the i18n package), with this app's own catalogs under `messages/`. */
|
|
4
|
+
export const landingI18n = createAppI18n(
|
|
5
|
+
"landing",
|
|
6
|
+
async (locale) => (await import(`./messages/${locale}.json`)).default,
|
|
7
|
+
)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"landing": {
|
|
3
|
+
"title": "{{project}}",
|
|
4
|
+
"description": "Trang giới thiệu {{project}}.",
|
|
5
|
+
"shell": {
|
|
6
|
+
"brand": "{{project}}"
|
|
7
|
+
},
|
|
8
|
+
"home": {
|
|
9
|
+
"title": "Chào mừng đến với {{project}}",
|
|
10
|
+
"lede": "Mọi thứ bạn cần đều ở trong ứng dụng.",
|
|
11
|
+
"openApp": "Mở ứng dụng"
|
|
12
|
+
},
|
|
13
|
+
"loading": {
|
|
14
|
+
"message": "Đang tải"
|
|
15
|
+
},
|
|
16
|
+
"notFound": {
|
|
17
|
+
"title": "Không tìm thấy trang",
|
|
18
|
+
"home": "Về trang chủ"
|
|
19
|
+
},
|
|
20
|
+
"errors": {
|
|
21
|
+
"page": {
|
|
22
|
+
"title": "Đã xảy ra lỗi",
|
|
23
|
+
"retry": "Thử lại"
|
|
24
|
+
},
|
|
25
|
+
"global": {
|
|
26
|
+
"title": "Đã xảy ra lỗi nghiêm trọng",
|
|
27
|
+
"retry": "Thử lại"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { proxy } from "@{{project}}/i18n/proxy"
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import "server-only"
|
|
2
|
+
import { hasLocale } from "next-intl"
|
|
3
|
+
import { createNavigation } from "next-intl/navigation"
|
|
4
|
+
import { getMessages, getRequestConfig, setRequestLocale } from "next-intl/server"
|
|
5
|
+
import { notFound } from "next/navigation"
|
|
6
|
+
import { locale as routeLocale } from "next/root-params"
|
|
7
|
+
import { PRODUCT_TIME_ZONE, routing } from "./routing"
|
|
8
|
+
|
|
9
|
+
/** Loads one app's own catalog for a served locale. */
|
|
10
|
+
type LoadMessages = (locale: string) => Promise<Record<string, unknown>>
|
|
11
|
+
|
|
12
|
+
/** The missing message next-intl asks a fallback for. */
|
|
13
|
+
type MissingMessage = { readonly namespace?: string; readonly key: string }
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The next-intl stack of one app of the product, written once here and called once by each app's `modules/i18n` (R59): the
|
|
17
|
+
* product's one routing with its locale-aware navigation, the request config next-intl's plugin loads (the app's
|
|
18
|
+
* `modules/i18n/request.ts` default-exports it) and what the app's `[locale]` layout resolves before it mounts the shell. `app` names
|
|
19
|
+
* the app in the text of a message its catalog lacks (`<app>:<namespace>.<key>`); `loadMessages` loads its own catalogs. A server
|
|
20
|
+
* module: a client component reads the default locale from `./routing`.
|
|
21
|
+
*/
|
|
22
|
+
export const createAppI18n = (app: string, loadMessages: LoadMessages) => ({
|
|
23
|
+
navigation: createNavigation(routing),
|
|
24
|
+
/**
|
|
25
|
+
* The locale is the `[locale]` route param read through `next/root-params` (`experimental.rootParams` in the app's next.config.ts,
|
|
26
|
+
* FE-I18N-1), never the deprecated `requestLocale`. An unrecognised locale resolves to the default before the loader runs, so a
|
|
27
|
+
* missing catalog file is never imported.
|
|
28
|
+
*/
|
|
29
|
+
requestConfig: getRequestConfig(async () => {
|
|
30
|
+
const requested: unknown = await routeLocale()
|
|
31
|
+
const locale = hasLocale(routing.locales, requested) ? requested : routing.defaultLocale
|
|
32
|
+
return {
|
|
33
|
+
locale,
|
|
34
|
+
timeZone: PRODUCT_TIME_ZONE,
|
|
35
|
+
messages: await loadMessages(locale),
|
|
36
|
+
getMessageFallback: ({ namespace, key }: MissingMessage) => `${app}:${namespace ?? ""}.${key}`,
|
|
37
|
+
}
|
|
38
|
+
}),
|
|
39
|
+
/**
|
|
40
|
+
* The language the address states, its catalog and the product time zone. An unknown segment is a route that does not exist,
|
|
41
|
+
* not a request to fall back silently.
|
|
42
|
+
*/
|
|
43
|
+
readLocaleSegment: async (params: Promise<{ readonly locale: string }>) => {
|
|
44
|
+
const { locale } = await params
|
|
45
|
+
if (!hasLocale(routing.locales, locale)) notFound()
|
|
46
|
+
setRequestLocale(locale)
|
|
47
|
+
return { locale, messages: await getMessages(), timeZone: PRODUCT_TIME_ZONE }
|
|
48
|
+
},
|
|
49
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import "server-only"
|
|
2
|
+
import createMiddleware from "next-intl/middleware"
|
|
3
|
+
import { NextResponse, type NextRequest } from "next/server"
|
|
4
|
+
import { routing } from "./routing"
|
|
5
|
+
|
|
6
|
+
/** The first path segments of the API, the health probe and the framework: never locale-negotiated. */
|
|
7
|
+
const UNNEGOTIATED_ROOTS: ReadonlySet<string> = new Set(["api", "health", "_next", "_vercel"])
|
|
8
|
+
|
|
9
|
+
/** Whether the path belongs to the API, the health probe, the framework or a file with an extension. */
|
|
10
|
+
const isUnnegotiated = (pathname: string): boolean => {
|
|
11
|
+
const segments = pathname.split("/")
|
|
12
|
+
const last = segments.at(-1) ?? ""
|
|
13
|
+
return UNNEGOTIATED_ROOTS.has(segments[1] ?? "") || (last.includes(".") && !last.endsWith("."))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const negotiate = createMiddleware(routing)
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The one thing that runs before a route exists: which language it is in. next-intl's middleware reads the cookie, falls back to
|
|
20
|
+
* the default and serves the default locale (vi) without a prefix. One routing table for every app; each app's `src/proxy.ts`
|
|
21
|
+
* re-exports this.
|
|
22
|
+
*/
|
|
23
|
+
export const proxy = (request: NextRequest) =>
|
|
24
|
+
isUnnegotiated(request.nextUrl.pathname) ? NextResponse.next() : negotiate(request)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineRouting } from "next-intl/routing"
|
|
2
|
+
|
|
3
|
+
/** The locales every app of the product serves; every catalog of an app has the same keys in each. */
|
|
4
|
+
const LOCALES = ["vi"] as const
|
|
5
|
+
|
|
6
|
+
/** The locale served at the unprefixed path, and the language of a document no locale reached (the global error boundary). */
|
|
7
|
+
export const DEFAULT_LOCALE = "vi"
|
|
8
|
+
|
|
9
|
+
/** The product's time zone: fixed, not inferred, so the server and the hydrated client format the same instant the same way. */
|
|
10
|
+
export const PRODUCT_TIME_ZONE = "Asia/Ho_Chi_Minh"
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The one routing table of the product, for the proxy, the navigation and the request config of every app: vi default, a prefix
|
|
14
|
+
* only when the locale is not the default, so `/vi` means the same thing on every app.
|
|
15
|
+
*/
|
|
16
|
+
export const routing = defineRouting({
|
|
17
|
+
locales: LOCALES,
|
|
18
|
+
defaultLocale: DEFAULT_LOCALE,
|
|
19
|
+
localePrefix: "as-needed",
|
|
20
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { I18nProvider } from "@heroui/react"
|
|
4
|
+
import { NextIntlClientProvider } from "next-intl"
|
|
5
|
+
import type { ReactNode } from "react"
|
|
6
|
+
|
|
7
|
+
/** What the provider stack takes: the locale resolved on the server, its catalog, the product time zone and the tree it wraps. */
|
|
8
|
+
type ProvidersProps = {
|
|
9
|
+
readonly locale: string
|
|
10
|
+
readonly messages: Record<string, unknown>
|
|
11
|
+
readonly timeZone: string
|
|
12
|
+
readonly children: ReactNode
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The two contexts above every route: next-intl's copy context and React Aria's locale for the grammar's controls. Both take the
|
|
17
|
+
* same locale, so the sentences and the controls of a page speak one language.
|
|
18
|
+
*/
|
|
19
|
+
export const Providers = (props: ProvidersProps) => (
|
|
20
|
+
<NextIntlClientProvider locale={props.locale} messages={props.messages} timeZone={props.timeZone}>
|
|
21
|
+
<I18nProvider locale={props.locale}>{props.children}</I18nProvider>
|
|
22
|
+
</NextIntlClientProvider>
|
|
23
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Alert } from "@starci/grammar/common"
|
|
2
|
+
|
|
3
|
+
/** The words of a recoverable failure and the one way out of it. */
|
|
4
|
+
type ErrorNoticeProps = {
|
|
5
|
+
readonly title: string
|
|
6
|
+
readonly retryLabel: string
|
|
7
|
+
/** Re-render the segment that failed. */
|
|
8
|
+
readonly onRetry: () => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** A failure shown as an assertive banner with its one recovery action, in place of a blank page. */
|
|
12
|
+
export const ErrorNotice = (props: ErrorNoticeProps) => (
|
|
13
|
+
<Alert title={props.title} tone="negative" action={{ label: props.retryLabel, onAction: props.onRetry }} />
|
|
14
|
+
)
|
package/templates/fe/skeleton/packages/__project__-ui/src/composites/GlobalErrorNotice/index.tsx
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Alert, GrammarRoot } from "@starci/grammar/common"
|
|
2
|
+
|
|
3
|
+
/** The document language, the words of the failure and the one way out of it. */
|
|
4
|
+
type GlobalErrorNoticeProps = {
|
|
5
|
+
readonly lang: string
|
|
6
|
+
readonly title: string
|
|
7
|
+
readonly retryLabel: string
|
|
8
|
+
/** Re-render the whole app. */
|
|
9
|
+
readonly onRetry: () => void
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** The last-resort failure: the whole document, drawn here because this boundary replaces the layout that would have drawn it. */
|
|
13
|
+
export const GlobalErrorNotice = (props: GlobalErrorNoticeProps) => (
|
|
14
|
+
<html lang={props.lang}>
|
|
15
|
+
<body>
|
|
16
|
+
<GrammarRoot>
|
|
17
|
+
<Alert
|
|
18
|
+
title={props.title}
|
|
19
|
+
tone="negative"
|
|
20
|
+
action={{ label: props.retryLabel, onAction: props.onRetry }}
|
|
21
|
+
/>
|
|
22
|
+
</GrammarRoot>
|
|
23
|
+
</body>
|
|
24
|
+
</html>
|
|
25
|
+
)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Spinner } from "@starci/grammar/common"
|
|
2
|
+
|
|
3
|
+
/** The word a wait announces. */
|
|
4
|
+
type LoadingNoticeProps = {
|
|
5
|
+
readonly label: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** A wait shown as one announced spinner while a route resolves. */
|
|
9
|
+
export const LoadingNotice = (props: LoadingNoticeProps) => <Spinner label={props.label} />
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ReactNode } from "react"
|
|
2
|
+
import { Providers } from "../../branches/Providers"
|
|
3
|
+
|
|
4
|
+
/** What the app's locale layout resolves before mounting the shell (the i18n package's readLocaleSegment). */
|
|
5
|
+
type LocaleShellProps = {
|
|
6
|
+
readonly locale: string
|
|
7
|
+
readonly messages: Record<string, unknown>
|
|
8
|
+
readonly timeZone: string
|
|
9
|
+
readonly children: ReactNode
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** The document of one route language: `<html lang>` from the address and the provider stack; the app's own chrome is the children. */
|
|
13
|
+
export const LocaleShell = (props: LocaleShellProps) => (
|
|
14
|
+
<html lang={props.locale}>
|
|
15
|
+
<body>
|
|
16
|
+
<Providers locale={props.locale} messages={props.messages} timeZone={props.timeZone}>
|
|
17
|
+
{props.children}
|
|
18
|
+
</Providers>
|
|
19
|
+
</body>
|
|
20
|
+
</html>
|
|
21
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Heading, TextAction } from "@starci/grammar/common"
|
|
2
|
+
|
|
3
|
+
/** The words of a page that does not exist and the way back. */
|
|
4
|
+
type NotFoundNoticeProps = {
|
|
5
|
+
readonly title: string
|
|
6
|
+
readonly homeLabel: string
|
|
7
|
+
/** The app's front door. */
|
|
8
|
+
readonly homeHref: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** A missing page: the message and the way back to the app's front door. */
|
|
12
|
+
export const NotFoundNotice = (props: NotFoundNoticeProps) => (
|
|
13
|
+
<>
|
|
14
|
+
<Heading level={1}>{props.title}</Heading>
|
|
15
|
+
<TextAction appearance="inline" href={props.homeHref}>
|
|
16
|
+
{props.homeLabel}
|
|
17
|
+
</TextAction>
|
|
18
|
+
</>
|
|
19
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ReactNode } from "react"
|
|
2
|
+
import { GrammarRoot, PageContainer, TextAction, TopBar, WorkspaceShell } from "@starci/grammar/common"
|
|
3
|
+
import { siteShellClassNames } from "./classNames"
|
|
4
|
+
|
|
5
|
+
/** What an app's chrome hands the shell: the brand, its home link and the routed body. */
|
|
6
|
+
type SiteShellProps = {
|
|
7
|
+
/** The wordmark; it also names the page's main landmark. */
|
|
8
|
+
readonly brand: string
|
|
9
|
+
/** The destination of the wordmark: the app's front door. */
|
|
10
|
+
readonly homeHref: string
|
|
11
|
+
/** The routed page body. */
|
|
12
|
+
readonly children: ReactNode
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The document chrome both apps share: Grammar's Common boundary, the brand header (the top bar carrying the wordmark that links
|
|
17
|
+
* home), then the routed body in the shell's main landmark at reading measure. Colours are the theme's semantic tokens.
|
|
18
|
+
*/
|
|
19
|
+
{{> fe/common/site-shell.tsx.partial}}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { ErrorNotice } from "./composites/ErrorNotice"
|
|
2
|
+
export { GlobalErrorNotice } from "./composites/GlobalErrorNotice"
|
|
3
|
+
export { LoadingNotice } from "./composites/LoadingNotice"
|
|
4
|
+
export { LocaleShell } from "./composites/LocaleShell"
|
|
5
|
+
export { NotFoundNotice } from "./composites/NotFoundNotice"
|
|
6
|
+
export { SiteShell } from "./composites/SiteShell"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { dirname, join } from "node:path"
|
|
2
|
+
import { fileURLToPath } from "node:url"
|
|
3
|
+
import type { NextConfig } from "next"
|
|
4
|
+
import createNextIntlPlugin from "next-intl/plugin"
|
|
5
|
+
|
|
6
|
+
/** The request config lives in this app's i18n module. */
|
|
7
|
+
const withNextIntl = createNextIntlPlugin("./src/modules/i18n/request.ts")
|
|
8
|
+
|
|
9
|
+
/** The npm workspace root, used by Turbopack and output tracing. */
|
|
10
|
+
const WORKSPACE_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "..")
|
|
11
|
+
|
|
12
|
+
/** Next config of the web app. */
|
|
13
|
+
const nextConfig: NextConfig = {
|
|
14
|
+
output: "standalone",
|
|
15
|
+
reactStrictMode: true,
|
|
16
|
+
experimental: { rootParams: true },
|
|
17
|
+
outputFileTracingRoot: WORKSPACE_ROOT,
|
|
18
|
+
turbopack: { root: WORKSPACE_ROOT },
|
|
19
|
+
poweredByHeader: false,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default withNextIntl(nextConfig)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { AppErrorPage } from "@/features/pages/AppErrorPage"
|
|
4
|
+
|
|
5
|
+
type ErrorProps = { readonly reset: () => void }
|
|
6
|
+
|
|
7
|
+
/** The locale segment's error boundary slot. */
|
|
8
|
+
const ErrorBoundary = (props: ErrorProps) => <AppErrorPage onRetry={props.reset} />
|
|
9
|
+
|
|
10
|
+
export default ErrorBoundary
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { hasLocale } from "next-intl"
|
|
2
|
+
import { getMessages, setRequestLocale } from "next-intl/server"
|
|
3
|
+
import { notFound } from "next/navigation"
|
|
4
|
+
import type { ReactNode } from "react"
|
|
5
|
+
import { AppLayout, appLayoutMetadata } from "@/features/layouts/AppLayout"
|
|
6
|
+
import { PRODUCT_TIME_ZONE, routing } from "@/modules/i18n"
|
|
7
|
+
import { Providers } from "./providers"
|
|
8
|
+
import "../globals.css"
|
|
9
|
+
import "@/modules/brand"
|
|
10
|
+
|
|
11
|
+
type LayoutProps = {
|
|
12
|
+
readonly children: ReactNode
|
|
13
|
+
readonly params: Promise<{ readonly locale: string }>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** The localized document title of this route segment. */
|
|
17
|
+
export const generateMetadata = async (props: LayoutProps) => appLayoutMetadata((await props.params).locale)
|
|
18
|
+
|
|
19
|
+
/** The locale segment's document, providers and app chrome. */
|
|
20
|
+
const Layout = async (props: LayoutProps) => {
|
|
21
|
+
const { locale } = await props.params
|
|
22
|
+
if (!hasLocale(routing.locales, locale)) notFound()
|
|
23
|
+
setRequestLocale(locale)
|
|
24
|
+
const messages = await getMessages()
|
|
25
|
+
return (
|
|
26
|
+
<AppLayout
|
|
27
|
+
locale={locale}
|
|
28
|
+
content={
|
|
29
|
+
<Providers locale={locale} messages={messages} timeZone={PRODUCT_TIME_ZONE}>
|
|
30
|
+
{props.children}
|
|
31
|
+
</Providers>
|
|
32
|
+
}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default Layout
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AppHomePage, appHomeMetadata } from "@/features/pages/AppHomePage"
|
|
2
|
+
|
|
3
|
+
/** The document title of this page. */
|
|
4
|
+
export const generateMetadata = appHomeMetadata
|
|
5
|
+
|
|
6
|
+
/** The locale root's page slot. */
|
|
7
|
+
const Page = () => <AppHomePage />
|
|
8
|
+
|
|
9
|
+
export default Page
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { I18nProvider } from "@heroui/react"
|
|
4
|
+
import { NextIntlClientProvider } from "next-intl"
|
|
5
|
+
import { useEffect, type ReactNode } from "react"
|
|
6
|
+
import { subscribeToAuthRefresh } from "@/modules/db/browser"
|
|
7
|
+
import { navigation } from "@/modules/i18n"
|
|
8
|
+
|
|
9
|
+
/** What the provider stack takes from the locale layout. */
|
|
10
|
+
type ProvidersProps = {
|
|
11
|
+
readonly locale: string
|
|
12
|
+
readonly messages: Record<string, unknown>
|
|
13
|
+
readonly timeZone: string
|
|
14
|
+
readonly children: ReactNode
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** The copy, React Aria and auth-refresh contexts above every route. */
|
|
18
|
+
export const Providers = (props: ProvidersProps) => {
|
|
19
|
+
const router = navigation.useRouter()
|
|
20
|
+
useEffect(() => subscribeToAuthRefresh(() => router.refresh()), [router])
|
|
21
|
+
return (
|
|
22
|
+
<NextIntlClientProvider locale={props.locale} messages={props.messages} timeZone={props.timeZone}>
|
|
23
|
+
<I18nProvider locale={props.locale}>{props.children}</I18nProvider>
|
|
24
|
+
</NextIntlClientProvider>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import "server-only"
|
|
2
|
+
|
|
3
|
+
import type { NextRequest } from "next/server"
|
|
4
|
+
import { NextResponse } from "next/server"
|
|
5
|
+
import { exchangeAuthCode } from "@/modules/db"
|
|
6
|
+
import { safeNextPath } from "@/modules/routes"
|
|
7
|
+
|
|
8
|
+
const destinationOf = (request: NextRequest): URL => {
|
|
9
|
+
const path = safeNextPath(request.nextUrl.searchParams.get("next"), request.nextUrl.origin)
|
|
10
|
+
return new URL(path, request.nextUrl.origin)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Completes Supabase's PKCE exchange and returns only to a same-origin path. */
|
|
14
|
+
export const GET = async (request: NextRequest): Promise<NextResponse> => {
|
|
15
|
+
const destination = destinationOf(request)
|
|
16
|
+
const code = request.nextUrl.searchParams.get("code")
|
|
17
|
+
if (code === null) {
|
|
18
|
+
destination.searchParams.set("auth", "invalid")
|
|
19
|
+
return NextResponse.redirect(destination)
|
|
20
|
+
}
|
|
21
|
+
const exchanged = await exchangeAuthCode(code)
|
|
22
|
+
if (exchanged.kind !== "ok") destination.searchParams.set("auth", exchanged.kind)
|
|
23
|
+
return NextResponse.redirect(destination)
|
|
24
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { AppGlobalErrorPage } from "@/features/pages/AppGlobalErrorPage"
|
|
4
|
+
|
|
5
|
+
type GlobalErrorProps = { readonly reset: () => void }
|
|
6
|
+
|
|
7
|
+
/** The last-resort error boundary slot. */
|
|
8
|
+
const GlobalError = (props: GlobalErrorProps) => <AppGlobalErrorPage onRetry={props.reset} />
|
|
9
|
+
|
|
10
|
+
export default GlobalError
|