typekro 0.3.0 → 0.4.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 (443) hide show
  1. package/README.md +142 -1054
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/alchemy/deployers.d.ts +0 -5
  4. package/dist/alchemy/deployers.d.ts.map +1 -1
  5. package/dist/alchemy/deployers.js +25 -72
  6. package/dist/alchemy/deployers.js.map +1 -1
  7. package/dist/core/composition/imperative.d.ts +2 -2
  8. package/dist/core/composition/imperative.d.ts.map +1 -1
  9. package/dist/core/composition/imperative.js +394 -10
  10. package/dist/core/composition/imperative.js.map +1 -1
  11. package/dist/core/composition/typekro-runtime/typekro-runtime.d.ts +1 -9
  12. package/dist/core/composition/typekro-runtime/typekro-runtime.d.ts.map +1 -1
  13. package/dist/core/composition/typekro-runtime/typekro-runtime.js +76 -10
  14. package/dist/core/composition/typekro-runtime/typekro-runtime.js.map +1 -1
  15. package/dist/core/composition/typekro-runtime/types.d.ts +8 -5
  16. package/dist/core/composition/typekro-runtime/types.d.ts.map +1 -1
  17. package/dist/core/composition/typekro-runtime/types.js.map +1 -1
  18. package/dist/core/constants/brands.d.ts +20 -0
  19. package/dist/core/constants/brands.d.ts.map +1 -1
  20. package/dist/core/constants/brands.js +20 -0
  21. package/dist/core/constants/brands.js.map +1 -1
  22. package/dist/core/deployment/direct-factory.d.ts +36 -1
  23. package/dist/core/deployment/direct-factory.d.ts.map +1 -1
  24. package/dist/core/deployment/direct-factory.js +289 -4
  25. package/dist/core/deployment/direct-factory.js.map +1 -1
  26. package/dist/core/deployment/engine.d.ts +57 -2
  27. package/dist/core/deployment/engine.d.ts.map +1 -1
  28. package/dist/core/deployment/engine.js +677 -49
  29. package/dist/core/deployment/engine.js.map +1 -1
  30. package/dist/core/deployment/event-filter.d.ts.map +1 -1
  31. package/dist/core/deployment/event-filter.js +6 -7
  32. package/dist/core/deployment/event-filter.js.map +1 -1
  33. package/dist/core/deployment/event-monitor.d.ts +36 -2
  34. package/dist/core/deployment/event-monitor.d.ts.map +1 -1
  35. package/dist/core/deployment/event-monitor.js +183 -33
  36. package/dist/core/deployment/event-monitor.js.map +1 -1
  37. package/dist/core/deployment/kro-factory.d.ts +22 -0
  38. package/dist/core/deployment/kro-factory.d.ts.map +1 -1
  39. package/dist/core/deployment/kro-factory.js +291 -27
  40. package/dist/core/deployment/kro-factory.js.map +1 -1
  41. package/dist/core/deployment/readiness.d.ts.map +1 -1
  42. package/dist/core/deployment/readiness.js +4 -2
  43. package/dist/core/deployment/readiness.js.map +1 -1
  44. package/dist/core/deployment/rollback-manager.d.ts +2 -1
  45. package/dist/core/deployment/rollback-manager.d.ts.map +1 -1
  46. package/dist/core/deployment/rollback-manager.js +5 -2
  47. package/dist/core/deployment/rollback-manager.js.map +1 -1
  48. package/dist/core/deployment/shared-utilities.js.map +1 -1
  49. package/dist/core/deployment/status-hydrator.d.ts +1 -1
  50. package/dist/core/deployment/status-hydrator.d.ts.map +1 -1
  51. package/dist/core/deployment/status-hydrator.js +8 -5
  52. package/dist/core/deployment/status-hydrator.js.map +1 -1
  53. package/dist/core/deployment/strategies/base-strategy.d.ts.map +1 -1
  54. package/dist/core/deployment/strategies/base-strategy.js +60 -21
  55. package/dist/core/deployment/strategies/base-strategy.js.map +1 -1
  56. package/dist/core/deployment/strategies/direct-strategy.d.ts +7 -0
  57. package/dist/core/deployment/strategies/direct-strategy.d.ts.map +1 -1
  58. package/dist/core/deployment/strategies/direct-strategy.js +50 -0
  59. package/dist/core/deployment/strategies/direct-strategy.js.map +1 -1
  60. package/dist/core/deployment/strategies/kro-strategy.d.ts +5 -0
  61. package/dist/core/deployment/strategies/kro-strategy.d.ts.map +1 -1
  62. package/dist/core/deployment/strategies/kro-strategy.js +53 -4
  63. package/dist/core/deployment/strategies/kro-strategy.js.map +1 -1
  64. package/dist/core/evaluation/cel-optimizer.d.ts.map +1 -1
  65. package/dist/core/evaluation/cel-optimizer.js +7 -13
  66. package/dist/core/evaluation/cel-optimizer.js.map +1 -1
  67. package/dist/core/expressions/analyzer.d.ts +6 -6
  68. package/dist/core/expressions/analyzer.d.ts.map +1 -1
  69. package/dist/core/expressions/analyzer.js +40 -75
  70. package/dist/core/expressions/analyzer.js.map +1 -1
  71. package/dist/core/expressions/cel-conversion-engine.d.ts.map +1 -1
  72. package/dist/core/expressions/cel-conversion-engine.js +10 -11
  73. package/dist/core/expressions/cel-conversion-engine.js.map +1 -1
  74. package/dist/core/expressions/composition-integration.d.ts +2 -2
  75. package/dist/core/expressions/composition-integration.d.ts.map +1 -1
  76. package/dist/core/expressions/composition-integration.js +20 -12
  77. package/dist/core/expressions/composition-integration.js.map +1 -1
  78. package/dist/core/expressions/field-hydration-processor.d.ts +4 -1
  79. package/dist/core/expressions/field-hydration-processor.d.ts.map +1 -1
  80. package/dist/core/expressions/field-hydration-processor.js +12 -13
  81. package/dist/core/expressions/field-hydration-processor.js.map +1 -1
  82. package/dist/core/expressions/imperative-analyzer.d.ts.map +1 -1
  83. package/dist/core/expressions/imperative-analyzer.js +193 -49
  84. package/dist/core/expressions/imperative-analyzer.js.map +1 -1
  85. package/dist/core/expressions/index.d.ts +2 -0
  86. package/dist/core/expressions/index.d.ts.map +1 -1
  87. package/dist/core/expressions/index.js +2 -0
  88. package/dist/core/expressions/index.js.map +1 -1
  89. package/dist/core/expressions/magic-proxy-analyzer.d.ts +1 -1
  90. package/dist/core/expressions/magic-proxy-analyzer.d.ts.map +1 -1
  91. package/dist/core/expressions/magic-proxy-analyzer.js +8 -7
  92. package/dist/core/expressions/magic-proxy-analyzer.js.map +1 -1
  93. package/dist/core/expressions/parser.d.ts +163 -0
  94. package/dist/core/expressions/parser.d.ts.map +1 -0
  95. package/dist/core/expressions/parser.js +272 -0
  96. package/dist/core/expressions/parser.js.map +1 -0
  97. package/dist/core/expressions/status-builder-analyzer.d.ts.map +1 -1
  98. package/dist/core/expressions/status-builder-analyzer.js +15 -5
  99. package/dist/core/expressions/status-builder-analyzer.js.map +1 -1
  100. package/dist/core/kubernetes/api.d.ts.map +1 -1
  101. package/dist/core/kubernetes/api.js +5 -6
  102. package/dist/core/kubernetes/api.js.map +1 -1
  103. package/dist/core/kubernetes/bun-api-client.d.ts +95 -0
  104. package/dist/core/kubernetes/bun-api-client.d.ts.map +1 -0
  105. package/dist/core/kubernetes/bun-api-client.js +160 -0
  106. package/dist/core/kubernetes/bun-api-client.js.map +1 -0
  107. package/dist/core/kubernetes/bun-http-library.d.ts +38 -0
  108. package/dist/core/kubernetes/bun-http-library.d.ts.map +1 -0
  109. package/dist/core/kubernetes/bun-http-library.js +133 -0
  110. package/dist/core/kubernetes/bun-http-library.js.map +1 -0
  111. package/dist/core/kubernetes/client-provider.d.ts +3 -0
  112. package/dist/core/kubernetes/client-provider.d.ts.map +1 -1
  113. package/dist/core/kubernetes/client-provider.js +32 -23
  114. package/dist/core/kubernetes/client-provider.js.map +1 -1
  115. package/dist/core/kubernetes/errors.d.ts +189 -0
  116. package/dist/core/kubernetes/errors.d.ts.map +1 -0
  117. package/dist/core/kubernetes/errors.js +298 -0
  118. package/dist/core/kubernetes/errors.js.map +1 -0
  119. package/dist/core/kubernetes/index.d.ts +19 -0
  120. package/dist/core/kubernetes/index.d.ts.map +1 -0
  121. package/dist/core/kubernetes/index.js +23 -0
  122. package/dist/core/kubernetes/index.js.map +1 -0
  123. package/dist/core/kubernetes/type-guards.d.ts +142 -0
  124. package/dist/core/kubernetes/type-guards.d.ts.map +1 -0
  125. package/dist/core/kubernetes/type-guards.js +151 -0
  126. package/dist/core/kubernetes/type-guards.js.map +1 -0
  127. package/dist/core/logging/logger.d.ts.map +1 -1
  128. package/dist/core/logging/logger.js +8 -0
  129. package/dist/core/logging/logger.js.map +1 -1
  130. package/dist/core/readiness/cluster-state.d.ts.map +1 -1
  131. package/dist/core/readiness/cluster-state.js +6 -4
  132. package/dist/core/readiness/cluster-state.js.map +1 -1
  133. package/dist/core/references/cel-evaluator.d.ts.map +1 -1
  134. package/dist/core/references/cel-evaluator.js +12 -2
  135. package/dist/core/references/cel-evaluator.js.map +1 -1
  136. package/dist/core/references/cel.d.ts +13 -1
  137. package/dist/core/references/cel.d.ts.map +1 -1
  138. package/dist/core/references/cel.js +50 -0
  139. package/dist/core/references/cel.js.map +1 -1
  140. package/dist/core/references/resolver.d.ts +28 -1
  141. package/dist/core/references/resolver.d.ts.map +1 -1
  142. package/dist/core/references/resolver.js +325 -11
  143. package/dist/core/references/resolver.js.map +1 -1
  144. package/dist/core/references/schema-proxy.d.ts.map +1 -1
  145. package/dist/core/references/schema-proxy.js +27 -13
  146. package/dist/core/references/schema-proxy.js.map +1 -1
  147. package/dist/core/scope/resolver.d.ts +16 -0
  148. package/dist/core/scope/resolver.d.ts.map +1 -0
  149. package/dist/core/scope/resolver.js +45 -0
  150. package/dist/core/scope/resolver.js.map +1 -0
  151. package/dist/core/serialization/core.d.ts +1 -1
  152. package/dist/core/serialization/core.d.ts.map +1 -1
  153. package/dist/core/serialization/core.js +78 -54
  154. package/dist/core/serialization/core.js.map +1 -1
  155. package/dist/core/types/common.d.ts +23 -1
  156. package/dist/core/types/common.d.ts.map +1 -1
  157. package/dist/core/types/deployment.d.ts +71 -1
  158. package/dist/core/types/deployment.d.ts.map +1 -1
  159. package/dist/core/types/deployment.js +24 -0
  160. package/dist/core/types/deployment.js.map +1 -1
  161. package/dist/core/types/factory-scope.d.ts +42 -0
  162. package/dist/core/types/factory-scope.d.ts.map +1 -0
  163. package/dist/core/types/factory-scope.js +14 -0
  164. package/dist/core/types/factory-scope.js.map +1 -0
  165. package/dist/core/types/kubernetes.d.ts +146 -4
  166. package/dist/core/types/kubernetes.d.ts.map +1 -1
  167. package/dist/core/types/references.d.ts +47 -3
  168. package/dist/core/types/references.d.ts.map +1 -1
  169. package/dist/core/types/references.js.map +1 -1
  170. package/dist/core/types/serialization.d.ts +17 -6
  171. package/dist/core/types/serialization.d.ts.map +1 -1
  172. package/dist/core/utils/crd-patcher.d.ts +30 -0
  173. package/dist/core/utils/crd-patcher.d.ts.map +1 -0
  174. package/dist/core/utils/crd-patcher.js +198 -0
  175. package/dist/core/utils/crd-patcher.js.map +1 -0
  176. package/dist/core/utils/crd-schema-fix.d.ts +108 -0
  177. package/dist/core/utils/crd-schema-fix.d.ts.map +1 -0
  178. package/dist/core/utils/crd-schema-fix.js +245 -0
  179. package/dist/core/utils/crd-schema-fix.js.map +1 -0
  180. package/dist/core/utils/index.d.ts +12 -0
  181. package/dist/core/utils/index.d.ts.map +1 -0
  182. package/dist/core/utils/index.js +12 -0
  183. package/dist/core/utils/index.js.map +1 -0
  184. package/dist/core/utils/minimal-connection-reset-suppression.d.ts +16 -0
  185. package/dist/core/utils/minimal-connection-reset-suppression.d.ts.map +1 -0
  186. package/dist/core/utils/minimal-connection-reset-suppression.js +72 -0
  187. package/dist/core/utils/minimal-connection-reset-suppression.js.map +1 -0
  188. package/dist/core/utils/output-filter.d.ts +16 -0
  189. package/dist/core/utils/output-filter.d.ts.map +1 -0
  190. package/dist/core/utils/output-filter.js +90 -0
  191. package/dist/core/utils/output-filter.js.map +1 -0
  192. package/dist/core/utils/scoped-error-suppression.d.ts +25 -0
  193. package/dist/core/utils/scoped-error-suppression.d.ts.map +1 -0
  194. package/dist/core/utils/scoped-error-suppression.js +226 -0
  195. package/dist/core/utils/scoped-error-suppression.js.map +1 -0
  196. package/dist/core/validation/cel-validator.d.ts.map +1 -1
  197. package/dist/core/validation/cel-validator.js +51 -15
  198. package/dist/core/validation/cel-validator.js.map +1 -1
  199. package/dist/factories/apisix/compositions/apisix-bootstrap.d.ts +38 -0
  200. package/dist/factories/apisix/compositions/apisix-bootstrap.d.ts.map +1 -0
  201. package/dist/factories/apisix/compositions/apisix-bootstrap.js +280 -0
  202. package/dist/factories/apisix/compositions/apisix-bootstrap.js.map +1 -0
  203. package/dist/factories/apisix/compositions/index.d.ts +5 -0
  204. package/dist/factories/apisix/compositions/index.d.ts.map +1 -0
  205. package/dist/factories/apisix/compositions/index.js +5 -0
  206. package/dist/factories/apisix/compositions/index.js.map +1 -0
  207. package/dist/factories/apisix/index.d.ts +11 -0
  208. package/dist/factories/apisix/index.d.ts.map +1 -0
  209. package/dist/factories/apisix/index.js +11 -0
  210. package/dist/factories/apisix/index.js.map +1 -0
  211. package/dist/factories/apisix/resources/helm.d.ts +59 -0
  212. package/dist/factories/apisix/resources/helm.d.ts.map +1 -0
  213. package/dist/factories/apisix/resources/helm.js +175 -0
  214. package/dist/factories/apisix/resources/helm.js.map +1 -0
  215. package/dist/factories/apisix/resources/index.d.ts +5 -0
  216. package/dist/factories/apisix/resources/index.d.ts.map +1 -0
  217. package/dist/factories/apisix/resources/index.js +5 -0
  218. package/dist/factories/apisix/resources/index.js.map +1 -0
  219. package/dist/factories/apisix/types.d.ts +339 -0
  220. package/dist/factories/apisix/types.d.ts.map +1 -0
  221. package/dist/factories/apisix/types.js +88 -0
  222. package/dist/factories/apisix/types.js.map +1 -0
  223. package/dist/factories/apisix/utils/helm-values-mapper.d.ts +19 -0
  224. package/dist/factories/apisix/utils/helm-values-mapper.d.ts.map +1 -0
  225. package/dist/factories/apisix/utils/helm-values-mapper.js +108 -0
  226. package/dist/factories/apisix/utils/helm-values-mapper.js.map +1 -0
  227. package/dist/factories/apisix/utils/index.d.ts +5 -0
  228. package/dist/factories/apisix/utils/index.d.ts.map +1 -0
  229. package/dist/factories/apisix/utils/index.js +5 -0
  230. package/dist/factories/apisix/utils/index.js.map +1 -0
  231. package/dist/factories/cert-manager/compositions/cert-manager-bootstrap.d.ts +45 -0
  232. package/dist/factories/cert-manager/compositions/cert-manager-bootstrap.d.ts.map +1 -0
  233. package/dist/factories/cert-manager/compositions/cert-manager-bootstrap.js +323 -0
  234. package/dist/factories/cert-manager/compositions/cert-manager-bootstrap.js.map +1 -0
  235. package/dist/factories/cert-manager/compositions/index.d.ts +2 -0
  236. package/dist/factories/cert-manager/compositions/index.d.ts.map +1 -0
  237. package/dist/factories/cert-manager/compositions/index.js +2 -0
  238. package/dist/factories/cert-manager/compositions/index.js.map +1 -0
  239. package/dist/factories/cert-manager/index.d.ts +10 -0
  240. package/dist/factories/cert-manager/index.d.ts.map +1 -0
  241. package/dist/factories/cert-manager/index.js +19 -0
  242. package/dist/factories/cert-manager/index.js.map +1 -0
  243. package/dist/factories/cert-manager/resources/certificates.d.ts +39 -0
  244. package/dist/factories/cert-manager/resources/certificates.d.ts.map +1 -0
  245. package/dist/factories/cert-manager/resources/certificates.js +132 -0
  246. package/dist/factories/cert-manager/resources/certificates.js.map +1 -0
  247. package/dist/factories/cert-manager/resources/challenges.d.ts +113 -0
  248. package/dist/factories/cert-manager/resources/challenges.d.ts.map +1 -0
  249. package/dist/factories/cert-manager/resources/challenges.js +281 -0
  250. package/dist/factories/cert-manager/resources/challenges.js.map +1 -0
  251. package/dist/factories/cert-manager/resources/helm.d.ts +57 -0
  252. package/dist/factories/cert-manager/resources/helm.d.ts.map +1 -0
  253. package/dist/factories/cert-manager/resources/helm.js +390 -0
  254. package/dist/factories/cert-manager/resources/helm.js.map +1 -0
  255. package/dist/factories/cert-manager/resources/index.d.ts +5 -0
  256. package/dist/factories/cert-manager/resources/index.d.ts.map +1 -0
  257. package/dist/factories/cert-manager/resources/index.js +6 -0
  258. package/dist/factories/cert-manager/resources/index.js.map +1 -0
  259. package/dist/factories/cert-manager/resources/issuers.d.ts +79 -0
  260. package/dist/factories/cert-manager/resources/issuers.d.ts.map +1 -0
  261. package/dist/factories/cert-manager/resources/issuers.js +204 -0
  262. package/dist/factories/cert-manager/resources/issuers.js.map +1 -0
  263. package/dist/factories/cert-manager/types.d.ts +1015 -0
  264. package/dist/factories/cert-manager/types.d.ts.map +1 -0
  265. package/dist/factories/cert-manager/types.js +198 -0
  266. package/dist/factories/cert-manager/types.js.map +1 -0
  267. package/dist/factories/cert-manager/utils/helm-values-mapper.d.ts +19 -0
  268. package/dist/factories/cert-manager/utils/helm-values-mapper.d.ts.map +1 -0
  269. package/dist/factories/cert-manager/utils/helm-values-mapper.js +117 -0
  270. package/dist/factories/cert-manager/utils/helm-values-mapper.js.map +1 -0
  271. package/dist/factories/cert-manager/utils/index.d.ts +2 -0
  272. package/dist/factories/cert-manager/utils/index.d.ts.map +1 -0
  273. package/dist/factories/cert-manager/utils/index.js +2 -0
  274. package/dist/factories/cert-manager/utils/index.js.map +1 -0
  275. package/dist/factories/cilium/compositions/cilium-bootstrap.d.ts +220 -0
  276. package/dist/factories/cilium/compositions/cilium-bootstrap.d.ts.map +1 -0
  277. package/dist/factories/cilium/compositions/cilium-bootstrap.js +293 -0
  278. package/dist/factories/cilium/compositions/cilium-bootstrap.js.map +1 -0
  279. package/dist/factories/cilium/compositions/index.d.ts +8 -0
  280. package/dist/factories/cilium/compositions/index.d.ts.map +1 -0
  281. package/dist/factories/cilium/compositions/index.js +11 -0
  282. package/dist/factories/cilium/compositions/index.js.map +1 -0
  283. package/dist/factories/cilium/index.d.ts +10 -0
  284. package/dist/factories/cilium/index.d.ts.map +1 -0
  285. package/dist/factories/cilium/index.js +19 -0
  286. package/dist/factories/cilium/index.js.map +1 -0
  287. package/dist/factories/cilium/resources/bgp.d.ts +10 -0
  288. package/dist/factories/cilium/resources/bgp.d.ts.map +1 -0
  289. package/dist/factories/cilium/resources/bgp.js +14 -0
  290. package/dist/factories/cilium/resources/bgp.js.map +1 -0
  291. package/dist/factories/cilium/resources/gateway.d.ts +72 -0
  292. package/dist/factories/cilium/resources/gateway.d.ts.map +1 -0
  293. package/dist/factories/cilium/resources/gateway.js +118 -0
  294. package/dist/factories/cilium/resources/gateway.js.map +1 -0
  295. package/dist/factories/cilium/resources/helm.d.ts +93 -0
  296. package/dist/factories/cilium/resources/helm.d.ts.map +1 -0
  297. package/dist/factories/cilium/resources/helm.js +377 -0
  298. package/dist/factories/cilium/resources/helm.js.map +1 -0
  299. package/dist/factories/cilium/resources/index.d.ts +14 -0
  300. package/dist/factories/cilium/resources/index.d.ts.map +1 -0
  301. package/dist/factories/cilium/resources/index.js +35 -0
  302. package/dist/factories/cilium/resources/index.js.map +1 -0
  303. package/dist/factories/cilium/resources/load-balancer.d.ts +9 -0
  304. package/dist/factories/cilium/resources/load-balancer.d.ts.map +1 -0
  305. package/dist/factories/cilium/resources/load-balancer.js +12 -0
  306. package/dist/factories/cilium/resources/load-balancer.js.map +1 -0
  307. package/dist/factories/cilium/resources/networking.d.ts +202 -0
  308. package/dist/factories/cilium/resources/networking.d.ts.map +1 -0
  309. package/dist/factories/cilium/resources/networking.js +581 -0
  310. package/dist/factories/cilium/resources/networking.js.map +1 -0
  311. package/dist/factories/cilium/resources/observability.d.ts +9 -0
  312. package/dist/factories/cilium/resources/observability.d.ts.map +1 -0
  313. package/dist/factories/cilium/resources/observability.js +11 -0
  314. package/dist/factories/cilium/resources/observability.js.map +1 -0
  315. package/dist/factories/cilium/resources/security.d.ts +10 -0
  316. package/dist/factories/cilium/resources/security.d.ts.map +1 -0
  317. package/dist/factories/cilium/resources/security.js +14 -0
  318. package/dist/factories/cilium/resources/security.js.map +1 -0
  319. package/dist/factories/cilium/types.d.ts +1001 -0
  320. package/dist/factories/cilium/types.d.ts.map +1 -0
  321. package/dist/factories/cilium/types.js +79 -0
  322. package/dist/factories/cilium/types.js.map +1 -0
  323. package/dist/factories/external-dns/compositions/external-dns-bootstrap.d.ts +32 -0
  324. package/dist/factories/external-dns/compositions/external-dns-bootstrap.d.ts.map +1 -0
  325. package/dist/factories/external-dns/compositions/external-dns-bootstrap.js +152 -0
  326. package/dist/factories/external-dns/compositions/external-dns-bootstrap.js.map +1 -0
  327. package/dist/factories/external-dns/compositions/index.d.ts +2 -0
  328. package/dist/factories/external-dns/compositions/index.d.ts.map +1 -0
  329. package/dist/factories/external-dns/compositions/index.js +3 -0
  330. package/dist/factories/external-dns/compositions/index.js.map +1 -0
  331. package/dist/factories/external-dns/index.d.ts +10 -0
  332. package/dist/factories/external-dns/index.d.ts.map +1 -0
  333. package/dist/factories/external-dns/index.js +19 -0
  334. package/dist/factories/external-dns/index.js.map +1 -0
  335. package/dist/factories/external-dns/resources/dns-endpoint.d.ts +54 -0
  336. package/dist/factories/external-dns/resources/dns-endpoint.d.ts.map +1 -0
  337. package/dist/factories/external-dns/resources/dns-endpoint.js +53 -0
  338. package/dist/factories/external-dns/resources/dns-endpoint.js.map +1 -0
  339. package/dist/factories/external-dns/resources/helm.d.ts +57 -0
  340. package/dist/factories/external-dns/resources/helm.d.ts.map +1 -0
  341. package/dist/factories/external-dns/resources/helm.js +435 -0
  342. package/dist/factories/external-dns/resources/helm.js.map +1 -0
  343. package/dist/factories/external-dns/resources/index.d.ts +3 -0
  344. package/dist/factories/external-dns/resources/index.d.ts.map +1 -0
  345. package/dist/factories/external-dns/resources/index.js +4 -0
  346. package/dist/factories/external-dns/resources/index.js.map +1 -0
  347. package/dist/factories/external-dns/types.d.ts +180 -0
  348. package/dist/factories/external-dns/types.d.ts.map +1 -0
  349. package/dist/factories/external-dns/types.js +39 -0
  350. package/dist/factories/external-dns/types.js.map +1 -0
  351. package/dist/factories/flux/git-repository.d.ts +2 -2
  352. package/dist/factories/flux/git-repository.d.ts.map +1 -1
  353. package/dist/factories/helm/types.d.ts +24 -3
  354. package/dist/factories/helm/types.d.ts.map +1 -1
  355. package/dist/factories/index.d.ts +7 -1
  356. package/dist/factories/index.d.ts.map +1 -1
  357. package/dist/factories/index.js +21 -1
  358. package/dist/factories/index.js.map +1 -1
  359. package/dist/factories/kubernetes/config/config-map.d.ts +4 -1
  360. package/dist/factories/kubernetes/config/config-map.d.ts.map +1 -1
  361. package/dist/factories/kubernetes/config/config-map.js +4 -0
  362. package/dist/factories/kubernetes/config/config-map.js.map +1 -1
  363. package/dist/factories/kubernetes/config/secret.d.ts +6 -1
  364. package/dist/factories/kubernetes/config/secret.d.ts.map +1 -1
  365. package/dist/factories/kubernetes/config/secret.js +4 -0
  366. package/dist/factories/kubernetes/config/secret.js.map +1 -1
  367. package/dist/factories/kubernetes/networking/service.d.ts.map +1 -1
  368. package/dist/factories/kubernetes/networking/service.js +6 -1
  369. package/dist/factories/kubernetes/networking/service.js.map +1 -1
  370. package/dist/factories/kubernetes/rbac/cluster-role-binding.d.ts.map +1 -1
  371. package/dist/factories/kubernetes/rbac/cluster-role-binding.js +1 -1
  372. package/dist/factories/kubernetes/rbac/cluster-role-binding.js.map +1 -1
  373. package/dist/factories/kubernetes/rbac/cluster-role.d.ts.map +1 -1
  374. package/dist/factories/kubernetes/rbac/cluster-role.js +1 -1
  375. package/dist/factories/kubernetes/rbac/cluster-role.js.map +1 -1
  376. package/dist/factories/kubernetes/scheduling/priority-class.d.ts.map +1 -1
  377. package/dist/factories/kubernetes/scheduling/priority-class.js +1 -1
  378. package/dist/factories/kubernetes/scheduling/priority-class.js.map +1 -1
  379. package/dist/factories/kubernetes/storage/storage-class.d.ts.map +1 -1
  380. package/dist/factories/kubernetes/storage/storage-class.js +1 -1
  381. package/dist/factories/kubernetes/storage/storage-class.js.map +1 -1
  382. package/dist/factories/kubernetes/workloads/deployment.d.ts.map +1 -1
  383. package/dist/factories/kubernetes/workloads/deployment.js +9 -4
  384. package/dist/factories/kubernetes/workloads/deployment.js.map +1 -1
  385. package/dist/factories/kubernetes/yaml/yaml-directory.js +2 -2
  386. package/dist/factories/kubernetes/yaml/yaml-directory.js.map +1 -1
  387. package/dist/factories/kubernetes/yaml/yaml-file.d.ts +31 -1
  388. package/dist/factories/kubernetes/yaml/yaml-file.d.ts.map +1 -1
  389. package/dist/factories/kubernetes/yaml/yaml-file.js +80 -7
  390. package/dist/factories/kubernetes/yaml/yaml-file.js.map +1 -1
  391. package/dist/factories/pebble/compositions/index.d.ts +2 -0
  392. package/dist/factories/pebble/compositions/index.d.ts.map +1 -0
  393. package/dist/factories/pebble/compositions/index.js +3 -0
  394. package/dist/factories/pebble/compositions/index.js.map +1 -0
  395. package/dist/factories/pebble/compositions/pebble-bootstrap.d.ts +56 -0
  396. package/dist/factories/pebble/compositions/pebble-bootstrap.d.ts.map +1 -0
  397. package/dist/factories/pebble/compositions/pebble-bootstrap.js +97 -0
  398. package/dist/factories/pebble/compositions/pebble-bootstrap.js.map +1 -0
  399. package/dist/factories/pebble/index.d.ts +10 -0
  400. package/dist/factories/pebble/index.d.ts.map +1 -0
  401. package/dist/factories/pebble/index.js +19 -0
  402. package/dist/factories/pebble/index.js.map +1 -0
  403. package/dist/factories/pebble/resources/helm.d.ts +99 -0
  404. package/dist/factories/pebble/resources/helm.d.ts.map +1 -0
  405. package/dist/factories/pebble/resources/helm.js +167 -0
  406. package/dist/factories/pebble/resources/helm.js.map +1 -0
  407. package/dist/factories/pebble/resources/index.d.ts +2 -0
  408. package/dist/factories/pebble/resources/index.d.ts.map +1 -0
  409. package/dist/factories/pebble/resources/index.js +3 -0
  410. package/dist/factories/pebble/resources/index.js.map +1 -0
  411. package/dist/factories/pebble/types.d.ts +184 -0
  412. package/dist/factories/pebble/types.d.ts.map +1 -0
  413. package/dist/factories/pebble/types.js +23 -0
  414. package/dist/factories/pebble/types.js.map +1 -0
  415. package/dist/factories/pebble/utils/helm-values-mapper.d.ts +21 -0
  416. package/dist/factories/pebble/utils/helm-values-mapper.d.ts.map +1 -0
  417. package/dist/factories/pebble/utils/helm-values-mapper.js +96 -0
  418. package/dist/factories/pebble/utils/helm-values-mapper.js.map +1 -0
  419. package/dist/factories/shared.d.ts +18 -1
  420. package/dist/factories/shared.d.ts.map +1 -1
  421. package/dist/factories/shared.js +89 -8
  422. package/dist/factories/shared.js.map +1 -1
  423. package/dist/factories/simple/config/config-map.d.ts +7 -2
  424. package/dist/factories/simple/config/config-map.d.ts.map +1 -1
  425. package/dist/factories/simple/config/config-map.js +3 -0
  426. package/dist/factories/simple/config/config-map.js.map +1 -1
  427. package/dist/factories/simple/config/secret.d.ts +11 -2
  428. package/dist/factories/simple/config/secret.d.ts.map +1 -1
  429. package/dist/factories/simple/config/secret.js +23 -1
  430. package/dist/factories/simple/config/secret.js.map +1 -1
  431. package/dist/factories/simple/storage/persistent-volume-claim.d.ts.map +1 -1
  432. package/dist/factories/simple/storage/persistent-volume-claim.js +1 -0
  433. package/dist/factories/simple/storage/persistent-volume-claim.js.map +1 -1
  434. package/dist/factories/simple/types.d.ts +5 -1
  435. package/dist/factories/simple/types.d.ts.map +1 -1
  436. package/dist/utils/helpers.d.ts.map +1 -1
  437. package/dist/utils/helpers.js +67 -0
  438. package/dist/utils/helpers.js.map +1 -1
  439. package/dist/utils/type-guards.d.ts +5 -0
  440. package/dist/utils/type-guards.d.ts.map +1 -1
  441. package/dist/utils/type-guards.js +9 -3
  442. package/dist/utils/type-guards.js.map +1 -1
  443. package/package.json +49 -5
@@ -4,13 +4,13 @@
4
4
  * Orchestrates the deployment of Kubernetes resources directly to a cluster
5
5
  * without requiring the Kro controller, using in-process dependency resolution.
6
6
  */
7
- import * as k8s from '@kubernetes/client-node';
8
7
  import { ensureReadinessEvaluator } from '../../utils/helpers.js';
9
8
  import { DependencyResolver } from '../dependencies/index.js';
10
9
  import { CircularDependencyError } from '../errors.js';
10
+ import { createBunCompatibleKubernetesObjectApi } from '../kubernetes/index.js';
11
11
  import { getComponentLogger } from '../logging/index.js';
12
12
  import { DeploymentMode, ReferenceResolver } from '../references/index.js';
13
- import { ResourceDeploymentError } from '../types/deployment.js';
13
+ import { ResourceDeploymentError, ResourceConflictError, UnsupportedMediaTypeError } from '../types/deployment.js';
14
14
  import { createDebugLoggerFromDeploymentOptions } from './debug-logger.js';
15
15
  import { ResourceReadinessChecker } from './readiness.js';
16
16
  import { StatusHydrator } from './status-hydrator.js';
@@ -27,6 +27,7 @@ export class DirectDeploymentEngine {
27
27
  eventMonitor;
28
28
  deploymentState = new Map();
29
29
  readyResources = new Set(); // Track resources that are already ready
30
+ activeAbortControllers = new Set(); // Track active abort controllers for cleanup
30
31
  logger = getComponentLogger('deployment-engine');
31
32
  constructor(kubeClient, k8sApi, referenceResolver, deploymentMode = DeploymentMode.DIRECT) {
32
33
  this.kubeClient = kubeClient;
@@ -34,7 +35,9 @@ export class DirectDeploymentEngine {
34
35
  this.dependencyResolver = new DependencyResolver();
35
36
  this.referenceResolver =
36
37
  referenceResolver || new ReferenceResolver(kubeClient, this.deploymentMode, k8sApi);
37
- this.k8sApi = k8sApi || kubeClient.makeApiClient(k8s.KubernetesObjectApi);
38
+ // Use createBunCompatibleKubernetesObjectApi which handles both Bun and Node.js
39
+ // This works around Bun's fetch TLS issues (https://github.com/oven-sh/bun/issues/10642)
40
+ this.k8sApi = k8sApi || createBunCompatibleKubernetesObjectApi(kubeClient);
38
41
  this.readinessChecker = new ResourceReadinessChecker(this.k8sApi);
39
42
  this.statusHydrator = new StatusHydrator(this.k8sApi);
40
43
  // this.eventFilter = createEventFilter();
@@ -48,6 +51,94 @@ export class DirectDeploymentEngine {
48
51
  });
49
52
  });
50
53
  }
54
+ /**
55
+ * Create an abortable delay that can be cancelled via AbortSignal
56
+ * @param ms - Delay in milliseconds
57
+ * @param signal - Optional AbortSignal to cancel the delay
58
+ * @returns Promise that resolves after the delay or rejects if aborted
59
+ */
60
+ abortableDelay(ms, signal) {
61
+ return new Promise((resolve, reject) => {
62
+ if (signal?.aborted) {
63
+ reject(new DOMException('Delay aborted', 'AbortError'));
64
+ return;
65
+ }
66
+ const timeoutId = setTimeout(() => {
67
+ resolve();
68
+ }, ms);
69
+ signal?.addEventListener('abort', () => {
70
+ clearTimeout(timeoutId);
71
+ reject(new DOMException('Delay aborted', 'AbortError'));
72
+ }, { once: true });
73
+ });
74
+ }
75
+ /**
76
+ * Wrap an async operation with abort signal handling
77
+ * If the signal is aborted, the promise will reject with AbortError
78
+ * Note: This doesn't actually cancel the underlying operation, but it allows
79
+ * the caller to stop waiting for it and handle the abort gracefully
80
+ * @param operation - The async operation to wrap
81
+ * @param signal - Optional AbortSignal to cancel the wait
82
+ * @returns Promise that resolves with the operation result or rejects if aborted
83
+ */
84
+ async withAbortSignal(operation, signal) {
85
+ if (!signal) {
86
+ return operation;
87
+ }
88
+ if (signal.aborted) {
89
+ throw new DOMException('Operation aborted', 'AbortError');
90
+ }
91
+ return new Promise((resolve, reject) => {
92
+ const abortHandler = () => {
93
+ reject(new DOMException('Operation aborted', 'AbortError'));
94
+ };
95
+ signal.addEventListener('abort', abortHandler, { once: true });
96
+ operation
97
+ .then((result) => {
98
+ signal.removeEventListener('abort', abortHandler);
99
+ resolve(result);
100
+ })
101
+ .catch((error) => {
102
+ signal.removeEventListener('abort', abortHandler);
103
+ // If the signal was aborted, throw AbortError instead of the original error
104
+ if (signal.aborted) {
105
+ reject(new DOMException('Operation aborted', 'AbortError'));
106
+ }
107
+ else {
108
+ reject(error);
109
+ }
110
+ });
111
+ });
112
+ }
113
+ /**
114
+ * Create and track an AbortController for a deployment operation
115
+ * @returns AbortController that is tracked for cleanup
116
+ */
117
+ createTrackedAbortController() {
118
+ const controller = new AbortController();
119
+ this.activeAbortControllers.add(controller);
120
+ return controller;
121
+ }
122
+ /**
123
+ * Remove an AbortController from tracking
124
+ * @param controller - The AbortController to remove
125
+ */
126
+ removeTrackedAbortController(controller) {
127
+ this.activeAbortControllers.delete(controller);
128
+ }
129
+ /**
130
+ * Abort all active operations and clean up
131
+ * This is called when a deployment times out or is cancelled
132
+ */
133
+ abortAllOperations() {
134
+ this.logger.debug('Aborting all active operations', {
135
+ activeControllers: this.activeAbortControllers.size,
136
+ });
137
+ for (const controller of this.activeAbortControllers) {
138
+ controller.abort();
139
+ }
140
+ this.activeAbortControllers.clear();
141
+ }
51
142
  /**
52
143
  * Get the Kubernetes API client for external integrations
53
144
  * @returns The configured KubernetesObjectApi instance
@@ -55,6 +146,41 @@ export class DirectDeploymentEngine {
55
146
  getKubernetesApi() {
56
147
  return this.k8sApi;
57
148
  }
149
+ /**
150
+ * Enhance a resource for evaluation by applying kind-specific logic
151
+ * This allows generic evaluators to work correctly without needing special cases
152
+ */
153
+ enhanceResourceForEvaluation(resource, kind) {
154
+ // For HelmRepository resources, handle OCI special case
155
+ if (kind === 'HelmRepository') {
156
+ const spec = resource.spec;
157
+ const isOciRepository = spec?.type === 'oci';
158
+ const hasBeenProcessed = resource.metadata?.generation && resource.metadata?.resourceVersion;
159
+ // If it's an OCI repo without Ready condition, synthesize one
160
+ // OCI repositories don't get status conditions from Flux, but they are functional
161
+ // once they've been processed (have generation and resourceVersion)
162
+ if (isOciRepository &&
163
+ hasBeenProcessed &&
164
+ !resource.status?.conditions?.some((c) => c.type === 'Ready')) {
165
+ return {
166
+ ...resource,
167
+ status: {
168
+ ...resource.status,
169
+ conditions: [
170
+ ...(resource.status?.conditions || []),
171
+ {
172
+ type: 'Ready',
173
+ status: 'True',
174
+ message: 'OCI repository is functional',
175
+ reason: 'OciRepositoryProcessed',
176
+ },
177
+ ],
178
+ },
179
+ };
180
+ }
181
+ }
182
+ return resource;
183
+ }
58
184
  /**
59
185
  * Check if a deployed resource is ready using the factory-provided readiness evaluator
60
186
  */
@@ -75,9 +201,12 @@ export class DirectDeploymentEngine {
75
201
  },
76
202
  };
77
203
  // Get the live resource from the cluster
204
+ // In the new API, methods return objects directly (no .body wrapper)
78
205
  const liveResource = await this.k8sApi.read(resourceRef);
206
+ // Apply kind-specific enhancements before calling custom evaluator
207
+ const enhancedResource = this.enhanceResourceForEvaluation(liveResource, deployedResource.kind);
79
208
  // Use the factory-provided readiness evaluator
80
- const result = readinessEvaluator(liveResource.body);
209
+ const result = readinessEvaluator(enhancedResource);
81
210
  let readinessResult;
82
211
  if (typeof result === 'boolean') {
83
212
  readinessResult = { ready: result };
@@ -108,8 +237,9 @@ export class DirectDeploymentEngine {
108
237
  namespace: deployedResource.namespace,
109
238
  },
110
239
  };
240
+ // In the new API, methods return objects directly (no .body wrapper)
111
241
  const liveResource = await this.k8sApi.read(resourceRef);
112
- return this.readinessChecker.isResourceReady(liveResource.body);
242
+ return this.readinessChecker.isResourceReady(liveResource);
113
243
  }
114
244
  }
115
245
  catch (error) {
@@ -136,6 +266,18 @@ export class DirectDeploymentEngine {
136
266
  const deploymentId = this.generateDeploymentId();
137
267
  const startTime = Date.now();
138
268
  const deployedResources = [];
269
+ // Create an AbortController for this deployment to enable proper cancellation
270
+ const deploymentAbortController = this.createTrackedAbortController();
271
+ const abortSignal = deploymentAbortController.signal;
272
+ // Set up timeout-based abort if timeout is specified
273
+ const timeout = options.timeout || 300000; // 5 minutes default
274
+ const timeoutId = setTimeout(() => {
275
+ this.logger.debug('Deployment timeout reached, aborting operations', {
276
+ deploymentId,
277
+ timeout,
278
+ });
279
+ deploymentAbortController.abort();
280
+ }, timeout);
139
281
  const errors = [];
140
282
  const deploymentLogger = this.logger.child({
141
283
  deploymentId,
@@ -185,10 +327,31 @@ export class DirectDeploymentEngine {
185
327
  this.readinessChecker.setDebugLogger(this.debugLogger);
186
328
  deploymentLogger.debug('Debug logging initialized');
187
329
  }
188
- // 4. Create resolution context
330
+ // 4. Create resolution context with resourceKeyMapping for cross-resource references
331
+ // The resourceKeyMapping maps original resource IDs (like 'webappDeployment') to their manifests
332
+ // This allows the reference resolver to find resources by their original IDs during deployment
333
+ const resourceKeyMapping = new Map();
334
+ for (const resource of graph.resources) {
335
+ const manifest = resource.manifest;
336
+ const originalResourceId = manifest.__resourceId;
337
+ if (originalResourceId) {
338
+ // Convert the Enhanced proxy to a plain object for reliable field extraction
339
+ // The proxy's toJSON method returns a clean object without proxy behavior
340
+ const plainManifest = typeof manifest.toJSON === 'function'
341
+ ? manifest.toJSON()
342
+ : JSON.parse(JSON.stringify(manifest));
343
+ resourceKeyMapping.set(originalResourceId, plainManifest);
344
+ deploymentLogger.debug('Added resource to resourceKeyMapping', {
345
+ originalResourceId,
346
+ kind: manifest.kind,
347
+ name: manifest.metadata?.name,
348
+ });
349
+ }
350
+ }
189
351
  const context = {
190
352
  deployedResources,
191
353
  kubeClient: this.kubeClient,
354
+ resourceKeyMapping,
192
355
  ...(options.namespace && { namespace: options.namespace }),
193
356
  timeout: options.timeout || 30000,
194
357
  };
@@ -232,7 +395,7 @@ export class DirectDeploymentEngine {
232
395
  try {
233
396
  resourceLogger.debug('Calling deploySingleResource');
234
397
  // Wait for CRD establishment if this is a custom resource
235
- await this.waitForCRDIfCustomResource(resource.manifest, options, resourceLogger);
398
+ await this.waitForCRDIfCustomResource(resource.manifest, options, resourceLogger, abortSignal);
236
399
  // FIX: Unconditionally ensure the readiness evaluator is attached just before deployment.
237
400
  const resourceWithEvaluator = ensureReadinessEvaluator(resource.manifest);
238
401
  // Add resource to event monitoring before deployment to capture creation events
@@ -254,7 +417,7 @@ export class DirectDeploymentEngine {
254
417
  resourceLogger.warn('Failed to add resource to event monitoring, continuing deployment', error);
255
418
  }
256
419
  }
257
- const deployedResource = await this.deploySingleResource(resourceWithEvaluator, context, options);
420
+ const deployedResource = await this.deploySingleResource(resourceWithEvaluator, context, options, abortSignal);
258
421
  resourceLogger.debug('Resource deployed successfully');
259
422
  return {
260
423
  success: true,
@@ -296,6 +459,37 @@ export class DirectDeploymentEngine {
296
459
  const deploymentResult = result.value;
297
460
  if (deploymentResult.success && deploymentResult.deployedResource) {
298
461
  deployedResources.push(deploymentResult.deployedResource);
462
+ // Update resourceKeyMapping with the live resource from the cluster (including status)
463
+ // This is critical for CEL expression evaluation which needs access to resource status
464
+ const deployedRes = deploymentResult.deployedResource;
465
+ const manifestWithId = deployedRes.manifest;
466
+ const originalResourceId = manifestWithId.__resourceId;
467
+ if (originalResourceId && resourceKeyMapping.has(originalResourceId)) {
468
+ try {
469
+ // Query the live resource from the cluster to get its current status
470
+ const liveResource = await this.k8sApi.read({
471
+ apiVersion: deployedRes.manifest.apiVersion || '',
472
+ kind: deployedRes.kind,
473
+ metadata: {
474
+ name: deployedRes.name,
475
+ namespace: deployedRes.namespace,
476
+ },
477
+ });
478
+ resourceKeyMapping.set(originalResourceId, liveResource);
479
+ deploymentLogger.debug('Updated resourceKeyMapping with live resource status', {
480
+ originalResourceId,
481
+ kind: deployedRes.kind,
482
+ name: deployedRes.name,
483
+ hasStatus: !!liveResource.status,
484
+ });
485
+ }
486
+ catch (error) {
487
+ deploymentLogger.warn('Failed to update resourceKeyMapping with live resource', {
488
+ originalResourceId,
489
+ error: error instanceof Error ? error.message : String(error),
490
+ });
491
+ }
492
+ }
299
493
  }
300
494
  else {
301
495
  levelHasFailures = true;
@@ -378,6 +572,9 @@ export class DirectDeploymentEngine {
378
572
  deploymentLogger.warn('Failed to stop event monitoring cleanly', error);
379
573
  }
380
574
  }
575
+ // Clean up abort controller and timeout
576
+ clearTimeout(timeoutId);
577
+ this.removeTrackedAbortController(deploymentAbortController);
381
578
  // Store deployment state for rollback
382
579
  this.deploymentState.set(deploymentId, {
383
580
  deploymentId,
@@ -400,8 +597,14 @@ export class DirectDeploymentEngine {
400
597
  catch (error) {
401
598
  // Re-throw circular dependency errors immediately - these are configuration errors
402
599
  if (error instanceof CircularDependencyError) {
600
+ // Clean up abort controller and timeout before re-throwing
601
+ clearTimeout(timeoutId);
602
+ this.removeTrackedAbortController(deploymentAbortController);
403
603
  throw error;
404
604
  }
605
+ // Clean up abort controller and timeout
606
+ clearTimeout(timeoutId);
607
+ this.removeTrackedAbortController(deploymentAbortController);
405
608
  const duration = Date.now() - startTime;
406
609
  this.emitEvent(options, {
407
610
  type: 'failed',
@@ -556,6 +759,18 @@ export class DirectDeploymentEngine {
556
759
  resourceCount: graph.resources.length,
557
760
  closureCount: Object.keys(closures).length,
558
761
  });
762
+ // Create an AbortController for this deployment to enable proper cancellation
763
+ const deploymentAbortController = this.createTrackedAbortController();
764
+ const abortSignal = deploymentAbortController.signal;
765
+ // Set up timeout-based abort if timeout is specified
766
+ const timeout = options.timeout || 300000; // 5 minutes default
767
+ const timeoutId = setTimeout(() => {
768
+ deploymentLogger.debug('Deployment timeout reached, aborting operations', {
769
+ deploymentId,
770
+ timeout,
771
+ });
772
+ deploymentAbortController.abort();
773
+ }, timeout);
559
774
  deploymentLogger.info('Starting deployment with closures', {
560
775
  options,
561
776
  closures: Object.keys(closures),
@@ -588,10 +803,30 @@ export class DirectDeploymentEngine {
588
803
  totalClosures: enhancedPlan.totalClosures,
589
804
  maxParallelism: enhancedPlan.maxParallelism,
590
805
  });
591
- // 4. Create resolution context
806
+ // 4. Create resolution context with resourceKeyMapping for cross-resource references
807
+ // The resourceKeyMapping maps original resource IDs (like 'webappDeployment') to their manifests
808
+ const resourceKeyMapping = new Map();
809
+ for (const resource of graph.resources) {
810
+ const manifest = resource.manifest;
811
+ const originalResourceId = manifest.__resourceId;
812
+ if (originalResourceId) {
813
+ // Convert the Enhanced proxy to a plain object for reliable field extraction
814
+ // The proxy's toJSON method returns a clean object without proxy behavior
815
+ const plainManifest = typeof manifest.toJSON === 'function'
816
+ ? manifest.toJSON()
817
+ : JSON.parse(JSON.stringify(manifest));
818
+ resourceKeyMapping.set(originalResourceId, plainManifest);
819
+ deploymentLogger.debug('Added resource to resourceKeyMapping', {
820
+ originalResourceId,
821
+ kind: manifest.kind,
822
+ name: manifest.metadata?.name,
823
+ });
824
+ }
825
+ }
592
826
  const context = {
593
827
  deployedResources,
594
828
  kubeClient: this.kubeClient,
829
+ resourceKeyMapping,
595
830
  ...(options.namespace && { namespace: options.namespace }),
596
831
  timeout: options.timeout || 30000,
597
832
  };
@@ -652,8 +887,10 @@ export class DirectDeploymentEngine {
652
887
  });
653
888
  try {
654
889
  resourceLogger.debug('Calling deploySingleResource');
890
+ // Wait for CRD establishment if this is a custom resource
891
+ await this.waitForCRDIfCustomResource(resource.manifest, options, resourceLogger, abortSignal);
655
892
  const resourceWithEvaluator = ensureReadinessEvaluator(resource.manifest);
656
- const deployedResource = await this.deploySingleResource(resourceWithEvaluator, context, options);
893
+ const deployedResource = await this.deploySingleResource(resourceWithEvaluator, context, options, abortSignal);
657
894
  resourceLogger.debug('Resource deployed successfully');
658
895
  return {
659
896
  success: true,
@@ -748,6 +985,37 @@ export class DirectDeploymentEngine {
748
985
  if (deploymentResult.success && deploymentResult.deployedResource) {
749
986
  deployedResources.push(deploymentResult.deployedResource);
750
987
  successfulResources++;
988
+ // Update resourceKeyMapping with the live resource from the cluster (including status)
989
+ // This is critical for CEL expression evaluation which needs access to resource status
990
+ const deployedRes = deploymentResult.deployedResource;
991
+ const manifestWithId = deployedRes.manifest;
992
+ const originalResourceId = manifestWithId.__resourceId;
993
+ if (originalResourceId && resourceKeyMapping.has(originalResourceId)) {
994
+ try {
995
+ // Query the live resource from the cluster to get its current status
996
+ const liveResource = await this.k8sApi.read({
997
+ apiVersion: deployedRes.manifest.apiVersion || '',
998
+ kind: deployedRes.kind,
999
+ metadata: {
1000
+ name: deployedRes.name,
1001
+ namespace: deployedRes.namespace,
1002
+ },
1003
+ });
1004
+ resourceKeyMapping.set(originalResourceId, liveResource);
1005
+ deploymentLogger.debug('Updated resourceKeyMapping with live resource status', {
1006
+ originalResourceId,
1007
+ kind: deployedRes.kind,
1008
+ name: deployedRes.name,
1009
+ hasStatus: !!liveResource.status,
1010
+ });
1011
+ }
1012
+ catch (error) {
1013
+ deploymentLogger.warn('Failed to update resourceKeyMapping with live resource', {
1014
+ originalResourceId,
1015
+ error: error instanceof Error ? error.message : String(error),
1016
+ });
1017
+ }
1018
+ }
751
1019
  }
752
1020
  else {
753
1021
  levelHasFailures = true;
@@ -816,6 +1084,9 @@ export class DirectDeploymentEngine {
816
1084
  message: `Deployment with closures ${status} in ${duration}ms (${enhancedPlan.totalClosures} closures + ${enhancedPlan.totalResources} resources across ${enhancedPlan.levels.length} levels)`,
817
1085
  timestamp: new Date(),
818
1086
  });
1087
+ // Clean up abort controller and timeout
1088
+ clearTimeout(timeoutId);
1089
+ this.removeTrackedAbortController(deploymentAbortController);
819
1090
  // Store deployment state for rollback
820
1091
  this.deploymentState.set(deploymentId, {
821
1092
  deploymentId,
@@ -838,8 +1109,14 @@ export class DirectDeploymentEngine {
838
1109
  catch (error) {
839
1110
  // Re-throw circular dependency errors immediately - these are configuration errors
840
1111
  if (error instanceof CircularDependencyError) {
1112
+ // Clean up abort controller and timeout before re-throwing
1113
+ clearTimeout(timeoutId);
1114
+ this.removeTrackedAbortController(deploymentAbortController);
841
1115
  throw error;
842
1116
  }
1117
+ // Clean up abort controller and timeout
1118
+ clearTimeout(timeoutId);
1119
+ this.removeTrackedAbortController(deploymentAbortController);
843
1120
  const duration = Date.now() - startTime;
844
1121
  this.emitEvent(options, {
845
1122
  type: 'failed',
@@ -877,8 +1154,14 @@ export class DirectDeploymentEngine {
877
1154
 
878
1155
  * Deploy a single resource
879
1156
  */
880
- async deploySingleResource(resource, context, options) {
881
- const resourceId = resource.id || resource.__resourceId || resource.metadata?.name || 'unknown';
1157
+ async deploySingleResource(resource, context, options, abortSignal) {
1158
+ // Check if already aborted
1159
+ if (abortSignal?.aborted) {
1160
+ throw new DOMException('Operation aborted', 'AbortError');
1161
+ }
1162
+ // __resourceId is an internal field that may be set during resource processing
1163
+ const resourceWithInternalId = resource;
1164
+ const resourceId = resource.id || resourceWithInternalId.__resourceId || resource.metadata?.name || 'unknown';
882
1165
  const resourceLogger = this.logger.child({
883
1166
  resourceId,
884
1167
  kind: resource.kind,
@@ -902,13 +1185,25 @@ export class DirectDeploymentEngine {
902
1185
  this.referenceResolver.resolveReferences(resource, context),
903
1186
  new Promise((_, reject) => setTimeout(() => reject(new Error('Reference resolution timeout')), resolveTimeout)),
904
1187
  ]));
1188
+ // Check for readinessEvaluator which may be on Enhanced resources
1189
+ const enhancedResource = resolvedResource;
905
1190
  resourceLogger.debug('References resolved successfully', {
906
1191
  resolvedMetadata: resolvedResource.metadata,
907
- hasReadinessEvaluator: !!resolvedResource.readinessEvaluator,
1192
+ hasReadinessEvaluator: !!enhancedResource.readinessEvaluator,
908
1193
  });
909
1194
  }
910
1195
  catch (error) {
911
- resourceLogger.warn('Reference resolution failed, using original resource', error);
1196
+ // In Alchemy deployments, resourceKeyMapping is often empty because resources are deployed
1197
+ // one at a time. This is expected behavior, so we log at debug level instead of warn.
1198
+ const hasResourceKeyMapping = context.resourceKeyMapping && context.resourceKeyMapping.size > 0;
1199
+ if (hasResourceKeyMapping) {
1200
+ resourceLogger.warn('Reference resolution failed, using original resource', error);
1201
+ }
1202
+ else {
1203
+ resourceLogger.debug('Reference resolution skipped (no resourceKeyMapping), using original resource', {
1204
+ error: error.message,
1205
+ });
1206
+ }
912
1207
  resolvedResource = resource;
913
1208
  }
914
1209
  // 2. Apply namespace if specified, but only if resource doesn't already have one
@@ -931,7 +1226,8 @@ export class DirectDeploymentEngine {
931
1226
  metadata: newMetadata,
932
1227
  };
933
1228
  // Copy the non-enumerable readiness evaluator if it exists
934
- const readinessEvaluator = resolvedResource.readinessEvaluator;
1229
+ const resourceWithEvaluator = resolvedResource;
1230
+ const readinessEvaluator = resourceWithEvaluator.readinessEvaluator;
935
1231
  if (readinessEvaluator) {
936
1232
  Object.defineProperty(newResolvedResource, 'readinessEvaluator', {
937
1233
  value: readinessEvaluator,
@@ -940,6 +1236,16 @@ export class DirectDeploymentEngine {
940
1236
  writable: false,
941
1237
  });
942
1238
  }
1239
+ // Copy the non-enumerable __resourceId if it exists (used for cross-resource references)
1240
+ const originalResourceId = resourceWithEvaluator.__resourceId;
1241
+ if (originalResourceId) {
1242
+ Object.defineProperty(newResolvedResource, '__resourceId', {
1243
+ value: originalResourceId,
1244
+ enumerable: false,
1245
+ configurable: true,
1246
+ writable: false,
1247
+ });
1248
+ }
943
1249
  resolvedResource = newResolvedResource;
944
1250
  }
945
1251
  // 3. Apply the resource to the cluster (or simulate for dry run)
@@ -970,7 +1276,8 @@ export class DirectDeploymentEngine {
970
1276
  // Check if resource already exists
971
1277
  let existing;
972
1278
  try {
973
- const readResult = await this.k8sApi.read({
1279
+ // In the new API, methods return objects directly (no .body wrapper)
1280
+ existing = await this.k8sApi.read({
974
1281
  apiVersion: resolvedResource.apiVersion,
975
1282
  kind: resolvedResource.kind,
976
1283
  metadata: {
@@ -978,26 +1285,109 @@ export class DirectDeploymentEngine {
978
1285
  namespace: resolvedResource.metadata?.namespace || 'default',
979
1286
  },
980
1287
  });
981
- existing = readResult.body;
982
1288
  }
983
1289
  catch (error) {
984
1290
  // If it's a 404, the resource doesn't exist, which is expected for creation
985
- if (error.statusCode !== 404) {
986
- resourceLogger.error('Error checking resource existence', error);
1291
+ const apiError = error;
1292
+ // Check for 404 in various error formats:
1293
+ // - apiError.statusCode (direct property)
1294
+ // - apiError.response?.statusCode (nested response)
1295
+ // - apiError.body?.code (body code)
1296
+ // - error message containing "HTTP-Code: 404"
1297
+ const is404 = apiError.statusCode === 404 ||
1298
+ apiError.response?.statusCode === 404 ||
1299
+ apiError.body?.code === 404 ||
1300
+ (typeof apiError.message === 'string' && apiError.message.includes('HTTP-Code: 404'));
1301
+ if (!is404) {
1302
+ // Also check for "Unrecognized API version and kind" errors - these indicate
1303
+ // the CRD is not installed yet, which should trigger CRD waiting logic
1304
+ const isUnrecognizedApiError = typeof apiError.message === 'string' &&
1305
+ apiError.message.includes('Unrecognized API version and kind');
1306
+ if (isUnrecognizedApiError) {
1307
+ resourceLogger.debug('CRD not yet registered, will retry after CRD establishment', error);
1308
+ }
1309
+ else {
1310
+ resourceLogger.error('Error checking resource existence', error);
1311
+ }
987
1312
  throw error;
988
1313
  }
1314
+ // 404 means resource doesn't exist - this is expected, we'll create it below
989
1315
  }
990
1316
  if (existing) {
991
1317
  // Resource exists, use patch for safer updates
992
- resourceLogger.debug('Resource exists, patching');
993
- const patchResult = await this.k8sApi.patch(resolvedResource);
994
- appliedResource = patchResult.body;
1318
+ // Log the full resource being patched, including non-standard fields like 'data' for Secrets
1319
+ const patchPayload = {
1320
+ apiVersion: resolvedResource.apiVersion,
1321
+ kind: resolvedResource.kind,
1322
+ metadata: resolvedResource.metadata,
1323
+ };
1324
+ // Include spec if present (most resources)
1325
+ if (resolvedResource.spec !== undefined) {
1326
+ patchPayload.spec = resolvedResource.spec;
1327
+ }
1328
+ // Include data if present (Secrets)
1329
+ if (resolvedResource.data !== undefined) {
1330
+ patchPayload.data = resolvedResource.data;
1331
+ }
1332
+ // Include stringData if present (Secrets)
1333
+ if (resolvedResource.stringData !== undefined) {
1334
+ patchPayload.stringData = resolvedResource.stringData;
1335
+ }
1336
+ // Include rules if present (RBAC resources)
1337
+ if (resolvedResource.rules !== undefined) {
1338
+ // Ensure arrays are preserved (not converted to objects with numeric keys)
1339
+ const rules = resolvedResource.rules;
1340
+ patchPayload.rules = Array.isArray(rules) ? [...rules] : rules;
1341
+ }
1342
+ // Include subjects if present (ClusterRoleBinding, RoleBinding)
1343
+ if (resolvedResource.subjects !== undefined) {
1344
+ // Ensure arrays are preserved (not converted to objects with numeric keys)
1345
+ const subjects = resolvedResource.subjects;
1346
+ patchPayload.subjects = Array.isArray(subjects) ? [...subjects] : subjects;
1347
+ }
1348
+ // Include roleRef if present (ClusterRoleBinding, RoleBinding)
1349
+ if (resolvedResource.roleRef !== undefined) {
1350
+ patchPayload.roleRef = resolvedResource.roleRef;
1351
+ }
1352
+ // Explicitly call toJSON to ensure arrays are preserved via our custom toJSON implementation
1353
+ // Then use JSON.parse(JSON.stringify()) to ensure we have a plain object without proxies
1354
+ const jsonPayload = typeof resolvedResource.toJSON === 'function'
1355
+ ? resolvedResource.toJSON()
1356
+ : patchPayload;
1357
+ // Deep clone to remove any proxy wrappers that might cause serialization issues
1358
+ const cleanPayload = JSON.parse(JSON.stringify(jsonPayload));
1359
+ // Strip internal TypeKro fields that should not be sent to Kubernetes
1360
+ // The 'id' field is used internally for resource mapping but is not a valid K8s field
1361
+ delete cleanPayload.id;
1362
+ resourceLogger.debug('Resource exists, patching', { patchPayload: cleanPayload });
1363
+ // In the new API, methods return objects directly (no .body wrapper)
1364
+ appliedResource = await this.patchResourceWithCorrectContentType(cleanPayload);
995
1365
  }
996
1366
  else {
997
1367
  // Resource does not exist, create it
998
1368
  resourceLogger.debug('Resource does not exist, creating');
999
- const createResult = await this.k8sApi.create(resolvedResource);
1000
- appliedResource = createResult.body;
1369
+ // DEBUG: Log the resource being created for Secrets
1370
+ if (resolvedResource.kind === 'Secret') {
1371
+ resourceLogger.debug('Creating Secret resource', {
1372
+ name: resolvedResource.metadata?.name,
1373
+ hasData: 'data' in resolvedResource,
1374
+ hasSpec: 'spec' in resolvedResource,
1375
+ dataKeys: resolvedResource.data ? Object.keys(resolvedResource.data) : [],
1376
+ specValue: resolvedResource.spec,
1377
+ });
1378
+ }
1379
+ // Explicitly call toJSON to ensure arrays are preserved via our custom toJSON implementation
1380
+ // Then use JSON.parse(JSON.stringify()) to ensure we have a plain object without proxies
1381
+ const jsonResource = typeof resolvedResource.toJSON === 'function'
1382
+ ? resolvedResource.toJSON()
1383
+ : resolvedResource;
1384
+ // Deep clone to remove any proxy wrappers that might cause serialization issues
1385
+ const cleanResource = JSON.parse(JSON.stringify(jsonResource));
1386
+ // Strip internal TypeKro fields that should not be sent to Kubernetes
1387
+ // The 'id' field is used internally for resource mapping but is not a valid K8s field
1388
+ delete cleanResource.id;
1389
+ // In the new API, methods return objects directly (no .body wrapper)
1390
+ appliedResource = await this.k8sApi.create(cleanResource);
1001
1391
  }
1002
1392
  resourceLogger.debug('Resource applied successfully', {
1003
1393
  appliedName: appliedResource.metadata?.name,
@@ -1010,7 +1400,121 @@ export class DirectDeploymentEngine {
1010
1400
  }
1011
1401
  catch (error) {
1012
1402
  lastError = error;
1403
+ // Check for 409 Conflict errors - resource already exists
1404
+ const apiError = error;
1405
+ const is409 = apiError.statusCode === 409 ||
1406
+ apiError.response?.statusCode === 409 ||
1407
+ apiError.body?.code === 409 ||
1408
+ (typeof apiError.message === 'string' && apiError.message.includes('HTTP-Code: 409'));
1409
+ if (is409) {
1410
+ const conflictStrategy = options.conflictStrategy || 'warn';
1411
+ const resourceName = resolvedResource.metadata?.name || 'unknown';
1412
+ const resourceKind = resolvedResource.kind || 'Unknown';
1413
+ const resourceNamespace = resolvedResource.metadata?.namespace;
1414
+ let conflictHandled = false;
1415
+ resourceLogger.debug('Resource already exists (409)', {
1416
+ name: resourceName,
1417
+ kind: resourceKind,
1418
+ conflictStrategy,
1419
+ });
1420
+ // Handle based on conflict strategy
1421
+ switch (conflictStrategy) {
1422
+ case 'fail':
1423
+ // Throw error immediately - don't retry
1424
+ throw new ResourceConflictError(resourceName, resourceKind, resourceNamespace);
1425
+ case 'warn':
1426
+ // Log warning and treat as success - fetch existing resource
1427
+ resourceLogger.warn('Resource already exists, treating as success', {
1428
+ name: resourceName,
1429
+ kind: resourceKind,
1430
+ namespace: resourceNamespace,
1431
+ });
1432
+ try {
1433
+ // Fetch the existing resource to return it
1434
+ appliedResource = await this.k8sApi.read({
1435
+ apiVersion: resolvedResource.apiVersion,
1436
+ kind: resolvedResource.kind,
1437
+ metadata: {
1438
+ name: resourceName,
1439
+ namespace: resourceNamespace || 'default',
1440
+ },
1441
+ });
1442
+ conflictHandled = true;
1443
+ }
1444
+ catch (readError) {
1445
+ resourceLogger.warn('Failed to read existing resource after 409, falling back to patch', readError);
1446
+ // Fall back to patch strategy
1447
+ try {
1448
+ const jsonResource = typeof resolvedResource.toJSON === 'function'
1449
+ ? resolvedResource.toJSON()
1450
+ : resolvedResource;
1451
+ const cleanResource = JSON.parse(JSON.stringify(jsonResource));
1452
+ delete cleanResource.id;
1453
+ appliedResource = await this.patchResourceWithCorrectContentType(cleanResource);
1454
+ resourceLogger.debug('Resource patched successfully after 409 conflict (warn fallback)');
1455
+ conflictHandled = true;
1456
+ }
1457
+ catch (patchError) {
1458
+ resourceLogger.warn('Failed to patch resource after 409 conflict', patchError);
1459
+ }
1460
+ }
1461
+ break;
1462
+ case 'patch':
1463
+ // Attempt to patch the existing resource
1464
+ try {
1465
+ const jsonResource = typeof resolvedResource.toJSON === 'function'
1466
+ ? resolvedResource.toJSON()
1467
+ : resolvedResource;
1468
+ const cleanResource = JSON.parse(JSON.stringify(jsonResource));
1469
+ delete cleanResource.id;
1470
+ appliedResource = await this.patchResourceWithCorrectContentType(cleanResource);
1471
+ resourceLogger.debug('Resource patched successfully after 409 conflict');
1472
+ conflictHandled = true;
1473
+ }
1474
+ catch (patchError) {
1475
+ resourceLogger.warn('Failed to patch resource after 409 conflict', patchError);
1476
+ }
1477
+ break;
1478
+ case 'replace':
1479
+ // Delete and recreate the resource
1480
+ try {
1481
+ resourceLogger.debug('Deleting existing resource for replace strategy');
1482
+ await this.k8sApi.delete({
1483
+ apiVersion: resolvedResource.apiVersion,
1484
+ kind: resolvedResource.kind,
1485
+ metadata: {
1486
+ name: resourceName,
1487
+ namespace: resourceNamespace || 'default',
1488
+ },
1489
+ });
1490
+ // Wait a moment for deletion to propagate
1491
+ await new Promise((resolve) => setTimeout(resolve, 500));
1492
+ // Create the new resource
1493
+ const jsonResource = typeof resolvedResource.toJSON === 'function'
1494
+ ? resolvedResource.toJSON()
1495
+ : resolvedResource;
1496
+ const cleanResource = JSON.parse(JSON.stringify(jsonResource));
1497
+ delete cleanResource.id;
1498
+ appliedResource = await this.k8sApi.create(cleanResource);
1499
+ resourceLogger.debug('Resource replaced successfully after 409 conflict');
1500
+ conflictHandled = true;
1501
+ }
1502
+ catch (replaceError) {
1503
+ resourceLogger.warn('Failed to replace resource after 409 conflict', replaceError);
1504
+ }
1505
+ break;
1506
+ }
1507
+ // If we successfully handled the conflict, break out of retry loop
1508
+ if (conflictHandled) {
1509
+ break;
1510
+ }
1511
+ }
1013
1512
  resourceLogger.error('Failed to apply resource to cluster', lastError, { attempt });
1513
+ // Check for HTTP 415 Unsupported Media Type errors
1514
+ if (this.isUnsupportedMediaTypeError(error)) {
1515
+ const acceptedTypes = this.extractAcceptedMediaTypes(error);
1516
+ throw new UnsupportedMediaTypeError(resolvedResource.metadata?.name || 'unknown', resolvedResource.kind || 'Unknown', acceptedTypes, lastError);
1517
+ }
1014
1518
  // If this was the last attempt, throw the error
1015
1519
  if (attempt >= retryPolicy.maxRetries) {
1016
1520
  throw new ResourceDeploymentError(resolvedResource.metadata?.name || 'unknown', resolvedResource.kind || 'Unknown', lastError);
@@ -1040,7 +1544,7 @@ export class DirectDeploymentEngine {
1040
1544
  // 5. Wait for resource to be ready if requested
1041
1545
  if (options.waitForReady !== false) {
1042
1546
  resourceLogger.debug('Waiting for resource to be ready');
1043
- await this.waitForResourceReady(deployedResource, options);
1547
+ await this.waitForResourceReady(deployedResource, options, abortSignal);
1044
1548
  deployedResource.status = 'ready';
1045
1549
  }
1046
1550
  resourceLogger.debug('Single resource deployment completed');
@@ -1048,16 +1552,23 @@ export class DirectDeploymentEngine {
1048
1552
  }
1049
1553
  /**
1050
1554
  * Wait for a resource to be ready
1555
+ * @param deployedResource - The deployed resource to wait for
1556
+ * @param options - Deployment options
1557
+ * @param abortSignal - Optional AbortSignal to cancel the wait
1051
1558
  */
1052
- async waitForResourceReady(deployedResource, options) {
1559
+ async waitForResourceReady(deployedResource, options, abortSignal) {
1053
1560
  const resourceKey = `${deployedResource.kind}/${deployedResource.name}/${deployedResource.namespace}`;
1054
1561
  // Check if already marked as ready
1055
1562
  if (deployedResource.status === 'ready' || this.readyResources.has(resourceKey)) {
1056
1563
  this.logger.debug('Resource already marked as ready', { resourceKey });
1057
1564
  return;
1058
1565
  }
1059
- // Safety-first approach: check for readiness evaluator before starting the wait loop
1060
- const readinessEvaluator = deployedResource.manifest.readinessEvaluator;
1566
+ // Check if already aborted
1567
+ if (abortSignal?.aborted) {
1568
+ throw new DOMException('Operation aborted', 'AbortError');
1569
+ }
1570
+ const enhancedManifest = deployedResource.manifest;
1571
+ const readinessEvaluator = enhancedManifest.readinessEvaluator;
1061
1572
  // Debug logging removed
1062
1573
  if (!readinessEvaluator) {
1063
1574
  const errorMessage = `Resource ${deployedResource.kind}/${deployedResource.name} does not have a factory-provided readiness evaluator`;
@@ -1068,17 +1579,25 @@ export class DirectDeploymentEngine {
1068
1579
  const timeout = options.timeout || 300000; // 5 minutes default
1069
1580
  let lastStatus = null;
1070
1581
  while (Date.now() - startTime < timeout) {
1582
+ // Check if aborted before each iteration
1583
+ if (abortSignal?.aborted) {
1584
+ throw new DOMException('Operation aborted', 'AbortError');
1585
+ }
1071
1586
  try {
1072
1587
  // Use custom readiness evaluator
1073
- const { body: liveResource } = await this.k8sApi.read({
1588
+ // In the new API, methods return objects directly (no .body wrapper)
1589
+ // Wrap with abort signal handling to stop waiting if aborted
1590
+ const liveResource = await this.withAbortSignal(this.k8sApi.read({
1074
1591
  apiVersion: deployedResource.manifest.apiVersion || '',
1075
1592
  kind: deployedResource.kind,
1076
1593
  metadata: {
1077
1594
  name: deployedResource.name,
1078
1595
  namespace: deployedResource.namespace,
1079
1596
  },
1080
- });
1081
- const result = readinessEvaluator(liveResource);
1597
+ }), abortSignal);
1598
+ // Apply kind-specific enhancements before calling custom evaluator
1599
+ const enhancedResource = this.enhanceResourceForEvaluation(liveResource, deployedResource.kind);
1600
+ const result = readinessEvaluator(enhancedResource);
1082
1601
  if (typeof result === 'boolean') {
1083
1602
  if (result) {
1084
1603
  this.readyResources.add(resourceKey);
@@ -1114,10 +1633,22 @@ export class DirectDeploymentEngine {
1114
1633
  timestamp: new Date(),
1115
1634
  });
1116
1635
  }
1117
- // Wait before next check
1118
- await new Promise((resolve) => setTimeout(resolve, 2000));
1636
+ // Wait before next check - use abortable delay
1637
+ try {
1638
+ await this.abortableDelay(2000, abortSignal);
1639
+ }
1640
+ catch (error) {
1641
+ if (error instanceof DOMException && (error.name === 'AbortError' || error.name === 'TimeoutError')) {
1642
+ throw error; // Re-throw abort/timeout errors
1643
+ }
1644
+ // Ignore other errors from delay
1645
+ }
1119
1646
  }
1120
1647
  catch (error) {
1648
+ // Re-throw abort/timeout errors immediately
1649
+ if (error instanceof DOMException && (error.name === 'AbortError' || error.name === 'TimeoutError')) {
1650
+ throw error;
1651
+ }
1121
1652
  // Emit error status event
1122
1653
  this.emitEvent(options, {
1123
1654
  type: 'resource-status',
@@ -1125,8 +1656,16 @@ export class DirectDeploymentEngine {
1125
1656
  message: `Unable to read resource status: ${error instanceof Error ? error.message : String(error)}`,
1126
1657
  timestamp: new Date(),
1127
1658
  });
1128
- // If we can't read the resource, it's not ready yet
1129
- await new Promise((resolve) => setTimeout(resolve, 2000));
1659
+ // If we can't read the resource, it's not ready yet - use abortable delay
1660
+ try {
1661
+ await this.abortableDelay(2000, abortSignal);
1662
+ }
1663
+ catch (delayError) {
1664
+ if (delayError instanceof DOMException && (delayError.name === 'AbortError' || delayError.name === 'TimeoutError')) {
1665
+ throw delayError; // Re-throw abort/timeout errors
1666
+ }
1667
+ // Ignore other errors from delay
1668
+ }
1130
1669
  }
1131
1670
  }
1132
1671
  // Timeout reached
@@ -1206,7 +1745,8 @@ export class DirectDeploymentEngine {
1206
1745
  ...(options.namespace && { namespace: options.namespace }),
1207
1746
  timeout: options.timeout || 30000,
1208
1747
  };
1209
- return this.deploySingleResource(resource, context, options);
1748
+ // Legacy method - no abort signal support
1749
+ return this.deploySingleResource(resource, context, options, undefined);
1210
1750
  }
1211
1751
  /**
1212
1752
  * Delete a resource from the cluster
@@ -1262,7 +1802,8 @@ export class DirectDeploymentEngine {
1262
1802
  * Wait for resource readiness (legacy method for compatibility)
1263
1803
  */
1264
1804
  async waitForResourceReadiness(resource, options) {
1265
- return this.waitForResourceReady(resource, options);
1805
+ // Legacy method - no abort signal support
1806
+ return this.waitForResourceReady(resource, options, undefined);
1266
1807
  }
1267
1808
  /**
1268
1809
  * Rollback a deployment by ID
@@ -1331,6 +1872,33 @@ export class DirectDeploymentEngine {
1331
1872
  }
1332
1873
  return result;
1333
1874
  }
1875
+ /**
1876
+ * Patch a resource with the correct Content-Type header for merge patch operations
1877
+ * This fixes HTTP 415 "Unsupported Media Type" errors that occur when using the generic patch method
1878
+ * In the new API, methods return objects directly (no .body wrapper)
1879
+ */
1880
+ async patchResourceWithCorrectContentType(resource) {
1881
+ // DEBUG: Log the resource being sent to K8s API for Secrets
1882
+ if (resource.kind === 'Secret') {
1883
+ const secretResource = resource;
1884
+ this.logger.debug('Patching Secret resource', {
1885
+ name: resource.metadata?.name,
1886
+ hasData: 'data' in resource,
1887
+ hasSpec: 'spec' in resource,
1888
+ dataKeys: secretResource.data ? Object.keys(secretResource.data) : [],
1889
+ specValue: secretResource.spec,
1890
+ });
1891
+ }
1892
+ // The k8sApi.patch method requires the full content-type string for the patchStrategy parameter
1893
+ // Use 'application/merge-patch+json' for merge patch operations
1894
+ // See: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
1895
+ return await this.k8sApi.patch(resource, undefined, // pretty
1896
+ undefined, // dryRun
1897
+ undefined, // fieldManager
1898
+ undefined, // force
1899
+ 'application/merge-patch+json' // patchStrategy - must be the full content-type string
1900
+ );
1901
+ }
1334
1902
  /**
1335
1903
  * Check if an error is a "not found" error
1336
1904
  */
@@ -1344,7 +1912,11 @@ export class DirectDeploymentEngine {
1344
1912
  /**
1345
1913
  * Wait for CRD establishment if the resource is a custom resource
1346
1914
  */
1347
- async waitForCRDIfCustomResource(resource, options, logger) {
1915
+ async waitForCRDIfCustomResource(resource, options, logger, abortSignal) {
1916
+ // Check if already aborted
1917
+ if (abortSignal?.aborted) {
1918
+ throw new DOMException('Operation aborted', 'AbortError');
1919
+ }
1348
1920
  // Skip if this is not a custom resource
1349
1921
  if (!this.isCustomResource(resource)) {
1350
1922
  return;
@@ -1361,7 +1933,7 @@ export class DirectDeploymentEngine {
1361
1933
  resourceKind: resource.kind,
1362
1934
  crdName,
1363
1935
  });
1364
- await this.waitForCRDEstablishment({ metadata: { name: crdName } }, options, logger);
1936
+ await this.waitForCRDEstablishment({ metadata: { name: crdName } }, options, logger, abortSignal);
1365
1937
  logger.debug('CRD established, proceeding with custom resource deployment', {
1366
1938
  resourceKind: resource.kind,
1367
1939
  crdName,
@@ -1422,12 +1994,14 @@ export class DirectDeploymentEngine {
1422
1994
  // Try to find the CRD by querying the API
1423
1995
  const crds = await this.k8sApi.list('apiextensions.k8s.io/v1', 'CustomResourceDefinition');
1424
1996
  // Look for a CRD that matches our group and kind
1425
- const matchingCrd = crds.body?.items?.find((crd) => {
1997
+ // In the new API, methods return objects directly (no .body wrapper)
1998
+ const crdList = crds;
1999
+ const matchingCrd = crdList?.items?.find((crd) => {
1426
2000
  const crdSpec = crd.spec;
1427
2001
  return crdSpec?.group === group && crdSpec?.names?.kind === resource.kind;
1428
2002
  });
1429
2003
  if (matchingCrd) {
1430
- return matchingCrd.metadata?.name;
2004
+ return matchingCrd.metadata?.name ?? null;
1431
2005
  }
1432
2006
  }
1433
2007
  catch (error) {
@@ -1442,32 +2016,39 @@ export class DirectDeploymentEngine {
1442
2016
  /**
1443
2017
  * Public method to wait for CRD readiness by name
1444
2018
  */
1445
- async waitForCRDReady(crdName, timeout = 300000) {
2019
+ async waitForCRDReady(crdName, timeout = 300000, abortSignal) {
1446
2020
  const logger = this.logger.child({ crdName, timeout });
1447
2021
  const options = {
1448
2022
  mode: this.deploymentMode,
1449
2023
  timeout,
1450
2024
  };
1451
- await this.waitForCRDEstablishment({ metadata: { name: crdName } }, options, logger);
2025
+ await this.waitForCRDEstablishment({ metadata: { name: crdName } }, options, logger, abortSignal);
1452
2026
  }
1453
2027
  /**
1454
2028
  * Wait for a CRD to be established in the cluster
1455
2029
  */
1456
- async waitForCRDEstablishment(crd, options, logger) {
2030
+ async waitForCRDEstablishment(crd, options, logger, abortSignal) {
1457
2031
  const crdName = crd.metadata?.name;
1458
2032
  const timeout = options.timeout || 300000; // 5 minutes default
1459
2033
  const startTime = Date.now();
1460
2034
  const pollInterval = 2000; // 2 seconds
1461
2035
  logger.debug('Waiting for CRD to exist and be established', { crdName, timeout });
1462
2036
  while (Date.now() - startTime < timeout) {
2037
+ // Check if aborted before each iteration
2038
+ if (abortSignal?.aborted) {
2039
+ throw new DOMException('Operation aborted', 'AbortError');
2040
+ }
1463
2041
  try {
1464
2042
  // Check if CRD is established by reading its status
1465
- const crdStatus = await this.k8sApi.read({
2043
+ // Wrap with abort signal handling
2044
+ const crdStatus = await this.withAbortSignal(this.k8sApi.read({
1466
2045
  apiVersion: 'apiextensions.k8s.io/v1',
1467
2046
  kind: 'CustomResourceDefinition',
1468
2047
  metadata: { name: crdName }, // CRDs are cluster-scoped, no namespace needed
1469
- });
1470
- const conditions = crdStatus.body?.status?.conditions || [];
2048
+ }), abortSignal);
2049
+ // In the new API, methods return objects directly (no .body wrapper)
2050
+ const crdItem = crdStatus;
2051
+ const conditions = crdItem?.status?.conditions || [];
1471
2052
  const establishedCondition = conditions.find((c) => c.type === 'Established');
1472
2053
  if (establishedCondition?.status === 'True') {
1473
2054
  logger.debug('CRD exists and is established', { crdName });
@@ -1479,6 +2060,10 @@ export class DirectDeploymentEngine {
1479
2060
  });
1480
2061
  }
1481
2062
  catch (error) {
2063
+ // Re-throw abort/timeout errors immediately
2064
+ if (error instanceof DOMException && (error.name === 'AbortError' || error.name === 'TimeoutError')) {
2065
+ throw error;
2066
+ }
1482
2067
  // CRD might not exist yet (e.g., being installed by a closure)
1483
2068
  // This is expected in scenarios where closures install CRDs
1484
2069
  logger.debug('CRD not found yet, waiting for it to be created...', {
@@ -1486,11 +2071,54 @@ export class DirectDeploymentEngine {
1486
2071
  error: error.message,
1487
2072
  });
1488
2073
  }
1489
- // Wait before next poll
1490
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
2074
+ // Wait before next poll - use abortable delay
2075
+ try {
2076
+ await this.abortableDelay(pollInterval, abortSignal);
2077
+ }
2078
+ catch (error) {
2079
+ if (error instanceof DOMException && (error.name === 'AbortError' || error.name === 'TimeoutError')) {
2080
+ throw error; // Re-throw abort/timeout errors
2081
+ }
2082
+ // Ignore other errors from delay
2083
+ }
1491
2084
  }
1492
2085
  // Timeout reached
1493
2086
  throw new Error(`Timeout waiting for CRD ${crdName} to be established after ${timeout}ms`);
1494
2087
  }
2088
+ /**
2089
+ * Check if an error is an HTTP 415 Unsupported Media Type error
2090
+ */
2091
+ isUnsupportedMediaTypeError(error) {
2092
+ if (!error || typeof error !== 'object') {
2093
+ return false;
2094
+ }
2095
+ const apiError = error;
2096
+ return (apiError.statusCode === 415 ||
2097
+ apiError.response?.statusCode === 415 ||
2098
+ apiError.body?.code === 415);
2099
+ }
2100
+ /**
2101
+ * Extract accepted media types from HTTP 415 error message
2102
+ */
2103
+ extractAcceptedMediaTypes(error) {
2104
+ const defaultTypes = [
2105
+ 'application/json-patch+json',
2106
+ 'application/merge-patch+json',
2107
+ 'application/apply-patch+yaml',
2108
+ ];
2109
+ try {
2110
+ // Try to extract from error message
2111
+ const apiError = error;
2112
+ const message = apiError.message || apiError.body?.message || '';
2113
+ const match = message.match(/accepted media types include: ([^"]+)/);
2114
+ if (match && match[1]) {
2115
+ return match[1].split(', ').map((type) => type.trim());
2116
+ }
2117
+ }
2118
+ catch (_e) {
2119
+ // Fallback to default types
2120
+ }
2121
+ return defaultTypes;
2122
+ }
1495
2123
  }
1496
2124
  //# sourceMappingURL=engine.js.map