@starci/hfs 4.11.21 → 4.12.0
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 +28 -0
- package/README.md +31 -31
- package/ci/cli.d.mts +15 -0
- package/ci/cli.mjs +71 -52
- package/ci/github.d.mts +43 -0
- package/ci/github.mjs +33 -28
- package/ci/local.d.mts +12 -0
- package/ci/local.mjs +145 -108
- package/ci/secret.d.mts +15 -0
- package/ci/secret.mjs +31 -21
- package/ci/vars.d.mts +17 -0
- package/ci/vars.mjs +47 -33
- package/ci/verify.d.mts +18 -0
- package/ci/verify.mjs +52 -40
- package/codemod/button-intent.d.mts +63 -0
- package/codemod/button-intent.mjs +338 -285
- package/coverage/cli.d.mts +28 -0
- package/coverage/cli.mjs +65 -51
- package/db/backup-receipt.d.mts +28 -0
- package/db/backup-receipt.mjs +78 -58
- package/db/drift.d.mts +86 -0
- package/db/drift.mjs +213 -180
- package/db/dump.d.mts +52 -0
- package/db/dump.mjs +63 -56
- package/db/entity-list.d.mts +4 -0
- package/db/entity-list.mjs +0 -2
- package/db/image.d.mts +8 -0
- package/db/image.mjs +1 -2
- package/db/migrate.d.mts +104 -0
- package/db/migrate.mjs +207 -167
- package/db/new.d.mts +11 -0
- package/db/new.mjs +25 -25
- package/db/post-cutover.d.mts +5 -0
- package/db/post-cutover.mjs +89 -82
- package/db/postgres.d.mts +71 -0
- package/db/postgres.mjs +62 -61
- package/emit/compiler.d.mts +3 -0
- package/emit/compiler.mjs +25 -27
- package/emit/contracts.d.mts +35 -0
- package/emit/contracts.mjs +46 -50
- package/emit/events.d.mts +9 -0
- package/emit/events.mjs +19 -20
- package/emit/form-bounds.d.mts +83 -0
- package/emit/form-bounds.mjs +133 -117
- package/emit/graphql-input-bounds.d.mts +63 -0
- package/emit/graphql-input-bounds.mjs +90 -79
- package/emit/input-bounds.d.mts +30 -0
- package/emit/input-bounds.mjs +29 -27
- package/emit/operation-schemas.d.mts +24 -0
- package/emit/operation-schemas.mjs +136 -116
- package/emit/operations-worker.d.mts +1 -0
- package/emit/operations-worker.mjs +9 -7
- package/emit/operations.d.mts +47 -0
- package/emit/operations.mjs +124 -133
- package/emit/schema-worker.d.mts +1 -0
- package/emit/schema-worker.mjs +57 -50
- package/emit/static-graph.d.mts +48 -0
- package/emit/static-graph.mjs +766 -640
- package/emit/type-schema.d.mts +29 -0
- package/emit/type-schema.mjs +153 -140
- package/lint/bound-sys.cjs +27 -33
- package/lint/chunk.d.mts +17 -0
- package/lint/chunk.mjs +41 -31
- package/lint/run.d.mts +120 -0
- package/lint/run.mjs +415 -322
- package/package.json +21 -4
- package/release/candidate-ci.d.mts +46 -0
- package/release/candidate-ci.mjs +76 -70
- package/release/gate.d.mts +120 -0
- package/release/gate.mjs +358 -330
- package/release/index.d.mts +68 -0
- package/release/index.mjs +95 -73
- package/release/lint-report.d.mts +14 -0
- package/release/lint-report.mjs +33 -32
- package/release/push.d.mts +32 -0
- package/release/push.mjs +92 -79
- package/release/records.d.mts +18 -0
- package/release/records.mjs +22 -21
- package/release/sonar-quality-gate.d.mts +18 -0
- package/release/sonar-quality-gate.mjs +60 -52
- package/release/urgent.d.mts +20 -0
- package/release/urgent.mjs +76 -74
- package/report/order.d.mts +1 -0
- package/report/sonar.d.mts +73 -0
- package/report/sonar.mjs +82 -89
- package/runtime/engine/admission.d.mts +209 -0
- package/runtime/engine/admission.mjs +225 -204
- package/runtime/engine/by-code-unit.d.mts +5 -0
- package/runtime/engine/by-code-unit.mjs +6 -6
- package/runtime/engine/config.d.mts +333 -0
- package/runtime/engine/config.mjs +486 -328
- package/runtime/engine/db/blob.d.mts +83 -0
- package/runtime/engine/db/blob.mjs +344 -268
- package/runtime/engine/db/event-compact.d.mts +21 -0
- package/runtime/engine/db/event-compact.mjs +34 -38
- package/runtime/engine/db/machine-connection.d.mts +68 -0
- package/runtime/engine/db/machine-connection.mjs +166 -119
- package/runtime/engine/db/machine-open.d.mts +26 -0
- package/runtime/engine/db/machine-open.mjs +59 -45
- package/runtime/engine/db/machine-schema.d.mts +34 -0
- package/runtime/engine/db/machine-schema.mjs +102 -83
- package/runtime/engine/db/machine.d.mts +1746 -0
- package/runtime/engine/db/machine.mjs +1040 -734
- package/runtime/engine/db/provider-reservations.d.mts +169 -0
- package/runtime/engine/db/provider-reservations.mjs +141 -119
- package/runtime/engine/db/provision-lock.d.mts +23 -0
- package/runtime/engine/db/provision-lock.mjs +14 -14
- package/runtime/engine/db/ref-value.d.mts +19 -0
- package/runtime/engine/db/ref-value.mjs +36 -35
- package/runtime/engine/db/sqlite-types.d.mts +28 -0
- package/runtime/engine/db/sqlite-types.mjs +4 -0
- package/runtime/engine/digest.d.mts +4 -0
- package/runtime/engine/digest.mjs +16 -7
- package/runtime/engine/invalid-config.d.mts +13 -0
- package/runtime/engine/invalid-config.mjs +17 -11
- package/runtime/engine/model-config.d.mts +91 -0
- package/runtime/engine/model-config.mjs +98 -76
- package/runtime/engine/orca-config.d.mts +26 -0
- package/runtime/engine/orca-config.mjs +22 -17
- package/runtime/engine/plain-object.d.mts +2 -0
- package/runtime/engine/refuse.d.mts +9 -0
- package/runtime/engine/refuse.mjs +3 -6
- package/runtime/engine/release-config.d.mts +19 -0
- package/runtime/engine/release-config.mjs +22 -18
- package/runtime/engine/removed-vocabulary.d.mts +12 -0
- package/runtime/engine/removed-vocabulary.mjs +21 -20
- package/runtime/engine/resources-config.d.mts +34 -0
- package/runtime/engine/resources-config.mjs +42 -35
- package/runtime/engine/runtime-root.d.mts +28 -0
- package/runtime/engine/runtime-root.mjs +11 -13
- package/runtime/engine/secrets.d.mts +41 -0
- package/runtime/engine/secrets.mjs +170 -102
- package/runtime/engine/sonar-config.d.mts +10 -0
- package/runtime/engine/sonar-config.mjs +16 -13
- package/runtime/engine/temp-root.d.mts +17 -0
- package/runtime/engine/temp-root.mjs +3 -9
- package/runtime/engine/yaml.d.mts +9 -0
- package/runtime/knowledge/hfs/canon-pins.yaml +10 -10
- package/runtime/knowledge/hfs/ci-standard.yaml +2 -2
- package/runtime/knowledge/hfs/rules.yaml +72 -6
- package/runtime/knowledge/hfs/slots.yaml +3 -3
- package/runtime/knowledge/sonar-gate.yaml +1 -1
- package/runtime/modules/kernel/failure-codes.yaml +43 -32
- package/runtime/modules/schemas/application-stacks.schema.yaml +3 -3
- package/runtime/packages/cli/src/catalog.generated.d.mts +13 -0
- package/runtime/packages/cli/src/catalog.generated.mjs +1853 -14824
- package/runtime/packages/cli/src/validate-args.d.mts +74 -0
- package/runtime/packages/cli/src/validate-args.mjs +183 -171
- package/runtime/packages/jest-preset/sonar-exclusions.cjs +5 -5
- package/runtime/scripts/api/fs/claim-file.d.mts +12 -0
- package/runtime/scripts/api/fs/claim-file.mjs +31 -17
- package/runtime/scripts/api/fs/ensure-temp-root.d.mts +4 -0
- package/runtime/scripts/api/fs/ensure-temp-root.mjs +15 -14
- package/runtime/scripts/api/fs/forbidden-root.d.mts +15 -0
- package/runtime/scripts/api/fs/forbidden-root.mjs +31 -23
- package/runtime/scripts/api/fs/is-link-like.d.mts +10 -0
- package/runtime/scripts/api/fs/is-link-like.mjs +25 -11
- package/runtime/scripts/api/fs/lib.d.mts +12 -0
- package/runtime/scripts/api/fs/lib.mjs +28 -8
- package/runtime/scripts/api/fs/make-temp-dir.d.mts +5 -0
- package/runtime/scripts/api/fs/make-temp-dir.mjs +3 -4
- package/runtime/scripts/api/fs/rename-over.d.mts +13 -0
- package/runtime/scripts/api/fs/rename-over.mjs +16 -10
- package/runtime/scripts/api/fs/safe-remove.d.mts +25 -0
- package/runtime/scripts/api/fs/safe-remove.mjs +129 -71
- package/runtime/scripts/api/git/add.d.mts +3 -0
- package/runtime/scripts/api/git/add.mjs +0 -1
- package/runtime/scripts/api/git/cat-file.d.mts +3 -0
- package/runtime/scripts/api/git/cat-file.mjs +0 -1
- package/runtime/scripts/api/git/check-ignore.d.mts +3 -0
- package/runtime/scripts/api/git/check-ignore.mjs +0 -1
- package/runtime/scripts/api/git/commit-tree.d.mts +3 -0
- package/runtime/scripts/api/git/commit-tree.mjs +0 -1
- package/runtime/scripts/api/git/config-get.d.mts +10 -0
- package/runtime/scripts/api/git/config-get.mjs +1 -2
- package/runtime/scripts/api/git/diff.d.mts +3 -0
- package/runtime/scripts/api/git/diff.mjs +0 -1
- package/runtime/scripts/api/git/init.d.mts +7 -0
- package/runtime/scripts/api/git/init.mjs +1 -2
- package/runtime/scripts/api/git/is-ancestor.d.mts +5 -0
- package/runtime/scripts/api/git/is-ancestor.mjs +0 -1
- package/runtime/scripts/api/git/lib.d.mts +67 -0
- package/runtime/scripts/api/git/lib.mjs +32 -32
- package/runtime/scripts/api/git/ls-files.d.mts +3 -0
- package/runtime/scripts/api/git/ls-files.mjs +0 -1
- package/runtime/scripts/api/git/ls-tree.d.mts +3 -0
- package/runtime/scripts/api/git/ls-tree.mjs +0 -1
- package/runtime/scripts/api/git/merge-base.d.mts +5 -0
- package/runtime/scripts/api/git/merge-base.mjs +2 -3
- package/runtime/scripts/api/git/remote.d.mts +3 -0
- package/runtime/scripts/api/git/remote.mjs +0 -1
- package/runtime/scripts/api/git/rev-parse-query.d.mts +3 -0
- package/runtime/scripts/api/git/rev-parse-query.mjs +0 -1
- package/runtime/scripts/api/git/show.d.mts +3 -0
- package/runtime/scripts/api/git/show.mjs +0 -1
- package/runtime/scripts/api/git/tag.d.mts +3 -0
- package/runtime/scripts/api/git/tag.mjs +0 -1
- package/runtime/scripts/api/git/update-ref.d.mts +7 -0
- package/runtime/scripts/api/git/update-ref.mjs +1 -2
- package/runtime/scripts/api/git/write-tree.d.mts +3 -0
- package/runtime/scripts/api/git/write-tree.mjs +0 -1
- package/runtime/scripts/api/node/lib.d.mts +7 -0
- package/runtime/scripts/api/node/lib.mjs +17 -7
- package/runtime/scripts/api/node/run-node.d.mts +3 -0
- package/runtime/scripts/api/node/run-node.mjs +0 -3
- package/runtime/scripts/api/process/resolve-real-tool.d.mts +12 -0
- package/runtime/scripts/api/process/resolve-real-tool.mjs +46 -38
- package/runtime/scripts/api/process/run-program.d.mts +3 -0
- package/runtime/scripts/api/process/run-program.mjs +5 -2
- package/runtime/scripts/api/sops/decrypt.d.mts +9 -0
- package/runtime/scripts/api/sops/decrypt.mjs +1 -2
- package/runtime/scripts/api/sops/lib.d.mts +149 -0
- package/runtime/scripts/api/sops/lib.mjs +417 -318
- package/runtime/scripts/api/sops/resolve-sops.d.mts +3 -0
- package/runtime/scripts/api/sops/resolve-sops.mjs +1 -2
- package/runtime/scripts/api/sops/seal.d.mts +19 -0
- package/runtime/scripts/api/sops/seal.mjs +14 -10
- package/runtime/scripts/api/sops/selected-age-recipient.d.mts +3 -0
- package/runtime/scripts/api/sops/selected-age-recipient.mjs +1 -2
- package/runtime/scripts/api/sops/update-keys.d.mts +16 -0
- package/runtime/scripts/api/sops/update-keys.mjs +11 -8
- package/runtime/scripts/cli/gen-catalog.d.mts +42 -0
- package/runtime/scripts/cli/gen-catalog.mjs +72 -0
- package/runtime/scripts/gates/runtime-host.d.mts +23 -0
- package/runtime/scripts/gates/runtime-host.mjs +48 -41
- package/runtime/scripts/gates/sonar-gate.d.mts +219 -0
- package/runtime/scripts/gates/sonar-gate.mjs +166 -153
- package/runtime/scripts/gates/starcistacks-ci.d.mts +35 -0
- package/runtime/scripts/gates/starcistacks-ci.mjs +47 -39
- package/runtime/scripts/gates/starcistacks-form.d.mts +80 -0
- package/runtime/scripts/gates/starcistacks-form.mjs +16 -14
- package/runtime/scripts/gates/starcistacks-runtime.d.mts +1 -0
- package/runtime/scripts/gates/starcistacks-value-file.d.mts +2 -0
- package/runtime/scripts/gates/starcistacks-value-file.mjs +14 -11
- package/runtime/scripts/gates/starcistacks.d.mts +141 -0
- package/runtime/scripts/gates/starcistacks.mjs +470 -355
- package/runtime/scripts/guards/git-pathspec.d.mts +48 -0
- package/runtime/scripts/guards/git-pathspec.mjs +215 -130
- package/runtime/scripts/guards/git-policy.d.mts +30 -0
- package/runtime/scripts/guards/git-policy.mjs +278 -235
- package/runtime/scripts/guards/hook-io.d.mts +22 -0
- package/runtime/scripts/guards/hook-io.mjs +77 -63
- package/runtime/scripts/guards/push-scan.d.mts +31 -0
- package/runtime/scripts/guards/push-scan.mjs +93 -80
- package/runtime/scripts/guards/release-push-gate.d.mts +22 -0
- package/runtime/scripts/guards/release-push-gate.mjs +40 -38
- package/runtime/scripts/hfs/allows.d.mts +24 -0
- package/runtime/scripts/hfs/allows.mjs +37 -38
- package/runtime/scripts/hfs/app-wiring.d.mts +72 -0
- package/runtime/scripts/hfs/app-wiring.mjs +197 -167
- package/runtime/scripts/hfs/architecture/ast-walks.d.mts +89 -0
- package/runtime/scripts/hfs/architecture/ast-walks.mjs +180 -163
- package/runtime/scripts/hfs/architecture/automatic-gates.d.mts +21 -0
- package/runtime/scripts/hfs/architecture/automatic-gates.mjs +80 -73
- package/runtime/scripts/hfs/architecture/backend-app-files.d.mts +10 -0
- package/runtime/scripts/hfs/architecture/backend-app-files.mjs +88 -77
- package/runtime/scripts/hfs/architecture/backend.d.mts +5 -0
- package/runtime/scripts/hfs/architecture/backend.mjs +378 -357
- package/runtime/scripts/hfs/architecture/background-unowned.d.mts +25 -0
- package/runtime/scripts/hfs/architecture/background-unowned.mjs +201 -187
- package/runtime/scripts/hfs/architecture/canon-clones.d.mts +8 -0
- package/runtime/scripts/hfs/architecture/canon-clones.mjs +260 -209
- package/runtime/scripts/hfs/architecture/canon-jsx-clones.d.mts +5 -0
- package/runtime/scripts/hfs/architecture/canon-jsx-clones.mjs +149 -116
- package/runtime/scripts/hfs/architecture/client-reaches-server.d.mts +28 -0
- package/runtime/scripts/hfs/architecture/client-reaches-server.mjs +72 -68
- package/runtime/scripts/hfs/architecture/clones.d.mts +54 -0
- package/runtime/scripts/hfs/architecture/clones.mjs +212 -217
- package/runtime/scripts/hfs/architecture/config-unread.d.mts +14 -0
- package/runtime/scripts/hfs/architecture/config-unread.mjs +7 -9
- package/runtime/scripts/hfs/architecture/config.d.mts +74 -0
- package/runtime/scripts/hfs/architecture/config.mjs +302 -268
- package/runtime/scripts/hfs/architecture/connection-map.d.mts +33 -0
- package/runtime/scripts/hfs/architecture/connection-map.mjs +258 -225
- package/runtime/scripts/hfs/architecture/constructor-deps.d.mts +57 -0
- package/runtime/scripts/hfs/architecture/constructor-deps.mjs +80 -71
- package/runtime/scripts/hfs/architecture/context-coupling.d.mts +21 -0
- package/runtime/scripts/hfs/architecture/context-coupling.mjs +82 -77
- package/runtime/scripts/hfs/architecture/context-map.d.mts +102 -0
- package/runtime/scripts/hfs/architecture/context-map.mjs +267 -234
- package/runtime/scripts/hfs/architecture/context-owner.d.mts +15 -0
- package/runtime/scripts/hfs/architecture/context-owner.mjs +73 -61
- package/runtime/scripts/hfs/architecture/context-platform-tables.d.mts +18 -0
- package/runtime/scripts/hfs/architecture/context-platform-tables.mjs +47 -43
- package/runtime/scripts/hfs/architecture/context-transaction.d.mts +20 -0
- package/runtime/scripts/hfs/architecture/context-transaction.mjs +54 -52
- package/runtime/scripts/hfs/architecture/contract-fixture-guard.d.mts +37 -0
- package/runtime/scripts/hfs/architecture/contract-fixture-guard.mjs +113 -104
- package/runtime/scripts/hfs/architecture/contracts-readonly.d.mts +32 -0
- package/runtime/scripts/hfs/architecture/contracts-readonly.mjs +288 -270
- package/runtime/scripts/hfs/architecture/contracts.d.mts +30 -0
- package/runtime/scripts/hfs/architecture/contracts.mjs +408 -393
- package/runtime/scripts/hfs/architecture/cross-app-duplicate.d.mts +27 -0
- package/runtime/scripts/hfs/architecture/cross-app-duplicate.mjs +50 -51
- package/runtime/scripts/hfs/architecture/dead-exports-bindings.d.mts +21 -0
- package/runtime/scripts/hfs/architecture/dead-exports-bindings.mjs +143 -119
- package/runtime/scripts/hfs/architecture/dead-exports.d.mts +32 -0
- package/runtime/scripts/hfs/architecture/dead-exports.mjs +286 -228
- package/runtime/scripts/hfs/architecture/default-deny.d.mts +21 -0
- package/runtime/scripts/hfs/architecture/default-deny.mjs +129 -110
- package/runtime/scripts/hfs/architecture/doc-language.d.mts +17 -0
- package/runtime/scripts/hfs/architecture/doc-language.mjs +24 -19
- package/runtime/scripts/hfs/architecture/entity-registry.d.mts +49 -0
- package/runtime/scripts/hfs/architecture/entity-registry.mjs +20 -22
- package/runtime/scripts/hfs/architecture/entrypoint.d.mts +13 -0
- package/runtime/scripts/hfs/architecture/entrypoint.mjs +47 -45
- package/runtime/scripts/hfs/architecture/error-codes.d.mts +16 -0
- package/runtime/scripts/hfs/architecture/error-codes.mjs +37 -35
- package/runtime/scripts/hfs/architecture/error-masked.d.mts +16 -0
- package/runtime/scripts/hfs/architecture/error-masked.mjs +55 -59
- package/runtime/scripts/hfs/architecture/fe-slot-allows.d.mts +38 -0
- package/runtime/scripts/hfs/architecture/fe-slot-allows.mjs +24 -23
- package/runtime/scripts/hfs/architecture/feature-shape.d.mts +26 -0
- package/runtime/scripts/hfs/architecture/feature-shape.mjs +40 -38
- package/runtime/scripts/hfs/architecture/framework-pinned.d.mts +3 -0
- package/runtime/scripts/hfs/architecture/framework-pinned.mjs +21 -21
- package/runtime/scripts/hfs/architecture/frontend-block-render.d.mts +26 -0
- package/runtime/scripts/hfs/architecture/frontend-block-render.mjs +106 -98
- package/runtime/scripts/hfs/architecture/frontend-grammar.d.mts +7 -0
- package/runtime/scripts/hfs/architecture/frontend-grammar.mjs +153 -150
- package/runtime/scripts/hfs/architecture/frontend-routing.d.mts +23 -0
- package/runtime/scripts/hfs/architecture/frontend-routing.mjs +161 -149
- package/runtime/scripts/hfs/architecture/frontend-world-render.d.mts +72 -0
- package/runtime/scripts/hfs/architecture/frontend-world-render.mjs +343 -305
- package/runtime/scripts/hfs/architecture/frontend-world.d.mts +94 -0
- package/runtime/scripts/hfs/architecture/frontend-world.mjs +340 -294
- package/runtime/scripts/hfs/architecture/frontend.d.mts +31 -0
- package/runtime/scripts/hfs/architecture/frontend.mjs +174 -184
- package/runtime/scripts/hfs/architecture/function-spec-providers.d.mts +27 -0
- package/runtime/scripts/hfs/architecture/function-spec-providers.mjs +124 -106
- package/runtime/scripts/hfs/architecture/hfs-graph.d.mts +78 -0
- package/runtime/scripts/hfs/architecture/hfs-graph.mjs +52 -48
- package/runtime/scripts/hfs/architecture/hfs.d.mts +135 -0
- package/runtime/scripts/hfs/architecture/hfs.mjs +328 -282
- package/runtime/scripts/hfs/architecture/hooks-are-hooks.d.mts +24 -0
- package/runtime/scripts/hfs/architecture/hooks-are-hooks.mjs +81 -71
- package/runtime/scripts/hfs/architecture/i18n-keys.d.mts +31 -0
- package/runtime/scripts/hfs/architecture/i18n-keys.mjs +155 -141
- package/runtime/scripts/hfs/architecture/identity.d.mts +7 -0
- package/runtime/scripts/hfs/architecture/identity.mjs +141 -125
- package/runtime/scripts/hfs/architecture/index.d.mts +101 -0
- package/runtime/scripts/hfs/architecture/index.mjs +272 -272
- package/runtime/scripts/hfs/architecture/injection-token-exported.d.mts +21 -0
- package/runtime/scripts/hfs/architecture/injection-token-exported.mjs +45 -43
- package/runtime/scripts/hfs/architecture/jwt-ast.d.mts +16 -0
- package/runtime/scripts/hfs/architecture/jwt-ast.mjs +195 -176
- package/runtime/scripts/hfs/architecture/machine-ast.d.mts +88 -0
- package/runtime/scripts/hfs/architecture/machine-ast.mjs +163 -155
- package/runtime/scripts/hfs/architecture/managed-scripts.d.mts +2 -0
- package/runtime/scripts/hfs/architecture/managed-scripts.mjs +19 -20
- package/runtime/scripts/hfs/architecture/module-per-transport.d.mts +35 -0
- package/runtime/scripts/hfs/architecture/module-per-transport.mjs +177 -172
- package/runtime/scripts/hfs/architecture/next-data-contract.d.mts +35 -0
- package/runtime/scripts/hfs/architecture/next-data-contract.mjs +100 -78
- package/runtime/scripts/hfs/architecture/next-data-inference.d.mts +39 -0
- package/runtime/scripts/hfs/architecture/next-data-inference.mjs +170 -154
- package/runtime/scripts/hfs/architecture/next-data-key.d.mts +50 -0
- package/runtime/scripts/hfs/architecture/next-data-key.mjs +311 -275
- package/runtime/scripts/hfs/architecture/next-data-symbols.d.mts +5 -0
- package/runtime/scripts/hfs/architecture/next-data-symbols.mjs +17 -17
- package/runtime/scripts/hfs/architecture/next-data.d.mts +36 -0
- package/runtime/scripts/hfs/architecture/next-data.mjs +351 -334
- package/runtime/scripts/hfs/architecture/operation-contract-roots.d.mts +10 -0
- package/runtime/scripts/hfs/architecture/operation-contract-roots.mjs +39 -37
- package/runtime/scripts/hfs/architecture/owners.d.mts +5 -0
- package/runtime/scripts/hfs/architecture/owners.mjs +97 -98
- package/runtime/scripts/hfs/architecture/package-shape.d.mts +26 -0
- package/runtime/scripts/hfs/architecture/package-shape.mjs +56 -55
- package/runtime/scripts/hfs/architecture/presentation.d.mts +24 -0
- package/runtime/scripts/hfs/architecture/presentation.mjs +138 -130
- package/runtime/scripts/hfs/architecture/reachability.d.mts +25 -0
- package/runtime/scripts/hfs/architecture/reachability.mjs +258 -241
- package/runtime/scripts/hfs/architecture/register-once.d.mts +18 -0
- package/runtime/scripts/hfs/architecture/register-once.mjs +152 -139
- package/runtime/scripts/hfs/architecture/registration.d.mts +15 -0
- package/runtime/scripts/hfs/architecture/registration.mjs +301 -267
- package/runtime/scripts/hfs/architecture/required-files.d.mts +64 -0
- package/runtime/scripts/hfs/architecture/required-files.mjs +172 -167
- package/runtime/scripts/hfs/architecture/route-files-thin.d.mts +23 -0
- package/runtime/scripts/hfs/architecture/route-files-thin.mjs +85 -77
- package/runtime/scripts/hfs/architecture/schema-owner.d.mts +34 -0
- package/runtime/scripts/hfs/architecture/schema-owner.mjs +206 -181
- package/runtime/scripts/hfs/architecture/server-action.d.mts +22 -0
- package/runtime/scripts/hfs/architecture/server-action.mjs +48 -48
- package/runtime/scripts/hfs/architecture/side-boundary.d.mts +3 -0
- package/runtime/scripts/hfs/architecture/side-boundary.mjs +2 -5
- package/runtime/scripts/hfs/architecture/source-names-shape.d.mts +85 -0
- package/runtime/scripts/hfs/architecture/source-names-shape.mjs +261 -259
- package/runtime/scripts/hfs/architecture/source-names.d.mts +7 -0
- package/runtime/scripts/hfs/architecture/source-names.mjs +304 -278
- package/runtime/scripts/hfs/architecture/sql-keys.d.mts +5 -0
- package/runtime/scripts/hfs/architecture/sql-keys.mjs +277 -194
- package/runtime/scripts/hfs/architecture/sql-owner.d.mts +30 -0
- package/runtime/scripts/hfs/architecture/sql-owner.mjs +236 -194
- package/runtime/scripts/hfs/architecture/sql-returning.d.mts +22 -0
- package/runtime/scripts/hfs/architecture/sql-returning.mjs +46 -45
- package/runtime/scripts/hfs/architecture/sql-token-forms.d.mts +21 -0
- package/runtime/scripts/hfs/architecture/sql-token-forms.mjs +86 -74
- package/runtime/scripts/hfs/architecture/sql-tokens.d.mts +32 -0
- package/runtime/scripts/hfs/architecture/sql-tokens.mjs +456 -341
- package/runtime/scripts/hfs/architecture/staged-consumers.d.mts +7 -0
- package/runtime/scripts/hfs/architecture/staged-consumers.mjs +35 -30
- package/runtime/scripts/hfs/architecture/surface.d.mts +26 -0
- package/runtime/scripts/hfs/architecture/surface.mjs +64 -74
- package/runtime/scripts/hfs/architecture/symbols.d.mts +11 -0
- package/runtime/scripts/hfs/architecture/symbols.mjs +209 -216
- package/runtime/scripts/hfs/architecture/test-world-files.d.mts +45 -0
- package/runtime/scripts/hfs/architecture/test-world-files.mjs +165 -155
- package/runtime/scripts/hfs/architecture/tiers.d.mts +29 -0
- package/runtime/scripts/hfs/architecture/tiers.mjs +161 -154
- package/runtime/scripts/hfs/architecture/transport-owner.d.mts +37 -0
- package/runtime/scripts/hfs/architecture/transport-owner.mjs +155 -149
- package/runtime/scripts/hfs/architecture/type-context.d.mts +60 -0
- package/runtime/scripts/hfs/architecture/type-context.mjs +255 -250
- package/runtime/scripts/hfs/architecture/typescript.d.mts +94 -0
- package/runtime/scripts/hfs/architecture/typescript.mjs +358 -318
- package/runtime/scripts/hfs/architecture/unit-spec-providers.d.mts +34 -0
- package/runtime/scripts/hfs/architecture/unit-spec-providers.mjs +110 -92
- package/runtime/scripts/hfs/architecture.d.mts +13 -0
- package/runtime/scripts/hfs/architecture.mjs +39 -29
- package/runtime/scripts/hfs/canon-pins.d.mts +26 -0
- package/runtime/scripts/hfs/canon-pins.mjs +5 -8
- package/runtime/scripts/hfs/catalog-once.d.mts +2 -0
- package/runtime/scripts/hfs/catalog-once.mjs +8 -9
- package/runtime/scripts/hfs/check-results.d.mts +29 -0
- package/runtime/scripts/hfs/check-results.mjs +14 -18
- package/runtime/scripts/hfs/check.d.mts +144 -0
- package/runtime/scripts/hfs/check.mjs +309 -329
- package/runtime/scripts/hfs/ci-declaration.d.mts +77 -0
- package/runtime/scripts/hfs/ci-declaration.mjs +99 -87
- package/runtime/scripts/hfs/coverage-from.d.mts +22 -0
- package/runtime/scripts/hfs/coverage-from.mjs +52 -49
- package/runtime/scripts/hfs/coverage-scope.d.mts +87 -0
- package/runtime/scripts/hfs/coverage-scope.mjs +139 -142
- package/runtime/scripts/hfs/db-baseline-verb.d.mts +84 -0
- package/runtime/scripts/hfs/db-baseline-verb.mjs +327 -266
- package/runtime/scripts/hfs/db-errors.d.mts +2 -0
- package/runtime/scripts/hfs/db-errors.mjs +2 -1
- package/runtime/scripts/hfs/db-plan-verb.d.mts +33 -0
- package/runtime/scripts/hfs/db-plan-verb.mjs +174 -128
- package/runtime/scripts/hfs/db-restamp-verb.d.mts +5 -0
- package/runtime/scripts/hfs/db-restamp-verb.mjs +94 -70
- package/runtime/scripts/hfs/db-squash.d.mts +117 -0
- package/runtime/scripts/hfs/db-squash.mjs +414 -351
- package/runtime/scripts/hfs/declaration-shape.d.mts +3 -0
- package/runtime/scripts/hfs/declaration-shape.mjs +140 -103
- package/runtime/scripts/hfs/declaration-slots.d.mts +18 -0
- package/runtime/scripts/hfs/declaration-slots.mjs +64 -61
- package/runtime/scripts/hfs/doc-commands.d.mts +71 -0
- package/runtime/scripts/hfs/doc-commands.mjs +257 -250
- package/runtime/scripts/hfs/edition-slots.d.mts +37 -0
- package/runtime/scripts/hfs/edition-slots.mjs +43 -40
- package/runtime/scripts/hfs/example-secrets.d.mts +18 -0
- package/runtime/scripts/hfs/example-secrets.mjs +173 -154
- package/runtime/scripts/hfs/gate-threshold.d.mts +20 -0
- package/runtime/scripts/hfs/gate-threshold.mjs +28 -0
- package/runtime/scripts/hfs/grammar-presentation.d.mts +74 -0
- package/runtime/scripts/hfs/grammar-presentation.mjs +109 -106
- package/runtime/scripts/hfs/linear-text.d.mts +6 -0
- package/runtime/scripts/hfs/linear-text.mjs +20 -20
- package/runtime/scripts/hfs/manifest-shape.d.mts +216 -0
- package/runtime/scripts/hfs/manifest-shape.mjs +399 -324
- package/runtime/scripts/hfs/param-names.d.mts +3 -0
- package/runtime/scripts/hfs/param-names.mjs +6 -11
- package/runtime/scripts/hfs/path-findings.d.mts +22 -0
- package/runtime/scripts/hfs/path-findings.mjs +120 -100
- package/runtime/scripts/hfs/pin-findings.d.mts +19 -0
- package/runtime/scripts/hfs/pin-findings.mjs +26 -21
- package/runtime/scripts/hfs/refusal-codes.d.mts +1 -0
- package/runtime/scripts/hfs/refusal-codes.mjs +2 -2
- package/runtime/scripts/hfs/repo-identity.d.mts +15 -0
- package/runtime/scripts/hfs/repo-identity.mjs +55 -42
- package/runtime/scripts/hfs/rule-catalog.d.mts +77 -0
- package/runtime/scripts/hfs/rule-catalog.mjs +353 -257
- package/runtime/scripts/hfs/rule-params-shape.d.mts +10 -0
- package/runtime/scripts/hfs/rule-params-shape.mjs +60 -47
- package/runtime/scripts/hfs/rules/a15-findings.d.mts +18 -0
- package/runtime/scripts/hfs/rules/a15-findings.mjs +59 -55
- package/runtime/scripts/hfs/rules/app-env-required.d.mts +9 -0
- package/runtime/scripts/hfs/rules/app-env-required.mjs +13 -13
- package/runtime/scripts/hfs/rules/app-root.d.mts +15 -0
- package/runtime/scripts/hfs/rules/app-root.mjs +20 -21
- package/runtime/scripts/hfs/rules/app-workflow-findings.d.mts +12 -0
- package/runtime/scripts/hfs/rules/app-workflow-findings.mjs +4 -4
- package/runtime/scripts/hfs/rules/assets.d.mts +13 -0
- package/runtime/scripts/hfs/rules/assets.mjs +58 -46
- package/runtime/scripts/hfs/rules/boot-proof.d.mts +11 -0
- package/runtime/scripts/hfs/rules/boot-proof.mjs +7 -8
- package/runtime/scripts/hfs/rules/bypass-markers.d.mts +9 -0
- package/runtime/scripts/hfs/rules/bypass-markers.mjs +7 -12
- package/runtime/scripts/hfs/rules/canon-copy-drift.d.mts +10 -0
- package/runtime/scripts/hfs/rules/canon-copy-drift.mjs +70 -68
- package/runtime/scripts/hfs/rules/ci-custody.d.mts +7 -0
- package/runtime/scripts/hfs/rules/ci-custody.mjs +72 -73
- package/runtime/scripts/hfs/rules/ci-standard.d.mts +12 -0
- package/runtime/scripts/hfs/rules/ci-standard.mjs +149 -142
- package/runtime/scripts/hfs/rules/cli.d.mts +7 -0
- package/runtime/scripts/hfs/rules/cli.mjs +24 -23
- package/runtime/scripts/hfs/rules/contract-compat.d.mts +11 -0
- package/runtime/scripts/hfs/rules/contract-compat.mjs +64 -53
- package/runtime/scripts/hfs/rules/contract.d.mts +26 -0
- package/runtime/scripts/hfs/rules/contract.mjs +126 -111
- package/runtime/scripts/hfs/rules/coverage-below.d.mts +17 -0
- package/runtime/scripts/hfs/rules/coverage-below.mjs +200 -167
- package/runtime/scripts/hfs/rules/database-access.d.mts +12 -0
- package/runtime/scripts/hfs/rules/database-access.mjs +231 -202
- package/runtime/scripts/hfs/rules/database-baseline.d.mts +22 -0
- package/runtime/scripts/hfs/rules/database-baseline.mjs +104 -104
- package/runtime/scripts/hfs/rules/database-config.d.mts +11 -0
- package/runtime/scripts/hfs/rules/database-config.mjs +101 -135
- package/runtime/scripts/hfs/rules/database-constants.d.mts +36 -0
- package/runtime/scripts/hfs/rules/database-constants.mjs +7 -7
- package/runtime/scripts/hfs/rules/database-migrations.d.mts +41 -0
- package/runtime/scripts/hfs/rules/database-migrations.mjs +428 -388
- package/runtime/scripts/hfs/rules/database-plpgsql.d.mts +5 -0
- package/runtime/scripts/hfs/rules/database-plpgsql.mjs +278 -259
- package/runtime/scripts/hfs/rules/database-queue-sources.d.mts +4 -0
- package/runtime/scripts/hfs/rules/database-queue-sources.mjs +48 -43
- package/runtime/scripts/hfs/rules/database-queues.d.mts +15 -0
- package/runtime/scripts/hfs/rules/database-queues.mjs +211 -182
- package/runtime/scripts/hfs/rules/database-sql.d.mts +16 -0
- package/runtime/scripts/hfs/rules/database-sql.mjs +394 -394
- package/runtime/scripts/hfs/rules/database-transaction.d.mts +3 -0
- package/runtime/scripts/hfs/rules/database-transaction.mjs +25 -27
- package/runtime/scripts/hfs/rules/database.d.mts +22 -0
- package/runtime/scripts/hfs/rules/database.mjs +42 -58
- package/runtime/scripts/hfs/rules/deploy-scan.d.mts +10 -0
- package/runtime/scripts/hfs/rules/deploy-scan.mjs +177 -168
- package/runtime/scripts/hfs/rules/deploy-workflow.d.mts +3 -0
- package/runtime/scripts/hfs/rules/deploy-workflow.mjs +194 -171
- package/runtime/scripts/hfs/rules/deps.d.mts +6 -0
- package/runtime/scripts/hfs/rules/deps.mjs +61 -60
- package/runtime/scripts/hfs/rules/doc-fresh.d.mts +11 -0
- package/runtime/scripts/hfs/rules/doc-fresh.mjs +242 -223
- package/runtime/scripts/hfs/rules/docker-health.d.mts +9 -0
- package/runtime/scripts/hfs/rules/docker-health.mjs +222 -196
- package/runtime/scripts/hfs/rules/docker.d.mts +13 -0
- package/runtime/scripts/hfs/rules/docker.mjs +234 -208
- package/runtime/scripts/hfs/rules/edition.d.mts +18 -0
- package/runtime/scripts/hfs/rules/edition.mjs +103 -101
- package/runtime/scripts/hfs/rules/env-parity.d.mts +25 -0
- package/runtime/scripts/hfs/rules/env-parity.mjs +278 -252
- package/runtime/scripts/hfs/rules/env-value-shape.d.mts +21 -0
- package/runtime/scripts/hfs/rules/env-value-shape.mjs +82 -67
- package/runtime/scripts/hfs/rules/event-bus.d.mts +17 -0
- package/runtime/scripts/hfs/rules/event-bus.mjs +145 -133
- package/runtime/scripts/hfs/rules/event-tables.d.mts +7 -0
- package/runtime/scripts/hfs/rules/event-tables.mjs +77 -75
- package/runtime/scripts/hfs/rules/fe-build-args.d.mts +10 -0
- package/runtime/scripts/hfs/rules/fe-build-args.mjs +116 -99
- package/runtime/scripts/hfs/rules/fe-contract-documents.d.mts +7 -0
- package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +121 -111
- package/runtime/scripts/hfs/rules/fe-no-tests.d.mts +9 -0
- package/runtime/scripts/hfs/rules/fe-no-tests.mjs +37 -36
- package/runtime/scripts/hfs/rules/fe-stack.d.mts +23 -0
- package/runtime/scripts/hfs/rules/fe-stack.mjs +108 -105
- package/runtime/scripts/hfs/rules/feature-files.d.mts +10 -0
- package/runtime/scripts/hfs/rules/feature-files.mjs +14 -19
- package/runtime/scripts/hfs/rules/frontend-tree.d.mts +18 -0
- package/runtime/scripts/hfs/rules/frontend-tree.mjs +105 -91
- package/runtime/scripts/hfs/rules/integration-specs.d.mts +7 -0
- package/runtime/scripts/hfs/rules/integration-specs.mjs +190 -177
- package/runtime/scripts/hfs/rules/kinds.d.mts +6 -0
- package/runtime/scripts/hfs/rules/kinds.mjs +88 -81
- package/runtime/scripts/hfs/rules/lexicon.d.mts +9 -0
- package/runtime/scripts/hfs/rules/lexicon.mjs +43 -40
- package/runtime/scripts/hfs/rules/lint-suppression.d.mts +5 -0
- package/runtime/scripts/hfs/rules/lint-suppression.mjs +22 -20
- package/runtime/scripts/hfs/rules/lite-proof-lane.d.mts +9 -0
- package/runtime/scripts/hfs/rules/lite-proof-lane.mjs +59 -58
- package/runtime/scripts/hfs/rules/lite-secrets.d.mts +12 -0
- package/runtime/scripts/hfs/rules/lite-secrets.mjs +60 -63
- package/runtime/scripts/hfs/rules/mcp-tools.d.mts +7 -0
- package/runtime/scripts/hfs/rules/mcp-tools.mjs +56 -41
- package/runtime/scripts/hfs/rules/monorepo.d.mts +17 -0
- package/runtime/scripts/hfs/rules/monorepo.mjs +153 -138
- package/runtime/scripts/hfs/rules/peer-integrations.d.mts +7 -0
- package/runtime/scripts/hfs/rules/peer-integrations.mjs +39 -36
- package/runtime/scripts/hfs/rules/pipeline.d.mts +7 -0
- package/runtime/scripts/hfs/rules/pipeline.mjs +53 -53
- package/runtime/scripts/hfs/rules/proof-commands.d.mts +14 -0
- package/runtime/scripts/hfs/rules/proof-commands.mjs +52 -41
- package/runtime/scripts/hfs/rules/read.d.mts +7 -0
- package/runtime/scripts/hfs/rules/read.mjs +19 -15
- package/runtime/scripts/hfs/rules/release-provenance.d.mts +12 -0
- package/runtime/scripts/hfs/rules/release-provenance.mjs +196 -159
- package/runtime/scripts/hfs/rules/repo-local-checks.d.mts +5 -0
- package/runtime/scripts/hfs/rules/repo-local-checks.mjs +19 -17
- package/runtime/scripts/hfs/rules/rule-types.d.mts +40 -0
- package/runtime/scripts/hfs/rules/rule-types.mjs +4 -0
- package/runtime/scripts/hfs/rules/saga-delivery.d.mts +2 -0
- package/runtime/scripts/hfs/rules/saga-delivery.mjs +58 -50
- package/runtime/scripts/hfs/rules/saga.d.mts +7 -0
- package/runtime/scripts/hfs/rules/saga.mjs +151 -145
- package/runtime/scripts/hfs/rules/script-hygiene.d.mts +11 -0
- package/runtime/scripts/hfs/rules/script-hygiene.mjs +112 -95
- package/runtime/scripts/hfs/rules/secret-custody-only.d.mts +7 -0
- package/runtime/scripts/hfs/rules/secret-custody-only.mjs +29 -35
- package/runtime/scripts/hfs/rules/secrets.d.mts +29 -0
- package/runtime/scripts/hfs/rules/secrets.mjs +45 -44
- package/runtime/scripts/hfs/rules/services.d.mts +7 -0
- package/runtime/scripts/hfs/rules/services.mjs +148 -148
- package/runtime/scripts/hfs/rules/spec-placement.d.mts +8 -0
- package/runtime/scripts/hfs/rules/spec-placement.mjs +12 -13
- package/runtime/scripts/hfs/rules/stack-tooling.d.mts +11 -0
- package/runtime/scripts/hfs/rules/stack-tooling.mjs +45 -52
- package/runtime/scripts/hfs/rules/stacks-auth-cookie-domain.d.mts +30 -0
- package/runtime/scripts/hfs/rules/stacks-auth-cookie-domain.mjs +149 -0
- package/runtime/scripts/hfs/rules/stacks-deploy.d.mts +7 -0
- package/runtime/scripts/hfs/rules/stacks-deploy.mjs +32 -42
- package/runtime/scripts/hfs/rules/stacks-ingress.d.mts +16 -0
- package/runtime/scripts/hfs/rules/stacks-ingress.mjs +62 -64
- package/runtime/scripts/hfs/rules/stacks-lite-backing.d.mts +17 -0
- package/runtime/scripts/hfs/rules/stacks-lite-backing.mjs +111 -116
- package/runtime/scripts/hfs/rules/stacks-release.d.mts +26 -0
- package/runtime/scripts/hfs/rules/stacks-release.mjs +335 -309
- package/runtime/scripts/hfs/rules/stacks-runtime.d.mts +31 -0
- package/runtime/scripts/hfs/rules/stacks-runtime.mjs +130 -124
- package/runtime/scripts/hfs/rules/stacks-swarm.d.mts +5 -0
- package/runtime/scripts/hfs/rules/stacks-swarm.mjs +366 -344
- package/runtime/scripts/hfs/rules/stacks.d.mts +7 -0
- package/runtime/scripts/hfs/rules/stacks.mjs +37 -38
- package/runtime/scripts/hfs/rules/staged-specs.d.mts +10 -0
- package/runtime/scripts/hfs/rules/staged-specs.mjs +14 -18
- package/runtime/scripts/hfs/rules/supply-chain.d.mts +10 -0
- package/runtime/scripts/hfs/rules/supply-chain.mjs +143 -150
- package/runtime/scripts/hfs/rules/test-topology.d.mts +5 -0
- package/runtime/scripts/hfs/rules/test-topology.mjs +23 -21
- package/runtime/scripts/hfs/rules/text-integrity.d.mts +9 -0
- package/runtime/scripts/hfs/rules/text-integrity.mjs +47 -43
- package/runtime/scripts/hfs/rules/unused-symbol-flow.d.mts +22 -0
- package/runtime/scripts/hfs/rules/unused-symbol-flow.mjs +226 -204
- package/runtime/scripts/hfs/rules/unused-symbol-ledger.d.mts +7 -0
- package/runtime/scripts/hfs/rules/unused-symbol-ledger.mjs +70 -49
- package/runtime/scripts/hfs/rules/unused-symbol-properties.d.mts +12 -0
- package/runtime/scripts/hfs/rules/unused-symbol-properties.mjs +141 -126
- package/runtime/scripts/hfs/rules/unused-symbol-translators.d.mts +8 -0
- package/runtime/scripts/hfs/rules/unused-symbol-translators.mjs +160 -140
- package/runtime/scripts/hfs/rules/unused-symbol-values.d.mts +9 -0
- package/runtime/scripts/hfs/rules/unused-symbol-values.mjs +138 -125
- package/runtime/scripts/hfs/rules/unused-symbol.d.mts +11 -0
- package/runtime/scripts/hfs/rules/unused-symbol.mjs +283 -253
- package/runtime/scripts/hfs/rules/workflow-contexts.d.mts +8 -0
- package/runtime/scripts/hfs/rules/workflow-contexts.mjs +79 -67
- package/runtime/scripts/hfs/runtime-rules/git-triggers.d.mts +6 -0
- package/runtime/scripts/hfs/runtime-rules/git-triggers.mjs +36 -35
- package/runtime/scripts/hfs/runtime-rules/hook-shape.d.mts +10 -0
- package/runtime/scripts/hfs/runtime-rules/hook-shape.mjs +45 -42
- package/runtime/scripts/hfs/runtime-rules/source-ast.d.mts +39 -0
- package/runtime/scripts/hfs/runtime-rules/source-ast.mjs +130 -116
- package/runtime/scripts/hfs/runtime-rules/workflow-source.d.mts +5 -0
- package/runtime/scripts/hfs/runtime-rules/workflow-source.mjs +8 -7
- package/runtime/scripts/hfs/sealed-members.d.mts +22 -0
- package/runtime/scripts/hfs/sealed-members.mjs +79 -75
- package/runtime/scripts/hfs/secret-bootstrap-crypto.d.mts +12 -0
- package/runtime/scripts/hfs/secret-bootstrap-crypto.mjs +151 -167
- package/runtime/scripts/hfs/secret-document.d.mts +16 -0
- package/runtime/scripts/hfs/secret-document.mjs +59 -75
- package/runtime/scripts/hfs/secret-edit.d.mts +14 -0
- package/runtime/scripts/hfs/secret-edit.mjs +115 -135
- package/runtime/scripts/hfs/secret-errors.d.mts +4 -0
- package/runtime/scripts/hfs/secret-errors.mjs +19 -16
- package/runtime/scripts/hfs/secret-files.d.mts +20 -0
- package/runtime/scripts/hfs/secret-files.mjs +103 -112
- package/runtime/scripts/hfs/secret-init.d.mts +108 -0
- package/runtime/scripts/hfs/secret-init.mjs +304 -346
- package/runtime/scripts/hfs/secret-output.d.mts +18 -0
- package/runtime/scripts/hfs/secret-output.mjs +52 -80
- package/runtime/scripts/hfs/secret-prompt.d.mts +39 -0
- package/runtime/scripts/hfs/secret-prompt.mjs +108 -93
- package/runtime/scripts/hfs/secret-sops.d.mts +29 -0
- package/runtime/scripts/hfs/secret-sops.mjs +161 -199
- package/runtime/scripts/hfs/secret-standard.d.mts +89 -0
- package/runtime/scripts/hfs/secret-standard.mjs +300 -264
- package/runtime/scripts/hfs/secret-store.d.mts +36 -0
- package/runtime/scripts/hfs/secret-store.mjs +120 -136
- package/runtime/scripts/hfs/secret.d.mts +40 -0
- package/runtime/scripts/hfs/secret.mjs +254 -222
- package/runtime/scripts/hfs/slot-app-view.d.mts +11 -0
- package/runtime/scripts/hfs/slot-app-view.mjs +69 -74
- package/runtime/scripts/hfs/slot-classify.d.mts +75 -0
- package/runtime/scripts/hfs/slot-classify.mjs +42 -38
- package/runtime/scripts/hfs/slot-errors.d.mts +6 -0
- package/runtime/scripts/hfs/slot-errors.mjs +8 -7
- package/runtime/scripts/hfs/slot-imports.d.mts +8 -0
- package/runtime/scripts/hfs/slot-imports.mjs +70 -63
- package/runtime/scripts/hfs/slot-manifest-shape.d.mts +9 -0
- package/runtime/scripts/hfs/slot-manifest-shape.mjs +74 -52
- package/runtime/scripts/hfs/slot-match.d.mts +50 -0
- package/runtime/scripts/hfs/slot-match.mjs +122 -111
- package/runtime/scripts/hfs/slot-path.d.mts +1 -0
- package/runtime/scripts/hfs/slot-path.mjs +0 -2
- package/runtime/scripts/hfs/slot-required.d.mts +11 -0
- package/runtime/scripts/hfs/slot-required.mjs +65 -59
- package/runtime/scripts/hfs/slot-semantic-problems.d.mts +9 -0
- package/runtime/scripts/hfs/slot-semantic-problems.mjs +138 -112
- package/runtime/scripts/hfs/slot-side-problems.d.mts +3 -0
- package/runtime/scripts/hfs/slot-side-problems.mjs +23 -19
- package/runtime/scripts/hfs/slots.d.mts +188 -0
- package/runtime/scripts/hfs/slots.mjs +175 -152
- package/runtime/scripts/hfs/sql/pg-parse.d.mts +9 -0
- package/runtime/scripts/hfs/sql/pg-parse.mjs +25 -25
- package/runtime/scripts/hfs/stack-config-kit.d.mts +22 -0
- package/runtime/scripts/hfs/stack-config-kit.mjs +21 -17
- package/runtime/scripts/hfs/stack-deploy-config.d.mts +155 -0
- package/runtime/scripts/hfs/stack-deploy-config.mjs +345 -273
- package/runtime/scripts/hfs/stack-ingress-config.d.mts +74 -0
- package/runtime/scripts/hfs/stack-ingress-config.mjs +211 -177
- package/runtime/scripts/hfs/stacks-gate.d.mts +52 -0
- package/runtime/scripts/hfs/stacks-gate.mjs +557 -397
- package/runtime/scripts/hfs/starcistacks-runtime.d.mts +7 -0
- package/runtime/scripts/hfs/starcistacks-runtime.mjs +51 -40
- package/runtime/scripts/hfs/test-world-slot.d.mts +2 -0
- package/runtime/scripts/hfs/test-world-slot.mjs +0 -1
- package/runtime/scripts/hfs/trailing-slashes.d.mts +2 -0
- package/runtime/scripts/hfs/trailing-slashes.mjs +4 -4
- package/runtime/scripts/hfs/tree-findings.d.mts +9 -0
- package/runtime/scripts/hfs/tree-findings.mjs +18 -17
- package/runtime/scripts/hfs/tree.d.mts +35 -0
- package/runtime/scripts/hfs/tree.mjs +56 -46
- package/runtime/scripts/hfs/typescript-programs.d.mts +36 -0
- package/runtime/scripts/hfs/typescript-programs.mjs +66 -69
- package/runtime/scripts/hfs/view.d.mts +45 -0
- package/runtime/scripts/hfs/view.mjs +38 -40
- package/runtime/scripts/lib/bypass-markers.d.mts +15 -0
- package/runtime/scripts/lib/bypass-markers.mjs +210 -197
- package/runtime/scripts/lib/cli-arg.d.mts +67 -0
- package/runtime/scripts/lib/cli-arg.mjs +59 -63
- package/runtime/scripts/lib/command-tokens.d.mts +11 -0
- package/runtime/scripts/lib/command-tokens.mjs +77 -78
- package/runtime/scripts/lib/compose-values.d.mts +6 -0
- package/runtime/scripts/lib/compose-values.mjs +7 -7
- package/runtime/scripts/lib/css-rules.d.mts +36 -0
- package/runtime/scripts/lib/css-rules.mjs +181 -171
- package/runtime/scripts/lib/deployment-findings.d.mts +9 -0
- package/runtime/scripts/lib/deployment-findings.mjs +4 -4
- package/runtime/scripts/lib/dockerfile.d.mts +39 -0
- package/runtime/scripts/lib/dockerfile.mjs +131 -114
- package/runtime/scripts/lib/dom-tree.d.mts +7 -0
- package/runtime/scripts/lib/dom-tree.mjs +3 -3
- package/runtime/scripts/lib/env.d.mts +12 -0
- package/runtime/scripts/lib/env.mjs +3 -6
- package/runtime/scripts/lib/escape.d.mts +6 -0
- package/runtime/scripts/lib/escape.mjs +2 -6
- package/runtime/scripts/lib/event-contract.d.mts +21 -0
- package/runtime/scripts/lib/event-contract.mjs +73 -78
- package/runtime/scripts/lib/event-items.d.mts +20 -0
- package/runtime/scripts/lib/event-items.mjs +27 -15
- package/runtime/scripts/lib/example-refs.d.mts +69 -0
- package/runtime/scripts/lib/example-refs.mjs +145 -129
- package/runtime/scripts/lib/fs-kind.d.mts +12 -0
- package/runtime/scripts/lib/fs-kind.mjs +20 -10
- package/runtime/scripts/lib/git-hooks-dir.d.mts +15 -0
- package/runtime/scripts/lib/git-hooks-dir.mjs +16 -16
- package/runtime/scripts/lib/git.d.mts +24 -0
- package/runtime/scripts/lib/git.mjs +15 -16
- package/runtime/scripts/lib/glob.d.mts +4 -0
- package/runtime/scripts/lib/glob.mjs +23 -14
- package/runtime/scripts/lib/grammar-lint.d.mts +47 -0
- package/runtime/scripts/lib/grammar-lint.mjs +33 -37
- package/runtime/scripts/lib/grammar-vendor-parity-jsx.d.mts +40 -0
- package/runtime/scripts/lib/grammar-vendor-parity-jsx.mjs +285 -266
- package/runtime/scripts/lib/grammar-vendor-parity.d.mts +61 -0
- package/runtime/scripts/lib/grammar-vendor-parity.mjs +209 -216
- package/runtime/scripts/lib/graphql-contract.d.mts +53 -0
- package/runtime/scripts/lib/graphql-contract.mjs +201 -198
- package/runtime/scripts/lib/graphql-sdl.d.mts +66 -0
- package/runtime/scripts/lib/graphql-sdl.mjs +230 -205
- package/runtime/scripts/lib/hook-limits.d.mts +11 -0
- package/runtime/scripts/lib/hook-limits.mjs +0 -1
- package/runtime/scripts/lib/i18n.d.mts +48 -0
- package/runtime/scripts/lib/i18n.mjs +32 -35
- package/runtime/scripts/lib/in-order.d.mts +12 -0
- package/runtime/scripts/lib/in-order.mjs +57 -38
- package/runtime/scripts/lib/is-main.d.mts +6 -0
- package/runtime/scripts/lib/is-main.mjs +11 -4
- package/runtime/scripts/lib/js-lex.d.mts +32 -0
- package/runtime/scripts/lib/js-lex.mjs +196 -162
- package/runtime/scripts/lib/json-clone.d.mts +11 -0
- package/runtime/scripts/lib/json-clone.mjs +45 -36
- package/runtime/scripts/lib/json-schema.d.mts +2 -0
- package/runtime/scripts/lib/json-schema.mjs +127 -90
- package/runtime/scripts/lib/json.d.mts +16 -0
- package/runtime/scripts/lib/json.mjs +26 -14
- package/runtime/scripts/lib/language.d.mts +44 -0
- package/runtime/scripts/lib/language.mjs +133 -129
- package/runtime/scripts/lib/list.d.mts +17 -0
- package/runtime/scripts/lib/list.mjs +9 -14
- package/runtime/scripts/lib/loosening-budgets.d.mts +12 -0
- package/runtime/scripts/lib/loosening-budgets.mjs +35 -29
- package/runtime/scripts/lib/loosening-config.d.mts +64 -0
- package/runtime/scripts/lib/loosening-config.mjs +267 -236
- package/runtime/scripts/lib/loosening-state.d.mts +77 -0
- package/runtime/scripts/lib/loosening-state.mjs +134 -128
- package/runtime/scripts/lib/mutation-fence.d.mts +11 -0
- package/runtime/scripts/lib/mutation-fence.mjs +10 -5
- package/runtime/scripts/lib/normalize.d.mts +12 -0
- package/runtime/scripts/lib/normalize.mjs +11 -11
- package/runtime/scripts/lib/numeric-match.d.mts +2 -0
- package/runtime/scripts/lib/numeric-match.mjs +2 -2
- package/runtime/scripts/lib/package-at.d.mts +24 -0
- package/runtime/scripts/lib/package-at.mjs +34 -31
- package/runtime/scripts/lib/path-key.d.mts +76 -0
- package/runtime/scripts/lib/path-key.mjs +53 -38
- package/runtime/scripts/lib/pid-alive.d.mts +2 -0
- package/runtime/scripts/lib/pid-alive.mjs +10 -3
- package/runtime/scripts/lib/properties.d.mts +2 -0
- package/runtime/scripts/lib/properties.mjs +17 -11
- package/runtime/scripts/lib/provision-operation-schema.d.mts +4 -0
- package/runtime/scripts/lib/provision-operation-schema.mjs +4 -5
- package/runtime/scripts/lib/read-text.d.mts +12 -0
- package/runtime/scripts/lib/read-text.mjs +30 -17
- package/runtime/scripts/lib/redact.d.mts +52 -0
- package/runtime/scripts/lib/redact.mjs +135 -121
- package/runtime/scripts/lib/regex.d.mts +2 -0
- package/runtime/scripts/lib/regex.mjs +1 -2
- package/runtime/scripts/lib/roots.d.mts +32 -0
- package/runtime/scripts/lib/roots.mjs +5 -15
- package/runtime/scripts/lib/runtime-example.d.mts +1 -0
- package/runtime/scripts/lib/runtime-example.mjs +10 -8
- package/runtime/scripts/lib/same-text.d.mts +2 -0
- package/runtime/scripts/lib/same-text.mjs +0 -1
- package/runtime/scripts/lib/sealed-member.d.mts +16 -0
- package/runtime/scripts/lib/sealed-member.mjs +8 -13
- package/runtime/scripts/lib/secret-patterns.d.mts +30 -0
- package/runtime/scripts/lib/secret-patterns.mjs +175 -163
- package/runtime/scripts/lib/shell-source.d.mts +2 -0
- package/runtime/scripts/lib/shell-source.mjs +0 -1
- package/runtime/scripts/lib/sleep-sync.d.mts +2 -0
- package/runtime/scripts/lib/sleep-sync.mjs +5 -6
- package/runtime/scripts/lib/sops-envelope.d.mts +34 -0
- package/runtime/scripts/lib/sops-envelope.mjs +148 -120
- package/runtime/scripts/lib/source-phrases.d.mts +4 -0
- package/runtime/scripts/lib/source-phrases.mjs +13 -13
- package/runtime/scripts/lib/sql-ast.d.mts +13 -0
- package/runtime/scripts/lib/sql-ast.mjs +19 -18
- package/runtime/scripts/lib/sqlite.d.mts +21 -0
- package/runtime/scripts/lib/sqlite.mjs +3 -9
- package/runtime/scripts/lib/stack-declaration.d.mts +51 -0
- package/runtime/scripts/lib/stack-declaration.mjs +27 -20
- package/runtime/scripts/lib/stack-services.d.mts +73 -0
- package/runtime/scripts/lib/stack-services.mjs +128 -129
- package/runtime/scripts/lib/starciwork-boundary.d.mts +10 -0
- package/runtime/scripts/lib/starciwork-boundary.mjs +98 -92
- package/runtime/scripts/lib/swarm-stack.d.mts +24 -0
- package/runtime/scripts/lib/swarm-stack.mjs +112 -100
- package/runtime/scripts/lib/trim-end.d.mts +2 -0
- package/runtime/scripts/lib/trim-end.mjs +4 -4
- package/runtime/scripts/lib/ts-analysis.d.mts +24 -0
- package/runtime/scripts/lib/ts-analysis.mjs +28 -26
- package/runtime/scripts/lib/ts-ast.d.mts +36 -0
- package/runtime/scripts/lib/ts-ast.mjs +36 -42
- package/runtime/scripts/lib/walk.d.mts +19 -0
- package/runtime/scripts/lib/walk.mjs +33 -27
- package/runtime/scripts/lib/work-edition.d.mts +10 -0
- package/runtime/scripts/lib/work-edition.mjs +29 -21
- package/runtime/scripts/lib/workflow-events.d.mts +2 -0
- package/runtime/scripts/lib/workflow-events.mjs +5 -4
- package/runtime/scripts/lib/worktree-exclude.d.mts +16 -0
- package/runtime/scripts/lib/worktree-exclude.mjs +6 -8
- package/runtime/scripts/lib/yaml-cached.d.mts +2 -0
- package/runtime/scripts/lib/yaml-cached.mjs +4 -4
- package/runtime/scripts/machine/artifact-hold.d.mts +26 -0
- package/runtime/scripts/machine/artifact-hold.mjs +22 -23
- package/runtime/scripts/work/asset-slot.d.mts +96 -0
- package/runtime/scripts/work/asset-slot.mjs +201 -175
- package/runtime/scripts/work/draw/draw-dna-anatomy.d.mts +30 -0
- package/runtime/scripts/work/draw/draw-dna-anatomy.mjs +40 -36
- package/runtime/scripts/work/draw/draw-dna-findings.d.mts +12 -0
- package/runtime/scripts/work/draw/draw-dna-findings.mjs +240 -206
- package/runtime/scripts/work/draw/draw-dna-selector.d.mts +7 -0
- package/runtime/scripts/work/draw/draw-dna-selector.mjs +28 -28
- package/runtime/scripts/work/draw/draw-dna.d.mts +191 -0
- package/runtime/scripts/work/draw/draw-dna.mjs +283 -249
- package/runtime/scripts/work/grammar-proposal.d.mts +83 -0
- package/runtime/scripts/work/grammar-proposal.mjs +215 -178
- package/runtime/scripts/work/work-io.d.mts +62 -0
- package/runtime/scripts/work/work-io.mjs +82 -63
- package/scaffold/add-app.d.mts +15 -0
- package/scaffold/add-app.mjs +111 -163
- package/scaffold/add-cli-lite.d.mts +8 -0
- package/scaffold/add-cli-lite.mjs +173 -207
- package/scaffold/add-compose.d.mts +44 -0
- package/scaffold/add-compose.mjs +62 -62
- package/scaffold/add-database-lite.d.mts +2 -0
- package/scaffold/add-database-lite.mjs +10 -10
- package/scaffold/add-fe-layout.d.mts +16 -0
- package/scaffold/add-fe-layout.mjs +23 -23
- package/scaffold/add-fe-overlay.d.mts +17 -0
- package/scaffold/add-fe-overlay.mjs +76 -78
- package/scaffold/add-fe-page.d.mts +41 -0
- package/scaffold/add-fe-page.mjs +84 -89
- package/scaffold/add-fe-unit.d.mts +59 -0
- package/scaffold/add-fe-unit.mjs +205 -197
- package/scaffold/add-inbox-lite.d.mts +17 -0
- package/scaffold/add-inbox-lite.mjs +209 -264
- package/scaffold/add-plan.d.mts +68 -0
- package/scaffold/add-plan.mjs +164 -149
- package/scaffold/add-queue-lite.d.mts +34 -0
- package/scaffold/add-queue-lite.mjs +267 -267
- package/scaffold/add-table.d.mts +16 -0
- package/scaffold/add-table.mjs +405 -442
- package/scaffold/add.d.mts +34 -0
- package/scaffold/add.mjs +260 -246
- package/scaffold/app.d.mts +198 -0
- package/scaffold/app.mjs +413 -391
- package/scaffold/edition-gate.d.mts +49 -0
- package/scaffold/edition-gate.mjs +19 -29
- package/scaffold/image.d.mts +4 -0
- package/scaffold/image.mjs +12 -12
- package/scaffold/lite-exports.d.mts +15 -0
- package/scaffold/lite-exports.mjs +262 -255
- package/scaffold/pattern-file-slots.d.mts +7 -0
- package/scaffold/pattern-file-slots.mjs +29 -24
- package/scaffold/service.d.mts +60 -0
- package/scaffold/service.mjs +297 -279
- package/scaffold/test-world.d.mts +31 -0
- package/scaffold/test-world.mjs +71 -78
- package/scaffold/yaml-block-edit.d.mts +23 -0
- package/scaffold/yaml-block-edit.mjs +95 -87
- package/scripts/sync-bundles.d.mts +31 -0
- package/src/fixtures/bypass-index.d.mts +4 -0
- package/src/fixtures/hfs-stack-tooling/passing.d.mts +8 -0
- package/src/fixtures/hfs-stack-tooling/violating.d.mts +19 -0
- package/src/fixtures/hfs-stacks-full/model-unavailable.d.mts +10 -0
- package/src/fixtures/hfs-stacks-full/passing.d.mts +19 -0
- package/src/fixtures/hfs-stacks-full/violating.d.mts +10 -0
- package/src/fixtures/loosening/adversarial.d.mts +4 -0
- package/src/fixtures/loosening/forms.d.mts +16 -0
- package/src/fixtures/loosening/swallows.d.mts +5 -0
- package/src/helpers/hfs-arch-fixture.d.mts +47 -0
- package/src/helpers/hfs-cli-fixture.d.mts +65 -0
- package/src/helpers/hfs-hfs-docker-rules-fixture.d.mts +5 -0
- package/src/helpers/hfs-secret-fixture.d.mts +19 -0
- package/src/helpers/pre-push-fixture.d.mts +21 -0
- package/src/helpers/stack-compose.d.mts +6 -0
- package/src/helpers/swarm-stack-fixture.d.mts +18 -0
- package/src/helpers/tmpdir.d.mts +2 -0
- package/src/main.d.mts +58 -0
- package/src/main.mjs +494 -346
- package/stack/age-install.d.mts +13 -0
- package/stack/age-install.mjs +28 -25
- package/stack/backup.d.mts +11 -0
- package/stack/backup.mjs +76 -69
- package/stack/build-args.d.mts +7 -0
- package/stack/build-args.mjs +22 -23
- package/stack/build.d.mts +8 -0
- package/stack/build.mjs +138 -119
- package/stack/cli.d.mts +55 -0
- package/stack/cli.mjs +187 -130
- package/stack/config.d.mts +197 -0
- package/stack/config.mjs +47 -33
- package/stack/context.d.mts +122 -0
- package/stack/context.mjs +63 -65
- package/stack/converge.d.mts +13 -0
- package/stack/converge.mjs +73 -69
- package/stack/deploy.d.mts +88 -0
- package/stack/deploy.mjs +272 -224
- package/stack/digest.d.mts +8 -0
- package/stack/digest.mjs +1 -6
- package/stack/docker-transport.d.mts +5 -0
- package/stack/docker-transport.mjs +101 -93
- package/stack/edge-alias.d.mts +42 -0
- package/stack/edge-alias.mjs +62 -60
- package/stack/errors.d.mts +18 -0
- package/stack/errors.mjs +8 -10
- package/stack/image-scan.d.mts +20 -0
- package/stack/image-scan.mjs +114 -101
- package/stack/ingress-create.d.mts +4 -0
- package/stack/ingress-create.mjs +82 -86
- package/stack/ingress-publish.d.mts +6 -0
- package/stack/ingress-publish.mjs +194 -182
- package/stack/ingress.d.mts +55 -0
- package/stack/ingress.mjs +534 -524
- package/stack/jobs.d.mts +12 -0
- package/stack/jobs.mjs +35 -34
- package/stack/live-restore.d.mts +35 -0
- package/stack/live-restore.mjs +120 -125
- package/stack/post-deploy.d.mts +8 -0
- package/stack/post-deploy.mjs +25 -25
- package/stack/prepare.d.mts +24 -0
- package/stack/prepare.mjs +213 -200
- package/stack/private-file.d.mts +5 -0
- package/stack/private-file.mjs +9 -9
- package/stack/provision.d.mts +25 -0
- package/stack/provision.mjs +64 -63
- package/stack/prune.d.mts +11 -0
- package/stack/prune.mjs +38 -27
- package/stack/release-store.d.mts +28 -0
- package/stack/release-store.mjs +68 -67
- package/stack/remote.d.mts +83 -0
- package/stack/remote.mjs +176 -162
- package/stack/render.d.mts +14 -0
- package/stack/render.mjs +132 -124
- package/stack/retire.d.mts +9 -0
- package/stack/retire.mjs +31 -34
- package/stack/sealed.d.mts +46 -0
- package/stack/sealed.mjs +78 -82
- package/stack/server-key.d.mts +67 -0
- package/stack/server-key.mjs +217 -203
- package/stack/ssh-session.d.mts +29 -0
- package/stack/ssh-session.mjs +133 -123
- package/stack/target-binding.d.mts +21 -0
- package/stack/target-binding.mjs +68 -44
- package/stack/task.d.mts +12 -0
- package/stack/task.mjs +26 -31
- package/stack/urgent-floor.d.mts +106 -0
- package/stack/urgent-floor.mjs +211 -160
- package/stack/urgent-release.d.mts +38 -0
- package/stack/urgent-release.mjs +26 -22
- package/stack/verify.d.mts +14 -0
- package/stack/verify.mjs +75 -65
- package/sync/ci-commands.d.mts +26 -0
- package/sync/ci-commands.mjs +181 -182
- package/sync/cli.d.mts +8 -0
- package/sync/cli.mjs +9 -9
- package/sync/format.d.mts +38 -0
- package/sync/format.mjs +30 -24
- package/sync/hygiene.d.mts +23 -0
- package/sync/hygiene.mjs +113 -99
- package/sync/index.d.mts +237 -0
- package/sync/index.mjs +457 -436
- package/sync/managed.d.mts +23 -0
- package/sync/managed.mjs +104 -94
- package/sync/quality-services.d.mts +35 -0
- package/sync/quality-services.mjs +48 -41
- package/sync/readme-badges.d.mts +13 -0
- package/sync/readme-badges.mjs +45 -44
- package/sync/sonar-key.d.mts +31 -0
- package/sync/sonar-key.mjs +29 -28
- package/sync/stack-images.d.mts +36 -0
- package/sync/stack-images.mjs +85 -95
- package/sync/ts-strict.d.mts +14 -0
- package/sync/ts-strict.mjs +43 -34
- package/templates/app/ci-workflows/github/workflows/ci.yml +1 -1
- package/templates/app/ci-workflows/github/workflows/images.yml +1 -1
- package/templates/app/ci-workflows/github/workflows/stack-deploy.yml +2 -2
- package/templates/app/ci-workflows/github/workflows/stack-key-restore.yml +1 -1
- package/templates/app/ci-workflows-lite/github/workflows/ci.yml +1 -1
- package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +3 -3
- package/templates/app/ci-workflows-lite/github/workflows/images.yml +1 -1
- package/templates/app/ci-workflows-lite/github/workflows/stack-deploy.yml +2 -2
- package/templates/app/ci-workflows-lite/github/workflows/stack-key-restore.yml +1 -1
- package/templates/app/codegen-lite/scripts/codegen.mjs +1 -1
- package/templates/app/db-bootstrap/db/bootstrap.sql +1 -1
- package/templates/app/db-image/starcistacks/images/db/Dockerfile +1 -1
- package/templates/app/hooks/husky/pre-commit +2 -2
- package/templates/app/package-scripts/db.json +3 -3
- package/templates/app/package-scripts/package.json +1 -1
- package/templates/app/quality-config/sonar-project.properties +1 -1
- package/templates/app/skeleton/.starcistacks/application-stacks.yaml +2 -2
- package/templates/app/skeleton/.starcistacks/production/README.md +4 -4
- package/templates/app/skeleton/.starcistacks/production/infra/swarm/stack.yaml +8 -3
- package/templates/app/skeleton/README.md +1 -1
- package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +2 -2
- package/templates/app/skeleton-lite/.starcistacks/dev/README.md +1 -1
- package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/stack.yaml +6 -2
- package/templates/app/skeleton-lite/.starcistacks/dev/runtime/env/KEYS.md +3 -2
- package/templates/app/skeleton-lite/.starcistacks/production/README.md +5 -5
- package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/stack.yaml +7 -2
- package/templates/app/skeleton-lite/.starcistacks/production/runtime/env/KEYS.md +3 -2
- package/templates/app/skeleton-lite/README.md +2 -2
- package/templates/be/skeleton/apps/cli/src/compose/platform.ts +1 -1
- package/templates/be/skeleton/apps/cli/src/main.ts +6 -4
- package/templates/be/skeleton/src/modules/platform/config/env-source.config.ts +12 -0
- package/templates/be/skeleton/src/modules/platform/database/abstract.entity.ts +19 -0
- package/templates/be/skeleton/src/modules/platform/database/database.module.ts +7 -1
- package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.spec.ts +19 -0
- package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.ts +4 -3
- package/templates/be/skeleton/src/modules/platform/logging/logging.module.ts +1 -1
- package/templates/be/skeleton/src/modules/platform/logging/logging.options.ts +5 -2
- package/templates/be/skeleton-lite/apps/cli/src/compose/platform.ts +1 -1
- package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.config.spec.ts +40 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.config.ts +1 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.cookie.spec.ts +48 -1
- package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.cookie.ts +5 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.options.ts +5 -0
- package/templates/be/skeleton-lite/src/modules/integrations/passport/strategies/google.strategy.ts +1 -1
- package/templates/be/skeleton-lite/src/modules/integrations/passport/strategies/oauth-state.store.ts +7 -3
- package/templates/be/skeleton-lite/src/modules/platform/database/database.module.ts +7 -1
- package/templates/be/table/entity.ts.tpl +4 -15
- package/upgrade/check.d.mts +9 -0
- package/upgrade/check.mjs +8 -8
- package/upgrade/file-state.d.mts +6 -0
- package/upgrade/file-state.mjs +32 -40
- package/upgrade/index.d.mts +13 -0
- package/upgrade/index.mjs +122 -151
- package/vendor-types.d.mts +8 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// app db baseline --squash: the whole active chain becomes ONE baseline read from a database the chain is applied to (--url-env), for a
|
|
1
|
+
// app db baseline --squash: the whole active chain becomes ONE baseline read from a database the chain is applied to (--db-url-env), for a
|
|
2
2
|
// cutover whose production starts on an empty database. Nothing is rebuilt from migration SQL: the source's schema is dumped with its
|
|
3
3
|
// privileges, the objects of the extensions the target image lacks (--drop-extension) and every function or view whose body reaches their
|
|
4
4
|
// schemas are left out by name, the role facts a per-database dump loses go to a marked section of db/bootstrap.sql, and the reference rows
|
|
@@ -12,7 +12,6 @@ import { randomBytes } from 'node:crypto';
|
|
|
12
12
|
import { DB_DOCKERFILE, DB_IMAGE_CONTEXT } from '../../../db/image.mjs';
|
|
13
13
|
import { DbVerbError } from './db-errors.mjs';
|
|
14
14
|
import { BOOTSTRAP_FILE, BOOTSTRAP_SQUASH_BEGIN, BOOTSTRAP_SQUASH_END, SEED_FILE, bootstrapSection } from './rules/database-constants.mjs';
|
|
15
|
-
|
|
16
15
|
/** The extensions a lite app's db image does not ship, dropped unless --drop-extension names others (pgmq stays: it is the lite event bus). */
|
|
17
16
|
export const DEFAULT_DROPPED_EXTENSIONS = Object.freeze(['pg_net', 'pg_cron']);
|
|
18
17
|
export const SEED_HEADER = '-- Generated by starci app db baseline --squash';
|
|
@@ -25,69 +24,68 @@ const LOCAL_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]']);
|
|
|
25
24
|
const REPLAY_DB = 'starci_squash_replay';
|
|
26
25
|
const READY_TIMEOUT_MS = 120_000;
|
|
27
26
|
const DIFF_LIMIT = 40;
|
|
28
|
-
|
|
29
27
|
const ident = (name) => `"${String(name).replaceAll('"', '""')}"`;
|
|
30
28
|
const literal = (value) => `'${String(value).replaceAll("'", "''")}'`;
|
|
31
29
|
const unquote = (name) => (/^".*"$/s.test(name) ? name.slice(1, -1).replaceAll('""', '"') : name);
|
|
32
30
|
const escape = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
33
31
|
const sleep = (ms) => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
34
32
|
const sorted = (items) => [...items].sort((left, right) => (left < right ? -1 : Number(left > right)));
|
|
35
|
-
|
|
36
33
|
/** A comma list flag as distinct names, or `fallback` when the flag is absent. */
|
|
37
34
|
export const flagList = (value, fallback) => (value === undefined ? [...fallback] : [...new Set(String(value).split(',').map((item) => item.trim()).filter(Boolean))]);
|
|
38
|
-
|
|
39
35
|
/* ---- docker: every client tool runs in a container of the db image, so the host needs Docker and no PostgreSQL client */
|
|
40
|
-
|
|
41
36
|
function docker(args, { input, env = {}, secrets = [] } = {}) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
const result = spawnSync('docker', args, { input, env: { ...process.env, ...env }, encoding: 'utf8', maxBuffer: 1 << 30, timeout: 600_000, windowsHide: true });
|
|
38
|
+
const scrub = (text) => secrets.filter(Boolean).reduce((out, secret) => out.replaceAll(secret, '[value]'), String(text ?? ''));
|
|
39
|
+
return { ok: !result.error && result.status === 0, stdout: String(result.stdout ?? ''), stderr: scrub(result.stderr || result.error?.message) };
|
|
45
40
|
}
|
|
46
|
-
|
|
47
41
|
const firstLines = (text, count = 4) => String(text).trim().split('\n').filter(Boolean).slice(0, count).join(' | ');
|
|
48
|
-
|
|
49
42
|
/** A throwaway container of `image` that can reach the host as host.docker.internal; refused without Docker. */
|
|
50
43
|
function startScratch(image) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
44
|
+
if (!docker(['version', '--format', '{{.Server.Version}}']).ok)
|
|
45
|
+
throw new DbVerbError('baseline --squash needs Docker for its scratch replay; start it');
|
|
46
|
+
const password = randomBytes(18).toString('hex');
|
|
47
|
+
const name = `starci-db-squash-${randomBytes(6).toString('hex')}`;
|
|
48
|
+
const scratch = { name, password, image, stop: () => docker(['rm', '-f', name]) };
|
|
49
|
+
const started = docker(['run', '-d', '--rm', '--name', name, '--label', 'starci.db-squash=1', '--add-host', 'host.docker.internal:host-gateway', '-e', 'POSTGRES_PASSWORD', image], { env: { POSTGRES_PASSWORD: password } });
|
|
50
|
+
if (!started.ok) {
|
|
51
|
+
scratch.stop();
|
|
52
|
+
throw new DbVerbError(`docker could not start ${image}: ${firstLines(started.stderr, 1)}`);
|
|
53
|
+
}
|
|
54
|
+
const since = Date.now();
|
|
55
|
+
// TCP, not the socket: the image's init server listens on the socket only, and restarts before it serves TCP.
|
|
56
|
+
while (!docker(['exec', '-e', 'PGPASSWORD', name, 'psql', '-X', '-h', '127.0.0.1', '-U', 'postgres', '-Atqc', 'select 1'], { env: { PGPASSWORD: password } }).ok) {
|
|
57
|
+
if (Date.now() - since > READY_TIMEOUT_MS) {
|
|
58
|
+
scratch.stop();
|
|
59
|
+
throw new DbVerbError(`the scratch database of ${image} did not start`);
|
|
60
|
+
}
|
|
61
|
+
sleep(500);
|
|
62
|
+
}
|
|
63
|
+
return scratch;
|
|
64
64
|
}
|
|
65
|
-
|
|
66
65
|
/** The app's own db image, built from its managed Dockerfile (DB_DOCKERFILE); its id names it. */
|
|
67
66
|
function buildImage(root) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
if (!docker(['version', '--format', '{{.Server.Version}}']).ok)
|
|
68
|
+
throw new DbVerbError('baseline --squash needs Docker for its scratch replay; start it');
|
|
69
|
+
const build = docker(['build', '--quiet', '--file', path.join(root, DB_DOCKERFILE), path.join(root, DB_IMAGE_CONTEXT)]);
|
|
70
|
+
const image = /sha256:[a-f0-9]{64}/.exec(build.stdout)?.[0];
|
|
71
|
+
if (!build.ok || !image)
|
|
72
|
+
throw new DbVerbError(`docker could not build ${DB_DOCKERFILE}: ${firstLines(build.stderr, 2)}`);
|
|
73
|
+
return image;
|
|
73
74
|
}
|
|
74
|
-
|
|
75
75
|
/** Where a target's client tools run: `docker exec` in the scratch container, or a one-shot container of its image on the host's network. */
|
|
76
76
|
const inScratch = (scratch) => ({ head: ['exec', '-i'], ref: scratch.name });
|
|
77
77
|
const onHostNetwork = (scratch) => ({ head: ['run', '--rm', '-i', '--network', 'host', '--label', 'starci.db-squash=1'], ref: scratch.image });
|
|
78
|
-
|
|
79
78
|
const scratchTarget = (scratch, database) => ({ url: `postgresql://postgres@127.0.0.1:5432/${database}`, password: scratch.password, label: `the scratch ${database}`, client: inScratch(scratch) });
|
|
80
|
-
|
|
81
79
|
function exec(target, tool, args, { input, query = false } = {}) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
const env = { PGPASSWORD: target.password, ...(query ? { PGOPTIONS: QUERY_OPTIONS } : {}) };
|
|
81
|
+
const result = docker([...target.client.head, '-e', 'PGPASSWORD', ...(query ? ['-e', 'PGOPTIONS'] : []), target.client.ref, tool, ...args], { input, env, secrets: [target.password, target.url] });
|
|
82
|
+
if (!result.ok)
|
|
83
|
+
throw new DbVerbError(`${tool} against ${target.label} failed: ${firstLines(result.stderr)}`);
|
|
84
|
+
return result.stdout;
|
|
86
85
|
}
|
|
87
|
-
|
|
88
86
|
const psqlArgs = (target) => ['-X', '-q', '-v', 'ON_ERROR_STOP=1', '-d', target.url];
|
|
87
|
+
// reason: the rows psql returns as JSON; each call site names the shape it expects.
|
|
89
88
|
const queryJson = (target, sql) => JSON.parse(exec(target, 'psql', [...psqlArgs(target), '-A', '-t', '-c', sql], { query: true }));
|
|
90
|
-
|
|
91
89
|
/**
|
|
92
90
|
* The source as a container reaches it. A remote host is reached from the scratch container. A loopback host is the host's own: Docker
|
|
93
91
|
* Desktop reaches it from the scratch container as host.docker.internal, a Linux engine only from a container on the host's network (its
|
|
@@ -95,29 +93,33 @@ const queryJson = (target, sql) => JSON.parse(exec(target, 'psql', [...psqlArgs(
|
|
|
95
93
|
* when none does, the verb refuses with each route's failure.
|
|
96
94
|
*/
|
|
97
95
|
export function sourceTarget(scratch, connection, label) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
96
|
+
const password = connection.env.PGPASSWORD ?? '';
|
|
97
|
+
const url = new URL(connection.url);
|
|
98
|
+
if (!LOCAL_HOSTS.has(url.hostname))
|
|
99
|
+
return { url: url.toString(), password, label, client: inScratch(scratch) };
|
|
100
|
+
const gateway = new URL(connection.url);
|
|
101
|
+
gateway.hostname = 'host.docker.internal';
|
|
102
|
+
const routes = [{ url: gateway.toString(), password, label, client: inScratch(scratch) }, { url: url.toString(), password, label, client: onHostNetwork(scratch) }];
|
|
103
|
+
const failures = [];
|
|
104
|
+
for (const route of routes) {
|
|
105
|
+
try {
|
|
106
|
+
exec(route, 'psql', [...psqlArgs(route), '-At', '-c', 'select 1']);
|
|
107
|
+
return route;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
failures.push(error.message);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
throw new DbVerbError(`no container of ${scratch.image} reaches ${label}:\n${failures.map((line) => ` ${line}`).join('\n')}`);
|
|
109
114
|
}
|
|
110
|
-
|
|
111
115
|
/** The runPostgres port of db-baseline-verb.mjs, served by the target's container: the history precondition needs no host psql. */
|
|
112
116
|
export function targetRunner(target, commandOf) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
+
return (_root, op) => {
|
|
118
|
+
const [tool, args] = commandOf(op, target.url);
|
|
119
|
+
return { status: 0, stdout: exec(target, tool, args) };
|
|
120
|
+
};
|
|
117
121
|
}
|
|
118
|
-
|
|
119
122
|
/* ---- the source facts: one read-only catalog query */
|
|
120
|
-
|
|
121
123
|
const notMember = (classid, column) => `not exists (select 1 from pg_catalog.pg_depend d where d.classid = '${classid}'::pg_catalog.regclass and d.objid = ${column} and d.deptype = 'e')`;
|
|
122
124
|
const userSchema = (column) => `${column} !~ '^pg_' and ${column} <> 'information_schema'`;
|
|
123
125
|
const FACTS_SQL = `select pg_catalog.json_build_object(
|
|
@@ -142,236 +144,268 @@ const FACTS_SQL = `select pg_catalog.json_build_object(
|
|
|
142
144
|
'views', (select coalesce(json_agg(json_build_object('schema', n.nspname, 'name', c.relname, 'kind', c.relkind, 'text', pg_catalog.pg_get_viewdef(c.oid)) order by n.nspname, c.relname), '[]')
|
|
143
145
|
from pg_catalog.pg_class c join pg_catalog.pg_namespace n on n.oid = c.relnamespace
|
|
144
146
|
where c.relkind in ('v', 'm') and ${userSchema('n.nspname')} and ${notMember('pg_catalog.pg_class', 'c.oid')}))`;
|
|
145
|
-
|
|
146
147
|
const QUEUES_SQL = `select coalesce(json_agg(json_build_object('name', m.queue_name, 'partitioned', m.is_partitioned, 'unlogged', m.is_unlogged) order by m.queue_name), '[]') from pgmq.meta m`;
|
|
147
|
-
|
|
148
148
|
/** Whether a queue name matches one --drop-pgmq-queue entry: a name, or a pattern where `*` matches any run of characters. */
|
|
149
149
|
export const queueDropped = (name, patterns) => patterns.some((pattern) => new RegExp(`^${pattern.split('*').map(escape).join('.*')}$`).test(name));
|
|
150
|
-
|
|
151
150
|
/* ---- the dump as entries */
|
|
152
|
-
|
|
153
151
|
const ENTRY = /^-- (?:Data for )?Name: (.*); Type: (.*); Schema: (.*); Owner: (.*)$/;
|
|
154
152
|
const LOOSE_SET = /^SET default_(?:tablespace|table_access_method) = .*;$/;
|
|
155
|
-
|
|
156
153
|
/** A plain pg_dump as { preamble, entries: [{ name, type, schema, body }] }; psql's \restrict guard and the version comments are dropped. */
|
|
157
154
|
export function dumpEntries(text) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
155
|
+
const lines = String(text).replace(/\r\n/g, '\n').split('\n').filter((line) => !/^\\(?:un)?restrict\b/.test(line));
|
|
156
|
+
const starts = lines.flatMap((line, index) => (ENTRY.test(line) && lines[index - 1] === '--' && lines[index + 1] === '--' ? [index] : []));
|
|
157
|
+
const preamble = lines.slice(0, starts.length ? starts[0] - 1 : lines.length).filter((line) => /^(?:SET|SELECT) /.test(line));
|
|
158
|
+
const entries = starts.map((start, index) => {
|
|
159
|
+
const [, name, type, schema] = ENTRY.exec(lines[start]);
|
|
160
|
+
const end = index + 1 < starts.length ? starts[index + 1] - 1 : lines.length;
|
|
161
|
+
const body = lines.slice(start + 2, end).filter((line) => {
|
|
162
|
+
if (!LOOSE_SET.test(line))
|
|
163
|
+
return true;
|
|
164
|
+
if (!preamble.includes(line))
|
|
165
|
+
preamble.push(line);
|
|
166
|
+
return false;
|
|
167
|
+
}).join('\n').replace(/\n--\n-- PostgreSQL database dump complete\n--\s*$/, '').trim();
|
|
168
|
+
return { name, type, schema, body };
|
|
169
|
+
});
|
|
170
|
+
return { preamble, entries };
|
|
172
171
|
}
|
|
173
|
-
|
|
174
172
|
const entryKey = (entry) => `${entry.type}|${entry.schema}|${entry.name}`;
|
|
175
173
|
const renderEntry = (entry) => `--\n-- Name: ${entry.name}; Type: ${entry.type}; Schema: ${entry.schema}; Owner: -\n--\n\n${entry.body}\n\n\n`;
|
|
176
|
-
|
|
177
174
|
const ROLE_NAMES = /\b(?:TO|FROM|FOR ROLE|SESSION AUTHORIZATION)\s+((?:"(?:[^"]|"")+"|[\w$]+)(?:\s*,\s*(?:"(?:[^"]|"")+"|[\w$]+))*)/gi;
|
|
178
175
|
/** The roles a statement grants to, revokes from, acts for or switches to. */
|
|
179
176
|
const rolesOf = (text) => [...String(text).matchAll(ROLE_NAMES)].flatMap((match) => match[1].split(/\s*,\s*/).map(unquote));
|
|
180
|
-
|
|
181
177
|
/* ---- the projection: what a squash of one database writes */
|
|
182
|
-
|
|
183
178
|
/** The names a bootstrap's own SQL creates: its schemas, roles and publications. */
|
|
184
179
|
export function bootstrapDeclares(head) {
|
|
185
|
-
|
|
186
|
-
|
|
180
|
+
const created = (kind) => new Set([...head.matchAll(new RegExp(`create\\s+${kind}\\s+(?:if\\s+not\\s+exists\\s+)?("(?:[^"]|"")+"|[\\w$]+)`, 'gi'))].map((match) => unquote(match[1])));
|
|
181
|
+
return { schemas: created('schema'), roles: created('role'), publications: created('publication') };
|
|
187
182
|
}
|
|
188
|
-
|
|
189
183
|
function ownerOf(entry) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
184
|
+
if (entry.schema !== '-')
|
|
185
|
+
return { schema: entry.schema };
|
|
186
|
+
const target = /^(SCHEMA|EXTENSION) (.+)$/.exec(entry.name);
|
|
187
|
+
if (entry.type === 'SCHEMA')
|
|
188
|
+
return { schema: unquote(entry.name) };
|
|
189
|
+
if (entry.type === 'EXTENSION')
|
|
190
|
+
return { extension: unquote(entry.name) };
|
|
191
|
+
if (['ACL', 'COMMENT'].includes(entry.type) && target)
|
|
192
|
+
return target[1] === 'SCHEMA' ? { schema: unquote(target[2]), schemaLevel: true } : { extension: unquote(target[2]) };
|
|
193
|
+
if (entry.type === 'DEFAULT ACL')
|
|
194
|
+
return { global: true };
|
|
195
|
+
if (entry.type === 'PUBLICATION')
|
|
196
|
+
return { publication: unquote(entry.name) };
|
|
197
|
+
if (entry.type === 'EVENT TRIGGER')
|
|
198
|
+
return { eventTrigger: unquote(/EXECUTE FUNCTION\s+("(?:[^"]|"")+"|[\w$]+)\./i.exec(entry.body)?.[1] ?? '') };
|
|
199
|
+
return { database: true };
|
|
199
200
|
}
|
|
200
|
-
|
|
201
201
|
function routineKeys(routine) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
202
|
+
const kind = { p: 'PROCEDURE', a: 'AGGREGATE' }[routine.kind] ?? 'FUNCTION';
|
|
203
|
+
const signature = `${routine.name}(${routine.args})`;
|
|
204
|
+
return [`${kind}|${routine.schema}|${routine.name}(${routine.types})`, `ACL|${routine.schema}|${kind} ${signature}`, `COMMENT|${routine.schema}|${kind} ${signature}`];
|
|
205
205
|
}
|
|
206
|
-
|
|
207
206
|
function viewKeys(view) {
|
|
208
|
-
|
|
209
|
-
|
|
207
|
+
const kind = view.kind === 'm' ? 'MATERIALIZED VIEW' : 'VIEW';
|
|
208
|
+
return [`${kind}|${view.schema}|${view.name}`, `ACL|${view.schema}|TABLE ${view.name}`, `COMMENT|${view.schema}|${kind} ${view.name}`, `MATERIALIZED VIEW DATA|${view.schema}|${view.name}`];
|
|
210
209
|
}
|
|
211
|
-
|
|
212
210
|
/** Which schemas are the app's, which belong to a dropped extension, and which objects reach the dropped ones. */
|
|
213
211
|
function squashScope(facts, config) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
212
|
+
const kept = facts.extensions.filter((extension) => !config.dropped.includes(extension.name));
|
|
213
|
+
const keptHomes = new Set(kept.map((extension) => extension.schema));
|
|
214
|
+
const droppedSchemas = new Set();
|
|
215
|
+
for (const extension of facts.extensions.filter((item) => config.dropped.includes(item.name))) {
|
|
216
|
+
for (const member of extension.members)
|
|
217
|
+
droppedSchemas.add(member);
|
|
218
|
+
if (!['public', 'pg_catalog'].includes(extension.schema) && !keptHomes.has(extension.schema) && !config.bootstrap.schemas.has(extension.schema))
|
|
219
|
+
droppedSchemas.add(extension.schema);
|
|
220
|
+
}
|
|
221
|
+
const appSchemas = new Set(facts.schemas.filter((schema) => !config.managedSchema(schema) && !droppedSchemas.has(schema) && !config.bootstrap.schemas.has(schema) && !keptHomes.has(schema)));
|
|
222
|
+
// A kept extension's own schema (pgmq) is created by the baseline before its extension; grants on it follow in the baseline's tail.
|
|
223
|
+
const extensionHomes = new Set([...keptHomes].filter((schema) => !['public', 'pg_catalog'].includes(schema) && !config.bootstrap.schemas.has(schema)));
|
|
224
|
+
const reaches = droppedSchemas.size ? new RegExp(`(?<![\\w$."])"?(?:${sorted(droppedSchemas).map(escape).join('|')})"?\\s*\\.`, 'i') : null;
|
|
225
|
+
const excluded = [
|
|
226
|
+
...facts.routines.filter((item) => appSchemas.has(item.schema) && reaches?.test(item.text)).map((item) => ({ label: `${item.schema}.${item.name}(${item.args})`, schema: item.schema, name: item.name, keys: routineKeys(item), call: true })),
|
|
227
|
+
...facts.views.filter((item) => appSchemas.has(item.schema) && reaches?.test(item.text)).map((item) => ({ label: `${item.schema}.${item.name}`, schema: item.schema, name: item.name, keys: viewKeys(item), call: false })),
|
|
228
|
+
];
|
|
229
|
+
return { kept, appSchemas, extensionHomes, droppedSchemas, reaches, excluded, droppedQueues: new Set() };
|
|
230
230
|
}
|
|
231
|
-
|
|
232
231
|
/** Kept entries naming a dropped schema or an excluded object: each pair is a refusal line. */
|
|
233
232
|
function danglingReferences(entries, scope) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
233
|
+
const lines = [];
|
|
234
|
+
for (const entry of entries) {
|
|
235
|
+
const where = `${entry.type} ${entry.schema === '-' ? '' : `${entry.schema}.`}${entry.name}`;
|
|
236
|
+
const schema = scope.reaches?.exec(entry.body);
|
|
237
|
+
if (schema)
|
|
238
|
+
lines.push(`${where} references the dropped schema ${schema[0].replace(/[\s.]+$/, '')}`);
|
|
239
|
+
for (const object of scope.excluded) {
|
|
240
|
+
const qualified = new RegExp(`(?<![\\w$])"?${escape(object.schema)}"?\\."?${escape(object.name)}"?(?![\\w$])`, 'i');
|
|
241
|
+
const bare = object.call && /^(?:FUNCTION|PROCEDURE|VIEW|MATERIALIZED VIEW|TRIGGER|POLICY)$/.test(entry.type) ? new RegExp(`(?<![\\w$."])${escape(object.name)}\\s*\\(`, 'i') : null;
|
|
242
|
+
if (qualified.test(entry.body) || bare?.test(entry.body))
|
|
243
|
+
lines.push(`${where} references the excluded ${object.label}`);
|
|
244
|
+
}
|
|
245
|
+
for (const match of entry.body.matchAll(/\bpgmq\s*\.\s*\w+\s*\(\s*'((?:[^']|'')+)'/gi)) {
|
|
246
|
+
const queue = match[1].replaceAll("''", "'");
|
|
247
|
+
if (scope.droppedQueues.has(queue))
|
|
248
|
+
lines.push(`${where} uses the dropped pgmq queue ${queue}`);
|
|
249
|
+
}
|
|
243
250
|
}
|
|
244
|
-
|
|
245
|
-
const queue = match[1].replaceAll("''", "'");
|
|
246
|
-
if (scope.droppedQueues.has(queue)) lines.push(`${where} uses the dropped pgmq queue ${queue}`);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
return lines;
|
|
251
|
+
return lines;
|
|
250
252
|
}
|
|
251
|
-
|
|
252
253
|
function roleSql(role, existing) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
254
|
+
const attributes = [role.login ? 'login' : 'nologin', role.inherit ? 'inherit' : 'noinherit', role.createdb ? 'createdb' : 'nocreatedb',
|
|
255
|
+
role.createrole ? 'createrole' : 'nocreaterole', role.bypassrls ? 'bypassrls' : 'nobypassrls', `connection limit ${role.connlimit}`].join(' ');
|
|
256
|
+
return [` if not exists (select 1 from pg_catalog.pg_roles where rolname = ${literal(role.name)}) then create role ${ident(role.name)}; end if;`,
|
|
257
|
+
existing ? null : `alter role ${ident(role.name)} with ${attributes};`];
|
|
257
258
|
}
|
|
258
|
-
|
|
259
259
|
function settingSql(role, entry, refusals) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
260
|
+
const at = entry.indexOf('=');
|
|
261
|
+
const [key, value] = [entry.slice(0, at), entry.slice(at + 1)];
|
|
262
|
+
if (!ROLE_SETTINGS.has(key)) {
|
|
263
|
+
refusals.push(`role ${role} carries the setting ${key}, which a squash does not carry (allowed: ${sorted(ROLE_SETTINGS).join(', ')})`);
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
if (key !== 'search_path')
|
|
267
|
+
return `alter role ${ident(role)} set ${key} = ${literal(value)};`;
|
|
268
|
+
if (!/^[\w$", ]+$/.test(value)) {
|
|
269
|
+
refusals.push(`role ${role} has a search_path the squash cannot restate: ${value}`);
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
return `alter role ${ident(role)} set search_path = ${value};`;
|
|
266
273
|
}
|
|
267
|
-
|
|
268
274
|
/** The bootstrap section: carried roles, their memberships and settings, schema-level grants on bootstrap schemas, database-wide default privileges. */
|
|
269
275
|
function sectionText({ facts, carried, bootstrapRoles, schemaGrants, defaultGrants, refusals }) {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
276
|
+
const roles = facts.roles.filter((role) => carried.has(role.name));
|
|
277
|
+
const create = roles.map((role) => roleSql(role, false));
|
|
278
|
+
const known = new Set([...carried, ...bootstrapRoles]);
|
|
279
|
+
const members = facts.members.filter((item) => known.has(item.role) && known.has(item.member)).map((item) => `grant ${ident(item.role)} to ${ident(item.member)};`);
|
|
280
|
+
const settings = facts.settings.filter((item) => known.has(item.role)).flatMap((item) => item.config.map((entry) => settingSql(item.role, entry, refusals))).filter(Boolean);
|
|
281
|
+
const body = [
|
|
282
|
+
'-- The source\'s app roles (passwords are set out of band), their memberships and role-level settings, the grants on schemas this bootstrap',
|
|
283
|
+
'-- creates, and the database-wide default privileges: a per-database dump keeps none of them.',
|
|
284
|
+
...(create.length ? ['do $starci_squash$', 'begin', ...create.map(([line]) => line), 'end', '$starci_squash$;', ...create.map(([, line]) => line)] : []),
|
|
285
|
+
...members, ...settings, ...schemaGrants, ...defaultGrants,
|
|
286
|
+
];
|
|
287
|
+
return `${BOOTSTRAP_SQUASH_BEGIN}\n${body.join('\n')}\n${BOOTSTRAP_SQUASH_END}\n`;
|
|
282
288
|
}
|
|
283
|
-
|
|
284
289
|
/** Partition one dump: baseline entries, statements for the bootstrap section and the baseline tail, and what was left out and why. */
|
|
285
|
-
function partition(dump,
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
290
|
+
function partition(dump, scope, config) {
|
|
291
|
+
const excludedKeys = new Map(scope.excluded.flatMap((object) => object.keys.map((key) => [key, object])));
|
|
292
|
+
const report = { extensions: [], objects: new Set(), eventTriggers: [], platformSchemas: new Map(), platformStatements: 0, ownerGrants: 0, lostGrants: [], droppedQueues: [], queues: [] };
|
|
293
|
+
const kept = [];
|
|
294
|
+
const bootstrapAcl = [];
|
|
295
|
+
const extensionAcl = [];
|
|
296
|
+
const globalAcl = [];
|
|
297
|
+
for (const entry of dump.entries) {
|
|
298
|
+
const owner = ownerOf(entry);
|
|
299
|
+
if (owner.extension !== undefined) {
|
|
300
|
+
if (config.dropped.includes(owner.extension) || owner.extension === 'plpgsql') {
|
|
301
|
+
if (entry.type === 'EXTENSION')
|
|
302
|
+
report.extensions.push(owner.extension);
|
|
303
|
+
}
|
|
304
|
+
else
|
|
305
|
+
kept.push(entry);
|
|
306
|
+
}
|
|
307
|
+
else if (owner.global)
|
|
308
|
+
globalAcl.push(entry);
|
|
309
|
+
else if (owner.publication !== undefined) {
|
|
310
|
+
// An empty publication (Supabase's supabase_realtime) is platform state: lite realtime is LISTEN/NOTIFY plus Redis.
|
|
311
|
+
const publishes = /\bFOR\s+(?:ALL\s+)?TABLES?\b/i.test(entry.body) || dump.entries.some((other) => other.type.startsWith('PUBLICATION TABLE') && other.name.startsWith(`${entry.name} `));
|
|
312
|
+
if (publishes && !config.bootstrap.publications.has(owner.publication))
|
|
313
|
+
kept.push(entry);
|
|
314
|
+
else if (!publishes)
|
|
315
|
+
report.objects.add(`publication ${owner.publication} (publishes no table)`);
|
|
316
|
+
}
|
|
317
|
+
else if (owner.eventTrigger !== undefined) {
|
|
318
|
+
if (scope.appSchemas.has(owner.eventTrigger))
|
|
319
|
+
kept.push(entry);
|
|
320
|
+
else
|
|
321
|
+
report.eventTriggers.push(unquote(entry.name));
|
|
322
|
+
}
|
|
323
|
+
else if (owner.database || scope.appSchemas.has(owner.schema)) {
|
|
324
|
+
const object = excludedKeys.get(entryKey(entry));
|
|
325
|
+
if (object)
|
|
326
|
+
report.objects.add(`${object.label} (reaches ${sorted(scope.droppedSchemas).join(', ')})`);
|
|
327
|
+
else
|
|
328
|
+
kept.push(entry);
|
|
329
|
+
}
|
|
330
|
+
else if (scope.extensionHomes.has(owner.schema)) {
|
|
331
|
+
if (entry.type === 'SCHEMA')
|
|
332
|
+
kept.push(entry);
|
|
333
|
+
else if (entry.type === 'ACL')
|
|
334
|
+
extensionAcl.push({ entry, schemaLevel: false });
|
|
335
|
+
}
|
|
336
|
+
else if (config.bootstrap.schemas.has(owner.schema) && entry.type === 'ACL')
|
|
337
|
+
bootstrapAcl.push({ entry, schemaLevel: owner.schemaLevel === true });
|
|
338
|
+
else {
|
|
339
|
+
report.platformSchemas.set(owner.schema, (report.platformSchemas.get(owner.schema) ?? 0) + 1);
|
|
340
|
+
// reason: lostGrants holds { line, schema } here and is narrowed to lines in project().
|
|
341
|
+
if (entry.type === 'ACL')
|
|
342
|
+
report.lostGrants.push(...entry.body.split('\n').filter((line) => /^(?:GRANT|REVOKE)\b/.test(line)).map((line) => ({ line, schema: owner.schema })));
|
|
343
|
+
}
|
|
303
344
|
}
|
|
304
|
-
|
|
305
|
-
else if (owner.database || scope.appSchemas.has(owner.schema)) {
|
|
306
|
-
const object = excludedKeys.get(entryKey(entry));
|
|
307
|
-
if (object) report.objects.add(`${object.label} (reaches ${sorted(scope.droppedSchemas).join(', ')})`);
|
|
308
|
-
else kept.push(entry);
|
|
309
|
-
} else if (scope.extensionHomes.has(owner.schema)) {
|
|
310
|
-
if (entry.type === 'SCHEMA') kept.push(entry);
|
|
311
|
-
else if (entry.type === 'ACL') extensionAcl.push({ entry, schemaLevel: false });
|
|
312
|
-
} else if (config.bootstrap.schemas.has(owner.schema) && entry.type === 'ACL') bootstrapAcl.push({ entry, schemaLevel: owner.schemaLevel === true });
|
|
313
|
-
else {
|
|
314
|
-
report.platformSchemas.set(owner.schema, (report.platformSchemas.get(owner.schema) ?? 0) + 1);
|
|
315
|
-
if (entry.type === 'ACL') report.lostGrants.push(...entry.body.split('\n').filter((line) => /^(?:GRANT|REVOKE)\b/.test(line)).map((line) => ({ line, schema: owner.schema })));
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
return { kept, bootstrapAcl, extensionAcl, globalAcl, report };
|
|
345
|
+
return { kept, bootstrapAcl, extensionAcl, globalAcl, report };
|
|
319
346
|
}
|
|
320
|
-
|
|
321
347
|
/** One database projected to the files a squash writes; the same function reads the source and the replay. */
|
|
322
348
|
function project(target, config) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
349
|
+
const facts = queryJson(target, FACTS_SQL);
|
|
350
|
+
const scope = squashScope(facts, config);
|
|
351
|
+
const queues = facts.extensions.some((extension) => extension.name === 'pgmq') && !config.dropped.includes('pgmq') ? queryJson(target, QUEUES_SQL) : [];
|
|
352
|
+
scope.droppedQueues = new Set(queues.filter((queue) => queueDropped(queue.name, config.droppedQueues)).map((queue) => queue.name));
|
|
353
|
+
const keptQueues = queues.filter((queue) => !scope.droppedQueues.has(queue.name));
|
|
354
|
+
const dump = dumpEntries(exec(target, 'pg_dump', ['--schema-only', '--no-owner', '-d', target.url]));
|
|
355
|
+
const parts = partition(dump, scope, config);
|
|
356
|
+
const refusals = danglingReferences(parts.kept, scope);
|
|
357
|
+
const roleNames = new Set(facts.roles.map((role) => role.name));
|
|
358
|
+
const platform = new Set(facts.roles.filter((role) => (role.super && role.name !== facts.user) || PLATFORM_ROLE.test(role.name)).map((role) => role.name));
|
|
359
|
+
const base = new Set([...config.bootstrap.roles, facts.user, 'postgres', 'public', 'PUBLIC']);
|
|
360
|
+
const statementLines = (body) => body.split('\n');
|
|
361
|
+
const naming = (line) => rolesOf(line).filter((role) => roleNames.has(role) && !base.has(role) && !platform.has(role));
|
|
362
|
+
// A statement naming a platform role is the platform's own state and is left out; the rest stays as dumped.
|
|
363
|
+
const keepLine = (line) => { const platformRole = rolesOf(line).some((role) => platform.has(role)); if (platformRole)
|
|
364
|
+
parts.report.platformStatements += 1; return !platformRole; };
|
|
365
|
+
// Every replayed object is owned by the migrating role, so a grant to it, spelled out on a source object a platform role owns, is implied.
|
|
366
|
+
const owners = new Set([facts.user, 'postgres']);
|
|
367
|
+
const ownerGrant = (entry, line) => entry.type === 'ACL' && /^GRANT\b/.test(line) && rolesOf(line).every((role) => owners.has(role));
|
|
368
|
+
const entries = parts.kept.flatMap((entry) => {
|
|
369
|
+
if (!['ACL', 'DEFAULT ACL'].includes(entry.type))
|
|
370
|
+
return [entry];
|
|
371
|
+
const body = statementLines(entry.body).filter((line) => {
|
|
372
|
+
if (!keepLine(line))
|
|
373
|
+
return false;
|
|
374
|
+
if (!ownerGrant(entry, line))
|
|
375
|
+
return true;
|
|
376
|
+
parts.report.ownerGrants += 1;
|
|
377
|
+
return false;
|
|
378
|
+
}).join('\n').trim();
|
|
379
|
+
return body ? [{ ...entry, body }] : [];
|
|
380
|
+
});
|
|
381
|
+
const carried = new Set(entries.flatMap((entry) => naming(entry.body)));
|
|
382
|
+
const aclLines = (items) => items.flatMap((item) => statementLines((item.entry?.body ?? item.body)).filter((line) => /^(?:GRANT|REVOKE|ALTER DEFAULT PRIVILEGES)\b/.test(line) && keepLine(line)).map((line) => ({ line, schemaLevel: item.schemaLevel })));
|
|
383
|
+
const queueTable = new RegExp(`\\bpgmq\\.[aq]_(?:${[...scope.droppedQueues].map(escape).join('|') || '(?!)'})\\b`);
|
|
384
|
+
const outside = [...aclLines(parts.bootstrapAcl), ...aclLines(parts.extensionAcl)].filter((item) => naming(item.line).length && !queueTable.test(item.line));
|
|
385
|
+
for (const item of outside)
|
|
386
|
+
for (const role of naming(item.line))
|
|
387
|
+
carried.add(role);
|
|
388
|
+
const defaultGrants = aclLines(parts.globalAcl).map((item) => item.line);
|
|
389
|
+
for (const line of defaultGrants)
|
|
390
|
+
for (const role of naming(line))
|
|
391
|
+
carried.add(role);
|
|
392
|
+
parts.report.lostGrants = parts.report.lostGrants.filter((lost) => naming(lost.line).length).map((lost) => lost.line);
|
|
393
|
+
for (const role of facts.roles.filter((item) => carried.has(item.name) && (item.super || item.replication)))
|
|
394
|
+
refusals.push(`role ${role.name} is a superuser or replication role; a squash carries no such role`);
|
|
395
|
+
const section = sectionText({ facts, carried, bootstrapRoles: config.bootstrap.roles, schemaGrants: outside.filter((item) => item.schemaLevel).map((item) => item.line), defaultGrants, refusals });
|
|
396
|
+
for (const queue of keptQueues.filter((item) => item.partitioned))
|
|
397
|
+
refusals.push(`pgmq queue ${queue.name} is partitioned; a squash recreates plain and unlogged queues only`);
|
|
398
|
+
const creates = keptQueues.filter((queue) => !queue.partitioned).map((queue) => `SELECT pgmq.${queue.unlogged ? 'create_unlogged' : 'create'}(${literal(queue.name)});`);
|
|
399
|
+
const tail = [...creates, ...outside.filter((item) => !item.schemaLevel).map((item) => item.line)];
|
|
400
|
+
parts.report.droppedQueues = sorted(scope.droppedQueues);
|
|
401
|
+
parts.report.queues = keptQueues.map((queue) => queue.name);
|
|
402
|
+
const seed = config.seedTables.length ? seedText(target, config.seedTables, scope, refusals) : null;
|
|
403
|
+
return { facts, scope, dump, entries, tail, section, seed, carried, report: parts.report, refusals };
|
|
368
404
|
}
|
|
369
|
-
|
|
370
405
|
/* ---- the seed */
|
|
371
|
-
|
|
372
406
|
function seedFactsSql(tables) {
|
|
373
|
-
|
|
374
|
-
|
|
407
|
+
const pairs = tables.map(([schema, table]) => `(${literal(schema)}, ${literal(table)})`).join(', ');
|
|
408
|
+
return `select coalesce(json_agg(json_build_object('schema', n.nspname, 'table', c.relname,
|
|
375
409
|
'unique', exists (select 1 from pg_catalog.pg_index i where i.indrelid = c.oid and i.indisunique and i.indpred is null),
|
|
376
410
|
'references', (select coalesce(jsonb_agg(distinct jsonb_build_array(rn.nspname, rc.relname)), '[]') from pg_catalog.pg_constraint f
|
|
377
411
|
join pg_catalog.pg_class rc on rc.oid = f.confrelid join pg_catalog.pg_namespace rn on rn.oid = rc.relnamespace where f.conrelid = c.oid and f.contype = 'f' and f.confrelid <> c.oid),
|
|
@@ -380,135 +414,164 @@ function seedFactsSql(tables) {
|
|
|
380
414
|
from pg_catalog.pg_class c join pg_catalog.pg_namespace n on n.oid = c.relnamespace
|
|
381
415
|
where c.relkind in ('r', 'p') and (n.nspname, c.relname) in (${pairs})`;
|
|
382
416
|
}
|
|
383
|
-
|
|
384
417
|
/** Seed tables in foreign-key order (a referenced table first), ties by name; a cycle among them is refused. */
|
|
385
418
|
function seedOrder(tables, refusals) {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
419
|
+
const name = (table) => `${table.schema}.${table.table}`;
|
|
420
|
+
const pending = new Map(tables.map((table) => [name(table), table]));
|
|
421
|
+
const order = [];
|
|
422
|
+
while (pending.size) {
|
|
423
|
+
const ready = sorted([...pending.keys()].filter((key) => pending.get(key).references.every(([schema, table]) => !pending.has(`${schema}.${table}`) || `${schema}.${table}` === key)));
|
|
424
|
+
if (!ready.length) {
|
|
425
|
+
refusals.push(`seed tables reference each other in a cycle: ${sorted(pending.keys()).join(', ')}`);
|
|
426
|
+
return order;
|
|
427
|
+
}
|
|
428
|
+
for (const key of ready) {
|
|
429
|
+
order.push(pending.get(key));
|
|
430
|
+
pending.delete(key);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return order;
|
|
395
434
|
}
|
|
396
|
-
|
|
397
435
|
function seedText(target, requested, scope, refusals) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const
|
|
408
|
-
|
|
409
|
-
const
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
436
|
+
const pairs = requested.map((name) => (name.includes('.') ? name.split('.') : ['public', name]));
|
|
437
|
+
const facts = queryJson(target, seedFactsSql(pairs));
|
|
438
|
+
const found = new Set(facts.map((table) => `${table.schema}.${table.table}`));
|
|
439
|
+
for (const [schema, table] of pairs) {
|
|
440
|
+
if (!found.has(`${schema}.${table}`))
|
|
441
|
+
refusals.push(`seed table ${schema}.${table} does not exist in the source`);
|
|
442
|
+
else if (!scope.appSchemas.has(schema))
|
|
443
|
+
refusals.push(`seed table ${schema}.${table} is outside the app schemas (${sorted(scope.appSchemas).join(', ')})`);
|
|
444
|
+
}
|
|
445
|
+
for (const table of facts.filter((item) => !item.unique))
|
|
446
|
+
refusals.push(`seed table ${table.schema}.${table.table} has no primary key or unique constraint, so its rows cannot be seeded idempotently`);
|
|
447
|
+
const blocks = seedOrder(facts, refusals).map((table) => {
|
|
448
|
+
const qualified = `${ident(table.schema)}.${ident(table.table)}`;
|
|
449
|
+
const columns = table.columns.map((column) => ident(column.name)).join(', ');
|
|
450
|
+
const overriding = table.columns.some((column) => column.identity === 'a') ? 'overriding system value ' : '';
|
|
451
|
+
const values = `pg_catalog.concat_ws(', ', ${table.columns.map((column) => `pg_catalog.quote_nullable(${ident(column.name)})`).join(', ')})`;
|
|
452
|
+
const rows = queryJson(target, `select coalesce(json_agg(line order by line collate "C"), '[]') from (select 'insert into ${qualified.replaceAll("'", "''")} (${columns.replaceAll("'", "''")}) ${overriding}values (' || ${values} || ') on conflict do nothing;' as line from ${qualified}) q`);
|
|
453
|
+
const sequences = table.columns.filter((column) => column.sequence).map((column) => `select pg_catalog.setval(pg_catalog.pg_get_serial_sequence(${literal(qualified)}, ${literal(column.name)}), coalesce(max(${ident(column.name)}), 0) + 1, false) from ${qualified};`);
|
|
454
|
+
return { name: `${table.schema}.${table.table}`, count: rows.length, sql: [`-- ${table.schema}.${table.table}: ${rows.length} row(s)`, ...rows, ...sequences].join('\n') };
|
|
455
|
+
});
|
|
456
|
+
return { counts: blocks.map((block) => [block.name, block.count]), text: `${SEED_HEADER} from the reference rows of ${blocks.map((block) => block.name).join(', ')}; rerun the verb to regenerate.\n${blocks.map((block) => `${block.sql}\n`).join('\n')}` };
|
|
416
457
|
}
|
|
417
|
-
|
|
418
458
|
/* ---- rendering, proof and writing */
|
|
419
|
-
|
|
420
459
|
function baselineText(projection, last, urlEnv) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
460
|
+
const header = [`-- starci:baseline ${last}`,
|
|
461
|
+
`-- Generated by starci app db baseline --squash from the database ${urlEnv} names: the schema of ${sorted(projection.scope.appSchemas).join(', ')} with its privileges,`,
|
|
462
|
+
`-- without the extensions ${sorted(projection.report.extensions).join(', ') || '(none)'} and the objects that reach them. Roles and database-wide grants live in ${BOOTSTRAP_FILE}.`];
|
|
463
|
+
const tail = projection.tail.length ? [renderEntry({ name: 'pgmq queues and grants on objects outside the app schemas', type: 'ACL', schema: '-', body: projection.tail.join('\n') })] : [];
|
|
464
|
+
return `${header.join('\n')}\n\n${projection.dump.preamble.join('\n')}\n\n${[...projection.entries.map(renderEntry), ...tail].join('')}`;
|
|
426
465
|
}
|
|
427
|
-
|
|
428
466
|
/** The differences between the source's projection and the replay's, as `-`/`+` lines; none means the replay is the source minus the drops. */
|
|
429
467
|
function projectionDiff(source, replay) {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
468
|
+
const lines = [];
|
|
469
|
+
const keyed = (projection) => new Map(projection.entries.map((entry) => [entryKey(entry), entry.body]));
|
|
470
|
+
const [want, have] = [keyed(source), keyed(replay)];
|
|
471
|
+
for (const [key, body] of want) {
|
|
472
|
+
if (!have.has(key))
|
|
473
|
+
lines.push(`- baseline ${key}`);
|
|
474
|
+
else if (have.get(key) !== body)
|
|
475
|
+
lines.push(`~ baseline ${key}: ${firstDifference(body, have.get(key))}`);
|
|
476
|
+
}
|
|
477
|
+
for (const key of have.keys())
|
|
478
|
+
if (!want.has(key))
|
|
479
|
+
lines.push(`+ baseline ${key}`);
|
|
480
|
+
const compare = (label, left, right) => { if (left !== right)
|
|
481
|
+
lines.push(`~ ${label}: ${firstDifference(left ?? '', right ?? '')}`); };
|
|
482
|
+
compare('baseline tail grants', source.tail.join('\n'), replay.tail.join('\n'));
|
|
483
|
+
compare(BOOTSTRAP_FILE, source.section, replay.section);
|
|
484
|
+
compare(SEED_FILE, source.seed?.text, replay.seed?.text);
|
|
485
|
+
return lines;
|
|
443
486
|
}
|
|
444
|
-
|
|
445
487
|
function firstDifference(left, right) {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
488
|
+
const [want, have] = [left.split('\n'), right.split('\n')];
|
|
489
|
+
const index = want.findIndex((line, at) => line !== have[at]);
|
|
490
|
+
const at = index < 0 ? want.length : index;
|
|
491
|
+
return `line ${at + 1} source ${JSON.stringify(want[at] ?? '(end)')}, replay ${JSON.stringify(have[at] ?? '(end)')}`;
|
|
450
492
|
}
|
|
451
|
-
|
|
452
493
|
function replay(scratch, files) {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
494
|
+
const admin = scratchTarget(scratch, 'postgres');
|
|
495
|
+
exec(admin, 'psql', [...psqlArgs(admin), '-c', `create database ${REPLAY_DB}`]);
|
|
496
|
+
const target = scratchTarget(scratch, REPLAY_DB);
|
|
497
|
+
for (const [label, text] of files) {
|
|
498
|
+
try {
|
|
499
|
+
exec(target, 'psql', [...psqlArgs(target), '-1', '-f', '-'], { input: text });
|
|
500
|
+
}
|
|
501
|
+
catch (error) {
|
|
502
|
+
throw new DbVerbError(`the replay of ${label} failed on ${scratch.image}: ${error.message}`);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return target;
|
|
461
506
|
}
|
|
462
|
-
|
|
463
507
|
function printReport(stdout, projection, config, files) {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
508
|
+
const { report } = projection;
|
|
509
|
+
stdout(`app schemas: ${sorted(projection.scope.appSchemas).join(', ')}\n`);
|
|
510
|
+
stdout(`dropped extensions: ${config.dropped.map((name) => (report.extensions.includes(name) ? name : `${name} (not installed)`)).join(', ')}\n`);
|
|
511
|
+
for (const label of sorted(report.objects))
|
|
512
|
+
stdout(`excluded ${label}\n`);
|
|
513
|
+
if (report.queues.length)
|
|
514
|
+
stdout(`pgmq queues kept: ${report.queues.join(', ')}\n`);
|
|
515
|
+
for (const name of report.droppedQueues)
|
|
516
|
+
stdout(`dropped pgmq queue ${name}\n`);
|
|
517
|
+
for (const name of sorted(report.eventTriggers))
|
|
518
|
+
stdout(`excluded event trigger ${name} (its function is outside the app schemas)\n`);
|
|
519
|
+
for (const [schema, count] of sorted(report.platformSchemas.keys()).map((key) => [key, report.platformSchemas.get(key)]))
|
|
520
|
+
stdout(`left out ${count} entr${count === 1 ? 'y' : 'ies'} of schema ${schema} (not the app's)\n`);
|
|
521
|
+
if (report.platformStatements)
|
|
522
|
+
stdout(`left out ${report.platformStatements} grant statement(s) naming platform roles\n`);
|
|
523
|
+
if (report.ownerGrants)
|
|
524
|
+
stdout(`left out ${report.ownerGrants} grant statement(s) to the migrating role, which owns every replayed object\n`);
|
|
525
|
+
for (const line of report.lostGrants)
|
|
526
|
+
stdout(`left out a grant to a carried role on a schema the target lacks: ${line}\n`);
|
|
527
|
+
stdout(`bootstrap section: roles ${sorted(projection.carried).join(', ') || '(none)'}; ${projection.section.split('\n').length - 2} line(s)\n`);
|
|
528
|
+
for (const [name, count] of projection.seed?.counts ?? [])
|
|
529
|
+
stdout(`seed ${name}: ${count} row(s)\n`);
|
|
530
|
+
for (const [file, text] of files)
|
|
531
|
+
stdout(`${file}: ${text.split('\n').length} line(s)\n`);
|
|
478
532
|
}
|
|
479
|
-
|
|
480
533
|
/**
|
|
481
|
-
* `starci app db baseline --squash`: plan is db-baseline-verb.mjs's baselinePlan, connection the source of --url-env, precondition the
|
|
534
|
+
* `starci app db baseline --squash`: plan is db-baseline-verb.mjs's baselinePlan, connection the source of --db-url-env, precondition the
|
|
482
535
|
* history check (the source holds exactly the active chain) run through the given runPostgres port, throwing its refusal, and archive
|
|
483
|
-
* the move of the active chain. Dry run by default; `
|
|
536
|
+
* the move of the active chain. Dry run by default; `execute` writes the baseline, the bootstrap section and the seed, then archives.
|
|
484
537
|
*/
|
|
485
538
|
export function squashBaseline({ root, opts, plan, urlEnv, connection, commandOf, precondition, managedSchema, archive, stdout }) {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
539
|
+
if (!opts.image && !fs.existsSync(path.join(root, DB_DOCKERFILE)))
|
|
540
|
+
throw new DbVerbError(`baseline --squash replays on the app's db image: ${DB_DOCKERFILE} is missing (run "npx starci app sync --execute") and no --image names one`);
|
|
541
|
+
const bootstrapPath = path.join(root, BOOTSTRAP_FILE);
|
|
542
|
+
if (!fs.existsSync(bootstrapPath))
|
|
543
|
+
throw new DbVerbError(`baseline --squash needs ${BOOTSTRAP_FILE}; run "npx starci app sync --execute" first`);
|
|
544
|
+
const head = bootstrapSection(fs.readFileSync(bootstrapPath, 'utf8').replace(/\r\n/g, '\n')).head;
|
|
545
|
+
const seedPath = path.join(root, SEED_FILE);
|
|
546
|
+
const seedTables = flagList(opts['seed-tables'], []);
|
|
547
|
+
if (seedTables.length && fs.existsSync(seedPath) && !fs.readFileSync(seedPath, 'utf8').startsWith(SEED_HEADER))
|
|
548
|
+
throw new DbVerbError(`${SEED_FILE} exists and was not generated by the squash; fold its rows into the source and remove it, or omit --seed-tables`);
|
|
549
|
+
const config = { dropped: flagList(opts['drop-extension'], DEFAULT_DROPPED_EXTENSIONS), droppedQueues: flagList(opts['drop-pgmq-queue'], []), seedTables, bootstrap: bootstrapDeclares(head), managedSchema };
|
|
550
|
+
const image = opts.image ?? buildImage(root);
|
|
551
|
+
const scratch = startScratch(image);
|
|
552
|
+
try {
|
|
553
|
+
const source = sourceTarget(scratch, connection, `the database ${urlEnv} names`);
|
|
554
|
+
precondition(targetRunner(source, commandOf));
|
|
555
|
+
const projected = project(source, config);
|
|
556
|
+
if (projected.refusals.length)
|
|
557
|
+
throw new DbVerbError(`baseline --squash cannot carry the source:\n${[...new Set(projected.refusals)].map((line) => ` ${line}`).join('\n')}`);
|
|
558
|
+
const files = [[BOOTSTRAP_FILE, `${head}${projected.section}`], [plan.file, baselineText(projected, plan.last, urlEnv)], ...(projected.seed ? [[SEED_FILE, projected.seed.text]] : [])];
|
|
559
|
+
const replayTarget = replay(scratch, [...files, ...(projected.seed ? [[`${SEED_FILE} (second run)`, projected.seed.text]] : [])]);
|
|
560
|
+
const replayed = project(replayTarget, config);
|
|
561
|
+
const diff = projectionDiff(projected, replayed);
|
|
562
|
+
stdout(`${opts.execute ? 'apply' : 'preview'} squash baseline ${plan.file}; archive ${plan.active.length} migrations; the source is read only\n`);
|
|
563
|
+
printReport(stdout, projected, config, files);
|
|
564
|
+
if (diff.length)
|
|
565
|
+
throw new DbVerbError(`the replay on ${image} differs from the source minus the dropped extensions:\n${diff.slice(0, DIFF_LIMIT).map((line) => ` ${line}`).join('\n')}${diff.length > DIFF_LIMIT ? `\n ... ${diff.length - DIFF_LIMIT} more` : ''}`);
|
|
566
|
+
stdout(`proof: bootstrap + baseline + seed (twice) replayed on ${image}; schema, grants, roles and seed rows equal the source minus ${config.dropped.join(', ')}\n`);
|
|
567
|
+
if (!opts.execute)
|
|
568
|
+
return 0;
|
|
569
|
+
for (const [file, text] of files)
|
|
570
|
+
fs.writeFileSync(path.join(root, file), text, { flag: file === plan.file ? 'wx' : 'w' });
|
|
571
|
+
archive();
|
|
572
|
+
return 0;
|
|
573
|
+
}
|
|
574
|
+
finally {
|
|
575
|
+
scratch.stop();
|
|
576
|
+
}
|
|
514
577
|
}
|