typekro 0.7.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 (532) 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 +39 -7
  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 +4 -4
  44. package/dist/core/containers/build.d.ts.map +1 -1
  45. package/dist/core/containers/build.js +44 -16
  46. package/dist/core/containers/build.js.map +1 -1
  47. package/dist/core/containers/registries/types.d.ts +1 -1
  48. package/dist/core/containers/registries/types.d.ts.map +1 -1
  49. package/dist/core/dependencies/resolver.d.ts +19 -0
  50. package/dist/core/dependencies/resolver.d.ts.map +1 -1
  51. package/dist/core/dependencies/resolver.js +261 -1
  52. package/dist/core/dependencies/resolver.js.map +1 -1
  53. package/dist/core/deployment/client-provider-manager.d.ts +9 -3
  54. package/dist/core/deployment/client-provider-manager.d.ts.map +1 -1
  55. package/dist/core/deployment/client-provider-manager.js +12 -0
  56. package/dist/core/deployment/client-provider-manager.js.map +1 -1
  57. package/dist/core/deployment/crd-manager.d.ts +24 -0
  58. package/dist/core/deployment/crd-manager.d.ts.map +1 -1
  59. package/dist/core/deployment/crd-manager.js +79 -1
  60. package/dist/core/deployment/crd-manager.js.map +1 -1
  61. package/dist/core/deployment/deployment-state-discovery.d.ts +116 -0
  62. package/dist/core/deployment/deployment-state-discovery.d.ts.map +1 -0
  63. package/dist/core/deployment/deployment-state-discovery.js +400 -0
  64. package/dist/core/deployment/deployment-state-discovery.js.map +1 -0
  65. package/dist/core/deployment/direct-factory.d.ts +65 -6
  66. package/dist/core/deployment/direct-factory.d.ts.map +1 -1
  67. package/dist/core/deployment/direct-factory.js +551 -56
  68. package/dist/core/deployment/direct-factory.js.map +1 -1
  69. package/dist/core/deployment/engine.d.ts +64 -3
  70. package/dist/core/deployment/engine.d.ts.map +1 -1
  71. package/dist/core/deployment/engine.js +194 -27
  72. package/dist/core/deployment/engine.js.map +1 -1
  73. package/dist/core/deployment/event-filter.js +1 -1
  74. package/dist/core/deployment/event-filter.js.map +1 -1
  75. package/dist/core/deployment/event-monitor.d.ts +11 -0
  76. package/dist/core/deployment/event-monitor.d.ts.map +1 -1
  77. package/dist/core/deployment/event-monitor.js +14 -0
  78. package/dist/core/deployment/event-monitor.js.map +1 -1
  79. package/dist/core/deployment/handle-tracing.d.ts +14 -0
  80. package/dist/core/deployment/handle-tracing.d.ts.map +1 -0
  81. package/dist/core/deployment/handle-tracing.js +38 -0
  82. package/dist/core/deployment/handle-tracing.js.map +1 -0
  83. package/dist/core/deployment/kro-factory.d.ts +136 -3
  84. package/dist/core/deployment/kro-factory.d.ts.map +1 -1
  85. package/dist/core/deployment/kro-factory.js +945 -268
  86. package/dist/core/deployment/kro-factory.js.map +1 -1
  87. package/dist/core/deployment/kro-readiness.d.ts.map +1 -1
  88. package/dist/core/deployment/kro-readiness.js +21 -12
  89. package/dist/core/deployment/kro-readiness.js.map +1 -1
  90. package/dist/core/deployment/nested-composition-status.d.ts +1 -1
  91. package/dist/core/deployment/nested-composition-status.d.ts.map +1 -1
  92. package/dist/core/deployment/nested-composition-status.js +96 -53
  93. package/dist/core/deployment/nested-composition-status.js.map +1 -1
  94. package/dist/core/deployment/resource-applier.d.ts +15 -2
  95. package/dist/core/deployment/resource-applier.d.ts.map +1 -1
  96. package/dist/core/deployment/resource-applier.js +75 -25
  97. package/dist/core/deployment/resource-applier.js.map +1 -1
  98. package/dist/core/deployment/resource-tagging.d.ts +220 -0
  99. package/dist/core/deployment/resource-tagging.d.ts.map +1 -0
  100. package/dist/core/deployment/resource-tagging.js +292 -0
  101. package/dist/core/deployment/resource-tagging.js.map +1 -0
  102. package/dist/core/deployment/rollback-manager.d.ts +25 -4
  103. package/dist/core/deployment/rollback-manager.d.ts.map +1 -1
  104. package/dist/core/deployment/rollback-manager.js +70 -57
  105. package/dist/core/deployment/rollback-manager.js.map +1 -1
  106. package/dist/core/deployment/shared-utilities.d.ts +6 -0
  107. package/dist/core/deployment/shared-utilities.d.ts.map +1 -1
  108. package/dist/core/deployment/shared-utilities.js +32 -2
  109. package/dist/core/deployment/shared-utilities.js.map +1 -1
  110. package/dist/core/deployment/singleton-owner-drift.d.ts +16 -0
  111. package/dist/core/deployment/singleton-owner-drift.d.ts.map +1 -0
  112. package/dist/core/deployment/singleton-owner-drift.js +54 -0
  113. package/dist/core/deployment/singleton-owner-drift.js.map +1 -0
  114. package/dist/core/deployment/strategies/alchemy-strategy.d.ts +3 -1
  115. package/dist/core/deployment/strategies/alchemy-strategy.d.ts.map +1 -1
  116. package/dist/core/deployment/strategies/alchemy-strategy.js +121 -18
  117. package/dist/core/deployment/strategies/alchemy-strategy.js.map +1 -1
  118. package/dist/core/deployment/strategies/base-strategy.d.ts +9 -3
  119. package/dist/core/deployment/strategies/base-strategy.d.ts.map +1 -1
  120. package/dist/core/deployment/strategies/base-strategy.js +32 -4
  121. package/dist/core/deployment/strategies/base-strategy.js.map +1 -1
  122. package/dist/core/deployment/strategies/direct-strategy.d.ts +12 -4
  123. package/dist/core/deployment/strategies/direct-strategy.d.ts.map +1 -1
  124. package/dist/core/deployment/strategies/direct-strategy.js +112 -8
  125. package/dist/core/deployment/strategies/direct-strategy.js.map +1 -1
  126. package/dist/core/errors.d.ts +2 -2
  127. package/dist/core/errors.d.ts.map +1 -1
  128. package/dist/core/errors.js.map +1 -1
  129. package/dist/core/expressions/analysis/cache.d.ts +2 -2
  130. package/dist/core/expressions/analysis/cache.d.ts.map +1 -1
  131. package/dist/core/expressions/analysis/cache.js +4 -0
  132. package/dist/core/expressions/analysis/cache.js.map +1 -1
  133. package/dist/core/expressions/analysis/fn-toString-self-test.d.ts.map +1 -1
  134. package/dist/core/expressions/analysis/fn-toString-self-test.js +0 -1
  135. package/dist/core/expressions/analysis/fn-toString-self-test.js.map +1 -1
  136. package/dist/core/expressions/analysis/shared-types.d.ts +2 -2
  137. package/dist/core/expressions/analysis/shared-types.d.ts.map +1 -1
  138. package/dist/core/expressions/analysis/source-map.d.ts.map +1 -1
  139. package/dist/core/expressions/analysis/source-map.js +1 -0
  140. package/dist/core/expressions/analysis/source-map.js.map +1 -1
  141. package/dist/core/expressions/analysis/types.d.ts +7 -7
  142. package/dist/core/expressions/analysis/types.d.ts.map +1 -1
  143. package/dist/core/expressions/composition/composition-analyzer-helpers.d.ts +37 -3
  144. package/dist/core/expressions/composition/composition-analyzer-helpers.d.ts.map +1 -1
  145. package/dist/core/expressions/composition/composition-analyzer-helpers.js +370 -7
  146. package/dist/core/expressions/composition/composition-analyzer-helpers.js.map +1 -1
  147. package/dist/core/expressions/composition/composition-analyzer-ternary.d.ts +2 -2
  148. package/dist/core/expressions/composition/composition-analyzer-ternary.d.ts.map +1 -1
  149. package/dist/core/expressions/composition/composition-analyzer-ternary.js +264 -29
  150. package/dist/core/expressions/composition/composition-analyzer-ternary.js.map +1 -1
  151. package/dist/core/expressions/composition/composition-analyzer-traversal.d.ts.map +1 -1
  152. package/dist/core/expressions/composition/composition-analyzer-traversal.js +78 -6
  153. package/dist/core/expressions/composition/composition-analyzer-traversal.js.map +1 -1
  154. package/dist/core/expressions/composition/composition-analyzer-types.d.ts +60 -0
  155. package/dist/core/expressions/composition/composition-analyzer-types.d.ts.map +1 -1
  156. package/dist/core/expressions/composition/composition-analyzer.d.ts +1 -1
  157. package/dist/core/expressions/composition/composition-analyzer.d.ts.map +1 -1
  158. package/dist/core/expressions/composition/composition-analyzer.js +158 -8
  159. package/dist/core/expressions/composition/composition-analyzer.js.map +1 -1
  160. package/dist/core/expressions/composition/expression-analyzer.d.ts.map +1 -1
  161. package/dist/core/expressions/composition/expression-analyzer.js +21 -4
  162. package/dist/core/expressions/composition/expression-analyzer.js.map +1 -1
  163. package/dist/core/expressions/composition/imperative-analyzer.d.ts +1 -1
  164. package/dist/core/expressions/composition/imperative-analyzer.d.ts.map +1 -1
  165. package/dist/core/expressions/composition/imperative-analyzer.js +31 -7
  166. package/dist/core/expressions/composition/imperative-analyzer.js.map +1 -1
  167. package/dist/core/expressions/composition/scope-manager.d.ts +2 -2
  168. package/dist/core/expressions/composition/scope-manager.d.ts.map +1 -1
  169. package/dist/core/expressions/composition/scope-manager.js.map +1 -1
  170. package/dist/core/expressions/conditional/conditional-expression-processor.d.ts +3 -3
  171. package/dist/core/expressions/conditional/conditional-expression-processor.d.ts.map +1 -1
  172. package/dist/core/expressions/conditional/conditional-expression-processor.js.map +1 -1
  173. package/dist/core/expressions/conditional/conditional-integration.d.ts.map +1 -1
  174. package/dist/core/expressions/conditional/conditional-integration.js.map +1 -1
  175. package/dist/core/expressions/context/context-aware-generator.d.ts +5 -5
  176. package/dist/core/expressions/context/context-aware-generator.d.ts.map +1 -1
  177. package/dist/core/expressions/context/context-aware-generator.js.map +1 -1
  178. package/dist/core/expressions/context/context-detector.d.ts +3 -3
  179. package/dist/core/expressions/context/context-detector.d.ts.map +1 -1
  180. package/dist/core/expressions/context/context-detector.js.map +1 -1
  181. package/dist/core/expressions/context/context-validator.d.ts +6 -6
  182. package/dist/core/expressions/context/context-validator.d.ts.map +1 -1
  183. package/dist/core/expressions/context/context-validator.js +2 -2
  184. package/dist/core/expressions/context/context-validator.js.map +1 -1
  185. package/dist/core/expressions/factory/cel-conversion-engine.d.ts +4 -4
  186. package/dist/core/expressions/factory/cel-conversion-engine.d.ts.map +1 -1
  187. package/dist/core/expressions/factory/cel-conversion-engine.js.map +1 -1
  188. package/dist/core/expressions/factory/dependency-tracker.d.ts +2 -2
  189. package/dist/core/expressions/factory/dependency-tracker.d.ts.map +1 -1
  190. package/dist/core/expressions/factory/dependency-tracker.js +21 -5
  191. package/dist/core/expressions/factory/dependency-tracker.js.map +1 -1
  192. package/dist/core/expressions/factory/factory-integration.d.ts +2 -4
  193. package/dist/core/expressions/factory/factory-integration.d.ts.map +1 -1
  194. package/dist/core/expressions/factory/factory-integration.js +0 -6
  195. package/dist/core/expressions/factory/factory-integration.js.map +1 -1
  196. package/dist/core/expressions/factory/factory-pattern-handler.d.ts +3 -3
  197. package/dist/core/expressions/factory/factory-pattern-handler.d.ts.map +1 -1
  198. package/dist/core/expressions/factory/factory-pattern-handler.js +1 -0
  199. package/dist/core/expressions/factory/factory-pattern-handler.js.map +1 -1
  200. package/dist/core/expressions/factory/migration-helpers.js.map +1 -1
  201. package/dist/core/expressions/factory/resource-analyzer.d.ts +4 -4
  202. package/dist/core/expressions/factory/resource-analyzer.d.ts.map +1 -1
  203. package/dist/core/expressions/factory/resource-analyzer.js.map +1 -1
  204. package/dist/core/expressions/factory/resource-type-validator.d.ts +5 -5
  205. package/dist/core/expressions/factory/resource-type-validator.d.ts.map +1 -1
  206. package/dist/core/expressions/factory/resource-type-validator.js.map +1 -1
  207. package/dist/core/expressions/factory/status-builder-analyzer.d.ts +6 -7
  208. package/dist/core/expressions/factory/status-builder-analyzer.d.ts.map +1 -1
  209. package/dist/core/expressions/factory/status-builder-analyzer.js +0 -3
  210. package/dist/core/expressions/factory/status-builder-analyzer.js.map +1 -1
  211. package/dist/core/expressions/factory/status-builder-types.d.ts +1 -1
  212. package/dist/core/expressions/factory/status-builder-types.d.ts.map +1 -1
  213. package/dist/core/expressions/factory/status-cel-generation.d.ts +1 -1
  214. package/dist/core/expressions/factory/status-cel-generation.d.ts.map +1 -1
  215. package/dist/core/expressions/factory/status-cel-generation.js +1 -1
  216. package/dist/core/expressions/factory/status-cel-generation.js.map +1 -1
  217. package/dist/core/expressions/factory/status-field-analysis.d.ts +3 -3
  218. package/dist/core/expressions/factory/status-field-analysis.d.ts.map +1 -1
  219. package/dist/core/expressions/factory/status-field-analysis.js.map +1 -1
  220. package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.d.ts +5 -5
  221. package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.d.ts.map +1 -1
  222. package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.js +1 -1
  223. package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.js.map +1 -1
  224. package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.d.ts +10 -10
  225. package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.d.ts.map +1 -1
  226. package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.js +5 -1
  227. package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.js.map +1 -1
  228. package/dist/core/expressions/magic-proxy/magic-proxy-ast.d.ts +2 -2
  229. package/dist/core/expressions/magic-proxy/magic-proxy-ast.d.ts.map +1 -1
  230. package/dist/core/expressions/magic-proxy/magic-proxy-ast.js.map +1 -1
  231. package/dist/core/expressions/magic-proxy/magic-proxy-detector.d.ts +5 -5
  232. package/dist/core/expressions/magic-proxy/magic-proxy-detector.d.ts.map +1 -1
  233. package/dist/core/expressions/magic-proxy/magic-proxy-detector.js.map +1 -1
  234. package/dist/core/expressions/magic-proxy/magic-proxy-types.d.ts +2 -2
  235. package/dist/core/expressions/magic-proxy/magic-proxy-types.d.ts.map +1 -1
  236. package/dist/core/expressions/magic-proxy/optionality-handler.d.ts +1 -2
  237. package/dist/core/expressions/magic-proxy/optionality-handler.d.ts.map +1 -1
  238. package/dist/core/expressions/magic-proxy/optionality-handler.js +2 -15
  239. package/dist/core/expressions/magic-proxy/optionality-handler.js.map +1 -1
  240. package/dist/core/expressions/validation/compile-time-checker.d.ts +1 -1
  241. package/dist/core/expressions/validation/compile-time-checker.d.ts.map +1 -1
  242. package/dist/core/expressions/validation/compile-time-checker.js.map +1 -1
  243. package/dist/core/expressions/validation/compile-time-types.d.ts +2 -2
  244. package/dist/core/expressions/validation/compile-time-types.d.ts.map +1 -1
  245. package/dist/core/expressions/validation/kubernetes-field-types.d.ts +4 -4
  246. package/dist/core/expressions/validation/kubernetes-field-types.d.ts.map +1 -1
  247. package/dist/core/expressions/validation/kubernetes-field-types.js.map +1 -1
  248. package/dist/core/expressions/validation/resource-field-utils.d.ts +10 -10
  249. package/dist/core/expressions/validation/resource-field-utils.d.ts.map +1 -1
  250. package/dist/core/expressions/validation/resource-field-utils.js.map +1 -1
  251. package/dist/core/expressions/validation/resource-validation.d.ts +3 -3
  252. package/dist/core/expressions/validation/resource-validation.d.ts.map +1 -1
  253. package/dist/core/expressions/validation/resource-validation.js.map +1 -1
  254. package/dist/core/expressions/validation/type-inference-types.d.ts +2 -2
  255. package/dist/core/expressions/validation/type-inference-types.d.ts.map +1 -1
  256. package/dist/core/expressions/validation/type-safety.d.ts +2 -2
  257. package/dist/core/expressions/validation/type-safety.d.ts.map +1 -1
  258. package/dist/core/expressions/validation/type-safety.js +1 -0
  259. package/dist/core/expressions/validation/type-safety.js.map +1 -1
  260. package/dist/core/kubernetes/bun-api-client.js.map +1 -1
  261. package/dist/core/kubernetes/bun-http-library.d.ts.map +1 -1
  262. package/dist/core/kubernetes/bun-http-library.js +29 -3
  263. package/dist/core/kubernetes/bun-http-library.js.map +1 -1
  264. package/dist/core/kubernetes/client-provider.d.ts +12 -0
  265. package/dist/core/kubernetes/client-provider.d.ts.map +1 -1
  266. package/dist/core/kubernetes/client-provider.js +35 -0
  267. package/dist/core/kubernetes/client-provider.js.map +1 -1
  268. package/dist/core/metadata/resource-metadata.d.ts +46 -1
  269. package/dist/core/metadata/resource-metadata.d.ts.map +1 -1
  270. package/dist/core/metadata/resource-metadata.js.map +1 -1
  271. package/dist/core/proxy/create-resource.d.ts +15 -0
  272. package/dist/core/proxy/create-resource.d.ts.map +1 -1
  273. package/dist/core/proxy/create-resource.js +56 -2
  274. package/dist/core/proxy/create-resource.js.map +1 -1
  275. package/dist/core/readiness/registry.js +2 -2
  276. package/dist/core/readiness/registry.js.map +1 -1
  277. package/dist/core/references/cel-evaluator.d.ts +1 -4
  278. package/dist/core/references/cel-evaluator.d.ts.map +1 -1
  279. package/dist/core/references/cel-evaluator.js +3 -7
  280. package/dist/core/references/cel-evaluator.js.map +1 -1
  281. package/dist/core/references/cel.d.ts +70 -0
  282. package/dist/core/references/cel.d.ts.map +1 -1
  283. package/dist/core/references/cel.js +188 -8
  284. package/dist/core/references/cel.js.map +1 -1
  285. package/dist/core/references/external-refs.d.ts.map +1 -1
  286. package/dist/core/references/external-refs.js +3 -0
  287. package/dist/core/references/external-refs.js.map +1 -1
  288. package/dist/core/references/resolver.d.ts.map +1 -1
  289. package/dist/core/references/resolver.js +28 -17
  290. package/dist/core/references/resolver.js.map +1 -1
  291. package/dist/core/references/schema-proxy.d.ts +18 -10
  292. package/dist/core/references/schema-proxy.d.ts.map +1 -1
  293. package/dist/core/references/schema-proxy.js +174 -23
  294. package/dist/core/references/schema-proxy.js.map +1 -1
  295. package/dist/core/runtime-patches/crd-schema-fix.d.ts.map +1 -1
  296. package/dist/core/runtime-patches/crd-schema-fix.js +4 -1
  297. package/dist/core/runtime-patches/crd-schema-fix.js.map +1 -1
  298. package/dist/core/serialization/cel-optimizer.d.ts.map +1 -1
  299. package/dist/core/serialization/cel-optimizer.js +2 -0
  300. package/dist/core/serialization/cel-optimizer.js.map +1 -1
  301. package/dist/core/serialization/cel-references.d.ts +75 -1
  302. package/dist/core/serialization/cel-references.d.ts.map +1 -1
  303. package/dist/core/serialization/cel-references.js +723 -145
  304. package/dist/core/serialization/cel-references.js.map +1 -1
  305. package/dist/core/serialization/core.d.ts +13 -8
  306. package/dist/core/serialization/core.d.ts.map +1 -1
  307. package/dist/core/serialization/core.js +973 -12
  308. package/dist/core/serialization/core.js.map +1 -1
  309. package/dist/core/serialization/kro-post-processing.d.ts +46 -0
  310. package/dist/core/serialization/kro-post-processing.d.ts.map +1 -0
  311. package/dist/core/serialization/kro-post-processing.js +150 -0
  312. package/dist/core/serialization/kro-post-processing.js.map +1 -0
  313. package/dist/core/serialization/schema.d.ts +62 -3
  314. package/dist/core/serialization/schema.d.ts.map +1 -1
  315. package/dist/core/serialization/schema.js +819 -6
  316. package/dist/core/serialization/schema.js.map +1 -1
  317. package/dist/core/serialization/status-analysis-pipeline.d.ts +1 -1
  318. package/dist/core/serialization/status-analysis-pipeline.d.ts.map +1 -1
  319. package/dist/core/serialization/status-analysis-pipeline.js.map +1 -1
  320. package/dist/core/serialization/yaml.d.ts +3 -2
  321. package/dist/core/serialization/yaml.d.ts.map +1 -1
  322. package/dist/core/serialization/yaml.js +404 -56
  323. package/dist/core/serialization/yaml.js.map +1 -1
  324. package/dist/core/singleton/singleton.d.ts +16 -0
  325. package/dist/core/singleton/singleton.d.ts.map +1 -0
  326. package/dist/core/singleton/singleton.js +135 -0
  327. package/dist/core/singleton/singleton.js.map +1 -0
  328. package/dist/core/types/common.d.ts +2 -2
  329. package/dist/core/types/common.d.ts.map +1 -1
  330. package/dist/core/types/composable.d.ts +1 -1
  331. package/dist/core/types/composable.d.ts.map +1 -1
  332. package/dist/core/types/deployment.d.ts +126 -6
  333. package/dist/core/types/deployment.d.ts.map +1 -1
  334. package/dist/core/types/deployment.js +1 -1
  335. package/dist/core/types/deployment.js.map +1 -1
  336. package/dist/core/types/kubernetes.d.ts +25 -17
  337. package/dist/core/types/kubernetes.d.ts.map +1 -1
  338. package/dist/core/types/references.d.ts +1 -1
  339. package/dist/core/types/references.d.ts.map +1 -1
  340. package/dist/core/types/references.js.map +1 -1
  341. package/dist/core/types/resource-graph.d.ts +1 -1
  342. package/dist/core/types/resource-graph.d.ts.map +1 -1
  343. package/dist/core/types/schema.d.ts +1 -1
  344. package/dist/core/types/schema.d.ts.map +1 -1
  345. package/dist/core/types/serialization.d.ts +62 -6
  346. package/dist/core/types/serialization.d.ts.map +1 -1
  347. package/dist/core/validation/cel-validator.d.ts +15 -2
  348. package/dist/core/validation/cel-validator.d.ts.map +1 -1
  349. package/dist/core/validation/cel-validator.js +144 -63
  350. package/dist/core/validation/cel-validator.js.map +1 -1
  351. package/dist/factories/apisix/compositions/apisix-bootstrap.d.ts +2 -41
  352. package/dist/factories/apisix/compositions/apisix-bootstrap.d.ts.map +1 -1
  353. package/dist/factories/apisix/compositions/apisix-bootstrap.js +262 -217
  354. package/dist/factories/apisix/compositions/apisix-bootstrap.js.map +1 -1
  355. package/dist/factories/apisix/index.d.ts +2 -2
  356. package/dist/factories/apisix/index.js +2 -2
  357. package/dist/factories/apisix/resources/helm.d.ts +2 -2
  358. package/dist/factories/apisix/resources/helm.d.ts.map +1 -1
  359. package/dist/factories/apisix/resources/helm.js.map +1 -1
  360. package/dist/factories/apisix/types.d.ts +21 -11
  361. package/dist/factories/apisix/types.d.ts.map +1 -1
  362. package/dist/factories/apisix/types.js +106 -4
  363. package/dist/factories/apisix/types.js.map +1 -1
  364. package/dist/factories/apisix/utils/admin-credentials.d.ts +5 -3
  365. package/dist/factories/apisix/utils/admin-credentials.d.ts.map +1 -1
  366. package/dist/factories/apisix/utils/admin-credentials.js +14 -10
  367. package/dist/factories/apisix/utils/admin-credentials.js.map +1 -1
  368. package/dist/factories/apisix/utils/helm-values-mapper.d.ts.map +1 -1
  369. package/dist/factories/apisix/utils/helm-values-mapper.js +4 -2
  370. package/dist/factories/apisix/utils/helm-values-mapper.js.map +1 -1
  371. package/dist/factories/cert-manager/resources/challenges.js.map +1 -1
  372. package/dist/factories/cert-manager/types.d.ts +3 -3
  373. package/dist/factories/cert-manager/types.d.ts.map +1 -1
  374. package/dist/factories/cilium/compositions/cilium-bootstrap.d.ts +4 -4
  375. package/dist/factories/cilium/types.d.ts +3 -3
  376. package/dist/factories/cilium/types.d.ts.map +1 -1
  377. package/dist/factories/cnpg/compositions/cnpg-bootstrap.d.ts +1 -0
  378. package/dist/factories/cnpg/compositions/cnpg-bootstrap.d.ts.map +1 -1
  379. package/dist/factories/cnpg/compositions/cnpg-bootstrap.js +48 -0
  380. package/dist/factories/cnpg/compositions/cnpg-bootstrap.js.map +1 -1
  381. package/dist/factories/cnpg/resources/cluster.js +1 -1
  382. package/dist/factories/cnpg/resources/cluster.js.map +1 -1
  383. package/dist/factories/cnpg/resources/helm.d.ts.map +1 -1
  384. package/dist/factories/cnpg/resources/helm.js +1 -0
  385. package/dist/factories/cnpg/resources/helm.js.map +1 -1
  386. package/dist/factories/cnpg/resources/pooler.js +1 -1
  387. package/dist/factories/cnpg/resources/pooler.js.map +1 -1
  388. package/dist/factories/cnpg/types.d.ts +9 -8
  389. package/dist/factories/cnpg/types.d.ts.map +1 -1
  390. package/dist/factories/cnpg/types.js +11 -0
  391. package/dist/factories/cnpg/types.js.map +1 -1
  392. package/dist/factories/external-dns/compositions/external-dns-bootstrap.d.ts.map +1 -1
  393. package/dist/factories/external-dns/compositions/external-dns-bootstrap.js +153 -41
  394. package/dist/factories/external-dns/compositions/external-dns-bootstrap.js.map +1 -1
  395. package/dist/factories/external-dns/resources/dns-endpoint.js +1 -1
  396. package/dist/factories/external-dns/resources/dns-endpoint.js.map +1 -1
  397. package/dist/factories/external-dns/resources/helm.d.ts +1 -1
  398. package/dist/factories/external-dns/resources/helm.d.ts.map +1 -1
  399. package/dist/factories/external-dns/resources/helm.js +17 -10
  400. package/dist/factories/external-dns/resources/helm.js.map +1 -1
  401. package/dist/factories/external-dns/types.d.ts +5 -2
  402. package/dist/factories/external-dns/types.d.ts.map +1 -1
  403. package/dist/factories/external-dns/types.js.map +1 -1
  404. package/dist/factories/flux/git-repository.d.ts.map +1 -1
  405. package/dist/factories/flux/git-repository.js +1 -1
  406. package/dist/factories/flux/git-repository.js.map +1 -1
  407. package/dist/factories/flux/kustomize/kustomization.d.ts +2 -2
  408. package/dist/factories/flux/kustomize/kustomization.d.ts.map +1 -1
  409. package/dist/factories/flux/kustomize/readiness-evaluators.d.ts +1 -1
  410. package/dist/factories/flux/kustomize/readiness-evaluators.d.ts.map +1 -1
  411. package/dist/factories/flux/kustomize/readiness-evaluators.js +1 -1
  412. package/dist/factories/flux/kustomize/readiness-evaluators.js.map +1 -1
  413. package/dist/factories/helm/helm-release.d.ts +3 -2
  414. package/dist/factories/helm/helm-release.d.ts.map +1 -1
  415. package/dist/factories/helm/helm-release.js +1 -0
  416. package/dist/factories/helm/helm-release.js.map +1 -1
  417. package/dist/factories/helm/helm-repository.d.ts +1 -1
  418. package/dist/factories/helm/helm-repository.d.ts.map +1 -1
  419. package/dist/factories/helm/helm-repository.js +6 -4
  420. package/dist/factories/helm/helm-repository.js.map +1 -1
  421. package/dist/factories/helm/readiness-evaluators.d.ts +6 -6
  422. package/dist/factories/helm/readiness-evaluators.d.ts.map +1 -1
  423. package/dist/factories/helm/readiness-evaluators.js +15 -9
  424. package/dist/factories/helm/readiness-evaluators.js.map +1 -1
  425. package/dist/factories/helm/types.d.ts +5 -1
  426. package/dist/factories/helm/types.d.ts.map +1 -1
  427. package/dist/factories/inngest/compositions/inngest-bootstrap.d.ts +1 -0
  428. package/dist/factories/inngest/compositions/inngest-bootstrap.d.ts.map +1 -1
  429. package/dist/factories/inngest/compositions/inngest-bootstrap.js +4 -3
  430. package/dist/factories/inngest/compositions/inngest-bootstrap.js.map +1 -1
  431. package/dist/factories/inngest/resources/helm.js +1 -1
  432. package/dist/factories/inngest/resources/helm.js.map +1 -1
  433. package/dist/factories/inngest/types.d.ts +5 -4
  434. package/dist/factories/inngest/types.d.ts.map +1 -1
  435. package/dist/factories/inngest/types.js +2 -0
  436. package/dist/factories/inngest/types.js.map +1 -1
  437. package/dist/factories/kro/kro-custom-resource.js +1 -1
  438. package/dist/factories/kro/kro-custom-resource.js.map +1 -1
  439. package/dist/factories/kubernetes/config/config-map.d.ts +2 -2
  440. package/dist/factories/kubernetes/config/config-map.d.ts.map +1 -1
  441. package/dist/factories/kubernetes/config/secret.d.ts +2 -2
  442. package/dist/factories/kubernetes/config/secret.d.ts.map +1 -1
  443. package/dist/factories/kubernetes/config/secret.js +11 -1
  444. package/dist/factories/kubernetes/config/secret.js.map +1 -1
  445. package/dist/factories/kubernetes/networking/service.js +1 -1
  446. package/dist/factories/kubernetes/networking/service.js.map +1 -1
  447. package/dist/factories/kubernetes/yaml/yaml-directory.d.ts.map +1 -1
  448. package/dist/factories/kubernetes/yaml/yaml-directory.js +9 -0
  449. package/dist/factories/kubernetes/yaml/yaml-directory.js.map +1 -1
  450. package/dist/factories/kubernetes/yaml/yaml-file.d.ts.map +1 -1
  451. package/dist/factories/kubernetes/yaml/yaml-file.js +9 -0
  452. package/dist/factories/kubernetes/yaml/yaml-file.js.map +1 -1
  453. package/dist/factories/pebble/resources/helm.js.map +1 -1
  454. package/dist/factories/pebble/types.d.ts +2 -2
  455. package/dist/factories/searxng/compositions/index.d.ts +2 -0
  456. package/dist/factories/searxng/compositions/index.d.ts.map +1 -0
  457. package/dist/factories/searxng/compositions/index.js +2 -0
  458. package/dist/factories/searxng/compositions/index.js.map +1 -0
  459. package/dist/factories/searxng/compositions/searxng-bootstrap.d.ts +66 -0
  460. package/dist/factories/searxng/compositions/searxng-bootstrap.d.ts.map +1 -0
  461. package/dist/factories/searxng/compositions/searxng-bootstrap.js +275 -0
  462. package/dist/factories/searxng/compositions/searxng-bootstrap.js.map +1 -0
  463. package/dist/factories/searxng/index.d.ts +29 -0
  464. package/dist/factories/searxng/index.d.ts.map +1 -0
  465. package/dist/factories/searxng/index.js +27 -0
  466. package/dist/factories/searxng/index.js.map +1 -0
  467. package/dist/factories/searxng/resources/index.d.ts +2 -0
  468. package/dist/factories/searxng/resources/index.d.ts.map +1 -0
  469. package/dist/factories/searxng/resources/index.js +2 -0
  470. package/dist/factories/searxng/resources/index.js.map +1 -0
  471. package/dist/factories/searxng/resources/searxng.d.ts +65 -0
  472. package/dist/factories/searxng/resources/searxng.d.ts.map +1 -0
  473. package/dist/factories/searxng/resources/searxng.js +188 -0
  474. package/dist/factories/searxng/resources/searxng.js.map +1 -0
  475. package/dist/factories/searxng/types.d.ts +127 -0
  476. package/dist/factories/searxng/types.d.ts.map +1 -0
  477. package/dist/factories/searxng/types.js +177 -0
  478. package/dist/factories/searxng/types.js.map +1 -0
  479. package/dist/factories/searxng/utils/settings-builder.d.ts +47 -0
  480. package/dist/factories/searxng/utils/settings-builder.d.ts.map +1 -0
  481. package/dist/factories/searxng/utils/settings-builder.js +53 -0
  482. package/dist/factories/searxng/utils/settings-builder.js.map +1 -0
  483. package/dist/factories/simple/config/config-map.d.ts +2 -2
  484. package/dist/factories/simple/config/config-map.d.ts.map +1 -1
  485. package/dist/factories/simple/config/secret.d.ts +2 -2
  486. package/dist/factories/simple/config/secret.d.ts.map +1 -1
  487. package/dist/factories/simple/config/secret.js +28 -0
  488. package/dist/factories/simple/config/secret.js.map +1 -1
  489. package/dist/factories/simple/helm/index.d.ts +1 -1
  490. package/dist/factories/simple/helm/index.d.ts.map +1 -1
  491. package/dist/factories/simple/helm/index.js.map +1 -1
  492. package/dist/factories/simple/storage/persistent-volume.js.map +1 -1
  493. package/dist/factories/simple/types.d.ts +11 -1
  494. package/dist/factories/simple/types.d.ts.map +1 -1
  495. package/dist/factories/simple/workloads/deployment.d.ts.map +1 -1
  496. package/dist/factories/simple/workloads/deployment.js +3 -0
  497. package/dist/factories/simple/workloads/deployment.js.map +1 -1
  498. package/dist/factories/valkey/compositions/valkey-bootstrap.d.ts +1 -0
  499. package/dist/factories/valkey/compositions/valkey-bootstrap.d.ts.map +1 -1
  500. package/dist/factories/valkey/compositions/valkey-bootstrap.js +116 -0
  501. package/dist/factories/valkey/compositions/valkey-bootstrap.js.map +1 -1
  502. package/dist/factories/valkey/resources/valkey.js +1 -1
  503. package/dist/factories/valkey/resources/valkey.js.map +1 -1
  504. package/dist/factories/valkey/types.d.ts +6 -5
  505. package/dist/factories/valkey/types.d.ts.map +1 -1
  506. package/dist/factories/valkey/types.js +10 -0
  507. package/dist/factories/valkey/types.js.map +1 -1
  508. package/dist/factories/webapp/compositions/web-app-with-processing.d.ts +95 -12
  509. package/dist/factories/webapp/compositions/web-app-with-processing.d.ts.map +1 -1
  510. package/dist/factories/webapp/compositions/web-app-with-processing.js +185 -26
  511. package/dist/factories/webapp/compositions/web-app-with-processing.js.map +1 -1
  512. package/dist/factories/webapp/index.d.ts +3 -4
  513. package/dist/factories/webapp/index.d.ts.map +1 -1
  514. package/dist/factories/webapp/index.js +3 -4
  515. package/dist/factories/webapp/index.js.map +1 -1
  516. package/dist/factories/webapp/types.d.ts +60 -2
  517. package/dist/factories/webapp/types.d.ts.map +1 -1
  518. package/dist/factories/webapp/types.js +80 -3
  519. package/dist/factories/webapp/types.js.map +1 -1
  520. package/dist/index.d.ts +2 -0
  521. package/dist/index.d.ts.map +1 -1
  522. package/dist/index.js +1 -0
  523. package/dist/index.js.map +1 -1
  524. package/dist/shared/brands.d.ts +18 -8
  525. package/dist/shared/brands.d.ts.map +1 -1
  526. package/dist/shared/brands.js +19 -9
  527. package/dist/shared/brands.js.map +1 -1
  528. package/dist/utils/cel-escape.d.ts +12 -0
  529. package/dist/utils/cel-escape.d.ts.map +1 -0
  530. package/dist/utils/cel-escape.js +19 -0
  531. package/dist/utils/cel-escape.js.map +1 -0
  532. package/package.json +7 -2
@@ -9,9 +9,15 @@
9
9
  * conversion. No other module should duplicate this logic.
10
10
  */
11
11
  import { isCelExpression, isKubernetesRef } from '../../utils/type-guards.js';
12
+ import { escapeCelString } from '../../utils/cel-escape.js';
13
+ import { KUBERNETES_REF_MARKER_SOURCE } from '../../shared/brands.js';
14
+ import { remapVariableNames } from '../composition/nested-status-cel.js';
12
15
  import { getComponentLogger } from '../logging/index.js';
13
16
  import { copyResourceMetadata } from '../metadata/index.js';
14
17
  const logger = getComponentLogger('cel-references');
18
+ function escapeRegExpLiteral(value) {
19
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
20
+ }
15
21
  // ---------------------------------------------------------------------------
16
22
  // Primitive helpers
17
23
  // ---------------------------------------------------------------------------
@@ -28,69 +34,618 @@ export function getInnerCelPath(ref) {
28
34
  const resourceId = ref.resourceId === '__schema__' ? 'schema' : ref.resourceId;
29
35
  return `${resourceId}.${ref.fieldPath}`;
30
36
  }
37
+ function resolveResourceIdAlias(resourceId, context) {
38
+ if (resourceId === '__schema__') {
39
+ return 'schema';
40
+ }
41
+ return context?.resourceAliases?.get(resourceId) ?? resourceId;
42
+ }
31
43
  // ---------------------------------------------------------------------------
32
44
  // Single-ref → CEL
33
45
  // ---------------------------------------------------------------------------
46
+ /**
47
+ * If `celPath` is a `schema.spec.<dotted.path>` reference whose path
48
+ * — or any of its ancestor prefixes — is listed in the context's omit
49
+ * set, wrap it with KRO 0.9+ `has(...) ? ... : omit()`. Otherwise
50
+ * return it unchanged.
51
+ *
52
+ * The wrapper is only applied to single-ref expressions — never to
53
+ * mixed templates like `${string(schema.spec.name)}-suffix` because
54
+ * those produce string values, not fields, and `omit()` operates at
55
+ * the field level.
56
+ *
57
+ * **Ancestor-prefix lookup:** `omitFields` may contain either leaf
58
+ * paths (`database.storageClass`) or parent paths (`env`, `cache`).
59
+ * The walk goes leaf-to-root and guards with `has()` on the *deepest*
60
+ * ancestor that's in the set. This covers three cases in one pass:
61
+ *
62
+ * 1. Exact leaf match — `database.storageClass?` → guard
63
+ * `has(schema.spec.database.storageClass)`.
64
+ * 2. Whole-object optional — `env?: {...}` → any child ref
65
+ * `schema.spec.env.FOO` is guarded by `has(schema.spec.env)`
66
+ * because leaf access throws when the parent is absent.
67
+ * 3. Mixed — both `cache?` (parent) and `cache.replicas?` (child)
68
+ * in the set → a ref to `schema.spec.cache.replicas` prefers
69
+ * the *deeper* `cache.replicas` guard so a partially-populated
70
+ * `cache: { shards: 1 }` (parent present, child absent) still
71
+ * omits correctly.
72
+ */
73
+ function maybeWrapWithOmit(celPath, stringWrap, omitFields) {
74
+ const value = stringWrap ? `string(${celPath})` : celPath;
75
+ if (!omitFields || omitFields.size === 0)
76
+ return value;
77
+ // Only handle refs rooted at `schema.spec.`.
78
+ const refMatch = /^schema\.spec\.([A-Za-z_$][\w$.]*)$/.exec(celPath);
79
+ const refPath = refMatch?.[1];
80
+ if (!refPath)
81
+ return value;
82
+ // Walk the full path and collect every optional prefix that applies.
83
+ // We chain from the SHALLOWEST optional ancestor through the leaf.
84
+ //
85
+ // Why shallowest? If both a parent object and a leaf field are optional
86
+ // (e.g. `cnpgOperator?` and `cnpgOperator.monitoring.enabled?`), guarding
87
+ // only the deepest leaf with `has(schema.spec.cnpgOperator.monitoring.enabled)`
88
+ // is not sufficient when the parent object is absent. KRO still evaluates
89
+ // the full path through its optional ancestors. Chaining every level from
90
+ // the first optional ancestor keeps both cases safe:
91
+ // - ancestor optional, leaf required
92
+ // - ancestor optional, leaf optional
93
+ // - multiple optional intermediates
94
+ const segments = refPath.split('.');
95
+ let shallowestOptionalIndex = null;
96
+ for (let i = 1; i <= segments.length; i++) {
97
+ const prefix = segments.slice(0, i).join('.');
98
+ if (omitFields.has(prefix)) {
99
+ shallowestOptionalIndex ??= i;
100
+ }
101
+ }
102
+ if (shallowestOptionalIndex !== null) {
103
+ const guards = [];
104
+ for (let i = shallowestOptionalIndex; i <= segments.length; i++) {
105
+ const guardPath = `schema.spec.${segments.slice(0, i).join('.')}`;
106
+ guards.push(`has(${guardPath})`);
107
+ }
108
+ return `${guards.join(' && ')} ? ${value} : omit()`;
109
+ }
110
+ return value;
111
+ }
34
112
  /**
35
113
  * Wrap a {@link KubernetesRef} in `${…}` for Kro YAML output.
114
+ *
115
+ * When the ref points to a nested composition's virtual status ID
116
+ * (e.g., `innerService1.status.serviceUrl`), resolve it via the
117
+ * transitive resolver — substituting the inner composition's analyzed
118
+ * expression and producing valid KRO CEL (no raw markers, no virtual
119
+ * IDs).
120
+ *
121
+ * The nested-composition lookup delegates to {@link lookupNestedExpression}
122
+ * — the single source of truth for the match strategy. See that function
123
+ * for the full priority order.
124
+ */
125
+ function generateCelExpression(ref, context) {
126
+ const isNestedComp = ref.__nestedComposition === true;
127
+ if (isNestedComp && context?.nestedStatusCel) {
128
+ const fieldName = ref.fieldPath.replace(/^status\./, '');
129
+ const innerExpr = context.resourceIds?.has(ref.resourceId)
130
+ ? lookupNestedExpression(ref.resourceId, fieldName, context.nestedStatusCel, false)
131
+ : lookupNestedExpression(ref.resourceId, fieldName, context.nestedStatusCel);
132
+ if (innerExpr !== undefined) {
133
+ return finalizeCelForKro(innerExpr, context.nestedStatusCel, context);
134
+ }
135
+ }
136
+ const expression = `${resolveResourceIdAlias(ref.resourceId, context)}.${ref.fieldPath}`;
137
+ const body = maybeWrapWithOmit(expression, false, context?.omitFields);
138
+ return `\${${body}}`;
139
+ }
140
+ // ---------------------------------------------------------------------------
141
+ // __KUBERNETES_REF__ marker primitives
142
+ // ---------------------------------------------------------------------------
143
+ /**
144
+ * Single source of truth for __KUBERNETES_REF__ marker detection.
145
+ *
146
+ * Marker shape:
147
+ * - Resource ref: `__KUBERNETES_REF_<resourceId>_<fieldPath>__`
148
+ * - Schema ref: `__KUBERNETES_REF___schema___<fieldPath>__`
149
+ *
150
+ * `resourceId` is `__schema__` for schema refs, or a marker-safe resource id
151
+ * with optional single `_` segments. `fieldPath` is a dot-separated identifier
152
+ * sequence like "spec.name", "status.image_tag", or
153
+ * "status.workers.$item.name".
154
+ *
155
+ * Two flavors are needed:
156
+ * - `MARKER_PATTERN_SOURCE` is the non-global base pattern. Create a fresh
157
+ * `new RegExp(MARKER_PATTERN_SOURCE, 'g')` wherever global matching is
158
+ * needed — avoids the stateful-lastIndex footgun.
159
+ * - `MARKER_PATTERN_FULL` matches when the entire string is exactly one
160
+ * marker (for the single-ref fast path in
161
+ * {@link convertKubernetesRefMarkersTocel}).
162
+ */
163
+ /**
164
+ * Non-global base pattern for __KUBERNETES_REF__ markers. Create a fresh
165
+ * `RegExp(MARKER_PATTERN_SOURCE, 'g')` wherever global matching is needed —
166
+ * avoids the stateful-lastIndex footgun of a module-level `/g` regex.
167
+ */
168
+ const MARKER_PATTERN_SOURCE = KUBERNETES_REF_MARKER_SOURCE;
169
+ const MARKER_PATTERN_FULL = new RegExp(`^${MARKER_PATTERN_SOURCE}$`);
170
+ /**
171
+ * Convert a marker substring captured from {@link MARKER_PATTERN_G} (or
172
+ * {@link MARKER_PATTERN_FULL}) to its bare CEL path. Handles the
173
+ * `__schema__` sentinel by emitting `schema.<fieldPath>`; otherwise
174
+ * emits `<resourceId>.<fieldPath>`.
175
+ */
176
+ function markerToCelPath(resourceId, fieldPath, context) {
177
+ return `${resolveResourceIdAlias(resourceId, context)}.${fieldPath}`;
178
+ }
179
+ /**
180
+ * Normalize any `__KUBERNETES_REF__` markers in `str` to their bare CEL paths
181
+ * in-place — without wrapping them in `${…}`. Used by the static/dynamic
182
+ * classifier and the transitive resolver when we need to scan for non-
183
+ * schema references inside a marker-laden string.
184
+ *
185
+ * Unlike {@link convertKubernetesRefMarkersTocel}, this does NOT produce a
186
+ * KRO mixed-template string. It produces a raw CEL-path blend where
187
+ * markers have been replaced by their dotted CEL paths.
188
+ *
189
+ * Example:
190
+ * "http://__KUBERNETES_REF___schema___spec.name__:__KUBERNETES_REF___schema___spec.port__"
191
+ * →
192
+ * "http://schema.spec.name:schema.spec.port"
193
+ *
194
+ * The result isn't valid CEL on its own — it's literal text interleaved
195
+ * with CEL paths, suitable for pattern matching only.
196
+ */
197
+ function normalizeMarkerString(str, context) {
198
+ return str.replace(new RegExp(MARKER_PATTERN_SOURCE, 'g'), (_match, id, path) => markerToCelPath(id, path, context));
199
+ }
200
+ /** Convert marker strings to bare CEL paths using the full serialization context. */
201
+ export function normalizeRefMarkersToCelPaths(str, context) {
202
+ const withNestedMarkers = resolveNestedRefMarkers(str, context?.nestedStatusCel, context?.resourceIds, context);
203
+ const withNestedStatus = resolveNestedCompositionRefs(withNestedMarkers, context?.nestedStatusCel, context?.resourceIds);
204
+ return normalizeMarkerString(withNestedStatus, context);
205
+ }
206
+ // ---------------------------------------------------------------------------
207
+ // CEL lambda variable handling
208
+ // ---------------------------------------------------------------------------
209
+ /**
210
+ * Pattern to extract lambda variable names from CEL macro calls.
211
+ *
212
+ * CEL macros (`.all`, `.exists`, `.exists_one`, `.map`, `.filter`)
213
+ * introduce a local variable in their first argument that should NOT
214
+ * be treated as a resource identifier when scanning for `<id>.status.X`
215
+ * patterns. The classification regex is shared with `cel-validator.ts`
216
+ * — keep them in sync if you change one.
217
+ *
218
+ * Note: `each` is also a special identifier — it's the implicit element
219
+ * variable used by KRO `forEach`/`readyWhen` callback bodies.
220
+ */
221
+ const CEL_LAMBDA_MACRO_PATTERN = /\.(?:all|exists|exists_one|map|filter)\(\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*,/g;
222
+ /**
223
+ * Build the set of identifiers that should be treated as lambda-bound
224
+ * variables when scanning `expr` for resource references. Always includes
225
+ * `each` as a sentinel for `forEach.readyWhen` bodies.
226
+ */
227
+ function collectLambdaVars(expr) {
228
+ const vars = new Set(['each']);
229
+ for (const m of expr.matchAll(CEL_LAMBDA_MACRO_PATTERN)) {
230
+ if (m[1])
231
+ vars.add(m[1]);
232
+ }
233
+ return vars;
234
+ }
235
+ // ---------------------------------------------------------------------------
236
+ // Static / dynamic classification
237
+ // ---------------------------------------------------------------------------
238
+ /**
239
+ * Check whether an already-resolved CEL-path string contains any
240
+ * non-schema resource references. "Non-schema resource reference" means
241
+ * any `<identifier>.(status|metadata|spec).<path>` where `<identifier>`
242
+ * is neither `schema` nor a CEL macro lambda variable.
243
+ *
244
+ * Lambda variables (the `c` in `.exists(c, c.status == "True")`) are
245
+ * detected via {@link collectLambdaVars} and excluded — otherwise a
246
+ * legitimate macro body would falsely classify the parent expression
247
+ * as dynamic for the wrong reason.
248
+ */
249
+ function containsNoNonSchemaRefs(expr) {
250
+ const lambdaVars = collectLambdaVars(expr);
251
+ const pattern = /\b([a-zA-Z_$][\w$]*)\.(status|metadata|spec)\./g;
252
+ for (const m of expr.matchAll(pattern)) {
253
+ const id = m[1];
254
+ if (id === 'schema')
255
+ continue;
256
+ if (id && lambdaVars.has(id))
257
+ continue;
258
+ return false;
259
+ }
260
+ return true;
261
+ }
262
+ /**
263
+ * Classify an expression as static (iff, after resolving all nested-
264
+ * composition references and schema markers, it contains no references
265
+ * to real-resource `status`/`metadata`/`spec` fields) or dynamic.
266
+ *
267
+ * This is the authoritative depth-agnostic static/dynamic classifier.
268
+ * It supersedes the local syntactic check in `validation/cel-validator.ts`
269
+ * for nested-composition references.
270
+ *
271
+ * Input shapes accepted:
272
+ * - CEL expression strings (e.g., `"app.status.readyReplicas >= 1"`)
273
+ * - Marker strings (e.g., `"http://__KUBERNETES_REF___schema___spec.name__"`)
274
+ * - Mixed: CEL paths + marker tokens + literals
275
+ *
276
+ * Returns `true` iff the fully-resolved expression is purely
277
+ * schema-and-literal.
278
+ */
279
+ export function isStaticExpression(expr, nestedStatusCel) {
280
+ const afterNesting = resolveNestedCompositionRefs(expr, nestedStatusCel);
281
+ const afterMarkers = normalizeMarkerString(afterNesting);
282
+ return containsNoNonSchemaRefs(afterMarkers);
283
+ }
284
+ // ---------------------------------------------------------------------------
285
+ // Nested composition reference resolution
286
+ // ---------------------------------------------------------------------------
287
+ /**
288
+ * Maximum number of substitution passes when resolving nested composition
289
+ * references in {@link resolveNestedCompositionRefs}. The fixed-point loop
290
+ * normally converges in one or two passes (one per level of nesting), so
291
+ * 16 is a comfortable cap that handles pathologically deep compositions
292
+ * without giving runaway substitution loops a chance to wedge serialization.
293
+ *
294
+ * Hitting this limit indicates a real bug in the resolution table — most
295
+ * likely a cycle introduced by a faulty alias entry — not a legitimate
296
+ * composition shape.
297
+ */
298
+ const NESTED_REF_RESOLUTION_DEPTH_LIMIT = 16;
299
+ /**
300
+ * Look up a nested composition's analyzed expression by `(resourceId, fieldName)`.
301
+ *
302
+ * **Single source of truth** for the nested-status match strategy. Used by
303
+ * every code path that needs to find an inner expression from a
304
+ * `nestedStatusCel` table — both the structured-ref paths
305
+ * (`generateCelExpression`, `serializeStatusMappingsToCel`) and the
306
+ * string-resolver path (`substituteNestedRefsOnce`,
307
+ * `resolveNestedRefMarkers`).
308
+ *
309
+ * Returns `undefined` when no match is found, leaving the caller to
310
+ * decide how to handle missing entries (typically: leave the reference
311
+ * in place and let downstream validation flag it).
312
+ *
313
+ * Match priority:
314
+ * 1. **Exact baseId match.** The reference uses the virtual nested
315
+ * composition baseId verbatim (e.g., from a template literal on a
316
+ * nested status proxy where `toString()` embeds the baseId).
317
+ * 2. **Base-name match (instance digits stripped).** Both the requested
318
+ * id and the candidate baseIds have their trailing instance digits
319
+ * stripped, then compared for equality. Handles the case where the
320
+ * reference uses `webAppWithProcessing2` but the table has
321
+ * `webAppWithProcessing1`.
322
+ * 3. **Unambiguous camelCase / case-insensitive prefix.** The
323
+ * reference uses a name that structurally relates to one (and only
324
+ * one) baseId stem (e.g., `inngest` matching `inngestBootstrap`).
325
+ * 4. **Field-name uniqueness.** When exactly one nested composition in
326
+ * the table provides the requested field, use it. Handles the case
327
+ * of arbitrary local variable names (e.g.,
328
+ * `const stack = webAppWithProcessing(...); stack.status.databaseUrl`).
329
+ *
330
+ * Ambiguous matches (multiple candidates from the prefix or field-name
331
+ * strategies) emit a warning log and return `undefined` so the caller
332
+ * can fall through to its own error handling.
36
333
  */
37
- function generateCelExpression(ref) {
38
- const expression = getInnerCelPath(ref);
39
- return `\${${expression}}`;
334
+ export function lookupNestedExpression(resourceId, fieldName, nestedStatusCel, allowFieldFallback = true) {
335
+ // Strategy 1: exact match.
336
+ const exactKey = `__nestedStatus:${resourceId}:${fieldName}`;
337
+ if (Object.hasOwn(nestedStatusCel, exactKey)) {
338
+ return nestedStatusCel[exactKey];
339
+ }
340
+ // Gather all entries for the requested field name once — strategies
341
+ // 2-4 all need this list.
342
+ const fieldSuffix = `:${fieldName}`;
343
+ const fieldMatches = [];
344
+ for (const key of Object.keys(nestedStatusCel)) {
345
+ if (!key.endsWith(fieldSuffix))
346
+ continue;
347
+ const parts = key.split(':');
348
+ if (parts.length === 3 && parts[1]) {
349
+ fieldMatches.push({ key, baseId: parts[1] });
350
+ }
351
+ }
352
+ if (fieldMatches.length === 0)
353
+ return undefined;
354
+ // Strategy 2: base-name match (instance digits stripped).
355
+ const refBase = resourceId.replace(/\d+$/, '');
356
+ const baseNameMatches = fieldMatches.filter((m) => m.baseId.replace(/\d+$/, '') === refBase);
357
+ if (baseNameMatches.length === 1) {
358
+ const match = baseNameMatches[0];
359
+ return match ? nestedStatusCel[match.key] : undefined;
360
+ }
361
+ // Strategy 3: unambiguous camelCase / case-insensitive prefix.
362
+ const prefixMatches = fieldMatches.filter((m) => {
363
+ const baseStem = m.baseId.replace(/\d+$/, '');
364
+ const resourceLooksLikeMergedChild = (resourceId.startsWith(baseStem) &&
365
+ resourceId.length > baseStem.length &&
366
+ (() => {
367
+ const boundaryChar = resourceId[baseStem.length];
368
+ return boundaryChar !== undefined && /[A-Z_-]/.test(boundaryChar);
369
+ })()) ||
370
+ new RegExp(`^${baseStem}\\d+[A-Z_-]`).test(resourceId);
371
+ if (resourceLooksLikeMergedChild) {
372
+ return false;
373
+ }
374
+ return (isCamelCasePrefix(resourceId, baseStem) ||
375
+ isCamelCasePrefix(baseStem, resourceId) ||
376
+ baseStem.toLowerCase() === resourceId.toLowerCase());
377
+ });
378
+ if (prefixMatches.length === 1) {
379
+ const match = prefixMatches[0];
380
+ return match ? nestedStatusCel[match.key] : undefined;
381
+ }
382
+ if (prefixMatches.length > 1) {
383
+ logger.warn('Ambiguous nested composition prefix match', {
384
+ resourceId,
385
+ fieldName,
386
+ candidates: prefixMatches.map((m) => m.baseId),
387
+ });
388
+ return undefined;
389
+ }
390
+ // Strategy 4: field-name uniqueness.
391
+ if (!allowFieldFallback)
392
+ return undefined;
393
+ if (fieldMatches.length === 1) {
394
+ const match = fieldMatches[0];
395
+ return match ? nestedStatusCel[match.key] : undefined;
396
+ }
397
+ // Field-only fallback is intentionally best-effort and fully silent on
398
+ // ambiguity. Prefix/base-name ambiguity still logs above, but this final
399
+ // branch should never emit low-signal warnings for common status fields
400
+ // like `ready` that appear across many unrelated nested compositions.
401
+ return undefined;
402
+ }
403
+ /**
404
+ * Transitively substitute nested-composition references inline from a
405
+ * lookup table.
406
+ *
407
+ * Searches `expr` for `<id>.status.<fieldPath>` patterns and, when `<id>`
408
+ * resolves to a nested composition entry via {@link lookupNestedExpression},
409
+ * replaces the match with the inner composition's analyzed expression
410
+ * wrapped in parentheses (to preserve operator precedence in compound
411
+ * expressions).
412
+ *
413
+ * **Does NOT touch `__KUBERNETES_REF__` markers.** Callers that need to
414
+ * emit final KRO CEL should run {@link convertKubernetesRefMarkersTocel}
415
+ * on the result. Callers that need to classify the result as
416
+ * static/dynamic should run {@link normalizeMarkerString} then
417
+ * {@link containsNoNonSchemaRefs} (or just call
418
+ * {@link isStaticExpression} which composes both steps).
419
+ *
420
+ * Iterates to a fixed point up to {@link NESTED_REF_RESOLUTION_DEPTH_LIMIT}
421
+ * — substituted expressions may themselves contain nested references that
422
+ * become resolvable once the outer reference is inlined (the three-level
423
+ * nesting case: L1 → L2 → L3).
424
+ *
425
+ * **Lambda variables are skipped.** When the resolved `<id>` is a CEL
426
+ * macro lambda variable like the `c` in `.exists(c, c.status == "Ready")`,
427
+ * the substitution does NOT fire — the variable refers to the macro's
428
+ * iteration element, not a nested composition.
429
+ */
430
+ function resolveNestedCompositionRefs(expr, nestedStatusCel, resourceIds) {
431
+ if (!nestedStatusCel || Object.keys(nestedStatusCel).length === 0) {
432
+ return expr;
433
+ }
434
+ let current = expr;
435
+ for (let i = 0; i < NESTED_REF_RESOLUTION_DEPTH_LIMIT; i++) {
436
+ const next = substituteNestedRefsOnce(current, nestedStatusCel, resourceIds);
437
+ if (next === current)
438
+ return current;
439
+ current = next;
440
+ }
441
+ logger.warn('Nested composition resolution depth limit exceeded', {
442
+ depthLimit: NESTED_REF_RESOLUTION_DEPTH_LIMIT,
443
+ expressionPreview: expr.slice(0, 200),
444
+ });
445
+ return current;
446
+ }
447
+ export function inlineNestedStatusRefs(expr, nestedStatusCel, resourceIds) {
448
+ return resolveNestedCompositionRefs(expr, nestedStatusCel, resourceIds);
449
+ }
450
+ /**
451
+ * One pass of nested-reference substitution. See
452
+ * {@link resolveNestedCompositionRefs} for the full contract.
453
+ */
454
+ function substituteNestedRefsOnce(expr, nestedStatusCel, resourceIds) {
455
+ const lambdaVars = collectLambdaVars(expr);
456
+ // Match `<id>.status.<fieldPath>`. The fieldPath capture is greedy on
457
+ // dots so paths like `components.app` are captured whole — that's the
458
+ // form `nestedStatusCel` keys use after recursive extraction.
459
+ const pattern = /\b([a-zA-Z_$][\w$]*)\.status\.([a-zA-Z_$][\w$.]*)/g;
460
+ return expr.replace(pattern, (match, id, field) => {
461
+ if (id === 'schema')
462
+ return match;
463
+ if (lambdaVars.has(id))
464
+ return match;
465
+ if (resourceIds?.has(id)) {
466
+ const strictInnerExpr = lookupNestedExpression(id, field, nestedStatusCel, false);
467
+ if (strictInnerExpr !== undefined)
468
+ return `(${strictInnerExpr})`;
469
+ return match;
470
+ }
471
+ const innerExpr = lookupNestedExpression(id, field, nestedStatusCel);
472
+ if (innerExpr !== undefined)
473
+ return `(${innerExpr})`;
474
+ return match;
475
+ });
476
+ }
477
+ /**
478
+ * Resolve `__KUBERNETES_REF__` markers whose resourceId is a virtual
479
+ * nested composition baseId (rather than a real resource). Each such
480
+ * marker is replaced inline with the inner composition's analyzed
481
+ * expression from `nestedStatusCel`.
482
+ *
483
+ * The substitution rewrites the marker into a KRO-formatted segment via
484
+ * {@link innerExprToYamlSegment}. Markers whose resourceId IS a real
485
+ * resource ID (or `__schema__`) are left in place — they're handled by
486
+ * downstream {@link convertKubernetesRefMarkersTocel}.
487
+ *
488
+ * Lookup uses the shared {@link lookupNestedExpression} so the match
489
+ * strategy stays consistent with the rest of the resolver.
490
+ */
491
+ function resolveNestedRefMarkers(str, nestedStatusCel, resourceIds, context) {
492
+ if (!nestedStatusCel || Object.keys(nestedStatusCel).length === 0) {
493
+ return str;
494
+ }
495
+ return str.replace(new RegExp(MARKER_PATTERN_SOURCE, 'g'), (match, id, path) => {
496
+ if (id === '__schema__')
497
+ return match;
498
+ // Strip leading "status." since nestedStatusCel keys use the bare field path.
499
+ const fieldPath = path.replace(/^status\./, '');
500
+ if (resourceIds?.has(id)) {
501
+ const strictInnerExpr = lookupNestedExpression(id, fieldPath, nestedStatusCel, false);
502
+ if (strictInnerExpr !== undefined)
503
+ return innerExprToYamlSegment(strictInnerExpr, nestedStatusCel, context);
504
+ return match;
505
+ }
506
+ const innerExpr = lookupNestedExpression(id, fieldPath, nestedStatusCel);
507
+ if (innerExpr !== undefined)
508
+ return innerExprToYamlSegment(innerExpr, nestedStatusCel, context);
509
+ return match;
510
+ });
511
+ }
512
+ /**
513
+ * Matches a bare CEL literal — an integer, float, boolean, or null.
514
+ * Used by {@link innerExprToYamlSegment} to detect when a resolved
515
+ * nested-composition value should be wrapped in `string(...)` so
516
+ * template-literal-originated references produce string values instead
517
+ * of the literal's natural CEL type.
518
+ */
519
+ const BARE_LITERAL_PATTERN = /^\s*(-?\d+(?:\.\d+)?|true|false|null)\s*$/;
520
+ /**
521
+ * Convert an inner composition's analyzed expression into a YAML-embeddable
522
+ * segment. Recursively resolves nested references within the inner expression
523
+ * and produces the appropriate KRO format.
524
+ *
525
+ * **Called from the marker-substitution path** (`resolveNestedRefMarkers`),
526
+ * which runs when the user wrote a template literal that coerced a nested
527
+ * composition proxy into a marker string (e.g., `` `${stack.status.cachePort}` ``).
528
+ * The template literal is the user's explicit signal that they want a
529
+ * STRING value — so when the resolved expression is a bare literal
530
+ * (number, boolean, null), we wrap it with `string(...)` so KRO's CEL
531
+ * evaluation produces a string matching the user's intent.
532
+ *
533
+ * The direct-ref path ({@link generateCelExpression} → {@link finalizeCelForKro})
534
+ * deliberately does NOT apply this wrapping — a direct assignment like
535
+ * `replicas: stack.status.someCount` should preserve the natural numeric
536
+ * type because the destination field expects a number.
537
+ */
538
+ function innerExprToYamlSegment(innerExpr, nestedStatusCel, context) {
539
+ // Recursively resolve any further nested refs the inner expression itself
540
+ // contains (multi-level nesting).
541
+ const resolved = resolveNestedCompositionRefs(innerExpr, nestedStatusCel, context?.resourceIds);
542
+ if (resolved.includes('__KUBERNETES_REF_')) {
543
+ // Marker-laden — convert to mixed-template form.
544
+ return convertKubernetesRefMarkersTocel(resolved, context);
545
+ }
546
+ if (resolved.includes('${')) {
547
+ // Already a KRO template (from Cel.template) — pass through.
548
+ return resolved;
549
+ }
550
+ // Bare literal reached via a template-literal coercion — wrap with
551
+ // `string(...)` so KRO evaluates it to a string value. This matches
552
+ // direct-mode JS semantics (`${6379}` stringifies to `"6379"`) and
553
+ // prevents type-mismatch errors when the literal is used in a
554
+ // string-typed context like env var values.
555
+ if (BARE_LITERAL_PATTERN.test(resolved)) {
556
+ return `\${string(${resolved.trim()})}`;
557
+ }
558
+ // Plain CEL — wrap in ${...}.
559
+ return `\${${resolved}}`;
560
+ }
561
+ /**
562
+ * Produce the final KRO CEL form for a nested-composition value, with all
563
+ * nested references substituted in and all schema markers converted to
564
+ * mixed-template form.
565
+ *
566
+ * The return value is always a valid KRO expression string ready to be
567
+ * embedded directly into a YAML value position (resource template field,
568
+ * status CEL expression). Three cases are handled:
569
+ *
570
+ * - Marker-laden input (from a template literal) → converted to KRO
571
+ * mixed-template form via {@link convertKubernetesRefMarkersTocel}.
572
+ * - Input that already contains `${…}` segments (from a `Cel.template()`
573
+ * call, for example) → returned as-is; assumed to be in KRO form.
574
+ * - Plain-CEL input (raw CEL with no markers or `${…}`) → wrapped in
575
+ * `${…}` so KRO recognizes it as an expression to evaluate.
576
+ */
577
+ export function finalizeCelForKro(expr, nestedStatusCel, context) {
578
+ const resolved = resolveNestedCompositionRefs(expr, nestedStatusCel, context?.resourceIds);
579
+ if (resolved.includes('__KUBERNETES_REF_')) {
580
+ return convertKubernetesRefMarkersTocel(resolved, context);
581
+ }
582
+ if (resolved.includes('${')) {
583
+ // Already contains KRO template placeholders — pass through.
584
+ return resolved;
585
+ }
586
+ return `\${${resolved}}`;
40
587
  }
41
588
  // ---------------------------------------------------------------------------
42
- // __KUBERNETES_REF__ marker conversion
589
+ // __KUBERNETES_REF__ marker → KRO CEL conversion
43
590
  // ---------------------------------------------------------------------------
44
591
  /**
45
592
  * Convert `__KUBERNETES_REF__` markers embedded in a string to CEL
46
- * expressions.
593
+ * expressions in KRO mixed-template form.
47
594
  *
48
595
  * These markers are created when schema proxy values are used in
49
596
  * template literals, e.g.:
50
597
  *
51
598
  * - `__KUBERNETES_REF___schema___spec.name__-policy`
52
- * → `${schema.spec.name + "-policy"}`
599
+ * → `${string(schema.spec.name)}-policy`
53
600
  *
54
- * Pattern: `__KUBERNETES_REF_{resourceId}_{fieldPath}__`
55
- * For schema: `__KUBERNETES_REF___schema___{fieldPath}__`
601
+ * Single-reference inputs use a fast path that avoids the `string(…)`
602
+ * wrapper and supports `has()/omit()` for optional schema fields. Mixed
603
+ * inputs always wrap each reference in `${string(…)}` so KRO accepts
604
+ * non-string types in string contexts (ConfigMap data values, env var
605
+ * values).
56
606
  */
57
- function convertKubernetesRefMarkersTocel(str) {
58
- // Pattern handles both regular resource IDs and __schema__ (which has underscores)
59
- // The field path is matched with [a-zA-Z0-9.$]+ which captures dot-separated identifiers
60
- // like "spec.name", "status.readyReplicas", or "spec.workers.$item.name"
61
- const refPattern = /__KUBERNETES_REF_(__schema__|[^_]+)_([a-zA-Z0-9.$]+)__/g;
62
- // Fast-path: entire string is a single reference
63
- const singleRefMatch = str.match(/^__KUBERNETES_REF_(__schema__|[^_]+)_([a-zA-Z0-9.$]+)__$/);
607
+ function convertKubernetesRefMarkersTocel(str, context) {
608
+ // Fast-path: entire string is a single reference.
609
+ const singleRefMatch = MARKER_PATTERN_FULL.exec(str);
64
610
  if (singleRefMatch) {
65
611
  const [, resourceId, fieldPath] = singleRefMatch;
66
- const celPath = resourceId === '__schema__' ? `schema.${fieldPath}` : `${resourceId}.${fieldPath}`;
67
- return `\${${celPath}}`;
612
+ if (!resourceId || !fieldPath) {
613
+ return str;
614
+ }
615
+ const celPath = markerToCelPath(resourceId, fieldPath, context);
616
+ // Single-ref: safe to wrap with has()/omit() for optional schema fields.
617
+ const body = maybeWrapWithOmit(celPath, false, context?.omitFields);
618
+ return `\${${body}}`;
68
619
  }
69
- // Mixed content → CEL concatenation
70
- const parts = [];
620
+ // Mixed content → KRO mixed-template format: literal${string(ref)}literal
621
+ // Each ${…} is independently evaluated. We wrap in string() so KRO's type
622
+ // validator accepts non-string types (booleans, numbers) in string contexts
623
+ // like ConfigMap data values.
624
+ //
625
+ // Mixed templates produce STRING values (not fields), so has()/omit() wrapping
626
+ // is intentionally NOT applied here — omit() operates at the YAML field level,
627
+ // and mixing it into a concatenation would be a type error.
628
+ let result = '';
71
629
  let lastIndex = 0;
72
- let match;
73
- refPattern.lastIndex = 0;
74
- match = refPattern.exec(str);
75
- while (match !== null) {
76
- if (match.index > lastIndex) {
77
- const textBefore = str.slice(lastIndex, match.index);
78
- parts.push(`"${textBefore}"`);
630
+ // Fresh global instance per call — no shared lastIndex state.
631
+ for (const match of str.matchAll(new RegExp(MARKER_PATTERN_SOURCE, 'g'))) {
632
+ const idx = match.index ?? 0;
633
+ if (idx > lastIndex) {
634
+ result += str.slice(lastIndex, idx);
79
635
  }
80
636
  const [, resourceId, fieldPath] = match;
81
- const celPath = resourceId === '__schema__' ? `schema.${fieldPath}` : `${resourceId}.${fieldPath}`;
82
- parts.push(celPath);
83
- lastIndex = match.index + match[0].length;
84
- match = refPattern.exec(str);
637
+ if (!resourceId || !fieldPath) {
638
+ result += match[0];
639
+ lastIndex = idx + match[0].length;
640
+ continue;
641
+ }
642
+ result += `\${string(${markerToCelPath(resourceId, fieldPath, context)})}`;
643
+ lastIndex = idx + match[0].length;
85
644
  }
86
645
  if (lastIndex < str.length) {
87
- const textAfter = str.slice(lastIndex);
88
- parts.push(`"${textAfter}"`);
646
+ result += str.slice(lastIndex);
89
647
  }
90
- if (parts.length === 1) {
91
- return `\${${parts[0]}}`;
92
- }
93
- return `\${${parts.join(' + ')}}`;
648
+ return result;
94
649
  }
95
650
  // ---------------------------------------------------------------------------
96
651
  // Recursive resource reference processing
@@ -103,20 +658,41 @@ function convertKubernetesRefMarkersTocel(str) {
103
658
  */
104
659
  export function processResourceReferences(obj, context) {
105
660
  if (isKubernetesRef(obj)) {
106
- return generateCelExpression(obj);
661
+ return generateCelExpression(obj, context);
107
662
  }
108
663
  if (isCelExpression(obj)) {
109
664
  if (obj.__isTemplate) {
110
- // Template expressions from Cel.template() are already in Kro's mixed-template
111
- // format (e.g. "http://${schema.spec.name}.${service.metadata.namespace}").
112
- // Pass them through as-is do NOT convert to CEL concat or re-wrap.
113
- return obj.expression;
665
+ return obj.expression.replace(/\$\{([^}]+)\}/g, (_match, innerExpr) => finalizeCelForKro(innerExpr, context?.nestedStatusCel, context));
666
+ }
667
+ // Bare CelExpressionmay be a single schema.spec.X reference (possibly
668
+ // wrapped in `string(...)`). Delegate any single schema ref to
669
+ // maybeWrapWithOmit so nested optional ancestors get the same guard chain
670
+ // as KubernetesRef objects.
671
+ const expr = resolveNestedCompositionRefs(obj.expression, context?.nestedStatusCel, context?.resourceIds);
672
+ const bareRef = /^schema\.spec\.[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*$/.exec(expr)?.[0];
673
+ if (bareRef) {
674
+ return `\${${maybeWrapWithOmit(bareRef, false, context?.omitFields)}}`;
114
675
  }
115
- return `\${${obj.expression}}`;
676
+ const stringRef = /^string\((schema\.spec\.[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\)$/.exec(expr)?.[1];
677
+ if (stringRef) {
678
+ return `\${${maybeWrapWithOmit(stringRef, true, context?.omitFields)}}`;
679
+ }
680
+ return finalizeCelForKro(expr, context?.nestedStatusCel, context);
116
681
  }
117
- // Strings containing __KUBERNETES_REF__ markers from template literals
682
+ // Strings containing __KUBERNETES_REF__ markers from template literals.
683
+ // First resolve any nested-composition references — markers produced by
684
+ // `createKubernetesRefProxy` use a virtual baseId as the resourceId,
685
+ // and that baseId only resolves via `nestedStatusCel`. After that, any
686
+ // remaining markers (schema refs and direct resource refs) are converted
687
+ // to KRO mixed-template form.
118
688
  if (typeof obj === 'string' && obj.includes('__KUBERNETES_REF_')) {
119
- return convertKubernetesRefMarkersTocel(obj);
689
+ const resolved = resolveNestedRefMarkers(obj, context?.nestedStatusCel, context?.resourceIds, context);
690
+ if (resolved.includes('__KUBERNETES_REF_')) {
691
+ return convertKubernetesRefMarkersTocel(resolved, context);
692
+ }
693
+ // All markers were resolved through nestedStatusCel — the result is
694
+ // pure literal text or KRO-formatted CEL. Pass it through.
695
+ return resolved;
120
696
  }
121
697
  if (Array.isArray(obj)) {
122
698
  return obj.map((item) => processResourceReferences(item, context));
@@ -144,121 +720,113 @@ export function processResourceReferences(obj, context) {
144
720
  *
145
721
  * Only processes dynamic fields that require Kro resolution.
146
722
  */
147
- export function serializeStatusMappingsToCel(statusMappings, nestedStatusCel, resourceIds) {
723
+ export function serializeStatusMappingsToCel(statusMappings, nestedStatusCel, resourceIds, resourceAliases) {
148
724
  logger.debug('Serializing status mappings to CEL', {
149
725
  fieldCount: Object.keys(statusMappings).length,
150
726
  hasNestedStatusCel: !!nestedStatusCel,
151
727
  nestedStatusCelKeys: nestedStatusCel ? Object.keys(nestedStatusCel) : [],
152
728
  });
153
729
  const celExpressions = {};
730
+ const localResourceIds = resourceIds ? Array.from(resourceIds) : [];
731
+ const preserveVariables = new Set();
732
+ if (nestedStatusCel) {
733
+ for (const key of Object.keys(nestedStatusCel)) {
734
+ const match = key.match(/^__nestedStatus:([^:]+):/);
735
+ const id = match?.[1];
736
+ if (id && !resourceIds?.has(id)) {
737
+ preserveVariables.add(id);
738
+ }
739
+ }
740
+ }
741
+ function normalizeLocalResourceExpr(expr) {
742
+ let normalized = expr;
743
+ if (resourceAliases && resourceAliases.size > 0) {
744
+ const aliasEntries = Array.from(resourceAliases.entries())
745
+ .filter(([alias, resolvedId]) => alias !== resolvedId)
746
+ .sort((left, right) => right[0].length - left[0].length);
747
+ for (const [alias, resolvedId] of aliasEntries) {
748
+ normalized = normalized
749
+ .replace(new RegExp(`\\b${escapeRegExpLiteral(alias)}(?=\\.(?:status|spec|metadata)\\.)`, 'g'), resolvedId)
750
+ .replace(new RegExp(`__KUBERNETES_REF_${escapeRegExpLiteral(alias)}_`, 'g'), `__KUBERNETES_REF_${resolvedId}_`);
751
+ }
752
+ }
753
+ return localResourceIds.length > 0
754
+ ? remapVariableNames(normalized, localResourceIds, preserveVariables)
755
+ : normalized;
756
+ }
757
+ /**
758
+ * Rewrite `schema.spec.*` references inside a resolved CEL expression so
759
+ * the result is valid KRO status CEL. KRO does not accept `schema.spec.*`
760
+ * in status CEL, so we apply two rewrites:
761
+ *
762
+ * - `schema.spec.X.Y.orValue(Z)` → `Z` (substitute the default)
763
+ * - `schema.spec.X.Y` → `X.spec.Y` iff `X` is a known resource ID
764
+ * (routes the reference to the deployed resource's spec field)
765
+ *
766
+ * Unknown schema references are left intact; the KRO factory's deploy-
767
+ * time hydration handles them.
768
+ */
769
+ function rewriteSchemaRefsForKroStatus(expr) {
770
+ let out = expr.replace(/__schema__\.spec\.[a-zA-Z0-9_.]+\.orValue\(([^)]+)\)/g, '$1');
771
+ out = out.replace(/__schema__\.spec\.([a-zA-Z0-9_.]+)/g, 'spec.$1');
772
+ out = out.replace(/schema\.spec\.[a-zA-Z0-9_.]+\.orValue\(([^)]+)\)/g, '$1');
773
+ out = out.replace(/schema\.spec\.([a-zA-Z0-9]+)\.([a-zA-Z0-9.]+)/g, (_match, firstSegment, rest) => {
774
+ if (resourceIds?.has(firstSegment)) {
775
+ return `${firstSegment}.spec.${rest}`;
776
+ }
777
+ return _match;
778
+ });
779
+ out = out.replace(/schema\.spec\.([a-zA-Z_$][\w$]*)/g, 'spec.$1');
780
+ return out;
781
+ }
782
+ /**
783
+ * Compose the inner-expression resolution + KRO-status finalization
784
+ * pipeline used by both the KubernetesRef and CelExpression branches.
785
+ * Centralized here so the two branches don't drift on what "produce
786
+ * KRO status CEL from a resolved expression" means.
787
+ */
788
+ function statusFieldFromExpression(expr) {
789
+ const resolved = normalizeLocalResourceExpr(resolveNestedCompositionRefs(normalizeLocalResourceExpr(expr), nestedStatusCel, resourceIds));
790
+ if (resolved.includes('__KUBERNETES_REF_')) {
791
+ // Marker-laden — use mixed-template form.
792
+ return rewriteSchemaRefsForKroStatus(convertKubernetesRefMarkersTocel(resolved));
793
+ }
794
+ if (resolved.includes('${')) {
795
+ // Already a KRO mixed-template value. Do not wrap it again as
796
+ // `${http://${...}}`, which is invalid CEL/YAML for status fields.
797
+ return rewriteSchemaRefsForKroStatus(resolved);
798
+ }
799
+ return `\${${rewriteSchemaRefsForKroStatus(resolved)}}`;
800
+ }
154
801
  function serializeValue(value) {
155
802
  if (isKubernetesRef(value)) {
156
803
  const ref = value;
157
- // For nested composition status references, inline the inner composition's
158
- // actual CEL expression instead of referencing the virtual composition ID.
804
+ // For nested composition status references, look up the inner
805
+ // composition's analyzed CEL via the shared resolver and finalize
806
+ // it for KRO status emission.
159
807
  if (ref.__nestedComposition && nestedStatusCel) {
160
808
  const fieldName = ref.fieldPath.replace(/^status\./, '');
161
- // Try exact match
162
- const exactKey = `__nestedStatus:${ref.resourceId}:${fieldName}`;
163
- logger.debug('Resolving nested composition KubernetesRef', {
164
- resourceId: ref.resourceId,
165
- fieldPath: ref.fieldPath,
166
- fieldName,
167
- exactKey,
168
- hasExactMatch: !!nestedStatusCel[exactKey],
169
- });
170
- if (nestedStatusCel[exactKey]) {
171
- return `\${${nestedStatusCel[exactKey]}}`;
172
- }
173
- // Try base-name match: strip trailing digits and compare.
174
- // The expression may use 'nestedService2' while the key has 'nestedService1'.
175
- // Also try prefix match for variable name → composition baseId mapping.
176
- const refBase = ref.resourceId.replace(/\d+$/, '');
177
- for (const [key, cel] of Object.entries(nestedStatusCel)) {
178
- const parts = key.split(':');
179
- if (parts.length !== 3 || parts[2] !== fieldName)
180
- continue;
181
- const keyBase = parts[1].replace(/\d+$/, '');
182
- if (refBase === keyBase) {
183
- return `\${${cel}}`;
184
- }
185
- if (isCamelCasePrefix(refBase, keyBase) || isCamelCasePrefix(keyBase, refBase)) {
186
- logger.warn('Nested status CEL resolved via prefix match (not exact)', {
187
- refResourceId: ref.resourceId, matchedKey: key, fieldName,
188
- });
189
- return `\${${cel}}`;
190
- }
809
+ const innerExpr = lookupNestedExpression(ref.resourceId, fieldName, nestedStatusCel);
810
+ if (innerExpr !== undefined) {
811
+ return statusFieldFromExpression(innerExpr);
191
812
  }
192
813
  }
193
- // Nested composition ref that couldn't be inlined the virtual ID
194
- // doesn't exist in the KRO RGD. Emit as-is; the validator will warn.
195
- // When nestedStatusCel IS available but didn't match, this is a real
196
- // missing mapping. When it's unavailable (simple compositions without
197
- // inner status CEL), the ref passes through for backward compatibility.
198
- return `\${${ref.resourceId}.${ref.fieldPath}}`;
814
+ // Unresolved ref still run through the status-expression finalizer so
815
+ // direct schema refs (`__schema__.spec.x`) become KRO status refs (`spec.x`).
816
+ // Downstream validation will flag virtual ids that don't correspond to a
817
+ // real resource.
818
+ return statusFieldFromExpression(`${ref.resourceId}.${ref.fieldPath}`);
199
819
  }
200
820
  if (isCelExpression(value)) {
201
821
  if (value.__isTemplate) {
202
- return value.expression;
822
+ return value.expression.replace(/\$\{([^}]+)\}/g, (_match, innerExpr) => statusFieldFromExpression(innerExpr));
203
823
  }
204
- // Replace nested composition status references with the inner composition's
205
- // actual CEL expression. Handles both standalone refs and refs embedded in
206
- // larger expressions (e.g., `... && inngest.status.ready`).
207
- //
208
- // The fn.toString analysis uses variable names (e.g., `inngest`) but the
209
- // nested status CEL keys use baseIds with instance numbers (e.g.,
210
- // `inngestBootstrap1`). We try the exact match first, then scan for keys
211
- // that start with the variable name.
212
- let expr = value.expression;
213
- if (nestedStatusCel) {
214
- expr = expr.replace(/(\w+)\.status\.([\w.]+)/g, (_match, compId, field) => {
215
- // Try exact match first
216
- const exactKey = `__nestedStatus:${compId}:${field}`;
217
- if (nestedStatusCel[exactKey]) {
218
- return `(${nestedStatusCel[exactKey]})`;
219
- }
220
- // Try base-name match: strip trailing digits and compare.
221
- // Also try prefix match: the fn.toString variable name (e.g., `inngest`)
222
- // may be a prefix of the nested composition's baseId (e.g., `inngestBootstrap`).
223
- const compIdBase = compId.replace(/\d+$/, '');
224
- for (const [key, cel] of Object.entries(nestedStatusCel)) {
225
- const parts = key.split(':');
226
- if (parts.length !== 3 || parts[2] !== field)
227
- continue;
228
- const keyBase = parts[1].replace(/\d+$/, '');
229
- if (compIdBase === keyBase) {
230
- return `(${cel})`;
231
- }
232
- if (isCamelCasePrefix(compIdBase, keyBase) || isCamelCasePrefix(keyBase, compIdBase)) {
233
- logger.warn('Nested status CEL expression resolved via prefix match', {
234
- compId, matchedKey: key, field,
235
- });
236
- return `(${cel})`;
237
- }
238
- }
239
- return `${compId}.status.${field}`;
240
- });
241
- }
242
- // KRO status CEL cannot reference `schema.spec.*` — only resource IDs.
243
- // Replace schema references with their .orValue() defaults, or with the
244
- // resource's own spec field if a mapping is available.
245
- // Pattern: `schema.spec.X.Y.orValue(Z)` → `Z` (use the default)
246
- expr = expr.replace(/schema\.spec\.[a-zA-Z0-9_.]+\.orValue\(([^)]+)\)/g, '$1');
247
- // For bare `schema.spec.X.Y` (no orValue): map to the resource's spec
248
- // field ONLY if X is a known resource ID. E.g., `schema.spec.database.instances`
249
- // → `database.spec.instances` when `database` is a resource in the RGD.
250
- // Unknown segments are left as-is (they'll be resolved at deploy time).
251
- expr = expr.replace(/schema\.spec\.([a-zA-Z0-9]+)\.([a-zA-Z0-9.]+)/g, (_match, firstSegment, rest) => {
252
- if (resourceIds?.has(firstSegment)) {
253
- return `${firstSegment}.spec.${rest}`;
254
- }
255
- // Not a known resource ID — keep the original schema ref.
256
- // This will be resolved by the KRO factory at deploy time.
257
- return _match;
258
- });
259
- return `\${${expr}}`;
824
+ return statusFieldFromExpression(value.expression);
260
825
  }
261
- if (value && typeof value === 'object' && !Array.isArray(value)) {
826
+ if (Array.isArray(value)) {
827
+ return value.map((item) => serializeValue(item));
828
+ }
829
+ if (value && typeof value === 'object') {
262
830
  const nestedExpressions = {};
263
831
  for (const [key, nestedValue] of Object.entries(value)) {
264
832
  nestedExpressions[key] = serializeValue(nestedValue);
@@ -266,11 +834,13 @@ export function serializeStatusMappingsToCel(statusMappings, nestedStatusCel, re
266
834
  return nestedExpressions;
267
835
  }
268
836
  if (typeof value === 'string') {
269
- // Convert embedded __KUBERNETES_REF__ markers to CEL expressions
270
837
  if (value.includes('__KUBERNETES_REF_')) {
271
- return convertKubernetesRefMarkersTocel(value);
838
+ // Resolve nested refs first (substitution is a no-op on pure marker
839
+ // strings but handles mixed forms), then convert markers to KRO CEL.
840
+ const resolved = resolveNestedRefMarkers(normalizeLocalResourceExpr(value), nestedStatusCel, resourceIds);
841
+ return rewriteSchemaRefsForKroStatus(convertKubernetesRefMarkersTocel(resolved));
272
842
  }
273
- return `\${"${value}"}`;
843
+ return `\${"${escapeCelString(value)}"}`;
274
844
  }
275
845
  if (typeof value === 'number') {
276
846
  return `\${${value}}`;
@@ -278,9 +848,16 @@ export function serializeStatusMappingsToCel(statusMappings, nestedStatusCel, re
278
848
  if (typeof value === 'boolean') {
279
849
  return `\${${value}}`;
280
850
  }
851
+ if (value === null) {
852
+ return `\${null}`;
853
+ }
281
854
  return `\${""}`;
282
855
  }
283
856
  for (const [fieldName, fieldValue] of Object.entries(statusMappings)) {
857
+ // Skip internal metadata fields — these are consumed during
858
+ // serialization, not emitted as status fields.
859
+ if (fieldName.startsWith('__'))
860
+ continue;
284
861
  celExpressions[fieldName] = serializeValue(fieldValue);
285
862
  }
286
863
  return celExpressions;
@@ -303,6 +880,7 @@ function isCamelCasePrefix(prefix, target) {
303
880
  if (prefix.length === target.length)
304
881
  return true;
305
882
  // Character after the prefix must be uppercase (camelCase word boundary)
306
- return /[A-Z]/.test(target[prefix.length]);
883
+ const boundaryChar = target[prefix.length];
884
+ return boundaryChar !== undefined && /[A-Z]/.test(boundaryChar);
307
885
  }
308
886
  //# sourceMappingURL=cel-references.js.map