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,698 @@
1
+ /**
2
+ * ClickStack storage consumption: TTL retention and the collector's
3
+ * persistent sending queue.
4
+ *
5
+ * The storage POLICY needs nothing here. The `clickhouse` factory sets
6
+ * `merge_tree/storage_policy` as the server default, so the gateway
7
+ * collector's goose migrations create `otel_logs` / `otel_traces` /
8
+ * `otel_metrics_*` / `hyperdx_sessions` on the S3 policy with no
9
+ * `SETTINGS storage_policy` clause and no per-table DDL from TypeKro. This
10
+ * module covers the two things a server default cannot express:
11
+ *
12
+ * 1. **Retention** — `TTL toDateTime(<timestamp>) + INTERVAL n UNIT DELETE`,
13
+ * applied by an idempotent CronJob because the tables do not exist until the
14
+ * collector has migrated, and because TypeKro does not own their DDL.
15
+ * LIVE-VERIFIED: the collector's own migration already sets a 30-day TTL
16
+ * (`toDateTime(Timestamp) + toIntervalDay(30)` with `ttl_only_drop_parts`),
17
+ * so `retention` OVERRIDES that default rather than establishing the first
18
+ * one — which is exactly why the idempotence probe compares the COMPLETE
19
+ * TTL clause rather than merely asking whether a TTL exists.
20
+ * 2. **Persistent queue** — a `file_storage`-backed exporter queue so a
21
+ * ClickHouse restart (which is exactly what an S3-backed node rebuild
22
+ * causes) does not drop in-flight telemetry. Its directory is backed by a
23
+ * STANDALONE PersistentVolumeClaim owned by the composition: an `emptyDir`
24
+ * or a generic ephemeral volume is deleted with the collector Pod, so
25
+ * neither survives the collector restart the queue exists to survive.
26
+ *
27
+ * S3_PLAIN_REWRITABLE NOTE: retention and that disk type are MUTUALLY
28
+ * EXCLUSIVE, and `resolveClickStackStorage` rejects the combination.
29
+ * `MODIFY TTL` normally schedules a materialization MUTATION, which
30
+ * plain_rewritable does not support — every statement this module emits
31
+ * therefore carries `SETTINGS materialize_ttl_after_modify = 0` so expiry
32
+ * happens during merges instead. LIVE-VERIFIED (ClickHouse 25.7) that this is
33
+ * not enough: the immutable metadata type refuses the metadata ALTER itself
34
+ * ("ALTER TABLE commands are not supported on immutable disk", code 344), and
35
+ * the identical statement succeeds against a table on the server's local
36
+ * policy. The setting is kept for the `diskType: 's3'` path, where the
37
+ * materialization pass is the only thing worth skipping.
38
+ */
39
+ import { assertSafeCollectorConfigKey } from './collector-config.js';
40
+ /** Default cron schedule for the retention DDL CronJob. */
41
+ export const DEFAULT_RETENTION_SCHEDULE = '17 * * * *';
42
+ /**
43
+ * Default image for the retention DDL CronJob. The ClickStack chart vendors
44
+ * ClickHouse 25.7, so the matching server image supplies a compatible
45
+ * `clickhouse-client`.
46
+ */
47
+ export const DEFAULT_RETENTION_IMAGE = 'clickhouse/clickhouse-server:25.7';
48
+ /** Default persistent-queue directory inside the collector pod. */
49
+ export const DEFAULT_QUEUE_DIRECTORY = '/var/lib/otelcol/file_storage';
50
+ /** Default `file_storage` extension instance name. */
51
+ export const QUEUE_EXTENSION_NAME = 'file_storage/hyperdx';
52
+ /**
53
+ * Default exporters whose `sending_queue` is switched to file storage.
54
+ *
55
+ * The ClickStack collector defines a single ClickHouse exporter, `clickhouse`,
56
+ * and all three signal pipelines export through it. A name that is NOT one the
57
+ * agent defines fails silently: the supervisor merges the overlay, the
58
+ * `exporters` map simply grows an exporter no pipeline uses, and the real one
59
+ * keeps its in-memory queue. That is why the integration suite asserts these
60
+ * names against the agent's own EFFECTIVE configuration instead of trusting
61
+ * the default.
62
+ */
63
+ export const DEFAULT_QUEUE_EXPORTER_NAMES = ['clickhouse'];
64
+ /**
65
+ * Default `service.extensions` list emitted with the queue overlay.
66
+ *
67
+ * A YAML list in `global.otelCollector.customConfig` REPLACES the supervisor's
68
+ * own list, so this must name every extension the collector needs — see the
69
+ * warning on {@link ClickStackPersistentQueueOptions}.
70
+ */
71
+ export const DEFAULT_QUEUE_EXTENSIONS = ['health_check', QUEUE_EXTENSION_NAME];
72
+ /** Volume name used for the persistent-queue directory. */
73
+ export const QUEUE_VOLUME_NAME = 'otel-file-storage';
74
+ /**
75
+ * Deployment update strategy forced on the gateway whenever the queue is on.
76
+ *
77
+ * The collector chart's `rollout.strategy` (default `RollingUpdate`) becomes
78
+ * the Deployment's `spec.strategy.type` verbatim. `Recreate` is the only value
79
+ * under which a rollout terminates the old collector BEFORE creating its
80
+ * replacement, which is what a single-writer queue on a ReadWriteOnce claim
81
+ * requires — see {@link renderPersistentQueueValues} for why the replica pin
82
+ * does not cover this on its own.
83
+ */
84
+ export const QUEUE_ROLLOUT_STRATEGY = 'Recreate';
85
+ /**
86
+ * The gateway subchart's OWN `extraVolumes` entry, which we must re-emit.
87
+ *
88
+ * Helm REPLACES a list-valued override rather than appending to it, and the
89
+ * chart mounts the ConfigMap rendered from `global.otelCollector.customConfig`
90
+ * through exactly these two lists. Chart 3.2.0's `values.yaml` says so in a
91
+ * comment on the defaults:
92
+ *
93
+ * "NOTE: if you override extraVolumes/extraVolumeMounts yourself, Helm
94
+ * replaces these lists entirely -- re-include the entries below to keep
95
+ * global.otelCollector.customConfig working."
96
+ *
97
+ * LIVE-VERIFIED what happens when you don't: the queue volume alone evicts the
98
+ * custom-config mount, the OpAMP supervisor logs `Could not read local config
99
+ * file: open /etc/otelcol-contrib/custom/custom.config.yaml: no such file or
100
+ * directory` on every poll, never composes a merged agent config, and the
101
+ * collector never starts its OTLP receivers — while the Pod still reports
102
+ * Ready, because readiness comes from the SUPERVISOR's health_check and not
103
+ * from the agent. Enabling the persistent queue would silently take the whole
104
+ * gateway down.
105
+ */
106
+ export const CHART_CUSTOM_CONFIG_VOLUME_NAME = 'custom-config';
107
+ /** ConfigMap the chart renders `global.otelCollector.customConfig` into. */
108
+ export const CHART_CUSTOM_CONFIG_CONFIG_MAP_NAME = 'clickstack-otel-custom-config';
109
+ /** Directory the chart mounts {@link CHART_CUSTOM_CONFIG_CONFIG_MAP_NAME} at. */
110
+ export const CHART_CUSTOM_CONFIG_MOUNT_PATH = '/etc/otelcol-contrib/custom';
111
+ /** Default size of the persistent-queue PersistentVolumeClaim. */
112
+ export const DEFAULT_QUEUE_SIZE = '10Gi';
113
+ /**
114
+ * Access modes of the persistent-queue PersistentVolumeClaim — not an option.
115
+ *
116
+ * `ReadWriteMany` used to be selectable, on the theory that a shared volume
117
+ * would let several collector replicas run off one queue directory. It does
118
+ * not, and the volume was never the binding constraint: the OTel `file_storage`
119
+ * extension stores the queue in a bbolt database, and bbolt takes an EXCLUSIVE
120
+ * FILE LOCK on open (the extension's own README says a single collector
121
+ * instance per directory; collector-contrib issue #5894 is the second instance
122
+ * hanging on that lock). Two replicas pointed at one directory therefore either
123
+ * block forever or, if the lock is lost across a node boundary the way a
124
+ * network filesystem can lose it, corrupt the database. Offering RWX advertised
125
+ * a multi-replica queue that cannot exist, so the knob is gone and the claim is
126
+ * always `ReadWriteOnce`.
127
+ */
128
+ export const QUEUE_ACCESS_MODES = ['ReadWriteOnce'];
129
+ /** Name suffix of the queue PersistentVolumeClaim (and its resource id). */
130
+ export const QUEUE_CLAIM_NAME_SUFFIX = '-otel-queue';
131
+ /**
132
+ * Name of the queue PersistentVolumeClaim for a release.
133
+ *
134
+ * Shared by the composition (which CREATES the claim) and the values mapper
135
+ * (which MOUNTS it by `claimName`), so the two cannot drift. Accepts a schema
136
+ * reference for `name` the same way every other name in this family does — the
137
+ * template literal serializes to CEL in KRO mode.
138
+ *
139
+ * @param releaseName - Helm release name (`spec.name`)
140
+ * @returns The claim name
141
+ */
142
+ export function clickStackQueueClaimName(releaseName) {
143
+ return `${releaseName}${QUEUE_CLAIM_NAME_SUFFIX}`;
144
+ }
145
+ /** ConfigMap the ClickStack chart renders the shared non-secret env into. */
146
+ export const CLICKSTACK_CONFIG_MAP_NAME = 'clickstack-config';
147
+ /** Secret the ClickStack chart renders the shared secret env into. */
148
+ export const CLICKSTACK_SECRET_NAME = 'clickstack-secret';
149
+ /**
150
+ * Tables per signal, with the timestamp column each one's TTL keys off.
151
+ *
152
+ * Columns mirror the `defaultSources` the values mapper emits (which mirror
153
+ * the chart's own defaults), so they track the schema HyperDX queries:
154
+ * `Timestamp` for logs/traces, `TimeUnix` for metrics, `TimestampTime` for
155
+ * sessions.
156
+ */
157
+ export const CLICKSTACK_RETENTION_TABLES = {
158
+ logs: [
159
+ { table: 'otel_logs', column: 'Timestamp' },
160
+ // A session is a log-kind table in HyperDX's own source definitions, so it
161
+ // follows the logs retention rather than getting its own knob.
162
+ { table: 'hyperdx_sessions', column: 'TimestampTime' },
163
+ ],
164
+ traces: [{ table: 'otel_traces', column: 'Timestamp' }],
165
+ metrics: [
166
+ { table: 'otel_metrics_gauge', column: 'TimeUnix' },
167
+ { table: 'otel_metrics_sum', column: 'TimeUnix' },
168
+ { table: 'otel_metrics_histogram', column: 'TimeUnix' },
169
+ ],
170
+ };
171
+ const RETENTION_UNITS = {
172
+ m: 'MINUTE',
173
+ h: 'HOUR',
174
+ d: 'DAY',
175
+ };
176
+ /**
177
+ * Parse a retention duration string into a ClickHouse `INTERVAL`.
178
+ *
179
+ * @param context - Entry point name for the error message
180
+ * @param field - Offending field path (e.g. `storage.retention.logs`)
181
+ * @param value - Duration string such as `'30d'`, `'720h'`, or `'90m'`
182
+ * @returns The parsed amount and `INTERVAL` unit
183
+ * @throws Error when the duration cannot be parsed or is not positive
184
+ */
185
+ export function parseRetentionDuration(context, field, value) {
186
+ const match = /^([0-9]+)\s*(m|h|d)$/.exec(value.trim());
187
+ const amount = match?.[1];
188
+ const suffix = match?.[2];
189
+ if (amount === undefined || suffix === undefined) {
190
+ throw new Error(`${context}: '${field}' must be a retention duration of minutes, hours or days ` +
191
+ `(e.g. '30d', '720h', '90m') — got ${JSON.stringify(value)}.`);
192
+ }
193
+ const parsed = Number(amount);
194
+ if (parsed < 1) {
195
+ throw new Error(`${context}: '${field}' must be at least 1 — got ${JSON.stringify(value)}.`);
196
+ }
197
+ const unit = RETENTION_UNITS[suffix];
198
+ if (unit === undefined) {
199
+ throw new Error(`${context}: '${field}' has an unsupported unit ${JSON.stringify(suffix)}.`);
200
+ }
201
+ return { amount: parsed, unit };
202
+ }
203
+ /**
204
+ * Collapse a TTL clause read back from ClickHouse into its comparable form.
205
+ *
206
+ * The server's own rendering is already canonical apart from whitespace, so
207
+ * this only collapses runs of blanks and trims — enough to compare clauses
208
+ * across formatting differences without pretending to normalize SQL.
209
+ *
210
+ * @param rendered - A TTL clause as extracted from `engine_full`
211
+ * @returns The clause with whitespace runs collapsed to single spaces
212
+ */
213
+ export function normalizeRenderedTtl(rendered) {
214
+ return rendered.replace(/\s+/g, ' ').trim();
215
+ }
216
+ /**
217
+ * Whether a TTL clause read back from a live table already expresses the
218
+ * intended retention.
219
+ *
220
+ * This is the exact predicate the rendered CronJob script implements in shell
221
+ * (an equality test against {@link ResolvedRetentionEntry.ttlRenderings}); it
222
+ * exists as a function so the comparison semantics — in particular the
223
+ * near-miss cases a substring probe gets wrong — are directly testable.
224
+ *
225
+ * @param currentClause - TTL clause extracted from `system.tables.engine_full`
226
+ * @param entry - The resolved retention entry being converged
227
+ * @returns True when no `MODIFY TTL` is needed
228
+ */
229
+ export function ttlAlreadyApplied(currentClause, entry) {
230
+ const normalized = normalizeRenderedTtl(currentClause);
231
+ return entry.ttlRenderings.includes(normalized);
232
+ }
233
+ /**
234
+ * Reject a collector component name that JavaScript's object model claims.
235
+ *
236
+ * Every name in `exporterNames` and `extensions` ends up as a MAPPING KEY in
237
+ * the rendered overlay, so `__proto__`, `constructor` and `prototype` are
238
+ * refused before they get there — see {@link assertSafeCollectorConfigKey} for
239
+ * the two silent failure modes. The error names the caller's own option path
240
+ * and the offending index.
241
+ *
242
+ * @param context - Entry point name for the error message
243
+ * @param field - The offending option, relative to `storage.persistentQueue`
244
+ * @param names - The supplied component names
245
+ * @throws Error when any name is an object-model member
246
+ */
247
+ function assertQueueComponentNames(context, field, names) {
248
+ names.forEach((name, index) => {
249
+ try {
250
+ assertSafeCollectorConfigKey(name);
251
+ }
252
+ catch (cause) {
253
+ throw new Error(`${context}: 'storage.persistentQueue.${field}[${index}]' is ` +
254
+ `${JSON.stringify(name)}, which cannot name a collector component. ` +
255
+ `${cause instanceof Error ? cause.message : String(cause)}`);
256
+ }
257
+ });
258
+ }
259
+ /**
260
+ * Resolve and validate the build-time storage options.
261
+ *
262
+ * @param context - Entry point name for every error message
263
+ * @param options - Build-time storage options (omit for the PVC default)
264
+ * @returns The resolved options, with retention expanded per table
265
+ * @throws Error when a retention duration is unparseable, when an
266
+ * S3-specific option is set on the PVC default, or when a queue component
267
+ * name is an object-model member (see {@link assertQueueComponentNames})
268
+ */
269
+ export function resolveClickStackStorage(context, options) {
270
+ const mode = options?.mode ?? 'pvc';
271
+ if (mode === 'pvc' && (options?.diskType !== undefined || options?.policyName !== undefined)) {
272
+ throw new Error(`${context}: storage mode 'pvc' (the default) rejects 'storage.diskType' and ` +
273
+ `'storage.policyName' — they describe an object-storage-backed ClickHouse. Set ` +
274
+ `storage.mode: 's3' to declare one.`);
275
+ }
276
+ // LIVE FINDING (ClickHouse 25.7, kind + MinIO): a table on an
277
+ // `s3_plain_rewritable` policy rejects the retention DDL outright —
278
+ //
279
+ // Code: 344. DB::Exception: ALTER TABLE commands are not supported on
280
+ // immutable disk 's3', except for setting and comment alteration.
281
+ // (SUPPORT_IS_DISABLED)
282
+ //
283
+ // `SETTINGS materialize_ttl_after_modify = 0` does not help: it only skips
284
+ // the materialization MUTATION, and it is the metadata ALTER itself that the
285
+ // immutable metadata type refuses. The same statement against a table on the
286
+ // server's local policy succeeds, so this is specific to the disk type and
287
+ // not to the statement. Rendering the CronJob anyway would ship a job that
288
+ // CrashLoops forever while reporting a retention policy that is never
289
+ // applied, so the combination is rejected here instead.
290
+ if (options?.diskType === 's3_plain_rewritable' && options?.retention !== undefined) {
291
+ throw new Error(`${context}: 'storage.retention' cannot be applied to a ClickHouse whose ` +
292
+ `'storage.diskType' is 's3_plain_rewritable'. Retention converges through ` +
293
+ `\`ALTER TABLE … MODIFY TTL\`, and ClickHouse refuses every ALTER except settings and ` +
294
+ `comments on that immutable metadata type ("ALTER TABLE commands are not supported on ` +
295
+ `immutable disk", SUPPORT_IS_DISABLED) — so the CronJob would fail on every run while ` +
296
+ `reporting a retention policy that never takes effect. Use diskType: 's3' (with ` +
297
+ `storage.backup on the ClickHouse side) if you need TypeKro-managed TTL, or drop ` +
298
+ `'storage.retention' and keep the TTL the collector's own migrations create.`);
299
+ }
300
+ const retentionEntries = [];
301
+ for (const signal of ['logs', 'traces', 'metrics']) {
302
+ const duration = options?.retention?.[signal];
303
+ if (duration === undefined)
304
+ continue;
305
+ const { amount, unit } = parseRetentionDuration(context, `storage.retention.${signal}`, duration);
306
+ for (const target of CLICKSTACK_RETENTION_TABLES[signal]) {
307
+ retentionEntries.push({
308
+ ...target,
309
+ signal,
310
+ duration,
311
+ // `toDateTime(...)` wraps the column deliberately: the collector's own
312
+ // migration renders its TTL as `toDateTime(Timestamp) + toIntervalDay(30)`
313
+ // (LIVE-VERIFIED against chart 3.2.0), and the timestamp columns are
314
+ // DateTime64. Emitting the same form keeps the stored expression — and
315
+ // therefore the idempotence probe below — directly comparable.
316
+ ttlExpression: `toDateTime(${target.column}) + INTERVAL ${amount} ${unit} DELETE`,
317
+ ttlRenderings: [
318
+ // Normalized AST rendering — exactly what ClickHouse stores and what
319
+ // `engine_full` / `create_table_query` return. The default `DELETE`
320
+ // action is not part of the rendered clause.
321
+ `toDateTime(${target.column}) + toInterval${unit.charAt(0)}${unit
322
+ .slice(1)
323
+ .toLowerCase()}(${amount})`,
324
+ // Source spelling, in case a release renders the clause verbatim.
325
+ `toDateTime(${target.column}) + INTERVAL ${amount} ${unit}`,
326
+ ],
327
+ });
328
+ }
329
+ }
330
+ const queue = options?.persistentQueue;
331
+ const exporterNames = queue?.exporterNames ?? DEFAULT_QUEUE_EXPORTER_NAMES;
332
+ if (queue?.enabled === true && exporterNames.length === 0) {
333
+ throw new Error(`${context}: 'storage.persistentQueue.exporterNames' cannot be empty — the queue exists ` +
334
+ `to back an exporter's \`sending_queue\`, and an empty list would render a ` +
335
+ `\`file_storage\` extension that nothing sends through. Omit the option to use ` +
336
+ `${JSON.stringify(DEFAULT_QUEUE_EXPORTER_NAMES)}.`);
337
+ }
338
+ const queueExtensions = queue?.extensions ?? DEFAULT_QUEUE_EXTENSIONS;
339
+ if (queue?.enabled === true && !queueExtensions.includes(QUEUE_EXTENSION_NAME)) {
340
+ throw new Error(`${context}: 'storage.persistentQueue.extensions' must include ` +
341
+ `'${QUEUE_EXTENSION_NAME}' — the list REPLACES the supervisor's own ` +
342
+ `\`service.extensions\`, so leaving it out means the file_storage extension the ` +
343
+ `exporters reference is never started and the collector refuses the config. Got ` +
344
+ `${JSON.stringify([...queueExtensions])}.`);
345
+ }
346
+ if (queue?.enabled === true) {
347
+ // BOTH lists carry COMPONENT NAMES, and a component name becomes a mapping
348
+ // key in the rendered overlay — `exporters.<name>` directly, and an
349
+ // extension instance name under `extensions.<name>`. JavaScript reserves a
350
+ // few of those, and the failure was silent in both directions: a
351
+ // `__proto__` exporter name rendered as `exporters: {}` (the overlay clone
352
+ // re-parented the copy instead of copying the key) while the merge's
353
+ // `key in target` test could hand `Object.prototype` to the deep merge and
354
+ // mutate it process-wide. Rejected
355
+ // HERE, at the option that supplied the name, so the message names the
356
+ // caller's own path rather than a position inside a fragment. The merge
357
+ // itself re-checks every key independently — see
358
+ // {@link assertSafeCollectorConfigKey}.
359
+ assertQueueComponentNames(context, 'exporterNames', exporterNames);
360
+ assertQueueComponentNames(context, 'extensions', queueExtensions);
361
+ }
362
+ return {
363
+ mode,
364
+ ...(options?.diskType !== undefined && { diskType: options.diskType }),
365
+ ...(options?.policyName !== undefined && { policyName: options.policyName }),
366
+ ...(options?.retention !== undefined && { retention: options.retention }),
367
+ retentionEntries,
368
+ retentionSchedule: options?.retentionSchedule ?? DEFAULT_RETENTION_SCHEDULE,
369
+ retentionImage: options?.retentionImage ?? DEFAULT_RETENTION_IMAGE,
370
+ ...(queue?.enabled === true && {
371
+ persistentQueue: {
372
+ directory: queue.directory ?? DEFAULT_QUEUE_DIRECTORY,
373
+ // Always a real claim size: the ephemeral fallback is gone on purpose
374
+ // (see ClickStackPersistentQueueOptions.size).
375
+ size: queue.size ?? DEFAULT_QUEUE_SIZE,
376
+ ...(queue.storageClassName !== undefined && {
377
+ storageClassName: queue.storageClassName,
378
+ }),
379
+ accessModes: [...QUEUE_ACCESS_MODES],
380
+ exporterNames,
381
+ extensions: queueExtensions,
382
+ },
383
+ }),
384
+ };
385
+ }
386
+ /**
387
+ * Reject more than one gateway collector replica alongside a persistent queue.
388
+ *
389
+ * UNCONDITIONAL: `persistentQueue` means exactly one collector replica, and no
390
+ * volume choice changes that. The `file_storage` extension keeps the queue in a
391
+ * bbolt database, and bbolt takes an EXCLUSIVE FILE LOCK for the lifetime of
392
+ * the handle — the extension's README is explicit that one directory serves one
393
+ * collector instance, and collector-contrib issue #5894 is the report of the
394
+ * second instance hanging on that lock. So a second replica either blocks
395
+ * forever on `Open` or, where the lock does not hold across a node boundary,
396
+ * writes the same pages as the first.
397
+ *
398
+ * The claim's `ReadWriteOnce` mode is a second, weaker line of defence (extra
399
+ * Pods on other nodes stay `Pending` on `Multi-Attach`), not the reason.
400
+ * `ReadWriteMany` was previously accepted as a way to lift this guard; it is
401
+ * gone, because a shared filesystem hands both replicas the same locked
402
+ * database rather than giving each its own.
403
+ *
404
+ * PER-REPLICA STORAGE IS THE REAL ALTERNATIVE, and it is not modelled here:
405
+ * it needs the upstream chart's `mode: statefulset` with `volumeClaimTemplates`
406
+ * so every replica gets its OWN queue directory. This composition renders the
407
+ * gateway as the chart's default Deployment and mounts one standalone claim, so
408
+ * the error names that path as future work rather than pretending it exists.
409
+ *
410
+ * @param context - Entry point name for the error message
411
+ * @param resolved - Resolved storage options
412
+ * @param replicaCount - Collector replica count from the build-time chart
413
+ * values, when one was set
414
+ * @throws Error when a persistent queue is requested with more than one replica
415
+ */
416
+ export function assertQueueReplicaCompatible(context, resolved, replicaCount) {
417
+ if (resolved.persistentQueue === undefined)
418
+ return;
419
+ if (typeof replicaCount !== 'number' || replicaCount <= 1)
420
+ return;
421
+ throw new Error(`${context}: 'storage.persistentQueue' requires exactly ONE gateway collector replica — ` +
422
+ `got values['otel-collector'].replicaCount = ${replicaCount}. The queue is a bbolt ` +
423
+ `database owned by the OTel 'file_storage' extension, and bbolt holds an exclusive file ` +
424
+ `lock on it: a second collector opening the same database blocks on that lock ` +
425
+ `(opentelemetry-collector-contrib issue #5894, and the filestorage README's "only one ` +
426
+ `collector instance per directory"), and loses the queue's integrity if the lock is not ` +
427
+ `honoured across nodes. A shared ReadWriteMany volume does NOT help — it hands both ` +
428
+ `replicas the same locked database. Drop to one replica. Giving every replica its own ` +
429
+ `queue would need the chart's 'mode: statefulset' with volumeClaimTemplates, which this ` +
430
+ `composition does not model today.`);
431
+ }
432
+ /**
433
+ * Render the idempotent retention DDL script.
434
+ *
435
+ * IDEMPOTENCE, and why this is a CronJob rather than a one-shot Job: the OTel
436
+ * tables do not exist until the gateway collector's goose migrations have run,
437
+ * and TypeKro does not own their DDL — so the script waits for each table to
438
+ * appear, and re-checks on every run. It only issues `MODIFY TTL` when the
439
+ * table's current TTL clause is not already the intended one, so a converged
440
+ * cluster does no metadata churn.
441
+ *
442
+ * THE IDEMPOTENCE PROBE COMPARES WHOLE CLAUSES. It extracts the complete TTL
443
+ * clause out of `system.tables.engine_full` — everything between `TTL ` and
444
+ * the trailing ` SETTINGS …`, whitespace-collapsed — and tests it for EQUALITY
445
+ * against {@link ResolvedRetentionEntry.ttlRenderings}. A substring probe was
446
+ * wrong in both directions (see the doc on `ttlRenderings`), and the actual
447
+ * clause is echoed on a mismatch so a rendering change is visible in the Job
448
+ * log instead of showing up as silent per-run churn.
449
+ *
450
+ * Notes on the SQL: the extraction deliberately contains no backslash escapes
451
+ * and no `$` anchors — it strips the `SETTINGS` tail with `replaceRegexpOne`
452
+ * first and uses the POSIX class `[[:space:]]` — because the expression has to
453
+ * survive being nested inside a double-quoted shell command substitution.
454
+ *
455
+ * @param resolved - Resolved storage options carrying `retentionEntries`
456
+ * @returns A POSIX shell script for `sh -c`
457
+ */
458
+ export function renderRetentionScript(resolved) {
459
+ const lines = [
460
+ 'set -eu',
461
+ // The chart's ConfigMap/Secret supply the connection, so this works
462
+ // identically in inline and Secret-backed credential modes. The braced
463
+ // forms below are POSIX parameter expansion (suffix/prefix stripping and
464
+ // defaults) — the only places braces are actually required.
465
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: POSIX shell suffix stripping
466
+ 'HOST="${CLICKHOUSE_SERVER_ENDPOINT%%:*}"',
467
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: POSIX shell prefix stripping
468
+ 'PORT="${CLICKHOUSE_SERVER_ENDPOINT##*:}"',
469
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: POSIX shell default value
470
+ 'DB="${HYPERDX_OTEL_EXPORTER_CLICKHOUSE_DATABASE:-default}"',
471
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: POSIX shell default value
472
+ 'USER="${CLICKHOUSE_USER:-default}"',
473
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: POSIX shell default value
474
+ 'PASSWORD="${CLICKHOUSE_PASSWORD:-}"',
475
+ // No port in the endpoint: the stripping above left it unchanged.
476
+ 'if [ "$PORT" = "$CLICKHOUSE_SERVER_ENDPOINT" ]; then PORT=9000; fi',
477
+ 'run_query() {',
478
+ ' clickhouse-client --host "$HOST" --port "$PORT" --user "$USER"' +
479
+ ' --password "$PASSWORD" --database "$DB" --query "$1"',
480
+ '}',
481
+ ];
482
+ for (const entry of resolved.retentionEntries) {
483
+ const ttl = entry.ttlExpression;
484
+ // Whole-clause equality — one `[ "$CURRENT" != … ]` test per accepted
485
+ // rendering, so ANY difference (a shorter interval that is a prefix of the
486
+ // intended one, an extra WHERE/GROUP BY, a second TTL entry) is a
487
+ // mismatch and gets re-applied.
488
+ const mismatch = entry.ttlRenderings
489
+ .map((rendering) => `[ "$CURRENT" != "${rendering}" ]`)
490
+ .join(' && ');
491
+ lines.push('', `# ${entry.signal}: ${entry.table} -> ${entry.duration}`, `if [ "$(run_query "EXISTS TABLE \\\`${entry.table}\\\`")" = "1" ]; then`,
492
+ // Strip the ` SETTINGS …` tail, take everything after `TTL `, collapse
493
+ // whitespace. Empty when the table carries no TTL at all.
494
+ ` CURRENT="$(run_query "SELECT trim(replaceRegexpAll(` +
495
+ `extract(replaceRegexpOne(engine_full, ' SETTINGS .*', ''), 'TTL (.*)'),` +
496
+ ` '[[:space:]]+', ' '))` +
497
+ ` FROM system.tables WHERE database = currentDatabase() AND name = '${entry.table}'")"`, ` if ${mismatch}; then`, ` echo "Applying TTL ${ttl} to ${entry.table} (current: [$CURRENT])"`,
498
+ // materialize_ttl_after_modify = 0: the materialization pass is a
499
+ // MUTATION, which s3_plain_rewritable does not support. Expiry still
500
+ // happens during merges.
501
+ ` run_query "ALTER TABLE \\\`${entry.table}\\\` MODIFY TTL ${ttl}` +
502
+ ` SETTINGS materialize_ttl_after_modify = 0"`, ' else', ` echo "TTL on ${entry.table} already matches ${entry.duration}"`, ' fi', 'else', ` echo "Table ${entry.table} does not exist yet; retention will be applied on a later run"`, 'fi');
503
+ }
504
+ lines.push('', 'echo "Retention convergence complete"', '');
505
+ return lines.join('\n');
506
+ }
507
+ /**
508
+ * The persistent queue's contribution to the collector-config overlay.
509
+ *
510
+ * ⚠️ A STRUCTURED FRAGMENT, NOT YAML TEXT, and that is the whole point. This
511
+ * used to return a YAML string that the values mapper CONCATENATED onto the
512
+ * ingest-pipeline string. Both opened a top-level `service:` key, so the
513
+ * rendered `custom.config.yaml` declared `service` twice and the OpAMP
514
+ * supervisor rejected the WHOLE file on every poll:
515
+ *
516
+ * Could not merge local config file: …/custom/custom.config.yaml
517
+ * yaml: unmarshal errors: line 18: mapping key "service" already defined at line 1
518
+ *
519
+ * The agent then ran with NEITHER the ingest pipelines NOR the queue, while
520
+ * the Pod still reported Ready off the supervisor's own `health_check` — so
521
+ * enabling the queue was a silent no-op that also took OTLP ingestion down.
522
+ * Fragments are merged by `mergeCollectorConfig` (see
523
+ * `utils/collector-config.ts`) and serialised exactly once, which makes a
524
+ * duplicate key unrepresentable.
525
+ *
526
+ * ⚠️ The YAML lists here REPLACE the supervisor's own lists (the chart's
527
+ * `customConfig` is a merge, not a deep list append) — see the warning on
528
+ * {@link ClickStackPersistentQueueOptions}. `service.extensions` is a sequence,
529
+ * so it UNIONS with any other fragment's contribution before that replacement
530
+ * happens.
531
+ *
532
+ * Every name in `exporterNames` gets its own `sending_queue.storage`. A name
533
+ * the agent does not define is inert rather than fatal — see
534
+ * {@link DEFAULT_QUEUE_EXPORTER_NAMES} for why it cannot be checked here.
535
+ *
536
+ * ⚠️ THE EXPORTER MAP IS BUILT KEY BY KEY, on a NULL-PROTOTYPE dictionary, and
537
+ * every name is re-checked. It used to be an `Object.fromEntries` over
538
+ * `exporterNames`, which is honest enough on its own — `fromEntries` DEFINES an
539
+ * own property, so it does not pollute — but the overlay merge then copied the
540
+ * map with `copy[key] = …` onto a plain `{}`, where assigning `__proto__` calls
541
+ * the inherited SETTER and re-parents the copy instead of adding a key. An
542
+ * `exporterNames: ['__proto__']` install therefore rendered `exporters: {}`: a
543
+ * queue that configured nothing, reported no error, and left the real exporter
544
+ * on its in-memory queue. `resolveClickStackStorage` rejects such a name at the
545
+ * option, and this function refuses it again so no caller holding a
546
+ * hand-built `ResolvedClickStackStorage` can route around that.
547
+ *
548
+ * @param queue - Resolved persistent-queue configuration
549
+ * @returns A fragment for `global.otelCollector.customConfig`
550
+ * @throws Error when a component name is a JavaScript object-model member
551
+ */
552
+ export function persistentQueueConfigFragment(queue) {
553
+ const exporters = Object.create(null);
554
+ for (const exporterName of queue.exporterNames) {
555
+ assertSafeCollectorConfigKey(exporterName, ['exporters']);
556
+ // `defineProperty`, not assignment: on a prototype-less dictionary the two
557
+ // are equivalent, and spelling it out keeps the guarantee local — this line
558
+ // cannot become a setter call however the dictionary above is later built.
559
+ Object.defineProperty(exporters, exporterName, {
560
+ value: { sending_queue: { enabled: true, storage: QUEUE_EXTENSION_NAME } },
561
+ enumerable: true,
562
+ writable: true,
563
+ configurable: true,
564
+ });
565
+ }
566
+ for (const extensionName of queue.extensions) {
567
+ // A `service.extensions` entry is a sequence item here, but it NAMES an
568
+ // extension instance whose name is a mapping key under `extensions:` — the
569
+ // same guard applies, at the same construction time.
570
+ assertSafeCollectorConfigKey(extensionName, ['service', 'extensions']);
571
+ }
572
+ return {
573
+ extensions: {
574
+ [QUEUE_EXTENSION_NAME]: {
575
+ directory: queue.directory,
576
+ create_directory: true,
577
+ },
578
+ },
579
+ exporters,
580
+ service: { extensions: [...queue.extensions] },
581
+ };
582
+ }
583
+ /**
584
+ * Chart values that mount the queue's PersistentVolumeClaim on the collector.
585
+ *
586
+ * The claim is a STANDALONE PersistentVolumeClaim owned by the composition
587
+ * (rendered next to the retention CronJob) and referenced here by
588
+ * `claimName` — never an `emptyDir` and never a *generic ephemeral volume*.
589
+ * Kubernetes deletes a generic ephemeral volume's PVC together with the Pod
590
+ * that owns it, so an ephemeral claim would be destroyed by exactly the
591
+ * collector restart the queue exists to survive.
592
+ *
593
+ * The collector is also PINNED to one replica, unconditionally: the queue is a
594
+ * bbolt database under an exclusive file lock, so a second replica cannot open
595
+ * it at all — see {@link assertQueueReplicaCompatible}, which rejects a
596
+ * build-time `replicaCount` above 1 at construction. The pin makes that
597
+ * guarantee explicit in the rendered values against later drift.
598
+ *
599
+ * ⚠️ `replicaCount: 1` IS NOT ENOUGH ON ITS OWN, which is why
600
+ * `rollout.strategy: 'Recreate'` travels with it. One replica bounds the
601
+ * STEADY state, not the state DURING a rollout: the chart leaves the
602
+ * Deployment on Kubernetes' default `RollingUpdate` (values.yaml `rollout`,
603
+ * collector chart 0.146.x), whose default `maxSurge: 25%` rounds UP to one
604
+ * extra Pod. A rollout therefore creates the replacement Pod while the old one
605
+ * is still running and still holding both the claim and the queue, and that
606
+ * overlap fails in one of two ways depending on where the replacement lands:
607
+ *
608
+ * - **On another node — a stuck rollout.** The ReadWriteOnce claim is still
609
+ * attached to the old Pod's node, so the replacement never leaves
610
+ * `ContainerCreating` (`Multi-Attach error for volume`). `RollingUpdate`
611
+ * will not terminate the old Pod until the new one is Ready, and
612
+ * `maxUnavailable: 25%` of one replica rounds DOWN to zero, so nothing gives:
613
+ * the rollout DEADLOCKS until `progressDeadlineSeconds` expires.
614
+ * - **On the same node — a silent two-writer window.** The replacement starts,
615
+ * and its `file_storage` extension cannot take bbolt's exclusive lock while
616
+ * the old collector holds it. Readiness does not notice: it comes from the
617
+ * OpAMP supervisor's own `health_check`, not from the agent's extensions
618
+ * (the same reason the missing `custom-config` mount below stayed invisible),
619
+ * so the Pod reports Ready and the rollout "succeeds" over a queue the new
620
+ * collector could not open. LIVE-OBSERVED on a single-node cluster: under
621
+ * `RollingUpdate` the replacement went Ready in under 10s.
622
+ *
623
+ * `Recreate` removes the overlap entirely: the old Pod is deleted, its claim
624
+ * detaches and its lock is released, and only then is the replacement created.
625
+ *
626
+ * The cost is a brief gateway outage on every rollout, and the persistent
627
+ * queue is precisely what makes that cost acceptable: producers upstream of
628
+ * the gateway retry, and telemetry the gateway already accepted is on the
629
+ * claim rather than in the departing Pod's memory, so the replacement resumes
630
+ * draining the same queue instead of starting from an empty one.
631
+ *
632
+ * `rollout.rollingUpdate` needs no clearing here. The chart's Deployment
633
+ * template emits that block only under `if eq .Values.rollout.strategy
634
+ * "RollingUpdate"`, so `Recreate` drops it — which matters, because a
635
+ * Deployment carrying `strategy.type: Recreate` alongside a
636
+ * `strategy.rollingUpdate` block is rejected by the API server.
637
+ *
638
+ * ⚠️ THE CHART'S OWN `custom-config` VOLUME IS RE-EMITTED HERE, and must be:
639
+ * Helm REPLACES a list override instead of appending to it, and these are the
640
+ * lists through which the chart mounts the ConfigMap it renders from
641
+ * `global.otelCollector.customConfig` — the overlay that carries the ingest
642
+ * pipelines AND this queue's own `file_storage` wiring. Dropping it makes the
643
+ * OpAMP supervisor fail to read `custom.config.yaml` and never start the
644
+ * agent's receivers, with the Pod still Ready. See
645
+ * {@link CHART_CUSTOM_CONFIG_VOLUME_NAME} for the live evidence.
646
+ *
647
+ * @param queue - Resolved persistent-queue configuration
648
+ * @param claimName - Name of the PVC the composition creates
649
+ * ({@link clickStackQueueClaimName})
650
+ * @returns Values under the `otel-collector` subchart alias
651
+ */
652
+ export function renderPersistentQueueValues(queue, claimName) {
653
+ return {
654
+ 'otel-collector': {
655
+ extraVolumes: [
656
+ // The chart's own entry, re-emitted because Helm replaces the list.
657
+ {
658
+ name: CHART_CUSTOM_CONFIG_VOLUME_NAME,
659
+ configMap: { name: CHART_CUSTOM_CONFIG_CONFIG_MAP_NAME, optional: true },
660
+ },
661
+ { name: QUEUE_VOLUME_NAME, persistentVolumeClaim: { claimName } },
662
+ ],
663
+ extraVolumeMounts: [
664
+ {
665
+ name: CHART_CUSTOM_CONFIG_VOLUME_NAME,
666
+ mountPath: CHART_CUSTOM_CONFIG_MOUNT_PATH,
667
+ readOnly: true,
668
+ },
669
+ { name: QUEUE_VOLUME_NAME, mountPath: queue.directory },
670
+ ],
671
+ // Always pinned: the queue's bbolt database admits exactly one writer.
672
+ replicaCount: 1,
673
+ // …and one writer AT A TIME, which the replica count alone does not buy
674
+ // during a rollout. RollingUpdate surges a second Pod onto the same RWO
675
+ // claim and the same bbolt lock while the old one still holds both:
676
+ // Multi-Attach deadlock on another node, silent lock contention on the
677
+ // same one. Recreate drains first. The chart emits `rollingUpdate` only
678
+ // for the RollingUpdate branch, so there is nothing to clear.
679
+ rollout: { strategy: QUEUE_ROLLOUT_STRATEGY },
680
+ },
681
+ };
682
+ }
683
+ /**
684
+ * Spec of the standalone PersistentVolumeClaim backing the collector queue.
685
+ *
686
+ * @param queue - Resolved persistent-queue configuration
687
+ * @returns A `V1PersistentVolumeClaim.spec` object
688
+ */
689
+ export function renderPersistentQueueClaimSpec(queue) {
690
+ return {
691
+ accessModes: [...queue.accessModes],
692
+ resources: { requests: { storage: queue.size } },
693
+ ...(queue.storageClassName !== undefined && {
694
+ storageClassName: queue.storageClassName,
695
+ }),
696
+ };
697
+ }
698
+ //# sourceMappingURL=storage.js.map