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.
Files changed (510) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/alchemy/deployers.d.ts +16 -1
  3. package/dist/alchemy/deployers.d.ts.map +1 -1
  4. package/dist/alchemy/deployers.js +131 -18
  5. package/dist/alchemy/deployers.js.map +1 -1
  6. package/dist/alchemy/deployment.d.ts +1 -1
  7. package/dist/alchemy/deployment.d.ts.map +1 -1
  8. package/dist/alchemy/deployment.js +1 -1
  9. package/dist/alchemy/deployment.js.map +1 -1
  10. package/dist/alchemy/kro-delete.d.ts +66 -0
  11. package/dist/alchemy/kro-delete.d.ts.map +1 -0
  12. package/dist/alchemy/kro-delete.js +183 -0
  13. package/dist/alchemy/kro-delete.js.map +1 -0
  14. package/dist/alchemy/resource-registration.d.ts +16 -0
  15. package/dist/alchemy/resource-registration.d.ts.map +1 -1
  16. package/dist/alchemy/resource-registration.js +138 -24
  17. package/dist/alchemy/resource-registration.js.map +1 -1
  18. package/dist/alchemy/types.d.ts +8 -4
  19. package/dist/alchemy/types.d.ts.map +1 -1
  20. package/dist/compositions/typekro-runtime/typekro-runtime.d.ts +1 -1
  21. package/dist/compositions/typekro-runtime/typekro-runtime.d.ts.map +1 -1
  22. package/dist/compositions/typekro-runtime/typekro-runtime.js +27 -9
  23. package/dist/compositions/typekro-runtime/typekro-runtime.js.map +1 -1
  24. package/dist/core/composition/context.d.ts +58 -2
  25. package/dist/core/composition/context.d.ts.map +1 -1
  26. package/dist/core/composition/context.js +4 -0
  27. package/dist/core/composition/context.js.map +1 -1
  28. package/dist/core/composition/imperative.d.ts +9 -0
  29. package/dist/core/composition/imperative.d.ts.map +1 -1
  30. package/dist/core/composition/imperative.js +538 -54
  31. package/dist/core/composition/imperative.js.map +1 -1
  32. package/dist/core/composition/nested-status-cel.d.ts +34 -1
  33. package/dist/core/composition/nested-status-cel.d.ts.map +1 -1
  34. package/dist/core/composition/nested-status-cel.js +379 -41
  35. package/dist/core/composition/nested-status-cel.js.map +1 -1
  36. package/dist/core/composition-debugger.d.ts +1 -1
  37. package/dist/core/composition-debugger.d.ts.map +1 -1
  38. package/dist/core/composition-debugger.js.map +1 -1
  39. package/dist/core/constants/brands.d.ts +1 -1
  40. package/dist/core/constants/brands.d.ts.map +1 -1
  41. package/dist/core/constants/brands.js +1 -1
  42. package/dist/core/constants/brands.js.map +1 -1
  43. package/dist/core/containers/build.d.ts.map +1 -1
  44. package/dist/core/containers/build.js +40 -12
  45. package/dist/core/containers/build.js.map +1 -1
  46. package/dist/core/dependencies/resolver.d.ts +19 -0
  47. package/dist/core/dependencies/resolver.d.ts.map +1 -1
  48. package/dist/core/dependencies/resolver.js +261 -1
  49. package/dist/core/dependencies/resolver.js.map +1 -1
  50. package/dist/core/deployment/client-provider-manager.d.ts +9 -3
  51. package/dist/core/deployment/client-provider-manager.d.ts.map +1 -1
  52. package/dist/core/deployment/client-provider-manager.js +12 -0
  53. package/dist/core/deployment/client-provider-manager.js.map +1 -1
  54. package/dist/core/deployment/crd-manager.d.ts +24 -0
  55. package/dist/core/deployment/crd-manager.d.ts.map +1 -1
  56. package/dist/core/deployment/crd-manager.js +79 -1
  57. package/dist/core/deployment/crd-manager.js.map +1 -1
  58. package/dist/core/deployment/deployment-state-discovery.d.ts +116 -0
  59. package/dist/core/deployment/deployment-state-discovery.d.ts.map +1 -0
  60. package/dist/core/deployment/deployment-state-discovery.js +400 -0
  61. package/dist/core/deployment/deployment-state-discovery.js.map +1 -0
  62. package/dist/core/deployment/direct-factory.d.ts +65 -6
  63. package/dist/core/deployment/direct-factory.d.ts.map +1 -1
  64. package/dist/core/deployment/direct-factory.js +551 -56
  65. package/dist/core/deployment/direct-factory.js.map +1 -1
  66. package/dist/core/deployment/engine.d.ts +64 -3
  67. package/dist/core/deployment/engine.d.ts.map +1 -1
  68. package/dist/core/deployment/engine.js +194 -27
  69. package/dist/core/deployment/engine.js.map +1 -1
  70. package/dist/core/deployment/event-filter.js +1 -1
  71. package/dist/core/deployment/event-filter.js.map +1 -1
  72. package/dist/core/deployment/event-monitor.d.ts +11 -0
  73. package/dist/core/deployment/event-monitor.d.ts.map +1 -1
  74. package/dist/core/deployment/event-monitor.js +14 -0
  75. package/dist/core/deployment/event-monitor.js.map +1 -1
  76. package/dist/core/deployment/handle-tracing.d.ts +14 -0
  77. package/dist/core/deployment/handle-tracing.d.ts.map +1 -0
  78. package/dist/core/deployment/handle-tracing.js +38 -0
  79. package/dist/core/deployment/handle-tracing.js.map +1 -0
  80. package/dist/core/deployment/kro-factory.d.ts +115 -3
  81. package/dist/core/deployment/kro-factory.d.ts.map +1 -1
  82. package/dist/core/deployment/kro-factory.js +906 -265
  83. package/dist/core/deployment/kro-factory.js.map +1 -1
  84. package/dist/core/deployment/kro-readiness.d.ts.map +1 -1
  85. package/dist/core/deployment/kro-readiness.js +21 -12
  86. package/dist/core/deployment/kro-readiness.js.map +1 -1
  87. package/dist/core/deployment/nested-composition-status.d.ts +1 -1
  88. package/dist/core/deployment/nested-composition-status.d.ts.map +1 -1
  89. package/dist/core/deployment/nested-composition-status.js +96 -53
  90. package/dist/core/deployment/nested-composition-status.js.map +1 -1
  91. package/dist/core/deployment/resource-applier.d.ts +15 -2
  92. package/dist/core/deployment/resource-applier.d.ts.map +1 -1
  93. package/dist/core/deployment/resource-applier.js +75 -25
  94. package/dist/core/deployment/resource-applier.js.map +1 -1
  95. package/dist/core/deployment/resource-tagging.d.ts +220 -0
  96. package/dist/core/deployment/resource-tagging.d.ts.map +1 -0
  97. package/dist/core/deployment/resource-tagging.js +292 -0
  98. package/dist/core/deployment/resource-tagging.js.map +1 -0
  99. package/dist/core/deployment/rollback-manager.d.ts +25 -4
  100. package/dist/core/deployment/rollback-manager.d.ts.map +1 -1
  101. package/dist/core/deployment/rollback-manager.js +70 -57
  102. package/dist/core/deployment/rollback-manager.js.map +1 -1
  103. package/dist/core/deployment/shared-utilities.d.ts +6 -0
  104. package/dist/core/deployment/shared-utilities.d.ts.map +1 -1
  105. package/dist/core/deployment/shared-utilities.js +32 -2
  106. package/dist/core/deployment/shared-utilities.js.map +1 -1
  107. package/dist/core/deployment/singleton-owner-drift.d.ts +16 -0
  108. package/dist/core/deployment/singleton-owner-drift.d.ts.map +1 -0
  109. package/dist/core/deployment/singleton-owner-drift.js +54 -0
  110. package/dist/core/deployment/singleton-owner-drift.js.map +1 -0
  111. package/dist/core/deployment/strategies/alchemy-strategy.d.ts +3 -1
  112. package/dist/core/deployment/strategies/alchemy-strategy.d.ts.map +1 -1
  113. package/dist/core/deployment/strategies/alchemy-strategy.js +121 -18
  114. package/dist/core/deployment/strategies/alchemy-strategy.js.map +1 -1
  115. package/dist/core/deployment/strategies/base-strategy.d.ts +9 -3
  116. package/dist/core/deployment/strategies/base-strategy.d.ts.map +1 -1
  117. package/dist/core/deployment/strategies/base-strategy.js +32 -4
  118. package/dist/core/deployment/strategies/base-strategy.js.map +1 -1
  119. package/dist/core/deployment/strategies/direct-strategy.d.ts +12 -4
  120. package/dist/core/deployment/strategies/direct-strategy.d.ts.map +1 -1
  121. package/dist/core/deployment/strategies/direct-strategy.js +112 -8
  122. package/dist/core/deployment/strategies/direct-strategy.js.map +1 -1
  123. package/dist/core/errors.d.ts +2 -2
  124. package/dist/core/errors.d.ts.map +1 -1
  125. package/dist/core/errors.js.map +1 -1
  126. package/dist/core/expressions/analysis/cache.d.ts +2 -2
  127. package/dist/core/expressions/analysis/cache.d.ts.map +1 -1
  128. package/dist/core/expressions/analysis/cache.js +4 -0
  129. package/dist/core/expressions/analysis/cache.js.map +1 -1
  130. package/dist/core/expressions/analysis/fn-toString-self-test.d.ts.map +1 -1
  131. package/dist/core/expressions/analysis/fn-toString-self-test.js +0 -1
  132. package/dist/core/expressions/analysis/fn-toString-self-test.js.map +1 -1
  133. package/dist/core/expressions/analysis/shared-types.d.ts +2 -2
  134. package/dist/core/expressions/analysis/shared-types.d.ts.map +1 -1
  135. package/dist/core/expressions/analysis/source-map.d.ts.map +1 -1
  136. package/dist/core/expressions/analysis/source-map.js +1 -0
  137. package/dist/core/expressions/analysis/source-map.js.map +1 -1
  138. package/dist/core/expressions/analysis/types.d.ts +7 -7
  139. package/dist/core/expressions/analysis/types.d.ts.map +1 -1
  140. package/dist/core/expressions/composition/composition-analyzer-helpers.d.ts +29 -1
  141. package/dist/core/expressions/composition/composition-analyzer-helpers.d.ts.map +1 -1
  142. package/dist/core/expressions/composition/composition-analyzer-helpers.js +348 -17
  143. package/dist/core/expressions/composition/composition-analyzer-helpers.js.map +1 -1
  144. package/dist/core/expressions/composition/composition-analyzer-ternary.d.ts +2 -2
  145. package/dist/core/expressions/composition/composition-analyzer-ternary.d.ts.map +1 -1
  146. package/dist/core/expressions/composition/composition-analyzer-ternary.js +221 -10
  147. package/dist/core/expressions/composition/composition-analyzer-ternary.js.map +1 -1
  148. package/dist/core/expressions/composition/composition-analyzer-traversal.d.ts.map +1 -1
  149. package/dist/core/expressions/composition/composition-analyzer-traversal.js +67 -2
  150. package/dist/core/expressions/composition/composition-analyzer-traversal.js.map +1 -1
  151. package/dist/core/expressions/composition/composition-analyzer-types.d.ts +52 -0
  152. package/dist/core/expressions/composition/composition-analyzer-types.d.ts.map +1 -1
  153. package/dist/core/expressions/composition/composition-analyzer.d.ts.map +1 -1
  154. package/dist/core/expressions/composition/composition-analyzer.js +150 -6
  155. package/dist/core/expressions/composition/composition-analyzer.js.map +1 -1
  156. package/dist/core/expressions/composition/expression-analyzer.d.ts.map +1 -1
  157. package/dist/core/expressions/composition/expression-analyzer.js +21 -4
  158. package/dist/core/expressions/composition/expression-analyzer.js.map +1 -1
  159. package/dist/core/expressions/composition/imperative-analyzer.d.ts +1 -1
  160. package/dist/core/expressions/composition/imperative-analyzer.d.ts.map +1 -1
  161. package/dist/core/expressions/composition/imperative-analyzer.js +31 -7
  162. package/dist/core/expressions/composition/imperative-analyzer.js.map +1 -1
  163. package/dist/core/expressions/composition/scope-manager.d.ts +2 -2
  164. package/dist/core/expressions/composition/scope-manager.d.ts.map +1 -1
  165. package/dist/core/expressions/composition/scope-manager.js.map +1 -1
  166. package/dist/core/expressions/conditional/conditional-expression-processor.d.ts +3 -3
  167. package/dist/core/expressions/conditional/conditional-expression-processor.d.ts.map +1 -1
  168. package/dist/core/expressions/conditional/conditional-expression-processor.js.map +1 -1
  169. package/dist/core/expressions/conditional/conditional-integration.d.ts.map +1 -1
  170. package/dist/core/expressions/conditional/conditional-integration.js.map +1 -1
  171. package/dist/core/expressions/context/context-aware-generator.d.ts +5 -5
  172. package/dist/core/expressions/context/context-aware-generator.d.ts.map +1 -1
  173. package/dist/core/expressions/context/context-aware-generator.js.map +1 -1
  174. package/dist/core/expressions/context/context-detector.d.ts +3 -3
  175. package/dist/core/expressions/context/context-detector.d.ts.map +1 -1
  176. package/dist/core/expressions/context/context-detector.js.map +1 -1
  177. package/dist/core/expressions/context/context-validator.d.ts +6 -6
  178. package/dist/core/expressions/context/context-validator.d.ts.map +1 -1
  179. package/dist/core/expressions/context/context-validator.js +2 -2
  180. package/dist/core/expressions/context/context-validator.js.map +1 -1
  181. package/dist/core/expressions/factory/cel-conversion-engine.d.ts +4 -4
  182. package/dist/core/expressions/factory/cel-conversion-engine.d.ts.map +1 -1
  183. package/dist/core/expressions/factory/cel-conversion-engine.js.map +1 -1
  184. package/dist/core/expressions/factory/dependency-tracker.d.ts +2 -2
  185. package/dist/core/expressions/factory/dependency-tracker.d.ts.map +1 -1
  186. package/dist/core/expressions/factory/dependency-tracker.js +21 -5
  187. package/dist/core/expressions/factory/dependency-tracker.js.map +1 -1
  188. package/dist/core/expressions/factory/factory-integration.d.ts +2 -4
  189. package/dist/core/expressions/factory/factory-integration.d.ts.map +1 -1
  190. package/dist/core/expressions/factory/factory-integration.js +0 -6
  191. package/dist/core/expressions/factory/factory-integration.js.map +1 -1
  192. package/dist/core/expressions/factory/factory-pattern-handler.d.ts +3 -3
  193. package/dist/core/expressions/factory/factory-pattern-handler.d.ts.map +1 -1
  194. package/dist/core/expressions/factory/factory-pattern-handler.js +1 -0
  195. package/dist/core/expressions/factory/factory-pattern-handler.js.map +1 -1
  196. package/dist/core/expressions/factory/migration-helpers.js.map +1 -1
  197. package/dist/core/expressions/factory/resource-analyzer.d.ts +4 -4
  198. package/dist/core/expressions/factory/resource-analyzer.d.ts.map +1 -1
  199. package/dist/core/expressions/factory/resource-analyzer.js.map +1 -1
  200. package/dist/core/expressions/factory/resource-type-validator.d.ts +5 -5
  201. package/dist/core/expressions/factory/resource-type-validator.d.ts.map +1 -1
  202. package/dist/core/expressions/factory/resource-type-validator.js.map +1 -1
  203. package/dist/core/expressions/factory/status-builder-analyzer.d.ts +6 -7
  204. package/dist/core/expressions/factory/status-builder-analyzer.d.ts.map +1 -1
  205. package/dist/core/expressions/factory/status-builder-analyzer.js +0 -3
  206. package/dist/core/expressions/factory/status-builder-analyzer.js.map +1 -1
  207. package/dist/core/expressions/factory/status-builder-types.d.ts +1 -1
  208. package/dist/core/expressions/factory/status-builder-types.d.ts.map +1 -1
  209. package/dist/core/expressions/factory/status-cel-generation.d.ts +1 -1
  210. package/dist/core/expressions/factory/status-cel-generation.d.ts.map +1 -1
  211. package/dist/core/expressions/factory/status-cel-generation.js +1 -1
  212. package/dist/core/expressions/factory/status-cel-generation.js.map +1 -1
  213. package/dist/core/expressions/factory/status-field-analysis.d.ts +3 -3
  214. package/dist/core/expressions/factory/status-field-analysis.d.ts.map +1 -1
  215. package/dist/core/expressions/factory/status-field-analysis.js.map +1 -1
  216. package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.d.ts +5 -5
  217. package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.d.ts.map +1 -1
  218. package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.js +1 -1
  219. package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.js.map +1 -1
  220. package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.d.ts +10 -10
  221. package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.d.ts.map +1 -1
  222. package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.js +5 -1
  223. package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.js.map +1 -1
  224. package/dist/core/expressions/magic-proxy/magic-proxy-ast.d.ts +2 -2
  225. package/dist/core/expressions/magic-proxy/magic-proxy-ast.d.ts.map +1 -1
  226. package/dist/core/expressions/magic-proxy/magic-proxy-ast.js.map +1 -1
  227. package/dist/core/expressions/magic-proxy/magic-proxy-detector.d.ts +5 -5
  228. package/dist/core/expressions/magic-proxy/magic-proxy-detector.d.ts.map +1 -1
  229. package/dist/core/expressions/magic-proxy/magic-proxy-detector.js.map +1 -1
  230. package/dist/core/expressions/magic-proxy/magic-proxy-types.d.ts +2 -2
  231. package/dist/core/expressions/magic-proxy/magic-proxy-types.d.ts.map +1 -1
  232. package/dist/core/expressions/magic-proxy/optionality-handler.d.ts +1 -2
  233. package/dist/core/expressions/magic-proxy/optionality-handler.d.ts.map +1 -1
  234. package/dist/core/expressions/magic-proxy/optionality-handler.js +2 -15
  235. package/dist/core/expressions/magic-proxy/optionality-handler.js.map +1 -1
  236. package/dist/core/expressions/validation/compile-time-checker.d.ts +1 -1
  237. package/dist/core/expressions/validation/compile-time-checker.d.ts.map +1 -1
  238. package/dist/core/expressions/validation/compile-time-checker.js.map +1 -1
  239. package/dist/core/expressions/validation/compile-time-types.d.ts +2 -2
  240. package/dist/core/expressions/validation/compile-time-types.d.ts.map +1 -1
  241. package/dist/core/expressions/validation/kubernetes-field-types.d.ts +4 -4
  242. package/dist/core/expressions/validation/kubernetes-field-types.d.ts.map +1 -1
  243. package/dist/core/expressions/validation/kubernetes-field-types.js.map +1 -1
  244. package/dist/core/expressions/validation/resource-field-utils.d.ts +10 -10
  245. package/dist/core/expressions/validation/resource-field-utils.d.ts.map +1 -1
  246. package/dist/core/expressions/validation/resource-field-utils.js.map +1 -1
  247. package/dist/core/expressions/validation/resource-validation.d.ts +3 -3
  248. package/dist/core/expressions/validation/resource-validation.d.ts.map +1 -1
  249. package/dist/core/expressions/validation/resource-validation.js.map +1 -1
  250. package/dist/core/expressions/validation/type-inference-types.d.ts +2 -2
  251. package/dist/core/expressions/validation/type-inference-types.d.ts.map +1 -1
  252. package/dist/core/expressions/validation/type-safety.d.ts +2 -2
  253. package/dist/core/expressions/validation/type-safety.d.ts.map +1 -1
  254. package/dist/core/expressions/validation/type-safety.js +1 -0
  255. package/dist/core/expressions/validation/type-safety.js.map +1 -1
  256. package/dist/core/kubernetes/bun-api-client.js.map +1 -1
  257. package/dist/core/kubernetes/bun-http-library.d.ts.map +1 -1
  258. package/dist/core/kubernetes/bun-http-library.js +29 -3
  259. package/dist/core/kubernetes/bun-http-library.js.map +1 -1
  260. package/dist/core/kubernetes/client-provider.d.ts +12 -0
  261. package/dist/core/kubernetes/client-provider.d.ts.map +1 -1
  262. package/dist/core/kubernetes/client-provider.js +35 -0
  263. package/dist/core/kubernetes/client-provider.js.map +1 -1
  264. package/dist/core/metadata/resource-metadata.d.ts +46 -1
  265. package/dist/core/metadata/resource-metadata.d.ts.map +1 -1
  266. package/dist/core/metadata/resource-metadata.js.map +1 -1
  267. package/dist/core/proxy/create-resource.d.ts +15 -0
  268. package/dist/core/proxy/create-resource.d.ts.map +1 -1
  269. package/dist/core/proxy/create-resource.js +56 -2
  270. package/dist/core/proxy/create-resource.js.map +1 -1
  271. package/dist/core/readiness/registry.js +2 -2
  272. package/dist/core/readiness/registry.js.map +1 -1
  273. package/dist/core/references/cel-evaluator.d.ts +1 -4
  274. package/dist/core/references/cel-evaluator.d.ts.map +1 -1
  275. package/dist/core/references/cel-evaluator.js +3 -7
  276. package/dist/core/references/cel-evaluator.js.map +1 -1
  277. package/dist/core/references/cel.d.ts +22 -0
  278. package/dist/core/references/cel.d.ts.map +1 -1
  279. package/dist/core/references/cel.js +106 -8
  280. package/dist/core/references/cel.js.map +1 -1
  281. package/dist/core/references/external-refs.d.ts.map +1 -1
  282. package/dist/core/references/external-refs.js +3 -0
  283. package/dist/core/references/external-refs.js.map +1 -1
  284. package/dist/core/references/resolver.d.ts.map +1 -1
  285. package/dist/core/references/resolver.js +28 -17
  286. package/dist/core/references/resolver.js.map +1 -1
  287. package/dist/core/references/schema-proxy.d.ts +18 -10
  288. package/dist/core/references/schema-proxy.d.ts.map +1 -1
  289. package/dist/core/references/schema-proxy.js +174 -23
  290. package/dist/core/references/schema-proxy.js.map +1 -1
  291. package/dist/core/runtime-patches/crd-schema-fix.d.ts.map +1 -1
  292. package/dist/core/runtime-patches/crd-schema-fix.js +4 -1
  293. package/dist/core/runtime-patches/crd-schema-fix.js.map +1 -1
  294. package/dist/core/serialization/cel-optimizer.d.ts.map +1 -1
  295. package/dist/core/serialization/cel-optimizer.js +2 -0
  296. package/dist/core/serialization/cel-optimizer.js.map +1 -1
  297. package/dist/core/serialization/cel-references.d.ts +75 -1
  298. package/dist/core/serialization/cel-references.d.ts.map +1 -1
  299. package/dist/core/serialization/cel-references.js +692 -156
  300. package/dist/core/serialization/cel-references.js.map +1 -1
  301. package/dist/core/serialization/core.d.ts +8 -8
  302. package/dist/core/serialization/core.d.ts.map +1 -1
  303. package/dist/core/serialization/core.js +638 -90
  304. package/dist/core/serialization/core.js.map +1 -1
  305. package/dist/core/serialization/kro-post-processing.d.ts +1 -1
  306. package/dist/core/serialization/kro-post-processing.d.ts.map +1 -1
  307. package/dist/core/serialization/kro-post-processing.js +69 -22
  308. package/dist/core/serialization/kro-post-processing.js.map +1 -1
  309. package/dist/core/serialization/schema.d.ts +1 -0
  310. package/dist/core/serialization/schema.d.ts.map +1 -1
  311. package/dist/core/serialization/schema.js +378 -50
  312. package/dist/core/serialization/schema.js.map +1 -1
  313. package/dist/core/serialization/status-analysis-pipeline.d.ts +1 -1
  314. package/dist/core/serialization/status-analysis-pipeline.d.ts.map +1 -1
  315. package/dist/core/serialization/status-analysis-pipeline.js.map +1 -1
  316. package/dist/core/serialization/yaml.d.ts +3 -2
  317. package/dist/core/serialization/yaml.d.ts.map +1 -1
  318. package/dist/core/serialization/yaml.js +385 -55
  319. package/dist/core/serialization/yaml.js.map +1 -1
  320. package/dist/core/singleton/singleton.d.ts +16 -0
  321. package/dist/core/singleton/singleton.d.ts.map +1 -0
  322. package/dist/core/singleton/singleton.js +135 -0
  323. package/dist/core/singleton/singleton.js.map +1 -0
  324. package/dist/core/types/common.d.ts +2 -2
  325. package/dist/core/types/common.d.ts.map +1 -1
  326. package/dist/core/types/composable.d.ts +1 -1
  327. package/dist/core/types/composable.d.ts.map +1 -1
  328. package/dist/core/types/deployment.d.ts +126 -6
  329. package/dist/core/types/deployment.d.ts.map +1 -1
  330. package/dist/core/types/deployment.js +1 -1
  331. package/dist/core/types/deployment.js.map +1 -1
  332. package/dist/core/types/kubernetes.d.ts +25 -17
  333. package/dist/core/types/kubernetes.d.ts.map +1 -1
  334. package/dist/core/types/references.d.ts +1 -1
  335. package/dist/core/types/references.d.ts.map +1 -1
  336. package/dist/core/types/references.js.map +1 -1
  337. package/dist/core/types/resource-graph.d.ts +1 -1
  338. package/dist/core/types/resource-graph.d.ts.map +1 -1
  339. package/dist/core/types/schema.d.ts +1 -1
  340. package/dist/core/types/schema.d.ts.map +1 -1
  341. package/dist/core/types/serialization.d.ts +24 -6
  342. package/dist/core/types/serialization.d.ts.map +1 -1
  343. package/dist/core/validation/cel-validator.d.ts +15 -2
  344. package/dist/core/validation/cel-validator.d.ts.map +1 -1
  345. package/dist/core/validation/cel-validator.js +144 -63
  346. package/dist/core/validation/cel-validator.js.map +1 -1
  347. package/dist/factories/apisix/compositions/apisix-bootstrap.d.ts +2 -41
  348. package/dist/factories/apisix/compositions/apisix-bootstrap.d.ts.map +1 -1
  349. package/dist/factories/apisix/compositions/apisix-bootstrap.js +262 -217
  350. package/dist/factories/apisix/compositions/apisix-bootstrap.js.map +1 -1
  351. package/dist/factories/apisix/index.d.ts +2 -2
  352. package/dist/factories/apisix/index.js +2 -2
  353. package/dist/factories/apisix/resources/helm.d.ts +2 -2
  354. package/dist/factories/apisix/resources/helm.d.ts.map +1 -1
  355. package/dist/factories/apisix/resources/helm.js.map +1 -1
  356. package/dist/factories/apisix/types.d.ts +21 -11
  357. package/dist/factories/apisix/types.d.ts.map +1 -1
  358. package/dist/factories/apisix/types.js +106 -4
  359. package/dist/factories/apisix/types.js.map +1 -1
  360. package/dist/factories/apisix/utils/admin-credentials.d.ts +5 -3
  361. package/dist/factories/apisix/utils/admin-credentials.d.ts.map +1 -1
  362. package/dist/factories/apisix/utils/admin-credentials.js +14 -10
  363. package/dist/factories/apisix/utils/admin-credentials.js.map +1 -1
  364. package/dist/factories/apisix/utils/helm-values-mapper.d.ts.map +1 -1
  365. package/dist/factories/apisix/utils/helm-values-mapper.js +4 -2
  366. package/dist/factories/apisix/utils/helm-values-mapper.js.map +1 -1
  367. package/dist/factories/cert-manager/resources/challenges.js.map +1 -1
  368. package/dist/factories/cert-manager/types.d.ts +3 -3
  369. package/dist/factories/cert-manager/types.d.ts.map +1 -1
  370. package/dist/factories/cilium/compositions/cilium-bootstrap.d.ts +4 -4
  371. package/dist/factories/cilium/types.d.ts +3 -3
  372. package/dist/factories/cilium/types.d.ts.map +1 -1
  373. package/dist/factories/cnpg/compositions/cnpg-bootstrap.d.ts +1 -0
  374. package/dist/factories/cnpg/compositions/cnpg-bootstrap.d.ts.map +1 -1
  375. package/dist/factories/cnpg/compositions/cnpg-bootstrap.js +48 -0
  376. package/dist/factories/cnpg/compositions/cnpg-bootstrap.js.map +1 -1
  377. package/dist/factories/cnpg/resources/cluster.js +1 -1
  378. package/dist/factories/cnpg/resources/cluster.js.map +1 -1
  379. package/dist/factories/cnpg/resources/helm.d.ts.map +1 -1
  380. package/dist/factories/cnpg/resources/helm.js +1 -0
  381. package/dist/factories/cnpg/resources/helm.js.map +1 -1
  382. package/dist/factories/cnpg/resources/pooler.js +1 -1
  383. package/dist/factories/cnpg/resources/pooler.js.map +1 -1
  384. package/dist/factories/cnpg/types.d.ts +9 -8
  385. package/dist/factories/cnpg/types.d.ts.map +1 -1
  386. package/dist/factories/cnpg/types.js +11 -0
  387. package/dist/factories/cnpg/types.js.map +1 -1
  388. package/dist/factories/external-dns/compositions/external-dns-bootstrap.d.ts.map +1 -1
  389. package/dist/factories/external-dns/compositions/external-dns-bootstrap.js +153 -41
  390. package/dist/factories/external-dns/compositions/external-dns-bootstrap.js.map +1 -1
  391. package/dist/factories/external-dns/resources/dns-endpoint.js +1 -1
  392. package/dist/factories/external-dns/resources/dns-endpoint.js.map +1 -1
  393. package/dist/factories/external-dns/resources/helm.d.ts +1 -1
  394. package/dist/factories/external-dns/resources/helm.d.ts.map +1 -1
  395. package/dist/factories/external-dns/resources/helm.js +17 -10
  396. package/dist/factories/external-dns/resources/helm.js.map +1 -1
  397. package/dist/factories/external-dns/types.d.ts +5 -2
  398. package/dist/factories/external-dns/types.d.ts.map +1 -1
  399. package/dist/factories/external-dns/types.js.map +1 -1
  400. package/dist/factories/flux/git-repository.d.ts.map +1 -1
  401. package/dist/factories/flux/git-repository.js +1 -1
  402. package/dist/factories/flux/git-repository.js.map +1 -1
  403. package/dist/factories/flux/kustomize/kustomization.d.ts +2 -2
  404. package/dist/factories/flux/kustomize/kustomization.d.ts.map +1 -1
  405. package/dist/factories/flux/kustomize/readiness-evaluators.d.ts +1 -1
  406. package/dist/factories/flux/kustomize/readiness-evaluators.d.ts.map +1 -1
  407. package/dist/factories/flux/kustomize/readiness-evaluators.js +1 -1
  408. package/dist/factories/flux/kustomize/readiness-evaluators.js.map +1 -1
  409. package/dist/factories/helm/helm-release.d.ts +3 -2
  410. package/dist/factories/helm/helm-release.d.ts.map +1 -1
  411. package/dist/factories/helm/helm-release.js +1 -0
  412. package/dist/factories/helm/helm-release.js.map +1 -1
  413. package/dist/factories/helm/helm-repository.d.ts +1 -1
  414. package/dist/factories/helm/helm-repository.d.ts.map +1 -1
  415. package/dist/factories/helm/helm-repository.js +6 -4
  416. package/dist/factories/helm/helm-repository.js.map +1 -1
  417. package/dist/factories/helm/readiness-evaluators.d.ts +6 -6
  418. package/dist/factories/helm/readiness-evaluators.d.ts.map +1 -1
  419. package/dist/factories/helm/readiness-evaluators.js +15 -9
  420. package/dist/factories/helm/readiness-evaluators.js.map +1 -1
  421. package/dist/factories/helm/types.d.ts +5 -1
  422. package/dist/factories/helm/types.d.ts.map +1 -1
  423. package/dist/factories/inngest/compositions/inngest-bootstrap.d.ts +1 -0
  424. package/dist/factories/inngest/compositions/inngest-bootstrap.d.ts.map +1 -1
  425. package/dist/factories/inngest/compositions/inngest-bootstrap.js +4 -3
  426. package/dist/factories/inngest/compositions/inngest-bootstrap.js.map +1 -1
  427. package/dist/factories/inngest/resources/helm.js +1 -1
  428. package/dist/factories/inngest/resources/helm.js.map +1 -1
  429. package/dist/factories/inngest/types.d.ts +5 -4
  430. package/dist/factories/inngest/types.d.ts.map +1 -1
  431. package/dist/factories/inngest/types.js +2 -0
  432. package/dist/factories/inngest/types.js.map +1 -1
  433. package/dist/factories/kro/kro-custom-resource.js +1 -1
  434. package/dist/factories/kro/kro-custom-resource.js.map +1 -1
  435. package/dist/factories/kubernetes/config/config-map.d.ts +2 -2
  436. package/dist/factories/kubernetes/config/config-map.d.ts.map +1 -1
  437. package/dist/factories/kubernetes/config/secret.d.ts +2 -2
  438. package/dist/factories/kubernetes/config/secret.d.ts.map +1 -1
  439. package/dist/factories/kubernetes/networking/service.js +1 -1
  440. package/dist/factories/kubernetes/networking/service.js.map +1 -1
  441. package/dist/factories/kubernetes/yaml/yaml-directory.d.ts.map +1 -1
  442. package/dist/factories/kubernetes/yaml/yaml-directory.js +9 -0
  443. package/dist/factories/kubernetes/yaml/yaml-directory.js.map +1 -1
  444. package/dist/factories/kubernetes/yaml/yaml-file.d.ts.map +1 -1
  445. package/dist/factories/kubernetes/yaml/yaml-file.js +9 -0
  446. package/dist/factories/kubernetes/yaml/yaml-file.js.map +1 -1
  447. package/dist/factories/pebble/resources/helm.js.map +1 -1
  448. package/dist/factories/pebble/types.d.ts +2 -2
  449. package/dist/factories/searxng/compositions/searxng-bootstrap.d.ts +3 -2
  450. package/dist/factories/searxng/compositions/searxng-bootstrap.d.ts.map +1 -1
  451. package/dist/factories/searxng/compositions/searxng-bootstrap.js +205 -167
  452. package/dist/factories/searxng/compositions/searxng-bootstrap.js.map +1 -1
  453. package/dist/factories/searxng/resources/searxng.d.ts +1 -1
  454. package/dist/factories/searxng/resources/searxng.js +1 -1
  455. package/dist/factories/searxng/types.d.ts +5 -4
  456. package/dist/factories/searxng/types.d.ts.map +1 -1
  457. package/dist/factories/searxng/types.js +8 -7
  458. package/dist/factories/searxng/types.js.map +1 -1
  459. package/dist/factories/searxng/utils/settings-builder.d.ts +4 -3
  460. package/dist/factories/searxng/utils/settings-builder.d.ts.map +1 -1
  461. package/dist/factories/searxng/utils/settings-builder.js +4 -3
  462. package/dist/factories/searxng/utils/settings-builder.js.map +1 -1
  463. package/dist/factories/simple/config/config-map.d.ts +2 -2
  464. package/dist/factories/simple/config/config-map.d.ts.map +1 -1
  465. package/dist/factories/simple/config/secret.d.ts +2 -2
  466. package/dist/factories/simple/config/secret.d.ts.map +1 -1
  467. package/dist/factories/simple/helm/index.d.ts +1 -1
  468. package/dist/factories/simple/helm/index.d.ts.map +1 -1
  469. package/dist/factories/simple/helm/index.js.map +1 -1
  470. package/dist/factories/simple/storage/persistent-volume.js.map +1 -1
  471. package/dist/factories/simple/types.d.ts +11 -1
  472. package/dist/factories/simple/types.d.ts.map +1 -1
  473. package/dist/factories/simple/workloads/deployment.d.ts.map +1 -1
  474. package/dist/factories/simple/workloads/deployment.js +3 -0
  475. package/dist/factories/simple/workloads/deployment.js.map +1 -1
  476. package/dist/factories/valkey/compositions/valkey-bootstrap.d.ts +1 -0
  477. package/dist/factories/valkey/compositions/valkey-bootstrap.d.ts.map +1 -1
  478. package/dist/factories/valkey/compositions/valkey-bootstrap.js +116 -0
  479. package/dist/factories/valkey/compositions/valkey-bootstrap.js.map +1 -1
  480. package/dist/factories/valkey/resources/valkey.js +1 -1
  481. package/dist/factories/valkey/resources/valkey.js.map +1 -1
  482. package/dist/factories/valkey/types.d.ts +6 -5
  483. package/dist/factories/valkey/types.d.ts.map +1 -1
  484. package/dist/factories/valkey/types.js +10 -0
  485. package/dist/factories/valkey/types.js.map +1 -1
  486. package/dist/factories/webapp/compositions/web-app-with-processing.d.ts +90 -6
  487. package/dist/factories/webapp/compositions/web-app-with-processing.d.ts.map +1 -1
  488. package/dist/factories/webapp/compositions/web-app-with-processing.js +180 -20
  489. package/dist/factories/webapp/compositions/web-app-with-processing.js.map +1 -1
  490. package/dist/factories/webapp/index.d.ts +3 -4
  491. package/dist/factories/webapp/index.d.ts.map +1 -1
  492. package/dist/factories/webapp/index.js +3 -4
  493. package/dist/factories/webapp/index.js.map +1 -1
  494. package/dist/factories/webapp/types.d.ts +60 -2
  495. package/dist/factories/webapp/types.d.ts.map +1 -1
  496. package/dist/factories/webapp/types.js +80 -3
  497. package/dist/factories/webapp/types.js.map +1 -1
  498. package/dist/index.d.ts +2 -0
  499. package/dist/index.d.ts.map +1 -1
  500. package/dist/index.js +1 -0
  501. package/dist/index.js.map +1 -1
  502. package/dist/shared/brands.d.ts +18 -8
  503. package/dist/shared/brands.d.ts.map +1 -1
  504. package/dist/shared/brands.js +19 -9
  505. package/dist/shared/brands.js.map +1 -1
  506. package/dist/utils/cel-escape.d.ts +12 -0
  507. package/dist/utils/cel-escape.d.ts.map +1 -0
  508. package/dist/utils/cel-escape.js +19 -0
  509. package/dist/utils/cel-escape.js.map +1 -0
  510. package/package.json +3 -2
@@ -4,18 +4,21 @@
4
4
  * This module provides the main serialization functions to convert
5
5
  * TypeScript resource definitions to Kro ResourceGraphDefinition YAML manifests.
6
6
  */
7
- import { createCompositionContext, runWithCompositionContext } from '../composition/context.js';
7
+ import { createCompositionContext, getCurrentCompositionContext, runInStatusBuilderContext, runWithCompositionContext, } from '../composition/context.js';
8
8
  import { createDirectResourceFactory } from '../deployment/direct-factory.js';
9
9
  import { createKroResourceFactory } from '../deployment/kro-factory.js';
10
10
  import { ensureError, ValidationError } from '../errors.js';
11
+ import { CEL_EXPRESSION_BRAND, KUBERNETES_REF_MARKER_SOURCE } from '../../shared/brands.js';
11
12
  import { analyzeCompositionBody, applyAnalysisToResources, } from '../expressions/composition/composition-analyzer.js';
13
+ import { remapResourceStatusReferences } from '../expressions/composition/composition-analyzer-helpers.js';
12
14
  import { StatusBuilderAnalyzer } from '../expressions/factory/status-builder-analyzer.js';
13
15
  import { getComponentLogger } from '../logging/index.js';
14
- import { setResourceId } from '../metadata/index.js';
16
+ import { getMetadataField, setResourceId } from '../metadata/index.js';
15
17
  import { createExternalRefWithoutRegistration, createSchemaProxy } from '../references/index.js';
16
18
  import { getKindInfo, getSemanticCandidateKinds } from '../resources/factory-registry.js';
17
19
  import { validateResourceGraphDefinition } from '../validation/cel-validator.js';
18
20
  import { optimizeStatusMappings } from './cel-optimizer.js';
21
+ import { finalizeCelForKro } from './cel-references.js';
19
22
  import { applyTernaryConditionalsToResources } from './kro-post-processing.js';
20
23
  import { generateKroSchemaFromArktype } from './schema.js';
21
24
  import { runStatusAnalysisPipeline } from './status-analysis-pipeline.js';
@@ -247,9 +250,9 @@ function processCompositionBodyAnalysis(statusMappings, resourcesWithKeys, analy
247
250
  try {
248
251
  const resourceIds = new Set(Object.keys(resourcesWithKeys));
249
252
  const specJson = schemaDefinition?.spec?.json;
250
- const optionalFieldNames = specJson
251
- ? new Set((specJson.optional ?? []).map((p) => p.key))
252
- : undefined;
253
+ const optionalFieldNames = specJson ? collectOptionalSpecPaths(specJson) : undefined;
254
+ const nestedStatusDescriptor = Object.getOwnPropertyDescriptor(statusMappings, '__nestedStatusCel');
255
+ const nestedStatusCel = nestedStatusDescriptor?.value;
253
256
  compositionAnalysis = analyzeCompositionBody(originalCompositionFnForAnalysis, resourceIds, optionalFieldNames);
254
257
  // Differential execution to capture untaken-branch resources.
255
258
  //
@@ -270,10 +273,78 @@ function processCompositionBodyAnalysis(statusMappings, resourcesWithKeys, analy
270
273
  // (so we set them to a sentinel that prevents the composition from
271
274
  // dereferencing undefined). Both runs use the same composition
272
275
  // function, so resource IDs and factory calls are deterministic.
273
- if (schemaDefinition &&
276
+ //
277
+ // SKIP when this composition is being executed as a nested call
278
+ // (`context.isNestedCall === true`). The inner composition's own
279
+ // definition-time pass already captured its hybrid-branch analysis
280
+ // with the INNER schema proxy. Re-running that hybrid capture here —
281
+ // against the fresh inner schema proxy that `captureHybridRunResources`
282
+ // creates — would emit differential CEL conditionals that reference
283
+ // inner-schema fields (e.g., `has(schema.spec.secretKeyRef)`) which
284
+ // don't exist in the outer RGD. The outer composition is the
285
+ // authority on branch conditions for its own calls; the inner's
286
+ // branch shape is driven by what the outer passed in.
287
+ // ── Resource-status ternary compilation (Phases 3+4) ────────────
288
+ //
289
+ // When the AST detects ternaries conditioned on resource status
290
+ // fields (e.g., `cache.status.ready ? 'redis' : 'memory'`), proxy
291
+ // JS evaluation does not necessarily match CEL truth evaluation.
292
+ // To emit the CEL conditional, re-execute explicit true and false
293
+ // branches using `liveStatusMap`, then diff those branch outputs.
294
+ //
295
+ // To avoid false positives (other fields changing due to the status
296
+ // flip), direct factory calls diff only `callSiteResourceId`; nested
297
+ // composition call arguments diff only resources registered under known
298
+ // nested composition base IDs.
299
+ const resourceStatusTernaries = compositionAnalysis.resourceStatusTernaries;
300
+ // Deduplicate by call site and condition. Conditionalization is scoped to
301
+ // one callSiteResourceId, so two resources using the same status condition
302
+ // must both be processed.
303
+ const seenConditions = new Set();
304
+ const uniqueTernaries = resourceStatusTernaries.filter((t) => {
305
+ const key = `${t.callSiteResourceId}:${t.variableName}:${t.conditionExpression ?? t.statusField}`;
306
+ if (seenConditions.has(key))
307
+ return false;
308
+ seenConditions.add(key);
309
+ return true;
310
+ });
311
+ // Process EACH resource-status ternary independently to avoid
312
+ // cross-contamination: flip ONE condition → run → diff → apply.
313
+ // Multiple ternaries on the same resource get independent conditionals.
314
+ for (const ternary of uniqueTernaries) {
315
+ const resId = compositionAnalysis.variableToResourceId.get(ternary.variableName) ??
316
+ ternary.variableName;
317
+ if (!resourceIds.has(resId))
318
+ continue;
319
+ const conditionCel = ternary.conditionExpression
320
+ ? remapResourceStatusReferences(ternary.conditionExpression, new Map(compositionAnalysis.variableToResourceId).set(ternary.variableName, resId))
321
+ : `${resId}.status.${ternary.statusField}`;
322
+ const trueCtx = runResourceStatusBranch(originalCompositionFnForAnalysis, schemaDefinition, compositionAnalysis, ternary, true);
323
+ const falseCtx = runResourceStatusBranch(originalCompositionFnForAnalysis, schemaDefinition, compositionAnalysis, ternary, false);
324
+ // Diff ONLY the targeted resource(s)
325
+ const targetIds = ternary.callSiteResourceId && ternary.callSiteResourceId !== '__non_factory_call__'
326
+ ? [ternary.callSiteResourceId]
327
+ : getNestedResourceStatusTargetIds(trueCtx.resources, trueCtx.nestedCompositionIds);
328
+ for (const id of targetIds) {
329
+ const targetRes = resourcesWithKeys[id];
330
+ const trueRes = trueCtx.resources[id];
331
+ const falseRes = falseCtx.resources[id];
332
+ if (targetRes && trueRes && falseRes) {
333
+ applyResourceStatusBranchDiff(targetRes, trueRes, falseRes, conditionCel, nestedStatusCel, resourceIds);
334
+ }
335
+ }
336
+ serializationLogger.debug('Resource-status branch runs applied', {
337
+ conditionCel,
338
+ targetIds,
339
+ });
340
+ }
341
+ const currentCtx = getCurrentCompositionContext();
342
+ const skipHybridCapture = currentCtx?.isNestedCall === true;
343
+ if (!skipHybridCapture &&
344
+ schemaDefinition &&
274
345
  (compositionAnalysis.unregisteredFactories.length > 0 ||
275
346
  collectOverridableOptionalFields(schemaDefinition, compositionAnalysis).size > 0)) {
276
- const { captured, overriddenFields } = captureHybridRunResources(originalCompositionFnForAnalysis, schemaDefinition, compositionAnalysis);
347
+ const { captured, overriddenFields, overrideConditions } = captureHybridRunResources(originalCompositionFnForAnalysis, schemaDefinition, compositionAnalysis);
277
348
  // (a) Merge resources that exist ONLY in the hybrid run — these
278
349
  // come from branches the proxy run didn't take (e.g., `if (!spec.x)`).
279
350
  // The AST analyzer has already attached the appropriate includeWhen.
@@ -306,11 +377,27 @@ function processCompositionBodyAnalysis(statusMappings, resourcesWithKeys, analy
306
377
  // so multiple `toYaml()` calls on the resulting TypedResourceGraph
307
378
  // all see a consistent final state.
308
379
  if (overriddenFields.size > 0) {
309
- for (const id of Object.keys(resourcesWithKeys)) {
310
- const proxyRes = resourcesWithKeys[id];
311
- const hybridRes = captured[id];
312
- if (proxyRes && hybridRes) {
313
- applyDifferentialFieldConditionals(proxyRes, hybridRes, overriddenFields);
380
+ const baselineResources = Object.fromEntries(Object.entries(resourcesWithKeys).map(([id, resource]) => [
381
+ id,
382
+ cloneResourceTree(resource),
383
+ ]));
384
+ const differentialFields = collectDifferentialOptionalFields(compositionAnalysis);
385
+ const fieldsToDiff = Array.from(differentialFields).filter((field) => overriddenFields.has(field));
386
+ for (const field of fieldsToDiff) {
387
+ const singleFieldSet = new Set([field]);
388
+ const { captured: fieldCaptured } = captureHybridRunResources(originalCompositionFnForAnalysis, schemaDefinition, compositionAnalysis, singleFieldSet);
389
+ const fieldConditions = new Map();
390
+ const explicitCondition = overrideConditions.get(field);
391
+ if (explicitCondition) {
392
+ fieldConditions.set(field, explicitCondition);
393
+ }
394
+ for (const id of Object.keys(resourcesWithKeys)) {
395
+ const proxyRes = resourcesWithKeys[id];
396
+ const baselineRes = baselineResources[id];
397
+ const hybridRes = fieldCaptured[id];
398
+ if (proxyRes && baselineRes && hybridRes) {
399
+ applyDifferentialFieldConditionals(proxyRes, baselineRes, hybridRes, singleFieldSet, fieldConditions, nestedStatusCel, resourceIds);
400
+ }
314
401
  }
315
402
  }
316
403
  }
@@ -369,23 +456,66 @@ function collectOverridableOptionalFields(schemaDefinition, analysis) {
369
456
  const specJson = schemaDefinition.spec.json;
370
457
  if (!specJson)
371
458
  return new Set();
372
- const optionalFields = new Set((specJson.optional ?? []).map((p) => p.key));
373
- const testedFields = new Set();
374
- // Pull field names from every includeWhen condition the AST analyzer
375
- // attached to a resource (including resources that were never
376
- // runtime-registered because their branch wasn't taken).
377
- for (const entry of analysis.resources.values()) {
378
- for (const cond of entry.includeWhen) {
379
- const matches = cond.expression.matchAll(/schema\.spec\.([A-Za-z_$][\w$]*)/g);
380
- for (const m of matches) {
381
- const field = m[1];
382
- if (field && optionalFields.has(field)) {
383
- testedFields.add(field);
459
+ const differentialFields = collectDifferentialOptionalFields(analysis);
460
+ return new Set(Array.from(collectOptionalSpecPaths(specJson))
461
+ .filter((field) => differentialFields.has(field)));
462
+ }
463
+ function collectOptionalSpecPaths(schemaJson, prefix = '') {
464
+ const paths = new Set();
465
+ if (!schemaJson || typeof schemaJson !== 'object')
466
+ return paths;
467
+ const node = schemaJson;
468
+ for (const entry of node.optional ?? []) {
469
+ if (!entry.key)
470
+ continue;
471
+ const path = prefix ? `${prefix}.${entry.key}` : entry.key;
472
+ paths.add(path);
473
+ for (const childPath of collectOptionalSpecPaths(entry.value, path)) {
474
+ paths.add(childPath);
475
+ }
476
+ }
477
+ for (const entry of node.required ?? []) {
478
+ if (!entry.key)
479
+ continue;
480
+ const path = prefix ? `${prefix}.${entry.key}` : entry.key;
481
+ for (const childPath of collectOptionalSpecPaths(entry.value, path)) {
482
+ paths.add(childPath);
483
+ }
484
+ }
485
+ return paths;
486
+ }
487
+ function collectDifferentialOptionalFields(analysis) {
488
+ const fields = new Set(analysis.hybridOverrideConditions.keys());
489
+ for (const field of analysis.differentialConditionFields) {
490
+ fields.add(field);
491
+ }
492
+ for (const controlFlow of analysis.resources.values()) {
493
+ for (const condition of controlFlow.includeWhen) {
494
+ const expression = condition.expression;
495
+ const matches = expression.matchAll(/schema\.spec\.([a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)*)/g);
496
+ for (const match of matches) {
497
+ const field = match[1];
498
+ if (field) {
499
+ fields.add(field);
384
500
  }
385
501
  }
386
502
  }
387
503
  }
388
- return testedFields;
504
+ return fields;
505
+ }
506
+ function collectHybridOverrideValues(analysis) {
507
+ const overrideValues = new Map();
508
+ for (const [field, expression] of analysis.hybridOverrideConditions.entries()) {
509
+ const match = expression.match(/^schema\.spec\.([a-zA-Z0-9_.]+)\s*!=\s*false$/);
510
+ const path = match?.[1];
511
+ if (!path || path !== field || overrideValues.has(field))
512
+ continue;
513
+ overrideValues.set(field, false);
514
+ }
515
+ return overrideValues;
516
+ }
517
+ function collectHybridOverrideConditions(analysis) {
518
+ return new Map(analysis.hybridOverrideConditions);
389
519
  }
390
520
  /**
391
521
  * Re-execute the composition function in an isolated composition context
@@ -412,11 +542,17 @@ function collectOverridableOptionalFields(schemaDefinition, analysis) {
412
542
  * effects a second time during this re-execution — see integration-skill
413
543
  * rule #30 for the full contract.
414
544
  */
415
- function captureHybridRunResources(compositionFn, schemaDefinition, analysis) {
545
+ function captureHybridRunResources(compositionFn, schemaDefinition, analysis, fieldsToOverride) {
416
546
  try {
417
- const overriddenFields = collectOverridableOptionalFields(schemaDefinition, analysis);
418
- if (overriddenFields.size === 0)
419
- return { captured: {}, overriddenFields };
547
+ const allOverriddenFields = collectOverridableOptionalFields(schemaDefinition, analysis);
548
+ const overriddenFields = fieldsToOverride
549
+ ? new Set(Array.from(allOverriddenFields).filter((field) => fieldsToOverride.has(field)))
550
+ : allOverriddenFields;
551
+ if (overriddenFields.size === 0) {
552
+ return { captured: {}, overriddenFields, overrideConditions: new Map() };
553
+ }
554
+ const overrideValues = new Map(Array.from(collectHybridOverrideValues(analysis)).filter(([field]) => overriddenFields.has(field)));
555
+ const overrideConditions = new Map(Array.from(collectHybridOverrideConditions(analysis)).filter(([field]) => overriddenFields.has(field)));
420
556
  // Build the hybrid spec: the real schema proxy (so all other field
421
557
  // accesses produce KubernetesRef values) wrapped in a Proxy that
422
558
  // intercepts the overridden keys and returns `undefined`. Accessing
@@ -424,21 +560,8 @@ function captureHybridRunResources(compositionFn, schemaDefinition, analysis) {
424
560
  // will throw — but that's exactly the code path the override is
425
561
  // meant to skip, so the thrown access lives inside the `else`
426
562
  // branch that this run intentionally does not execute.
427
- const realSchema = createSchemaProxy();
428
- const hybridSpec = new Proxy(realSchema.spec, {
429
- get(target, prop, receiver) {
430
- if (typeof prop === 'string' && overriddenFields.has(prop)) {
431
- return undefined;
432
- }
433
- return Reflect.get(target, prop, receiver);
434
- },
435
- has(target, prop) {
436
- if (typeof prop === 'string' && overriddenFields.has(prop)) {
437
- return false;
438
- }
439
- return Reflect.has(target, prop);
440
- },
441
- });
563
+ const realSchema = createSchemaProxy(schemaDefinition.spec?.json, schemaDefinition.status?.json);
564
+ const hybridSpec = createHybridSpecProxy(realSchema.spec, overriddenFields, overrideValues);
442
565
  const tempCtx = createCompositionContext('hybrid-capture');
443
566
  runWithCompositionContext(tempCtx, () => {
444
567
  compositionFn(hybridSpec);
@@ -446,15 +569,72 @@ function captureHybridRunResources(compositionFn, schemaDefinition, analysis) {
446
569
  return {
447
570
  captured: tempCtx.resources,
448
571
  overriddenFields,
572
+ overrideConditions,
449
573
  };
450
574
  }
451
575
  catch {
452
576
  // Best-effort: compositions that throw when running with a hybrid spec
453
577
  // degrade gracefully — stub resources still cover the missing factories
454
578
  // and the proxy-run resources are used as-is.
455
- return { captured: {}, overriddenFields: new Set() };
579
+ return { captured: {}, overriddenFields: new Set(), overrideConditions: new Map() };
456
580
  }
457
581
  }
582
+ function createHybridSpecProxy(target, overriddenFields, overrideValues, pathPrefix = '') {
583
+ return new Proxy(target, {
584
+ get(proxyTarget, prop, receiver) {
585
+ if (typeof prop !== 'string') {
586
+ return Reflect.get(proxyTarget, prop, receiver);
587
+ }
588
+ const path = pathPrefix ? `${pathPrefix}.${prop}` : prop;
589
+ if (overriddenFields.has(path)) {
590
+ return overrideValues.has(path) ? overrideValues.get(path) : undefined;
591
+ }
592
+ const hasNestedOverride = Array.from(overriddenFields).some((field) => field.startsWith(`${path}.`));
593
+ const value = Reflect.get(proxyTarget, prop, receiver);
594
+ if (hasNestedOverride && value && (typeof value === 'object' || typeof value === 'function')) {
595
+ return createHybridSpecProxy(value, overriddenFields, overrideValues, path);
596
+ }
597
+ return value;
598
+ },
599
+ has(proxyTarget, prop) {
600
+ if (typeof prop !== 'string') {
601
+ return Reflect.has(proxyTarget, prop);
602
+ }
603
+ const path = pathPrefix ? `${pathPrefix}.${prop}` : prop;
604
+ if (overriddenFields.has(path)) {
605
+ return overrideValues.has(path);
606
+ }
607
+ return Reflect.has(proxyTarget, prop);
608
+ },
609
+ });
610
+ }
611
+ function cloneResourceTree(value) {
612
+ if (Array.isArray(value)) {
613
+ return value.map((item) => cloneResourceTree(item));
614
+ }
615
+ if (isPlainObject(value)) {
616
+ return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [key, cloneResourceTree(entryValue)]));
617
+ }
618
+ return value;
619
+ }
620
+ function structuralEquals(a, b) {
621
+ if (isLeafValue(a) || isLeafValue(b)) {
622
+ return leafEquals(a, b);
623
+ }
624
+ if (Array.isArray(a) && Array.isArray(b)) {
625
+ return a.length === b.length && a.every((item, index) => structuralEquals(item, b[index]));
626
+ }
627
+ if (isWalkableRecord(a) && isWalkableRecord(b)) {
628
+ const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
629
+ for (const key of keys) {
630
+ if (!structuralEquals(a[key], b[key])) {
631
+ return false;
632
+ }
633
+ }
634
+ return true;
635
+ }
636
+ return a === b;
637
+ }
458
638
  /**
459
639
  * Walk `proxyRes` and `hybridRes` in parallel and replace any leaf value
460
640
  * in `proxyRes` that differs from the corresponding leaf in `hybridRes`
@@ -482,59 +662,72 @@ function captureHybridRunResources(compositionFn, schemaDefinition, analysis) {
482
662
  * are converted to their dollar-wrapped forms before embedding in
483
663
  * the conditional.
484
664
  */
485
- function applyDifferentialFieldConditionals(proxyRes, hybridRes, overriddenFields) {
486
- walkAndConditionalize(proxyRes, hybridRes, overriddenFields);
665
+ function applyDifferentialFieldConditionals(currentRes, baselineRes, hybridRes, overriddenFields, overrideConditions, nestedStatusCel, resourceIds) {
666
+ walkAndConditionalize(currentRes, baselineRes, hybridRes, overriddenFields, overrideConditions, nestedStatusCel, resourceIds);
487
667
  }
488
- function walkAndConditionalize(proxy, hybrid, overriddenFields) {
489
- if (Array.isArray(proxy) && Array.isArray(hybrid)) {
490
- const maxLen = Math.max(proxy.length, hybrid.length);
668
+ function walkAndConditionalize(current, baseline, hybrid, overriddenFields, overrideConditions, nestedStatusCel, resourceIds) {
669
+ if (Array.isArray(current) && Array.isArray(baseline) && Array.isArray(hybrid)) {
670
+ if (baseline.length !== hybrid.length) {
671
+ return structuralEquals(current, baseline)
672
+ ? buildCelConditional(baseline, hybrid, overriddenFields, overrideConditions, nestedStatusCel, resourceIds)
673
+ : current;
674
+ }
675
+ const maxLen = Math.max(current.length, hybrid.length);
491
676
  for (let i = 0; i < maxLen; i++) {
492
- const p = proxy[i];
677
+ const c = current[i];
678
+ const b = baseline[i];
493
679
  const h = hybrid[i];
494
- if (i >= proxy.length) {
680
+ if (i >= current.length) {
495
681
  // New element added by hybrid run — copy it over.
496
- proxy.push(h);
682
+ current.push(h);
497
683
  continue;
498
684
  }
499
685
  if (i >= hybrid.length) {
500
686
  // Element removed in hybrid — leave the proxy value as-is.
501
687
  continue;
502
688
  }
503
- if (isLeafValue(p) && isLeafValue(h)) {
504
- if (!leafEquals(p, h)) {
505
- proxy[i] = buildCelConditional(p, h, overriddenFields);
689
+ if (isLeafValue(b) && isLeafValue(h)) {
690
+ if (!leafEquals(b, h) && leafEquals(c, b)) {
691
+ current[i] = buildCelConditional(b, h, overriddenFields, overrideConditions, nestedStatusCel, resourceIds);
506
692
  }
507
693
  }
508
694
  else {
509
- walkAndConditionalize(p, h, overriddenFields);
695
+ const conditionalized = walkAndConditionalize(c, b, h, overriddenFields, overrideConditions, nestedStatusCel, resourceIds);
696
+ if (conditionalized !== c) {
697
+ current[i] = conditionalized;
698
+ }
510
699
  }
511
700
  }
512
- return proxy;
701
+ return current;
513
702
  }
514
- if (isPlainObject(proxy) && isPlainObject(hybrid)) {
515
- const keys = new Set([...Object.keys(proxy), ...Object.keys(hybrid)]);
703
+ if (isWalkableRecord(current) && isWalkableRecord(baseline) && isWalkableRecord(hybrid)) {
704
+ const keys = new Set([...Object.keys(current), ...Object.keys(baseline), ...Object.keys(hybrid)]);
516
705
  for (const key of keys) {
517
- const p = proxy[key];
706
+ const c = current[key];
707
+ const b = baseline[key];
518
708
  const h = hybrid[key];
519
709
  if (!(key in hybrid)) {
520
- continue; // Proxy has it, hybrid doesn't — keep proxy value
710
+ continue;
521
711
  }
522
- if (!(key in proxy)) {
523
- proxy[key] = h;
712
+ if (!(key in current)) {
713
+ current[key] = h;
524
714
  continue;
525
715
  }
526
- if (isLeafValue(p) && isLeafValue(h)) {
527
- if (!leafEquals(p, h)) {
528
- proxy[key] = buildCelConditional(p, h, overriddenFields);
716
+ if (isLeafValue(b) && isLeafValue(h)) {
717
+ if (!leafEquals(b, h) && leafEquals(c, b)) {
718
+ current[key] = buildCelConditional(b, h, overriddenFields, overrideConditions, nestedStatusCel, resourceIds);
529
719
  }
530
720
  }
531
721
  else {
532
- walkAndConditionalize(p, h, overriddenFields);
722
+ const conditionalized = walkAndConditionalize(c, b, h, overriddenFields, overrideConditions, nestedStatusCel, resourceIds);
723
+ if (conditionalized !== c) {
724
+ current[key] = conditionalized;
725
+ }
533
726
  }
534
727
  }
535
- return proxy;
728
+ return current;
536
729
  }
537
- return proxy;
730
+ return current;
538
731
  }
539
732
  function isLeafValue(v) {
540
733
  return (v === null ||
@@ -542,9 +735,213 @@ function isLeafValue(v) {
542
735
  typeof v === 'string' ||
543
736
  typeof v === 'number' ||
544
737
  typeof v === 'boolean' ||
738
+ isCelExpressionLike(v) ||
545
739
  // KubernetesRef proxies register as functions (typeof fn is 'function')
546
740
  typeof v === 'function');
547
741
  }
742
+ function runResourceStatusBranch(compositionFn, schemaDefinition, analysis, ternary, desiredConditionValue) {
743
+ const branchCtx = createCompositionContext('resource-status-branch', {
744
+ isReExecution: true,
745
+ });
746
+ branchCtx.liveStatusMap = createResourceStatusBranchMap(analysis, ternary, desiredConditionValue);
747
+ const branchSchema = createSchemaProxy(schemaDefinition?.spec?.json, schemaDefinition?.status?.json);
748
+ const specOverrides = createSpecConditionOverrideMap(ternary.conditionExpression, desiredConditionValue);
749
+ const branchSpec = specOverrides.size > 0
750
+ ? createSpecOverrideProxy(branchSchema.spec, specOverrides)
751
+ : branchSchema.spec;
752
+ runWithCompositionContext(branchCtx, () => {
753
+ runInStatusBuilderContext(() => {
754
+ compositionFn(branchSpec);
755
+ });
756
+ });
757
+ return branchCtx;
758
+ }
759
+ function createResourceStatusBranchMap(analysis, ternary, desiredConditionValue) {
760
+ const conditionExpression = ternary.conditionExpression ?? `${ternary.variableName}.status.${ternary.statusField}`;
761
+ const statusRefs = collectStatusRefs(conditionExpression);
762
+ if (statusRefs.length === 0) {
763
+ statusRefs.push({ variableName: ternary.variableName, statusField: ternary.statusField });
764
+ }
765
+ const statusMap = new Map();
766
+ for (const statusRef of statusRefs) {
767
+ const resourceId = analysis.variableToResourceId.get(statusRef.variableName) ?? statusRef.variableName;
768
+ const existing = statusMap.get(resourceId) ?? {};
769
+ setNestedBranchStatusValue(existing, statusRef.statusField, getBranchStatusValue(conditionExpression, `${statusRef.variableName}.status.${statusRef.statusField}`, desiredConditionValue));
770
+ statusMap.set(resourceId, existing);
771
+ }
772
+ return statusMap;
773
+ }
774
+ function setNestedBranchStatusValue(target, statusField, value) {
775
+ const parts = statusField.split('.').filter(Boolean);
776
+ if (parts.length === 0)
777
+ return;
778
+ let cursor = target;
779
+ for (let i = 0; i < parts.length - 1; i++) {
780
+ const part = parts[i];
781
+ if (!part)
782
+ continue;
783
+ const next = cursor[part];
784
+ if (!isPlainObject(next)) {
785
+ cursor[part] = {};
786
+ }
787
+ cursor = cursor[part];
788
+ }
789
+ const leaf = parts[parts.length - 1];
790
+ if (leaf) {
791
+ cursor[leaf] = value;
792
+ }
793
+ }
794
+ function collectStatusRefs(conditionExpression) {
795
+ const refs = [];
796
+ const seen = new Set();
797
+ const statusRefPattern = /\b([A-Za-z_$][\w$]*)\.status\.([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)/g;
798
+ for (const match of conditionExpression.matchAll(statusRefPattern)) {
799
+ const variableName = match[1];
800
+ const statusField = match[2];
801
+ if (!variableName || !statusField)
802
+ continue;
803
+ const key = `${variableName}:${statusField}`;
804
+ if (seen.has(key))
805
+ continue;
806
+ seen.add(key);
807
+ refs.push({ variableName, statusField });
808
+ }
809
+ return refs;
810
+ }
811
+ function createSpecConditionOverrideMap(conditionExpression, desiredConditionValue) {
812
+ const overrides = new Map();
813
+ if (!conditionExpression)
814
+ return overrides;
815
+ const specRefPattern = /\b(?:schema\.)?spec\.([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)/g;
816
+ for (const match of conditionExpression.matchAll(specRefPattern)) {
817
+ const specPath = match[1];
818
+ const fullRef = match[0];
819
+ if (!specPath || !fullRef || overrides.has(specPath))
820
+ continue;
821
+ overrides.set(specPath, getBranchStatusValue(conditionExpression, fullRef, desiredConditionValue));
822
+ }
823
+ return overrides;
824
+ }
825
+ function createSpecOverrideProxy(target, overrides, path = []) {
826
+ return new Proxy(target, {
827
+ get(obj, prop, receiver) {
828
+ if (typeof prop !== 'string')
829
+ return Reflect.get(obj, prop, receiver);
830
+ const fullPath = [...path, prop].join('.');
831
+ if (overrides.has(fullPath))
832
+ return overrides.get(fullPath);
833
+ const hasNestedOverride = [...overrides.keys()].some((key) => key.startsWith(`${fullPath}.`));
834
+ const value = Reflect.get(obj, prop, receiver);
835
+ if (hasNestedOverride && value && (typeof value === 'object' || typeof value === 'function')) {
836
+ return createSpecOverrideProxy(value, overrides, [...path, prop]);
837
+ }
838
+ return value;
839
+ },
840
+ ownKeys: (obj) => Reflect.ownKeys(obj),
841
+ getOwnPropertyDescriptor: (obj, prop) => Reflect.getOwnPropertyDescriptor(obj, prop),
842
+ });
843
+ }
844
+ function getBranchStatusValue(conditionExpression, statusRefExpression, desiredConditionValue) {
845
+ const escapedRef = statusRefExpression.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
846
+ const comparison = conditionExpression.match(new RegExp(`${escapedRef}\\s*(>=|>|<=|<|==|!=)\\s*(-?\\d+(?:\\.\\d+)?)`));
847
+ if (comparison?.[1] && comparison[2] !== undefined) {
848
+ const operator = comparison[1];
849
+ const numberValue = Number(comparison[2]);
850
+ if (operator === '>=')
851
+ return desiredConditionValue ? numberValue : numberValue - 1;
852
+ if (operator === '>')
853
+ return desiredConditionValue ? numberValue + 1 : numberValue;
854
+ if (operator === '<=')
855
+ return desiredConditionValue ? numberValue : numberValue + 1;
856
+ if (operator === '<')
857
+ return desiredConditionValue ? numberValue - 1 : numberValue;
858
+ if (operator === '==')
859
+ return desiredConditionValue ? numberValue : numberValue + 1;
860
+ if (operator === '!=')
861
+ return desiredConditionValue ? numberValue + 1 : numberValue;
862
+ }
863
+ const stringComparison = conditionExpression.match(new RegExp(`${escapedRef}\\s*(==|!=)\\s*(['"])(.*?)\\2`));
864
+ if (stringComparison?.[1] && stringComparison[3] !== undefined) {
865
+ const operator = stringComparison[1];
866
+ const stringValue = stringComparison[3];
867
+ if (operator === '==')
868
+ return desiredConditionValue ? stringValue : `__typekro_not_${stringValue}`;
869
+ if (operator === '!=')
870
+ return desiredConditionValue ? `__typekro_not_${stringValue}` : stringValue;
871
+ }
872
+ const booleanComparison = conditionExpression.match(new RegExp(`${escapedRef}\\s*(==|!=)\\s*(true|false)`));
873
+ if (booleanComparison?.[1] && booleanComparison[2] !== undefined) {
874
+ const operator = booleanComparison[1];
875
+ const booleanValue = booleanComparison[2] === 'true';
876
+ if (operator === '==')
877
+ return desiredConditionValue ? booleanValue : !booleanValue;
878
+ if (operator === '!=')
879
+ return desiredConditionValue ? !booleanValue : booleanValue;
880
+ }
881
+ const negatedRef = new RegExp(`!\\s*${escapedRef}(?![A-Za-z0-9_$.])`).test(conditionExpression);
882
+ return negatedRef ? !desiredConditionValue : desiredConditionValue;
883
+ }
884
+ function applyResourceStatusBranchDiff(targetRes, trueRes, falseRes, conditionCel, nestedStatusCel, resourceIds) {
885
+ for (const key of new Set([...Object.keys(trueRes), ...Object.keys(falseRes)])) {
886
+ if (key === '__resourceId' || key === 'id' || key.startsWith('__'))
887
+ continue;
888
+ const tv = trueRes[key];
889
+ const fv = falseRes[key];
890
+ if (tv === undefined && fv !== undefined) {
891
+ const falseRepr = celValueRepr(fv, nestedStatusCel, resourceIds);
892
+ targetRes[key] = `\${${conditionCel} ? omit() : ${falseRepr}}`;
893
+ continue;
894
+ }
895
+ if (fv === undefined && tv !== undefined) {
896
+ const trueRepr = celValueRepr(tv, nestedStatusCel, resourceIds);
897
+ targetRes[key] = `\${${conditionCel} ? ${trueRepr} : omit()}`;
898
+ continue;
899
+ }
900
+ if (tv === undefined || fv === undefined)
901
+ continue;
902
+ if (isCelExpressionLike(tv) || isCelExpressionLike(fv)) {
903
+ if (!leafEquals(tv, fv)) {
904
+ const trueRepr = celValueRepr(tv, nestedStatusCel, resourceIds);
905
+ const falseRepr = celValueRepr(fv, nestedStatusCel, resourceIds);
906
+ targetRes[key] = `\${${conditionCel} ? ${trueRepr} : ${falseRepr}}`;
907
+ }
908
+ continue;
909
+ }
910
+ const targetValue = targetRes[key];
911
+ if (isPlainObject(tv) && isPlainObject(fv)) {
912
+ if (!isPlainObject(targetValue))
913
+ targetRes[key] = {};
914
+ applyResourceStatusBranchDiff(targetRes[key], tv, fv, conditionCel, nestedStatusCel, resourceIds);
915
+ }
916
+ else if (Array.isArray(tv) && Array.isArray(fv) && tv.length === fv.length) {
917
+ if (!Array.isArray(targetValue))
918
+ targetRes[key] = [...tv];
919
+ const targetArray = targetRes[key];
920
+ for (let i = 0; i < tv.length; i++) {
921
+ if (isPlainObject(tv[i]) && isPlainObject(fv[i])) {
922
+ if (!isPlainObject(targetArray[i]))
923
+ targetArray[i] = {};
924
+ applyResourceStatusBranchDiff(targetArray[i], tv[i], fv[i], conditionCel, nestedStatusCel, resourceIds);
925
+ }
926
+ else if (!leafEquals(tv[i], fv[i])) {
927
+ const trueRepr = celValueRepr(tv[i], nestedStatusCel, resourceIds);
928
+ const falseRepr = celValueRepr(fv[i], nestedStatusCel, resourceIds);
929
+ targetArray[i] = `\${${conditionCel} ? ${trueRepr} : ${falseRepr}}`;
930
+ }
931
+ }
932
+ }
933
+ else if (Array.isArray(tv) && Array.isArray(fv) && tv.length !== fv.length) {
934
+ const trueRepr = celValueRepr(tv, nestedStatusCel, resourceIds);
935
+ const falseRepr = celValueRepr(fv, nestedStatusCel, resourceIds);
936
+ targetRes[key] = `\${${conditionCel} ? ${trueRepr} : ${falseRepr}}`;
937
+ }
938
+ else if (!leafEquals(tv, fv)) {
939
+ const trueRepr = celValueRepr(tv, nestedStatusCel, resourceIds);
940
+ const falseRepr = celValueRepr(fv, nestedStatusCel, resourceIds);
941
+ targetRes[key] = `\${${conditionCel} ? ${trueRepr} : ${falseRepr}}`;
942
+ }
943
+ }
944
+ }
548
945
  function leafEquals(a, b) {
549
946
  // For KubernetesRef proxies, compare their string coercions (marker tokens).
550
947
  if (typeof a === 'function' || typeof b === 'function') {
@@ -552,8 +949,45 @@ function leafEquals(a, b) {
552
949
  }
553
950
  return a === b;
554
951
  }
952
+ function getNestedResourceStatusTargetIds(resources, nestedCompositionIds) {
953
+ if (!nestedCompositionIds || nestedCompositionIds.size === 0)
954
+ return [];
955
+ return Object.entries(resources)
956
+ .filter(([resourceId, resource]) => [...nestedCompositionIds].some((nestedId) => isNestedCompositionChild(resourceId, resource, nestedId)))
957
+ .map(([resourceId]) => resourceId);
958
+ }
959
+ function isNestedCompositionChild(resourceId, resource, nestedId) {
960
+ if (resourceId === nestedId)
961
+ return true;
962
+ const boundaryChar = resourceId[nestedId.length];
963
+ if (resourceId.startsWith(nestedId) && boundaryChar !== undefined && /[A-Z_-]/.test(boundaryChar)) {
964
+ return true;
965
+ }
966
+ const aliases = getMetadataField(resource, 'resourceAliases');
967
+ return aliases?.some((alias) => {
968
+ if (alias === nestedId)
969
+ return true;
970
+ const aliasBoundaryChar = alias[nestedId.length];
971
+ return alias.startsWith(nestedId) && aliasBoundaryChar !== undefined && /[A-Z_-]/.test(aliasBoundaryChar);
972
+ }) ?? false;
973
+ }
555
974
  function isPlainObject(v) {
556
- return typeof v === 'object' && v !== null && !Array.isArray(v);
975
+ return typeof v === 'object' && v !== null && !Array.isArray(v) && !isCelExpressionLike(v);
976
+ }
977
+ function isWalkableRecord(v) {
978
+ if (isPlainObject(v)) {
979
+ return true;
980
+ }
981
+ return typeof v === 'function' && Object.keys(v).length > 0;
982
+ }
983
+ /** Duck-type check for CelExpression objects — avoids importing from cel.ts (cycle risk). */
984
+ function isCelExpressionLike(v) {
985
+ if (typeof v !== 'object' || v === null)
986
+ return false;
987
+ // Plain Cel.expr() objects carry the symbol brand; template expressions also
988
+ // carry `__isTemplate`. Support both shapes without importing cel.ts.
989
+ return 'expression' in v && typeof v.expression === 'string'
990
+ && (v[CEL_EXPRESSION_BRAND] === true || '__isTemplate' in v);
557
991
  }
558
992
  /**
559
993
  * Build a CEL conditional string from two diverging leaf values.
@@ -564,11 +998,44 @@ function isPlainObject(v) {
564
998
  * `${has(schema.spec.X) ? <proxy repr> : <hybrid repr>}` that later
565
999
  * serialization phases treat as a final CEL expression.
566
1000
  */
567
- function buildCelConditional(proxyValue, hybridValue, overriddenFields) {
1001
+ function buildCelConditional(proxyValue, hybridValue, overriddenFields, overrideConditions, nestedStatusCel, resourceIds) {
568
1002
  const field = pickConditionField(proxyValue, hybridValue, overriddenFields);
569
- const proxyRepr = celValueRepr(proxyValue);
570
- const hybridRepr = celValueRepr(hybridValue);
571
- return `\${has(schema.spec.${field}) ? ${proxyRepr} : ${hybridRepr}}`;
1003
+ const proxyRepr = celValueRepr(proxyValue, nestedStatusCel, resourceIds);
1004
+ const hybridRepr = celValueRepr(hybridValue, nestedStatusCel, resourceIds);
1005
+ const explicitCondition = overrideConditions.get(field);
1006
+ if (explicitCondition) {
1007
+ return `\${${explicitCondition} ? ${proxyRepr} : ${hybridRepr}}`;
1008
+ }
1009
+ // Chain has() guards when the proxy value references a sub-field deeper
1010
+ // than the controlling optional field. A single has(schema.spec.X) is
1011
+ // insufficient when the value accesses X.Y — the user may provide X: {}
1012
+ // without Y, and KRO would fail with "no such key: Y".
1013
+ const guardField = `schema.spec.${field}`;
1014
+ let guard = `has(${guardField})`;
1015
+ // Extract the full schema path from the proxy repr to check depth.
1016
+ // proxyRepr may be a bare path like `schema.spec.cnpgOperator.version`
1017
+ // or wrapped in string() like `string(schema.spec.cnpgOperator.version)`.
1018
+ // Chain has() guards for ALL intermediate levels between the controlling
1019
+ // field and the leaf. For `cnpgOperator.monitoring.enabled`, we need:
1020
+ // has(cnpgOperator) && has(cnpgOperator.monitoring) && has(cnpgOperator.monitoring.enabled)
1021
+ const schemaPathMatch = proxyRepr.match(/schema\.spec\.([a-zA-Z0-9_.]+)/);
1022
+ if (schemaPathMatch) {
1023
+ const fullRefPath = schemaPathMatch[1]?.replace(/\.+$/, '');
1024
+ if (!fullRefPath)
1025
+ return `\${has(${guardField}) ? ${proxyRepr} : ${hybridRepr}}`;
1026
+ const fullPath = `schema.spec.${fullRefPath}`;
1027
+ if (fullPath !== guardField && fullPath.startsWith(`${guardField}.`)) {
1028
+ const guardSegments = field.split('.').length;
1029
+ const leafSegments = fullRefPath.split('.');
1030
+ const guards = [`has(${guardField})`];
1031
+ for (let j = guardSegments + 1; j <= leafSegments.length; j++) {
1032
+ const intermediatePath = `schema.spec.${leafSegments.slice(0, j).join('.')}`;
1033
+ guards.push(`has(${intermediatePath})`);
1034
+ }
1035
+ guard = guards.join(' && ');
1036
+ }
1037
+ }
1038
+ return `\${${guard} ? ${proxyRepr} : ${hybridRepr}}`;
572
1039
  }
573
1040
  /**
574
1041
  * Pick the "controlling" optional field for a diverging leaf. If exactly
@@ -612,11 +1079,18 @@ function pickConditionField(proxyValue, hybridValue, overriddenFields) {
612
1079
  * result is valid CEL, not just a raw string)
613
1080
  * - Numbers and booleans are emitted verbatim
614
1081
  */
615
- function celValueRepr(value) {
1082
+ // Re-export from shared utility for local use. This was previously an
1083
+ // inline copy; the canonical implementation lives in utils/cel-escape.ts.
1084
+ import { escapeCelString as escapeCelLiteral } from '../../utils/cel-escape.js';
1085
+ function celValueRepr(value, nestedStatusCel, resourceIds) {
616
1086
  if (value === null || value === undefined)
617
1087
  return '""';
618
1088
  if (typeof value === 'number' || typeof value === 'boolean')
619
1089
  return String(value);
1090
+ // CelExpression object — use the expression string directly.
1091
+ if (isCelExpressionLike(value)) {
1092
+ return unwrapKroExpression(finalizeCelForKro(value.expression, nestedStatusCel, createBranchCelContext(nestedStatusCel, resourceIds)));
1093
+ }
620
1094
  if (typeof value === 'function') {
621
1095
  // KubernetesRef proxy — toString yields the marker token which we
622
1096
  // convert to a bare CEL path via the marker → CEL rules.
@@ -627,16 +1101,40 @@ function celValueRepr(value) {
627
1101
  return markerStringToCelExpr(value);
628
1102
  }
629
1103
  // Plain string literal — escape for CEL embedding
630
- return `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
1104
+ return `"${escapeCelLiteral(value)}"`;
1105
+ }
1106
+ if (Array.isArray(value)) {
1107
+ return `[${value.map((item) => celValueRepr(item, nestedStatusCel, resourceIds)).join(', ')}]`;
1108
+ }
1109
+ if (isPlainObject(value)) {
1110
+ return `{${Object.entries(value)
1111
+ .map(([key, entryValue]) => `"${escapeCelLiteral(key)}": ${celValueRepr(entryValue, nestedStatusCel, resourceIds)}`)
1112
+ .join(', ')}}`;
631
1113
  }
632
1114
  return '""';
633
1115
  }
1116
+ function createBranchCelContext(nestedStatusCel, resourceIds) {
1117
+ if (!nestedStatusCel && !resourceIds)
1118
+ return undefined;
1119
+ return {
1120
+ celPrefix: '',
1121
+ resourceIdStrategy: 'deterministic',
1122
+ ...(nestedStatusCel ? { nestedStatusCel } : {}),
1123
+ ...(resourceIds ? { resourceIds } : {}),
1124
+ };
1125
+ }
1126
+ function unwrapKroExpression(value) {
1127
+ if (value.startsWith('${') && value.endsWith('}') && value.indexOf('${', 2) === -1) {
1128
+ return value.slice(2, -1);
1129
+ }
1130
+ return value;
1131
+ }
634
1132
  /**
635
1133
  * Convert a single-marker string (the whole string is one marker) to
636
1134
  * its bare CEL path form: `schema.spec.X` or `resources.X.field`.
637
1135
  */
638
1136
  function markerStringToCelBare(str) {
639
- const m = str.match(/^__KUBERNETES_REF_(__schema__|[^_]+)_([a-zA-Z0-9.$]+)__$/);
1137
+ const m = str.match(new RegExp(`^${KUBERNETES_REF_MARKER_SOURCE}$`));
640
1138
  if (!m)
641
1139
  return markerStringToCelExpr(str);
642
1140
  const [, resourceId, fieldPath] = m;
@@ -648,8 +1146,9 @@ function markerStringToCelBare(str) {
648
1146
  * embedding inside a CEL ternary.
649
1147
  */
650
1148
  function markerStringToCelExpr(str) {
1149
+ const markerSource = KUBERNETES_REF_MARKER_SOURCE;
651
1150
  // Fast path: whole string is a single marker
652
- const singleMatch = str.match(/^__KUBERNETES_REF_(__schema__|[^_]+)_([a-zA-Z0-9.$]+)__$/);
1151
+ const singleMatch = str.match(new RegExp(`^${markerSource}$`));
653
1152
  if (singleMatch) {
654
1153
  const [, resourceId, fieldPath] = singleMatch;
655
1154
  return resourceId === '__schema__' ? `schema.${fieldPath}` : `${resourceId}.${fieldPath}`;
@@ -657,15 +1156,19 @@ function markerStringToCelExpr(str) {
657
1156
  // Slow path: interleave literal text and markers via CEL string concatenation
658
1157
  const parts = [];
659
1158
  let lastIndex = 0;
660
- const pattern = /__KUBERNETES_REF_(__schema__|[^_]+)_([a-zA-Z0-9.$]+)__/g;
1159
+ const pattern = new RegExp(markerSource, 'g');
661
1160
  let m = pattern.exec(str);
662
1161
  while (m !== null) {
663
1162
  if (m.index > lastIndex) {
664
1163
  const literal = str.slice(lastIndex, m.index);
665
- parts.push(`"${literal.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`);
1164
+ parts.push(`"${escapeCelLiteral(literal)}"`);
666
1165
  }
667
1166
  const resourceId = m[1];
668
1167
  const fieldPath = m[2];
1168
+ if (!resourceId || !fieldPath) {
1169
+ m = pattern.exec(str);
1170
+ continue;
1171
+ }
669
1172
  const celPath = resourceId === '__schema__' ? `schema.${fieldPath}` : `${resourceId}.${fieldPath}`;
670
1173
  parts.push(`string(${celPath})`);
671
1174
  lastIndex = m.index + m[0].length;
@@ -673,9 +1176,10 @@ function markerStringToCelExpr(str) {
673
1176
  }
674
1177
  if (lastIndex < str.length) {
675
1178
  const literal = str.slice(lastIndex);
676
- parts.push(`"${literal.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`);
1179
+ parts.push(`"${escapeCelLiteral(literal)}"`);
677
1180
  }
678
- return parts.length === 1 ? parts[0] : parts.join(' + ');
1181
+ const [firstPart] = parts;
1182
+ return parts.length === 1 && firstPart !== undefined ? firstPart : parts.join(' + ');
679
1183
  }
680
1184
  // =============================================================================
681
1185
  // Extracted helper: Direct factory status re-analysis
@@ -828,10 +1332,14 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
828
1332
  const schemaDefinition = {
829
1333
  apiVersion: definition.apiVersion || 'v1alpha1',
830
1334
  kind: definition.kind,
1335
+ ...(definition.group && { group: definition.group }),
831
1336
  spec: definition.spec,
832
1337
  status: definition.status,
833
1338
  };
834
- const schema = createSchemaProxy();
1339
+ // Pass the Arktype JSON so the proxy is shape-aware — spread
1340
+ // (`{ ...spec.X }`) and `Object.keys(spec.X)` enumerate declared
1341
+ // fields instead of returning an opaque empty object.
1342
+ const schema = createSchemaProxy(definition.spec?.json, definition.status?.json);
835
1343
  const builderResult = resourceBuilder(schema);
836
1344
  const { resources: resourcesWithKeys, closures } = separateResourcesAndClosures(builderResult);
837
1345
  // 3. Analyze status builder and convert JS expressions to CEL
@@ -856,6 +1364,18 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
856
1364
  // Evaluate and optimize CEL expressions
857
1365
  const evaluationContext = { resources: resourcesWithKeys, schema };
858
1366
  const { mappings: optimizedStatusMappings, optimizations } = optimizeStatusMappings(analyzedStatusMappings, evaluationContext);
1367
+ for (const metadataKey of [
1368
+ '__originalCompositionFn',
1369
+ '__nestedCompositionFns',
1370
+ '__nestedCompositionDefinitions',
1371
+ '__nestedCompositionResources',
1372
+ '__nestedCompositionSpecMappings',
1373
+ ]) {
1374
+ const descriptor = Object.getOwnPropertyDescriptor(statusMappings, metadataKey);
1375
+ if (descriptor) {
1376
+ Object.defineProperty(optimizedStatusMappings, metadataKey, descriptor);
1377
+ }
1378
+ }
859
1379
  if (optimizations.length > 0) {
860
1380
  serializationLogger.info('CEL expression optimizations applied', { optimizations });
861
1381
  }
@@ -890,6 +1410,11 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
890
1410
  statusMappings: directStatusMappings,
891
1411
  compositionFn: declarativeCompositionFn,
892
1412
  compositionDefinition: definition,
1413
+ ...(this._singletonDefinitions
1414
+ ? {
1415
+ singletonDefinitions: this._singletonDefinitions,
1416
+ }
1417
+ : {}),
893
1418
  });
894
1419
  }
895
1420
  else if (mode === 'kro') {
@@ -898,13 +1423,22 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
898
1423
  closures,
899
1424
  factoryType: 'kro',
900
1425
  compositionFn: declarativeCompositionFn,
1426
+ compositionAnalysis,
1427
+ ...(this._singletonDefinitions
1428
+ ? {
1429
+ singletonDefinitions: this._singletonDefinitions,
1430
+ }
1431
+ : {}),
901
1432
  });
902
1433
  }
903
1434
  else {
904
1435
  throw new ValidationError(`Unsupported factory mode: ${mode}`, 'ResourceGraphDefinition', definition.name, 'mode', ['Use "kro" or "direct" as the factory mode']);
905
1436
  }
906
1437
  },
907
- toYaml() {
1438
+ toYaml(spec) {
1439
+ if (spec !== undefined) {
1440
+ return this.factory('kro').toYaml(spec);
1441
+ }
908
1442
  // Apply composition body analysis results (guard: only once)
909
1443
  if (compositionAnalysis && !analysisState.appliedToResources) {
910
1444
  analysisState.appliedToResources = true;
@@ -921,10 +1455,13 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
921
1455
  // Collect nested composition status CEL mappings from the composition context.
922
1456
  // These enable inlining the inner composition's real CEL expressions instead
923
1457
  // of referencing virtual nested composition IDs.
924
- // Extract nested composition status CEL mappings attached by executeCompositionCore.
925
- // These are on the raw statusMappings (capturedStatus from the composition function),
926
- // not on the optimizedStatusMappings (which is a processed copy).
927
- const nestedStatusCel = statusMappings.__nestedStatusCel ?? {};
1458
+ // Extract nested composition status CEL mappings attached by
1459
+ // executeCompositionCore via Reflect.set. Must use
1460
+ // Object.getOwnPropertyDescriptor to bypass the Enhanced proxy's
1461
+ // get handler which would return a KubernetesRef instead of the
1462
+ // actual Record<string, string>.
1463
+ const nestedStatusDescriptor = Object.getOwnPropertyDescriptor(statusMappings, '__nestedStatusCel');
1464
+ const nestedStatusCel = nestedStatusDescriptor?.value ?? {};
928
1465
  serializationLogger.debug('Nested status CEL extraction', {
929
1466
  hasNestedStatusCel: Object.keys(nestedStatusCel).length > 0,
930
1467
  keys: Object.keys(nestedStatusCel),
@@ -934,6 +1471,17 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
934
1471
  if (definition.group) {
935
1472
  kroSchema.group = definition.group;
936
1473
  }
1474
+ // Attach nested status CEL mappings to the schema as a non-enumerable
1475
+ // property (same pattern as __ternaryConditionals, __omitFields).
1476
+ // Non-enumerable so it doesn't appear in the YAML output, but
1477
+ // accessible via KroSimpleSchemaWithMetadata for the YAML serializer
1478
+ // to resolve virtual composition IDs in resource templates.
1479
+ if (Object.keys(nestedStatusCel).length > 0) {
1480
+ Object.defineProperty(kroSchema, '__nestedStatusCel', {
1481
+ value: nestedStatusCel,
1482
+ enumerable: false,
1483
+ });
1484
+ }
937
1485
  // Inject status overrides into schema status section.
938
1486
  // Convert "..." to '...' in CEL string literals for YAML compatibility.
939
1487
  const statusOverrides = compositionAnalysis?.statusOverrides ?? [];
@@ -955,7 +1503,7 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
955
1503
  if (!analysisState.ternaryAndOmitApplied) {
956
1504
  analysisState.ternaryAndOmitApplied = true;
957
1505
  if (kroSchema.__ternaryConditionals?.length) {
958
- applyTernaryConditionalsToResources(resourcesWithKeys, kroSchema.__ternaryConditionals);
1506
+ applyTernaryConditionalsToResources(resourcesWithKeys, kroSchema.__ternaryConditionals, kroSchema.__nestedStatusCel);
959
1507
  }
960
1508
  }
961
1509
  return serializeResourceGraphToYaml(definition.name, resourcesWithKeys, options, kroSchema);