typekro 0.33.9 → 0.34.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 (352) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/compositions/typekro-runtime/typekro-runtime.d.ts +0 -33
  3. package/dist/compositions/typekro-runtime/typekro-runtime.d.ts.map +1 -1
  4. package/dist/compositions/typekro-runtime/typekro-runtime.js +63 -1
  5. package/dist/compositions/typekro-runtime/typekro-runtime.js.map +1 -1
  6. package/dist/compositions/typekro-runtime/types.d.ts +8 -0
  7. package/dist/compositions/typekro-runtime/types.d.ts.map +1 -1
  8. package/dist/compositions/typekro-runtime/types.js +1 -0
  9. package/dist/compositions/typekro-runtime/types.js.map +1 -1
  10. package/dist/core/aspects/values-merge.d.ts +17 -0
  11. package/dist/core/aspects/values-merge.d.ts.map +1 -1
  12. package/dist/core/aspects/values-merge.js +67 -8
  13. package/dist/core/aspects/values-merge.js.map +1 -1
  14. package/dist/core/deployment/direct-factory.d.ts +9 -0
  15. package/dist/core/deployment/direct-factory.d.ts.map +1 -1
  16. package/dist/core/deployment/direct-factory.js +37 -3
  17. package/dist/core/deployment/direct-factory.js.map +1 -1
  18. package/dist/core/deployment/engine.d.ts +34 -0
  19. package/dist/core/deployment/engine.d.ts.map +1 -1
  20. package/dist/core/deployment/engine.js +173 -29
  21. package/dist/core/deployment/engine.js.map +1 -1
  22. package/dist/core/deployment/index.d.ts +2 -0
  23. package/dist/core/deployment/index.d.ts.map +1 -1
  24. package/dist/core/deployment/index.js +1 -0
  25. package/dist/core/deployment/index.js.map +1 -1
  26. package/dist/core/deployment/k8s-helpers.d.ts +73 -0
  27. package/dist/core/deployment/k8s-helpers.d.ts.map +1 -1
  28. package/dist/core/deployment/k8s-helpers.js +198 -4
  29. package/dist/core/deployment/k8s-helpers.js.map +1 -1
  30. package/dist/core/deployment/kro-factory.d.ts.map +1 -1
  31. package/dist/core/deployment/kro-factory.js +21 -1
  32. package/dist/core/deployment/kro-factory.js.map +1 -1
  33. package/dist/core/deployment/status-leaf-resolution.d.ts +101 -0
  34. package/dist/core/deployment/status-leaf-resolution.d.ts.map +1 -0
  35. package/dist/core/deployment/status-leaf-resolution.js +232 -0
  36. package/dist/core/deployment/status-leaf-resolution.js.map +1 -0
  37. package/dist/core/deployment/strategies/base-strategy.d.ts.map +1 -1
  38. package/dist/core/deployment/strategies/base-strategy.js +31 -3
  39. package/dist/core/deployment/strategies/base-strategy.js.map +1 -1
  40. package/dist/core/deployment/strategies/kro-strategy.d.ts.map +1 -1
  41. package/dist/core/deployment/strategies/kro-strategy.js +8 -1
  42. package/dist/core/deployment/strategies/kro-strategy.js.map +1 -1
  43. package/dist/core/expressions/composition/composition-analyzer-helpers.d.ts.map +1 -1
  44. package/dist/core/expressions/composition/composition-analyzer-helpers.js +20 -2
  45. package/dist/core/expressions/composition/composition-analyzer-helpers.js.map +1 -1
  46. package/dist/core/kro/index.d.ts +6 -0
  47. package/dist/core/kro/index.d.ts.map +1 -0
  48. package/dist/core/kro/index.js +6 -0
  49. package/dist/core/kro/index.js.map +1 -0
  50. package/dist/core/kro/label-guard-capability.d.ts +141 -0
  51. package/dist/core/kro/label-guard-capability.d.ts.map +1 -0
  52. package/dist/core/kro/label-guard-capability.js +257 -0
  53. package/dist/core/kro/label-guard-capability.js.map +1 -0
  54. package/dist/core/kro/labels.d.ts +56 -0
  55. package/dist/core/kro/labels.d.ts.map +1 -0
  56. package/dist/core/kro/labels.js +62 -0
  57. package/dist/core/kro/labels.js.map +1 -0
  58. package/dist/core/kubernetes/api-capability.d.ts +196 -0
  59. package/dist/core/kubernetes/api-capability.d.ts.map +1 -0
  60. package/dist/core/kubernetes/api-capability.js +301 -0
  61. package/dist/core/kubernetes/api-capability.js.map +1 -0
  62. package/dist/core/kubernetes/index.d.ts +2 -0
  63. package/dist/core/kubernetes/index.d.ts.map +1 -1
  64. package/dist/core/kubernetes/index.js +2 -0
  65. package/dist/core/kubernetes/index.js.map +1 -1
  66. package/dist/core/kubernetes/naming.d.ts +100 -0
  67. package/dist/core/kubernetes/naming.d.ts.map +1 -0
  68. package/dist/core/kubernetes/naming.js +93 -0
  69. package/dist/core/kubernetes/naming.js.map +1 -0
  70. package/dist/core/planning/direct-runtime-adapter.d.ts.map +1 -1
  71. package/dist/core/planning/direct-runtime-adapter.js +54 -17
  72. package/dist/core/planning/direct-runtime-adapter.js.map +1 -1
  73. package/dist/core/planning/planner.d.ts.map +1 -1
  74. package/dist/core/planning/planner.js +17 -0
  75. package/dist/core/planning/planner.js.map +1 -1
  76. package/dist/core/planning/schema.d.ts.map +1 -1
  77. package/dist/core/planning/schema.js +7 -3
  78. package/dist/core/planning/schema.js.map +1 -1
  79. package/dist/core/references/cel-lexical-scanner.d.ts +100 -1
  80. package/dist/core/references/cel-lexical-scanner.d.ts.map +1 -1
  81. package/dist/core/references/cel-lexical-scanner.js +196 -2
  82. package/dist/core/references/cel-lexical-scanner.js.map +1 -1
  83. package/dist/core/references/cel.d.ts +249 -1
  84. package/dist/core/references/cel.d.ts.map +1 -1
  85. package/dist/core/references/cel.js +289 -8
  86. package/dist/core/references/cel.js.map +1 -1
  87. package/dist/core/serialization/arktype-ast.d.ts +21 -0
  88. package/dist/core/serialization/arktype-ast.d.ts.map +1 -0
  89. package/dist/core/serialization/arktype-ast.js +29 -0
  90. package/dist/core/serialization/arktype-ast.js.map +1 -0
  91. package/dist/core/serialization/cel-references.d.ts +133 -32
  92. package/dist/core/serialization/cel-references.d.ts.map +1 -1
  93. package/dist/core/serialization/cel-references.js +908 -109
  94. package/dist/core/serialization/cel-references.js.map +1 -1
  95. package/dist/core/serialization/core.d.ts.map +1 -1
  96. package/dist/core/serialization/core.js +13 -2
  97. package/dist/core/serialization/core.js.map +1 -1
  98. package/dist/core/serialization/schema.d.ts +16 -2
  99. package/dist/core/serialization/schema.d.ts.map +1 -1
  100. package/dist/core/serialization/schema.js +113 -21
  101. package/dist/core/serialization/schema.js.map +1 -1
  102. package/dist/core/types/composable.d.ts +7 -1
  103. package/dist/core/types/composable.d.ts.map +1 -1
  104. package/dist/core/types/deployment.d.ts +32 -2
  105. package/dist/core/types/deployment.d.ts.map +1 -1
  106. package/dist/core/types/serialization.d.ts +37 -0
  107. package/dist/core/types/serialization.d.ts.map +1 -1
  108. package/dist/core/validation/cel-dialect.d.ts +246 -0
  109. package/dist/core/validation/cel-dialect.d.ts.map +1 -0
  110. package/dist/core/validation/cel-dialect.js +1997 -0
  111. package/dist/core/validation/cel-dialect.js.map +1 -0
  112. package/dist/core/validation/cel-validator.d.ts.map +1 -1
  113. package/dist/core/validation/cel-validator.js +8 -1
  114. package/dist/core/validation/cel-validator.js.map +1 -1
  115. package/dist/core/validation/literal-status.d.ts +107 -0
  116. package/dist/core/validation/literal-status.d.ts.map +1 -0
  117. package/dist/core/validation/literal-status.js +346 -0
  118. package/dist/core/validation/literal-status.js.map +1 -0
  119. package/dist/core/validation/structural-spec-dependence.d.ts +179 -0
  120. package/dist/core/validation/structural-spec-dependence.d.ts.map +1 -0
  121. package/dist/core/validation/structural-spec-dependence.js +911 -0
  122. package/dist/core/validation/structural-spec-dependence.js.map +1 -0
  123. package/dist/factories/apisix/compositions/apisix-bootstrap.d.ts.map +1 -1
  124. package/dist/factories/apisix/compositions/apisix-bootstrap.js +9 -0
  125. package/dist/factories/apisix/compositions/apisix-bootstrap.js.map +1 -1
  126. package/dist/factories/clickhouse/compositions/clickhouse-cluster.d.ts +6 -0
  127. package/dist/factories/clickhouse/compositions/clickhouse-cluster.d.ts.map +1 -1
  128. package/dist/factories/clickhouse/compositions/clickhouse-cluster.js +273 -23
  129. package/dist/factories/clickhouse/compositions/clickhouse-cluster.js.map +1 -1
  130. package/dist/factories/clickhouse/resources/index.d.ts +1 -0
  131. package/dist/factories/clickhouse/resources/index.d.ts.map +1 -1
  132. package/dist/factories/clickhouse/resources/index.js +1 -0
  133. package/dist/factories/clickhouse/resources/index.js.map +1 -1
  134. package/dist/factories/clickhouse/resources/installation.d.ts.map +1 -1
  135. package/dist/factories/clickhouse/resources/installation.js +31 -4
  136. package/dist/factories/clickhouse/resources/installation.js.map +1 -1
  137. package/dist/factories/clickhouse/resources/s3-backup.d.ts +215 -0
  138. package/dist/factories/clickhouse/resources/s3-backup.d.ts.map +1 -0
  139. package/dist/factories/clickhouse/resources/s3-backup.js +410 -0
  140. package/dist/factories/clickhouse/resources/s3-backup.js.map +1 -0
  141. package/dist/factories/clickhouse/types.d.ts +416 -20
  142. package/dist/factories/clickhouse/types.d.ts.map +1 -1
  143. package/dist/factories/clickhouse/types.js +235 -11
  144. package/dist/factories/clickhouse/types.js.map +1 -1
  145. package/dist/factories/clickhouse/utils/helm-values-mapper.d.ts +42 -0
  146. package/dist/factories/clickhouse/utils/helm-values-mapper.d.ts.map +1 -1
  147. package/dist/factories/clickhouse/utils/helm-values-mapper.js +48 -0
  148. package/dist/factories/clickhouse/utils/helm-values-mapper.js.map +1 -1
  149. package/dist/factories/clickhouse/utils/index.d.ts +2 -0
  150. package/dist/factories/clickhouse/utils/index.d.ts.map +1 -1
  151. package/dist/factories/clickhouse/utils/index.js +2 -0
  152. package/dist/factories/clickhouse/utils/index.js.map +1 -1
  153. package/dist/factories/clickhouse/utils/s3-storage.d.ts +503 -0
  154. package/dist/factories/clickhouse/utils/s3-storage.d.ts.map +1 -0
  155. package/dist/factories/clickhouse/utils/s3-storage.js +1139 -0
  156. package/dist/factories/clickhouse/utils/s3-storage.js.map +1 -0
  157. package/dist/factories/clickhouse/utils/validation.d.ts +103 -0
  158. package/dist/factories/clickhouse/utils/validation.d.ts.map +1 -1
  159. package/dist/factories/clickhouse/utils/validation.js +129 -0
  160. package/dist/factories/clickhouse/utils/validation.js.map +1 -1
  161. package/dist/factories/clickhouse/utils/xml.d.ts +87 -0
  162. package/dist/factories/clickhouse/utils/xml.d.ts.map +1 -0
  163. package/dist/factories/clickhouse/utils/xml.js +151 -0
  164. package/dist/factories/clickhouse/utils/xml.js.map +1 -0
  165. package/dist/factories/clickstack/compositions/clickstack-bootstrap.d.ts +57 -0
  166. package/dist/factories/clickstack/compositions/clickstack-bootstrap.d.ts.map +1 -1
  167. package/dist/factories/clickstack/compositions/clickstack-bootstrap.js +266 -7
  168. package/dist/factories/clickstack/compositions/clickstack-bootstrap.js.map +1 -1
  169. package/dist/factories/clickstack/types.d.ts +205 -26
  170. package/dist/factories/clickstack/types.d.ts.map +1 -1
  171. package/dist/factories/clickstack/types.js +106 -8
  172. package/dist/factories/clickstack/types.js.map +1 -1
  173. package/dist/factories/clickstack/utils/collector-config.d.ts +104 -0
  174. package/dist/factories/clickstack/utils/collector-config.d.ts.map +1 -0
  175. package/dist/factories/clickstack/utils/collector-config.js +266 -0
  176. package/dist/factories/clickstack/utils/collector-config.js.map +1 -0
  177. package/dist/factories/clickstack/utils/helm-values-mapper.d.ts +26 -0
  178. package/dist/factories/clickstack/utils/helm-values-mapper.d.ts.map +1 -1
  179. package/dist/factories/clickstack/utils/helm-values-mapper.js +53 -12
  180. package/dist/factories/clickstack/utils/helm-values-mapper.js.map +1 -1
  181. package/dist/factories/clickstack/utils/index.d.ts +2 -0
  182. package/dist/factories/clickstack/utils/index.d.ts.map +1 -1
  183. package/dist/factories/clickstack/utils/index.js +2 -0
  184. package/dist/factories/clickstack/utils/index.js.map +1 -1
  185. package/dist/factories/clickstack/utils/storage.d.ts +449 -0
  186. package/dist/factories/clickstack/utils/storage.d.ts.map +1 -0
  187. package/dist/factories/clickstack/utils/storage.js +698 -0
  188. package/dist/factories/clickstack/utils/storage.js.map +1 -0
  189. package/dist/factories/cnpg/resources/helm.d.ts.map +1 -1
  190. package/dist/factories/cnpg/resources/helm.js +4 -4
  191. package/dist/factories/cnpg/resources/helm.js.map +1 -1
  192. package/dist/factories/cnpg/types.d.ts +10 -1
  193. package/dist/factories/cnpg/types.d.ts.map +1 -1
  194. package/dist/factories/cnpg/types.js.map +1 -1
  195. package/dist/factories/cnpg/utils/helm-values-mapper.d.ts +19 -2
  196. package/dist/factories/cnpg/utils/helm-values-mapper.d.ts.map +1 -1
  197. package/dist/factories/cnpg/utils/helm-values-mapper.js +22 -4
  198. package/dist/factories/cnpg/utils/helm-values-mapper.js.map +1 -1
  199. package/dist/factories/envoy-ai-gateway/compositions/gateway.d.ts.map +1 -1
  200. package/dist/factories/envoy-ai-gateway/compositions/gateway.js +16 -3
  201. package/dist/factories/envoy-ai-gateway/compositions/gateway.js.map +1 -1
  202. package/dist/factories/envoy-ai-gateway/constants.d.ts +5 -2
  203. package/dist/factories/envoy-ai-gateway/constants.d.ts.map +1 -1
  204. package/dist/factories/envoy-ai-gateway/constants.js +5 -2
  205. package/dist/factories/envoy-ai-gateway/constants.js.map +1 -1
  206. package/dist/factories/envoy-ai-gateway/resources/gateway.d.ts +12 -0
  207. package/dist/factories/envoy-ai-gateway/resources/gateway.d.ts.map +1 -1
  208. package/dist/factories/envoy-ai-gateway/resources/gateway.js +27 -104
  209. package/dist/factories/envoy-ai-gateway/resources/gateway.js.map +1 -1
  210. package/dist/factories/envoy-ai-gateway/types.d.ts +15 -47
  211. package/dist/factories/envoy-ai-gateway/types.d.ts.map +1 -1
  212. package/dist/factories/envoy-ai-gateway/types.js.map +1 -1
  213. package/dist/factories/gateway-api/constants.d.ts +27 -0
  214. package/dist/factories/gateway-api/constants.d.ts.map +1 -0
  215. package/dist/factories/gateway-api/constants.js +27 -0
  216. package/dist/factories/gateway-api/constants.js.map +1 -0
  217. package/dist/factories/gateway-api/index.d.ts +14 -0
  218. package/dist/factories/gateway-api/index.d.ts.map +1 -0
  219. package/dist/factories/gateway-api/index.js +14 -0
  220. package/dist/factories/gateway-api/index.js.map +1 -0
  221. package/dist/factories/gateway-api/readiness.d.ts +67 -0
  222. package/dist/factories/gateway-api/readiness.d.ts.map +1 -0
  223. package/dist/factories/gateway-api/readiness.js +213 -0
  224. package/dist/factories/gateway-api/readiness.js.map +1 -0
  225. package/dist/factories/gateway-api/resources/gateway.d.ts +91 -0
  226. package/dist/factories/gateway-api/resources/gateway.d.ts.map +1 -0
  227. package/dist/factories/gateway-api/resources/gateway.js +99 -0
  228. package/dist/factories/gateway-api/resources/gateway.js.map +1 -0
  229. package/dist/factories/gateway-api/resources/index.d.ts +2 -0
  230. package/dist/factories/gateway-api/resources/index.d.ts.map +1 -0
  231. package/dist/factories/gateway-api/resources/index.js +2 -0
  232. package/dist/factories/gateway-api/resources/index.js.map +1 -0
  233. package/dist/factories/gateway-api/types.d.ts +1269 -0
  234. package/dist/factories/gateway-api/types.d.ts.map +1 -0
  235. package/dist/factories/gateway-api/types.js +417 -0
  236. package/dist/factories/gateway-api/types.js.map +1 -0
  237. package/dist/factories/helm/readiness-evaluators.d.ts +21 -3
  238. package/dist/factories/helm/readiness-evaluators.d.ts.map +1 -1
  239. package/dist/factories/helm/readiness-evaluators.js +117 -11
  240. package/dist/factories/helm/readiness-evaluators.js.map +1 -1
  241. package/dist/factories/helm/types.d.ts +28 -0
  242. package/dist/factories/helm/types.d.ts.map +1 -1
  243. package/dist/factories/index.d.ts +2 -0
  244. package/dist/factories/index.d.ts.map +1 -1
  245. package/dist/factories/index.js +8 -0
  246. package/dist/factories/index.js.map +1 -1
  247. package/dist/factories/inngest/compositions/inngest-bootstrap.d.ts.map +1 -1
  248. package/dist/factories/inngest/compositions/inngest-bootstrap.js +10 -0
  249. package/dist/factories/inngest/compositions/inngest-bootstrap.js.map +1 -1
  250. package/dist/factories/kubernetes/admission/index.d.ts +2 -0
  251. package/dist/factories/kubernetes/admission/index.d.ts.map +1 -1
  252. package/dist/factories/kubernetes/admission/index.js +2 -0
  253. package/dist/factories/kubernetes/admission/index.js.map +1 -1
  254. package/dist/factories/kubernetes/admission/label-propagation-guard.d.ts +108 -0
  255. package/dist/factories/kubernetes/admission/label-propagation-guard.d.ts.map +1 -0
  256. package/dist/factories/kubernetes/admission/label-propagation-guard.js +247 -0
  257. package/dist/factories/kubernetes/admission/label-propagation-guard.js.map +1 -0
  258. package/dist/factories/kubernetes/admission/mutating-admission-policy.d.ts +286 -0
  259. package/dist/factories/kubernetes/admission/mutating-admission-policy.d.ts.map +1 -0
  260. package/dist/factories/kubernetes/admission/mutating-admission-policy.js +157 -0
  261. package/dist/factories/kubernetes/admission/mutating-admission-policy.js.map +1 -0
  262. package/dist/factories/opensearch/compositions/cluster.d.ts.map +1 -1
  263. package/dist/factories/opensearch/compositions/cluster.js +6 -1
  264. package/dist/factories/opensearch/compositions/cluster.js.map +1 -1
  265. package/dist/factories/ory/compositions/ory-identity-stack.d.ts +8 -8
  266. package/dist/factories/ory/types.d.ts +16 -16
  267. package/dist/factories/rook/compositions/object-storage-claim.d.ts +1 -1
  268. package/dist/factories/rook/compositions/rook-ceph-platform.js +8 -1
  269. package/dist/factories/rook/compositions/rook-ceph-platform.js.map +1 -1
  270. package/dist/factories/rook/types.d.ts +1 -1
  271. package/dist/factories/searxng/compositions/searxng-bootstrap.d.ts +1 -1
  272. package/dist/factories/searxng/compositions/searxng-bootstrap.d.ts.map +1 -1
  273. package/dist/factories/searxng/compositions/searxng-bootstrap.js +18 -13
  274. package/dist/factories/searxng/compositions/searxng-bootstrap.js.map +1 -1
  275. package/dist/factories/searxng/index.d.ts +3 -0
  276. package/dist/factories/searxng/index.d.ts.map +1 -1
  277. package/dist/factories/searxng/index.js +3 -0
  278. package/dist/factories/searxng/index.js.map +1 -1
  279. package/dist/factories/searxng/types.js +1 -1
  280. package/dist/factories/searxng/types.js.map +1 -1
  281. package/dist/factories/traefik/compositions/index.d.ts +6 -0
  282. package/dist/factories/traefik/compositions/index.d.ts.map +1 -0
  283. package/dist/factories/traefik/compositions/index.js +6 -0
  284. package/dist/factories/traefik/compositions/index.js.map +1 -0
  285. package/dist/factories/traefik/compositions/traefik-bootstrap.d.ts +185 -0
  286. package/dist/factories/traefik/compositions/traefik-bootstrap.d.ts.map +1 -0
  287. package/dist/factories/traefik/compositions/traefik-bootstrap.js +339 -0
  288. package/dist/factories/traefik/compositions/traefik-bootstrap.js.map +1 -0
  289. package/dist/factories/traefik/compositions/traefik-helm-repository.d.ts +16 -0
  290. package/dist/factories/traefik/compositions/traefik-helm-repository.d.ts.map +1 -0
  291. package/dist/factories/traefik/compositions/traefik-helm-repository.js +31 -0
  292. package/dist/factories/traefik/compositions/traefik-helm-repository.js.map +1 -0
  293. package/dist/factories/traefik/constants.d.ts +78 -0
  294. package/dist/factories/traefik/constants.d.ts.map +1 -0
  295. package/dist/factories/traefik/constants.js +104 -0
  296. package/dist/factories/traefik/constants.js.map +1 -0
  297. package/dist/factories/traefik/index.d.ts +25 -0
  298. package/dist/factories/traefik/index.d.ts.map +1 -0
  299. package/dist/factories/traefik/index.js +25 -0
  300. package/dist/factories/traefik/index.js.map +1 -0
  301. package/dist/factories/traefik/resources/common.d.ts +68 -0
  302. package/dist/factories/traefik/resources/common.d.ts.map +1 -0
  303. package/dist/factories/traefik/resources/common.js +59 -0
  304. package/dist/factories/traefik/resources/common.js.map +1 -0
  305. package/dist/factories/traefik/resources/gateway.d.ts +85 -0
  306. package/dist/factories/traefik/resources/gateway.d.ts.map +1 -0
  307. package/dist/factories/traefik/resources/gateway.js +109 -0
  308. package/dist/factories/traefik/resources/gateway.js.map +1 -0
  309. package/dist/factories/traefik/resources/helm.d.ts +56 -0
  310. package/dist/factories/traefik/resources/helm.d.ts.map +1 -0
  311. package/dist/factories/traefik/resources/helm.js +131 -0
  312. package/dist/factories/traefik/resources/helm.js.map +1 -0
  313. package/dist/factories/traefik/resources/index.d.ts +10 -0
  314. package/dist/factories/traefik/resources/index.d.ts.map +1 -0
  315. package/dist/factories/traefik/resources/index.js +10 -0
  316. package/dist/factories/traefik/resources/index.js.map +1 -0
  317. package/dist/factories/traefik/resources/middleware.d.ts +169 -0
  318. package/dist/factories/traefik/resources/middleware.d.ts.map +1 -0
  319. package/dist/factories/traefik/resources/middleware.js +225 -0
  320. package/dist/factories/traefik/resources/middleware.js.map +1 -0
  321. package/dist/factories/traefik/resources/routing.d.ts +113 -0
  322. package/dist/factories/traefik/resources/routing.d.ts.map +1 -0
  323. package/dist/factories/traefik/resources/routing.js +119 -0
  324. package/dist/factories/traefik/resources/routing.js.map +1 -0
  325. package/dist/factories/traefik/resources/tls.d.ts +85 -0
  326. package/dist/factories/traefik/resources/tls.d.ts.map +1 -0
  327. package/dist/factories/traefik/resources/tls.js +93 -0
  328. package/dist/factories/traefik/resources/tls.js.map +1 -0
  329. package/dist/factories/traefik/types.d.ts +2690 -0
  330. package/dist/factories/traefik/types.d.ts.map +1 -0
  331. package/dist/factories/traefik/types.js +1084 -0
  332. package/dist/factories/traefik/types.js.map +1 -0
  333. package/dist/factories/traefik/utils/helm-values-mapper.d.ts +198 -0
  334. package/dist/factories/traefik/utils/helm-values-mapper.d.ts.map +1 -0
  335. package/dist/factories/traefik/utils/helm-values-mapper.js +372 -0
  336. package/dist/factories/traefik/utils/helm-values-mapper.js.map +1 -0
  337. package/dist/factories/traefik/utils/index.d.ts +6 -0
  338. package/dist/factories/traefik/utils/index.d.ts.map +1 -0
  339. package/dist/factories/traefik/utils/index.js +6 -0
  340. package/dist/factories/traefik/utils/index.js.map +1 -0
  341. package/dist/factories/traefik/utils/middleware-validation.d.ts +42 -0
  342. package/dist/factories/traefik/utils/middleware-validation.d.ts.map +1 -0
  343. package/dist/factories/traefik/utils/middleware-validation.js +78 -0
  344. package/dist/factories/traefik/utils/middleware-validation.js.map +1 -0
  345. package/dist/factories/webapp/compositions/web-app-with-processing.d.ts.map +1 -1
  346. package/dist/factories/webapp/compositions/web-app-with-processing.js +10 -0
  347. package/dist/factories/webapp/compositions/web-app-with-processing.js.map +1 -1
  348. package/dist/index.d.ts +4 -3
  349. package/dist/index.d.ts.map +1 -1
  350. package/dist/index.js +3 -1
  351. package/dist/index.js.map +1 -1
  352. package/package.json +9 -1
@@ -0,0 +1,911 @@
1
+ /**
2
+ * Structural spec-dependence diagnostics.
3
+ *
4
+ * ## The rule
5
+ *
6
+ * A `ResourceGraphDefinition` is fixed at build time. `schema.spec.*` values
7
+ * are *runtime* references: KRO substitutes them per instance, long after the
8
+ * composition function has run. So a spec value may decide what a field
9
+ * **contains** (a value position), but it may never decide what the graph
10
+ * **looks like** — which resources exist, how many list entries there are, or
11
+ * what an object's keys are called (a structural position).
12
+ *
13
+ * When a composition puts a spec value in a structural position, the
14
+ * composition function still runs: the schema proxy hands the author a
15
+ * `KubernetesRef` and JavaScript does something plausible-but-wrong with it.
16
+ * An `if` takes the truthy branch because a proxy object is truthy. A `.map()`
17
+ * runs exactly once against a sentinel element. `Object.keys()` yields one
18
+ * fabricated key. The RGD that comes out is well-formed and silently encodes
19
+ * the build-time guess for every instance.
20
+ *
21
+ * This module turns that silence into a KRO-mode serialization error.
22
+ *
23
+ * ## What is detected
24
+ *
25
+ * Two independent detectors, deliberately narrow so that legitimate
26
+ * value-position uses (`replicas: spec.replicas`, `` url: `http://${spec.host}` ``,
27
+ * CEL ternaries in status) stay silent:
28
+ *
29
+ * 1. {@link scanRgdResourcesForStructuralSpecArtifacts} — reads the RGD that is
30
+ * about to be emitted and reports build-time residue that can only come from
31
+ * a structural use. This is evidence-based: every finding is a concrete
32
+ * artifact in the output, so there are no false positives by construction.
33
+ * - `spec-derived-key`: an object key (or resource id) that is a schema
34
+ * reference marker — `{ [spec.key]: v }`, or `Object.fromEntries(...)`
35
+ * over a spec collection.
36
+ * - `runtime-map-enumerated`: the `__typekroSchemaKey` sentinel, which the
37
+ * schema proxy hands out when a composition enumerates a
38
+ * `Record<string, V>` spec field (`Object.keys(spec.settings)`,
39
+ * `{ ...spec.settings }`) whose keys are not knowable until runtime.
40
+ * - `collection-length-collapsed`: a `$item` element sentinel surviving in
41
+ * a resource that carries no `forEach` dimension — a `.map()` / `for-of`
42
+ * over a spec collection that was flattened to a single element instead
43
+ * of being compiled to KRO's `forEach`. A backstop: the serializer
44
+ * normally rewrites `$item` either into a `forEach` loop variable or
45
+ * into a whole-array reference (`ports: ${schema.spec.ports}`), both of
46
+ * which are correct, so this catches only what those miss.
47
+ *
48
+ * 2. {@link detectStructuralSpecPredicates} — parses the composition source and
49
+ * reports branch predicates that are spec-derived in a form the control-flow
50
+ * analyzer cannot compile to `includeWhen`, so the branch was decided at
51
+ * build time:
52
+ * - `uncompiled-predicate`: the `if` / ternary test reaches the spec only
53
+ * through a local binding (`const enabled = spec.enabled; if (enabled)`,
54
+ * `const { enabled } = spec;`), so the analyzer's lexical `spec` check
55
+ * misses it and no `includeWhen` is attached.
56
+ * - `switch-discriminator`: a `switch` on a spec-derived discriminant.
57
+ * There is no `switch` lowering at all; the proxy matches no `case`, so
58
+ * `default` wins for every instance.
59
+ * - `collection-length-read`: `.length` on a spec-derived collection or
60
+ * string. The proxy always answers `1`, so the value is a build-time
61
+ * constant no matter what the instance holds.
62
+ *
63
+ * A branch only counts when it BUILDS something. That question is settled
64
+ * by an allowlist, not by the callee's name: nothing in the source says
65
+ * whether an imported binding is a factory, and casing least of all — most
66
+ * of this repo's factories are camelCase (`helmRelease`, `serviceAccount`,
67
+ * `persistentVolumeClaim`, `observedResource`, `singleton`). So any call in
68
+ * the branch counts as building structure unless it is a pure JavaScript
69
+ * builtin (`String(…)`, `JSON.stringify(…)`, `Math.max(…)`, `items.map(…)`)
70
+ * or a `Cel.*` runtime expression. See {@link isPureHelperCall}.
71
+ *
72
+ * ## What is NOT detected
73
+ *
74
+ * Static analysis of arbitrary JavaScript cannot be complete, and this check
75
+ * does not pretend otherwise. Known blind spots:
76
+ *
77
+ * - A predicate laundered through a **helper function** or a module-level
78
+ * constant: `if (isEnabled(spec))`. The alias resolver only walks
79
+ * top-level `const`/`let` bindings in the composition body.
80
+ * - A predicate on a value read back **out of a resource** rather than off
81
+ * the spec proxy.
82
+ * - Structure decided by a spec value that is **consumed by a factory** and
83
+ * collapsed inside it, if the collapse leaves no marker, sentinel or
84
+ * `$item` residue in the emitted RGD.
85
+ * - A branch whose only call is a **method named like a builtin**
86
+ * (`registry.push(…)`, `catalog.map(…)`): the pure-helper allowlist matches
87
+ * on the method name without resolving the receiver, so such a call is
88
+ * assumed pure. No factory in `src/factories/**` carries one of those
89
+ * names, and a new one must not.
90
+ * - Anything reached through `eval`, dynamic imports, or a composition whose
91
+ * source cannot be parsed (the AST detector degrades to silence, never to
92
+ * a false positive).
93
+ *
94
+ * Detector 1 is the backstop for most of these: however the structure was
95
+ * decided, if the decision left residue in the RGD it is reported.
96
+ */
97
+ import { Parser } from 'acorn';
98
+ import * as estraverse from 'estraverse';
99
+ import { TypeKroError } from '../errors.js';
100
+ import { getComponentLogger } from '../logging/index.js';
101
+ const logger = getComponentLogger('structural-spec-dependence');
102
+ /**
103
+ * Sentinel key handed out by the schema proxy's `ownKeys` trap for
104
+ * `Record<string, V>` spec fields, whose real keys only exist at runtime.
105
+ * Must stay in sync with `src/core/references/schema-proxy.ts`.
106
+ */
107
+ const RUNTIME_MAP_SENTINEL = '__typekroSchemaKey';
108
+ /** Prefix of the schema-reference marker string emitted by the schema proxy. */
109
+ const SCHEMA_REF_MARKER_PREFIX = '__KUBERNETES_REF___schema___';
110
+ /**
111
+ * A schema reference ending in the proxy's `$item` element sentinel, which it
112
+ * appends when a spec collection is iterated. Anchored to a schema path rather
113
+ * than matching a bare `$item`, so a shell script or template in a ConfigMap
114
+ * that happens to contain `$item` is not mistaken for one.
115
+ *
116
+ * Survives into the RGD only when the iteration was NOT compiled into a KRO
117
+ * `forEach` dimension.
118
+ */
119
+ const COLLECTION_ITEM_REFERENCE = /(?:schema\.spec|__KUBERNETES_REF___schema___spec)[A-Za-z0-9_.$[\]?]*\.\$item/;
120
+ /** Thrown when a KRO-mode RGD would silently encode a build-time guess. */
121
+ export class StructuralSpecDependenceError extends TypeKroError {
122
+ graphName;
123
+ findings;
124
+ constructor(message, graphName, findings) {
125
+ super(message, 'STRUCTURAL_SPEC_DEPENDENCE', { graphName, findings });
126
+ this.graphName = graphName;
127
+ this.findings = findings;
128
+ this.name = 'StructuralSpecDependenceError';
129
+ }
130
+ }
131
+ // ---------------------------------------------------------------------------
132
+ // Detector 1 — emitted-RGD scan
133
+ // ---------------------------------------------------------------------------
134
+ function schemaPathFromMarker(text) {
135
+ const match = new RegExp(`${SCHEMA_REF_MARKER_PREFIX}([A-Za-z0-9_.$[\\]?]+?)__`).exec(text);
136
+ return match?.[1] === undefined ? undefined : trimProxySentinelSuffix(match[1]);
137
+ }
138
+ /**
139
+ * Trim the proxy's own placeholder segments so the reported path names the spec
140
+ * field the author wrote, not the sentinel the proxy appended.
141
+ */
142
+ function trimProxySentinelSuffix(path) {
143
+ return path
144
+ .replace(new RegExp(`(?:\\.${RUNTIME_MAP_SENTINEL})+$`), '')
145
+ .replace(/(?:\.\$item)+$/, '');
146
+ }
147
+ /** Collect every `schema.spec.<path>` / marker path mentioned anywhere in `text`. */
148
+ function schemaPathsIn(text) {
149
+ const paths = new Set();
150
+ const markerPattern = new RegExp(`${SCHEMA_REF_MARKER_PREFIX}([A-Za-z0-9_.$[\\]?]+?)__`, 'g');
151
+ for (const match of text.matchAll(markerPattern)) {
152
+ if (match[1])
153
+ paths.add(trimProxySentinelSuffix(match[1]));
154
+ }
155
+ for (const match of text.matchAll(/schema\.(spec\.[A-Za-z0-9_.$[\]?]+)/g)) {
156
+ if (match[1])
157
+ paths.add(trimProxySentinelSuffix(match[1]));
158
+ }
159
+ return [...paths].filter((path) => path !== '' && path !== 'spec');
160
+ }
161
+ /**
162
+ * Walk an already-serialized template (plain JSON data — no proxies, no
163
+ * `KubernetesRef` objects) reporting every object key and every string leaf.
164
+ */
165
+ function walkTemplate(value, path, visitor) {
166
+ if (typeof value === 'string') {
167
+ visitor.onString(path, value);
168
+ return;
169
+ }
170
+ if (Array.isArray(value)) {
171
+ value.forEach((entry, index) => walkTemplate(entry, `${path}[${index}]`, visitor));
172
+ return;
173
+ }
174
+ if (value === null || typeof value !== 'object')
175
+ return;
176
+ for (const [key, child] of Object.entries(value)) {
177
+ const childPath = path ? `${path}.${key}` : key;
178
+ visitor.onKey(childPath, key, child);
179
+ walkTemplate(child, childPath, visitor);
180
+ }
181
+ }
182
+ /**
183
+ * Report build-time residue in the RGD that is about to be emitted.
184
+ *
185
+ * Operates on the serialized manifest rather than on live composition state,
186
+ * so every finding is backed by a concrete artifact in the output.
187
+ */
188
+ export function scanRgdResourcesForStructuralSpecArtifacts(resources) {
189
+ const findings = [];
190
+ for (const entry of resources) {
191
+ const id = entry.id;
192
+ if (id.includes(SCHEMA_REF_MARKER_PREFIX) || id.includes(RUNTIME_MAP_SENTINEL)) {
193
+ findings.push({
194
+ kind: 'spec-derived-key',
195
+ location: `resource id "${id}"`,
196
+ specPaths: schemaPathsIn(id),
197
+ detail: 'the resource id itself was built from a runtime spec value, so the RGD names one ' +
198
+ 'resource after a build-time placeholder instead of one resource per instance value',
199
+ });
200
+ }
201
+ // A `forEach` dimension IS the legitimate way to let a spec collection
202
+ // decide how many resources exist, and its own source expression lives
203
+ // outside the template. When one is present, a surviving `$item` in the
204
+ // template is the loop variable doing its job, not a collapsed collection.
205
+ const hasForEach = Array.isArray(entry.forEach) && entry.forEach.length > 0;
206
+ // Template paths already reported via their key, so the string walk that
207
+ // follows does not report the same leaf twice.
208
+ const seenAtPath = new Set();
209
+ walkTemplate(entry.template, '', {
210
+ onKey(path, key, child) {
211
+ if (key.includes(SCHEMA_REF_MARKER_PREFIX)) {
212
+ const specPath = schemaPathFromMarker(key);
213
+ findings.push({
214
+ kind: 'spec-derived-key',
215
+ location: `resource "${id}" at template.${path}`,
216
+ specPaths: specPath ? [specPath] : [],
217
+ detail: 'an object key was built from a runtime spec value; KRO substitutes references ' +
218
+ 'in values only, so the RGD carries the unsubstituted reference as a literal key',
219
+ });
220
+ seenAtPath.add(path);
221
+ return;
222
+ }
223
+ if (key.includes(RUNTIME_MAP_SENTINEL)) {
224
+ findings.push({
225
+ kind: 'runtime-map-enumerated',
226
+ location: `resource "${id}" at template.${path}`,
227
+ // The sentinel key carries no path, but the value the proxy paired
228
+ // with it does (`${schema.spec.settings.__typekroSchemaKey}`).
229
+ specPaths: typeof child === 'string' ? schemaPathsIn(child) : [],
230
+ detail: 'the composition enumerated a map-typed spec field at build time; its real keys ' +
231
+ 'exist only per instance, so the RGD encodes one placeholder key',
232
+ });
233
+ seenAtPath.add(path);
234
+ }
235
+ },
236
+ onString(path, value) {
237
+ if (seenAtPath.has(path))
238
+ return;
239
+ if (value.includes(RUNTIME_MAP_SENTINEL)) {
240
+ findings.push({
241
+ kind: 'runtime-map-enumerated',
242
+ location: `resource "${id}" at template.${path}`,
243
+ specPaths: schemaPathsIn(value),
244
+ detail: 'the composition enumerated a map-typed spec field at build time; its real keys ' +
245
+ 'exist only per instance, so the RGD encodes one placeholder key',
246
+ });
247
+ return;
248
+ }
249
+ if (!hasForEach && COLLECTION_ITEM_REFERENCE.test(value)) {
250
+ const specPaths = schemaPathsIn(value);
251
+ findings.push({
252
+ kind: 'collection-length-collapsed',
253
+ location: `resource "${id}" at template.${path}`,
254
+ specPaths,
255
+ detail: 'a spec collection was iterated at build time and flattened to a single element; ' +
256
+ 'the RGD encodes exactly one entry regardless of how many the instance supplies',
257
+ });
258
+ }
259
+ },
260
+ });
261
+ }
262
+ return findings;
263
+ }
264
+ /** Read the composition's spec parameter name (`(spec) => ...` → `spec`). */
265
+ function specParamNameOf(fn) {
266
+ const first = fn.params?.[0];
267
+ if (!first)
268
+ return undefined;
269
+ if (first.type === 'Identifier')
270
+ return first.name;
271
+ return undefined;
272
+ }
273
+ /** The composition's own function node, whichever form the source parsed into. */
274
+ function findCompositionFunction(program) {
275
+ let found;
276
+ estraverse.traverse(program, {
277
+ enter(node) {
278
+ if (found)
279
+ return estraverse.VisitorOption.Break;
280
+ const type = node.type;
281
+ if (type === 'ArrowFunctionExpression' ||
282
+ type === 'FunctionExpression' ||
283
+ type === 'FunctionDeclaration') {
284
+ found = node;
285
+ return estraverse.VisitorOption.Break;
286
+ }
287
+ return undefined;
288
+ },
289
+ fallback: 'iteration',
290
+ });
291
+ return found;
292
+ }
293
+ /** Unwrap parenthesis-like and TypeScript-only wrapper nodes. */
294
+ function unwrap(node) {
295
+ let current = node;
296
+ while (current &&
297
+ (current.type === 'ChainExpression' ||
298
+ current.type === 'ParenthesizedExpression' ||
299
+ current.type === 'TSAsExpression' ||
300
+ current.type === 'TSNonNullExpression' ||
301
+ current.type === 'TSSatisfiesExpression' ||
302
+ current.type === 'AwaitExpression')) {
303
+ current = (current.expression ?? current.argument);
304
+ }
305
+ return current;
306
+ }
307
+ /**
308
+ * The `spec.<path>` a node names, when the node is a **pure member chain**
309
+ * rooted at the spec parameter or at a pure alias — nothing else.
310
+ *
311
+ * A computed segment (`spec.users[name]`) resolves to the object's path,
312
+ * because a runtime-keyed read still depends on the object it reads from.
313
+ */
314
+ function pureSpecChainPath(node, specParam, aliases) {
315
+ const current = unwrap(node);
316
+ if (!current)
317
+ return undefined;
318
+ if (current.type === 'Identifier') {
319
+ const name = current.name;
320
+ if (name === specParam)
321
+ return 'spec';
322
+ return aliases.get(name);
323
+ }
324
+ if (current.type !== 'MemberExpression' && current.type !== 'OptionalMemberExpression') {
325
+ return undefined;
326
+ }
327
+ const objectPath = pureSpecChainPath(current.object, specParam, aliases);
328
+ if (!objectPath)
329
+ return undefined;
330
+ if (current.computed)
331
+ return objectPath;
332
+ const property = current.property?.name;
333
+ if (!property)
334
+ return undefined;
335
+ // `toResourceGraph` hands the whole schema proxy in, so the first hop off the
336
+ // parameter is `.spec` and must not be doubled up.
337
+ if (objectPath === 'spec' && property === 'spec')
338
+ return 'spec';
339
+ return `${objectPath}.${property}`;
340
+ }
341
+ /**
342
+ * Spec paths an expression depends on: pure spec chains combined by operators
343
+ * that pass their operands through unchanged.
344
+ *
345
+ * The walk stops at calls and function bodies — a helper's return value and a
346
+ * callback's internals are opaque, and following them is what turns
347
+ * `resolved.users.map((u) => spec.users[u.name])` into a bogus claim that the
348
+ * resulting array is spec-derived.
349
+ */
350
+ function specPathsOf(node, specParam, aliases) {
351
+ const paths = new Set();
352
+ const visit = (raw) => {
353
+ const current = unwrap(raw);
354
+ if (!current)
355
+ return;
356
+ const chain = pureSpecChainPath(current, specParam, aliases);
357
+ if (chain) {
358
+ paths.add(chain);
359
+ return;
360
+ }
361
+ switch (current.type) {
362
+ case 'UnaryExpression':
363
+ visit(current.argument);
364
+ return;
365
+ case 'BinaryExpression':
366
+ case 'LogicalExpression':
367
+ visit(current.left);
368
+ visit(current.right);
369
+ return;
370
+ case 'ConditionalExpression':
371
+ visit(current.test);
372
+ visit(current.consequent);
373
+ visit(current.alternate);
374
+ return;
375
+ case 'TemplateLiteral':
376
+ for (const expression of (current.expressions ?? []))
377
+ visit(expression);
378
+ return;
379
+ case 'SequenceExpression':
380
+ for (const expression of (current.expressions ?? []))
381
+ visit(expression);
382
+ return;
383
+ default:
384
+ // Calls, functions, object/array literals and everything else are
385
+ // opaque on purpose. See {@link SpecAliasScope}.
386
+ return;
387
+ }
388
+ };
389
+ visit(node);
390
+ return [...paths].filter((path) => path !== 'spec').sort();
391
+ }
392
+ /**
393
+ * Collect top-level bindings that alias a pure spec member chain.
394
+ *
395
+ * Two forms only: `const enabled = spec.enabled;` and
396
+ * `const { enabled, mode: storageMode } = spec;`.
397
+ */
398
+ function buildSpecAliasScope(body, specParam) {
399
+ const aliases = new Map();
400
+ for (const statement of body) {
401
+ if (statement.type !== 'VariableDeclaration')
402
+ continue;
403
+ for (const declarator of (statement.declarations ?? [])) {
404
+ const init = declarator.init;
405
+ if (!init)
406
+ continue;
407
+ const initPath = pureSpecChainPath(init, specParam, aliases);
408
+ if (!initPath)
409
+ continue;
410
+ const id = declarator.id;
411
+ if (id.type === 'Identifier') {
412
+ aliases.set(id.name, initPath);
413
+ continue;
414
+ }
415
+ if (id.type === 'ObjectPattern') {
416
+ for (const property of (id.properties ?? [])) {
417
+ if (property.type !== 'Property')
418
+ continue;
419
+ const key = property.key?.name;
420
+ const local = property.value?.name;
421
+ if (!key || !local)
422
+ continue;
423
+ aliases.set(local, `${initPath}.${key}`);
424
+ }
425
+ }
426
+ }
427
+ }
428
+ return aliases;
429
+ }
430
+ /**
431
+ * Global functions that only compute a value from their arguments.
432
+ *
433
+ * Casing says nothing about whether a call builds a resource — most of the
434
+ * repo's own factories are camelCase (`helmRelease`, `serviceAccount`,
435
+ * `persistentVolumeClaim`) — so {@link branchBuildsStructure} assumes a call
436
+ * builds structure and this allowlist is what buys silence back. Everything
437
+ * listed here is a pure JavaScript builtin: adding to it can only make the
438
+ * check quieter, so entries must be builtins, never project functions.
439
+ */
440
+ const PURE_HELPER_GLOBALS = new Set([
441
+ 'Boolean',
442
+ 'BigInt',
443
+ 'Number',
444
+ 'String',
445
+ 'Symbol',
446
+ 'decodeURI',
447
+ 'decodeURIComponent',
448
+ 'encodeURI',
449
+ 'encodeURIComponent',
450
+ 'isFinite',
451
+ 'isNaN',
452
+ 'parseFloat',
453
+ 'parseInt',
454
+ 'structuredClone',
455
+ ]);
456
+ /**
457
+ * Namespaces whose every member call computes a value: `JSON.stringify(x)`,
458
+ * `Math.max(a, b)`, `Object.keys(x)`, and TypeKro's own `Cel.expr(...)` /
459
+ * `Cel.template(...)`, which are runtime expressions rather than structure.
460
+ */
461
+ const PURE_HELPER_NAMESPACES = new Set([
462
+ 'Array',
463
+ 'Boolean',
464
+ 'Cel',
465
+ 'Date',
466
+ 'JSON',
467
+ 'Math',
468
+ 'Number',
469
+ 'Object',
470
+ 'Promise',
471
+ 'Reflect',
472
+ 'RegExp',
473
+ 'String',
474
+ 'Symbol',
475
+ ]);
476
+ /**
477
+ * Builtin constructors that produce a plain value rather than graph structure.
478
+ * `if (flag) { index = new Map(…) }` is a value computation; nothing else in
479
+ * this repo is reached with `new`, and no factory is a class.
480
+ */
481
+ const PURE_HELPER_CONSTRUCTORS = new Set([
482
+ 'Array',
483
+ 'Date',
484
+ 'Error',
485
+ 'Map',
486
+ 'Number',
487
+ 'Object',
488
+ 'RegExp',
489
+ 'Set',
490
+ 'String',
491
+ 'TypeError',
492
+ 'URL',
493
+ 'URLSearchParams',
494
+ 'WeakMap',
495
+ 'WeakSet',
496
+ ]);
497
+ /**
498
+ * Builtin array/string/map methods. These reshape, read or accumulate into a
499
+ * value; none of them registers a resource, because in TypeKro a resource
500
+ * enters the graph when its FACTORY is called, not when the returned object is
501
+ * pushed somewhere. Allowlisting `.map` costs nothing either: a factory called
502
+ * inside the callback is still reached by the walk, which never stops at a
503
+ * pure call.
504
+ *
505
+ * The receiver is not checked, so a project function that happened to share
506
+ * one of these names would be exempted by mistake. None does — every one of
507
+ * these names was checked against the exports of `src/factories/**` — and a
508
+ * new factory must not take one.
509
+ */
510
+ const PURE_HELPER_METHODS = new Set([
511
+ 'at', 'charAt', 'concat', 'endsWith', 'entries', 'every', 'fill', 'filter',
512
+ 'find', 'findIndex', 'findLast', 'findLastIndex', 'flat', 'flatMap',
513
+ 'forEach', 'get', 'has', 'includes', 'indexOf', 'join', 'keys', 'lastIndexOf', 'map',
514
+ 'match', 'normalize', 'padEnd', 'padStart', 'pop', 'push', 'reduce',
515
+ 'reduceRight', 'repeat', 'replace', 'replaceAll', 'reverse', 'shift',
516
+ 'slice', 'some', 'sort', 'split', 'splice', 'startsWith', 'substring',
517
+ 'toFixed', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimEnd',
518
+ 'trimStart', 'unshift', 'valueOf', 'values',
519
+ ]);
520
+ /**
521
+ * True when a call is a known pure helper — the ONLY calls
522
+ * {@link branchBuildsStructure} lets through.
523
+ *
524
+ * The default runs the other way round on purpose. There is no reliable way to
525
+ * tell a factory call from any other call by looking at the source: the callee
526
+ * is an imported binding this module cannot resolve, and its name carries no
527
+ * signal (`helmRelease`, `observedResource`, `singleton` and
528
+ * `kubernetesComposition` all build structure; `ConfigMap` and
529
+ * `simple.Deployment` do too). So an unrecognised call — and any `new` that is
530
+ * not a builtin constructor — is treated as structure-building, and only the
531
+ * builtins above are exempt.
532
+ */
533
+ function isPureHelperCall(node) {
534
+ const callee = unwrap(node.callee);
535
+ if (!callee)
536
+ return false;
537
+ if (node.type === 'NewExpression') {
538
+ return callee.type === 'Identifier' && PURE_HELPER_CONSTRUCTORS.has(callee.name);
539
+ }
540
+ if (callee.type === 'Identifier')
541
+ return PURE_HELPER_GLOBALS.has(callee.name);
542
+ if (callee.type !== 'MemberExpression' && callee.type !== 'OptionalMemberExpression') {
543
+ return false;
544
+ }
545
+ // `fns[i]()` names nothing this side of runtime.
546
+ if (callee.computed)
547
+ return false;
548
+ const method = callee.property?.name;
549
+ if (!method)
550
+ return false;
551
+ const namespace = (unwrap(callee.object) ?? {});
552
+ if (namespace.type === 'Identifier' &&
553
+ PURE_HELPER_NAMESPACES.has(namespace.name)) {
554
+ return true;
555
+ }
556
+ return PURE_HELPER_METHODS.has(method);
557
+ }
558
+ /**
559
+ * True when the subtree contains a call that may build graph structure — a
560
+ * factory, a nested composition, or any helper that wraps one.
561
+ *
562
+ * The walk does not stop at a pure helper, so `spec.items.map(() => Deployment(…))`
563
+ * still counts: `.map` is exempt, the `Deployment(…)` inside it is not.
564
+ */
565
+ function branchBuildsStructure(node) {
566
+ if (!node)
567
+ return false;
568
+ let found = false;
569
+ estraverse.traverse(node, {
570
+ enter(raw) {
571
+ if (found)
572
+ return estraverse.VisitorOption.Break;
573
+ const current = raw;
574
+ if (current.type !== 'CallExpression' && current.type !== 'NewExpression')
575
+ return undefined;
576
+ if (isPureHelperCall(current))
577
+ return undefined;
578
+ found = true;
579
+ return estraverse.VisitorOption.Break;
580
+ },
581
+ fallback: 'iteration',
582
+ });
583
+ return found;
584
+ }
585
+ /**
586
+ * The enumerated operand when `node` reads an object's keys — `Object.keys(x)`,
587
+ * `Object.values(x)`, `Object.entries(x)`, or a spread `{ ...x }` / `[ ...x ]`.
588
+ */
589
+ function mapEnumerationTarget(node) {
590
+ if (node.type === 'SpreadElement' || node.type === 'RestElement') {
591
+ return node.argument;
592
+ }
593
+ if (node.type !== 'CallExpression')
594
+ return undefined;
595
+ const callee = node.callee;
596
+ if (callee?.type !== 'MemberExpression')
597
+ return undefined;
598
+ const object = callee.object?.name;
599
+ const method = callee.property?.name;
600
+ if (object !== 'Object')
601
+ return undefined;
602
+ if (method !== 'keys' && method !== 'values' && method !== 'entries')
603
+ return undefined;
604
+ return node.arguments?.[0];
605
+ }
606
+ function excerpt(source, node, limit = 80) {
607
+ const start = node.start;
608
+ const end = node.end;
609
+ if (typeof start !== 'number' || typeof end !== 'number')
610
+ return '<expression>';
611
+ const text = source.slice(start, end).replace(/\s+/g, ' ').trim();
612
+ return text.length > limit ? `${text.slice(0, limit - 1)}…` : text;
613
+ }
614
+ /**
615
+ * Report spec-derived structure decisions visible in the composition source
616
+ * that the control-flow analyzer does not compile into KRO constructs.
617
+ *
618
+ * Degrades to an empty result — never to a guess — when the source cannot be
619
+ * parsed or the spec parameter is not a plain identifier.
620
+ */
621
+ function analyzeCompositionSource(compositionSource) {
622
+ if (!compositionSource)
623
+ return { findings: [], mapEnumerationSites: [] };
624
+ let program;
625
+ try {
626
+ program = Parser.parse(compositionSource, {
627
+ ecmaVersion: 2022,
628
+ sourceType: 'script',
629
+ ranges: true,
630
+ });
631
+ }
632
+ catch {
633
+ try {
634
+ program = Parser.parse(`(${compositionSource})`, {
635
+ ecmaVersion: 2022,
636
+ sourceType: 'script',
637
+ ranges: true,
638
+ });
639
+ // Offsets shift by the added paren; excerpts stay readable either way.
640
+ }
641
+ catch (error) {
642
+ logger.debug('Composition source could not be parsed for structural analysis', {
643
+ error: error instanceof Error ? error.message : String(error),
644
+ });
645
+ return { findings: [], mapEnumerationSites: [] };
646
+ }
647
+ }
648
+ const fn = findCompositionFunction(program);
649
+ const specParam = fn ? specParamNameOf(fn) : undefined;
650
+ if (!fn || !specParam)
651
+ return { findings: [], mapEnumerationSites: [] };
652
+ const bodyNode = fn.body;
653
+ const body = bodyNode?.type === 'BlockStatement' ? bodyNode.body : [];
654
+ const aliases = buildSpecAliasScope(body, specParam);
655
+ const findings = [];
656
+ const mapEnumerationSites = [];
657
+ const seen = new Set();
658
+ const push = (finding) => {
659
+ const key = `${finding.kind}|${finding.location}|${finding.specPaths.join(',')}`;
660
+ if (seen.has(key))
661
+ return;
662
+ seen.add(key);
663
+ findings.push(finding);
664
+ };
665
+ /**
666
+ * A predicate is *compiled* when the analyzer's own gate would fire: the test
667
+ * lexically mentions the spec parameter. Those become `includeWhen` and stay
668
+ * silent here. Anything spec-derived that the gate misses decided the branch
669
+ * at build time.
670
+ */
671
+ const mentionsSpecLexically = (node) => {
672
+ let found = false;
673
+ estraverse.traverse(node, {
674
+ enter(raw) {
675
+ if (found)
676
+ return estraverse.VisitorOption.Break;
677
+ const current = raw;
678
+ if (current.type === 'Identifier' && current.name === specParam) {
679
+ found = true;
680
+ return estraverse.VisitorOption.Break;
681
+ }
682
+ return undefined;
683
+ },
684
+ fallback: 'iteration',
685
+ });
686
+ return found;
687
+ };
688
+ /**
689
+ * `.length` inside a status expression is FINE: the JS→CEL analyzer rewrites
690
+ * `schema.spec.x.length` to `size(schema.spec.x)`, which KRO evaluates per
691
+ * instance. Only a `.length` that lands in a resource TEMPLATE is a
692
+ * build-time constant. Status expressions live in the composition's `return`
693
+ * statement and inside explicit `Cel.*(…)` arguments, so track that context
694
+ * and stay silent there.
695
+ */
696
+ let celContextDepth = 0;
697
+ const opensCelContext = (node) => {
698
+ if (node.type === 'ReturnStatement')
699
+ return true;
700
+ if (node.type !== 'CallExpression')
701
+ return false;
702
+ const callee = node.callee;
703
+ return (callee?.type === 'MemberExpression' &&
704
+ callee.object?.name === 'Cel');
705
+ };
706
+ estraverse.traverse(fn, {
707
+ leave(raw) {
708
+ if (opensCelContext(raw))
709
+ celContextDepth -= 1;
710
+ },
711
+ enter(raw) {
712
+ const node = raw;
713
+ if (opensCelContext(node))
714
+ celContextDepth += 1;
715
+ if (node.type === 'IfStatement' || node.type === 'ConditionalExpression') {
716
+ const test = node.test;
717
+ const branchCarriesResources = branchBuildsStructure(node.consequent) ||
718
+ branchBuildsStructure(node.alternate);
719
+ if (!branchCarriesResources)
720
+ return undefined;
721
+ if (mentionsSpecLexically(test))
722
+ return undefined;
723
+ const specPaths = specPathsOf(test, specParam, aliases);
724
+ if (specPaths.length === 0)
725
+ return undefined;
726
+ push({
727
+ kind: 'uncompiled-predicate',
728
+ location: `condition \`${excerpt(compositionSource, test)}\``,
729
+ specPaths,
730
+ detail: 'the branch decides what the composition builds and reaches the spec only through a ' +
731
+ 'local binding, so TypeKro could not compile it to a KRO includeWhen and the ' +
732
+ 'build-time branch is baked into the RGD',
733
+ });
734
+ return undefined;
735
+ }
736
+ if (node.type === 'SwitchStatement') {
737
+ if (!branchBuildsStructure(node))
738
+ return undefined;
739
+ const specPaths = specPathsOf(node.discriminant, specParam, aliases);
740
+ if (specPaths.length === 0)
741
+ return undefined;
742
+ push({
743
+ kind: 'switch-discriminator',
744
+ location: `switch (${excerpt(compositionSource, node.discriminant, 60)})`,
745
+ specPaths,
746
+ detail: 'a switch on a spec value selects which resources exist; TypeKro has no lowering for ' +
747
+ 'switch, so no case matches the runtime reference and the default branch is baked ' +
748
+ 'into the RGD for every instance',
749
+ });
750
+ return undefined;
751
+ }
752
+ if ((node.type === 'MemberExpression' || node.type === 'OptionalMemberExpression') &&
753
+ !node.computed &&
754
+ node.property?.name === 'length') {
755
+ if (celContextDepth > 0)
756
+ return undefined;
757
+ // A pure chain only: `spec.items.length`, not a `.length` read on a
758
+ // build-time-shaped local that merely mentions the spec somewhere.
759
+ const chain = pureSpecChainPath(node.object, specParam, aliases);
760
+ if (!chain || chain === 'spec')
761
+ return undefined;
762
+ push({
763
+ kind: 'collection-length-read',
764
+ location: `\`${excerpt(compositionSource, node, 60)}\``,
765
+ specPaths: [chain],
766
+ detail: 'the schema proxy answers `.length` with the build-time placeholder 1, so the emitted ' +
767
+ 'value is a constant rather than the instance’s actual length',
768
+ });
769
+ return undefined;
770
+ }
771
+ const enumerated = mapEnumerationTarget(node);
772
+ if (enumerated) {
773
+ const chain = pureSpecChainPath(enumerated, specParam, aliases);
774
+ if (chain && chain !== 'spec') {
775
+ const site = { location: excerpt(compositionSource, node, 60), specPath: chain };
776
+ if (!mapEnumerationSites.some((existing) => existing.specPath === site.specPath)) {
777
+ mapEnumerationSites.push(site);
778
+ }
779
+ }
780
+ }
781
+ return undefined;
782
+ },
783
+ fallback: 'iteration',
784
+ });
785
+ return { findings, mapEnumerationSites };
786
+ }
787
+ /**
788
+ * Branch predicates and `.length` reads the control-flow analyzer does not
789
+ * compile. See {@link analyzeCompositionSource}.
790
+ */
791
+ export function detectStructuralSpecPredicates(compositionSource) {
792
+ return analyzeCompositionSource(compositionSource).findings;
793
+ }
794
+ /**
795
+ * Sites where the composition reads the keys of a spec field at build time.
796
+ *
797
+ * These are CANDIDATES, never findings. Enumerating an *object-typed* spec
798
+ * field is legitimate — the schema proxy is shape-aware and yields the real
799
+ * declared names — and the AST cannot tell that apart from a map-typed field,
800
+ * whose keys exist only per instance. Only the emitted RGD can, by leaving the
801
+ * `__typekroSchemaKey` sentinel behind; but that sentinel carries no path when
802
+ * it was consumed as a plain string. Reporting these alongside such a finding
803
+ * lets the message point at the lines worth reading without claiming any one
804
+ * of them is the culprit.
805
+ */
806
+ export function detectMapEnumerationSites(compositionSource) {
807
+ return analyzeCompositionSource(compositionSource).mapEnumerationSites;
808
+ }
809
+ // ---------------------------------------------------------------------------
810
+ // Reporting
811
+ // ---------------------------------------------------------------------------
812
+ /** Remedies, ordered most-specific-first for the kinds present. */
813
+ function remediesFor(kinds) {
814
+ const remedies = [];
815
+ if (kinds.has('uncompiled-predicate')) {
816
+ remedies.push('Inline the spec reference into the condition itself (`if (spec.enabled) { … }`) so TypeKro ' +
817
+ 'compiles it to a KRO includeWhen.');
818
+ }
819
+ remedies.push('Make it a BUILD-TIME factory option: take the value as an argument to the factory that ' +
820
+ 'builds the composition, so the structure is decided before the RGD is emitted, and ship ' +
821
+ 'one RGD per shape.');
822
+ remedies.push('Keep the structure FIXED and pass the spec value as a plain field: every resource, list ' +
823
+ 'entry and key always exists, and the runtime value only decides what a field contains.');
824
+ return remedies;
825
+ }
826
+ function formatFinding(finding, index) {
827
+ const paths = finding.specPaths.length > 0
828
+ ? finding.specPaths.map((path) => `\`${path}\``).join(', ')
829
+ : '(unresolved spec path)';
830
+ return [
831
+ ` ${index + 1}. [${finding.kind}] ${finding.location}`,
832
+ ` spec value: ${paths}`,
833
+ ` ${finding.detail}`,
834
+ ].join('\n');
835
+ }
836
+ /** Render the diagnostic text shared by the error and the escape-hatch warning. */
837
+ export function formatStructuralSpecDependence(graphName, findings, mapEnumerationSites = []) {
838
+ const kinds = new Set(findings.map((finding) => finding.kind));
839
+ const remedies = remediesFor(kinds)
840
+ .map((remedy, index) => ` ${String.fromCharCode(97 + index)}) ${remedy}`)
841
+ .join('\n');
842
+ const candidates = mapEnumerationSites.length > 0
843
+ ? [
844
+ '',
845
+ 'A placeholder key above carries no spec path, because it was consumed as a plain',
846
+ 'string. The composition reads spec keys at build time in these places — one of them',
847
+ 'reads a map-typed field whose keys only exist per instance:',
848
+ mapEnumerationSites
849
+ .map((site) => ` - \`${site.location}\` (\`${site.specPath}\`)`)
850
+ .join('\n'),
851
+ ]
852
+ : [];
853
+ return [
854
+ `Resource graph "${graphName}" lets a runtime spec value decide build-time STRUCTURE. ` +
855
+ 'TypeKro can only serialize a ResourceGraphDefinition whose shape is fixed: `schema.spec.*` ' +
856
+ 'is substituted per instance, so it may decide what a field CONTAINS but never which ' +
857
+ 'resources, list entries or keys EXIST.',
858
+ '',
859
+ `${findings.length} structural use${findings.length === 1 ? '' : 's'} of a spec value:`,
860
+ findings.map(formatFinding).join('\n'),
861
+ ...candidates,
862
+ '',
863
+ 'Two shapes are legitimate:',
864
+ remedies,
865
+ '',
866
+ 'To keep the current behavior while migrating, pass ' +
867
+ '`{ allowStructuralSpecDependence: true }` in the composition options — the RGD is emitted ' +
868
+ 'unchanged and this becomes a warning.',
869
+ ].join('\n');
870
+ }
871
+ /**
872
+ * Whether the structural spec-dependence check ignores per-composition escape
873
+ * hatches.
874
+ *
875
+ * `TYPEKRO_STRUCTURAL_SPEC=strict` makes every structural use an error even
876
+ * when the composition sets `allowStructuralSpecDependence`, so a repository
877
+ * can audit what its shipped graphs still depend on without editing them.
878
+ * Resolved in ONE place, matching `isStrictCelDiagnosticsEnabled`.
879
+ */
880
+ export function isStructuralSpecDependenceStrict() {
881
+ return process.env.TYPEKRO_STRUCTURAL_SPEC === 'strict';
882
+ }
883
+ /**
884
+ * Gate KRO-mode serialization on structural spec-dependence.
885
+ *
886
+ * Throws {@link StructuralSpecDependenceError} unless `allow` is set, in which
887
+ * case the same report is logged as a warning naming every path.
888
+ */
889
+ export function assertNoStructuralSpecDependence(input) {
890
+ const source = analyzeCompositionSource(input.compositionSource);
891
+ const findings = [
892
+ ...scanRgdResourcesForStructuralSpecArtifacts(input.resources),
893
+ ...source.findings,
894
+ ];
895
+ if (findings.length === 0)
896
+ return;
897
+ // Offer the enumeration candidates only when a sentinel finding could not
898
+ // name its own path — the AST cannot prove which site produced it.
899
+ const needsCandidates = findings.some((finding) => finding.kind === 'runtime-map-enumerated' && finding.specPaths.length === 0);
900
+ const message = formatStructuralSpecDependence(input.graphName, findings, needsCandidates ? source.mapEnumerationSites : []);
901
+ if (input.allow && !isStructuralSpecDependenceStrict()) {
902
+ logger.warn(message, {
903
+ graphName: input.graphName,
904
+ specPaths: [...new Set(findings.flatMap((finding) => finding.specPaths))],
905
+ kinds: [...new Set(findings.map((finding) => finding.kind))],
906
+ });
907
+ return;
908
+ }
909
+ throw new StructuralSpecDependenceError(message, input.graphName, findings);
910
+ }
911
+ //# sourceMappingURL=structural-spec-dependence.js.map