@starci/hfs 4.0.7 → 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 +22 -0
- package/README.md +86 -43
- 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 +54 -20
- 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/engine/runtime-root.mjs +5 -0
- package/runtime/engine/yaml.mjs +3 -3
- package/runtime/knowledge/hfs/canon-pins.yaml +163 -32
- package/runtime/knowledge/hfs/peer-integrations.yaml +2 -2
- package/runtime/knowledge/hfs/rules.yaml +2059 -0
- package/runtime/knowledge/hfs/slots.yaml +915 -123
- 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 +133 -27
- package/runtime/knowledge/sonar-gate.yaml +53 -19
- package/runtime/modules/kernel/failure-codes.yaml +580 -50
- 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 +14 -0
- package/runtime/scripts/api/fs/safe-remove.mjs +104 -0
- 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 +17 -27
- 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 +10 -6
- package/runtime/scripts/api/sops/lib.mjs +35 -0
- package/runtime/scripts/api/sops/seal.mjs +18 -0
- package/runtime/scripts/{lib/hfs-allows.mjs → hfs/allows.mjs} +3 -3
- package/runtime/scripts/hfs/architecture/ast-walks.mjs +220 -0
- package/runtime/scripts/{checks → hfs}/architecture/backend.mjs +17 -24
- package/runtime/scripts/{checks → hfs}/architecture/background-unowned.mjs +16 -34
- package/runtime/scripts/{checks → hfs}/architecture/client-reaches-server.mjs +3 -1
- package/runtime/scripts/{checks → hfs}/architecture/clones.mjs +4 -4
- package/runtime/scripts/{checks → hfs}/architecture/config.mjs +11 -8
- package/runtime/scripts/{checks → hfs}/architecture/connection-map.mjs +21 -9
- 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/{checks → hfs}/architecture/contract-fixture-guard.mjs +5 -11
- package/runtime/scripts/{checks → hfs}/architecture/contracts.mjs +33 -162
- package/runtime/scripts/{checks → hfs}/architecture/dead-exports.mjs +58 -29
- package/runtime/scripts/{checks → hfs}/architecture/doc-language.mjs +1 -1
- package/runtime/scripts/{checks → hfs}/architecture/entrypoint.mjs +2 -1
- package/runtime/scripts/{checks → hfs}/architecture/fe-slot-allows.mjs +4 -4
- package/runtime/scripts/{checks → hfs}/architecture/feature-shape.mjs +6 -3
- package/runtime/scripts/{checks → hfs}/architecture/framework-pinned.mjs +1 -1
- package/runtime/scripts/{checks → hfs}/architecture/frontend.mjs +17 -43
- package/runtime/scripts/{checks → hfs}/architecture/hfs-graph.mjs +1 -1
- package/runtime/scripts/{checks → hfs}/architecture/hfs.mjs +27 -42
- package/runtime/scripts/{checks → hfs}/architecture/i18n-keys.mjs +1 -1
- package/runtime/scripts/{checks → hfs}/architecture/index.mjs +17 -4
- package/runtime/scripts/{checks → hfs}/architecture/machine-ast.mjs +44 -11
- package/runtime/scripts/hfs/architecture/managed-scripts.mjs +27 -0
- package/runtime/scripts/{checks → hfs}/architecture/module-per-transport.mjs +30 -6
- package/runtime/scripts/hfs/architecture/next-data-contract.mjs +96 -0
- package/runtime/scripts/{checks → hfs}/architecture/next-data.mjs +40 -168
- package/runtime/scripts/{checks → hfs}/architecture/owners.mjs +35 -15
- package/runtime/scripts/{checks → hfs}/architecture/register-once.mjs +2 -1
- package/runtime/scripts/{checks → hfs}/architecture/registration.mjs +23 -81
- package/runtime/scripts/{checks → hfs}/architecture/required-files.mjs +21 -13
- package/runtime/scripts/{checks → 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/{checks → hfs}/architecture/source-names.mjs +27 -147
- package/runtime/scripts/{checks → 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/{checks → hfs}/architecture/surface.mjs +10 -4
- package/runtime/scripts/{checks → hfs}/architecture/test-world-files.mjs +11 -21
- package/runtime/scripts/{checks → hfs}/architecture/tiers.mjs +47 -5
- package/runtime/scripts/{checks → hfs}/architecture/transport-owner.mjs +3 -3
- package/runtime/scripts/{checks → hfs}/architecture/typescript.mjs +13 -27
- package/runtime/scripts/{checks → hfs}/architecture.mjs +5 -5
- package/runtime/scripts/{lib/hfs-check.mjs → hfs/check.mjs} +95 -84
- 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 +247 -0
- package/runtime/scripts/hfs/param-names.mjs +18 -0
- package/runtime/scripts/{lib/hfs-path-findings.mjs → hfs/path-findings.mjs} +7 -7
- package/runtime/scripts/{lib → 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/{lib/hfs-rules → hfs/rules}/contract.mjs +11 -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/{lib/hfs-rules → 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 +66 -0
- package/runtime/scripts/{lib/hfs-rules → hfs/rules}/fe-no-tests.mjs +6 -5
- package/runtime/scripts/{lib/hfs-rules/frontend.mjs → hfs/rules/frontend-tree.mjs} +9 -9
- package/runtime/scripts/{lib/hfs-rules → hfs/rules}/integration-specs.mjs +3 -6
- package/runtime/scripts/hfs/rules/kinds.mjs +84 -0
- package/runtime/scripts/{lib/hfs-rules → hfs/rules}/lint-suppression.mjs +1 -1
- package/runtime/scripts/hfs/rules/monorepo.mjs +179 -0
- package/runtime/scripts/{lib/hfs-rules → hfs/rules}/peer-integrations.mjs +3 -3
- package/runtime/scripts/{lib/hfs-rules → hfs/rules}/pipeline.mjs +11 -21
- package/runtime/scripts/{lib/hfs-rules → hfs/rules}/proof-commands.mjs +2 -2
- package/runtime/scripts/{lib/hfs-rules → hfs/rules}/read.mjs +1 -1
- package/runtime/scripts/{lib/hfs-rules → hfs/rules}/repo-local-checks.mjs +2 -2
- package/runtime/scripts/hfs/rules/saga.mjs +170 -0
- package/runtime/scripts/{lib/hfs-rules → hfs/rules}/secrets.mjs +4 -4
- package/runtime/scripts/hfs/rules/services.mjs +220 -0
- package/runtime/scripts/{lib/hfs-rules → hfs/rules}/spec-placement.mjs +1 -1
- package/runtime/scripts/{lib/hfs-rules → hfs/rules}/stacks.mjs +5 -5
- package/runtime/scripts/hfs/rules/supabase-secrets.mjs +89 -0
- package/runtime/scripts/{lib/hfs-rules → hfs/rules}/test-topology.mjs +2 -2
- package/runtime/scripts/hfs/secret.mjs +175 -0
- package/runtime/scripts/{lib/hfs-slots.mjs → hfs/slots.mjs} +114 -150
- package/runtime/scripts/hfs/sql/pg-parse.mjs +46 -0
- package/runtime/scripts/hfs/test-world-slot.mjs +6 -0
- package/runtime/scripts/{lib/hfs-tree.mjs → hfs/tree.mjs} +6 -5
- package/runtime/scripts/{checks → hfs}/typescript-programs.mjs +0 -5
- package/runtime/scripts/{lib/hfs-view.mjs → hfs/view.mjs} +6 -5
- 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 +429 -0
- package/runtime/scripts/lib/i18n.mjs +86 -0
- package/runtime/scripts/lib/is-main.mjs +13 -0
- package/runtime/scripts/lib/json.mjs +13 -3
- package/runtime/scripts/lib/language.mjs +26 -7
- package/runtime/scripts/lib/list.mjs +20 -0
- package/runtime/scripts/lib/package-at.mjs +37 -0
- package/runtime/scripts/lib/path-key.mjs +59 -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-declaration.mjs +2 -2
- package/runtime/scripts/lib/stack-services.mjs +7 -31
- package/runtime/scripts/lib/ts-ast.mjs +35 -0
- package/runtime/scripts/{checks/common.mjs → lib/walk.mjs} +5 -15
- 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 +359 -70
- package/scaffold/edition-gate.mjs +25 -0
- package/scaffold/image.mjs +19 -0
- package/scaffold/lite-exports.mjs +186 -0
- package/scaffold/service.mjs +33 -27
- 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 +17 -17
- package/sync/index.mjs +171 -71
- 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 +2 -5
- 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/origin.guard.ts +2 -2
- 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 +3 -3
- 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/landing/next.config.ts +21 -0
- 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/apps/__app__ → skeleton-lite/apps/web}/src/modules/i18n/request.ts +4 -2
- 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/engine/admission.mjs +0 -284
- package/runtime/engine/digest.mjs +0 -10
- package/runtime/engine/ledger-db.mjs +0 -1245
- package/runtime/engine/machine-db.mjs +0 -1565
- package/runtime/engine/migrations/machine/0001-init.sql +0 -887
- package/runtime/engine/migrations/machine/0002-worktrees-no-workflow-kind.sql +0 -13
- package/runtime/engine/migrations/machine/0003-worktrees-workflow-orca.sql +0 -21
- package/runtime/engine/migrations/runtime/0001-init.sql +0 -1072
- package/runtime/engine/migrations/runtime/0003-usage-unavailable.sql +0 -13
- package/runtime/engine/migrations/runtime/0004-attempt-why.sql +0 -43
- package/runtime/engine/migrations/runtime/0005-ended-workflow-views.sql +0 -93
- package/runtime/scripts/api/fs/rmdir-link.mjs +0 -12
- package/runtime/scripts/lib/artifact-hold.mjs +0 -89
- package/runtime/scripts/lib/artifact-store.mjs +0 -103
- package/runtime/scripts/lib/redact.mjs +0 -148
- package/runtime/scripts/lib/safe-remove.mjs +0 -275
- package/runtime/scripts/lib/test-secrets.mjs +0 -116
- package/templates/fe/skeleton/apps/__app__/next.config.ts +0 -11
- 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 -21
- package/templates/fe/skeleton/apps/__app__/src/features/pages/ErrorPage/index.tsx +0 -17
- package/templates/fe/skeleton/apps/__app__/src/features/pages/GlobalErrorPage/component.tsx +0 -26
- package/templates/fe/skeleton/apps/__app__/src/features/pages/GlobalErrorPage/index.tsx +0 -15
- package/templates/fe/skeleton/apps/__app__/src/features/pages/HomePage/component.tsx +0 -25
- 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 -27
- 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 -32
- 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/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/runtime/scripts/{checks → hfs}/architecture/config-unread.mjs +0 -0
- /package/runtime/scripts/{checks → hfs}/architecture/constructor-deps.mjs +0 -0
- /package/runtime/scripts/{checks → hfs}/architecture/cross-app-duplicate.mjs +0 -0
- /package/runtime/scripts/{checks → hfs}/architecture/default-deny.mjs +0 -0
- /package/runtime/scripts/{checks → hfs}/architecture/error-codes.mjs +0 -0
- /package/runtime/scripts/{checks → hfs}/architecture/error-masked.mjs +0 -0
- /package/runtime/scripts/{checks → hfs}/architecture/hooks-are-hooks.mjs +0 -0
- /package/runtime/scripts/{checks → hfs}/architecture/injection-token-exported.mjs +0 -0
- /package/runtime/scripts/{checks → hfs}/architecture/package-shape.mjs +0 -0
- /package/runtime/scripts/{checks → hfs}/architecture/reachability.mjs +0 -0
- /package/runtime/scripts/{checks → hfs}/architecture/route-files-thin.mjs +0 -0
- /package/runtime/scripts/{checks → hfs}/architecture/sql-tokens.mjs +0 -0
- /package/runtime/scripts/{checks → hfs}/architecture/symbols.mjs +0 -0
- /package/runtime/scripts/{checks → hfs}/architecture/unit-spec-providers.mjs +0 -0
- /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
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { isInside } from './config.mjs';
|
|
3
|
-
import {
|
|
3
|
+
import { relativePath, UNPROVEN_FRAMEWORK, unwrapExpression } from './typescript.mjs';
|
|
4
|
+
import { commonJsRequireReasons, constructedDecoratorKind, decoratorCallee, moduleExportsOf, mutableDecoratorKind, nodeDecorators, normalizedSymbol, normalizedSymbolValue, programSourcesOf, returnedExpressions, selectedNode, tracedFrameworkKinds, valueSymbol, violation } from './ast-walks.mjs';
|
|
5
|
+
import { sourceLocation } from '../../lib/ts-ast.mjs';
|
|
4
6
|
|
|
5
7
|
const SOURCE_LAYOUT_RULE_ID = 'BE_FEATURE_LAYOUT_INVALID';
|
|
6
8
|
const SOURCE_NAME_RULE_ID = 'BE_SOURCE_FORM';
|
|
@@ -9,16 +11,16 @@ const FRAMEWORK_EXPORTS = new Map([
|
|
|
9
11
|
['typeorm', new Set(['Entity', 'EntitySchema', 'MigrationInterface', 'ViewEntity'])],
|
|
10
12
|
]);
|
|
11
13
|
const APPLICATION_ROLES = new Set(['command', 'contracts', 'handler', 'query']);
|
|
12
|
-
const TRANSPORT_ROLES = new Set(['args', 'cli', 'consumer', 'controller', 'gateway', 'input', '
|
|
14
|
+
const TRANSPORT_ROLES = new Set(['args', 'cli', 'consumer', 'controller', 'gateway', 'input', 'processor', 'request', 'resolver', 'response', 'type']);
|
|
13
15
|
const APPLICATION_LAYER_ROLES = new Set([...APPLICATION_ROLES, 'mapper']);
|
|
14
16
|
const TRANSPORT_LAYER_ROLES = new Set([...TRANSPORT_ROLES, 'enum', 'filter', 'guard', 'interceptor', 'mapper']);
|
|
15
17
|
// Class-bearing roles of the CLOSED suffix list of BE-CONVENTION 1.15 (class name = PascalCase of file + role). A role that is
|
|
16
|
-
// not in that list (adapter, exception,
|
|
18
|
+
// not in that list (adapter, exception, provider, repository, strategy, use-case) is never an allowed role here.
|
|
17
19
|
const CLASS_ROLE_SUFFIX = new Map([
|
|
18
20
|
['args', 'Args'], ['cli', 'Cli'], ['client', 'Client'], ['command', 'Command'], ['consumer', 'Consumer'],
|
|
19
21
|
['controller', 'Controller'], ['entity', 'Entity'], ['error', 'Error'], ['filter', 'Filter'], ['gateway', 'Gateway'],
|
|
20
|
-
['guard', 'Guard'], ['handler', 'Handler'], ['input', 'Input'], ['interceptor', 'Interceptor'], ['
|
|
21
|
-
['mapper', 'Mapper'], ['module', 'Module'], ['module-definition', 'Module'], ['policy', 'Policy'], ['query', 'Query'],
|
|
22
|
+
['guard', 'Guard'], ['handler', 'Handler'], ['input', 'Input'], ['interceptor', 'Interceptor'], ['processor', 'Processor'], ['event', 'Event'], ['queue', 'Queue'],
|
|
23
|
+
['projection', 'Projection'], ['projection-entity', 'ProjectionEntity'], ['step', 'Step'], ['mapper', 'Mapper'], ['module', 'Module'], ['module-definition', 'Module'], ['policy', 'Policy'], ['query', 'Query'],
|
|
22
24
|
['request', 'Request'], ['resolver', 'Resolver'], ['response', 'Response'], ['service', 'Service'], ['type', 'Type'],
|
|
23
25
|
]);
|
|
24
26
|
// Transport object contracts (interfaces and object aliases) named by their file role: <Action>Input in *.input.ts,
|
|
@@ -41,162 +43,40 @@ function canonical(file) {
|
|
|
41
43
|
return path.resolve(file);
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
function normalizedSymbolValue(ts, checker, value) {
|
|
45
|
-
let symbol = value ?? null;
|
|
46
|
-
const seen = new Set();
|
|
47
|
-
while (symbol && (symbol.flags & ts.SymbolFlags.Alias) && !seen.has(symbol)) {
|
|
48
|
-
seen.add(symbol);
|
|
49
|
-
const target = checker.getAliasedSymbol(symbol);
|
|
50
|
-
if (!target || target === symbol) break;
|
|
51
|
-
symbol = target;
|
|
52
|
-
}
|
|
53
|
-
return symbol;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function normalizedSymbol(ts, checker, node) {
|
|
57
|
-
return normalizedSymbolValue(ts, checker, checker?.getSymbolAtLocation(node) ?? null);
|
|
58
|
-
}
|
|
59
46
|
|
|
60
|
-
function selectedNode(ts, expression) {
|
|
61
|
-
expression = unwrapExpression(ts, expression);
|
|
62
|
-
if (ts.isIdentifier(expression)) return expression;
|
|
63
|
-
if (ts.isPropertyAccessExpression(expression)) return expression.name;
|
|
64
|
-
if (ts.isElementAccessExpression(expression) && ts.isStringLiteralLike(expression.argumentExpression)) return expression.argumentExpression;
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function valueSymbol(ts, checker, node, seen = new Set()) {
|
|
69
|
-
const selected = selectedNode(ts, node) ?? node;
|
|
70
|
-
const symbol = normalizedSymbol(ts, checker, selected);
|
|
71
|
-
if (!symbol || seen.has(symbol)) return symbol;
|
|
72
|
-
seen.add(symbol);
|
|
73
|
-
const declarations = symbol.getDeclarations?.() ?? [];
|
|
74
|
-
if (declarations.length === 1 && ts.isVariableDeclaration(declarations[0]) && declarations[0].initializer
|
|
75
|
-
&& (ts.getCombinedNodeFlags(declarations[0].parent) & ts.NodeFlags.Const)) {
|
|
76
|
-
return valueSymbol(ts, checker, declarations[0].initializer, seen);
|
|
77
|
-
}
|
|
78
|
-
return symbol;
|
|
79
|
-
}
|
|
80
47
|
|
|
81
48
|
function frameworkTargets(config, context, checker, localFiles) {
|
|
82
|
-
const bySymbol = new Map();
|
|
83
49
|
const reasons = [];
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
50
|
+
const bySymbol = new Map();
|
|
51
|
+
const files = programSourcesOf(context, checker, localFiles);
|
|
52
|
+
if (!files) return { bySymbol, reasons: ['a TypeScript program checker could not be associated with its source'] };
|
|
53
|
+
for (const sourceFile of files) {
|
|
88
54
|
for (const statement of sourceFile.statements) {
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
if (!moduleSymbol) {
|
|
95
|
-
reasons.push(`${relativePath(config.root, sourceFile.fileName)} cannot resolve ${specifier}`);
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
const selected = FRAMEWORK_EXPORTS.get(specifier);
|
|
99
|
-
for (const exported of checker.getExportsOfModule(moduleSymbol)) if (selected.has(exported.getName())) {
|
|
100
|
-
const target = normalizedSymbolValue(context.ts, checker, exported);
|
|
101
|
-
if (target) bySymbol.set(target, exported.getName());
|
|
102
|
-
}
|
|
55
|
+
const bound = moduleExportsOf(context.ts, checker, statement);
|
|
56
|
+
if (!bound || !FRAMEWORK_EXPORTS.has(bound.specifier)) continue;
|
|
57
|
+
if (!bound.symbol) { reasons.push(`${relativePath(config.root, sourceFile.fileName)} cannot resolve ${bound.specifier}`); continue; }
|
|
58
|
+
const selected = FRAMEWORK_EXPORTS.get(bound.specifier);
|
|
59
|
+
for (const [name, target] of bound.exports) if (selected.has(name) && target) bySymbol.set(target, name);
|
|
103
60
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
&& node.arguments.length === 1 && context.ts.isStringLiteralLike(node.arguments[0]) && FRAMEWORK_EXPORTS.has(node.arguments[0].text)) {
|
|
107
|
-
reasons.push(`${relativePath(config.root, sourceFile.fileName)} uses a CommonJS ${node.arguments[0].text} binding whose source role cannot be proved`);
|
|
108
|
-
}
|
|
109
|
-
context.ts.forEachChild(node, visit);
|
|
110
|
-
};
|
|
111
|
-
visit(sourceFile);
|
|
61
|
+
commonJsRequireReasons(context.ts, checker, sourceFile, (specifier) => FRAMEWORK_EXPORTS.has(specifier),
|
|
62
|
+
reasons, relativePath(config.root, sourceFile.fileName), 'binding whose source role cannot be proved');
|
|
112
63
|
}
|
|
113
64
|
return { bySymbol, reasons };
|
|
114
65
|
}
|
|
115
66
|
|
|
116
|
-
function calledExpression(ts, decorator) {
|
|
117
|
-
return ts.isCallExpression(decorator.expression) ? decorator.expression.expression : decorator.expression;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
67
|
function decoratorKind(ts, checker, decorator, targets) {
|
|
121
|
-
const selected = selectedNode(ts,
|
|
68
|
+
const selected = selectedNode(ts, decoratorCallee(ts, decorator));
|
|
122
69
|
return selected ? targets.get(valueSymbol(ts, checker, selected)) ?? null : null;
|
|
123
70
|
}
|
|
124
71
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const symbol = selected ? normalizedSymbol(ts, checker, selected) : null;
|
|
128
|
-
const declarations = symbol?.getDeclarations?.() ?? [];
|
|
129
|
-
if (declarations.length !== 1 || !ts.isVariableDeclaration(declarations[0]) || !declarations[0].initializer
|
|
130
|
-
|| (ts.getCombinedNodeFlags(declarations[0].parent) & ts.NodeFlags.Const)) return null;
|
|
131
|
-
return targets.get(valueSymbol(ts, checker, declarations[0].initializer)) ?? null;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function returnedExpressions(ts, declaration) {
|
|
135
|
-
if ((ts.isArrowFunction(declaration) || ts.isFunctionExpression(declaration)) && !ts.isBlock(declaration.body)) return [declaration.body];
|
|
136
|
-
const body = ts.isFunctionDeclaration(declaration) || ts.isMethodDeclaration(declaration)
|
|
137
|
-
|| ts.isArrowFunction(declaration) || ts.isFunctionExpression(declaration) ? declaration.body : null;
|
|
138
|
-
if (!body || !ts.isBlock(body)) return [];
|
|
139
|
-
const returned = [];
|
|
140
|
-
const visit = node => {
|
|
141
|
-
if (node !== body && (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node))) return;
|
|
142
|
-
if (ts.isReturnStatement(node) && node.expression) returned.push(node.expression);
|
|
143
|
-
else ts.forEachChild(node, visit);
|
|
144
|
-
};
|
|
145
|
-
visit(body);
|
|
146
|
-
return returned;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function tracedFrameworkKinds(ts, checker, expression, targets, seen = new Set(), depth = 0) {
|
|
150
|
-
if (!expression) return new Set();
|
|
151
|
-
if (depth > 10) return new Set([UNPROVEN_FRAMEWORK]);
|
|
152
|
-
expression = unwrapExpression(ts, expression);
|
|
153
|
-
const selected = selectedNode(ts, expression);
|
|
154
|
-
const symbol = selected ? normalizedSymbol(ts, checker, selected) : null;
|
|
155
|
-
const direct = symbol ? targets.get(symbol) : null;
|
|
156
|
-
if (direct) return new Set([direct]);
|
|
157
|
-
if (ts.isArrowFunction(expression) || ts.isFunctionExpression(expression)) {
|
|
158
|
-
const kinds = new Set();
|
|
159
|
-
for (const returned of returnedExpressions(ts, expression)) {
|
|
160
|
-
for (const kind of tracedFrameworkKinds(ts, checker, returned, targets, seen, depth + 1)) kinds.add(kind);
|
|
161
|
-
}
|
|
162
|
-
return kinds;
|
|
163
|
-
}
|
|
164
|
-
if (ts.isCallExpression(expression)) {
|
|
165
|
-
const kinds = tracedFrameworkKinds(ts, checker, expression.expression, targets, seen, depth + 1);
|
|
166
|
-
if (kinds.size) return kinds;
|
|
167
|
-
}
|
|
168
|
-
if (ts.isNewExpression(expression)) return tracedFrameworkKinds(ts, checker, expression.expression, targets, seen, depth + 1);
|
|
169
|
-
if (!symbol || seen.has(symbol)) return new Set();
|
|
170
|
-
const nextSeen = new Set(seen).add(symbol);
|
|
171
|
-
const kinds = new Set();
|
|
172
|
-
for (const declaration of symbol.getDeclarations?.() ?? []) {
|
|
173
|
-
if (ts.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
174
|
-
for (const kind of tracedFrameworkKinds(ts, checker, declaration.initializer, targets, nextSeen, depth + 1)) kinds.add(kind);
|
|
175
|
-
}
|
|
176
|
-
for (const returned of returnedExpressions(ts, declaration)) {
|
|
177
|
-
for (const kind of tracedFrameworkKinds(ts, checker, returned, targets, nextSeen, depth + 1)) kinds.add(kind);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return kinds;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
function constructedDecoratorKind(ts, checker, decorator, targets) {
|
|
184
|
-
const kinds = tracedFrameworkKinds(ts, checker, calledExpression(ts, decorator), targets);
|
|
185
|
-
if (kinds.has(UNPROVEN_FRAMEWORK)) return 'unproven framework';
|
|
186
|
-
return kinds.size === 1 ? [...kinds][0] : kinds.size ? 'multiple framework' : null;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function decorators(ts, node) {
|
|
190
|
-
return ts.canHaveDecorators(node) ? ts.getDecorators(node) ?? [] : node.decorators ?? [];
|
|
191
|
-
}
|
|
72
|
+
/* This module's trace descends `new X()` callees too; the framework map keys symbols directly. */
|
|
73
|
+
const TRACE_NEW = { newExpression: true };
|
|
192
74
|
|
|
193
75
|
function hasModifier(ts, node, kind) {
|
|
194
76
|
return (ts.canHaveModifiers(node) ? ts.getModifiers(node) ?? [] : node.modifiers ?? []).some(modifier => modifier.kind === kind);
|
|
195
77
|
}
|
|
196
78
|
|
|
197
|
-
|
|
198
|
-
return { ruleId, path: relativePath(config.root, sourceFile.fileName), ...sourceLocation(sourceFile, node), message, ...extra };
|
|
199
|
-
}
|
|
79
|
+
|
|
200
80
|
|
|
201
81
|
function sourceRole(ts, sourceFile) {
|
|
202
82
|
const file = path.basename(sourceFile.fileName).replace(SOURCE_EXTENSION, '');
|
|
@@ -304,7 +184,7 @@ function companionInterfaceAllowed(ts, sourceFile, name) {
|
|
|
304
184
|
if (!/^I[A-Z]/.test(name)) return false;
|
|
305
185
|
const companion = name.slice(1);
|
|
306
186
|
return sourceFile.statements.some(statement => ts.isClassDeclaration(statement) && statement.name?.text === companion
|
|
307
|
-
&&
|
|
187
|
+
&& nodeDecorators(ts, statement).length > 0);
|
|
308
188
|
}
|
|
309
189
|
|
|
310
190
|
function camelCase(value) {
|
|
@@ -485,7 +365,7 @@ export function checkBackendSourceShape(config, context) {
|
|
|
485
365
|
|
|
486
366
|
const classDeclarations = sourceFile.statements.filter(statement => ts.isClassDeclaration(statement));
|
|
487
367
|
for (const declaration of classDeclarations) {
|
|
488
|
-
const declarationDecorators =
|
|
368
|
+
const declarationDecorators = nodeDecorators(ts, declaration);
|
|
489
369
|
const kinds = declarationDecorators.map(decorator => decoratorKind(ts, checker, decorator, framework.bySymbol)).filter(Boolean);
|
|
490
370
|
const graphQlDto = kinds.some(kind => kind === 'ArgsType' || kind === 'InputType' || kind === 'ObjectType');
|
|
491
371
|
if (graphQlDto && (!featureRoot || !inTransport || directories[transportIndex + 1] !== 'graphql')) {
|
|
@@ -551,11 +431,11 @@ export function checkBackendSourceShape(config, context) {
|
|
|
551
431
|
}
|
|
552
432
|
|
|
553
433
|
const visit = node => {
|
|
554
|
-
for (const decorator of
|
|
434
|
+
for (const decorator of nodeDecorators(ts, node)) {
|
|
555
435
|
const kind = decoratorKind(ts, checker, decorator, framework.bySymbol);
|
|
556
436
|
if (!kind) {
|
|
557
437
|
const dynamic = mutableDecoratorKind(ts, checker, decorator, framework.bySymbol)
|
|
558
|
-
?? constructedDecoratorKind(ts, checker, decorator, framework.bySymbol);
|
|
438
|
+
?? constructedDecoratorKind(ts, checker, decorator, framework.bySymbol, TRACE_NEW);
|
|
559
439
|
if (dynamic) {
|
|
560
440
|
const detail = `${relative} uses a mutable or constructed ${dynamic} decorator identity`;
|
|
561
441
|
if (['Entity', 'ViewEntity', 'ArgsType', 'InputType', 'ObjectType', 'multiple framework', 'unproven framework'].includes(dynamic)) layoutReasons.push(detail);
|
|
@@ -574,7 +454,7 @@ export function checkBackendSourceShape(config, context) {
|
|
|
574
454
|
}
|
|
575
455
|
const exportedFactoryCall = ts.isCallExpression(node) && ts.isVariableDeclaration(node.parent) && publicDeclarations.has(node.parent);
|
|
576
456
|
if ((ts.isNewExpression(node) || exportedFactoryCall) && featureRoot) {
|
|
577
|
-
const constructed = tracedFrameworkKinds(ts, checker, node, framework.bySymbol);
|
|
457
|
+
const constructed = tracedFrameworkKinds(ts, checker, node, framework.bySymbol, TRACE_NEW);
|
|
578
458
|
if (constructed.has('EntitySchema')) violations.push(violation(config, sourceFile, node.expression, SOURCE_LAYOUT_RULE_ID,
|
|
579
459
|
'TypeORM EntitySchema cannot be owned by a feature; place schema under its declared persistence module.'));
|
|
580
460
|
if (constructed.has(UNPROVEN_FRAMEWORK)) layoutReasons.push(`${relative} has a constructed provider identity beyond the bounded static trace`);
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { analyzeSql, HOLE } from './sql-tokens.mjs';
|
|
3
3
|
import { machineKit } from './machine-ast.mjs';
|
|
4
|
+
import { contextModelOf } from './context-map.mjs';
|
|
5
|
+
import { supabaseTablesOf } from './supabase-tables.mjs';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* R86 `sql-owner` (BE_SQL_TABLE_OWNER). Every `sql` tagged template (the tag declared in platform/database) of a
|
|
7
9
|
* `<name>.sql.ts` file in a capability's `persistence/` is read with the tokenizer of sql-tokens.mjs and judged against the
|
|
8
|
-
*
|
|
9
|
-
* - it writes (INSERT INTO, UPDATE, DELETE FROM, MERGE INTO, TRUNCATE) only tables the file's own capability declares
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* - every table it names is declared by some entity
|
|
10
|
+
* schema authority of the whole program:
|
|
11
|
+
* - it writes (INSERT INTO, UPDATE, DELETE FROM, MERGE INTO, TRUNCATE) only tables the file's own capability declares;
|
|
12
|
+
* - it reads (FROM, JOIN, USING) only tables of its own CONTEXT (the connection its capability's arrays are registered on): its own
|
|
13
|
+
* capability's, or those of a same-context capability its owner may import (the tier matrix, through `resolver.importAllowed`
|
|
14
|
+
* to the table owner's public entry); a table of another context is refused (cross-context data comes only by events);
|
|
15
|
+
* - every table it names is declared by some entity under TypeORM authority, or by the generated
|
|
16
|
+
* `Database['public']['Tables']` contract under Supabase authority;
|
|
14
17
|
* - a SELECT carries LIMIT, or constrains the primary key or a unique key of its first table with `=`, or selects only
|
|
15
18
|
* aggregates without GROUP BY.
|
|
16
19
|
* Table positions that hold a `${...}` substitution (SqlIdent) are dynamic; they are counted in the coverage and judged by
|
|
@@ -28,7 +31,7 @@ const literalStrings = (ts, node) => {
|
|
|
28
31
|
return null;
|
|
29
32
|
};
|
|
30
33
|
|
|
31
|
-
function entitiesOf(kit, graph) {
|
|
34
|
+
export function entitiesOf(kit, graph) {
|
|
32
35
|
const { ts } = kit;
|
|
33
36
|
const tables = new Map();
|
|
34
37
|
let unreadable = 0;
|
|
@@ -90,11 +93,29 @@ function entitiesOf(kit, graph) {
|
|
|
90
93
|
return { tables, unreadable };
|
|
91
94
|
}
|
|
92
95
|
|
|
96
|
+
const capabilityTable = root => path.posix.basename(root).replaceAll('-', '_').toLowerCase();
|
|
97
|
+
|
|
98
|
+
/** Supabase declarations, with an owner when the generated table name matches a capability's persistence folder. */
|
|
99
|
+
function supabaseDeclarations(graph, appRoot, ts) {
|
|
100
|
+
const generated = supabaseTablesOf(appRoot, ts);
|
|
101
|
+
const tables = new Map([...generated].map(table => [table, { table, owner: null, rel: null, uniqueSets: [] }]));
|
|
102
|
+
for (const file of graph.files.values()) {
|
|
103
|
+
if (file.slot !== 'be.persistence' || !file.owner) continue;
|
|
104
|
+
const key = capabilityTable(file.owner.root);
|
|
105
|
+
const declaration = tables.get(key);
|
|
106
|
+
if (declaration && declaration.owner === null) tables.set(key, { ...declaration, owner: file.owner.root, rel: file.rel });
|
|
107
|
+
}
|
|
108
|
+
return tables;
|
|
109
|
+
}
|
|
110
|
+
|
|
93
111
|
export function checkSqlOwner(input) {
|
|
94
|
-
const { graph } = input;
|
|
112
|
+
const { config, graph } = input;
|
|
95
113
|
const kit = machineKit(input);
|
|
96
114
|
const { ts, resolver } = kit;
|
|
97
|
-
const
|
|
115
|
+
const supabase = resolver.ruleParams().schemaAuthority === 'supabase';
|
|
116
|
+
const entityDeclarations = supabase ? { tables: new Map(), unreadable: 0 } : entitiesOf(kit, graph);
|
|
117
|
+
const tables = supabase ? supabaseDeclarations(graph, config.packageRoot, ts) : entityDeclarations.tables;
|
|
118
|
+
const model = contextModelOf(kit, graph);
|
|
98
119
|
const violations = [];
|
|
99
120
|
let templates = 0;
|
|
100
121
|
let dynamic = 0;
|
|
@@ -119,17 +140,36 @@ export function checkSqlOwner(input) {
|
|
|
119
140
|
};
|
|
120
141
|
const result = analyzeSql(text, { uniqueSetsOf: table => tables.get(table.toLowerCase())?.uniqueSets ?? null });
|
|
121
142
|
dynamic += result.dynamic;
|
|
143
|
+
const ownTable = capabilityTable(file.owner.root);
|
|
122
144
|
for (const write of result.writes) {
|
|
123
|
-
const
|
|
124
|
-
if (!
|
|
125
|
-
|
|
145
|
+
const declaration = tables.get(write.table.toLowerCase());
|
|
146
|
+
if (!declaration) {
|
|
147
|
+
report(supabase
|
|
148
|
+
? `SQL writes table ${write.table}, which Database['public']['Tables'] does not declare; regenerate supabase/types/database.types.ts from the migrations.`
|
|
149
|
+
: `SQL writes table ${write.table}, which no @Entity declares; declare the entity in the owning capability's persistence/entities.`, { table: write.table });
|
|
150
|
+
} else if (supabase && write.table.toLowerCase() !== ownTable) {
|
|
151
|
+
report(`SQL in ${file.owner.root} writes table ${write.table}${declaration.owner ? `, owned by ${declaration.owner}` : ''}; under Supabase schema authority a capability writes only its own table (${ownTable}), named for that capability.`, { table: write.table, ...(declaration.owner ? { tableOwner: declaration.owner } : {}) });
|
|
152
|
+
} else if (!supabase && declaration.owner !== file.owner.root) {
|
|
153
|
+
report(`SQL in ${file.owner.root} writes table ${write.table}, owned by ${declaration.owner}; a capability writes only the tables of its own entities, call the owner's public API instead.`, { table: write.table, tableOwner: declaration.owner });
|
|
154
|
+
}
|
|
126
155
|
}
|
|
127
156
|
for (const read of result.reads) {
|
|
128
|
-
const
|
|
129
|
-
if (!
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
157
|
+
const declaration = tables.get(read.table.toLowerCase());
|
|
158
|
+
if (!declaration) {
|
|
159
|
+
report(supabase
|
|
160
|
+
? `SQL reads table ${read.table}, which Database['public']['Tables'] does not declare; regenerate supabase/types/database.types.ts from the migrations.`
|
|
161
|
+
: `SQL reads table ${read.table}, which no @Entity declares; declare the entity in the owning capability's persistence/entities.`, { table: read.table });
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (!declaration.owner || declaration.owner === file.owner.root) continue;
|
|
165
|
+
const ownContext = model.contextOfCapability(file.owner.root);
|
|
166
|
+
const tableContext = model.contextOfCapability(declaration.owner);
|
|
167
|
+
if (ownContext && tableContext && ownContext !== tableContext) {
|
|
168
|
+
report(`SQL in ${file.owner.root} (context ${ownContext}) reads table ${read.table}, owned by ${declaration.owner} (context ${tableContext}); a context reads and writes only its own context's tables, so a cross-context JOIN or subquery is refused. Keep a local copy fed by the other context's events (a reactor), or read a projection.`, { table: read.table, tableOwner: declaration.owner, context: ownContext, tableContext });
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const verdict = resolver.importAllowed(file.rel, `${declaration.owner}/index.ts`);
|
|
172
|
+
if (!verdict.allowed) report(`SQL in ${file.owner.root} reads table ${read.table}, owned by ${declaration.owner}, which ${file.owner.root} may not import (${verdict.reason}); read it through the owner's public API.`, { table: read.table, tableOwner: declaration.owner, reason: verdict.reason });
|
|
133
173
|
}
|
|
134
174
|
for (const select of result.selects) {
|
|
135
175
|
if (select.bounded || (select.table && !tables.has(select.table.toLowerCase()))) continue;
|
|
@@ -138,5 +178,6 @@ export function checkSqlOwner(input) {
|
|
|
138
178
|
return true;
|
|
139
179
|
});
|
|
140
180
|
}
|
|
141
|
-
return { violations, coverage: { status: 'checked', entities: tables.size, unreadableEntities: unreadable,
|
|
181
|
+
return { violations, coverage: { status: 'checked', entities: entityDeclarations.tables.size, unreadableEntities: entityDeclarations.unreadable,
|
|
182
|
+
...(supabase ? { supabaseTables: tables.size } : {}), templates, dynamicIdentifiers: dynamic, foreignTags } };
|
|
142
183
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { HOLE, tokenizeSql } from './sql-tokens.mjs';
|
|
3
|
+
import { machineKit } from './machine-ast.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* R181 `sql-returning` (BE_SQL_RETURNING_SHAPE). TypeORM's `EntityManager.query` returns an UPDATE or DELETE with RETURNING as
|
|
7
|
+
* `[rows, affectedCount]`, not as rows (an INSERT ... RETURNING returns rows), so a caller that reads the result as rows silently reads
|
|
8
|
+
* the wrong thing and no unit spec that stubs the SQL can see it. Every `sql` tagged template (the tag declared in platform/database) of a
|
|
9
|
+
* `<name>.sql.ts` file in a capability's `persistence/` is read with the tokenizer of sql-tokens.mjs, split into statements at top-level
|
|
10
|
+
* semicolons, and a statement that STARTS with UPDATE or DELETE and carries RETURNING at the top level is refused: write it as
|
|
11
|
+
* `WITH changed AS (UPDATE ... RETURNING ...) SELECT ... FROM changed`, which returns rows. A RETURNING inside a parenthesised CTE is the
|
|
12
|
+
* wrapped form and passes; so does INSERT ... RETURNING and any statement without RETURNING.
|
|
13
|
+
*/
|
|
14
|
+
export const SQL_RETURNING_RULE_IDS = ['BE_SQL_RETURNING_SHAPE'];
|
|
15
|
+
|
|
16
|
+
const RULE = 'BE_SQL_RETURNING_SHAPE';
|
|
17
|
+
|
|
18
|
+
/** The leading verbs of the top-level statements of `text` that RETURN from an UPDATE or DELETE without a wrapping SELECT. */
|
|
19
|
+
function unwrappedReturning(text) {
|
|
20
|
+
const found = [];
|
|
21
|
+
let depth = 0;
|
|
22
|
+
let verb = null;
|
|
23
|
+
let returning = false;
|
|
24
|
+
const close = () => { if (verb && returning) found.push(verb); verb = null; returning = false; };
|
|
25
|
+
for (const token of tokenizeSql(text)) {
|
|
26
|
+
if (token.t === 'punct') {
|
|
27
|
+
if (token.v === '(') depth += 1;
|
|
28
|
+
else if (token.v === ')') depth = Math.max(0, depth - 1);
|
|
29
|
+
else if (token.v === ';' && depth === 0) close();
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (depth !== 0 || token.t !== 'word') continue;
|
|
33
|
+
if (verb === null) verb = token.up;
|
|
34
|
+
else if (token.up === 'RETURNING') returning = true;
|
|
35
|
+
}
|
|
36
|
+
close();
|
|
37
|
+
return found.filter(verb => verb === 'UPDATE' || verb === 'DELETE');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function checkSqlReturning(input) {
|
|
41
|
+
const { graph } = input;
|
|
42
|
+
const kit = machineKit(input);
|
|
43
|
+
const { ts } = kit;
|
|
44
|
+
const violations = [];
|
|
45
|
+
let templates = 0;
|
|
46
|
+
for (const file of graph.files.values()) {
|
|
47
|
+
if (file.slot !== 'be.persistence' || !path.posix.basename(file.rel).endsWith('.sql.ts') || !file.owner) continue;
|
|
48
|
+
const checker = kit.checkerOf(file.sourceFile);
|
|
49
|
+
kit.walk(file.sourceFile, node => {
|
|
50
|
+
if (!ts.isTaggedTemplateExpression(node)) return true;
|
|
51
|
+
const home = kit.declarationsOf(checker, node.tag).map(kit.ownerOfDeclaration).find(Boolean);
|
|
52
|
+
if (!home || home.tier !== 'platform' || home.name !== 'database') return true;
|
|
53
|
+
templates += 1;
|
|
54
|
+
const template = node.template;
|
|
55
|
+
const text = ts.isNoSubstitutionTemplateLiteral(template) ? template.text
|
|
56
|
+
: template.head.text + template.templateSpans.map(span => HOLE + span.literal.text).join('');
|
|
57
|
+
for (const verb of unwrappedReturning(text)) {
|
|
58
|
+
violations.push({ ruleId: RULE, path: file.rel, ...kit.at(file.rel, file.sourceFile, node), message: `${verb} ... RETURNING in ${file.rel} is returned by EntityManager.query as [rows, affectedCount], not as rows, so a caller reading rows reads the wrong value. Wrap it: WITH changed AS (${verb} ... RETURNING ...) SELECT ... FROM changed.`, verb });
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return { violations, coverage: { status: 'checked', templates } };
|
|
64
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// supabase-ast.mjs - shared TypeScript-symbol and expression helpers for the front-end and back-end Supabase
|
|
2
|
+
// architecture checks. Recognition follows imported declarations and inferred types, never local spelling alone.
|
|
3
|
+
export const SUPABASE_MODULES = new Set(['@supabase/ssr', '@supabase/supabase-js']);
|
|
4
|
+
|
|
5
|
+
export const moduleNameOf = (ts, node) => {
|
|
6
|
+
if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) && node.moduleSpecifier && ts.isStringLiteralLike(node.moduleSpecifier)) return node.moduleSpecifier.text;
|
|
7
|
+
if (!ts.isCallExpression(node)) return null;
|
|
8
|
+
const dynamic = node.expression.kind === ts.SyntaxKind.ImportKeyword;
|
|
9
|
+
const required = ts.isIdentifier(node.expression) && node.expression.text === 'require';
|
|
10
|
+
return (dynamic || required) && node.arguments.length === 1 && ts.isStringLiteralLike(node.arguments[0]) ? node.arguments[0].text : null;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const importedFrom = (kit, checker, node, modules, names = null) => {
|
|
14
|
+
const binding = kit.importBinding(checker, node);
|
|
15
|
+
return Boolean(binding && modules.has(binding.module) && (names === null || names.has(binding.name)));
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const declarationFromSupabase = (declaration) => /(?:^|\/)node_modules\/@supabase\/(?:ssr|supabase-js|auth-js|postgrest-js|storage-js)(?:\/|$)/u
|
|
19
|
+
.test(String(declaration?.getSourceFile?.().fileName ?? '').replace(/\\/gu, '/'));
|
|
20
|
+
|
|
21
|
+
const typeFromSupabase = (checker, node) => {
|
|
22
|
+
let type;
|
|
23
|
+
try { type = checker.getTypeAtLocation(node); } catch { return false; }
|
|
24
|
+
const queue = [type];
|
|
25
|
+
const seen = new Set();
|
|
26
|
+
while (queue.length) {
|
|
27
|
+
const item = queue.shift();
|
|
28
|
+
if (!item || seen.has(item)) continue;
|
|
29
|
+
seen.add(item);
|
|
30
|
+
if ([item.symbol, item.aliasSymbol].some((symbol) => symbol?.declarations?.some(declarationFromSupabase))) return true;
|
|
31
|
+
if (item.types) queue.push(...item.types);
|
|
32
|
+
if (item.target && item.target !== item) queue.push(item.target);
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const signatureFromSupabase = (checker, call) => {
|
|
38
|
+
try { return declarationFromSupabase(checker.getResolvedSignature(call)?.declaration); } catch { return false; }
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const unwrap = (ts, node) => {
|
|
42
|
+
let current = node;
|
|
43
|
+
while (current && (ts.isParenthesizedExpression(current) || ts.isAwaitExpression(current) || ts.isAsExpression(current)
|
|
44
|
+
|| ts.isTypeAssertionExpression(current) || ts.isNonNullExpression(current))) current = current.expression;
|
|
45
|
+
return current;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const isSupabaseValue = (kit, checker, node) => {
|
|
49
|
+
const current = unwrap(kit.ts, node);
|
|
50
|
+
if (!current) return false;
|
|
51
|
+
if (importedFrom(kit, checker, current, SUPABASE_MODULES)) return true;
|
|
52
|
+
if (kit.ts.isCallExpression(current) && signatureFromSupabase(checker, current)) return true;
|
|
53
|
+
return typeFromSupabase(checker, current);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const callName = (ts, call) => ts.isCallExpression(call) && ts.isPropertyAccessExpression(call.expression) ? call.expression.name.text : null;
|
|
57
|
+
|
|
58
|
+
export const chainParts = (ts, expression) => {
|
|
59
|
+
const names = [];
|
|
60
|
+
let current = unwrap(ts, expression);
|
|
61
|
+
while (current) {
|
|
62
|
+
if (ts.isCallExpression(current)) {
|
|
63
|
+
if (ts.isPropertyAccessExpression(current.expression)) {
|
|
64
|
+
names.unshift(current.expression.name.text);
|
|
65
|
+
current = unwrap(ts, current.expression.expression);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
current = unwrap(ts, current.expression);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (ts.isPropertyAccessExpression(current)) {
|
|
72
|
+
names.unshift(current.name.text);
|
|
73
|
+
current = unwrap(ts, current.expression);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
return names;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const isSupabaseCall = (kit, checker, node) => kit.ts.isCallExpression(node)
|
|
82
|
+
&& (signatureFromSupabase(checker, node) || isSupabaseValue(kit, checker, kit.ts.isPropertyAccessExpression(node.expression) ? node.expression.expression : node.expression));
|
|
83
|
+
|
|
84
|
+
export const isDatabaseType = (ts, node) => {
|
|
85
|
+
if (!node) return false;
|
|
86
|
+
if (ts.isTypeReferenceNode(node)) {
|
|
87
|
+
const name = ts.isIdentifier(node.typeName) ? node.typeName.text : node.typeName.right.text;
|
|
88
|
+
return name === 'Database';
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const supabaseClientType = (kit, checker, node) => {
|
|
94
|
+
if (!node || !kit.ts.isTypeReferenceNode(node)) return false;
|
|
95
|
+
const name = kit.ts.isIdentifier(node.typeName) ? node.typeName : null;
|
|
96
|
+
return Boolean(name && importedFrom(kit, checker, name, SUPABASE_MODULES, new Set(['SupabaseClient'])));
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const contextTypesClient = (kit, checker, call) => {
|
|
100
|
+
let parent = call.parent;
|
|
101
|
+
while (parent && (kit.ts.isParenthesizedExpression(parent) || kit.ts.isAsExpression(parent))) {
|
|
102
|
+
if (kit.ts.isAsExpression(parent) && supabaseClientType(kit, checker, parent.type) && isDatabaseType(kit.ts, parent.type.typeArguments?.[0])) return true;
|
|
103
|
+
parent = parent.parent;
|
|
104
|
+
}
|
|
105
|
+
return kit.ts.isVariableDeclaration(parent) && supabaseClientType(kit, checker, parent.type)
|
|
106
|
+
&& isDatabaseType(kit.ts, parent.type.typeArguments?.[0]);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const reportAt = (violations, kit, ruleId, file, node, message, extra = {}) => {
|
|
110
|
+
violations.push({ ruleId, ...kit.at(file.rel, file.sourceFile, node), message, ...extra });
|
|
111
|
+
};
|