@intentius/chant 0.57.0 → 0.59.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/dist/audit/catalog.d.ts +51 -1
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/core.d.ts +36 -1
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts +26 -9
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/lineage.d.ts +10 -0
- package/dist/audit/lineage.d.ts.map +1 -0
- package/dist/audit/prior-art.d.ts +385 -0
- package/dist/audit/prior-art.d.ts.map +1 -0
- package/dist/audit/proof.d.ts +16 -0
- package/dist/audit/proof.d.ts.map +1 -1
- package/dist/audit/report-html.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +8 -1
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts +3 -0
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/audit/secrets.d.ts +15 -0
- package/dist/audit/secrets.d.ts.map +1 -1
- package/dist/audit/terraform-state.d.ts +46 -0
- package/dist/audit/terraform-state.d.ts.map +1 -0
- package/dist/build.d.ts +17 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/claimed-fields.d.ts +161 -0
- package/dist/claimed-fields.d.ts.map +1 -0
- package/dist/cli/build-params-cli.d.ts +2 -2
- package/dist/cli/command-group.d.ts +14 -0
- package/dist/cli/command-group.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts +17 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/carve-bridge.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-docs.d.ts +1 -1
- package/dist/cli/commands/check-lexicon-examples.d.ts +16 -6
- package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts +1 -0
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/project.d.ts +7 -0
- package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/lint.d.ts +13 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +2 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +82 -16
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts +49 -42
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts +12 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts +16 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
- package/dist/cli/mcp/resources/context.d.ts.map +1 -1
- package/dist/cli/plugins.d.ts +22 -0
- package/dist/cli/plugins.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +40 -9
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
- package/dist/components/auto-release.d.ts +10 -20
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/capability.d.ts +4 -4
- package/dist/components/cli-support.d.ts +24 -22
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +21 -6
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/driver-output.d.ts.map +1 -1
- package/dist/components/driver.d.ts +73 -37
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/manifest-persistence.d.ts +1 -9
- package/dist/components/manifest-persistence.d.ts.map +1 -1
- package/dist/components/run-progress.d.ts +6 -6
- package/dist/components/run-progress.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts +10 -22
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts +2 -2
- package/dist/deep-observation.d.ts +17 -0
- package/dist/deep-observation.d.ts.map +1 -1
- package/dist/detectLexicon.d.ts +13 -0
- package/dist/detectLexicon.d.ts.map +1 -1
- package/dist/discovery/files.d.ts +4 -4
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +33 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
- package/dist/discovery/sandbox/config-wire.d.ts +2 -2
- package/dist/fold/foldable-helpers.d.ts +5 -1
- package/dist/fold/foldable-helpers.d.ts.map +1 -1
- package/dist/fold-provenance.d.ts +236 -0
- package/dist/fold-provenance.d.ts.map +1 -0
- package/dist/graph-ops.d.ts +1 -1
- package/dist/held-elsewhere.d.ts +85 -0
- package/dist/held-elsewhere.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts +3 -3
- package/dist/lexicon-config.d.ts +4 -4
- package/dist/lexicon-plugin-helpers.d.ts +1 -1
- package/dist/lexicon.d.ts +273 -16
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/change-set.d.ts +13 -0
- package/dist/lifecycle/change-set.d.ts.map +1 -1
- package/dist/lifecycle/deep-diff.d.ts +133 -6
- package/dist/lifecycle/deep-diff.d.ts.map +1 -1
- package/dist/lifecycle/deep-observe.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +79 -3
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts +2 -2
- package/dist/lifecycle/run-ledger.d.ts +53 -0
- package/dist/lifecycle/run-ledger.d.ts.map +1 -0
- package/dist/lifecycle/symptoms.d.ts +3 -3
- package/dist/lifecycle/symptoms.d.ts.map +1 -1
- package/dist/lint/config.d.ts +81 -2
- package/dist/lint/config.d.ts.map +1 -1
- package/dist/lint/post-synth.d.ts +55 -2
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
- package/dist/lint/rules/comp/index.d.ts +1 -1
- package/dist/lint/rules/comp/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.d.ts +16 -0
- package/dist/lint/rules/op/index.d.ts.map +1 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
- package/dist/lint/rules/op/support.d.ts +12 -0
- package/dist/lint/rules/op/support.d.ts.map +1 -0
- package/dist/lint/suppressions.d.ts +108 -0
- package/dist/lint/suppressions.d.ts.map +1 -0
- package/dist/live-endpoint.d.ts +1 -1
- package/dist/op/activities/activity-contracts.d.ts +54 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -0
- package/dist/op/activities/apply.d.ts +262 -0
- package/dist/op/activities/apply.d.ts.map +1 -0
- package/dist/op/activities/build.d.ts +13 -0
- package/dist/op/activities/build.d.ts.map +1 -0
- package/dist/op/activities/converge.d.ts +110 -0
- package/dist/op/activities/converge.d.ts.map +1 -0
- package/dist/op/activities/env-teardown.d.ts +76 -0
- package/dist/op/activities/env-teardown.d.ts.map +1 -0
- package/dist/op/activities/guard-validate.d.ts +64 -0
- package/dist/op/activities/guard-validate.d.ts.map +1 -0
- package/dist/op/activities/http-check.d.ts +34 -0
- package/dist/op/activities/http-check.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +31 -0
- package/dist/op/activities/index.d.ts.map +1 -0
- package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
- package/dist/op/activities/lifecycle.d.ts +42 -0
- package/dist/op/activities/lifecycle.d.ts.map +1 -0
- package/dist/op/activities/pipeline-audit.d.ts +84 -0
- package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
- package/dist/op/activities/policy.d.ts +17 -0
- package/dist/op/activities/policy.d.ts.map +1 -0
- package/dist/op/activities/reconcile.d.ts +149 -0
- package/dist/op/activities/reconcile.d.ts.map +1 -0
- package/dist/op/activities/shell.d.ts +13 -0
- package/dist/op/activities/shell.d.ts.map +1 -0
- package/dist/op/activities/teardown.d.ts +10 -0
- package/dist/op/activities/teardown.d.ts.map +1 -0
- package/dist/op/activities/util.d.ts +7 -0
- package/dist/op/activities/util.d.ts.map +1 -0
- package/dist/op/activities/wait.d.ts +28 -0
- package/dist/op/activities/wait.d.ts.map +1 -0
- package/dist/op/activities/workflow-audit.d.ts +92 -0
- package/dist/op/activities/workflow-audit.d.ts.map +1 -0
- package/dist/op/activity-contract-registry.d.ts +76 -0
- package/dist/op/activity-contract-registry.d.ts.map +1 -0
- package/dist/op/activity-contract.d.ts +25 -18
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-failure.d.ts +28 -0
- package/dist/op/activity-failure.d.ts.map +1 -0
- package/dist/op/activity-profiles.d.ts +118 -0
- package/dist/op/activity-profiles.d.ts.map +1 -0
- package/dist/op/activity-registry.d.ts +22 -38
- package/dist/op/activity-registry.d.ts.map +1 -1
- package/dist/op/activity-runtime.d.ts +3 -14
- package/dist/op/activity-runtime.d.ts.map +1 -1
- package/dist/op/builders.d.ts +85 -30
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/change-signal.d.ts +91 -0
- package/dist/op/change-signal.d.ts.map +1 -0
- package/dist/op/composites/apply-op.d.ts +118 -0
- package/dist/op/composites/apply-op.d.ts.map +1 -0
- package/dist/op/composites/converge-op.d.ts +120 -0
- package/dist/op/composites/converge-op.d.ts.map +1 -0
- package/dist/op/composites/index.d.ts +26 -0
- package/dist/op/composites/index.d.ts.map +1 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
- package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
- package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
- package/dist/op/composites/reconcile-op.d.ts +57 -0
- package/dist/op/composites/reconcile-op.d.ts.map +1 -0
- package/dist/op/composites/watch-op.d.ts +60 -0
- package/dist/op/composites/watch-op.d.ts.map +1 -0
- package/dist/op/composites/workflow-audit-op.d.ts +57 -0
- package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
- package/dist/op/converge-rule.d.ts +12 -10
- package/dist/op/converge-rule.d.ts.map +1 -1
- package/dist/op/cron.d.ts +51 -0
- package/dist/op/cron.d.ts.map +1 -0
- package/dist/op/discover.d.ts +9 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/duration.d.ts +11 -0
- package/dist/op/duration.d.ts.map +1 -0
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/gate-name.d.ts +40 -0
- package/dist/op/gate-name.d.ts.map +1 -0
- package/dist/op/gate-summary.d.ts +43 -0
- package/dist/op/gate-summary.d.ts.map +1 -0
- package/dist/op/gate.d.ts +90 -0
- package/dist/op/gate.d.ts.map +1 -0
- package/dist/op/generate-pipeline.d.ts +9 -0
- package/dist/op/generate-pipeline.d.ts.map +1 -1
- package/dist/op/index.d.ts +29 -9
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +114 -28
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-output.d.ts +11 -1
- package/dist/op/local-output.d.ts.map +1 -1
- package/dist/op/op-ir.d.ts +185 -0
- package/dist/op/op-ir.d.ts.map +1 -0
- package/dist/op/op-verb-class.d.ts +10 -2
- package/dist/op/op-verb-class.d.ts.map +1 -1
- package/dist/op/operator.d.ts +93 -5
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/receipt-store.d.ts +1 -1
- package/dist/op/receipt-store.d.ts.map +1 -1
- package/dist/op/resource.d.ts +15 -1
- package/dist/op/resource.d.ts.map +1 -1
- package/dist/op/runtime.d.ts +200 -0
- package/dist/op/runtime.d.ts.map +1 -0
- package/dist/op/runtimes/local.d.ts +29 -0
- package/dist/op/runtimes/local.d.ts.map +1 -0
- package/dist/op/step-output-ref.d.ts +15 -13
- package/dist/op/step-output-ref.d.ts.map +1 -1
- package/dist/op/types.d.ts +96 -29
- package/dist/op/types.d.ts.map +1 -1
- package/dist/ownership.d.ts +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/serializer-walker.d.ts.map +1 -1
- package/dist/terraform/bridge.d.ts +26 -7
- package/dist/terraform/bridge.d.ts.map +1 -1
- package/dist/terraform/carve-provider.d.ts +28 -2
- package/dist/terraform/carve-provider.d.ts.map +1 -1
- package/dist/terraform/data-source-shape.d.ts +77 -0
- package/dist/terraform/data-source-shape.d.ts.map +1 -0
- package/dist/terraform/graph.d.ts.map +1 -1
- package/dist/terraform/providers/kubernetes.d.ts +5 -0
- package/dist/terraform/providers/kubernetes.d.ts.map +1 -1
- package/dist/terraform/tier-map.d.ts +16 -4
- package/dist/terraform/tier-map.d.ts.map +1 -1
- package/dist/terraform/types.d.ts +8 -0
- package/dist/terraform/types.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/audit/catalog.test.ts +79 -3
- package/src/audit/catalog.ts +111 -13
- package/src/audit/core.test.ts +26 -0
- package/src/audit/core.ts +84 -18
- package/src/audit/discover.test.ts +39 -0
- package/src/audit/discover.ts +202 -18
- package/src/audit/lineage.ts +100 -0
- package/src/audit/prior-art.ts +153 -0
- package/src/audit/proof.test.ts +67 -0
- package/src/audit/proof.ts +70 -0
- package/src/audit/report-html.ts +9 -4
- package/src/audit/report-model.ts +16 -2
- package/src/audit/report.test.ts +33 -0
- package/src/audit/report.ts +5 -3
- package/src/audit/rules-doc.test.ts +34 -2
- package/src/audit/rules-doc.ts +82 -9
- package/src/audit/secrets.ts +15 -3
- package/src/audit/terraform-state.test.ts +144 -0
- package/src/audit/terraform-state.ts +131 -0
- package/src/build.ts +31 -1
- package/src/claimed-fields.test.ts +145 -0
- package/src/claimed-fields.ts +208 -0
- package/src/cli/build-params-cli.ts +2 -2
- package/src/cli/command-group.ts +14 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
- package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
- package/src/cli/commands/audit.test.ts +191 -11
- package/src/cli/commands/audit.ts +78 -28
- package/src/cli/commands/build.test.ts +330 -9
- package/src/cli/commands/build.ts +170 -24
- package/src/cli/commands/carve-bridge.test.ts +237 -14
- package/src/cli/commands/carve-bridge.ts +21 -17
- package/src/cli/commands/carve-emit-k8s.test.ts +17 -10
- package/src/cli/commands/check-lexicon-docs.ts +1 -1
- package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
- package/src/cli/commands/check-lexicon-examples.ts +42 -10
- package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
- package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
- package/src/cli/commands/init-lexicon.test.ts +97 -2
- package/src/cli/commands/init-lexicon.ts +4 -2
- package/src/cli/commands/init.test.ts +35 -1
- package/src/cli/commands/init.ts +14 -3
- package/src/cli/commands/lint.test.ts +194 -1
- package/src/cli/commands/lint.ts +205 -7
- package/src/cli/commands/onboard.test.ts +75 -0
- package/src/cli/commands/onboard.ts +54 -23
- package/src/cli/handlers/build.test.ts +81 -1
- package/src/cli/handlers/build.ts +15 -1
- package/src/cli/handlers/graph.test.ts +3 -3
- package/src/cli/handlers/lifecycle.test.ts +195 -12
- package/src/cli/handlers/lifecycle.ts +123 -6
- package/src/cli/handlers/misc.ts +1 -1
- package/src/cli/handlers/operator.test.ts +183 -11
- package/src/cli/handlers/operator.ts +341 -55
- package/src/cli/handlers/run.test.ts +568 -1295
- package/src/cli/handlers/run.ts +446 -912
- package/src/cli/main.test.ts +22 -16
- package/src/cli/main.ts +66 -33
- package/src/cli/mcp/op-tools.ts +147 -88
- package/src/cli/mcp/resource-handlers.ts +10 -37
- package/src/cli/mcp/resources/context.ts +11 -12
- package/src/cli/mcp/server.test.ts +25 -27
- package/src/cli/mcp/server.ts +2 -2
- package/src/cli/plugins.test.ts +68 -2
- package/src/cli/plugins.ts +39 -0
- package/src/cli/registry.ts +40 -9
- package/src/codegen/docs.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.ts +1 -1
- package/src/components/README.md +4 -3
- package/src/components/__fixtures__/neo4j-fanout.json +1 -1
- package/src/components/auto-release.test.ts +4 -20
- package/src/components/auto-release.ts +17 -42
- package/src/components/capability.ts +4 -4
- package/src/components/cli-support.test.ts +28 -12
- package/src/components/cli-support.ts +60 -47
- package/src/components/component-schema.test.ts +18 -2
- package/src/components/component.schema.json +18 -5
- package/src/components/component.test.ts +2 -2
- package/src/components/component.ts +27 -7
- package/src/components/config-defaults.test.ts +2 -2
- package/src/components/driver-output.ts +14 -2
- package/src/components/driver.test.ts +109 -20
- package/src/components/driver.ts +201 -84
- package/src/components/index.ts +1 -6
- package/src/components/manifest-persistence.test.ts +2 -20
- package/src/components/manifest-persistence.ts +4 -24
- package/src/components/pilots/neo4j-fanout.pilot.ts +3 -3
- package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
- package/src/components/run-progress.ts +6 -6
- package/src/components/verbs/run-agent.test.ts +19 -0
- package/src/components/verbs/run-agent.ts +12 -24
- package/src/components/verbs/verify.ts +2 -2
- package/src/deep-observation.test.ts +75 -0
- package/src/deep-observation.ts +48 -0
- package/src/detectLexicon.ts +18 -1
- package/src/discovery/collect.test.ts +3 -3
- package/src/discovery/files.ts +4 -4
- package/src/discovery/fold-import.test.ts +1 -1
- package/src/discovery/fold-import.ts +105 -2
- package/src/discovery/param-deps.test.ts +112 -1
- package/src/discovery/param-deps.ts +193 -0
- package/src/discovery/sandbox/bundle.ts +15 -1
- package/src/discovery/sandbox/config-wire.test.ts +2 -2
- package/src/discovery/sandbox/config-wire.ts +2 -2
- package/src/fold/fold.test.ts +56 -0
- package/src/fold/foldable-helpers.ts +82 -2
- package/src/fold-provenance-exclusion.test.ts +186 -0
- package/src/fold-provenance.test.ts +495 -0
- package/src/fold-provenance.ts +441 -0
- package/src/graph-ops.test.ts +3 -3
- package/src/graph-ops.ts +1 -1
- package/src/held-elsewhere.test.ts +102 -0
- package/src/held-elsewhere.ts +114 -0
- package/src/index.ts +3 -0
- package/src/kubectl-context.ts +3 -3
- package/src/lexicon-config.test.ts +5 -5
- package/src/lexicon-config.ts +4 -4
- package/src/lexicon-plugin-helpers.ts +1 -1
- package/src/lexicon.ts +296 -16
- package/src/lifecycle/change-set.test.ts +49 -0
- package/src/lifecycle/change-set.ts +67 -0
- package/src/lifecycle/converge-ledger.ts +1 -1
- package/src/lifecycle/deep-diff.test.ts +267 -14
- package/src/lifecycle/deep-diff.ts +217 -14
- package/src/lifecycle/deep-observe.test.ts +3 -1
- package/src/lifecycle/deep-observe.ts +16 -6
- package/src/lifecycle/gate-ledger.test.ts +74 -2
- package/src/lifecycle/gate-ledger.ts +154 -36
- package/src/lifecycle/index.ts +1 -0
- package/src/lifecycle/release-ledger.ts +2 -2
- package/src/lifecycle/run-ledger.test.ts +268 -0
- package/src/lifecycle/run-ledger.ts +201 -0
- package/src/lifecycle/symptoms.ts +3 -3
- package/src/lint/config.test.ts +82 -1
- package/src/lint/config.ts +112 -3
- package/src/lint/pipeline-change-gate.test.ts +2 -2
- package/src/lint/policy.test.ts +1 -1
- package/src/lint/post-synth.test.ts +31 -0
- package/src/lint/post-synth.ts +54 -1
- package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
- package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
- package/src/lint/rules/comp/comp.test.ts +27 -1
- package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +76 -0
- package/src/lint/rules/comp/index.ts +3 -3
- package/src/lint/rules/op/index.ts +23 -0
- package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
- package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
- package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
- package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
- package/src/lint/rules/op/support.ts +11 -0
- package/src/lint/suppressions.test.ts +163 -0
- package/src/lint/suppressions.ts +204 -0
- package/src/live-endpoint.ts +1 -1
- package/src/op/activities/activity-contracts.ts +66 -0
- package/src/op/activities/apply.test.ts +567 -0
- package/src/op/activities/apply.ts +662 -0
- package/src/op/activities/build.ts +26 -0
- package/src/op/activities/converge.test.ts +330 -0
- package/src/op/activities/converge.ts +449 -0
- package/src/op/activities/env-teardown.test.ts +187 -0
- package/src/op/activities/env-teardown.ts +171 -0
- package/src/op/activities/guard-validate.test.ts +139 -0
- package/src/op/activities/guard-validate.ts +223 -0
- package/src/op/activities/http-check.test.ts +48 -0
- package/src/op/activities/http-check.ts +55 -0
- package/src/op/activities/index.ts +119 -0
- package/src/op/activities/lexicon-upgrade.test.ts +492 -0
- package/src/op/activities/lexicon-upgrade.ts +673 -0
- package/src/op/activities/lifecycle.ts +85 -0
- package/src/op/activities/pipeline-audit.test.ts +67 -0
- package/src/op/activities/pipeline-audit.ts +201 -0
- package/src/op/activities/policy.test.ts +19 -0
- package/src/op/activities/policy.ts +37 -0
- package/src/op/activities/reconcile.test.ts +161 -0
- package/src/op/activities/reconcile.ts +354 -0
- package/src/op/activities/shell.ts +26 -0
- package/src/op/activities/teardown.ts +22 -0
- package/src/op/activities/util.ts +6 -0
- package/src/op/activities/wait.ts +69 -0
- package/src/op/activities/workflow-audit.test.ts +90 -0
- package/src/op/activities/workflow-audit.ts +203 -0
- package/src/op/activity-contract-registry.test.ts +98 -0
- package/src/op/activity-contract-registry.ts +114 -0
- package/src/op/activity-contract.test.ts +1 -1
- package/src/op/activity-contract.ts +37 -33
- package/src/op/activity-failure.ts +34 -0
- package/src/op/activity-profiles.test.ts +56 -0
- package/src/op/activity-profiles.ts +116 -0
- package/src/op/activity-registry.test.ts +37 -28
- package/src/op/activity-registry.ts +27 -56
- package/src/op/activity-runtime.ts +3 -47
- package/src/op/builders-exports.test.ts +0 -49
- package/src/op/builders-typed.test.ts +164 -0
- package/src/op/builders.ts +125 -41
- package/src/op/change-signal.test.ts +117 -0
- package/src/op/change-signal.ts +169 -0
- package/src/op/composites/apply-op.ts +218 -0
- package/src/op/composites/composites.test.ts +379 -0
- package/src/op/composites/converge-op.test.ts +168 -0
- package/src/op/composites/converge-op.ts +214 -0
- package/src/op/composites/index.ts +26 -0
- package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
- package/src/op/composites/lexicon-upgrade-op.ts +134 -0
- package/src/op/composites/pipeline-audit-op.test.ts +25 -0
- package/src/op/composites/pipeline-audit-op.ts +78 -0
- package/src/op/composites/reconcile-op.test.ts +51 -0
- package/src/op/composites/reconcile-op.ts +110 -0
- package/src/op/composites/watch-op.ts +108 -0
- package/src/op/composites/workflow-audit-op.test.ts +25 -0
- package/src/op/composites/workflow-audit-op.ts +88 -0
- package/src/op/converge-rule.ts +12 -10
- package/src/op/cron.test.ts +128 -0
- package/src/op/cron.ts +149 -0
- package/src/op/discover-root.test.ts +105 -1
- package/src/op/discover.test.ts +6 -2
- package/src/op/discover.ts +84 -16
- package/src/op/duration.ts +21 -0
- package/src/op/effect-step.test.ts +29 -14
- package/src/op/emulator-lifecycle.ts +1 -2
- package/src/op/gate-name.test.ts +65 -0
- package/src/op/gate-name.ts +60 -0
- package/src/op/gate-summary.ts +84 -0
- package/src/op/gate.ts +155 -0
- package/src/op/generate-pipeline.test.ts +65 -3
- package/src/op/generate-pipeline.ts +19 -2
- package/src/op/index.ts +48 -8
- package/src/op/local-executor.test.ts +178 -34
- package/src/op/local-executor.ts +371 -102
- package/src/op/local-output.test.ts +95 -11
- package/src/op/local-output.ts +33 -4
- package/src/op/op-ir.test.ts +292 -0
- package/src/op/op-ir.ts +419 -0
- package/src/op/op-verb-class.test.ts +2 -2
- package/src/op/op-verb-class.ts +19 -5
- package/src/op/op.test.ts +28 -7
- package/src/op/operator.test.ts +543 -6
- package/src/op/operator.ts +203 -20
- package/src/op/receipt-store.ts +1 -1
- package/src/op/resource.ts +20 -2
- package/src/op/runtime.ts +203 -0
- package/src/op/runtimes/local.test.ts +181 -0
- package/src/op/runtimes/local.ts +212 -0
- package/src/op/step-output-ref.ts +15 -13
- package/src/op/types.ts +106 -26
- package/src/ownership.ts +1 -1
- package/src/provenance.test.ts +6 -0
- package/src/provenance.ts +21 -1
- package/src/serializer-walker.test.ts +42 -0
- package/src/serializer-walker.ts +21 -2
- package/src/terraform/aws-resources.test.ts +13 -4
- package/src/terraform/bridge.test.ts +22 -9
- package/src/terraform/bridge.ts +89 -28
- package/src/terraform/carve-provider.ts +38 -2
- package/src/terraform/data-source-shape.ts +95 -0
- package/src/terraform/graph.ts +35 -7
- package/src/terraform/providers/kubernetes.ts +48 -2
- package/src/terraform/tier-map.ts +21 -6
- package/src/terraform/types.ts +8 -0
- package/dist/cli/handlers/op-progress.d.ts +0 -90
- package/dist/cli/handlers/op-progress.d.ts.map +0 -1
- package/dist/cli/handlers/run-client.d.ts +0 -127
- package/dist/cli/handlers/run-client.d.ts.map +0 -1
- package/dist/cli/handlers/run-report.d.ts +0 -5
- package/dist/cli/handlers/run-report.d.ts.map +0 -1
- package/dist/components/temporal-codegen-loader.d.ts +0 -27
- package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
- package/src/cli/handlers/op-progress.test.ts +0 -268
- package/src/cli/handlers/op-progress.ts +0 -248
- package/src/cli/handlers/run-client.test.ts +0 -82
- package/src/cli/handlers/run-client.ts +0 -219
- package/src/cli/handlers/run-report.test.ts +0 -62
- package/src/cli/handlers/run-report.ts +0 -122
- package/src/components/temporal-codegen-loader.ts +0 -41
- package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
|
@@ -0,0 +1,662 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nativeApply` — push declared source to the cloud through the target's own
|
|
3
|
+
* mechanism. Authority stays with the platform; chant hosts no state file.
|
|
4
|
+
*
|
|
5
|
+
* ## Where the shell went (chant #1075, #1448, #1449)
|
|
6
|
+
*
|
|
7
|
+
* This used to build a shell command for every target — `kubectl apply -f`,
|
|
8
|
+
* `az deployment group create`, `aws cloudformation deploy`. Two things were
|
|
9
|
+
* wrong with that. The shell commands carried product knowledge that belongs to
|
|
10
|
+
* each product's lexicon, against the one-lexicon-per-product rule that already
|
|
11
|
+
* moved `kubectlApply`, `k3dUp`/`k3dDown` and `waitForArgoSync` out (chant
|
|
12
|
+
* #809). And each CLI's semantics diverged from what the docblocks promised —
|
|
13
|
+
* `kubectl apply`'s client-side merge gave the diff engine nothing to key on
|
|
14
|
+
* (#1075), and ARM Complete mode deleted resources chant never applied (#1448).
|
|
15
|
+
*
|
|
16
|
+
* So each branch moved to its product's lexicon: `kubectl`/`kustomize` are a
|
|
17
|
+
* server-side apply over the k8s lexicon's typed client (#1075, #1548), `arm`
|
|
18
|
+
* is the azure lexicon's per-resource `azApply` (#1448), `cloudformation`
|
|
19
|
+
* is the aws lexicon's `awsApply` — the CloudFormation Query API directly, no
|
|
20
|
+
* CLI in the path (#1449) — and `gcp`/`fly` are the gcp lexicon's
|
|
21
|
+
* per-resource `gcpApply` and the fly lexicon's `flyApply`, which never had a
|
|
22
|
+
* CLI in the path to begin with: gcp maps each CNRM kind to its REST API
|
|
23
|
+
* itself, and fly speaks the Machines API (flaps) directly, no flyctl.
|
|
24
|
+
* **The dispatcher stayed here**, because "which
|
|
25
|
+
* mechanism applies this target" is not any one product's knowledge — and
|
|
26
|
+
* because the activity keeps its name, its arguments and its place in
|
|
27
|
+
* `ApplyOp`, so no existing Op changes shape.
|
|
28
|
+
*
|
|
29
|
+
* The lexicons are reached by dynamic import at call time, never by a static
|
|
30
|
+
* one: this package must not depend on them. A project applying a target
|
|
31
|
+
* already lists that lexicon in its config, so the module is there; when it is
|
|
32
|
+
* not, the failure names the package to install.
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
import { exec } from "node:child_process";
|
|
36
|
+
import { promisify } from "node:util";
|
|
37
|
+
import { normalizeApply, type ApplyResult } from "../../apply";
|
|
38
|
+
|
|
39
|
+
const execAsync = promisify(exec);
|
|
40
|
+
|
|
41
|
+
/** The native apply mechanism for a target. */
|
|
42
|
+
export type ApplyTarget = "cloudformation" | "kubectl" | "arm" | "kustomize" | "gcp" | "fly";
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* How apply treats resources no longer declared.
|
|
46
|
+
* - `never` — additive only; never deletes.
|
|
47
|
+
* - `owned-only` — enables the target's own delete path. What bounds that path
|
|
48
|
+
* differs per target, and all of them are genuinely owned-only: `kubectl`
|
|
49
|
+
* sweeps by the ownership marker, `arm` prunes by the ownership tag
|
|
50
|
+
* (`isChantOwned`, via the azure lexicon's `azApply`), `gcp` prunes by the
|
|
51
|
+
* ownership label (via the gcp lexicon's `gcpApply` — only kinds it can
|
|
52
|
+
* list; the rest are reported not-prunable), `fly` prunes machines by the
|
|
53
|
+
* metadata marker and the metadata-less types (volumes/ips/certs/secrets)
|
|
54
|
+
* app-scoped under a managed app (via the fly lexicon's `flyApply`), and
|
|
55
|
+
* `cloudformation` is bounded by the stack — which holds, because a
|
|
56
|
+
* resource CFN did not create is not in the stack.
|
|
57
|
+
* - `gated` — same delete scope as `owned-only`, but an approval gate precedes
|
|
58
|
+
* the destructive apply, so an unapproved run ends `gated` before deleting
|
|
59
|
+
* anything (the gate lives in the composite).
|
|
60
|
+
*/
|
|
61
|
+
export type DeleteMode = "never" | "owned-only" | "gated";
|
|
62
|
+
|
|
63
|
+
export interface NativeApplyArgs {
|
|
64
|
+
/** Native mechanism to delegate to. */
|
|
65
|
+
target: ApplyTarget;
|
|
66
|
+
/** Environment. What it means is per target: the CFN stack name on
|
|
67
|
+
* `cloudformation`, the ARM resource group on `arm`, the chant environment
|
|
68
|
+
* on `kubectl`/`kustomize`. On `gcp` and `fly` it is a log label only — the
|
|
69
|
+
* gcp applier resolves the project (`GOOGLE_CLOUD_PROJECT` env / CNRM
|
|
70
|
+
* annotation) and endpoint (`GCP_ENDPOINT_URL` env) itself, and the fly
|
|
71
|
+
* applier resolves its endpoint (`FLY_FLAPS_BASE_URL` env) and token
|
|
72
|
+
* (`FLY_API_TOKEN` env) itself, with the app names coming from the plan. */
|
|
73
|
+
env: string;
|
|
74
|
+
/** Built manifest/template path. Default per target ({@link defaultOutput}):
|
|
75
|
+
* `dist` (a dir) for kubectl, `template.json` (a file) for
|
|
76
|
+
* CloudFormation/ARM, `dist/gcp.yaml` for gcp, `dist/fly.json` for fly. */
|
|
77
|
+
output?: string;
|
|
78
|
+
/** Delete handling. Default: never. */
|
|
79
|
+
deleteMode?: DeleteMode;
|
|
80
|
+
/**
|
|
81
|
+
* kubectl target only (chant #1075). Take ownership of fields another field
|
|
82
|
+
* manager owns instead of failing with a conflict that names them.
|
|
83
|
+
* **Opt-in, and never defaulted on**: transferring ownership of a live field
|
|
84
|
+
* is a decision, not a retry.
|
|
85
|
+
*/
|
|
86
|
+
forceConflicts?: boolean;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* What an apply did — one shape for every target: the count projection of
|
|
91
|
+
* core's `NormalizedApply` (#1446, collapsed here in #1449). The per-target
|
|
92
|
+
* shapes this used to carry (`fieldManager`, `stackName`/`status`/`action`,
|
|
93
|
+
* a separate `notPrunable`) belong to the appliers and stay in their lexicons;
|
|
94
|
+
* this activity's result is the shape every Op reads back regardless of
|
|
95
|
+
* target, and the target-specific detail still reaches the operator on the
|
|
96
|
+
* activity log.
|
|
97
|
+
*/
|
|
98
|
+
export interface NativeApplyResult {
|
|
99
|
+
/** Resources the provider was called for and which converged — created,
|
|
100
|
+
* updated or unchanged. On `cloudformation` the unit is the stack, so a
|
|
101
|
+
* settled deploy is `1`. */
|
|
102
|
+
applied: number;
|
|
103
|
+
/** Owned, no-longer-declared resources deleted. */
|
|
104
|
+
pruned: number;
|
|
105
|
+
/** Declared resources no provider call was made for (#1447), including
|
|
106
|
+
* kinds an owned-only prune could not consider (`not-prunable`). Zero on a
|
|
107
|
+
* complete apply. */
|
|
108
|
+
notAttempted: number;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The k8s lexicon's server-side apply, as this module needs to call it.
|
|
113
|
+
* Structural, so nothing here imports the k8s lexicon's types.
|
|
114
|
+
*/
|
|
115
|
+
export type K8sApplier = (
|
|
116
|
+
args: {
|
|
117
|
+
manifest: string;
|
|
118
|
+
/** Already-rendered documents (#1548) — the kustomize target hands the
|
|
119
|
+
* render straight in; `manifest` is then only the log label. */
|
|
120
|
+
documents?: Array<Record<string, unknown>>;
|
|
121
|
+
environment?: string;
|
|
122
|
+
deleteMode?: DeleteMode;
|
|
123
|
+
force?: boolean;
|
|
124
|
+
},
|
|
125
|
+
signal?: AbortSignal,
|
|
126
|
+
) => Promise<{ applied: unknown[]; pruned: unknown[]; fieldManager: string }>;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* The azure lexicon's per-resource ARM applier, as this module needs to call
|
|
130
|
+
* it: `azApply` composed with the lexicon's own `toApplyResult` projection, so
|
|
131
|
+
* what crosses this seam is core's versioned apply envelope (#1446) and
|
|
132
|
+
* nothing ARM-shaped.
|
|
133
|
+
*/
|
|
134
|
+
export type AzureApplier = (
|
|
135
|
+
args: {
|
|
136
|
+
templatePath: string;
|
|
137
|
+
resourceGroup: string;
|
|
138
|
+
endpoint?: string;
|
|
139
|
+
prune?: boolean;
|
|
140
|
+
},
|
|
141
|
+
signal?: AbortSignal,
|
|
142
|
+
) => Promise<ApplyResult>;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* The gcp lexicon's per-resource applier, as this module needs to call it
|
|
146
|
+
* (#1449): `gcpApply` composed with the lexicon's own `toApplyResult`
|
|
147
|
+
* projection, so what crosses this seam is core's versioned apply envelope
|
|
148
|
+
* (#1446) — the skips of #1447 ride it as NOT-ATTEMPTED entries, and a kind
|
|
149
|
+
* the prune could not consider rides it as `not-prunable`.
|
|
150
|
+
*
|
|
151
|
+
* Deliberately narrow: no `endpoint`, because `gcpApply` resolves
|
|
152
|
+
* `GCP_ENDPOINT_URL` itself — the same variable gcp's read path honours, so an
|
|
153
|
+
* apply lands wherever `--live` is already looking (floci-gcp, or real GCP
|
|
154
|
+
* when unset); and no `project`, because `gcpApply` resolves
|
|
155
|
+
* `GOOGLE_CLOUD_PROJECT` / the CNRM project-id annotation itself.
|
|
156
|
+
*/
|
|
157
|
+
export type GcpApplier = (
|
|
158
|
+
args: {
|
|
159
|
+
manifestPath: string;
|
|
160
|
+
prune?: boolean;
|
|
161
|
+
},
|
|
162
|
+
signal?: AbortSignal,
|
|
163
|
+
) => Promise<ApplyResult>;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* The fly lexicon's flaps applier, as this module needs to call it (#1449):
|
|
167
|
+
* `flyApply` composed with the lexicon's own `toApplyResult` projection. The
|
|
168
|
+
* eleven arrays flyApply returns — six entity classes applied, five pruned —
|
|
169
|
+
* are its own contract and stay in the fly lexicon; what crosses this seam is
|
|
170
|
+
* core's versioned apply envelope (#1446).
|
|
171
|
+
*
|
|
172
|
+
* Deliberately narrow: no `endpoint`, because `flyApply` resolves
|
|
173
|
+
* `FLY_FLAPS_BASE_URL` itself — mudflaps locally, real Fly when unset; and no
|
|
174
|
+
* `token`, because it resolves `FLY_API_TOKEN` itself.
|
|
175
|
+
*/
|
|
176
|
+
export type FlyApplier = (
|
|
177
|
+
args: {
|
|
178
|
+
planPath: string;
|
|
179
|
+
prune?: boolean;
|
|
180
|
+
},
|
|
181
|
+
signal?: AbortSignal,
|
|
182
|
+
) => Promise<ApplyResult>;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The aws lexicon's CloudFormation applier, as this module needs to call it
|
|
186
|
+
* (#1449). Structural, like {@link K8sApplier} and {@link AzureApplier}.
|
|
187
|
+
*
|
|
188
|
+
* Deliberately narrow: no `endpoint`, because `awsApply` resolves
|
|
189
|
+
* `AWS_ENDPOINT_URL_CLOUDFORMATION` then `AWS_ENDPOINT_URL` itself (#1694) —
|
|
190
|
+
* the rule that used to live here as `applyEndpoint` (#926); and no
|
|
191
|
+
* `capabilities`, because `awsApply` derives them from the template body
|
|
192
|
+
* (`CAPABILITY_NAMED_IAM`, plus `CAPABILITY_AUTO_EXPAND` for a top-level
|
|
193
|
+
* `Transform` — #980), the rule that used to live here as `cfnCapabilities`.
|
|
194
|
+
*/
|
|
195
|
+
export type AwsApplier = (
|
|
196
|
+
args: { templatePath: string; stackName: string },
|
|
197
|
+
signal?: AbortSignal,
|
|
198
|
+
) => Promise<{ stackName: string; status: string; action: "created" | "updated" | "unchanged" }>;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* The aws lexicon's CloudFormation rollback (saga compensation), as
|
|
202
|
+
* {@link compensateApply} needs to call it. Structural, like the appliers.
|
|
203
|
+
*/
|
|
204
|
+
export type AwsRollback = (
|
|
205
|
+
args: { stackName: string },
|
|
206
|
+
signal?: AbortSignal,
|
|
207
|
+
) => Promise<{ stackName: string; rolledBack: boolean; status?: string }>;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Render a kustomization directory to parsed documents (#1548): `kustomize
|
|
211
|
+
* build`, falling back to kubectl's vendored kustomize when the standalone
|
|
212
|
+
* binary is absent. The 64MiB buffer matches the k8s/helm lexicons' bound —
|
|
213
|
+
* a big overlay renders megabytes. YAML parsing is js-yaml's multi-doc
|
|
214
|
+
* loader, the same one the k8s applier uses on files.
|
|
215
|
+
*/
|
|
216
|
+
async function renderKustomization(dir: string): Promise<Array<Record<string, unknown>>> {
|
|
217
|
+
const quoted = `'${dir.replace(/'/g, "'\\''")}'`;
|
|
218
|
+
const run = (cmd: string) => execAsync(cmd, { maxBuffer: 64 * 1024 * 1024 });
|
|
219
|
+
let stdout: string;
|
|
220
|
+
try {
|
|
221
|
+
({ stdout } = await run(`kustomize build ${quoted}`));
|
|
222
|
+
} catch (err) {
|
|
223
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
224
|
+
if (!/ENOENT|not found|command not found|127/.test(message)) throw err;
|
|
225
|
+
({ stdout } = await run(`kubectl kustomize ${quoted}`));
|
|
226
|
+
}
|
|
227
|
+
const { loadAll } = await import("js-yaml");
|
|
228
|
+
const documents: Array<Record<string, unknown>> = [];
|
|
229
|
+
for (const doc of loadAll(stdout)) {
|
|
230
|
+
if (doc && typeof doc === "object" && !Array.isArray(doc)) documents.push(doc as Record<string, unknown>);
|
|
231
|
+
}
|
|
232
|
+
return documents;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Load the k8s lexicon's apply. A variable specifier, so `tsc` does not
|
|
237
|
+
* statically resolve a package this one deliberately does not depend on — the
|
|
238
|
+
* same mechanism core's activity registry uses to load a lexicon's activities.
|
|
239
|
+
*/
|
|
240
|
+
async function loadK8sApplier(): Promise<K8sApplier> {
|
|
241
|
+
const spec = "@intentius/chant-lexicon-k8s/op/activities";
|
|
242
|
+
let mod: { applyManifest?: K8sApplier };
|
|
243
|
+
try {
|
|
244
|
+
mod = (await import(spec)) as { applyManifest?: K8sApplier };
|
|
245
|
+
} catch (err) {
|
|
246
|
+
throw new Error(
|
|
247
|
+
`apply target "kubectl" needs @intentius/chant-lexicon-k8s, which could not be loaded ` +
|
|
248
|
+
`(${err instanceof Error ? err.message : String(err)}). Kubernetes applies moved out of the ` +
|
|
249
|
+
`op lexicon in chant #1075; install the k8s lexicon and list it in chant.config.ts.`,
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
if (typeof mod.applyManifest !== "function") {
|
|
253
|
+
throw new Error(
|
|
254
|
+
"the installed @intentius/chant-lexicon-k8s exports no applyManifest — it predates chant #1075",
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
return mod.applyManifest;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Load the azure lexicon's `azApply` (#1448). Same variable-specifier trick as
|
|
262
|
+
* {@link loadK8sApplier}, for the same reason.
|
|
263
|
+
*/
|
|
264
|
+
async function loadAzureApplier(): Promise<AzureApplier> {
|
|
265
|
+
const spec = "@intentius/chant-lexicon-azure/op/activities";
|
|
266
|
+
type AzureModule = {
|
|
267
|
+
azApply?: (args: Parameters<AzureApplier>[0], signal?: AbortSignal) => Promise<unknown>;
|
|
268
|
+
toApplyResult?: (result: unknown) => ApplyResult;
|
|
269
|
+
};
|
|
270
|
+
let mod: AzureModule;
|
|
271
|
+
try {
|
|
272
|
+
mod = (await import(spec)) as AzureModule;
|
|
273
|
+
} catch (err) {
|
|
274
|
+
throw new Error(
|
|
275
|
+
`apply target "arm" needs @intentius/chant-lexicon-azure, which could not be loaded ` +
|
|
276
|
+
`(${err instanceof Error ? err.message : String(err)}). ARM applies go through the azure ` +
|
|
277
|
+
`lexicon's per-resource applier since chant #1448; install the azure lexicon and list it ` +
|
|
278
|
+
`in chant.config.ts.`,
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
const { azApply, toApplyResult } = mod;
|
|
282
|
+
if (typeof azApply !== "function") {
|
|
283
|
+
throw new Error(
|
|
284
|
+
"the installed @intentius/chant-lexicon-azure exports no azApply — it predates chant #707",
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
if (typeof toApplyResult !== "function") {
|
|
288
|
+
throw new Error(
|
|
289
|
+
"the installed @intentius/chant-lexicon-azure exports no toApplyResult — it predates chant #1449",
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
return async (args, signal) => toApplyResult(await azApply(args, signal));
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Load the gcp lexicon's `gcpApply` (#1449). Same variable-specifier trick as
|
|
297
|
+
* {@link loadK8sApplier}, for the same reason.
|
|
298
|
+
*/
|
|
299
|
+
async function loadGcpApplier(): Promise<GcpApplier> {
|
|
300
|
+
const spec = "@intentius/chant-lexicon-gcp/op/activities";
|
|
301
|
+
type GcpModule = {
|
|
302
|
+
gcpApply?: (args: Parameters<GcpApplier>[0], signal?: AbortSignal) => Promise<unknown>;
|
|
303
|
+
toApplyResult?: (result: unknown) => ApplyResult;
|
|
304
|
+
};
|
|
305
|
+
let mod: GcpModule;
|
|
306
|
+
try {
|
|
307
|
+
mod = (await import(spec)) as GcpModule;
|
|
308
|
+
} catch (err) {
|
|
309
|
+
throw new Error(
|
|
310
|
+
`apply target "gcp" needs @intentius/chant-lexicon-gcp, which could not be loaded ` +
|
|
311
|
+
`(${err instanceof Error ? err.message : String(err)}). GCP applies go through the gcp ` +
|
|
312
|
+
`lexicon's native applier since chant #1449; install the gcp lexicon and list it ` +
|
|
313
|
+
`in chant.config.ts.`,
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
const { gcpApply, toApplyResult } = mod;
|
|
317
|
+
if (typeof gcpApply !== "function") {
|
|
318
|
+
throw new Error(
|
|
319
|
+
"the installed @intentius/chant-lexicon-gcp exports no gcpApply — it predates chant #706",
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
if (typeof toApplyResult !== "function") {
|
|
323
|
+
throw new Error(
|
|
324
|
+
"the installed @intentius/chant-lexicon-gcp exports no toApplyResult — it predates chant #1449",
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
return async (args, signal) => toApplyResult(await gcpApply(args, signal));
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Load the fly lexicon's `flyApply` (#1449). Same variable-specifier trick as
|
|
332
|
+
* {@link loadK8sApplier}, for the same reason.
|
|
333
|
+
*/
|
|
334
|
+
async function loadFlyApplier(): Promise<FlyApplier> {
|
|
335
|
+
const spec = "@intentius/chant-lexicon-fly/op/activities";
|
|
336
|
+
type FlyModule = {
|
|
337
|
+
flyApply?: (args: Parameters<FlyApplier>[0], signal?: AbortSignal) => Promise<unknown>;
|
|
338
|
+
toApplyResult?: (result: unknown) => ApplyResult;
|
|
339
|
+
};
|
|
340
|
+
let mod: FlyModule;
|
|
341
|
+
try {
|
|
342
|
+
mod = (await import(spec)) as FlyModule;
|
|
343
|
+
} catch (err) {
|
|
344
|
+
throw new Error(
|
|
345
|
+
`apply target "fly" needs @intentius/chant-lexicon-fly, which could not be loaded ` +
|
|
346
|
+
`(${err instanceof Error ? err.message : String(err)}). Fly applies go through the fly ` +
|
|
347
|
+
`lexicon's native flaps applier since chant #1449; install the fly lexicon and list it ` +
|
|
348
|
+
`in chant.config.ts.`,
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
const { flyApply, toApplyResult } = mod;
|
|
352
|
+
if (typeof flyApply !== "function") {
|
|
353
|
+
throw new Error(
|
|
354
|
+
"the installed @intentius/chant-lexicon-fly exports no flyApply — it predates chant #739",
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
if (typeof toApplyResult !== "function") {
|
|
358
|
+
throw new Error(
|
|
359
|
+
"the installed @intentius/chant-lexicon-fly exports no toApplyResult — it predates chant #1449",
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
return async (args, signal) => toApplyResult(await flyApply(args, signal));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Load the aws lexicon's `awsApply` (#1449). Same variable-specifier trick as
|
|
367
|
+
* {@link loadK8sApplier}, for the same reason.
|
|
368
|
+
*/
|
|
369
|
+
async function loadAwsApplier(): Promise<AwsApplier> {
|
|
370
|
+
const spec = "@intentius/chant-lexicon-aws/op/activities";
|
|
371
|
+
let mod: { awsApply?: AwsApplier };
|
|
372
|
+
try {
|
|
373
|
+
mod = (await import(spec)) as { awsApply?: AwsApplier };
|
|
374
|
+
} catch (err) {
|
|
375
|
+
throw new Error(
|
|
376
|
+
`apply target "cloudformation" needs @intentius/chant-lexicon-aws, which could not be loaded ` +
|
|
377
|
+
`(${err instanceof Error ? err.message : String(err)}). CloudFormation applies go through the ` +
|
|
378
|
+
`aws lexicon's native applier since chant #1449; install the aws lexicon and list it ` +
|
|
379
|
+
`in chant.config.ts.`,
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
if (typeof mod.awsApply !== "function") {
|
|
383
|
+
throw new Error(
|
|
384
|
+
"the installed @intentius/chant-lexicon-aws exports no awsApply — it predates chant #1446",
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
return mod.awsApply;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Load the aws lexicon's `rollbackStack` (#1449) — the compensation twin of
|
|
392
|
+
* {@link loadAwsApplier}.
|
|
393
|
+
*/
|
|
394
|
+
async function loadAwsRollback(): Promise<AwsRollback> {
|
|
395
|
+
const spec = "@intentius/chant-lexicon-aws/op/activities";
|
|
396
|
+
let mod: { rollbackStack?: AwsRollback };
|
|
397
|
+
try {
|
|
398
|
+
mod = (await import(spec)) as { rollbackStack?: AwsRollback };
|
|
399
|
+
} catch (err) {
|
|
400
|
+
throw new Error(
|
|
401
|
+
`rollback for target "cloudformation" needs @intentius/chant-lexicon-aws, which could not be ` +
|
|
402
|
+
`loaded (${err instanceof Error ? err.message : String(err)}). CloudFormation rollback goes ` +
|
|
403
|
+
`through the aws lexicon's rollbackStack since chant #1449; install the aws lexicon and ` +
|
|
404
|
+
`list it in chant.config.ts.`,
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
if (typeof mod.rollbackStack !== "function") {
|
|
408
|
+
throw new Error(
|
|
409
|
+
"the installed @intentius/chant-lexicon-aws exports no rollbackStack — it predates chant #1449",
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
return mod.rollbackStack;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Sensible default build output per target. kubectl takes a directory (all
|
|
417
|
+
* manifests), so `dist`; kustomize's "output" is the kustomization DIRECTORY
|
|
418
|
+
* the render reads. The file targets take the file their lexicon's build
|
|
419
|
+
* conventionally emits: `template.json` for CloudFormation/ARM, `dist/gcp.yaml`
|
|
420
|
+
* (the CNRM manifest) for gcp, `dist/fly.json` (the serialized plan) for fly.
|
|
421
|
+
* Pure — exported for testing.
|
|
422
|
+
*/
|
|
423
|
+
export function defaultOutput(target: ApplyTarget): string {
|
|
424
|
+
switch (target) {
|
|
425
|
+
case "kubectl":
|
|
426
|
+
case "kustomize":
|
|
427
|
+
return "dist";
|
|
428
|
+
case "gcp":
|
|
429
|
+
return "dist/gcp.yaml";
|
|
430
|
+
case "fly":
|
|
431
|
+
return "dist/fly.json";
|
|
432
|
+
default:
|
|
433
|
+
return "template.json";
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Collapse a #1446 apply envelope onto the one result shape this activity
|
|
439
|
+
* returns, logging the counts (and warning on skips) as it goes. The envelope
|
|
440
|
+
* is normalized through core's `normalizeApply`, so the counts are the lengths
|
|
441
|
+
* of `NormalizedApply`'s three arrays — nothing re-derived, nothing invented.
|
|
442
|
+
*/
|
|
443
|
+
function collapseEnvelope(envelope: ApplyResult, label: string): NativeApplyResult {
|
|
444
|
+
const n = normalizeApply(envelope);
|
|
445
|
+
console.log(
|
|
446
|
+
`[${label}] applied ${n.applied.length} resource(s)` +
|
|
447
|
+
(n.pruned.length > 0 ? `; pruned ${n.pruned.length}` : ""),
|
|
448
|
+
);
|
|
449
|
+
// #1447: a resource the applier made no call for is reported, not dropped —
|
|
450
|
+
// otherwise a partial apply reads as a full one. The per-resource reasons
|
|
451
|
+
// ride the envelope; the count is what a later step reads.
|
|
452
|
+
if (n.notAttempted.length > 0) {
|
|
453
|
+
console.warn(`[${label}] NOT attempted: ${n.notAttempted.length} resource(s)`);
|
|
454
|
+
for (const skip of n.notAttempted) {
|
|
455
|
+
console.warn(
|
|
456
|
+
`[${label}] ${skip.kind}/${skip.name}: ${skip.reason}${skip.detail ? ` (${skip.detail})` : ""}`,
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return {
|
|
461
|
+
applied: n.applied.length,
|
|
462
|
+
pruned: n.pruned.length,
|
|
463
|
+
notAttempted: n.notAttempted.length,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Apply declared source to the cloud via the target's native mechanism.
|
|
469
|
+
* Deletes (when enabled) ride that mechanism's own delete path — marker-scoped
|
|
470
|
+
* on `kubectl`, tag-scoped on `arm`, label-scoped on `gcp`, marker- and
|
|
471
|
+
* app-scoped on `fly`, and stack-scoped on `cloudformation`, where the deploy
|
|
472
|
+
* itself removes resources dropped from the template and `deleteMode` changes
|
|
473
|
+
* nothing: a resource CFN did not create is not in the stack. See
|
|
474
|
+
* {@link DeleteMode}.
|
|
475
|
+
*
|
|
476
|
+
* The appliers are injectable so this dispatcher can be tested without the
|
|
477
|
+
* product lexicons present; production resolves them through
|
|
478
|
+
* {@link loadK8sApplier} / {@link loadAzureApplier} / {@link loadAwsApplier} /
|
|
479
|
+
* {@link loadGcpApplier} / {@link loadFlyApplier}.
|
|
480
|
+
*/
|
|
481
|
+
export async function nativeApply(
|
|
482
|
+
args: NativeApplyArgs,
|
|
483
|
+
signal?: AbortSignal,
|
|
484
|
+
applier?: K8sApplier,
|
|
485
|
+
azureApplier?: AzureApplier,
|
|
486
|
+
renderer: (dir: string) => Promise<Array<Record<string, unknown>>> = renderKustomization,
|
|
487
|
+
awsApplier?: AwsApplier,
|
|
488
|
+
gcpApplier?: GcpApplier,
|
|
489
|
+
flyApplier?: FlyApplier,
|
|
490
|
+
): Promise<NativeApplyResult> {
|
|
491
|
+
const output = args.output ?? defaultOutput(args.target);
|
|
492
|
+
const deleteMode = args.deleteMode ?? "never";
|
|
493
|
+
|
|
494
|
+
if (args.target === "kubectl" || args.target === "kustomize") {
|
|
495
|
+
const apply = applier ?? (await loadK8sApplier());
|
|
496
|
+
// kustomize (#1548): `output` is the kustomization DIRECTORY; render it
|
|
497
|
+
// and hand the documents to the SAME k8s applier inline — stamping, the
|
|
498
|
+
// marker-scoped prune, and the conflict semantics are identical.
|
|
499
|
+
const kustomized =
|
|
500
|
+
args.target === "kustomize"
|
|
501
|
+
? { documents: await renderer(output), manifest: `kustomize:${output}` }
|
|
502
|
+
: { manifest: output };
|
|
503
|
+
const result = await apply(
|
|
504
|
+
{
|
|
505
|
+
...kustomized,
|
|
506
|
+
environment: args.env,
|
|
507
|
+
deleteMode,
|
|
508
|
+
...(args.forceConflicts !== undefined ? { force: args.forceConflicts } : {}),
|
|
509
|
+
},
|
|
510
|
+
signal,
|
|
511
|
+
);
|
|
512
|
+
// The field manager is the operator's detail and stays on the log; the
|
|
513
|
+
// result is the count projection like every other target's. The k8s
|
|
514
|
+
// applier's contract has no skip path — a document it cannot classify
|
|
515
|
+
// throws — so NOT-ATTEMPTED is structurally zero here.
|
|
516
|
+
console.log(
|
|
517
|
+
`applied ${result.applied.length} object(s) as field manager "${result.fieldManager}"` +
|
|
518
|
+
(result.pruned.length > 0 ? `; pruned ${result.pruned.length}` : ""),
|
|
519
|
+
);
|
|
520
|
+
return {
|
|
521
|
+
applied: result.applied.length,
|
|
522
|
+
pruned: result.pruned.length,
|
|
523
|
+
notAttempted: 0,
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (args.target === "arm") {
|
|
528
|
+
const apply = azureApplier ?? (await loadAzureApplier());
|
|
529
|
+
const envelope = await apply(
|
|
530
|
+
{
|
|
531
|
+
templatePath: output,
|
|
532
|
+
resourceGroup: args.env,
|
|
533
|
+
// The same variable azure's read path honours, so an ARM apply lands
|
|
534
|
+
// wherever `--live` is already looking (floci-az, or real Azure when
|
|
535
|
+
// unset).
|
|
536
|
+
...(process.env.AZURE_ENDPOINT_URL ? { endpoint: process.env.AZURE_ENDPOINT_URL } : {}),
|
|
537
|
+
prune: deleteMode !== "never",
|
|
538
|
+
},
|
|
539
|
+
signal,
|
|
540
|
+
);
|
|
541
|
+
return collapseEnvelope(envelope, args.env);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
if (args.target === "gcp") {
|
|
545
|
+
// gcp (#1449): the gcp lexicon's per-resource applier. Only the manifest
|
|
546
|
+
// path and the prune switch cross this seam — endpoint (`GCP_ENDPOINT_URL`)
|
|
547
|
+
// and project (`GOOGLE_CLOUD_PROJECT` / CNRM annotation) are gcpApply's own
|
|
548
|
+
// env resolution, and `env` is a log label here: GCP has no stack or
|
|
549
|
+
// resource-group equivalent for it to name.
|
|
550
|
+
const apply = gcpApplier ?? (await loadGcpApplier());
|
|
551
|
+
const envelope = await apply({ manifestPath: output, prune: deleteMode !== "never" }, signal);
|
|
552
|
+
// #1447's skips and the not-prunable kinds both ride the envelope as
|
|
553
|
+
// NOT-ATTEMPTED entries — one bucket, per-entry reasons, one count out.
|
|
554
|
+
return collapseEnvelope(envelope, args.env);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if (args.target === "fly") {
|
|
558
|
+
// fly (#1449): the fly lexicon's flaps applier. Only the plan path and the
|
|
559
|
+
// prune switch cross this seam — the endpoint (`FLY_FLAPS_BASE_URL`,
|
|
560
|
+
// mudflaps locally) and token (`FLY_API_TOKEN`) are flyApply's own env
|
|
561
|
+
// resolution, and `env` is a log label here: the app names live in the
|
|
562
|
+
// plan itself.
|
|
563
|
+
const apply = flyApplier ?? (await loadFlyApplier());
|
|
564
|
+
const envelope = await apply({ planPath: output, prune: deleteMode !== "never" }, signal);
|
|
565
|
+
// The six applied classes and five pruned classes are already flattened
|
|
566
|
+
// into the envelope by fly's own toApplyResult; here they are just counts.
|
|
567
|
+
return collapseEnvelope(envelope, args.env);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// cloudformation (#1449): the aws lexicon's native applier. env is the stack
|
|
571
|
+
// name and output the template path; endpoint resolution (#1694) and
|
|
572
|
+
// capability derivation (#980) are awsApply's own, so nothing else is passed.
|
|
573
|
+
const apply = awsApplier ?? (await loadAwsApplier());
|
|
574
|
+
const result = await apply({ templatePath: output, stackName: args.env }, signal);
|
|
575
|
+
// The stack, its settled status and the action are the operator's detail and
|
|
576
|
+
// stay on the log. The result is the same count projection as every other
|
|
577
|
+
// target's, with the stack as the unit: one settled deploy, one applied.
|
|
578
|
+
console.log(`${result.action}: stack ${result.stackName} (${result.status})`);
|
|
579
|
+
return { applied: 1, pruned: 0, notAttempted: 0 };
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Whether a target has a mapped native rollback for {@link compensateApply} to
|
|
584
|
+
* run without an explicit `compensate.command`. `cloudformation` is the only
|
|
585
|
+
* one today — the aws lexicon's `rollbackStack`. This is the totality
|
|
586
|
+
* predicate `ApplyOp` checks at build time (#1449): a target outside it with
|
|
587
|
+
* no command has nothing a compensation could run, so the op refuses to build
|
|
588
|
+
* with compensation on rather than warn at rollback time.
|
|
589
|
+
*/
|
|
590
|
+
export function hasNativeRollback(target: ApplyTarget): boolean {
|
|
591
|
+
return target === "cloudformation";
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
export interface CompensateApplyArgs {
|
|
595
|
+
/** Native mechanism that was applied. */
|
|
596
|
+
target: ApplyTarget;
|
|
597
|
+
/** Environment — CFN stack name / ARM resource group. */
|
|
598
|
+
env: string;
|
|
599
|
+
/** Explicit rollback command, used in preference to the native default. */
|
|
600
|
+
command?: string;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/** What a compensation did. */
|
|
604
|
+
export interface CompensateApplyResult {
|
|
605
|
+
/** The explicit rollback command that ran, when one was supplied. */
|
|
606
|
+
command?: string;
|
|
607
|
+
/** The stack rolled back — cloudformation. */
|
|
608
|
+
stackName?: string;
|
|
609
|
+
/** Whether the native rollback actually ran — cloudformation. `false` when
|
|
610
|
+
* the stack was absent or the target does not implement RollbackStack (Floci). */
|
|
611
|
+
rolledBack?: boolean;
|
|
612
|
+
/** The settled post-rollback stack status — cloudformation. */
|
|
613
|
+
status?: string;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/**
|
|
617
|
+
* Compensation step (saga rollback) for a partial apply failure. Runs the
|
|
618
|
+
* explicit `command` if given; otherwise `cloudformation` rolls back natively
|
|
619
|
+
* through the aws lexicon's `rollbackStack` (#1449 — CloudFormation
|
|
620
|
+
* `RollbackStack` over the Query API, no CLI in the path).
|
|
621
|
+
*
|
|
622
|
+
* Compensation is total for built ops: `ApplyOp` refuses at build time to wire
|
|
623
|
+
* this activity for a target with neither a native rollback
|
|
624
|
+
* ({@link hasNativeRollback}) nor an explicit `command`, so the no-rollback
|
|
625
|
+
* branch below is unreachable from an op it built. It stays as a throw, not a
|
|
626
|
+
* warn — a hand-assembled op that reaches it must fail loudly, because partial
|
|
627
|
+
* state should never look reverted when it isn't.
|
|
628
|
+
*
|
|
629
|
+
* `rollback` is injectable for tests; production resolves it through
|
|
630
|
+
* {@link loadAwsRollback}.
|
|
631
|
+
*/
|
|
632
|
+
export async function compensateApply(
|
|
633
|
+
args: CompensateApplyArgs,
|
|
634
|
+
signal?: AbortSignal,
|
|
635
|
+
rollback?: AwsRollback,
|
|
636
|
+
): Promise<CompensateApplyResult> {
|
|
637
|
+
if (args.command) {
|
|
638
|
+
const { stdout, stderr } = await execAsync(args.command, { signal });
|
|
639
|
+
if (stdout) console.log(stdout);
|
|
640
|
+
if (stderr) console.error(stderr);
|
|
641
|
+
return { command: args.command };
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
if (args.target === "cloudformation") {
|
|
645
|
+
const roll = rollback ?? (await loadAwsRollback());
|
|
646
|
+
const result = await roll({ stackName: args.env }, signal);
|
|
647
|
+
return {
|
|
648
|
+
stackName: result.stackName,
|
|
649
|
+
rolledBack: result.rolledBack,
|
|
650
|
+
...(result.status !== undefined ? { status: result.status } : {}),
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// Defensive: unreachable from an ApplyOp, which refuses this combination at
|
|
655
|
+
// build time (#1449). Reaching it means the op was assembled without that
|
|
656
|
+
// check, and the honest outcome is a failure that says the state stands.
|
|
657
|
+
throw new Error(
|
|
658
|
+
`no automatic rollback for target "${args.target}" — the partial apply to ${args.env} was NOT ` +
|
|
659
|
+
`reverted and cannot be. ApplyOp refuses compensate for this target at build time; either ` +
|
|
660
|
+
`supply compensate.command or use a target with a mapped rollback (cloudformation).`,
|
|
661
|
+
);
|
|
662
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
|
|
4
|
+
const execAsync = promisify(exec);
|
|
5
|
+
|
|
6
|
+
export interface ChantBuildArgs {
|
|
7
|
+
path: string;
|
|
8
|
+
/** npm script to run. Default: `build`. Set e.g. `build:aws` to build one target. */
|
|
9
|
+
script?: string;
|
|
10
|
+
/** Optional extra env vars to pass to the build command. */
|
|
11
|
+
env?: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Run an npm build script (`build` by default) in the given project directory.
|
|
16
|
+
* Uses fastIdempotent profile — 5m timeout, 3 retries.
|
|
17
|
+
*/
|
|
18
|
+
export async function chantBuild(args: ChantBuildArgs, signal?: AbortSignal): Promise<void> {
|
|
19
|
+
const { stdout, stderr } = await execAsync(`npm run ${args.script ?? "build"}`, {
|
|
20
|
+
cwd: args.path,
|
|
21
|
+
env: { ...process.env, ...args.env },
|
|
22
|
+
signal,
|
|
23
|
+
});
|
|
24
|
+
if (stdout) console.log(stdout);
|
|
25
|
+
if (stderr) console.error(stderr);
|
|
26
|
+
}
|