@starci/hfs 4.0.8 → 4.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +81 -39
- package/emit/contracts.mjs +56 -9
- package/emit/db-types.mjs +169 -0
- package/emit/events.mjs +41 -0
- package/emit/operations-worker.mjs +1 -1
- package/emit/operations.mjs +2 -2
- package/emit/schema-worker.mjs +1 -1
- package/lint/bound-sys.cjs +50 -0
- package/lint/run.mjs +131 -24
- package/package.json +16 -10
- package/report/sonar.mjs +8 -8
- package/runtime/engine/admission.mjs +308 -0
- package/runtime/engine/canonical-json.mjs +10 -0
- package/runtime/engine/config.mjs +486 -0
- package/runtime/engine/db/blob.mjs +315 -0
- package/runtime/engine/db/ledger-paths.mjs +83 -0
- package/runtime/engine/db/ledger.mjs +1118 -0
- package/runtime/engine/db/machine-connection.mjs +135 -0
- package/runtime/engine/db/machine-schema.mjs +84 -0
- package/runtime/engine/db/machine.mjs +1367 -0
- package/runtime/engine/db/migrations/machine/0001-init.sql +924 -0
- package/runtime/engine/db/migrations/runtime/0001-init.sql +1108 -0
- package/runtime/engine/db/provider-reservations.mjs +101 -0
- package/runtime/engine/digest.mjs +16 -0
- package/runtime/engine/invalid-config.mjs +15 -0
- package/runtime/engine/orca-config.mjs +27 -0
- package/runtime/engine/refuse.mjs +11 -0
- package/runtime/engine/secrets.mjs +130 -0
- package/runtime/knowledge/hfs/canon-pins.yaml +162 -31
- package/runtime/knowledge/hfs/peer-integrations.yaml +2 -2
- package/runtime/knowledge/hfs/rules.yaml +2059 -0
- package/runtime/knowledge/hfs/slots.yaml +912 -120
- package/runtime/knowledge/patterns/be/api.yaml +369 -0
- package/runtime/knowledge/patterns/be/cli.yaml +297 -0
- package/runtime/knowledge/patterns/be/domain.yaml +113 -0
- package/runtime/knowledge/patterns/be/event-bus.yaml +285 -0
- package/runtime/knowledge/patterns/be/jobs.yaml +261 -0
- package/runtime/knowledge/patterns/be/projections.yaml +178 -0
- package/runtime/knowledge/patterns/be/queues.yaml +236 -0
- package/runtime/knowledge/patterns/be/reactors.yaml +140 -0
- package/runtime/knowledge/patterns/be/realtime.yaml +222 -0
- package/runtime/knowledge/patterns/be/saga.yaml +248 -0
- package/runtime/knowledge/patterns/be/webhooks.yaml +221 -0
- package/runtime/knowledge/patterns/fe/folder.yaml +131 -25
- package/runtime/knowledge/sonar-gate.yaml +52 -18
- package/runtime/modules/kernel/failure-codes.yaml +611 -51
- package/runtime/modules/models/registry.yaml +553 -0
- package/runtime/modules/models/runtimes.yaml +695 -0
- package/runtime/modules/ops/_labels.yaml +53 -0
- package/runtime/scripts/api/fs/forbidden-root.mjs +51 -0
- package/runtime/scripts/api/fs/is-link-like.mjs +25 -0
- package/runtime/scripts/api/fs/lib.mjs +16 -2
- package/runtime/scripts/api/fs/safe-remove.mjs +12 -132
- package/runtime/scripts/api/git/config-get.mjs +10 -0
- package/runtime/scripts/api/git/diff.mjs +5 -0
- package/runtime/scripts/api/git/lib.mjs +18 -26
- package/runtime/scripts/api/git/log.mjs +5 -0
- package/runtime/scripts/api/git/ls-files.mjs +6 -0
- package/runtime/scripts/api/git/ls-tree.mjs +5 -0
- package/runtime/scripts/api/git/merge-base.mjs +9 -0
- package/runtime/scripts/api/git/remote.mjs +5 -0
- package/runtime/scripts/api/git/rev-parse-query.mjs +5 -0
- package/runtime/scripts/api/git/show.mjs +6 -0
- package/runtime/scripts/api/node/lib.mjs +14 -0
- package/runtime/scripts/api/node/spawn-node.mjs +6 -0
- package/runtime/scripts/api/process/lib.mjs +111 -0
- package/runtime/scripts/api/process/owned-process.mjs +78 -0
- package/runtime/scripts/api/process/resolve-real-tool.mjs +46 -0
- package/runtime/scripts/api/process/run-program.mjs +7 -0
- package/runtime/scripts/api/process/stop-owned-process.mjs +9 -0
- package/runtime/scripts/api/sops/decrypt.mjs +9 -12
- package/runtime/scripts/api/sops/lib.mjs +255 -0
- package/runtime/scripts/api/sops/seal.mjs +22 -0
- package/runtime/scripts/connectors/lib.mjs +488 -0
- package/runtime/scripts/hfs/architecture/ast-walks.mjs +220 -0
- package/runtime/scripts/hfs/architecture/backend.mjs +16 -23
- package/runtime/scripts/hfs/architecture/background-unowned.mjs +16 -34
- package/runtime/scripts/hfs/architecture/client-reaches-server.mjs +3 -1
- package/runtime/scripts/hfs/architecture/clones.mjs +4 -4
- package/runtime/scripts/hfs/architecture/config.mjs +9 -6
- package/runtime/scripts/hfs/architecture/connection-map.mjs +20 -8
- package/runtime/scripts/hfs/architecture/context-coupling.mjs +88 -0
- package/runtime/scripts/hfs/architecture/context-map.mjs +237 -0
- package/runtime/scripts/hfs/architecture/context-owner.mjs +82 -0
- package/runtime/scripts/hfs/architecture/context-platform-tables.mjs +47 -0
- package/runtime/scripts/hfs/architecture/context-transaction.mjs +60 -0
- package/runtime/scripts/hfs/architecture/contract-fixture-guard.mjs +4 -10
- package/runtime/scripts/hfs/architecture/contracts.mjs +33 -162
- package/runtime/scripts/hfs/architecture/dead-exports.mjs +58 -29
- package/runtime/scripts/hfs/architecture/doc-language.mjs +1 -1
- package/runtime/scripts/hfs/architecture/entrypoint.mjs +2 -1
- package/runtime/scripts/hfs/architecture/fe-slot-allows.mjs +2 -2
- package/runtime/scripts/hfs/architecture/feature-shape.mjs +5 -2
- package/runtime/scripts/hfs/architecture/framework-pinned.mjs +1 -1
- package/runtime/scripts/hfs/architecture/frontend.mjs +17 -43
- package/runtime/scripts/hfs/architecture/hfs.mjs +24 -39
- package/runtime/scripts/hfs/architecture/i18n-keys.mjs +1 -1
- package/runtime/scripts/hfs/architecture/index.mjs +17 -4
- package/runtime/scripts/hfs/architecture/machine-ast.mjs +44 -11
- package/runtime/scripts/hfs/architecture/managed-scripts.mjs +27 -0
- package/runtime/scripts/hfs/architecture/module-per-transport.mjs +30 -6
- package/runtime/scripts/hfs/architecture/next-data.mjs +22 -63
- package/runtime/scripts/hfs/architecture/owners.mjs +35 -15
- package/runtime/scripts/hfs/architecture/register-once.mjs +2 -1
- package/runtime/scripts/hfs/architecture/registration.mjs +23 -81
- package/runtime/scripts/hfs/architecture/required-files.mjs +20 -12
- package/runtime/scripts/hfs/architecture/schema-owner.mjs +17 -114
- package/runtime/scripts/hfs/architecture/server-action.mjs +24 -0
- package/runtime/scripts/hfs/architecture/side-boundary.mjs +16 -0
- package/runtime/scripts/hfs/architecture/source-names.mjs +27 -147
- package/runtime/scripts/hfs/architecture/sql-owner.mjs +59 -18
- package/runtime/scripts/hfs/architecture/sql-returning.mjs +64 -0
- package/runtime/scripts/hfs/architecture/supabase-ast.mjs +111 -0
- package/runtime/scripts/hfs/architecture/supabase-be.mjs +131 -0
- package/runtime/scripts/hfs/architecture/supabase-tables.mjs +42 -0
- package/runtime/scripts/hfs/architecture/supabase.mjs +434 -0
- package/runtime/scripts/hfs/architecture/surface.mjs +9 -3
- package/runtime/scripts/hfs/architecture/test-world-files.mjs +9 -19
- package/runtime/scripts/hfs/architecture/tiers.mjs +47 -5
- package/runtime/scripts/hfs/architecture/transport-owner.mjs +3 -3
- package/runtime/scripts/hfs/architecture/typescript.mjs +12 -26
- package/runtime/scripts/hfs/architecture.mjs +4 -4
- package/runtime/scripts/hfs/check.mjs +75 -72
- package/runtime/scripts/hfs/coverage-scope.mjs +162 -0
- package/runtime/scripts/hfs/declaration-shape.mjs +62 -0
- package/runtime/scripts/hfs/declaration-slots.mjs +75 -0
- package/runtime/scripts/hfs/edition-slots.mjs +66 -0
- package/runtime/scripts/hfs/manifest-shape.mjs +109 -32
- package/runtime/scripts/hfs/param-names.mjs +18 -0
- package/runtime/scripts/hfs/path-findings.mjs +1 -1
- package/runtime/scripts/hfs/repo-identity.mjs +9 -6
- package/runtime/scripts/hfs/rule-params-shape.mjs +50 -0
- package/runtime/scripts/hfs/rules/app-root.mjs +51 -0
- package/runtime/scripts/hfs/rules/cli.mjs +37 -0
- package/runtime/scripts/hfs/rules/contract-compat.mjs +71 -0
- package/runtime/scripts/hfs/rules/contract.mjs +10 -9
- package/runtime/scripts/hfs/rules/database-config.mjs +102 -0
- package/runtime/scripts/hfs/rules/database-constants.mjs +13 -0
- package/runtime/scripts/hfs/rules/database-migrations.mjs +111 -0
- package/runtime/scripts/hfs/rules/database-plpgsql.mjs +233 -0
- package/runtime/scripts/hfs/rules/database-sql.mjs +336 -0
- package/runtime/scripts/hfs/rules/database.mjs +68 -0
- package/runtime/scripts/hfs/rules/deps.mjs +1 -1
- package/runtime/scripts/hfs/rules/docker.mjs +259 -0
- package/runtime/scripts/hfs/rules/edition.mjs +111 -0
- package/runtime/scripts/hfs/rules/event-bus.mjs +153 -0
- package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +1 -1
- package/runtime/scripts/hfs/rules/fe-no-tests.mjs +6 -5
- package/runtime/scripts/hfs/rules/frontend-tree.mjs +9 -9
- package/runtime/scripts/hfs/rules/integration-specs.mjs +3 -6
- package/runtime/scripts/hfs/rules/kinds.mjs +84 -0
- package/runtime/scripts/hfs/rules/lint-suppression.mjs +1 -1
- package/runtime/scripts/hfs/rules/monorepo.mjs +179 -0
- package/runtime/scripts/hfs/rules/peer-integrations.mjs +3 -3
- package/runtime/scripts/hfs/rules/pipeline.mjs +11 -21
- package/runtime/scripts/hfs/rules/proof-commands.mjs +2 -2
- package/runtime/scripts/hfs/rules/read.mjs +1 -1
- package/runtime/scripts/hfs/rules/repo-local-checks.mjs +2 -2
- package/runtime/scripts/hfs/rules/saga.mjs +170 -0
- package/runtime/scripts/hfs/rules/secrets.mjs +3 -3
- package/runtime/scripts/hfs/rules/services.mjs +220 -0
- package/runtime/scripts/hfs/rules/spec-placement.mjs +1 -1
- package/runtime/scripts/hfs/rules/stacks.mjs +3 -3
- package/runtime/scripts/hfs/rules/supabase-secrets.mjs +89 -0
- package/runtime/scripts/hfs/rules/test-topology.mjs +2 -2
- package/runtime/scripts/hfs/secret.mjs +209 -0
- package/runtime/scripts/hfs/slots.mjs +78 -108
- package/runtime/scripts/hfs/sql/pg-parse.mjs +46 -0
- package/runtime/scripts/hfs/test-world-slot.mjs +6 -0
- package/runtime/scripts/hfs/tree.mjs +5 -4
- package/runtime/scripts/hfs/typescript-programs.mjs +0 -5
- package/runtime/scripts/hfs/view.mjs +3 -2
- package/runtime/scripts/lib/clip.mjs +19 -0
- package/runtime/scripts/lib/display-names.mjs +259 -0
- package/runtime/scripts/lib/dockerfile.mjs +124 -0
- package/runtime/scripts/lib/env.mjs +10 -0
- package/runtime/scripts/lib/event-contract.mjs +103 -0
- package/runtime/scripts/lib/example-refs.mjs +158 -0
- package/runtime/scripts/lib/fs-kind.mjs +14 -4
- package/runtime/scripts/lib/git.mjs +36 -0
- package/runtime/scripts/lib/graphql-contract.mjs +1 -1
- package/runtime/scripts/lib/i18n.mjs +86 -0
- package/runtime/scripts/lib/json-schema.mjs +52 -0
- package/runtime/scripts/lib/json.mjs +13 -3
- package/runtime/scripts/lib/language.mjs +24 -5
- package/runtime/scripts/lib/list.mjs +20 -0
- package/runtime/scripts/lib/mutation-fence.mjs +15 -0
- package/runtime/scripts/lib/package-at.mjs +37 -0
- package/runtime/scripts/lib/path-key.mjs +57 -2
- package/runtime/scripts/lib/process-identity.mjs +6 -0
- package/runtime/scripts/lib/read-text.mjs +34 -0
- package/runtime/scripts/lib/read-yaml.mjs +18 -0
- package/runtime/scripts/lib/redact.mjs +161 -0
- package/runtime/scripts/lib/regex.mjs +4 -0
- package/runtime/scripts/lib/same-text.mjs +5 -0
- package/runtime/scripts/lib/secret-patterns.mjs +4 -3
- package/runtime/scripts/lib/sleep-sync.mjs +2 -1
- package/runtime/scripts/lib/sleep.mjs +7 -0
- package/runtime/scripts/lib/sops-envelope.mjs +112 -0
- package/runtime/scripts/lib/source-phrases.mjs +34 -0
- package/runtime/scripts/lib/sqlite.mjs +21 -0
- package/runtime/scripts/lib/stack-services.mjs +7 -31
- package/runtime/scripts/lib/ts-ast.mjs +35 -0
- package/runtime/scripts/lib/walk.mjs +4 -3
- package/scaffold/add-app.mjs +174 -0
- package/scaffold/add-cli-lite.mjs +257 -0
- package/scaffold/add-inbox-lite.mjs +314 -0
- package/scaffold/add-table.mjs +344 -0
- package/scaffold/add.mjs +299 -0
- package/scaffold/app.mjs +358 -69
- package/scaffold/edition-gate.mjs +25 -0
- package/scaffold/image.mjs +19 -0
- package/scaffold/lite-exports.mjs +186 -0
- package/scaffold/service.mjs +32 -26
- package/scaffold/supabase-ports.mjs +26 -0
- package/src/main.mjs +327 -0
- package/sync/cli.mjs +6 -9
- package/sync/format.mjs +1 -1
- package/sync/hygiene.mjs +10 -10
- package/sync/index.mjs +167 -104
- package/sync/managed.mjs +19 -11
- package/sync/sonar-key.mjs +5 -0
- package/templates/app/ci-workflows/github/workflows/ci.yml +14 -14
- package/templates/app/ci-workflows/github/workflows/images.yml +37 -0
- package/templates/app/ci-workflows/sonar-steps.yml +9 -0
- package/templates/app/ci-workflows-lite/github/workflows/ci.yml +66 -0
- package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +31 -0
- package/templates/app/ci-workflows-lite/github/workflows/images.yml +37 -0
- package/templates/app/codegen-lite/scripts/codegen.mjs +32 -0
- package/templates/app/docker-ignore/dockerignore +50 -0
- package/templates/app/gitignore-lite +35 -0
- package/templates/app/hooks/husky/pre-commit +3 -8
- package/templates/app/hooks/husky/pre-push +45 -6
- package/templates/app/package-scripts/core.json +8 -0
- package/templates/app/package-scripts/package.json +3 -10
- package/templates/app/package-scripts-lite/package.json +15 -0
- package/templates/app/quality-config/codecov.yml +15 -3
- package/templates/app/quality-config/sonar-base.properties +4 -0
- package/templates/app/quality-config/sonar-project.properties +1 -4
- package/templates/app/quality-config-lite/sonar-project.properties +5 -0
- package/templates/app/skeleton/.starcistacks/dev/seeds/primary-notes.sql +5 -0
- package/templates/app/skeleton/.starciwork/features/system-health/index.yaml +4 -0
- package/templates/app/skeleton/.starciwork/{features/index.yaml → index.yaml} +2 -2
- package/templates/app/skeleton/README.md +7 -5
- package/templates/app/skeleton-lite/.sops.yaml +3 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/environment.json +5 -0
- package/templates/app/skeleton-lite/.starcistacks/dev/secrets/.gitkeep +1 -0
- package/templates/app/skeleton-lite/.starciwork/shell/index.yaml +55 -0
- package/templates/app/skeleton-lite/README.md +40 -0
- package/templates/app/skeleton-lite/supabase/config.toml +41 -0
- package/templates/app/skeleton-lite/supabase/migrations/__timestamp___baseline.sql +56 -0
- package/templates/app/skeleton-lite/supabase/seed.sql +0 -0
- package/templates/app/task-graph/turbo.json +23 -0
- package/templates/app/tool-config-lite/prettierignore +2 -0
- package/templates/app/tool-config-lite/prettierrc +1 -0
- package/templates/app/upgrade-full/.starcistacks/application-stacks.yaml +38 -0
- package/templates/app/upgrade-full/.starcistacks/dev/README.md +10 -0
- package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/api.yaml +13 -0
- package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/compose.yaml +3 -0
- package/templates/app/upgrade-full/.starcistacks/dev/infra/compose/postgres.yaml +12 -0
- package/templates/app/upgrade-full/.starcistacks/dev/infra/metadata.json +7 -0
- package/templates/be/common/main-listen.ts.partial +14 -0
- package/templates/be/common/sql-ident.ts.partial +7 -0
- package/templates/be/common/sql-tag.ts.partial +5 -0
- package/templates/be/image/api/Dockerfile +38 -0
- package/templates/be/image/cli/Dockerfile +38 -0
- package/templates/be/image/worker/Dockerfile +36 -0
- package/templates/be/inbox/database-client.ts.tpl +50 -0
- package/templates/be/inbox/index.ts.tpl +2 -0
- package/templates/be/inbox/migration.sql.tpl +29 -0
- package/templates/be/inbox/module-definition.ts.tpl +6 -0
- package/templates/be/inbox/module.ts.tpl +14 -0
- package/templates/be/inbox/options.ts.tpl +2 -0
- package/templates/be/inbox/service.ts.tpl +33 -0
- package/templates/be/inbox/sql.ts.tpl +16 -0
- package/templates/be/inbox/webhook-door.ts.tpl +36 -0
- package/templates/be/patterns/api/application.command.http.ts.tpl +10 -0
- package/templates/be/patterns/api/application.command.ts.tpl +10 -0
- package/templates/be/patterns/api/application.contracts.ts.tpl +11 -0
- package/templates/be/patterns/api/application.handler.http.ts.tpl +22 -0
- package/templates/be/patterns/api/application.handler.ts.tpl +22 -0
- package/templates/be/patterns/api/feature.index.http.ts.tpl +1 -0
- package/templates/be/patterns/api/feature.index.ts.tpl +1 -0
- package/templates/be/patterns/api/feature.module.ts.tpl +6 -0
- package/templates/be/patterns/api/graphql.input.ts.tpl +13 -0
- package/templates/be/patterns/api/graphql.mapper.ts.tpl +9 -0
- package/templates/be/patterns/api/graphql.module.ts.tpl +7 -0
- package/templates/be/patterns/api/graphql.resolver.ts.tpl +27 -0
- package/templates/be/patterns/api/graphql.type.ts.tpl +9 -0
- package/templates/be/patterns/api/http.controller.ts.tpl +27 -0
- package/templates/be/patterns/api/http.mapper.ts.tpl +9 -0
- package/templates/be/patterns/api/http.module.ts.tpl +7 -0
- package/templates/be/patterns/api/http.request.ts.tpl +10 -0
- package/templates/be/patterns/api/http.response.ts.tpl +5 -0
- package/templates/be/patterns/cli/group.cli.spec.ts.tpl +15 -0
- package/templates/be/patterns/cli/group.cli.ts.tpl +11 -0
- package/templates/be/patterns/cli/group.module.ts.tpl +7 -0
- package/templates/be/patterns/cli/sub.run.cli.spec.ts.tpl +17 -0
- package/templates/be/patterns/cli/sub.run.cli.ts.tpl +15 -0
- package/templates/be/patterns/event-bus/platform/errors/event-bus.error.ts.tpl +22 -0
- package/templates/be/patterns/event-bus/platform/event-bus.config.ts.tpl +19 -0
- package/templates/be/patterns/event-bus/platform/event-bus.contracts.ts.tpl +58 -0
- package/templates/be/patterns/event-bus/platform/event-bus.decorators.ts.tpl +46 -0
- package/templates/be/patterns/event-bus/platform/event-bus.log-events.ts.tpl +12 -0
- package/templates/be/patterns/event-bus/platform/event-bus.module-definition.ts.tpl +10 -0
- package/templates/be/patterns/event-bus/platform/event-bus.module.ts.tpl +52 -0
- package/templates/be/patterns/event-bus/platform/event-bus.options.ts.tpl +19 -0
- package/templates/be/patterns/event-bus/platform/event-bus.port.ts.tpl +28 -0
- package/templates/be/patterns/event-bus/platform/event-bus.service.spec.ts.tpl +165 -0
- package/templates/be/patterns/event-bus/platform/event-bus.service.ts.tpl +93 -0
- package/templates/be/patterns/event-bus/platform/event-envelope.policy.spec.ts.tpl +90 -0
- package/templates/be/patterns/event-bus/platform/event-envelope.policy.ts.tpl +58 -0
- package/templates/be/patterns/event-bus/platform/event-relay.service.spec.ts.tpl +136 -0
- package/templates/be/patterns/event-bus/platform/event-relay.service.ts.tpl +56 -0
- package/templates/be/patterns/event-bus/platform/event-runner.service.spec.ts.tpl +272 -0
- package/templates/be/patterns/event-bus/platform/event-runner.service.ts.tpl +128 -0
- package/templates/be/patterns/event-bus/platform/event-transport.port.ts.tpl +180 -0
- package/templates/be/patterns/event-bus/platform/event.policy.spec.ts.tpl +67 -0
- package/templates/be/patterns/event-bus/platform/event.policy.ts.tpl +38 -0
- package/templates/be/patterns/event-bus/platform/index.ts.tpl +11 -0
- package/templates/be/patterns/event-bus/platform/kafka-event-transport.client.spec.ts.tpl +348 -0
- package/templates/be/patterns/event-bus/platform/kafka-event-transport.client.ts.tpl +241 -0
- package/templates/be/patterns/event-bus/platform/messages/event-bus.messages.ts.tpl +15 -0
- package/templates/be/patterns/event-bus/platform/persistence/connection.ts.tpl +8 -0
- package/templates/be/patterns/event-bus/platform/persistence/entities/event-outbox.entity.ts.tpl +37 -0
- package/templates/be/patterns/event-bus/platform/persistence/event-bus.rows.ts.tpl +11 -0
- package/templates/be/patterns/event-bus/platform/persistence/event-bus.sql.ts.tpl +12 -0
- package/templates/be/patterns/event-bus/platform/persistence/migrations/1789800009000-create-event-outbox.ts.tpl +26 -0
- package/templates/be/patterns/jobs/job.index.ts.tpl +1 -0
- package/templates/be/patterns/jobs/job.module.ts.tpl +6 -0
- package/templates/be/patterns/jobs/job.processor.ts.tpl +20 -0
- package/templates/be/patterns/jobs/job.queue.module.ts.tpl +20 -0
- package/templates/be/patterns/jobs/job.step.ts.tpl +19 -0
- package/templates/be/patterns/jobs/platform/fenced.processor.spec.ts.tpl +31 -0
- package/templates/be/patterns/jobs/platform/fenced.processor.ts.tpl +13 -0
- package/templates/be/patterns/jobs/platform/job-claim.service.spec.ts.tpl +150 -0
- package/templates/be/patterns/jobs/platform/job-claim.service.ts.tpl +100 -0
- package/templates/be/patterns/jobs/platform/job-runner.service.spec.ts.tpl +138 -0
- package/templates/be/patterns/jobs/platform/job-runner.service.ts.tpl +69 -0
- package/templates/be/patterns/jobs/platform/jobs.config.ts.tpl +11 -0
- package/templates/be/patterns/jobs/platform/jobs.contracts.ts.tpl +62 -0
- package/templates/be/patterns/jobs/platform/jobs.decorators.ts.tpl +31 -0
- package/templates/be/patterns/jobs/platform/jobs.error.ts.tpl +22 -0
- package/templates/be/patterns/jobs/platform/jobs.index.ts.tpl +11 -0
- package/templates/be/patterns/jobs/platform/jobs.log-events.ts.tpl +9 -0
- package/templates/be/patterns/jobs/platform/jobs.messages.ts.tpl +15 -0
- package/templates/be/patterns/jobs/platform/jobs.module-definition.ts.tpl +10 -0
- package/templates/be/patterns/jobs/platform/jobs.module.ts.tpl +32 -0
- package/templates/be/patterns/jobs/platform/jobs.options.ts.tpl +11 -0
- package/templates/be/patterns/jobs/platform/jobs.port.ts.tpl +36 -0
- package/templates/be/patterns/jobs/platform/persistence.connection.ts.tpl +8 -0
- package/templates/be/patterns/jobs/platform/persistence.job.entity.ts.tpl +53 -0
- package/templates/be/patterns/jobs/platform/persistence.jobs.rows.ts.tpl +13 -0
- package/templates/be/patterns/jobs/platform/persistence.jobs.sql.ts.tpl +33 -0
- package/templates/be/patterns/jobs/platform/persistence.migration.ts.tpl +29 -0
- package/templates/be/patterns/outbox/platform/index.ts.tpl +2 -0
- package/templates/be/patterns/outbox/platform/outbox-relay.policy.spec.ts.tpl +96 -0
- package/templates/be/patterns/outbox/platform/outbox-relay.policy.ts.tpl +78 -0
- package/templates/be/patterns/outbox/platform/outbox.log-events.ts.tpl +5 -0
- package/templates/be/patterns/projections/migration.ts.tpl +18 -0
- package/templates/be/patterns/projections/persistence.connection.ts.tpl +8 -0
- package/templates/be/patterns/projections/projection.entity.ts.tpl +9 -0
- package/templates/be/patterns/projections/projection.index.ts.tpl +3 -0
- package/templates/be/patterns/projections/projection.module-definition.ts.tpl +7 -0
- package/templates/be/patterns/projections/projection.module.ts.tpl +18 -0
- package/templates/be/patterns/projections/projection.options.ts.tpl +2 -0
- package/templates/be/patterns/projections/projection.projection.spec.ts.tpl +55 -0
- package/templates/be/patterns/projections/projection.projection.ts.tpl +21 -0
- package/templates/be/patterns/queues/platform/bullmq-queue-transport.client.spec.ts.tpl +142 -0
- package/templates/be/patterns/queues/platform/bullmq-queue-transport.client.ts.tpl +81 -0
- package/templates/be/patterns/queues/platform/persistence.connection.ts.tpl +8 -0
- package/templates/be/patterns/queues/platform/persistence.migration.ts.tpl +25 -0
- package/templates/be/patterns/queues/platform/persistence.queue-outbox.entity.ts.tpl +25 -0
- package/templates/be/patterns/queues/platform/persistence.queue.rows.ts.tpl +9 -0
- package/templates/be/patterns/queues/platform/persistence.queue.sql.ts.tpl +12 -0
- package/templates/be/patterns/queues/platform/queue-outbox.service.spec.ts.tpl +48 -0
- package/templates/be/patterns/queues/platform/queue-outbox.service.ts.tpl +17 -0
- package/templates/be/patterns/queues/platform/queue-relay.service.spec.ts.tpl +128 -0
- package/templates/be/patterns/queues/platform/queue-relay.service.ts.tpl +48 -0
- package/templates/be/patterns/queues/platform/queue-transport.port.ts.tpl +115 -0
- package/templates/be/patterns/queues/platform/queue-worker.service.spec.ts.tpl +91 -0
- package/templates/be/patterns/queues/platform/queue-worker.service.ts.tpl +45 -0
- package/templates/be/patterns/queues/platform/queue.config.ts.tpl +15 -0
- package/templates/be/patterns/queues/platform/queue.contracts.ts.tpl +31 -0
- package/templates/be/patterns/queues/platform/queue.decorators.ts.tpl +45 -0
- package/templates/be/patterns/queues/platform/queue.index.ts.tpl +7 -0
- package/templates/be/patterns/queues/platform/queue.log-events.ts.tpl +5 -0
- package/templates/be/patterns/queues/platform/queue.module-definition.ts.tpl +10 -0
- package/templates/be/patterns/queues/platform/queue.module.ts.tpl +62 -0
- package/templates/be/patterns/queues/platform/queue.options.ts.tpl +22 -0
- package/templates/be/patterns/queues/platform/queue.policy.spec.ts.tpl +19 -0
- package/templates/be/patterns/queues/platform/queue.policy.ts.tpl +11 -0
- package/templates/be/patterns/queues/platform/queue.port.ts.tpl +14 -0
- package/templates/be/patterns/queues/queue.index.ts.tpl +3 -0
- package/templates/be/patterns/queues/queue.module.ts.tpl +6 -0
- package/templates/be/patterns/queues/queue.queue.ts.tpl +23 -0
- package/templates/be/patterns/reactors/application.command.ts.tpl +10 -0
- package/templates/be/patterns/reactors/application.contracts.ts.tpl +12 -0
- package/templates/be/patterns/reactors/application.handler.ts.tpl +22 -0
- package/templates/be/patterns/reactors/consumer.ts.tpl +19 -0
- package/templates/be/patterns/reactors/message.module.ts.tpl +20 -0
- package/templates/be/patterns/reactors/reactor.index.ts.tpl +1 -0
- package/templates/be/patterns/reactors/reactor.module.ts.tpl +6 -0
- package/templates/be/patterns/realtime/channel.graphql.module.ts.tpl +6 -0
- package/templates/be/patterns/realtime/channel.index.ts.tpl +1 -0
- package/templates/be/patterns/realtime/channel.input.ts.tpl +12 -0
- package/templates/be/patterns/realtime/channel.subscription.spec.ts.tpl +51 -0
- package/templates/be/patterns/realtime/channel.subscription.ts.tpl +32 -0
- package/templates/be/patterns/realtime/channel.type.ts.tpl +9 -0
- package/templates/be/patterns/saga/saga.compensate.command.ts.tpl +11 -0
- package/templates/be/patterns/saga/saga.compensate.contracts.ts.tpl +7 -0
- package/templates/be/patterns/saga/saga.compensate.handler.ts.tpl +22 -0
- package/templates/be/patterns/saga/saga.compensation.ts.tpl +21 -0
- package/templates/be/patterns/saga/saga.complete.command.ts.tpl +11 -0
- package/templates/be/patterns/saga/saga.complete.contracts.ts.tpl +7 -0
- package/templates/be/patterns/saga/saga.complete.handler.ts.tpl +22 -0
- package/templates/be/patterns/saga/saga.done.consumer.ts.tpl +21 -0
- package/templates/be/patterns/saga/saga.failed.consumer.ts.tpl +21 -0
- package/templates/be/patterns/saga/saga.index.ts.tpl +1 -0
- package/templates/be/patterns/saga/saga.message.module.ts.tpl +23 -0
- package/templates/be/patterns/saga/saga.module.ts.tpl +20 -0
- package/templates/be/patterns/saga/saga.service.spec.ts.tpl +70 -0
- package/templates/be/patterns/saga/saga.service.ts.tpl +44 -0
- package/templates/be/patterns/saga/saga.state.ts.tpl +14 -0
- package/templates/be/patterns/saga/saga.step.ts.tpl +11 -0
- package/templates/be/patterns/saga/saga.undo.command.ts.tpl +10 -0
- package/templates/be/patterns/saga/saga.undo.contracts.ts.tpl +5 -0
- package/templates/be/patterns/saga/saga.undo.handler.ts.tpl +21 -0
- package/templates/be/patterns/webhooks/webhook.door.spec.ts.tpl +72 -0
- package/templates/be/patterns/webhooks/webhook.door.ts.tpl +36 -0
- package/templates/be/patterns/webhooks/webhook.http.module.ts.tpl +6 -0
- package/templates/be/patterns/webhooks/webhook.index.ts.tpl +1 -0
- package/templates/be/patterns/webhooks/webhook.request.ts.tpl +9 -0
- package/templates/be/skeleton/apps/__app__/src/__app__.options.ts +3 -0
- package/templates/be/skeleton/apps/__app__/src/app.module.ts +15 -2
- package/templates/be/skeleton/apps/__app__/src/main.ts +7 -15
- package/templates/be/skeleton/apps/cli/src/app.module.ts +30 -0
- package/templates/be/skeleton/apps/cli/src/cli.options.ts +22 -0
- package/templates/be/skeleton/apps/cli/src/main.ts +24 -0
- package/templates/be/skeleton/src/features/cli/cli.module.ts +7 -0
- package/templates/be/skeleton/src/features/cli/index.ts +1 -0
- package/templates/be/skeleton/src/features/cli/migrate/migrate.cli.spec.ts +17 -0
- package/templates/be/skeleton/src/features/cli/migrate/migrate.cli.ts +15 -0
- package/templates/be/skeleton/src/features/cli/migrate/migrate.module.ts +7 -0
- package/templates/be/skeleton/src/features/cli/migrate/subs/run.cli.spec.ts +17 -0
- package/templates/be/skeleton/src/features/cli/migrate/subs/run.cli.ts +18 -0
- package/templates/be/skeleton/src/features/cli/seed/seed.cli.spec.ts +17 -0
- package/templates/be/skeleton/src/features/cli/seed/seed.cli.ts +15 -0
- package/templates/be/skeleton/src/features/cli/seed/seed.module.ts +7 -0
- package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.spec.ts +33 -0
- package/templates/be/skeleton/src/features/cli/seed/subs/run.cli.ts +34 -0
- package/templates/be/skeleton/src/modules/domain/identity/admission.policy.spec.ts +13 -0
- package/templates/be/skeleton/src/modules/domain/identity/auth.guard.spec.ts +40 -0
- package/templates/be/skeleton/src/modules/domain/identity/messages/identity.messages.ts +1 -1
- package/templates/be/skeleton/src/modules/domain/note/errors/note.error.ts +16 -0
- package/templates/be/skeleton/src/modules/domain/note/index.ts +3 -0
- package/templates/be/skeleton/src/modules/domain/note/note.contracts.ts +19 -0
- package/templates/be/skeleton/src/modules/domain/note/note.decorators.ts +9 -0
- package/templates/be/skeleton/src/modules/domain/note/note.module-definition.ts +7 -0
- package/templates/be/skeleton/src/modules/domain/note/note.module.ts +19 -0
- package/templates/be/skeleton/src/modules/domain/note/note.options.ts +2 -0
- package/templates/be/skeleton/src/modules/domain/note/note.service.spec.ts +76 -0
- package/templates/be/skeleton/src/modules/domain/note/note.service.ts +37 -0
- package/templates/be/skeleton/src/modules/domain/note/persistence/connection.ts +8 -0
- package/templates/be/skeleton/src/modules/domain/note/persistence/entities/note.entity.ts +17 -0
- package/templates/be/skeleton/src/modules/domain/note/persistence/migrations/1790000000000-init-note.ts +22 -0
- package/templates/be/skeleton/src/modules/domain/note/persistence/note.rows.ts +17 -0
- package/templates/be/skeleton/src/modules/domain/note/persistence/note.sql.ts +4 -0
- package/templates/be/skeleton/src/modules/platform/config/env-source.config.ts +20 -0
- package/templates/be/skeleton/src/modules/platform/config/index.ts +1 -1
- package/templates/be/skeleton/src/modules/platform/cqrs/cqrs.contracts.ts +18 -0
- package/templates/be/skeleton/src/modules/platform/database/connection-source.client.spec.ts +41 -0
- package/templates/be/skeleton/src/modules/platform/database/connection-source.client.ts +17 -0
- package/templates/be/skeleton/src/modules/platform/database/database.module-definition.ts +13 -0
- package/templates/be/skeleton/src/modules/platform/database/database.module.ts +77 -0
- package/templates/be/skeleton/src/modules/platform/database/database.options.ts +30 -0
- package/templates/be/skeleton/src/modules/platform/database/database.port.ts +65 -0
- package/templates/be/skeleton/src/modules/platform/database/database.sql.ts +47 -0
- package/templates/be/skeleton/src/modules/platform/database/errors/database.error.ts +16 -0
- package/templates/be/skeleton/src/modules/platform/database/index.ts +9 -0
- package/templates/be/skeleton/src/modules/platform/database/migrate-connections.client.ts +30 -0
- package/templates/be/skeleton/src/modules/platform/database/migration-runner.service.spec.ts +84 -0
- package/templates/be/skeleton/src/modules/platform/database/migration-runner.service.ts +23 -0
- package/templates/be/skeleton/src/modules/platform/database/primary.config.ts +9 -0
- package/templates/be/skeleton/src/modules/platform/database/primary.connection.ts +2 -0
- package/templates/be/skeleton/src/modules/platform/database/primary.decorators.ts +10 -0
- package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.spec.ts +108 -0
- package/templates/be/skeleton/src/modules/platform/database/seed-connections.client.ts +75 -0
- package/templates/be/skeleton/src/modules/platform/database/seed-runner.service.spec.ts +88 -0
- package/templates/be/skeleton/src/modules/platform/database/seed-runner.service.ts +29 -0
- package/templates/be/skeleton/src/modules/platform/errors/errors.filter.spec.ts +48 -0
- package/templates/be/skeleton/src/modules/platform/errors/messages/errors.messages.ts +1 -1
- package/templates/be/skeleton/src/modules/platform/http-security/errors/http-security.error.ts +12 -0
- package/templates/be/skeleton/src/modules/platform/http-security/execution-request.mapper.spec.ts +16 -0
- package/templates/be/skeleton/src/modules/platform/http-security/http-security.config.ts +8 -1
- package/templates/be/skeleton/src/modules/platform/http-security/http-security.decorators.ts +8 -0
- package/templates/be/skeleton/src/modules/platform/http-security/http-security.module.ts +14 -1
- package/templates/be/skeleton/src/modules/platform/http-security/http-security.options.ts +12 -0
- package/templates/be/skeleton/src/modules/platform/http-security/messages/http-security.messages.ts +10 -2
- package/templates/be/skeleton/src/modules/platform/http-security/origin.guard.spec.ts +63 -0
- package/templates/be/skeleton/src/modules/platform/http-security/rate-limit.guard.spec.ts +108 -0
- package/templates/be/skeleton/src/modules/platform/http-security/request-validation.service.spec.ts +39 -0
- package/templates/be/skeleton/src/modules/platform/http-security/request-validation.service.ts +25 -0
- package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.spec.ts +172 -0
- package/templates/be/skeleton/src/modules/platform/http-security/webhook-signature.service.ts +66 -0
- package/templates/be/skeleton/src/modules/platform/logging/logging.log-events.ts +3 -1
- package/templates/be/skeleton/src/modules/platform/primitives/outcome.mapper.spec.ts +52 -0
- package/templates/be/skeleton-lite/apps/api/Dockerfile +37 -0
- package/templates/be/skeleton-lite/apps/api/src/api.options.ts +16 -0
- package/templates/be/skeleton-lite/apps/api/src/app.module.ts +81 -0
- package/templates/be/skeleton-lite/apps/api/src/main.ts +34 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/admission.policy.ts +14 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/auth.guard.ts +50 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.contracts.ts +26 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.decorators.ts +19 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.module.ts +26 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/identity.options.ts +7 -0
- package/templates/be/skeleton-lite/src/modules/domain/identity/index.ts +6 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/errors/supabase.error.ts +19 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/index.ts +10 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.client.ts +24 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.config.ts +8 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.decorators.ts +17 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.jwks.ts +32 -0
- package/templates/be/skeleton-lite/src/modules/integrations/supabase/supabase.options.ts +24 -0
- package/templates/be/skeleton-lite/src/modules/platform/cqrs/index.ts +4 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/database.module.ts +54 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/database.options.ts +23 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/database.port.ts +10 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/database.sql.ts +49 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/index.ts +4 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/migration-runner.service.ts +21 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/primary.config.ts +11 -0
- package/templates/be/skeleton-lite/src/modules/platform/database/seed-runner.service.ts +28 -0
- package/templates/be/skeleton-lite/src/modules/platform/http-security/http-security.module.ts +25 -0
- package/templates/be/skeleton-lite/src/modules/platform/http-security/index.ts +9 -0
- package/templates/be/skeleton-lite/src/modules/platform/i18n/index.ts +4 -0
- package/templates/be/skeleton-lite/src/modules/platform/logging/index.ts +5 -0
- package/templates/be/table/error.ts.tpl +16 -0
- package/templates/be/table/index.ts.tpl +2 -0
- package/templates/be/table/migration.sql.tpl +51 -0
- package/templates/be/table/module-definition.ts.tpl +7 -0
- package/templates/be/table/module.ts.tpl +14 -0
- package/templates/be/table/options.ts.tpl +2 -0
- package/templates/be/table/rows.ts.tpl +4 -0
- package/templates/be/table/service.ts.tpl +23 -0
- package/templates/be/table/sql.ts.tpl +4 -0
- package/templates/be/tool-config/jest.config.js +3 -1
- package/templates/be/upgrade-full/apps/cli/src/app.module.ts +14 -0
- package/templates/be/upgrade-full/apps/cli/src/main.ts +26 -0
- package/templates/be/upgrade-full/src/features/cli/cli.module.ts +6 -0
- package/templates/be/upgrade-full/src/features/cli/migrate/subs/run.cli.ts +23 -0
- package/templates/common/gitignore.base +1 -2
- package/templates/fe/app/package.json.tpl +1 -0
- package/templates/fe/app/tsconfig.json +12 -0
- package/templates/fe/common/app-layout.tsx.partial +8 -0
- package/templates/fe/common/site-shell.tsx.partial +9 -0
- package/templates/fe/image/next/Dockerfile +42 -0
- package/templates/fe/skeleton/apps/app/next.config.ts +23 -0
- package/templates/fe/skeleton/apps/app/postcss.config.mjs +7 -0
- package/templates/fe/skeleton/apps/{__app__ → app}/src/app/[locale]/error.tsx +2 -2
- package/templates/fe/skeleton/apps/app/src/app/[locale]/layout.tsx +22 -0
- package/templates/fe/skeleton/apps/{__app__ → app}/src/app/[locale]/loading.tsx +2 -2
- package/templates/fe/skeleton/apps/{__app__ → app}/src/app/[locale]/not-found.tsx +2 -2
- package/templates/fe/skeleton/apps/app/src/app/[locale]/page.tsx +9 -0
- package/templates/fe/skeleton/apps/{__app__ → app}/src/app/global-error.tsx +2 -2
- package/templates/fe/skeleton/apps/app/src/app/globals.css +10 -0
- package/templates/fe/skeleton/apps/app/src/features/layouts/AppLayout/index.tsx +18 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppErrorPage/component.tsx +19 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppErrorPage/index.tsx +11 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppGlobalErrorPage/index.tsx +16 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/component.tsx +10 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppHomePage/index.tsx +15 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppLoadingPage/index.tsx +8 -0
- package/templates/fe/skeleton/apps/app/src/features/pages/AppNotFoundPage/index.tsx +9 -0
- package/templates/fe/skeleton/apps/app/src/modules/i18n/index.ts +4 -0
- package/templates/fe/skeleton/apps/app/src/modules/i18n/messages/vi.json +28 -0
- package/templates/fe/skeleton/apps/app/src/modules/i18n/request.ts +4 -0
- package/templates/fe/skeleton/apps/app/src/modules/routes/index.ts +4 -0
- package/templates/fe/skeleton/apps/app/src/proxy.ts +1 -0
- package/templates/fe/skeleton/apps/{__app__ → landing}/next.config.ts +4 -2
- package/templates/fe/skeleton/apps/landing/postcss.config.mjs +7 -0
- package/templates/fe/skeleton/apps/landing/src/app/[locale]/error.tsx +10 -0
- package/templates/fe/skeleton/apps/landing/src/app/[locale]/layout.tsx +22 -0
- package/templates/fe/skeleton/apps/landing/src/app/[locale]/loading.tsx +6 -0
- package/templates/fe/skeleton/apps/landing/src/app/[locale]/not-found.tsx +6 -0
- package/templates/fe/skeleton/apps/landing/src/app/[locale]/page.tsx +9 -0
- package/templates/fe/skeleton/apps/landing/src/app/global-error.tsx +10 -0
- package/templates/fe/skeleton/apps/landing/src/app/globals.css +10 -0
- package/templates/fe/skeleton/apps/landing/src/features/layouts/LandingLayout/index.tsx +24 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingErrorPage/component.tsx +18 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingErrorPage/index.tsx +11 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingGlobalErrorPage/index.tsx +16 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingLoadingPage/index.tsx +8 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingNotFoundPage/index.tsx +9 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingPage/component.tsx +24 -0
- package/templates/fe/skeleton/apps/landing/src/features/pages/LandingPage/index.tsx +16 -0
- package/templates/fe/skeleton/apps/landing/src/modules/config/index.ts +12 -0
- package/templates/fe/skeleton/apps/landing/src/modules/i18n/index.ts +7 -0
- package/templates/fe/skeleton/apps/landing/src/modules/i18n/messages/vi.json +31 -0
- package/templates/fe/skeleton/apps/landing/src/modules/i18n/request.ts +4 -0
- package/templates/fe/skeleton/apps/landing/src/modules/routes/index.ts +4 -0
- package/templates/fe/skeleton/apps/landing/src/proxy.ts +1 -0
- package/templates/fe/skeleton/packages/__project__-i18n/src/index.ts +49 -0
- package/templates/fe/skeleton/packages/__project__-i18n/src/proxy.ts +24 -0
- package/templates/fe/skeleton/packages/__project__-i18n/src/routing.ts +20 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/branches/Providers/index.tsx +23 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/ErrorNotice/index.tsx +14 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/GlobalErrorNotice/index.tsx +25 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/LoadingNotice/index.tsx +9 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/LocaleShell/index.tsx +21 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/NotFoundNotice/index.tsx +19 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/SiteShell/classNames.ts +4 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/composites/SiteShell/index.tsx +19 -0
- package/templates/fe/skeleton/packages/__project__-ui/src/index.ts +6 -0
- package/templates/fe/skeleton-lite/apps/web/next.config.ts +22 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/error.tsx +10 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/layout.tsx +37 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/loading.tsx +6 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/not-found.tsx +6 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/page.tsx +9 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/[locale]/providers.tsx +26 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/auth/callback/route.ts +24 -0
- package/templates/fe/skeleton-lite/apps/web/src/app/global-error.tsx +10 -0
- package/templates/fe/{skeleton/apps/__app__ → skeleton-lite/apps/web}/src/app/globals.css +1 -1
- package/templates/fe/skeleton-lite/apps/web/src/app/health/live/route.ts +5 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignInForm/component.tsx +29 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignInForm/index.tsx +41 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignOutButton/component.tsx +17 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/blocks/SignOutButton/index.tsx +38 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/composites/ErrorNotice/index.tsx +13 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/composites/GlobalErrorNotice/index.tsx +24 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/composites/LoadingNotice/index.tsx +7 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/composites/NotFoundNotice/index.tsx +18 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/composites/SiteShell/classNames.ts +4 -0
- package/templates/fe/skeleton-lite/apps/web/src/components/composites/SiteShell/index.tsx +13 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/layouts/AppLayout/index.tsx +31 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppErrorPage/component.tsx +12 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppErrorPage/index.tsx +10 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppGlobalErrorPage/index.tsx +15 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/component.tsx +14 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppHomePage/index.tsx +30 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppLoadingPage/index.tsx +8 -0
- package/templates/fe/skeleton-lite/apps/web/src/features/pages/AppNotFoundPage/index.tsx +9 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/brand/brand.css +20 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/brand/index.ts +2 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/config/index.ts +20 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/auth/read-session.ts +25 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/auth/write-sign-in.ts +25 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/auth/write-sign-out.ts +17 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/browser.ts +14 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/index.ts +3 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/outcome.ts +59 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/principal.ts +29 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/server.ts +70 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/db/validation/validation.mapper.ts +50 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/index.ts +8 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/messages/vi.json +48 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/request.ts +16 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/i18n/routing.ts +14 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/routes/index.ts +7 -0
- package/templates/fe/skeleton-lite/apps/web/src/modules/routes/safe-next-path.ts +26 -0
- package/templates/fe/skeleton-lite/apps/web/src/proxy.ts +43 -0
- package/templates/fe/table/read.ts.tpl +16 -0
- package/templates/fe/table/write.ts.tpl +16 -0
- package/upgrade/check.mjs +137 -0
- package/upgrade/index.mjs +524 -0
- package/bin/hfs.mjs +0 -233
- package/runtime/scripts/api/fs/rmdir-link.mjs +0 -12
- package/runtime/scripts/lib/test-secrets.mjs +0 -116
- package/templates/fe/skeleton/apps/__app__/src/app/[locale]/layout.tsx +0 -20
- package/templates/fe/skeleton/apps/__app__/src/app/[locale]/page.tsx +0 -9
- package/templates/fe/skeleton/apps/__app__/src/components/composites/FailureScreen/index.tsx +0 -28
- package/templates/fe/skeleton/apps/__app__/src/features/layouts/LocaleShell/index.tsx +0 -35
- package/templates/fe/skeleton/apps/__app__/src/features/pages/ErrorPage/component.tsx +0 -19
- package/templates/fe/skeleton/apps/__app__/src/features/pages/ErrorPage/index.tsx +0 -11
- package/templates/fe/skeleton/apps/__app__/src/features/pages/GlobalErrorPage/component.tsx +0 -24
- package/templates/fe/skeleton/apps/__app__/src/features/pages/GlobalErrorPage/index.tsx +0 -14
- package/templates/fe/skeleton/apps/__app__/src/features/pages/HomePage/component.tsx +0 -21
- package/templates/fe/skeleton/apps/__app__/src/features/pages/HomePage/index.tsx +0 -15
- package/templates/fe/skeleton/apps/__app__/src/features/pages/LoadingPage/component.tsx +0 -23
- package/templates/fe/skeleton/apps/__app__/src/features/pages/LoadingPage/index.tsx +0 -8
- package/templates/fe/skeleton/apps/__app__/src/features/pages/NotFoundPage/component.tsx +0 -28
- package/templates/fe/skeleton/apps/__app__/src/features/pages/NotFoundPage/index.tsx +0 -8
- package/templates/fe/skeleton/apps/__app__/src/modules/i18n/config.ts +0 -8
- package/templates/fe/skeleton/apps/__app__/src/modules/i18n/index.ts +0 -2
- package/templates/fe/skeleton/apps/__app__/src/modules/i18n/messages/vi.json +0 -25
- package/templates/fe/skeleton/apps/__app__/src/modules/i18n/request.ts +0 -19
- package/templates/fe/skeleton/apps/__app__/src/modules/i18n/routing.ts +0 -9
- package/templates/fe/skeleton/apps/__app__/src/modules/routes/index.ts +0 -4
- package/templates/fe/skeleton/apps/__app__/src/proxy.ts +0 -10
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/application/check-liveness.contracts.ts +0 -0
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/application/check-liveness.handler.ts +0 -0
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/application/check-liveness.query.ts +0 -0
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/index.ts +0 -0
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/system-health.module.ts +0 -0
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/transport/http/live.controller.ts +0 -0
- /package/templates/be/skeleton/src/features/{system-health → api/system-health}/transport/http/system-health-http.module.ts +0 -0
- /package/templates/fe/skeleton/apps/{__app__ → app}/src/app/health/live/route.ts +0 -0
- /package/templates/fe/skeleton/apps/{__app__ → app}/src/modules/config/index.ts +0 -0
- /package/templates/fe/{skeleton/apps/__app__ → skeleton-lite/apps/web}/postcss.config.mjs +0 -0
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
@import "@heroui/styles/css";
|
|
3
3
|
@import "@starci/grammar/common.css";
|
|
4
4
|
|
|
5
|
-
/*
|
|
5
|
+
/* Grammar's renderers contain Tailwind utilities outside the app source tree. */
|
|
6
6
|
@source "../../../../../node_modules/@starci/grammar/dist";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Liveness is answered per request, never prerendered at build time. */
|
|
2
|
+
export const dynamic = "force-dynamic"
|
|
3
|
+
|
|
4
|
+
/** Process-local liveness; it never touches a dependency. */
|
|
5
|
+
export const GET = (): Response => Response.json({ status: "ok", info: {}, error: {}, details: {} })
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Button, Form, Input, SectionHeader, Text } from "@starci/grammar/common"
|
|
2
|
+
|
|
3
|
+
/** Copy, state and action supplied by the connected sign-in block. */
|
|
4
|
+
export interface SignInFormBaseProps {
|
|
5
|
+
readonly state: "ready" | "working" | "failed"
|
|
6
|
+
readonly props: {
|
|
7
|
+
readonly title: string
|
|
8
|
+
readonly emailLabel: string
|
|
9
|
+
readonly passwordLabel: string
|
|
10
|
+
readonly submitLabel: string
|
|
11
|
+
readonly failure?: string
|
|
12
|
+
}
|
|
13
|
+
readonly on: { readonly submit: (input: FormData) => void }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Draws the sign-in form without reading navigation, copy or database state. */
|
|
17
|
+
export const SignInFormBase = (props: SignInFormBaseProps) => (
|
|
18
|
+
<>
|
|
19
|
+
<SectionHeader title={props.props.title} level={2} />
|
|
20
|
+
<Form label={props.props.title} isPending={props.state === "working"} onSubmit={props.on.submit}>
|
|
21
|
+
<Input id="sign-in-email" name="email" label={props.props.emailLabel} kind="email" isRequired />
|
|
22
|
+
<Input id="sign-in-password" name="password" label={props.props.passwordLabel} kind="password" isRequired />
|
|
23
|
+
{props.props.failure === undefined ? null : <Text live="assertive">{props.props.failure}</Text>}
|
|
24
|
+
<Button type="submit" variant="primary" isPending={props.state === "working"}>
|
|
25
|
+
{props.props.submitLabel}
|
|
26
|
+
</Button>
|
|
27
|
+
</Form>
|
|
28
|
+
</>
|
|
29
|
+
)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useTranslations } from "next-intl"
|
|
4
|
+
import { useState, useTransition } from "react"
|
|
5
|
+
import { writeSignIn } from "@/modules/db/auth/write-sign-in"
|
|
6
|
+
import { navigation } from "@/modules/i18n"
|
|
7
|
+
import { SignInFormBase } from "./component"
|
|
8
|
+
|
|
9
|
+
type SignInFailure = "refused" | "not-found" | "invalid" | "unavailable"
|
|
10
|
+
|
|
11
|
+
/** The interactive sign-in form wired to the schema-checked Server Action. */
|
|
12
|
+
export const SignInForm = () => {
|
|
13
|
+
const router = navigation.useRouter()
|
|
14
|
+
const t = useTranslations("app.signIn")
|
|
15
|
+
const [failure, setFailure] = useState<SignInFailure>()
|
|
16
|
+
const [pending, startTransition] = useTransition()
|
|
17
|
+
const submit = (input: FormData) => {
|
|
18
|
+
startTransition(async () => {
|
|
19
|
+
const outcome = await writeSignIn(input)
|
|
20
|
+
if (outcome.kind === "ok") {
|
|
21
|
+
setFailure(undefined)
|
|
22
|
+
router.refresh()
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
setFailure(outcome.kind)
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
return (
|
|
29
|
+
<SignInFormBase
|
|
30
|
+
state={pending ? "working" : failure === undefined ? "ready" : "failed"}
|
|
31
|
+
props={{
|
|
32
|
+
title: t("title"),
|
|
33
|
+
emailLabel: t("email"),
|
|
34
|
+
passwordLabel: t("password"),
|
|
35
|
+
submitLabel: pending ? t("working") : t("submit"),
|
|
36
|
+
failure: failure === undefined ? undefined : t(failure),
|
|
37
|
+
}}
|
|
38
|
+
on={{ submit }}
|
|
39
|
+
/>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Button, Text } from "@starci/grammar/common"
|
|
2
|
+
|
|
3
|
+
/** Copy, state and action supplied by the connected sign-out block. */
|
|
4
|
+
export interface SignOutButtonBaseProps {
|
|
5
|
+
readonly props: { readonly label: string; readonly pending: boolean; readonly failure?: string }
|
|
6
|
+
readonly on: { readonly press: () => void }
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Draws the sign-out control without reading navigation, copy or database state. */
|
|
10
|
+
export const SignOutButtonBase = (props: SignOutButtonBaseProps) => (
|
|
11
|
+
<>
|
|
12
|
+
<Button variant="secondary" isPending={props.props.pending} onPress={props.on.press}>
|
|
13
|
+
{props.props.label}
|
|
14
|
+
</Button>
|
|
15
|
+
{props.props.failure === undefined ? null : <Text live="assertive">{props.props.failure}</Text>}
|
|
16
|
+
</>
|
|
17
|
+
)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useTranslations } from "next-intl"
|
|
4
|
+
import { useState, useTransition } from "react"
|
|
5
|
+
import { writeSignOut } from "@/modules/db/auth/write-sign-out"
|
|
6
|
+
import { navigation } from "@/modules/i18n"
|
|
7
|
+
import { SignOutButtonBase } from "./component"
|
|
8
|
+
|
|
9
|
+
type SignOutFailure = "refused" | "not-found" | "invalid" | "unavailable"
|
|
10
|
+
|
|
11
|
+
/** The connected control that ends the current browser session. */
|
|
12
|
+
export const SignOutButton = () => {
|
|
13
|
+
const router = navigation.useRouter()
|
|
14
|
+
const t = useTranslations("app.signOut")
|
|
15
|
+
const [failure, setFailure] = useState<SignOutFailure>()
|
|
16
|
+
const [pending, startTransition] = useTransition()
|
|
17
|
+
const signOut = () => {
|
|
18
|
+
startTransition(async () => {
|
|
19
|
+
const outcome = await writeSignOut()
|
|
20
|
+
if (outcome.kind !== "ok") {
|
|
21
|
+
setFailure(outcome.kind)
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
setFailure(undefined)
|
|
25
|
+
router.refresh()
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
return (
|
|
29
|
+
<SignOutButtonBase
|
|
30
|
+
props={{
|
|
31
|
+
label: pending ? t("working") : t("submit"),
|
|
32
|
+
pending,
|
|
33
|
+
failure: failure === undefined ? undefined : t(failure),
|
|
34
|
+
}}
|
|
35
|
+
on={{ press: signOut }}
|
|
36
|
+
/>
|
|
37
|
+
)
|
|
38
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Alert } from "@starci/grammar/common"
|
|
2
|
+
|
|
3
|
+
/** The words of a recoverable failure and its one recovery action. */
|
|
4
|
+
type ErrorNoticeProps = {
|
|
5
|
+
readonly title: string
|
|
6
|
+
readonly retryLabel: string
|
|
7
|
+
readonly onRetry: () => void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** A recoverable failure shown as an assertive banner. */
|
|
11
|
+
export const ErrorNotice = (props: ErrorNoticeProps) => (
|
|
12
|
+
<Alert title={props.title} tone="negative" action={{ label: props.retryLabel, onAction: props.onRetry }} />
|
|
13
|
+
)
|
package/templates/fe/skeleton-lite/apps/web/src/components/composites/GlobalErrorNotice/index.tsx
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Alert, GrammarRoot } from "@starci/grammar/common"
|
|
2
|
+
|
|
3
|
+
/** The document language, failure words and recovery action. */
|
|
4
|
+
type GlobalErrorNoticeProps = {
|
|
5
|
+
readonly lang: string
|
|
6
|
+
readonly title: string
|
|
7
|
+
readonly retryLabel: string
|
|
8
|
+
readonly onRetry: () => void
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** The last-resort failure replaces the layout and therefore draws the document itself. */
|
|
12
|
+
export const GlobalErrorNotice = (props: GlobalErrorNoticeProps) => (
|
|
13
|
+
<html lang={props.lang}>
|
|
14
|
+
<body>
|
|
15
|
+
<GrammarRoot>
|
|
16
|
+
<Alert
|
|
17
|
+
title={props.title}
|
|
18
|
+
tone="negative"
|
|
19
|
+
action={{ label: props.retryLabel, onAction: props.onRetry }}
|
|
20
|
+
/>
|
|
21
|
+
</GrammarRoot>
|
|
22
|
+
</body>
|
|
23
|
+
</html>
|
|
24
|
+
)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Spinner } from "@starci/grammar/common"
|
|
2
|
+
|
|
3
|
+
/** The word a wait announces. */
|
|
4
|
+
type LoadingNoticeProps = { readonly label: string }
|
|
5
|
+
|
|
6
|
+
/** A wait shown as one announced spinner. */
|
|
7
|
+
export const LoadingNotice = (props: LoadingNoticeProps) => <Spinner label={props.label} />
|
package/templates/fe/skeleton-lite/apps/web/src/components/composites/NotFoundNotice/index.tsx
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Heading, TextAction } from "@starci/grammar/common"
|
|
2
|
+
|
|
3
|
+
/** The words of a missing page and the way home. */
|
|
4
|
+
type NotFoundNoticeProps = {
|
|
5
|
+
readonly title: string
|
|
6
|
+
readonly homeLabel: string
|
|
7
|
+
readonly homeHref: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** A missing page with one destination back to the app's front door. */
|
|
11
|
+
export const NotFoundNotice = (props: NotFoundNoticeProps) => (
|
|
12
|
+
<>
|
|
13
|
+
<Heading level={1}>{props.title}</Heading>
|
|
14
|
+
<TextAction appearance="inline" href={props.homeHref}>
|
|
15
|
+
{props.homeLabel}
|
|
16
|
+
</TextAction>
|
|
17
|
+
</>
|
|
18
|
+
)
|
|
@@ -0,0 +1,13 @@
|
|
|
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 the app chrome hands the shell. */
|
|
6
|
+
type SiteShellProps = {
|
|
7
|
+
readonly brand: string
|
|
8
|
+
readonly homeHref: string
|
|
9
|
+
readonly children: ReactNode
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** The app chrome: grammar boundary, wordmark header and routed body. */
|
|
13
|
+
{{> fe/common/site-shell.tsx.partial}}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Metadata } from "next"
|
|
2
|
+
import { getTranslations } from "next-intl/server"
|
|
3
|
+
import type { ReactNode } from "react"
|
|
4
|
+
import { SiteShell } from "@/components/composites/SiteShell"
|
|
5
|
+
import { siteUrl } from "@/modules/config"
|
|
6
|
+
import { APP_ROUTES } from "@/modules/routes"
|
|
7
|
+
|
|
8
|
+
type AppLayoutProps = {
|
|
9
|
+
readonly locale: string
|
|
10
|
+
readonly content: ReactNode
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** The document title and absolute metadata base for the requested locale. */
|
|
14
|
+
export const appLayoutMetadata = async (locale: string): Promise<Metadata> => {
|
|
15
|
+
const t = await getTranslations({ locale, namespace: "app" })
|
|
16
|
+
return { title: t("title"), metadataBase: new URL(siteUrl()) }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** The server-resolved app chrome around the routed body. */
|
|
20
|
+
export const AppLayout = async (props: AppLayoutProps) => {
|
|
21
|
+
const t = await getTranslations("app.shell")
|
|
22
|
+
return (
|
|
23
|
+
<html lang={props.locale}>
|
|
24
|
+
<body>
|
|
25
|
+
<SiteShell brand={t("brand")} homeHref={APP_ROUTES.home}>
|
|
26
|
+
{props.content}
|
|
27
|
+
</SiteShell>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ErrorNotice } from "@/components/composites/ErrorNotice"
|
|
2
|
+
|
|
3
|
+
/** Props for the pure error page. */
|
|
4
|
+
export type AppErrorPageBaseProps = {
|
|
5
|
+
readonly props: { readonly title: string; readonly retryLabel: string }
|
|
6
|
+
readonly on: { readonly retry: () => void }
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Draws the locale segment's recoverable failure. */
|
|
10
|
+
export const AppErrorPageBase = (props: AppErrorPageBaseProps) => (
|
|
11
|
+
<ErrorNotice title={props.props.title} retryLabel={props.props.retryLabel} onRetry={props.on.retry} />
|
|
12
|
+
)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { useTranslations } from "next-intl"
|
|
2
|
+
import { AppErrorPageBase } from "./component"
|
|
3
|
+
|
|
4
|
+
type AppErrorPageProps = { readonly onRetry: () => void }
|
|
5
|
+
|
|
6
|
+
/** A render failure with the segment retry. */
|
|
7
|
+
export const AppErrorPage = (props: AppErrorPageProps) => {
|
|
8
|
+
const t = useTranslations("app.errors.page")
|
|
9
|
+
return <AppErrorPageBase props={{ title: t("title"), retryLabel: t("retry") }} on={{ retry: props.onRetry }} />
|
|
10
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { GlobalErrorNotice } from "@/components/composites/GlobalErrorNotice"
|
|
2
|
+
import { DEFAULT_LOCALE } from "@/modules/i18n"
|
|
3
|
+
import messages from "@/modules/i18n/messages/vi.json"
|
|
4
|
+
|
|
5
|
+
type AppGlobalErrorPageProps = { readonly onRetry: () => void }
|
|
6
|
+
|
|
7
|
+
/** The provider-free last-resort boundary reads the default catalog directly. */
|
|
8
|
+
export const AppGlobalErrorPage = (props: AppGlobalErrorPageProps) => (
|
|
9
|
+
<GlobalErrorNotice
|
|
10
|
+
lang={DEFAULT_LOCALE}
|
|
11
|
+
title={messages.app.errors.global.title}
|
|
12
|
+
retryLabel={messages.app.errors.global.retry}
|
|
13
|
+
onRetry={props.onRetry}
|
|
14
|
+
/>
|
|
15
|
+
)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Heading, Text } from "@starci/grammar/common"
|
|
2
|
+
|
|
3
|
+
/** Props for the signed-in home page. */
|
|
4
|
+
export type AppHomePageBaseProps = {
|
|
5
|
+
readonly props: { readonly title: string; readonly principal: string }
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** Draws the signed-in front door. */
|
|
9
|
+
export const AppHomePageBase = (props: AppHomePageBaseProps) => (
|
|
10
|
+
<>
|
|
11
|
+
<Heading level={1}>{props.props.title}</Heading>
|
|
12
|
+
<Text>{props.props.principal}</Text>
|
|
13
|
+
</>
|
|
14
|
+
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Metadata } from "next"
|
|
2
|
+
import { getTranslations } from "next-intl/server"
|
|
3
|
+
import { SignInForm } from "@/components/blocks/SignInForm"
|
|
4
|
+
import { SignOutButton } from "@/components/blocks/SignOutButton"
|
|
5
|
+
import { readSession } from "@/modules/db"
|
|
6
|
+
import { AppHomePageBase } from "./component"
|
|
7
|
+
|
|
8
|
+
/** The document title of the home page. */
|
|
9
|
+
export const appHomeMetadata = async (): Promise<Metadata> => {
|
|
10
|
+
const t = await getTranslations("app.home")
|
|
11
|
+
return { title: t("title") }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** The front door: sign-in for an anonymous request, otherwise the verified principal. */
|
|
15
|
+
export const AppHomePage = async () => {
|
|
16
|
+
const session = await readSession()
|
|
17
|
+
if (session.kind !== "ok") return <SignInForm />
|
|
18
|
+
const t = await getTranslations("app.home")
|
|
19
|
+
return (
|
|
20
|
+
<>
|
|
21
|
+
<AppHomePageBase
|
|
22
|
+
props={{
|
|
23
|
+
title: t("title"),
|
|
24
|
+
principal: session.value.email ?? t("signedIn"),
|
|
25
|
+
}}
|
|
26
|
+
/>
|
|
27
|
+
<SignOutButton />
|
|
28
|
+
</>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { getTranslations } from "next-intl/server"
|
|
2
|
+
import { LoadingNotice } from "@/components/composites/LoadingNotice"
|
|
3
|
+
|
|
4
|
+
/** Shown while a route resolves. */
|
|
5
|
+
export const AppLoadingPage = async () => {
|
|
6
|
+
const t = await getTranslations("app.loading")
|
|
7
|
+
return <LoadingNotice label={t("message")} />
|
|
8
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { getTranslations } from "next-intl/server"
|
|
2
|
+
import { NotFoundNotice } from "@/components/composites/NotFoundNotice"
|
|
3
|
+
import { APP_ROUTES } from "@/modules/routes"
|
|
4
|
+
|
|
5
|
+
/** Shown when a route does not exist. */
|
|
6
|
+
export const AppNotFoundPage = async () => {
|
|
7
|
+
const t = await getTranslations("app.notFound")
|
|
8
|
+
return <NotFoundNotice title={t("title")} homeLabel={t("home")} homeHref={APP_ROUTES.home} />
|
|
9
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/* The lite scaffold's neutral brand layer; replace these values through the brand workflow. */
|
|
2
|
+
:root,
|
|
3
|
+
.light,
|
|
4
|
+
.dark {
|
|
5
|
+
--starci-core-accent: #0d9488;
|
|
6
|
+
--accent: var(--starci-core-accent);
|
|
7
|
+
--accent-foreground: #051817;
|
|
8
|
+
--font-sans: ui-sans-serif, system-ui, sans-serif;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
:root,
|
|
12
|
+
.light {
|
|
13
|
+
--info-soft: #ccf3ef;
|
|
14
|
+
--info-soft-foreground: #0b5c54;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.dark {
|
|
18
|
+
--info-soft: #0d3b37;
|
|
19
|
+
--info-soft-foreground: #7fe0d4;
|
|
20
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** The only process-environment reader in the web app. */
|
|
2
|
+
const required = (name: string, value: string | undefined): string => {
|
|
3
|
+
if (value === undefined || value === "") throw new Error(`${name} is not set`)
|
|
4
|
+
return value
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/** The public origin used for metadata and same-origin redirects. */
|
|
8
|
+
export const siteUrl = (): string => required("NEXT_PUBLIC_SITE_URL", process.env.NEXT_PUBLIC_SITE_URL)
|
|
9
|
+
/** The public Supabase project origin. */
|
|
10
|
+
export const supabaseUrl = (): string => required("NEXT_PUBLIC_SUPABASE_URL", process.env.NEXT_PUBLIC_SUPABASE_URL)
|
|
11
|
+
/** The public anonymous key; RLS remains the authority for every request. */
|
|
12
|
+
export const supabaseAnonKey = (): string =>
|
|
13
|
+
required("NEXT_PUBLIC_SUPABASE_ANON_KEY", process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY)
|
|
14
|
+
|
|
15
|
+
/** Security attributes applied whenever the app writes a Supabase session cookie. */
|
|
16
|
+
export const sessionCookieOptions = {
|
|
17
|
+
httpOnly: true,
|
|
18
|
+
secure: process.env.NODE_ENV === "production",
|
|
19
|
+
sameSite: "lax",
|
|
20
|
+
} as const
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import "server-only"
|
|
2
|
+
|
|
3
|
+
import type { NextRequest, NextResponse } from "next/server"
|
|
4
|
+
import { getPrincipal, principalFromClaims } from "../principal"
|
|
5
|
+
import type { Principal } from "../principal"
|
|
6
|
+
import { createRequestDbClient, createServerDbClient } from "../server"
|
|
7
|
+
import { toOutcome } from "../outcome"
|
|
8
|
+
import type { DbOutcome } from "../outcome"
|
|
9
|
+
|
|
10
|
+
/** Reads the verified principal of the current server request. */
|
|
11
|
+
export const readSession = (): Promise<DbOutcome<Principal>> => getPrincipal()
|
|
12
|
+
|
|
13
|
+
/** Exchanges the one-time PKCE code and lets the server client write the resulting cookies. */
|
|
14
|
+
export const exchangeAuthCode = async (code: string) => {
|
|
15
|
+
const client = await createServerDbClient()
|
|
16
|
+
return toOutcome(await client.auth.exchangeCodeForSession(code))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Refreshes proxy cookies through `getClaims()` and returns the verified principal outcome. */
|
|
20
|
+
export const refreshSession = async (request: NextRequest, response: NextResponse): Promise<DbOutcome<Principal>> => {
|
|
21
|
+
const client = createRequestDbClient(request, response)
|
|
22
|
+
const claims = toOutcome(await client.auth.getClaims())
|
|
23
|
+
if (claims.kind !== "ok") return claims
|
|
24
|
+
return principalFromClaims(claims.value.claims)
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use server"
|
|
2
|
+
import "server-only"
|
|
3
|
+
|
|
4
|
+
import { getPrincipal } from "../principal"
|
|
5
|
+
import { createServerDbClient } from "../server"
|
|
6
|
+
import { dbFailure, dbOk, toOutcome } from "../outcome"
|
|
7
|
+
import type { DbOutcome } from "../outcome"
|
|
8
|
+
import { signInInputSchema } from "../validation/validation.mapper"
|
|
9
|
+
|
|
10
|
+
/** Result exposed to the client boundary after sign-in. */
|
|
11
|
+
export interface SignInResult {
|
|
12
|
+
readonly userId: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Schema-checks credentials, signs in through the server client and returns a typed outcome. */
|
|
16
|
+
export const writeSignIn = async (input: FormData): Promise<DbOutcome<SignInResult>> => {
|
|
17
|
+
const principal = await getPrincipal()
|
|
18
|
+
if (principal.kind === "ok") return dbOk({ userId: principal.value.id })
|
|
19
|
+
const parsed = signInInputSchema.safeParse(input)
|
|
20
|
+
if (!parsed.success) return dbFailure("invalid", "sign-in-input")
|
|
21
|
+
const client = await createServerDbClient()
|
|
22
|
+
const signedIn = toOutcome(await client.auth.signInWithPassword(parsed.data))
|
|
23
|
+
if (signedIn.kind !== "ok") return signedIn
|
|
24
|
+
return signedIn.value.user === null ? dbFailure("refused", "user") : dbOk({ userId: signedIn.value.user.id })
|
|
25
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use server"
|
|
2
|
+
import "server-only"
|
|
3
|
+
|
|
4
|
+
import { getPrincipal } from "../principal"
|
|
5
|
+
import { createServerDbClient } from "../server"
|
|
6
|
+
import { dbFailure, dbOk } from "../outcome"
|
|
7
|
+
import type { DbOutcome } from "../outcome"
|
|
8
|
+
|
|
9
|
+
/** Ends the cookie-backed Supabase session, including an already-anonymous one. */
|
|
10
|
+
export const writeSignOut = async (): Promise<DbOutcome<true>> => {
|
|
11
|
+
const principal = await getPrincipal()
|
|
12
|
+
void principal
|
|
13
|
+
const client = await createServerDbClient()
|
|
14
|
+
const result = await client.auth.signOut()
|
|
15
|
+
if (result.error === null) return dbOk(true)
|
|
16
|
+
return dbFailure(result.error.status === 401 ? "refused" : "unavailable", result.error.code ?? "sign-out")
|
|
17
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createBrowserClient } from "@supabase/ssr"
|
|
2
|
+
import type { SupabaseClient } from "@supabase/supabase-js"
|
|
3
|
+
import type { Database } from "../../../../../../supabase/types/database.types"
|
|
4
|
+
import { supabaseAnonKey, supabaseUrl } from "@/modules/config"
|
|
5
|
+
|
|
6
|
+
/** Creates the typed public client used only by client-side auth lifecycle hooks. */
|
|
7
|
+
const createBrowserDbClient = (): SupabaseClient<Database> =>
|
|
8
|
+
createBrowserClient<Database>(supabaseUrl(), supabaseAnonKey())
|
|
9
|
+
|
|
10
|
+
/** Owns the browser Auth subscription and exposes only its lifecycle to client hooks. */
|
|
11
|
+
export const subscribeToAuthRefresh = (refresh: () => void): (() => void) => {
|
|
12
|
+
const listener = createBrowserDbClient().auth.onAuthStateChange(refresh)
|
|
13
|
+
return () => listener.data.subscription.unsubscribe()
|
|
14
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** Failure kinds exposed by the database boundary. */
|
|
2
|
+
export type DbFailureKind = "refused" | "not-found" | "invalid" | "unavailable"
|
|
3
|
+
|
|
4
|
+
/** A successful database or Auth operation. */
|
|
5
|
+
export interface DbOk<T> {
|
|
6
|
+
readonly kind: "ok"
|
|
7
|
+
readonly value: T
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** An expected database or Auth failure. */
|
|
11
|
+
export interface DbFailure {
|
|
12
|
+
readonly kind: DbFailureKind
|
|
13
|
+
readonly code: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** The app's one result vocabulary, owned by the lite database transport. */
|
|
17
|
+
export type DbOutcome<T> = DbOk<T> | DbFailure
|
|
18
|
+
|
|
19
|
+
/** The structural part of a Supabase error this boundary interprets. */
|
|
20
|
+
interface SupabaseFailure {
|
|
21
|
+
readonly code?: string
|
|
22
|
+
readonly status?: number
|
|
23
|
+
readonly message: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** The common structural pair returned by Supabase data and Auth calls. */
|
|
27
|
+
export interface SupabaseResult {
|
|
28
|
+
readonly data: unknown
|
|
29
|
+
readonly error: SupabaseFailure | null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The non-null data carried by one concrete SDK result. */
|
|
33
|
+
export type SupabaseData<T extends SupabaseResult> = NonNullable<T["data"]>
|
|
34
|
+
|
|
35
|
+
/** Wraps a value as a successful outcome. */
|
|
36
|
+
export const dbOk = <T>(value: T): DbOk<T> => ({ kind: "ok", value })
|
|
37
|
+
/** Builds a refusal without throwing across a Server Action boundary. */
|
|
38
|
+
export const dbFailure = (kind: DbFailureKind, code: string): DbFailure => ({ kind, code })
|
|
39
|
+
|
|
40
|
+
const hasSignal = (error: SupabaseFailure, signals: ReadonlyArray<string>): boolean => {
|
|
41
|
+
const values = [error.code, error.status === undefined ? undefined : String(error.status)]
|
|
42
|
+
return values.some((value) => value !== undefined && signals.includes(value))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const hasData = <T>(value: T): value is NonNullable<T> => value !== null && value !== undefined
|
|
46
|
+
|
|
47
|
+
/** Maps Supabase's data/error pair into the app's closed outcome vocabulary. */
|
|
48
|
+
export const toOutcome = <T extends SupabaseResult>(result: T): DbOutcome<SupabaseData<T>> => {
|
|
49
|
+
if (result.error === null) {
|
|
50
|
+
return hasData(result.data) ? dbOk(result.data) : dbFailure("not-found", "empty")
|
|
51
|
+
}
|
|
52
|
+
const code = result.error.code ?? String(result.error.status ?? "transport")
|
|
53
|
+
if (hasSignal(result.error, ["42501", "PGRST301", "401", "403", "invalid_credentials"])) {
|
|
54
|
+
return dbFailure("refused", code)
|
|
55
|
+
}
|
|
56
|
+
if (hasSignal(result.error, ["PGRST116"])) return dbFailure("not-found", code)
|
|
57
|
+
if (result.error.code?.startsWith("23") === true) return dbFailure("invalid", code)
|
|
58
|
+
return dbFailure("unavailable", code)
|
|
59
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import "server-only"
|
|
2
|
+
|
|
3
|
+
import { cache } from "react"
|
|
4
|
+
import { createServerDbClient } from "./server"
|
|
5
|
+
import { dbFailure, dbOk, toOutcome } from "./outcome"
|
|
6
|
+
import type { DbOutcome } from "./outcome"
|
|
7
|
+
|
|
8
|
+
/** The trusted caller claims exposed to server readers and writers. */
|
|
9
|
+
export interface Principal {
|
|
10
|
+
readonly id: string
|
|
11
|
+
readonly email?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Keeps only the claims a consumer may trust after `getClaims()` verified the token. */
|
|
15
|
+
export const principalFromClaims = (claims: Readonly<Record<string, unknown>>): DbOutcome<Principal> => {
|
|
16
|
+
if (typeof claims.sub !== "string") return dbFailure("refused", "claims")
|
|
17
|
+
return dbOk({
|
|
18
|
+
id: claims.sub,
|
|
19
|
+
...(typeof claims.email === "string" ? { email: claims.email } : {}),
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Verifies and memoizes the current request principal. */
|
|
24
|
+
export const getPrincipal = cache(async (): Promise<DbOutcome<Principal>> => {
|
|
25
|
+
const client = await createServerDbClient()
|
|
26
|
+
const claims = toOutcome(await client.auth.getClaims())
|
|
27
|
+
if (claims.kind !== "ok") return claims
|
|
28
|
+
return principalFromClaims(claims.value.claims)
|
|
29
|
+
})
|