typekro 0.8.0 → 0.9.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/.tsbuildinfo +1 -1
- package/dist/alchemy/deployers.d.ts +16 -1
- package/dist/alchemy/deployers.d.ts.map +1 -1
- package/dist/alchemy/deployers.js +131 -18
- package/dist/alchemy/deployers.js.map +1 -1
- package/dist/alchemy/deployment.d.ts +1 -1
- package/dist/alchemy/deployment.d.ts.map +1 -1
- package/dist/alchemy/deployment.js +1 -1
- package/dist/alchemy/deployment.js.map +1 -1
- package/dist/alchemy/kro-delete.d.ts +66 -0
- package/dist/alchemy/kro-delete.d.ts.map +1 -0
- package/dist/alchemy/kro-delete.js +183 -0
- package/dist/alchemy/kro-delete.js.map +1 -0
- package/dist/alchemy/resource-registration.d.ts +16 -0
- package/dist/alchemy/resource-registration.d.ts.map +1 -1
- package/dist/alchemy/resource-registration.js +138 -24
- package/dist/alchemy/resource-registration.js.map +1 -1
- package/dist/alchemy/types.d.ts +8 -4
- package/dist/alchemy/types.d.ts.map +1 -1
- package/dist/compositions/typekro-runtime/typekro-runtime.d.ts +1 -1
- package/dist/compositions/typekro-runtime/typekro-runtime.d.ts.map +1 -1
- package/dist/compositions/typekro-runtime/typekro-runtime.js +27 -9
- package/dist/compositions/typekro-runtime/typekro-runtime.js.map +1 -1
- package/dist/core/composition/context.d.ts +58 -2
- package/dist/core/composition/context.d.ts.map +1 -1
- package/dist/core/composition/context.js +4 -0
- package/dist/core/composition/context.js.map +1 -1
- package/dist/core/composition/imperative.d.ts +9 -0
- package/dist/core/composition/imperative.d.ts.map +1 -1
- package/dist/core/composition/imperative.js +538 -54
- package/dist/core/composition/imperative.js.map +1 -1
- package/dist/core/composition/nested-status-cel.d.ts +34 -1
- package/dist/core/composition/nested-status-cel.d.ts.map +1 -1
- package/dist/core/composition/nested-status-cel.js +379 -41
- package/dist/core/composition/nested-status-cel.js.map +1 -1
- package/dist/core/composition-debugger.d.ts +1 -1
- package/dist/core/composition-debugger.d.ts.map +1 -1
- package/dist/core/composition-debugger.js.map +1 -1
- package/dist/core/constants/brands.d.ts +1 -1
- package/dist/core/constants/brands.d.ts.map +1 -1
- package/dist/core/constants/brands.js +1 -1
- package/dist/core/constants/brands.js.map +1 -1
- package/dist/core/containers/build.d.ts.map +1 -1
- package/dist/core/containers/build.js +40 -12
- package/dist/core/containers/build.js.map +1 -1
- package/dist/core/dependencies/resolver.d.ts +19 -0
- package/dist/core/dependencies/resolver.d.ts.map +1 -1
- package/dist/core/dependencies/resolver.js +261 -1
- package/dist/core/dependencies/resolver.js.map +1 -1
- package/dist/core/deployment/client-provider-manager.d.ts +9 -3
- package/dist/core/deployment/client-provider-manager.d.ts.map +1 -1
- package/dist/core/deployment/client-provider-manager.js +12 -0
- package/dist/core/deployment/client-provider-manager.js.map +1 -1
- package/dist/core/deployment/crd-manager.d.ts +24 -0
- package/dist/core/deployment/crd-manager.d.ts.map +1 -1
- package/dist/core/deployment/crd-manager.js +79 -1
- package/dist/core/deployment/crd-manager.js.map +1 -1
- package/dist/core/deployment/deployment-state-discovery.d.ts +116 -0
- package/dist/core/deployment/deployment-state-discovery.d.ts.map +1 -0
- package/dist/core/deployment/deployment-state-discovery.js +400 -0
- package/dist/core/deployment/deployment-state-discovery.js.map +1 -0
- package/dist/core/deployment/direct-factory.d.ts +65 -6
- package/dist/core/deployment/direct-factory.d.ts.map +1 -1
- package/dist/core/deployment/direct-factory.js +551 -56
- package/dist/core/deployment/direct-factory.js.map +1 -1
- package/dist/core/deployment/engine.d.ts +64 -3
- package/dist/core/deployment/engine.d.ts.map +1 -1
- package/dist/core/deployment/engine.js +194 -27
- package/dist/core/deployment/engine.js.map +1 -1
- package/dist/core/deployment/event-filter.js +1 -1
- package/dist/core/deployment/event-filter.js.map +1 -1
- package/dist/core/deployment/event-monitor.d.ts +11 -0
- package/dist/core/deployment/event-monitor.d.ts.map +1 -1
- package/dist/core/deployment/event-monitor.js +14 -0
- package/dist/core/deployment/event-monitor.js.map +1 -1
- package/dist/core/deployment/handle-tracing.d.ts +14 -0
- package/dist/core/deployment/handle-tracing.d.ts.map +1 -0
- package/dist/core/deployment/handle-tracing.js +38 -0
- package/dist/core/deployment/handle-tracing.js.map +1 -0
- package/dist/core/deployment/kro-factory.d.ts +115 -3
- package/dist/core/deployment/kro-factory.d.ts.map +1 -1
- package/dist/core/deployment/kro-factory.js +906 -265
- package/dist/core/deployment/kro-factory.js.map +1 -1
- package/dist/core/deployment/kro-readiness.d.ts.map +1 -1
- package/dist/core/deployment/kro-readiness.js +21 -12
- package/dist/core/deployment/kro-readiness.js.map +1 -1
- package/dist/core/deployment/nested-composition-status.d.ts +1 -1
- package/dist/core/deployment/nested-composition-status.d.ts.map +1 -1
- package/dist/core/deployment/nested-composition-status.js +96 -53
- package/dist/core/deployment/nested-composition-status.js.map +1 -1
- package/dist/core/deployment/resource-applier.d.ts +15 -2
- package/dist/core/deployment/resource-applier.d.ts.map +1 -1
- package/dist/core/deployment/resource-applier.js +75 -25
- package/dist/core/deployment/resource-applier.js.map +1 -1
- package/dist/core/deployment/resource-tagging.d.ts +220 -0
- package/dist/core/deployment/resource-tagging.d.ts.map +1 -0
- package/dist/core/deployment/resource-tagging.js +292 -0
- package/dist/core/deployment/resource-tagging.js.map +1 -0
- package/dist/core/deployment/rollback-manager.d.ts +25 -4
- package/dist/core/deployment/rollback-manager.d.ts.map +1 -1
- package/dist/core/deployment/rollback-manager.js +70 -57
- package/dist/core/deployment/rollback-manager.js.map +1 -1
- package/dist/core/deployment/shared-utilities.d.ts +6 -0
- package/dist/core/deployment/shared-utilities.d.ts.map +1 -1
- package/dist/core/deployment/shared-utilities.js +32 -2
- package/dist/core/deployment/shared-utilities.js.map +1 -1
- package/dist/core/deployment/singleton-owner-drift.d.ts +16 -0
- package/dist/core/deployment/singleton-owner-drift.d.ts.map +1 -0
- package/dist/core/deployment/singleton-owner-drift.js +54 -0
- package/dist/core/deployment/singleton-owner-drift.js.map +1 -0
- package/dist/core/deployment/strategies/alchemy-strategy.d.ts +3 -1
- package/dist/core/deployment/strategies/alchemy-strategy.d.ts.map +1 -1
- package/dist/core/deployment/strategies/alchemy-strategy.js +121 -18
- package/dist/core/deployment/strategies/alchemy-strategy.js.map +1 -1
- package/dist/core/deployment/strategies/base-strategy.d.ts +9 -3
- package/dist/core/deployment/strategies/base-strategy.d.ts.map +1 -1
- package/dist/core/deployment/strategies/base-strategy.js +32 -4
- package/dist/core/deployment/strategies/base-strategy.js.map +1 -1
- package/dist/core/deployment/strategies/direct-strategy.d.ts +12 -4
- package/dist/core/deployment/strategies/direct-strategy.d.ts.map +1 -1
- package/dist/core/deployment/strategies/direct-strategy.js +112 -8
- package/dist/core/deployment/strategies/direct-strategy.js.map +1 -1
- package/dist/core/errors.d.ts +2 -2
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js.map +1 -1
- package/dist/core/expressions/analysis/cache.d.ts +2 -2
- package/dist/core/expressions/analysis/cache.d.ts.map +1 -1
- package/dist/core/expressions/analysis/cache.js +4 -0
- package/dist/core/expressions/analysis/cache.js.map +1 -1
- package/dist/core/expressions/analysis/fn-toString-self-test.d.ts.map +1 -1
- package/dist/core/expressions/analysis/fn-toString-self-test.js +0 -1
- package/dist/core/expressions/analysis/fn-toString-self-test.js.map +1 -1
- package/dist/core/expressions/analysis/shared-types.d.ts +2 -2
- package/dist/core/expressions/analysis/shared-types.d.ts.map +1 -1
- package/dist/core/expressions/analysis/source-map.d.ts.map +1 -1
- package/dist/core/expressions/analysis/source-map.js +1 -0
- package/dist/core/expressions/analysis/source-map.js.map +1 -1
- package/dist/core/expressions/analysis/types.d.ts +7 -7
- package/dist/core/expressions/analysis/types.d.ts.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-helpers.d.ts +29 -1
- package/dist/core/expressions/composition/composition-analyzer-helpers.d.ts.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-helpers.js +348 -17
- package/dist/core/expressions/composition/composition-analyzer-helpers.js.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-ternary.d.ts +2 -2
- package/dist/core/expressions/composition/composition-analyzer-ternary.d.ts.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-ternary.js +221 -10
- package/dist/core/expressions/composition/composition-analyzer-ternary.js.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-traversal.d.ts.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-traversal.js +67 -2
- package/dist/core/expressions/composition/composition-analyzer-traversal.js.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-types.d.ts +52 -0
- package/dist/core/expressions/composition/composition-analyzer-types.d.ts.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer.js +150 -6
- package/dist/core/expressions/composition/composition-analyzer.js.map +1 -1
- package/dist/core/expressions/composition/expression-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/composition/expression-analyzer.js +21 -4
- package/dist/core/expressions/composition/expression-analyzer.js.map +1 -1
- package/dist/core/expressions/composition/imperative-analyzer.d.ts +1 -1
- package/dist/core/expressions/composition/imperative-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/composition/imperative-analyzer.js +31 -7
- package/dist/core/expressions/composition/imperative-analyzer.js.map +1 -1
- package/dist/core/expressions/composition/scope-manager.d.ts +2 -2
- package/dist/core/expressions/composition/scope-manager.d.ts.map +1 -1
- package/dist/core/expressions/composition/scope-manager.js.map +1 -1
- package/dist/core/expressions/conditional/conditional-expression-processor.d.ts +3 -3
- package/dist/core/expressions/conditional/conditional-expression-processor.d.ts.map +1 -1
- package/dist/core/expressions/conditional/conditional-expression-processor.js.map +1 -1
- package/dist/core/expressions/conditional/conditional-integration.d.ts.map +1 -1
- package/dist/core/expressions/conditional/conditional-integration.js.map +1 -1
- package/dist/core/expressions/context/context-aware-generator.d.ts +5 -5
- package/dist/core/expressions/context/context-aware-generator.d.ts.map +1 -1
- package/dist/core/expressions/context/context-aware-generator.js.map +1 -1
- package/dist/core/expressions/context/context-detector.d.ts +3 -3
- package/dist/core/expressions/context/context-detector.d.ts.map +1 -1
- package/dist/core/expressions/context/context-detector.js.map +1 -1
- package/dist/core/expressions/context/context-validator.d.ts +6 -6
- package/dist/core/expressions/context/context-validator.d.ts.map +1 -1
- package/dist/core/expressions/context/context-validator.js +2 -2
- package/dist/core/expressions/context/context-validator.js.map +1 -1
- package/dist/core/expressions/factory/cel-conversion-engine.d.ts +4 -4
- package/dist/core/expressions/factory/cel-conversion-engine.d.ts.map +1 -1
- package/dist/core/expressions/factory/cel-conversion-engine.js.map +1 -1
- package/dist/core/expressions/factory/dependency-tracker.d.ts +2 -2
- package/dist/core/expressions/factory/dependency-tracker.d.ts.map +1 -1
- package/dist/core/expressions/factory/dependency-tracker.js +21 -5
- package/dist/core/expressions/factory/dependency-tracker.js.map +1 -1
- package/dist/core/expressions/factory/factory-integration.d.ts +2 -4
- package/dist/core/expressions/factory/factory-integration.d.ts.map +1 -1
- package/dist/core/expressions/factory/factory-integration.js +0 -6
- package/dist/core/expressions/factory/factory-integration.js.map +1 -1
- package/dist/core/expressions/factory/factory-pattern-handler.d.ts +3 -3
- package/dist/core/expressions/factory/factory-pattern-handler.d.ts.map +1 -1
- package/dist/core/expressions/factory/factory-pattern-handler.js +1 -0
- package/dist/core/expressions/factory/factory-pattern-handler.js.map +1 -1
- package/dist/core/expressions/factory/migration-helpers.js.map +1 -1
- package/dist/core/expressions/factory/resource-analyzer.d.ts +4 -4
- package/dist/core/expressions/factory/resource-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/factory/resource-analyzer.js.map +1 -1
- package/dist/core/expressions/factory/resource-type-validator.d.ts +5 -5
- package/dist/core/expressions/factory/resource-type-validator.d.ts.map +1 -1
- package/dist/core/expressions/factory/resource-type-validator.js.map +1 -1
- package/dist/core/expressions/factory/status-builder-analyzer.d.ts +6 -7
- package/dist/core/expressions/factory/status-builder-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/factory/status-builder-analyzer.js +0 -3
- package/dist/core/expressions/factory/status-builder-analyzer.js.map +1 -1
- package/dist/core/expressions/factory/status-builder-types.d.ts +1 -1
- package/dist/core/expressions/factory/status-builder-types.d.ts.map +1 -1
- package/dist/core/expressions/factory/status-cel-generation.d.ts +1 -1
- package/dist/core/expressions/factory/status-cel-generation.d.ts.map +1 -1
- package/dist/core/expressions/factory/status-cel-generation.js +1 -1
- package/dist/core/expressions/factory/status-cel-generation.js.map +1 -1
- package/dist/core/expressions/factory/status-field-analysis.d.ts +3 -3
- package/dist/core/expressions/factory/status-field-analysis.d.ts.map +1 -1
- package/dist/core/expressions/factory/status-field-analysis.js.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.d.ts +5 -5
- package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.js +1 -1
- package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.js.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.d.ts +10 -10
- package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.js +5 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.js.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-ast.d.ts +2 -2
- package/dist/core/expressions/magic-proxy/magic-proxy-ast.d.ts.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-ast.js.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-detector.d.ts +5 -5
- package/dist/core/expressions/magic-proxy/magic-proxy-detector.d.ts.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-detector.js.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-types.d.ts +2 -2
- package/dist/core/expressions/magic-proxy/magic-proxy-types.d.ts.map +1 -1
- package/dist/core/expressions/magic-proxy/optionality-handler.d.ts +1 -2
- package/dist/core/expressions/magic-proxy/optionality-handler.d.ts.map +1 -1
- package/dist/core/expressions/magic-proxy/optionality-handler.js +2 -15
- package/dist/core/expressions/magic-proxy/optionality-handler.js.map +1 -1
- package/dist/core/expressions/validation/compile-time-checker.d.ts +1 -1
- package/dist/core/expressions/validation/compile-time-checker.d.ts.map +1 -1
- package/dist/core/expressions/validation/compile-time-checker.js.map +1 -1
- package/dist/core/expressions/validation/compile-time-types.d.ts +2 -2
- package/dist/core/expressions/validation/compile-time-types.d.ts.map +1 -1
- package/dist/core/expressions/validation/kubernetes-field-types.d.ts +4 -4
- package/dist/core/expressions/validation/kubernetes-field-types.d.ts.map +1 -1
- package/dist/core/expressions/validation/kubernetes-field-types.js.map +1 -1
- package/dist/core/expressions/validation/resource-field-utils.d.ts +10 -10
- package/dist/core/expressions/validation/resource-field-utils.d.ts.map +1 -1
- package/dist/core/expressions/validation/resource-field-utils.js.map +1 -1
- package/dist/core/expressions/validation/resource-validation.d.ts +3 -3
- package/dist/core/expressions/validation/resource-validation.d.ts.map +1 -1
- package/dist/core/expressions/validation/resource-validation.js.map +1 -1
- package/dist/core/expressions/validation/type-inference-types.d.ts +2 -2
- package/dist/core/expressions/validation/type-inference-types.d.ts.map +1 -1
- package/dist/core/expressions/validation/type-safety.d.ts +2 -2
- package/dist/core/expressions/validation/type-safety.d.ts.map +1 -1
- package/dist/core/expressions/validation/type-safety.js +1 -0
- package/dist/core/expressions/validation/type-safety.js.map +1 -1
- package/dist/core/kubernetes/bun-api-client.js.map +1 -1
- package/dist/core/kubernetes/bun-http-library.d.ts.map +1 -1
- package/dist/core/kubernetes/bun-http-library.js +29 -3
- package/dist/core/kubernetes/bun-http-library.js.map +1 -1
- package/dist/core/kubernetes/client-provider.d.ts +12 -0
- package/dist/core/kubernetes/client-provider.d.ts.map +1 -1
- package/dist/core/kubernetes/client-provider.js +35 -0
- package/dist/core/kubernetes/client-provider.js.map +1 -1
- package/dist/core/metadata/resource-metadata.d.ts +46 -1
- package/dist/core/metadata/resource-metadata.d.ts.map +1 -1
- package/dist/core/metadata/resource-metadata.js.map +1 -1
- package/dist/core/proxy/create-resource.d.ts +15 -0
- package/dist/core/proxy/create-resource.d.ts.map +1 -1
- package/dist/core/proxy/create-resource.js +56 -2
- package/dist/core/proxy/create-resource.js.map +1 -1
- package/dist/core/readiness/registry.js +2 -2
- package/dist/core/readiness/registry.js.map +1 -1
- package/dist/core/references/cel-evaluator.d.ts +1 -4
- package/dist/core/references/cel-evaluator.d.ts.map +1 -1
- package/dist/core/references/cel-evaluator.js +3 -7
- package/dist/core/references/cel-evaluator.js.map +1 -1
- package/dist/core/references/cel.d.ts +22 -0
- package/dist/core/references/cel.d.ts.map +1 -1
- package/dist/core/references/cel.js +106 -8
- package/dist/core/references/cel.js.map +1 -1
- package/dist/core/references/external-refs.d.ts.map +1 -1
- package/dist/core/references/external-refs.js +3 -0
- package/dist/core/references/external-refs.js.map +1 -1
- package/dist/core/references/resolver.d.ts.map +1 -1
- package/dist/core/references/resolver.js +28 -17
- package/dist/core/references/resolver.js.map +1 -1
- package/dist/core/references/schema-proxy.d.ts +18 -10
- package/dist/core/references/schema-proxy.d.ts.map +1 -1
- package/dist/core/references/schema-proxy.js +174 -23
- package/dist/core/references/schema-proxy.js.map +1 -1
- package/dist/core/runtime-patches/crd-schema-fix.d.ts.map +1 -1
- package/dist/core/runtime-patches/crd-schema-fix.js +4 -1
- package/dist/core/runtime-patches/crd-schema-fix.js.map +1 -1
- package/dist/core/serialization/cel-optimizer.d.ts.map +1 -1
- package/dist/core/serialization/cel-optimizer.js +2 -0
- package/dist/core/serialization/cel-optimizer.js.map +1 -1
- package/dist/core/serialization/cel-references.d.ts +75 -1
- package/dist/core/serialization/cel-references.d.ts.map +1 -1
- package/dist/core/serialization/cel-references.js +692 -156
- package/dist/core/serialization/cel-references.js.map +1 -1
- package/dist/core/serialization/core.d.ts +8 -8
- package/dist/core/serialization/core.d.ts.map +1 -1
- package/dist/core/serialization/core.js +638 -90
- package/dist/core/serialization/core.js.map +1 -1
- package/dist/core/serialization/kro-post-processing.d.ts +1 -1
- package/dist/core/serialization/kro-post-processing.d.ts.map +1 -1
- package/dist/core/serialization/kro-post-processing.js +69 -22
- package/dist/core/serialization/kro-post-processing.js.map +1 -1
- package/dist/core/serialization/schema.d.ts +1 -0
- package/dist/core/serialization/schema.d.ts.map +1 -1
- package/dist/core/serialization/schema.js +378 -50
- package/dist/core/serialization/schema.js.map +1 -1
- package/dist/core/serialization/status-analysis-pipeline.d.ts +1 -1
- package/dist/core/serialization/status-analysis-pipeline.d.ts.map +1 -1
- package/dist/core/serialization/status-analysis-pipeline.js.map +1 -1
- package/dist/core/serialization/yaml.d.ts +3 -2
- package/dist/core/serialization/yaml.d.ts.map +1 -1
- package/dist/core/serialization/yaml.js +385 -55
- package/dist/core/serialization/yaml.js.map +1 -1
- package/dist/core/singleton/singleton.d.ts +16 -0
- package/dist/core/singleton/singleton.d.ts.map +1 -0
- package/dist/core/singleton/singleton.js +135 -0
- package/dist/core/singleton/singleton.js.map +1 -0
- package/dist/core/types/common.d.ts +2 -2
- package/dist/core/types/common.d.ts.map +1 -1
- package/dist/core/types/composable.d.ts +1 -1
- package/dist/core/types/composable.d.ts.map +1 -1
- package/dist/core/types/deployment.d.ts +126 -6
- package/dist/core/types/deployment.d.ts.map +1 -1
- package/dist/core/types/deployment.js +1 -1
- package/dist/core/types/deployment.js.map +1 -1
- package/dist/core/types/kubernetes.d.ts +25 -17
- package/dist/core/types/kubernetes.d.ts.map +1 -1
- package/dist/core/types/references.d.ts +1 -1
- package/dist/core/types/references.d.ts.map +1 -1
- package/dist/core/types/references.js.map +1 -1
- package/dist/core/types/resource-graph.d.ts +1 -1
- package/dist/core/types/resource-graph.d.ts.map +1 -1
- package/dist/core/types/schema.d.ts +1 -1
- package/dist/core/types/schema.d.ts.map +1 -1
- package/dist/core/types/serialization.d.ts +24 -6
- package/dist/core/types/serialization.d.ts.map +1 -1
- package/dist/core/validation/cel-validator.d.ts +15 -2
- package/dist/core/validation/cel-validator.d.ts.map +1 -1
- package/dist/core/validation/cel-validator.js +144 -63
- package/dist/core/validation/cel-validator.js.map +1 -1
- package/dist/factories/apisix/compositions/apisix-bootstrap.d.ts +2 -41
- package/dist/factories/apisix/compositions/apisix-bootstrap.d.ts.map +1 -1
- package/dist/factories/apisix/compositions/apisix-bootstrap.js +262 -217
- package/dist/factories/apisix/compositions/apisix-bootstrap.js.map +1 -1
- package/dist/factories/apisix/index.d.ts +2 -2
- package/dist/factories/apisix/index.js +2 -2
- package/dist/factories/apisix/resources/helm.d.ts +2 -2
- package/dist/factories/apisix/resources/helm.d.ts.map +1 -1
- package/dist/factories/apisix/resources/helm.js.map +1 -1
- package/dist/factories/apisix/types.d.ts +21 -11
- package/dist/factories/apisix/types.d.ts.map +1 -1
- package/dist/factories/apisix/types.js +106 -4
- package/dist/factories/apisix/types.js.map +1 -1
- package/dist/factories/apisix/utils/admin-credentials.d.ts +5 -3
- package/dist/factories/apisix/utils/admin-credentials.d.ts.map +1 -1
- package/dist/factories/apisix/utils/admin-credentials.js +14 -10
- package/dist/factories/apisix/utils/admin-credentials.js.map +1 -1
- package/dist/factories/apisix/utils/helm-values-mapper.d.ts.map +1 -1
- package/dist/factories/apisix/utils/helm-values-mapper.js +4 -2
- package/dist/factories/apisix/utils/helm-values-mapper.js.map +1 -1
- package/dist/factories/cert-manager/resources/challenges.js.map +1 -1
- package/dist/factories/cert-manager/types.d.ts +3 -3
- package/dist/factories/cert-manager/types.d.ts.map +1 -1
- package/dist/factories/cilium/compositions/cilium-bootstrap.d.ts +4 -4
- package/dist/factories/cilium/types.d.ts +3 -3
- package/dist/factories/cilium/types.d.ts.map +1 -1
- package/dist/factories/cnpg/compositions/cnpg-bootstrap.d.ts +1 -0
- package/dist/factories/cnpg/compositions/cnpg-bootstrap.d.ts.map +1 -1
- package/dist/factories/cnpg/compositions/cnpg-bootstrap.js +48 -0
- package/dist/factories/cnpg/compositions/cnpg-bootstrap.js.map +1 -1
- package/dist/factories/cnpg/resources/cluster.js +1 -1
- package/dist/factories/cnpg/resources/cluster.js.map +1 -1
- package/dist/factories/cnpg/resources/helm.d.ts.map +1 -1
- package/dist/factories/cnpg/resources/helm.js +1 -0
- package/dist/factories/cnpg/resources/helm.js.map +1 -1
- package/dist/factories/cnpg/resources/pooler.js +1 -1
- package/dist/factories/cnpg/resources/pooler.js.map +1 -1
- package/dist/factories/cnpg/types.d.ts +9 -8
- package/dist/factories/cnpg/types.d.ts.map +1 -1
- package/dist/factories/cnpg/types.js +11 -0
- package/dist/factories/cnpg/types.js.map +1 -1
- package/dist/factories/external-dns/compositions/external-dns-bootstrap.d.ts.map +1 -1
- package/dist/factories/external-dns/compositions/external-dns-bootstrap.js +153 -41
- package/dist/factories/external-dns/compositions/external-dns-bootstrap.js.map +1 -1
- package/dist/factories/external-dns/resources/dns-endpoint.js +1 -1
- package/dist/factories/external-dns/resources/dns-endpoint.js.map +1 -1
- package/dist/factories/external-dns/resources/helm.d.ts +1 -1
- package/dist/factories/external-dns/resources/helm.d.ts.map +1 -1
- package/dist/factories/external-dns/resources/helm.js +17 -10
- package/dist/factories/external-dns/resources/helm.js.map +1 -1
- package/dist/factories/external-dns/types.d.ts +5 -2
- package/dist/factories/external-dns/types.d.ts.map +1 -1
- package/dist/factories/external-dns/types.js.map +1 -1
- package/dist/factories/flux/git-repository.d.ts.map +1 -1
- package/dist/factories/flux/git-repository.js +1 -1
- package/dist/factories/flux/git-repository.js.map +1 -1
- package/dist/factories/flux/kustomize/kustomization.d.ts +2 -2
- package/dist/factories/flux/kustomize/kustomization.d.ts.map +1 -1
- package/dist/factories/flux/kustomize/readiness-evaluators.d.ts +1 -1
- package/dist/factories/flux/kustomize/readiness-evaluators.d.ts.map +1 -1
- package/dist/factories/flux/kustomize/readiness-evaluators.js +1 -1
- package/dist/factories/flux/kustomize/readiness-evaluators.js.map +1 -1
- package/dist/factories/helm/helm-release.d.ts +3 -2
- package/dist/factories/helm/helm-release.d.ts.map +1 -1
- package/dist/factories/helm/helm-release.js +1 -0
- package/dist/factories/helm/helm-release.js.map +1 -1
- package/dist/factories/helm/helm-repository.d.ts +1 -1
- package/dist/factories/helm/helm-repository.d.ts.map +1 -1
- package/dist/factories/helm/helm-repository.js +6 -4
- package/dist/factories/helm/helm-repository.js.map +1 -1
- package/dist/factories/helm/readiness-evaluators.d.ts +6 -6
- package/dist/factories/helm/readiness-evaluators.d.ts.map +1 -1
- package/dist/factories/helm/readiness-evaluators.js +15 -9
- package/dist/factories/helm/readiness-evaluators.js.map +1 -1
- package/dist/factories/helm/types.d.ts +5 -1
- package/dist/factories/helm/types.d.ts.map +1 -1
- package/dist/factories/inngest/compositions/inngest-bootstrap.d.ts +1 -0
- package/dist/factories/inngest/compositions/inngest-bootstrap.d.ts.map +1 -1
- package/dist/factories/inngest/compositions/inngest-bootstrap.js +4 -3
- package/dist/factories/inngest/compositions/inngest-bootstrap.js.map +1 -1
- package/dist/factories/inngest/resources/helm.js +1 -1
- package/dist/factories/inngest/resources/helm.js.map +1 -1
- package/dist/factories/inngest/types.d.ts +5 -4
- package/dist/factories/inngest/types.d.ts.map +1 -1
- package/dist/factories/inngest/types.js +2 -0
- package/dist/factories/inngest/types.js.map +1 -1
- package/dist/factories/kro/kro-custom-resource.js +1 -1
- package/dist/factories/kro/kro-custom-resource.js.map +1 -1
- package/dist/factories/kubernetes/config/config-map.d.ts +2 -2
- package/dist/factories/kubernetes/config/config-map.d.ts.map +1 -1
- package/dist/factories/kubernetes/config/secret.d.ts +2 -2
- package/dist/factories/kubernetes/config/secret.d.ts.map +1 -1
- package/dist/factories/kubernetes/networking/service.js +1 -1
- package/dist/factories/kubernetes/networking/service.js.map +1 -1
- package/dist/factories/kubernetes/yaml/yaml-directory.d.ts.map +1 -1
- package/dist/factories/kubernetes/yaml/yaml-directory.js +9 -0
- package/dist/factories/kubernetes/yaml/yaml-directory.js.map +1 -1
- package/dist/factories/kubernetes/yaml/yaml-file.d.ts.map +1 -1
- package/dist/factories/kubernetes/yaml/yaml-file.js +9 -0
- package/dist/factories/kubernetes/yaml/yaml-file.js.map +1 -1
- package/dist/factories/pebble/resources/helm.js.map +1 -1
- package/dist/factories/pebble/types.d.ts +2 -2
- package/dist/factories/searxng/compositions/searxng-bootstrap.d.ts +3 -2
- package/dist/factories/searxng/compositions/searxng-bootstrap.d.ts.map +1 -1
- package/dist/factories/searxng/compositions/searxng-bootstrap.js +205 -167
- package/dist/factories/searxng/compositions/searxng-bootstrap.js.map +1 -1
- package/dist/factories/searxng/resources/searxng.d.ts +1 -1
- package/dist/factories/searxng/resources/searxng.js +1 -1
- package/dist/factories/searxng/types.d.ts +5 -4
- package/dist/factories/searxng/types.d.ts.map +1 -1
- package/dist/factories/searxng/types.js +8 -7
- package/dist/factories/searxng/types.js.map +1 -1
- package/dist/factories/searxng/utils/settings-builder.d.ts +4 -3
- package/dist/factories/searxng/utils/settings-builder.d.ts.map +1 -1
- package/dist/factories/searxng/utils/settings-builder.js +4 -3
- package/dist/factories/searxng/utils/settings-builder.js.map +1 -1
- package/dist/factories/simple/config/config-map.d.ts +2 -2
- package/dist/factories/simple/config/config-map.d.ts.map +1 -1
- package/dist/factories/simple/config/secret.d.ts +2 -2
- package/dist/factories/simple/config/secret.d.ts.map +1 -1
- package/dist/factories/simple/helm/index.d.ts +1 -1
- package/dist/factories/simple/helm/index.d.ts.map +1 -1
- package/dist/factories/simple/helm/index.js.map +1 -1
- package/dist/factories/simple/storage/persistent-volume.js.map +1 -1
- package/dist/factories/simple/types.d.ts +11 -1
- package/dist/factories/simple/types.d.ts.map +1 -1
- package/dist/factories/simple/workloads/deployment.d.ts.map +1 -1
- package/dist/factories/simple/workloads/deployment.js +3 -0
- package/dist/factories/simple/workloads/deployment.js.map +1 -1
- package/dist/factories/valkey/compositions/valkey-bootstrap.d.ts +1 -0
- package/dist/factories/valkey/compositions/valkey-bootstrap.d.ts.map +1 -1
- package/dist/factories/valkey/compositions/valkey-bootstrap.js +116 -0
- package/dist/factories/valkey/compositions/valkey-bootstrap.js.map +1 -1
- package/dist/factories/valkey/resources/valkey.js +1 -1
- package/dist/factories/valkey/resources/valkey.js.map +1 -1
- package/dist/factories/valkey/types.d.ts +6 -5
- package/dist/factories/valkey/types.d.ts.map +1 -1
- package/dist/factories/valkey/types.js +10 -0
- package/dist/factories/valkey/types.js.map +1 -1
- package/dist/factories/webapp/compositions/web-app-with-processing.d.ts +90 -6
- package/dist/factories/webapp/compositions/web-app-with-processing.d.ts.map +1 -1
- package/dist/factories/webapp/compositions/web-app-with-processing.js +180 -20
- package/dist/factories/webapp/compositions/web-app-with-processing.js.map +1 -1
- package/dist/factories/webapp/index.d.ts +3 -4
- package/dist/factories/webapp/index.d.ts.map +1 -1
- package/dist/factories/webapp/index.js +3 -4
- package/dist/factories/webapp/index.js.map +1 -1
- package/dist/factories/webapp/types.d.ts +60 -2
- package/dist/factories/webapp/types.d.ts.map +1 -1
- package/dist/factories/webapp/types.js +80 -3
- package/dist/factories/webapp/types.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/shared/brands.d.ts +18 -8
- package/dist/shared/brands.d.ts.map +1 -1
- package/dist/shared/brands.js +19 -9
- package/dist/shared/brands.js.map +1 -1
- package/dist/utils/cel-escape.d.ts +12 -0
- package/dist/utils/cel-escape.d.ts.map +1 -0
- package/dist/utils/cel-escape.js +19 -0
- package/dist/utils/cel-escape.js.map +1 -0
- package/package.json +3 -2
|
@@ -8,18 +8,23 @@ import * as yaml from 'js-yaml';
|
|
|
8
8
|
import { toCamelCase } from '../../utils/string.js';
|
|
9
9
|
import { isCelExpression, isKubernetesRef } from '../../utils/type-guards.js';
|
|
10
10
|
import { createCompositionContext, runWithCompositionContext } from '../composition/context.js';
|
|
11
|
+
import { buildNestedCompositionAliasTargets } from '../composition/nested-status-cel.js';
|
|
12
|
+
import { KUBERNETES_REF_SCHEMA_MARKER_SOURCE } from '../constants/brands.js';
|
|
11
13
|
import { DEFAULT_DELETE_TIMEOUT, DEFAULT_FAST_POLL_INTERVAL, DEFAULT_MAX_RECURSION_DEPTH, } from '../config/defaults.js';
|
|
12
14
|
import { DependencyResolver } from '../dependencies/index.js';
|
|
15
|
+
import { BUILT_IN_GVKS } from './deployment-state-discovery.js';
|
|
13
16
|
import { ensureError, ResourceGraphFactoryError, TypeKroError, ValidationError, } from '../errors.js';
|
|
14
17
|
import { getComponentLogger } from '../logging/index.js';
|
|
15
|
-
import { copyResourceMetadata, getResourceId, setResourceId } from '../metadata/index.js';
|
|
18
|
+
import { copyResourceMetadata, getMetadataField, getResourceId, setResourceId } from '../metadata/index.js';
|
|
19
|
+
import { logHandleSnapshot } from './handle-tracing.js';
|
|
16
20
|
import { KubernetesClientManager } from './client-provider-manager.js';
|
|
17
21
|
import { DirectDeploymentEngine } from './engine.js';
|
|
18
22
|
import { synthesizeNestedCompositionStatus } from './nested-composition-status.js';
|
|
19
23
|
import { ResourceReadinessChecker } from './readiness.js';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
24
|
+
import { generateInstanceName, getSingletonInstanceName, validateSpec } from './shared-utilities.js';
|
|
25
|
+
import { assertNoDeployedSingletonSpecDrift, assertNoDiscoveredSingletonSpecDrift, singletonSpecFingerprintAnnotationValue, } from './singleton-owner-drift.js';
|
|
22
26
|
import { AlchemyDeploymentStrategy, DirectDeploymentStrategy } from './strategies/index.js';
|
|
27
|
+
import { getSingletonResourceId } from '../singleton/singleton.js';
|
|
23
28
|
/**
|
|
24
29
|
* DirectResourceFactory implementation
|
|
25
30
|
*
|
|
@@ -34,14 +39,19 @@ export class DirectResourceFactoryImpl {
|
|
|
34
39
|
resources;
|
|
35
40
|
closures;
|
|
36
41
|
schemaDefinition;
|
|
42
|
+
// biome-ignore lint/suspicious/noExplicitAny: status builders accept composition-specific resource maps that cannot be expressed more tightly here.
|
|
37
43
|
statusBuilder;
|
|
38
44
|
deploymentEngine;
|
|
39
45
|
alchemyScope;
|
|
40
46
|
factoryOptions;
|
|
47
|
+
singletonDefinitions;
|
|
48
|
+
singletonOwnerStatuses = new Map();
|
|
41
49
|
deployedInstances = new Map();
|
|
42
50
|
logger = getComponentLogger('direct-factory');
|
|
43
51
|
clientManager;
|
|
44
|
-
constructor(name, resources, schemaDefinition,
|
|
52
|
+
constructor(name, resources, schemaDefinition,
|
|
53
|
+
// biome-ignore lint/suspicious/noExplicitAny: constructor must preserve the generic status-builder resource map contract.
|
|
54
|
+
statusBuilder, options = {}) {
|
|
45
55
|
this.name = name;
|
|
46
56
|
this.namespace = options.namespace || 'default';
|
|
47
57
|
this.alchemyScope = options.alchemyScope;
|
|
@@ -51,6 +61,7 @@ export class DirectResourceFactoryImpl {
|
|
|
51
61
|
this.schemaDefinition = schemaDefinition;
|
|
52
62
|
this.statusBuilder = statusBuilder;
|
|
53
63
|
this.factoryOptions = options;
|
|
64
|
+
this.singletonDefinitions = options.singletonDefinitions ?? [];
|
|
54
65
|
this.clientManager = new KubernetesClientManager(options);
|
|
55
66
|
}
|
|
56
67
|
/**
|
|
@@ -59,6 +70,29 @@ export class DirectResourceFactoryImpl {
|
|
|
59
70
|
getClientProvider() {
|
|
60
71
|
return this.clientManager.getClientProvider();
|
|
61
72
|
}
|
|
73
|
+
getDebugState() {
|
|
74
|
+
return {
|
|
75
|
+
mode: this.mode,
|
|
76
|
+
namespace: this.namespace,
|
|
77
|
+
deployedInstances: this.deployedInstances.size,
|
|
78
|
+
hasDeploymentEngine: !!this.deploymentEngine,
|
|
79
|
+
clientManager: this.clientManager.getDebugState(),
|
|
80
|
+
deploymentEngine: this.deploymentEngine?.getDebugState(),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
async dispose() {
|
|
84
|
+
logHandleSnapshot(this.logger, 'direct-factory.dispose.before', {
|
|
85
|
+
factoryState: this.getDebugState(),
|
|
86
|
+
});
|
|
87
|
+
if (this.deploymentEngine) {
|
|
88
|
+
await this.deploymentEngine.dispose();
|
|
89
|
+
this.deploymentEngine = undefined;
|
|
90
|
+
}
|
|
91
|
+
this.clientManager.dispose();
|
|
92
|
+
logHandleSnapshot(this.logger, 'direct-factory.dispose.after', {
|
|
93
|
+
factoryState: this.getDebugState(),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
62
96
|
/**
|
|
63
97
|
* Get or create the deployment engine using the centralized client provider
|
|
64
98
|
*/
|
|
@@ -81,17 +115,22 @@ export class DirectResourceFactoryImpl {
|
|
|
81
115
|
/**
|
|
82
116
|
* Deploy a new instance with the given spec
|
|
83
117
|
*/
|
|
84
|
-
async deploy(spec) {
|
|
118
|
+
async deploy(spec, opts) {
|
|
85
119
|
this.logger.debug('DirectResourceFactory deploy called', {
|
|
86
120
|
factoryName: this.name,
|
|
87
121
|
hasStatusBuilder: !!this.statusBuilder,
|
|
88
122
|
});
|
|
123
|
+
validateSpec(spec, this.schemaDefinition, {
|
|
124
|
+
kind: this.schemaDefinition.kind,
|
|
125
|
+
name: this.name,
|
|
126
|
+
});
|
|
89
127
|
// Use the consolidated deployment strategy
|
|
90
128
|
const strategy = this.getDeploymentStrategy();
|
|
91
129
|
this.logger.debug('Got deployment strategy', {
|
|
92
130
|
strategyType: strategy.constructor.name,
|
|
93
131
|
});
|
|
94
|
-
|
|
132
|
+
await this.ensureSingletonOwners(spec);
|
|
133
|
+
const instance = await strategy.deploy(spec, opts);
|
|
95
134
|
// Check if deployment failed and throw for user-facing error handling
|
|
96
135
|
if (instance.metadata?.annotations?.['typekro.io/deployment-status'] === 'failed') {
|
|
97
136
|
const errorMessage = instance.metadata?.annotations?.['typekro.io/deployment-error'] ||
|
|
@@ -99,7 +138,7 @@ export class DirectResourceFactoryImpl {
|
|
|
99
138
|
throw new ResourceGraphFactoryError(errorMessage, this.name, 'deployment');
|
|
100
139
|
}
|
|
101
140
|
// Track the deployed instance
|
|
102
|
-
const instanceName = this.generateInstanceName(spec);
|
|
141
|
+
const instanceName = opts?.instanceNameOverride ?? this.generateInstanceName(spec);
|
|
103
142
|
this.deployedInstances.set(instanceName, instance);
|
|
104
143
|
return instance;
|
|
105
144
|
}
|
|
@@ -118,35 +157,58 @@ export class DirectResourceFactoryImpl {
|
|
|
118
157
|
}
|
|
119
158
|
/**
|
|
120
159
|
* Get all deployed instances
|
|
160
|
+
*
|
|
161
|
+
* Direct mode currently reports same-process instances only. Cross-process
|
|
162
|
+
* discovery is implemented for `deleteInstance(name)`, but reconstructing
|
|
163
|
+
* fully typed Enhanced instances from live tagged resources is intentionally
|
|
164
|
+
* not attempted here.
|
|
121
165
|
*/
|
|
122
166
|
async getInstances() {
|
|
123
167
|
return Array.from(this.deployedInstances.values());
|
|
124
168
|
}
|
|
125
169
|
/**
|
|
126
|
-
* Delete a specific instance by name
|
|
170
|
+
* Delete a specific instance by name.
|
|
171
|
+
*
|
|
172
|
+
* Lookup order:
|
|
173
|
+
* 1. In-memory `deployedInstances` Map (same-process path) — uses
|
|
174
|
+
* the deployment-id annotation on the Enhanced instance proxy.
|
|
175
|
+
* 2. Cluster-side label discovery (cross-process path) — queries
|
|
176
|
+
* for all resources labeled `typekro.io/factory-name=<factory>,
|
|
177
|
+
* typekro.io/instance-name=<instance>`, reconstructs the
|
|
178
|
+
* dependency graph from per-resource `typekro.io/depends-on`
|
|
179
|
+
* annotations, and performs reverse-topological deletion.
|
|
180
|
+
*
|
|
181
|
+
* Both paths feed into the same graph-based reverse-topological
|
|
182
|
+
* delete via `engine.rollbackRecord`.
|
|
183
|
+
*
|
|
184
|
+
* **Scope filtering**: By default, unscoped (instance-private)
|
|
185
|
+
* resources are deleted and scoped resources are preserved. Pass
|
|
186
|
+
* `opts.scopes` to include broader-scope resources additively:
|
|
187
|
+
*
|
|
188
|
+
* ```ts
|
|
189
|
+
* await factory.deleteInstance('my-app'); // unscoped only (safe default)
|
|
190
|
+
* await factory.deleteInstance('my-app', { scopes: ['cluster'] }); // unscoped + cluster
|
|
191
|
+
* await factory.deleteInstance('my-app', { scopes: ['cluster'],
|
|
192
|
+
* includeUnscopedResources: false }); // cluster-only (leave app running)
|
|
193
|
+
* ```
|
|
127
194
|
*/
|
|
128
|
-
async deleteInstance(name) {
|
|
129
|
-
const
|
|
130
|
-
if (!instance) {
|
|
131
|
-
throw new TypeKroError(`Instance not found: ${name}`, 'INSTANCE_NOT_FOUND', {
|
|
132
|
-
instanceName: name,
|
|
133
|
-
factoryName: this.name,
|
|
134
|
-
});
|
|
135
|
-
}
|
|
195
|
+
async deleteInstance(name, opts) {
|
|
196
|
+
const engine = this.getDeploymentEngine();
|
|
136
197
|
try {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
198
|
+
const rollbackResult = await this.rollbackInstanceResources(name, opts);
|
|
199
|
+
if (rollbackResult.status !== 'success' || rollbackResult.errors.length > 0) {
|
|
200
|
+
const errorSummary = rollbackResult.errors
|
|
201
|
+
.map((error) => `${error.resourceId}: ${ensureError(error.error).message}`)
|
|
202
|
+
.join('; ');
|
|
203
|
+
throw new Error(`Cleanup incomplete for instance ${name}: rollback ${rollbackResult.status}${errorSummary ? ` (${errorSummary})` : ''}`);
|
|
142
204
|
}
|
|
143
|
-
const rollbackResult = await engine.rollback(deploymentId);
|
|
144
205
|
// Wait for any namespaces to be fully deleted before returning.
|
|
145
206
|
// Namespace deletion is asynchronous (enters "Terminating" phase) and can
|
|
146
207
|
// cause race conditions if the caller immediately re-creates resources.
|
|
147
208
|
const deletedNamespaces = rollbackResult.rolledBackResources
|
|
148
209
|
.filter((r) => r.startsWith('Namespace/'))
|
|
149
|
-
.map((r) => r.split('/')[1])
|
|
210
|
+
.map((r) => r.split('/')[1])
|
|
211
|
+
.filter((namespace) => namespace !== undefined);
|
|
150
212
|
if (deletedNamespaces.length > 0) {
|
|
151
213
|
// Delete PVCs in namespaces before waiting — StatefulSet PVCs have
|
|
152
214
|
// finalizers that block namespace termination until volumes are released.
|
|
@@ -192,17 +254,81 @@ export class DirectResourceFactoryImpl {
|
|
|
192
254
|
this.deployedInstances.delete(name);
|
|
193
255
|
}
|
|
194
256
|
catch (error) {
|
|
195
|
-
//
|
|
196
|
-
//
|
|
257
|
+
// INSTANCE_NOT_FOUND bubbles up — the caller asked us to delete
|
|
258
|
+
// an instance that has neither in-memory state nor a persisted
|
|
259
|
+
// record. That's a legitimate error (wrong name, already cleaned
|
|
260
|
+
// up) and the caller needs to see it.
|
|
261
|
+
if (error instanceof TypeKroError && error.code === 'INSTANCE_NOT_FOUND') {
|
|
262
|
+
throw error;
|
|
263
|
+
}
|
|
264
|
+
// Soft-swallow "Cannot rollback" errors from the engine —
|
|
265
|
+
// they indicate the engine's in-memory deployment state has
|
|
266
|
+
// already been cleaned up (e.g., by a previous rollback call).
|
|
267
|
+
// The instance is effectively gone, so we remove from tracking.
|
|
197
268
|
const errorMessage = ensureError(error).message;
|
|
198
|
-
if (errorMessage.includes('
|
|
269
|
+
if (errorMessage.includes('Cannot rollback')) {
|
|
199
270
|
this.deployedInstances.delete(name);
|
|
200
|
-
// Don't throw - the instance is already gone
|
|
201
271
|
return;
|
|
202
272
|
}
|
|
203
273
|
throw new ResourceGraphFactoryError(`Failed to delete instance ${name}: ${errorMessage}`, this.name, 'cleanup');
|
|
204
274
|
}
|
|
205
275
|
}
|
|
276
|
+
buildKnownGvks() {
|
|
277
|
+
const crdHints = new Map();
|
|
278
|
+
for (const r of Object.values(this.resources)) {
|
|
279
|
+
if (!r.apiVersion || !r.kind)
|
|
280
|
+
continue;
|
|
281
|
+
const key = `${r.apiVersion}/${r.kind}`;
|
|
282
|
+
if (crdHints.has(key))
|
|
283
|
+
continue;
|
|
284
|
+
const scope = getMetadataField(r, 'scope');
|
|
285
|
+
crdHints.set(key, { apiVersion: r.apiVersion, kind: r.kind, namespaced: scope !== 'cluster' });
|
|
286
|
+
}
|
|
287
|
+
return [
|
|
288
|
+
...BUILT_IN_GVKS,
|
|
289
|
+
...crdHints.values(),
|
|
290
|
+
];
|
|
291
|
+
}
|
|
292
|
+
async rollbackInstanceResources(name, opts) {
|
|
293
|
+
const engine = this.getDeploymentEngine();
|
|
294
|
+
const instance = this.deployedInstances.get(name);
|
|
295
|
+
if (instance) {
|
|
296
|
+
const deploymentId = instance.metadata?.annotations?.['typekro.io/deployment-id'];
|
|
297
|
+
if (deploymentId) {
|
|
298
|
+
try {
|
|
299
|
+
return await engine.rollback(deploymentId, {
|
|
300
|
+
...(opts?.scopes && { scopes: opts.scopes }),
|
|
301
|
+
...(opts?.includeUnscopedResources === false && { includeUnscopedResources: false }),
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
const isNotFound = error instanceof ResourceGraphFactoryError &&
|
|
306
|
+
error.operation === 'cleanup';
|
|
307
|
+
if (!isNotFound) {
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const record = await engine.loadDeploymentByInstance({
|
|
314
|
+
factoryName: this.name,
|
|
315
|
+
instanceName: name,
|
|
316
|
+
knownGvks: this.buildKnownGvks(),
|
|
317
|
+
});
|
|
318
|
+
if (!record) {
|
|
319
|
+
throw new TypeKroError(`Instance not found: ${name} (no in-memory state and no tagged resources on the cluster). The instance may have been cleaned up already, or was deployed with a typekro version that did not tag resources.`, 'INSTANCE_NOT_FOUND', { instanceName: name, factoryName: this.name });
|
|
320
|
+
}
|
|
321
|
+
this.logger.info('Cross-process cleanup: discovered deployment from cluster labels', {
|
|
322
|
+
instanceName: name,
|
|
323
|
+
factoryName: this.name,
|
|
324
|
+
deploymentId: record.deploymentId,
|
|
325
|
+
resourceCount: record.resources.length,
|
|
326
|
+
});
|
|
327
|
+
return engine.rollbackRecord(record, {
|
|
328
|
+
...(opts?.scopes && { scopes: opts.scopes }),
|
|
329
|
+
...(opts?.includeUnscopedResources === false && { includeUnscopedResources: false }),
|
|
330
|
+
});
|
|
331
|
+
}
|
|
206
332
|
/**
|
|
207
333
|
* Poll until the given namespaces no longer exist (HTTP 404).
|
|
208
334
|
* Namespaces enter a "Terminating" phase on deletion and may take time
|
|
@@ -214,6 +340,7 @@ export class DirectResourceFactoryImpl {
|
|
|
214
340
|
for (const ns of namespaces) {
|
|
215
341
|
// Each namespace gets its own timeout budget
|
|
216
342
|
const nsStartTime = Date.now();
|
|
343
|
+
let deleted = false;
|
|
217
344
|
while (Date.now() - nsStartTime < timeout) {
|
|
218
345
|
try {
|
|
219
346
|
await k8sApi.read({
|
|
@@ -229,20 +356,28 @@ export class DirectResourceFactoryImpl {
|
|
|
229
356
|
const k8sErr = error;
|
|
230
357
|
if (k8sErr.statusCode === 404 || k8sErr.body?.code === 404) {
|
|
231
358
|
this.logger.debug('Namespace fully deleted', { namespace: ns });
|
|
359
|
+
deleted = true;
|
|
232
360
|
break;
|
|
233
361
|
}
|
|
234
|
-
// Unexpected error —
|
|
362
|
+
// Unexpected error — fail loudly so callers do not assume cleanup completed.
|
|
235
363
|
this.logger.warn('Error polling namespace deletion', {
|
|
236
364
|
namespace: ns,
|
|
237
365
|
error: ensureError(error).message,
|
|
238
366
|
});
|
|
239
|
-
|
|
367
|
+
throw error;
|
|
240
368
|
}
|
|
241
369
|
}
|
|
370
|
+
if (!deleted) {
|
|
371
|
+
throw new ResourceGraphFactoryError(`Timed out waiting for namespace ${ns} to be deleted after ${timeout}ms`, this.name, 'cleanup');
|
|
372
|
+
}
|
|
242
373
|
}
|
|
243
374
|
}
|
|
244
375
|
/**
|
|
245
376
|
* Get factory status with real health checking using readiness evaluators
|
|
377
|
+
*
|
|
378
|
+
* Direct mode status is based on same-process instances returned by
|
|
379
|
+
* `getInstances()`. Use `deleteInstance(name)` for cross-process cleanup;
|
|
380
|
+
* status reconstruction from tagged live resources is not currently exposed.
|
|
246
381
|
*/
|
|
247
382
|
async getStatus() {
|
|
248
383
|
const instances = await this.getInstances();
|
|
@@ -460,27 +595,60 @@ export class DirectResourceFactoryImpl {
|
|
|
460
595
|
}
|
|
461
596
|
/**
|
|
462
597
|
* Rollback all deployments made by this factory
|
|
598
|
+
*
|
|
599
|
+
* This rolls back same-process deployments tracked by this factory instance.
|
|
600
|
+
* For cross-process cleanup, call `deleteInstance(name)` with the known
|
|
601
|
+
* instance name so TypeKro can discover tagged resources from the cluster.
|
|
463
602
|
*/
|
|
464
603
|
async rollback() {
|
|
465
604
|
this.logger.debug('Starting rollback for all deployed instances');
|
|
466
|
-
|
|
467
|
-
const
|
|
468
|
-
const kubeConfig = clientProvider.getKubeConfig();
|
|
469
|
-
// Create rollback manager with the provider's KubeConfig
|
|
470
|
-
const rollbackManager = createRollbackManagerWithKubeConfig(kubeConfig);
|
|
471
|
-
// Get all deployed instances as Enhanced resources
|
|
472
|
-
const resourcesToRollback = Array.from(this.deployedInstances.values());
|
|
605
|
+
const startedAt = Date.now();
|
|
606
|
+
const instanceNames = Array.from(this.deployedInstances.keys());
|
|
473
607
|
this.logger.debug('Rolling back resources', {
|
|
474
|
-
|
|
475
|
-
instanceNames
|
|
476
|
-
});
|
|
477
|
-
// Perform rollback using consolidated logic
|
|
478
|
-
const result = await rollbackManager.rollbackResources(resourcesToRollback, {
|
|
479
|
-
timeout: this.factoryOptions.timeout || undefined,
|
|
480
|
-
emitEvent: this.factoryOptions.progressCallback || undefined,
|
|
608
|
+
instanceCount: instanceNames.length,
|
|
609
|
+
instanceNames,
|
|
481
610
|
});
|
|
482
|
-
|
|
483
|
-
|
|
611
|
+
const rolledBackResources = [];
|
|
612
|
+
const errors = [];
|
|
613
|
+
let status = 'success';
|
|
614
|
+
for (const instanceName of instanceNames) {
|
|
615
|
+
try {
|
|
616
|
+
const result = await this.rollbackInstanceResources(instanceName);
|
|
617
|
+
rolledBackResources.push(...result.rolledBackResources);
|
|
618
|
+
errors.push(...result.errors);
|
|
619
|
+
if (result.status === 'failed') {
|
|
620
|
+
status = 'failed';
|
|
621
|
+
}
|
|
622
|
+
else if (result.status === 'partial' && status === 'success') {
|
|
623
|
+
status = 'partial';
|
|
624
|
+
}
|
|
625
|
+
if (result.status === 'success' && result.errors.length === 0) {
|
|
626
|
+
this.deployedInstances.delete(instanceName);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
catch (error) {
|
|
630
|
+
status = 'failed';
|
|
631
|
+
errors.push({
|
|
632
|
+
resourceId: instanceName,
|
|
633
|
+
phase: 'rollback',
|
|
634
|
+
error: ensureError(error),
|
|
635
|
+
timestamp: new Date(),
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
if (errors.length > 0 && status === 'success') {
|
|
640
|
+
status = rolledBackResources.length > 0 ? 'partial' : 'failed';
|
|
641
|
+
}
|
|
642
|
+
const result = {
|
|
643
|
+
deploymentId: `factory-rollback-${Date.now()}`,
|
|
644
|
+
rolledBackResources,
|
|
645
|
+
duration: Date.now() - startedAt,
|
|
646
|
+
status,
|
|
647
|
+
errors,
|
|
648
|
+
};
|
|
649
|
+
if (result.status === 'success') {
|
|
650
|
+
this.deployedInstances.clear();
|
|
651
|
+
}
|
|
484
652
|
this.logger.info('Rollback completed', {
|
|
485
653
|
status: result.status,
|
|
486
654
|
resourceCount: result.rolledBackResources.length,
|
|
@@ -572,10 +740,10 @@ export class DirectResourceFactoryImpl {
|
|
|
572
740
|
/**
|
|
573
741
|
* Create a resource graph for a specific instance
|
|
574
742
|
*/
|
|
575
|
-
createResourceGraphForInstance(spec) {
|
|
743
|
+
createResourceGraphForInstance(spec, instanceNameOverride) {
|
|
576
744
|
const dependencyResolver = new DependencyResolver();
|
|
577
745
|
const resolvedResources = this.resolveResourcesForSpec(spec);
|
|
578
|
-
const instanceName = this.generateInstanceName(spec);
|
|
746
|
+
const instanceName = instanceNameOverride ?? this.generateInstanceName(spec);
|
|
579
747
|
const resourceArray = Object.values(resolvedResources).map((resource, index) => {
|
|
580
748
|
this.logger.debug('Processing resource for ID generation', {
|
|
581
749
|
index,
|
|
@@ -662,7 +830,8 @@ export class DirectResourceFactoryImpl {
|
|
|
662
830
|
}
|
|
663
831
|
}
|
|
664
832
|
catch (error) {
|
|
665
|
-
this.logger.error('Failed to re-execute composition
|
|
833
|
+
this.logger.error('Failed to re-execute composition with actual spec values', ensureError(error));
|
|
834
|
+
throw error;
|
|
666
835
|
}
|
|
667
836
|
}
|
|
668
837
|
// Fall back to the original reference resolution approach
|
|
@@ -699,6 +868,7 @@ export class DirectResourceFactoryImpl {
|
|
|
699
868
|
// with the same id (e.g., 'regionDep') get unique keys ('regionDep', 'regionDep-1', etc.)
|
|
700
869
|
const reExecutionContext = createCompositionContext('re-execution', {
|
|
701
870
|
deduplicateIds: true,
|
|
871
|
+
isReExecution: true,
|
|
702
872
|
});
|
|
703
873
|
// Execute the composition function within the new context and capture both resources and status
|
|
704
874
|
const { resources, status } = runWithCompositionContext(reExecutionContext, () => {
|
|
@@ -737,7 +907,7 @@ export class DirectResourceFactoryImpl {
|
|
|
737
907
|
}
|
|
738
908
|
catch (error) {
|
|
739
909
|
this.logger.error('Failed to re-execute composition', ensureError(error));
|
|
740
|
-
|
|
910
|
+
throw error;
|
|
741
911
|
}
|
|
742
912
|
}
|
|
743
913
|
/**
|
|
@@ -747,6 +917,22 @@ export class DirectResourceFactoryImpl {
|
|
|
747
917
|
getReExecutedStatus() {
|
|
748
918
|
return this.reExecutedStatus;
|
|
749
919
|
}
|
|
920
|
+
reExecuteSingletonStatus(singletonDefinition, liveStatusMap) {
|
|
921
|
+
const compositionFn = singletonDefinition.composition._compositionFn;
|
|
922
|
+
if (!compositionFn) {
|
|
923
|
+
return undefined;
|
|
924
|
+
}
|
|
925
|
+
const singletonContext = createCompositionContext('singleton-re-execution', {
|
|
926
|
+
deduplicateIds: true,
|
|
927
|
+
isReExecution: true,
|
|
928
|
+
});
|
|
929
|
+
singletonContext.liveStatusMap = liveStatusMap;
|
|
930
|
+
const status = runWithCompositionContext(singletonContext, () => compositionFn(singletonDefinition.spec));
|
|
931
|
+
if (status && typeof status === 'object' && !Array.isArray(status)) {
|
|
932
|
+
return status;
|
|
933
|
+
}
|
|
934
|
+
return undefined;
|
|
935
|
+
}
|
|
750
936
|
/**
|
|
751
937
|
* Re-execute the composition with live status data from deployed resources.
|
|
752
938
|
*
|
|
@@ -773,6 +959,7 @@ export class DirectResourceFactoryImpl {
|
|
|
773
959
|
// synthesize status entries from child resources' live data.
|
|
774
960
|
const probeContext = createCompositionContext('re-execution-probe', {
|
|
775
961
|
deduplicateIds: true,
|
|
962
|
+
isReExecution: true,
|
|
776
963
|
});
|
|
777
964
|
probeContext.liveStatusMap = liveStatusMap;
|
|
778
965
|
runWithCompositionContext(probeContext, () => {
|
|
@@ -787,10 +974,41 @@ export class DirectResourceFactoryImpl {
|
|
|
787
974
|
// This uses synthesizeNestedCompositionStatus which is shared between
|
|
788
975
|
// direct and KRO deployment strategies — it only depends on the probe
|
|
789
976
|
// context's resource keys and the liveStatusMap's deployed resource keys.
|
|
790
|
-
const enrichedMap = synthesizeNestedCompositionStatus(probeContext.resources, liveStatusMap, this.logger, probeContext.nestedCompositionIds);
|
|
977
|
+
const enrichedMap = synthesizeNestedCompositionStatus(probeContext.resources, liveStatusMap, this.logger, probeContext.nestedCompositionIds, probeContext.nestedStatusSnapshots);
|
|
978
|
+
// Framework invariant: direct-mode re-execution must preserve the same
|
|
979
|
+
// cross-composition semantics as KRO-mode serialization. If a user writes
|
|
980
|
+
// `const stack = nestedComp(...); return { ready: stack.status.ready && ... }`,
|
|
981
|
+
// TypeKro must resolve that alias in the framework rather than pushing
|
|
982
|
+
// CEL-specific workarounds into composition code.
|
|
983
|
+
const aliasTargets = buildNestedCompositionAliasTargets(this.factoryOptions.compositionFn.toString(), probeContext.nestedCompositionIds);
|
|
984
|
+
for (const [aliasName, baseId] of Object.entries(aliasTargets)) {
|
|
985
|
+
const synthesizedStatus = enrichedMap.get(baseId);
|
|
986
|
+
if (synthesizedStatus && !enrichedMap.has(aliasName)) {
|
|
987
|
+
enrichedMap.set(aliasName, synthesizedStatus);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
const singletonDefinitions = new Map();
|
|
991
|
+
for (const definition of this.singletonDefinitions) {
|
|
992
|
+
singletonDefinitions.set(definition.key, definition);
|
|
993
|
+
}
|
|
994
|
+
for (const definition of probeContext.singletonDefinitions?.values() ?? []) {
|
|
995
|
+
singletonDefinitions.set(definition.key, definition);
|
|
996
|
+
}
|
|
997
|
+
for (const definition of singletonDefinitions.values()) {
|
|
998
|
+
const singletonResourceId = getSingletonResourceId(definition.key);
|
|
999
|
+
if (enrichedMap.has(singletonResourceId)) {
|
|
1000
|
+
continue;
|
|
1001
|
+
}
|
|
1002
|
+
const singletonStatus = this.singletonOwnerStatuses.get(singletonResourceId) ??
|
|
1003
|
+
this.reExecuteSingletonStatus(definition, liveStatusMap);
|
|
1004
|
+
if (singletonStatus) {
|
|
1005
|
+
enrichedMap.set(singletonResourceId, singletonStatus);
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
791
1008
|
// Phase 2: Real execution with enriched live status map
|
|
792
1009
|
const reExecutionContext = createCompositionContext('re-execution', {
|
|
793
1010
|
deduplicateIds: true,
|
|
1011
|
+
isReExecution: true,
|
|
794
1012
|
});
|
|
795
1013
|
reExecutionContext.liveStatusMap = enrichedMap;
|
|
796
1014
|
const { status } = runWithCompositionContext(reExecutionContext, () => {
|
|
@@ -920,6 +1138,19 @@ export class DirectResourceFactoryImpl {
|
|
|
920
1138
|
}
|
|
921
1139
|
return { found: true, value: currentValue };
|
|
922
1140
|
}
|
|
1141
|
+
resolveSpecPathValue(spec, specPath, logPath) {
|
|
1142
|
+
const pathParts = specPath.split('.').filter(Boolean);
|
|
1143
|
+
return this.traverseSpec(spec, pathParts, logPath);
|
|
1144
|
+
}
|
|
1145
|
+
stringifyCelFallbackValue(value) {
|
|
1146
|
+
if (value === null)
|
|
1147
|
+
return 'null';
|
|
1148
|
+
if (typeof value === 'string')
|
|
1149
|
+
return value;
|
|
1150
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
1151
|
+
return String(value);
|
|
1152
|
+
return JSON.stringify(value);
|
|
1153
|
+
}
|
|
923
1154
|
/**
|
|
924
1155
|
* Resolve schema references and CEL expressions to actual values for direct deployment.
|
|
925
1156
|
* This is the final, corrected version that handles both direct proxies and Cel.expr wrappers.
|
|
@@ -949,15 +1180,24 @@ export class DirectResourceFactoryImpl {
|
|
|
949
1180
|
this.logger.trace('Found CEL Expression', { path, expression: resource.expression });
|
|
950
1181
|
// The .expression property holds a string like "schema.spec.name-db-config"
|
|
951
1182
|
let expressionString = resource.expression;
|
|
1183
|
+
const exactSchemaRef = expressionString.match(/^schema\.spec\.([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)$/);
|
|
1184
|
+
const exactSpecPath = exactSchemaRef?.[1];
|
|
1185
|
+
if (exactSpecPath !== undefined) {
|
|
1186
|
+
const resolved = this.resolveSpecPathValue(spec, exactSpecPath, path);
|
|
1187
|
+
if (resolved.found) {
|
|
1188
|
+
return resolved.value;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
952
1191
|
// Use regex to find all `schema.spec.fieldName` placeholders in the string
|
|
953
1192
|
// and replace them with the corresponding values from the spec object.
|
|
954
1193
|
// The 'g' flag ensures all occurrences are replaced.
|
|
955
|
-
expressionString = expressionString.replace(/schema\.spec\.(\w
|
|
956
|
-
const
|
|
957
|
-
|
|
1194
|
+
expressionString = expressionString.replace(/schema\.spec\.([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)/g, (_match, specPath) => {
|
|
1195
|
+
const resolved = this.resolveSpecPathValue(spec, specPath, path);
|
|
1196
|
+
const value = resolved.found ? resolved.value : undefined;
|
|
1197
|
+
this.logger.trace('Replacing CEL placeholder', { specPath, value });
|
|
958
1198
|
// If the value exists in the spec, convert it to a string for concatenation.
|
|
959
1199
|
// Otherwise, keep the original placeholder (though this shouldn't happen in valid cases).
|
|
960
|
-
return value !== undefined ?
|
|
1200
|
+
return value !== undefined ? this.stringifyCelFallbackValue(value) : _match;
|
|
961
1201
|
});
|
|
962
1202
|
this.logger.trace('Resolved CEL expression to value', {
|
|
963
1203
|
path,
|
|
@@ -1007,7 +1247,7 @@ export class DirectResourceFactoryImpl {
|
|
|
1007
1247
|
// Pattern: __KUBERNETES_REF_{resourceId}_{fieldPath}__
|
|
1008
1248
|
// For schema: __KUBERNETES_REF___schema___{fieldPath}__
|
|
1009
1249
|
// The fieldPath for schema refs is like "spec.baseName" or "spec.nested.field"
|
|
1010
|
-
const resolvedString = resource.replace(
|
|
1250
|
+
const resolvedString = resource.replace(new RegExp(KUBERNETES_REF_SCHEMA_MARKER_SOURCE, 'g'), (_match, fieldPath) => {
|
|
1011
1251
|
// fieldPath is like "spec.baseName" - we need to traverse starting from the schema root
|
|
1012
1252
|
const pathParts = fieldPath.split('.');
|
|
1013
1253
|
// The first part should be 'spec' or 'status'
|
|
@@ -1050,6 +1290,259 @@ export class DirectResourceFactoryImpl {
|
|
|
1050
1290
|
// Use the imported shared utility
|
|
1051
1291
|
return generateInstanceName(spec);
|
|
1052
1292
|
}
|
|
1293
|
+
async ensureTargetNamespace(namespace = this.namespace) {
|
|
1294
|
+
try {
|
|
1295
|
+
const { createBunCompatibleKubernetesObjectApi } = await import('../kubernetes/bun-api-client.js');
|
|
1296
|
+
const k8sApi = createBunCompatibleKubernetesObjectApi(this.getClientProvider().getKubeConfig());
|
|
1297
|
+
const waitForNamespaceDeletion = async () => {
|
|
1298
|
+
const start = Date.now();
|
|
1299
|
+
while (Date.now() - start < 120000) {
|
|
1300
|
+
try {
|
|
1301
|
+
const existing = (await k8sApi.read({
|
|
1302
|
+
apiVersion: 'v1',
|
|
1303
|
+
kind: 'Namespace',
|
|
1304
|
+
metadata: { name: namespace },
|
|
1305
|
+
}));
|
|
1306
|
+
if (!existing.metadata?.deletionTimestamp) {
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
catch (pollError) {
|
|
1311
|
+
const err = pollError;
|
|
1312
|
+
const code = err.statusCode ?? err.body?.code;
|
|
1313
|
+
if (code === 404) {
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
throw pollError;
|
|
1317
|
+
}
|
|
1318
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
1319
|
+
}
|
|
1320
|
+
throw new Error(`Namespace ${namespace} is still terminating after 120000ms`);
|
|
1321
|
+
};
|
|
1322
|
+
try {
|
|
1323
|
+
const existing = (await k8sApi.read({
|
|
1324
|
+
apiVersion: 'v1',
|
|
1325
|
+
kind: 'Namespace',
|
|
1326
|
+
metadata: { name: namespace },
|
|
1327
|
+
}));
|
|
1328
|
+
if (existing.metadata?.deletionTimestamp) {
|
|
1329
|
+
await waitForNamespaceDeletion();
|
|
1330
|
+
}
|
|
1331
|
+
else {
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
catch (readError) {
|
|
1336
|
+
const k8sErr = readError;
|
|
1337
|
+
const code = k8sErr.statusCode ?? k8sErr.body?.code;
|
|
1338
|
+
if (code !== 404) {
|
|
1339
|
+
throw readError;
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
try {
|
|
1343
|
+
await k8sApi.create({
|
|
1344
|
+
apiVersion: 'v1',
|
|
1345
|
+
kind: 'Namespace',
|
|
1346
|
+
metadata: {
|
|
1347
|
+
name: namespace,
|
|
1348
|
+
labels: {
|
|
1349
|
+
'app.kubernetes.io/managed-by': 'typekro',
|
|
1350
|
+
},
|
|
1351
|
+
},
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
catch (createError) {
|
|
1355
|
+
const k8sErr = createError;
|
|
1356
|
+
const code = k8sErr.statusCode ?? k8sErr.body?.code;
|
|
1357
|
+
const isNamespaceTerminating = k8sErr.body?.reason === 'Forbidden' &&
|
|
1358
|
+
k8sErr.message?.includes('NamespaceTerminating') === true;
|
|
1359
|
+
if (isNamespaceTerminating) {
|
|
1360
|
+
await waitForNamespaceDeletion();
|
|
1361
|
+
await k8sApi.create({
|
|
1362
|
+
apiVersion: 'v1',
|
|
1363
|
+
kind: 'Namespace',
|
|
1364
|
+
metadata: {
|
|
1365
|
+
name: namespace,
|
|
1366
|
+
labels: {
|
|
1367
|
+
'app.kubernetes.io/managed-by': 'typekro',
|
|
1368
|
+
},
|
|
1369
|
+
},
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
else if (code !== 409) {
|
|
1373
|
+
throw createError;
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
catch (error) {
|
|
1378
|
+
throw new ResourceGraphFactoryError(`Failed to ensure target namespace "${namespace}" exists: ${ensureError(error).message}`, this.name, 'deployment', ensureError(error));
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
async ensureSingletonOwners(spec) {
|
|
1382
|
+
const discoveredSingletons = new Map();
|
|
1383
|
+
if (this.factoryOptions.compositionFn) {
|
|
1384
|
+
const singletonContext = createCompositionContext('singleton-owner-discovery');
|
|
1385
|
+
runWithCompositionContext(singletonContext, () => {
|
|
1386
|
+
this.factoryOptions.compositionFn?.(spec);
|
|
1387
|
+
});
|
|
1388
|
+
for (const [key, definition] of singletonContext.singletonDefinitions ?? []) {
|
|
1389
|
+
discoveredSingletons.set(key, definition);
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
for (const definition of this.singletonDefinitions) {
|
|
1393
|
+
if (!discoveredSingletons.has(definition.key)) {
|
|
1394
|
+
discoveredSingletons.set(definition.key, definition);
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
if (discoveredSingletons.size === 0)
|
|
1398
|
+
return;
|
|
1399
|
+
for (const definition of discoveredSingletons.values()) {
|
|
1400
|
+
await this.ensureTargetNamespace(definition.registryNamespace);
|
|
1401
|
+
const singletonInstanceName = getSingletonInstanceName(definition.id);
|
|
1402
|
+
const singletonFactory = definition.composition.factory('direct', {
|
|
1403
|
+
namespace: definition.registryNamespace,
|
|
1404
|
+
waitForReady: true,
|
|
1405
|
+
...(this.factoryOptions.timeout !== undefined ? { timeout: this.factoryOptions.timeout } : {}),
|
|
1406
|
+
...(this.factoryOptions.kubeConfig !== undefined ? { kubeConfig: this.factoryOptions.kubeConfig } : {}),
|
|
1407
|
+
...(this.factoryOptions.skipTLSVerify !== undefined ? { skipTLSVerify: this.factoryOptions.skipTLSVerify } : {}),
|
|
1408
|
+
});
|
|
1409
|
+
try {
|
|
1410
|
+
const existingInstances = await singletonFactory.getInstances();
|
|
1411
|
+
assertNoDeployedSingletonSpecDrift(definition, singletonInstanceName, existingInstances);
|
|
1412
|
+
if ('createResourceGraphForInstance' in singletonFactory && existingInstances.length === 0) {
|
|
1413
|
+
const discovered = await this.getDeploymentEngine().loadDeploymentByInstance({
|
|
1414
|
+
factoryName: singletonFactory.name,
|
|
1415
|
+
instanceName: singletonInstanceName,
|
|
1416
|
+
});
|
|
1417
|
+
const discoveredResources = discovered?.resources ?? [];
|
|
1418
|
+
const driftCheck = assertNoDiscoveredSingletonSpecDrift(definition, singletonInstanceName, discoveredResources);
|
|
1419
|
+
if (driftCheck.hasLegacyUnfingerprintedResources) {
|
|
1420
|
+
const expectedGraph = singletonFactory.createResourceGraphForInstance(definition.spec, singletonInstanceName);
|
|
1421
|
+
const discoveredIds = new Set(discoveredResources.map((resource) => resource.id));
|
|
1422
|
+
const hasAllExpectedResources = expectedGraph.resources.every((resource) => discoveredIds.has(resource.id));
|
|
1423
|
+
const hasHelmReleaseResources = expectedGraph.resources.some((resource) => resource.manifest.kind === 'HelmRelease');
|
|
1424
|
+
const legacyStatus = this.reExecuteSingletonStatusFromDiscoveredResources(definition, discoveredResources);
|
|
1425
|
+
if (legacyStatus) {
|
|
1426
|
+
this.singletonOwnerStatuses.set(getSingletonResourceId(definition.key), legacyStatus);
|
|
1427
|
+
}
|
|
1428
|
+
if (hasAllExpectedResources && !hasHelmReleaseResources) {
|
|
1429
|
+
this.logger.warn('Skipping direct singleton owner reconciliation for legacy resources without a spec fingerprint', {
|
|
1430
|
+
singletonId: definition.id,
|
|
1431
|
+
singletonKey: definition.key,
|
|
1432
|
+
singletonInstanceName,
|
|
1433
|
+
registryNamespace: definition.registryNamespace,
|
|
1434
|
+
});
|
|
1435
|
+
continue;
|
|
1436
|
+
}
|
|
1437
|
+
this.logger.warn('Reconciling direct singleton owner because legacy resources may need repair', {
|
|
1438
|
+
singletonId: definition.id,
|
|
1439
|
+
singletonKey: definition.key,
|
|
1440
|
+
singletonInstanceName,
|
|
1441
|
+
registryNamespace: definition.registryNamespace,
|
|
1442
|
+
discoveredResourceCount: discoveredResources.length,
|
|
1443
|
+
expectedResourceCount: expectedGraph.resources.length,
|
|
1444
|
+
hasAllExpectedResources,
|
|
1445
|
+
hasHelmReleaseResources,
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
const singletonDeployOptions = {
|
|
1450
|
+
instanceNameOverride: singletonInstanceName,
|
|
1451
|
+
singletonSpecFingerprint: singletonSpecFingerprintAnnotationValue(definition.specFingerprint),
|
|
1452
|
+
};
|
|
1453
|
+
const deployedSingleton = await singletonFactory.deploy(definition.spec, singletonDeployOptions);
|
|
1454
|
+
const singletonStatus = deployedSingleton.status;
|
|
1455
|
+
if (singletonStatus && typeof singletonStatus === 'object' && !Array.isArray(singletonStatus)) {
|
|
1456
|
+
this.singletonOwnerStatuses.set(getSingletonResourceId(definition.key), singletonStatus);
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
finally {
|
|
1460
|
+
await singletonFactory.dispose?.();
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
reExecuteSingletonStatusFromDiscoveredResources(definition, resources) {
|
|
1465
|
+
if (resources.length === 0)
|
|
1466
|
+
return null;
|
|
1467
|
+
const liveStatusMap = new Map();
|
|
1468
|
+
const localIdsByLiveIdentity = this.getSingletonLocalIdsByLiveIdentity(definition);
|
|
1469
|
+
const singletonInstanceName = getSingletonInstanceName(definition.id);
|
|
1470
|
+
for (const resource of resources) {
|
|
1471
|
+
const manifest = resource.manifest;
|
|
1472
|
+
const status = manifest && typeof manifest === 'object' && 'status' in manifest
|
|
1473
|
+
? manifest.status
|
|
1474
|
+
: undefined;
|
|
1475
|
+
const statusRecord = status && typeof status === 'object' && !Array.isArray(status)
|
|
1476
|
+
? status
|
|
1477
|
+
: {};
|
|
1478
|
+
for (const id of this.getSingletonStatusAliases(resource.id, manifest, singletonInstanceName, localIdsByLiveIdentity)) {
|
|
1479
|
+
liveStatusMap.set(id, statusRecord);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
return this.reExecuteSingletonStatus(definition, liveStatusMap) ?? null;
|
|
1483
|
+
}
|
|
1484
|
+
getSingletonLocalIdsByLiveIdentity(definition) {
|
|
1485
|
+
const compositionFn = definition.composition._compositionFn;
|
|
1486
|
+
const idsByIdentity = new Map();
|
|
1487
|
+
if (!compositionFn)
|
|
1488
|
+
return idsByIdentity;
|
|
1489
|
+
const probeContext = createCompositionContext('singleton-status-discovery-probe', {
|
|
1490
|
+
deduplicateIds: true,
|
|
1491
|
+
isReExecution: true,
|
|
1492
|
+
});
|
|
1493
|
+
runWithCompositionContext(probeContext, () => compositionFn(definition.spec));
|
|
1494
|
+
for (const [id, resource] of Object.entries(probeContext.resources)) {
|
|
1495
|
+
const identity = this.getLiveIdentityKey(resource.kind, resource.metadata?.name, resource.metadata?.namespace);
|
|
1496
|
+
if (identity)
|
|
1497
|
+
idsByIdentity.set(identity, id);
|
|
1498
|
+
const namespaceAgnosticIdentity = this.getLiveIdentityKey(resource.kind, resource.metadata?.name);
|
|
1499
|
+
if (namespaceAgnosticIdentity)
|
|
1500
|
+
idsByIdentity.set(namespaceAgnosticIdentity, id);
|
|
1501
|
+
}
|
|
1502
|
+
return idsByIdentity;
|
|
1503
|
+
}
|
|
1504
|
+
getSingletonStatusAliases(discoveredId, manifest, singletonInstanceName, localIdsByLiveIdentity) {
|
|
1505
|
+
const aliases = new Set([discoveredId]);
|
|
1506
|
+
const annotationId = manifest && typeof manifest === 'object'
|
|
1507
|
+
? manifest.metadata?.annotations?.['typekro.io/resource-id']
|
|
1508
|
+
: undefined;
|
|
1509
|
+
if (annotationId)
|
|
1510
|
+
aliases.add(annotationId);
|
|
1511
|
+
const derivedId = this.deriveLocalIdFromDirectGraphId(discoveredId, singletonInstanceName, localIdsByLiveIdentity.values());
|
|
1512
|
+
if (derivedId)
|
|
1513
|
+
aliases.add(derivedId);
|
|
1514
|
+
if (manifest && typeof manifest === 'object') {
|
|
1515
|
+
const resource = manifest;
|
|
1516
|
+
const identity = this.getLiveIdentityKey(resource.kind, resource.metadata?.name, resource.metadata?.namespace);
|
|
1517
|
+
const namespaceAgnosticIdentity = this.getLiveIdentityKey(resource.kind, resource.metadata?.name);
|
|
1518
|
+
const localId = (identity ? localIdsByLiveIdentity.get(identity) : undefined) ??
|
|
1519
|
+
(namespaceAgnosticIdentity ? localIdsByLiveIdentity.get(namespaceAgnosticIdentity) : undefined);
|
|
1520
|
+
if (localId)
|
|
1521
|
+
aliases.add(localId);
|
|
1522
|
+
}
|
|
1523
|
+
return [...aliases];
|
|
1524
|
+
}
|
|
1525
|
+
deriveLocalIdFromDirectGraphId(id, singletonInstanceName, candidateLocalIds = []) {
|
|
1526
|
+
const prefix = `${toCamelCase(singletonInstanceName)}Resource`;
|
|
1527
|
+
const match = id.match(new RegExp(`^${prefix}\\d+(.+)$`));
|
|
1528
|
+
if (!match?.[1])
|
|
1529
|
+
return undefined;
|
|
1530
|
+
const suffix = match[1].charAt(0).toLowerCase() + match[1].slice(1);
|
|
1531
|
+
const normalizedSuffix = suffix.toLowerCase();
|
|
1532
|
+
for (const candidate of candidateLocalIds) {
|
|
1533
|
+
if (candidate === suffix ||
|
|
1534
|
+
candidate.toLowerCase() === normalizedSuffix ||
|
|
1535
|
+
toCamelCase(candidate).toLowerCase() === normalizedSuffix) {
|
|
1536
|
+
return candidate;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
return suffix;
|
|
1540
|
+
}
|
|
1541
|
+
getLiveIdentityKey(kind, name, namespace) {
|
|
1542
|
+
if (!kind || !name)
|
|
1543
|
+
return undefined;
|
|
1544
|
+
return `${kind}/${namespace ?? ''}/${name}`;
|
|
1545
|
+
}
|
|
1053
1546
|
}
|
|
1054
1547
|
/**
|
|
1055
1548
|
* Recursively walk a resolved resource tree and collect any remaining
|
|
@@ -1107,7 +1600,9 @@ function findUnresolvedReferences(resources) {
|
|
|
1107
1600
|
/**
|
|
1108
1601
|
* Create a DirectResourceFactory instance
|
|
1109
1602
|
*/
|
|
1110
|
-
export function createDirectResourceFactory(name, resources, schemaDefinition,
|
|
1603
|
+
export function createDirectResourceFactory(name, resources, schemaDefinition,
|
|
1604
|
+
// biome-ignore lint/suspicious/noExplicitAny: factory creation must accept status builders with composition-specific resource maps.
|
|
1605
|
+
statusBuilder, options = {}) {
|
|
1111
1606
|
return new DirectResourceFactoryImpl(name, resources, schemaDefinition, statusBuilder, options);
|
|
1112
1607
|
}
|
|
1113
1608
|
//# sourceMappingURL=direct-factory.js.map
|