typekro 0.24.1 → 0.26.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 (210) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/core/composition/context.d.ts +4 -0
  3. package/dist/core/composition/context.d.ts.map +1 -1
  4. package/dist/core/composition/context.js +1 -0
  5. package/dist/core/composition/context.js.map +1 -1
  6. package/dist/core/composition/imperative.d.ts.map +1 -1
  7. package/dist/core/composition/imperative.js +24 -3
  8. package/dist/core/composition/imperative.js.map +1 -1
  9. package/dist/core/deployment/direct-factory.d.ts +8 -1
  10. package/dist/core/deployment/direct-factory.d.ts.map +1 -1
  11. package/dist/core/deployment/direct-factory.js +80 -61
  12. package/dist/core/deployment/direct-factory.js.map +1 -1
  13. package/dist/core/deployment/engine.d.ts +2 -0
  14. package/dist/core/deployment/engine.d.ts.map +1 -1
  15. package/dist/core/deployment/engine.js +22 -1
  16. package/dist/core/deployment/engine.js.map +1 -1
  17. package/dist/core/deployment/kro-factory.d.ts +2 -0
  18. package/dist/core/deployment/kro-factory.d.ts.map +1 -1
  19. package/dist/core/deployment/kro-factory.js +47 -11
  20. package/dist/core/deployment/kro-factory.js.map +1 -1
  21. package/dist/core/deployment/kro-instance-safety.d.ts +24 -0
  22. package/dist/core/deployment/kro-instance-safety.d.ts.map +1 -0
  23. package/dist/core/deployment/kro-instance-safety.js +157 -0
  24. package/dist/core/deployment/kro-instance-safety.js.map +1 -0
  25. package/dist/core/deployment/readiness-waiter.d.ts.map +1 -1
  26. package/dist/core/deployment/readiness-waiter.js +17 -2
  27. package/dist/core/deployment/readiness-waiter.js.map +1 -1
  28. package/dist/core/deployment/rollback-manager.d.ts +1 -1
  29. package/dist/core/deployment/rollback-manager.d.ts.map +1 -1
  30. package/dist/core/deployment/rollback-manager.js +16 -9
  31. package/dist/core/deployment/rollback-manager.js.map +1 -1
  32. package/dist/core/deployment/schema-cel-evaluator.d.ts +5 -0
  33. package/dist/core/deployment/schema-cel-evaluator.d.ts.map +1 -0
  34. package/dist/core/deployment/schema-cel-evaluator.js +36 -0
  35. package/dist/core/deployment/schema-cel-evaluator.js.map +1 -0
  36. package/dist/core/deployment/singleton-gitops.d.ts.map +1 -1
  37. package/dist/core/deployment/singleton-gitops.js +9 -2
  38. package/dist/core/deployment/singleton-gitops.js.map +1 -1
  39. package/dist/core/serialization/core.d.ts.map +1 -1
  40. package/dist/core/serialization/core.js +17 -4
  41. package/dist/core/serialization/core.js.map +1 -1
  42. package/dist/core/serialization/schema.d.ts.map +1 -1
  43. package/dist/core/serialization/schema.js +19 -4
  44. package/dist/core/serialization/schema.js.map +1 -1
  45. package/dist/core/serialization/yaml.d.ts.map +1 -1
  46. package/dist/core/serialization/yaml.js +15 -1
  47. package/dist/core/serialization/yaml.js.map +1 -1
  48. package/dist/core/types/kubernetes.d.ts +9 -0
  49. package/dist/core/types/kubernetes.d.ts.map +1 -1
  50. package/dist/core/types/serialization.d.ts +9 -0
  51. package/dist/core/types/serialization.d.ts.map +1 -1
  52. package/dist/factories/clickhouse/compositions/clickhouse-operator-bootstrap.d.ts +1 -1
  53. package/dist/factories/clickhouse/compositions/clickhouse-operator-bootstrap.js +1 -1
  54. package/dist/factories/clickhouse/index.d.ts +4 -1
  55. package/dist/factories/clickhouse/index.d.ts.map +1 -1
  56. package/dist/factories/clickhouse/index.js +4 -1
  57. package/dist/factories/clickhouse/index.js.map +1 -1
  58. package/dist/factories/clickstack/compositions/clickstack-bootstrap.d.ts +1 -1
  59. package/dist/factories/clickstack/compositions/clickstack-bootstrap.js +1 -1
  60. package/dist/factories/clickstack/compositions/k8s-telemetry.d.ts +1 -1
  61. package/dist/factories/clickstack/compositions/k8s-telemetry.js +1 -1
  62. package/dist/factories/clickstack/index.d.ts +1 -1
  63. package/dist/factories/clickstack/index.js +1 -1
  64. package/dist/factories/cnpg/compositions/cnpg-bootstrap.d.ts +1 -1
  65. package/dist/factories/cnpg/compositions/cnpg-bootstrap.js +1 -1
  66. package/dist/factories/cnpg/index.d.ts +1 -1
  67. package/dist/factories/cnpg/index.js +1 -1
  68. package/dist/factories/dagster/index.d.ts +1 -1
  69. package/dist/factories/dagster/index.js +1 -1
  70. package/dist/factories/index.d.ts +2 -0
  71. package/dist/factories/index.d.ts.map +1 -1
  72. package/dist/factories/index.js +8 -0
  73. package/dist/factories/index.js.map +1 -1
  74. package/dist/factories/inngest/compositions/inngest-bootstrap.d.ts +1 -1
  75. package/dist/factories/inngest/compositions/inngest-bootstrap.js +1 -1
  76. package/dist/factories/inngest/index.d.ts +1 -1
  77. package/dist/factories/inngest/index.js +1 -1
  78. package/dist/factories/kro/resource-graph-definition.d.ts.map +1 -1
  79. package/dist/factories/kro/resource-graph-definition.js +17 -1
  80. package/dist/factories/kro/resource-graph-definition.js.map +1 -1
  81. package/dist/factories/nats/compositions/index.d.ts +2 -0
  82. package/dist/factories/nats/compositions/index.d.ts.map +1 -0
  83. package/dist/factories/nats/compositions/index.js +2 -0
  84. package/dist/factories/nats/compositions/index.js.map +1 -0
  85. package/dist/factories/nats/compositions/nats-bootstrap.d.ts +49 -0
  86. package/dist/factories/nats/compositions/nats-bootstrap.d.ts.map +1 -0
  87. package/dist/factories/nats/compositions/nats-bootstrap.js +135 -0
  88. package/dist/factories/nats/compositions/nats-bootstrap.js.map +1 -0
  89. package/dist/factories/nats/index.d.ts +5 -0
  90. package/dist/factories/nats/index.d.ts.map +1 -0
  91. package/dist/factories/nats/index.js +5 -0
  92. package/dist/factories/nats/index.js.map +1 -0
  93. package/dist/factories/nats/resources/helm.d.ts +28 -0
  94. package/dist/factories/nats/resources/helm.d.ts.map +1 -0
  95. package/dist/factories/nats/resources/helm.js +39 -0
  96. package/dist/factories/nats/resources/helm.js.map +1 -0
  97. package/dist/factories/nats/resources/index.d.ts +3 -0
  98. package/dist/factories/nats/resources/index.d.ts.map +1 -0
  99. package/dist/factories/nats/resources/index.js +3 -0
  100. package/dist/factories/nats/resources/index.js.map +1 -0
  101. package/dist/factories/nats/resources/jetstream.d.ts +13 -0
  102. package/dist/factories/nats/resources/jetstream.d.ts.map +1 -0
  103. package/dist/factories/nats/resources/jetstream.js +105 -0
  104. package/dist/factories/nats/resources/jetstream.js.map +1 -0
  105. package/dist/factories/nats/types.d.ts +91 -0
  106. package/dist/factories/nats/types.d.ts.map +1 -0
  107. package/dist/factories/nats/types.js +72 -0
  108. package/dist/factories/nats/types.js.map +1 -0
  109. package/dist/factories/ory/compositions/ory-identity-stack.d.ts +1 -1
  110. package/dist/factories/ory/types.d.ts +2 -2
  111. package/dist/factories/rook/compositions/index.d.ts +4 -0
  112. package/dist/factories/rook/compositions/index.d.ts.map +1 -0
  113. package/dist/factories/rook/compositions/index.js +4 -0
  114. package/dist/factories/rook/compositions/index.js.map +1 -0
  115. package/dist/factories/rook/compositions/object-storage-claim.d.ts +32 -0
  116. package/dist/factories/rook/compositions/object-storage-claim.d.ts.map +1 -0
  117. package/dist/factories/rook/compositions/object-storage-claim.js +63 -0
  118. package/dist/factories/rook/compositions/object-storage-claim.js.map +1 -0
  119. package/dist/factories/rook/compositions/rook-ceph-helm-repository.d.ts +12 -0
  120. package/dist/factories/rook/compositions/rook-ceph-helm-repository.d.ts.map +1 -0
  121. package/dist/factories/rook/compositions/rook-ceph-helm-repository.js +25 -0
  122. package/dist/factories/rook/compositions/rook-ceph-helm-repository.js.map +1 -0
  123. package/dist/factories/rook/compositions/rook-ceph-operator-bootstrap.d.ts +2 -0
  124. package/dist/factories/rook/compositions/rook-ceph-operator-bootstrap.d.ts.map +1 -0
  125. package/dist/factories/rook/compositions/rook-ceph-operator-bootstrap.js +2 -0
  126. package/dist/factories/rook/compositions/rook-ceph-operator-bootstrap.js.map +1 -0
  127. package/dist/factories/rook/compositions/rook-ceph-operator-installation.d.ts +67 -0
  128. package/dist/factories/rook/compositions/rook-ceph-operator-installation.d.ts.map +1 -0
  129. package/dist/factories/rook/compositions/rook-ceph-operator-installation.js +71 -0
  130. package/dist/factories/rook/compositions/rook-ceph-operator-installation.js.map +1 -0
  131. package/dist/factories/rook/index.d.ts +15 -0
  132. package/dist/factories/rook/index.d.ts.map +1 -0
  133. package/dist/factories/rook/index.js +15 -0
  134. package/dist/factories/rook/index.js.map +1 -0
  135. package/dist/factories/rook/resources/bucket-storage-class.d.ts +12 -0
  136. package/dist/factories/rook/resources/bucket-storage-class.d.ts.map +1 -0
  137. package/dist/factories/rook/resources/bucket-storage-class.js +29 -0
  138. package/dist/factories/rook/resources/bucket-storage-class.js.map +1 -0
  139. package/dist/factories/rook/resources/ceph-object-store-user.d.ts +14 -0
  140. package/dist/factories/rook/resources/ceph-object-store-user.d.ts.map +1 -0
  141. package/dist/factories/rook/resources/ceph-object-store-user.js +42 -0
  142. package/dist/factories/rook/resources/ceph-object-store-user.js.map +1 -0
  143. package/dist/factories/rook/resources/ceph-object-store.d.ts +27 -0
  144. package/dist/factories/rook/resources/ceph-object-store.d.ts.map +1 -0
  145. package/dist/factories/rook/resources/ceph-object-store.js +56 -0
  146. package/dist/factories/rook/resources/ceph-object-store.js.map +1 -0
  147. package/dist/factories/rook/resources/helm.d.ts +18 -0
  148. package/dist/factories/rook/resources/helm.d.ts.map +1 -0
  149. package/dist/factories/rook/resources/helm.js +45 -0
  150. package/dist/factories/rook/resources/helm.js.map +1 -0
  151. package/dist/factories/rook/resources/index.d.ts +6 -0
  152. package/dist/factories/rook/resources/index.d.ts.map +1 -0
  153. package/dist/factories/rook/resources/index.js +6 -0
  154. package/dist/factories/rook/resources/index.js.map +1 -0
  155. package/dist/factories/rook/resources/object-bucket-claim.d.ts +15 -0
  156. package/dist/factories/rook/resources/object-bucket-claim.d.ts.map +1 -0
  157. package/dist/factories/rook/resources/object-bucket-claim.js +52 -0
  158. package/dist/factories/rook/resources/object-bucket-claim.js.map +1 -0
  159. package/dist/factories/rook/types.d.ts +307 -0
  160. package/dist/factories/rook/types.d.ts.map +1 -0
  161. package/dist/factories/rook/types.js +239 -0
  162. package/dist/factories/rook/types.js.map +1 -0
  163. package/dist/factories/rook/utils/helm-values-mapper.d.ts +33 -0
  164. package/dist/factories/rook/utils/helm-values-mapper.d.ts.map +1 -0
  165. package/dist/factories/rook/utils/helm-values-mapper.js +60 -0
  166. package/dist/factories/rook/utils/helm-values-mapper.js.map +1 -0
  167. package/dist/factories/rook/utils/index.d.ts +2 -0
  168. package/dist/factories/rook/utils/index.d.ts.map +1 -0
  169. package/dist/factories/rook/utils/index.js +2 -0
  170. package/dist/factories/rook/utils/index.js.map +1 -0
  171. package/dist/factories/valkey/compositions/index.d.ts +2 -1
  172. package/dist/factories/valkey/compositions/index.d.ts.map +1 -1
  173. package/dist/factories/valkey/compositions/index.js +2 -1
  174. package/dist/factories/valkey/compositions/index.js.map +1 -1
  175. package/dist/factories/valkey/compositions/valkey-bootstrap.d.ts +21 -2
  176. package/dist/factories/valkey/compositions/valkey-bootstrap.d.ts.map +1 -1
  177. package/dist/factories/valkey/compositions/valkey-bootstrap.js +26 -136
  178. package/dist/factories/valkey/compositions/valkey-bootstrap.js.map +1 -1
  179. package/dist/factories/valkey/compositions/valkey-helm-repository.d.ts +16 -0
  180. package/dist/factories/valkey/compositions/valkey-helm-repository.d.ts.map +1 -0
  181. package/dist/factories/valkey/compositions/valkey-helm-repository.js +29 -0
  182. package/dist/factories/valkey/compositions/valkey-helm-repository.js.map +1 -0
  183. package/dist/factories/valkey/index.d.ts +6 -3
  184. package/dist/factories/valkey/index.d.ts.map +1 -1
  185. package/dist/factories/valkey/index.js +6 -3
  186. package/dist/factories/valkey/index.js.map +1 -1
  187. package/dist/factories/valkey/resources/helm.d.ts.map +1 -1
  188. package/dist/factories/valkey/resources/helm.js +13 -11
  189. package/dist/factories/valkey/resources/helm.js.map +1 -1
  190. package/dist/factories/valkey/types.d.ts +29 -16
  191. package/dist/factories/valkey/types.d.ts.map +1 -1
  192. package/dist/factories/valkey/types.js +34 -22
  193. package/dist/factories/valkey/types.js.map +1 -1
  194. package/dist/factories/valkey/utils/helm-values-mapper.d.ts +6 -1
  195. package/dist/factories/valkey/utils/helm-values-mapper.d.ts.map +1 -1
  196. package/dist/factories/valkey/utils/helm-values-mapper.js +52 -19
  197. package/dist/factories/valkey/utils/helm-values-mapper.js.map +1 -1
  198. package/dist/factories/webapp/compositions/index.d.ts +1 -1
  199. package/dist/factories/webapp/compositions/index.d.ts.map +1 -1
  200. package/dist/factories/webapp/compositions/index.js +1 -1
  201. package/dist/factories/webapp/compositions/index.js.map +1 -1
  202. package/dist/factories/webapp/compositions/web-app-with-processing.d.ts +9 -13
  203. package/dist/factories/webapp/compositions/web-app-with-processing.d.ts.map +1 -1
  204. package/dist/factories/webapp/compositions/web-app-with-processing.js +290 -278
  205. package/dist/factories/webapp/compositions/web-app-with-processing.js.map +1 -1
  206. package/dist/factories/webapp/types.d.ts +26 -7
  207. package/dist/factories/webapp/types.d.ts.map +1 -1
  208. package/dist/factories/webapp/types.js +0 -9
  209. package/dist/factories/webapp/types.js.map +1 -1
  210. package/package.json +9 -1
@@ -1,6 +1,6 @@
1
1
  import { kubernetesComposition } from '../../../core/composition/imperative.js';
2
2
  import { singleton } from '../../../core/singleton/singleton.js';
3
- import { isKubernetesRef } from '../../../utils/type-guards.js';
3
+ import { containsKubernetesRefs, isKubernetesRef } from '../../../utils/type-guards.js';
4
4
  import { cnpgBootstrap } from '../../cnpg/compositions/cnpg-bootstrap.js';
5
5
  import { cluster } from '../../cnpg/resources/cluster.js';
6
6
  import { secret } from '../../kubernetes/config/secret.js';
@@ -47,11 +47,10 @@ import { WebAppWithProcessingConfigSchema, WebAppWithProcessingStatusSchema, } f
47
47
  * - Inngest references `database.status.writeService` for the postgres URI → deploys after CNPG
48
48
  * - App references service names derived from resource names → deploys after all infra
49
49
  *
50
- * Operator install settings can be overridden per-deployment via
51
- * `spec.cnpgOperator` and `spec.valkeyOperator` e.g., to pin chart
52
- * versions or change the install namespace. Both fields are optional;
53
- * defaults install the latest pinned version into each operator's
54
- * system namespace.
50
+ * CNPG operator install settings can be overridden per deployment via
51
+ * `spec.cnpgOperator`. Valkey settings are graph-authoring-time options on
52
+ * `makeWebAppWithProcessing(...)` because singleton ownership cannot safely
53
+ * depend on a per-instance KRO schema value.
55
54
  *
56
55
  * @example
57
56
  * ```typescript
@@ -91,290 +90,303 @@ import { WebAppWithProcessingConfigSchema, WebAppWithProcessingStatusSchema, } f
91
90
  * });
92
91
  * ```
93
92
  */
94
- export const webAppWithProcessing = kubernetesComposition({
95
- name: 'web-app-with-processing',
96
- kind: 'WebAppWithProcessing',
97
- spec: WebAppWithProcessingConfigSchema,
98
- status: WebAppWithProcessingStatusSchema,
99
- }, (spec) => {
100
- const ns = spec.namespace ?? 'default';
101
- const appPort = spec.app.port ?? 3000;
102
- const appReplicas = spec.app.replicas ?? 1;
103
- const inngestReplicas = spec.processing.replicas ?? 1;
104
- // Defaults for optional DB fields. These literals are picked up by
105
- // `extractNullishDefaults` and propagated to the outer KRO schema as
106
- // `| default="..."` annotations (see schema.ts). Using schema-ref
107
- // fallbacks (e.g., `spec.name`) does NOT work in KRO mode because
108
- // the schema proxy is truthy and `??` never fires — KRO also has
109
- // no way to express a cross-field schema default statically.
110
- const dbName = spec.database.database ?? 'app';
111
- const dbOwner = spec.database.owner ?? 'app';
112
- // ── Operator bootstraps ────────────────────────────────────────────
113
- //
114
- // Install the CNPG and Valkey operators as part of the composition
115
- // so consumers get a fully self-contained stack. The bootstraps run
116
- // in their own system namespaces (not the app namespace) and install
117
- // cluster-scoped operators; the later `cluster()`/`valkey()` calls
118
- // create instances in the app namespace managed by those operators.
119
- //
120
- // Operators are cluster-scoped infrastructure one install per
121
- // cluster serves every consumer. Use singleton(...) so KRO-mode
122
- // consumers reference the shared operator boundary instead of
123
- // inlining the operator bootstrap resources into every app graph.
124
- //
125
- // Users who need a dedicated per-instance operator (multi-tenancy,
126
- // version testing, isolated failure domains) can override any
127
- // combination of fields via `spec.cnpgOperator` / `spec.valkeyOperator` —
128
- // e.g., `{ name: 'testapp-cnpg', namespace: 'testapp-cnpg-system', shared: false }`.
129
- // The spread puts user overrides AFTER the defaults so they win.
130
- // Operator bootstrap config: merge user overrides AFTER defaults.
131
- // Use explicit ?? fallbacks for name/namespace instead of relying on
132
- // object-literal-before-spread ordering the spread of an optional
133
- // spec field produces schema refs that get wrapped with omit(), but
134
- // metadata.name is required and cannot be omitted. The ?? ensures
135
- // the default is expressed as a KRO orValue/default, not omit().
136
- const _cnpg = singleton(cnpgBootstrap, {
137
- id: 'cnpg-operator',
138
- spec: {
139
- ...spec.cnpgOperator,
140
- name: spec.cnpgOperator?.name ?? 'cnpg-operator',
141
- namespace: spec.cnpgOperator?.namespace ?? 'cnpg-system',
142
- installCRDs: spec.cnpgOperator?.installCRDs ?? true,
143
- },
144
- });
145
- const _valkeyOp = singleton(valkeyBootstrap, {
146
- id: 'valkey-operator',
147
- spec: {
148
- ...spec.valkeyOperator,
149
- name: spec.valkeyOperator?.name ?? 'valkey-operator',
150
- namespace: spec.valkeyOperator?.namespace ?? 'valkey-operator-system',
151
- },
152
- });
153
- // ── PostgreSQL (CNPG) ──────────────────────────────────────────────
154
- const database = cluster({
155
- name: `${spec.name}-db`,
156
- namespace: ns,
157
- spec: {
158
- instances: spec.database.instances,
159
- storage: {
160
- size: spec.database.storageSize,
161
- ...(spec.database.storageClass ? { storageClass: spec.database.storageClass } : {}),
93
+ export function makeWebAppWithProcessing(options = {}) {
94
+ if (containsKubernetesRefs(options)) {
95
+ throw new Error('makeWebAppWithProcessing: valkeyOperator is a build-time option and must be concrete. ' +
96
+ 'Move schema/resource references into the per-instance webapp spec instead.');
97
+ }
98
+ if (options.valkeyOperator?.shared === false) {
99
+ throw new Error('makeWebAppWithProcessing: valkeyOperator.shared=false is no longer supported because the webapp consumes one cluster singleton. ' +
100
+ 'Install a dedicated valkeyBootstrap separately if you need an independently owned operator.');
101
+ }
102
+ const { shared: _deprecatedShared, ...valkeyOperatorOptions } = options.valkeyOperator ?? {};
103
+ const valkeyOperator = {
104
+ ...valkeyOperatorOptions,
105
+ name: valkeyOperatorOptions.name ?? 'valkey-operator',
106
+ namespace: valkeyOperatorOptions.namespace ?? 'valkey-operator-system',
107
+ };
108
+ return kubernetesComposition({
109
+ name: 'web-app-with-processing',
110
+ kind: 'WebAppWithProcessing',
111
+ spec: WebAppWithProcessingConfigSchema,
112
+ status: WebAppWithProcessingStatusSchema,
113
+ }, (spec) => {
114
+ const ns = spec.namespace ?? 'default';
115
+ const appPort = spec.app.port ?? 3000;
116
+ const appReplicas = spec.app.replicas ?? 1;
117
+ const inngestReplicas = spec.processing.replicas ?? 1;
118
+ // Defaults for optional DB fields. These literals are picked up by
119
+ // `extractNullishDefaults` and propagated to the outer KRO schema as
120
+ // `| default="..."` annotations (see schema.ts). Using schema-ref
121
+ // fallbacks (e.g., `spec.name`) does NOT work in KRO mode because
122
+ // the schema proxy is truthy and `??` never fires — KRO also has
123
+ // no way to express a cross-field schema default statically.
124
+ const dbName = spec.database.database ?? 'app';
125
+ const dbOwner = spec.database.owner ?? 'app';
126
+ // ── Operator bootstraps ────────────────────────────────────────────
127
+ //
128
+ // Install the CNPG and Valkey operators as part of the composition
129
+ // so consumers get a fully self-contained stack. The bootstraps run
130
+ // in their own system namespaces (not the app namespace) and install
131
+ // cluster-scoped operators; the later `cluster()`/`valkey()` calls
132
+ // create instances in the app namespace managed by those operators.
133
+ //
134
+ // Operators are cluster-scoped infrastructure one install per
135
+ // cluster serves every consumer. Use singleton(...) so KRO-mode
136
+ // consumers reference the shared operator boundary instead of
137
+ // inlining the operator bootstrap resources into every app graph.
138
+ //
139
+ // Users who need a dedicated per-instance operator (multi-tenancy,
140
+ // version testing, isolated failure domains) can override any
141
+ // combination of CNPG fields via `spec.cnpgOperator`.
142
+ // The spread puts user overrides AFTER the defaults so they win.
143
+ // Operator bootstrap config: merge user overrides AFTER defaults.
144
+ // Use explicit ?? fallbacks for name/namespace instead of relying on
145
+ // object-literal-before-spread ordering — the spread of an optional
146
+ // spec field produces schema refs that get wrapped with omit(), but
147
+ // metadata.name is required and cannot be omitted. The ?? ensures
148
+ // the default is expressed as a KRO orValue/default, not omit().
149
+ const _cnpg = singleton(cnpgBootstrap, {
150
+ id: 'cnpg-operator',
151
+ spec: {
152
+ ...spec.cnpgOperator,
153
+ name: spec.cnpgOperator?.name ?? 'cnpg-operator',
154
+ namespace: spec.cnpgOperator?.namespace ?? 'cnpg-system',
155
+ installCRDs: spec.cnpgOperator?.installCRDs ?? true,
162
156
  },
163
- bootstrap: {
164
- initdb: { database: dbName, owner: dbOwner },
157
+ });
158
+ const _valkeyOp = singleton(valkeyBootstrap, {
159
+ id: 'valkey-operator',
160
+ spec: valkeyOperator,
161
+ });
162
+ // ── PostgreSQL (CNPG) ──────────────────────────────────────────────
163
+ const database = cluster({
164
+ name: `${spec.name}-db`,
165
+ namespace: ns,
166
+ spec: {
167
+ instances: spec.database.instances,
168
+ storage: {
169
+ size: spec.database.storageSize,
170
+ ...(spec.database.storageClass ? { storageClass: spec.database.storageClass } : {}),
171
+ },
172
+ bootstrap: {
173
+ initdb: { database: dbName, owner: dbOwner },
174
+ },
165
175
  },
166
- },
167
- id: 'database',
168
- });
169
- const dbPooler = pooler({
170
- name: `${spec.name}-db-pooler`,
171
- namespace: ns,
172
- spec: {
173
- cluster: { name: `${spec.name}-db` },
174
- type: 'rw',
175
- pgbouncer: { poolMode: 'transaction' },
176
- },
177
- id: 'dbPooler',
178
- });
179
- // ── Valkey Cache ────────────────────────────────────────────────────
180
- const cache = valkey({
181
- name: `${spec.name}-cache`,
182
- namespace: ns,
183
- spec: {
184
- volumePermissions: spec.cache?.volumePermissions ?? true,
185
- anonymousAuth: true,
186
- ...(spec.cache?.shards != null ? { shards: spec.cache.shards } : {}),
187
- ...(spec.cache?.replicas != null ? { replicas: spec.cache.replicas } : {}),
188
- storage: {
189
- spec: {
190
- accessModes: ['ReadWriteOnce'],
191
- resources: { requests: { storage: spec.cache?.storageSize ?? '1Gi' } },
176
+ id: 'database',
177
+ });
178
+ const dbPooler = pooler({
179
+ name: `${spec.name}-db-pooler`,
180
+ namespace: ns,
181
+ spec: {
182
+ cluster: { name: `${spec.name}-db` },
183
+ type: 'rw',
184
+ pgbouncer: { poolMode: 'transaction' },
185
+ },
186
+ id: 'dbPooler',
187
+ });
188
+ // ── Valkey Cache ────────────────────────────────────────────────────
189
+ const cache = valkey({
190
+ name: `${spec.name}-cache`,
191
+ namespace: ns,
192
+ spec: {
193
+ volumePermissions: spec.cache?.volumePermissions ?? true,
194
+ anonymousAuth: true,
195
+ ...(spec.cache?.shards != null ? { shards: spec.cache.shards } : {}),
196
+ ...(spec.cache?.replicas != null ? { replicas: spec.cache.replicas } : {}),
197
+ storage: {
198
+ spec: {
199
+ accessModes: ['ReadWriteOnce'],
200
+ resources: { requests: { storage: spec.cache?.storageSize ?? '1Gi' } },
201
+ },
192
202
  },
193
203
  },
194
- },
195
- id: 'cache',
196
- });
197
- // KRO applyset pruning workaround (upstream: kubernetes-sigs/kro#1153).
198
- //
199
- // The Hyperspike Valkey operator copies ALL parent labels to child
200
- // resources. KRO stamps applyset labels on the Valkey CR, so the
201
- // operator propagates them to children (ConfigMap, headless Service,
202
- // etc.). KRO's pruner then treats those children as applyset members
203
- // and deletes any whose GK is already in `contains-group-kinds` but
204
- // whose UID isn't in `keepUIDs` creating an infinite create/delete
205
- // loop. KRO closed this as "expected behavior"; the fix belongs on
206
- // the operator side, but Hyperspike has no label-propagation opt-out.
207
- //
208
- // Workaround: pre-declare the operator-created resources as typekro
209
- // graph nodes so KRO claims them with their own `kro.run/node-id`
210
- // label. The operator's upsert then patches the existing resource
211
- // instead of creating a new one with inherited applyset labels.
212
- //
213
- // TODO: remove when migrating to valkey-io/valkey-operator, which
214
- // is unlikely to have this label-copying behavior.
215
- simple.Service({
216
- name: `${spec.name}-cache`,
217
- namespace: ns,
218
- selector: {
219
- 'app.kubernetes.io/name': 'valkey',
220
- 'app.kubernetes.io/instance': `${spec.name}-cache`,
221
- },
222
- ports: [{ port: 6379, targetPort: 6379 }],
223
- id: 'cacheService',
224
- });
225
- simple.ConfigMap({
226
- name: `${spec.name}-cache`,
227
- namespace: ns,
228
- data: {},
229
- id: 'cacheConfigMap',
230
- });
231
- // ── Database credentials ──────────────────────────────────────────────
232
- // CNPG auto-generates a Secret named {cluster}-{owner} during bootstrap.
233
- // Validated against CNPG v1.25 (cloudnative-pg chart 0.23.0).
234
- // The name is deterministic no need for an externalRef which would block
235
- // KRO reconciliation (KRO waits for external refs to exist before creating
236
- // dependent resources, but the Secret only exists after CNPG bootstraps).
237
- const dbSecretName = `${spec.name}-db-${dbOwner}`;
238
- const inngestRepositoryName = `${spec.name}-${ns}-inngest-repo`;
239
- // ── Inngest (with external DB + cache) ──────────────────────────────
240
- // The actual postgres credentials are injected via the CNPG Secret
241
- // (secretKeyRef below). Use the deterministic pooler host here instead of
242
- // database.status.writeService so nested compositions do not leak an inner
243
- // resource status marker into the parent deployment graph.
244
- const inngestBootstrapApp = inngestBootstrap({
245
- name: `${spec.name}-inngest`,
246
- namespace: ns,
247
- repositoryName: inngestRepositoryName,
248
- inngest: {
249
- eventKey: spec.processing.eventKey,
250
- signingKey: spec.processing.signingKey,
251
- postgres: { uri: `postgresql://${dbOwner}@${dbPooler.metadata.name}:5432/${dbName}` },
252
- redis: { uri: `redis://${cache.metadata.name}:6379` },
253
- sdkUrl: spec.processing.sdkUrl,
254
- },
255
- postgresql: { enabled: false },
256
- redis: { enabled: false },
257
- replicaCount: inngestReplicas,
258
- ...(spec.processing.resources ? { resources: spec.processing.resources } : {}),
259
- // Deploy Inngest pods in the same namespace as CNPG (for Secret access)
260
- // and inject the real postgres URI from the CNPG Secret via secretKeyRef.
261
- customValues: {
262
- namespace: { create: false, name: ns },
204
+ id: 'cache',
205
+ });
206
+ // KRO applyset pruning workaround (upstream: kubernetes-sigs/kro#1153).
207
+ //
208
+ // The Hyperspike Valkey operator copies ALL parent labels to child
209
+ // resources. KRO stamps applyset labels on the Valkey CR, so the
210
+ // operator propagates them to children (ConfigMap, headless Service,
211
+ // etc.). KRO's pruner then treats those children as applyset members
212
+ // and deletes any whose GK is already in `contains-group-kinds` but
213
+ // whose UID isn't in `keepUIDs` — creating an infinite create/delete
214
+ // loop. KRO closed this as "expected behavior"; the fix belongs on
215
+ // the operator side, but Hyperspike has no label-propagation opt-out.
216
+ //
217
+ // Workaround: pre-declare the operator-created resources as typekro
218
+ // graph nodes so KRO claims them with their own `kro.run/node-id`
219
+ // label. The operator's upsert then patches the existing resource
220
+ // instead of creating a new one with inherited applyset labels.
221
+ //
222
+ // TODO: remove when migrating to valkey-io/valkey-operator, which
223
+ // is unlikely to have this label-copying behavior.
224
+ simple.Service({
225
+ name: `${spec.name}-cache`,
226
+ namespace: ns,
227
+ selector: {
228
+ 'app.kubernetes.io/name': 'valkey',
229
+ 'app.kubernetes.io/instance': `${spec.name}-cache`,
230
+ },
231
+ ports: [{ port: 6379, targetPort: 6379 }],
232
+ id: 'cacheService',
233
+ });
234
+ simple.ConfigMap({
235
+ name: `${spec.name}-cache`,
236
+ namespace: ns,
237
+ data: {},
238
+ id: 'cacheConfigMap',
239
+ });
240
+ // ── Database credentials ──────────────────────────────────────────────
241
+ // CNPG auto-generates a Secret named {cluster}-{owner} during bootstrap.
242
+ // Validated against CNPG v1.25 (cloudnative-pg chart 0.23.0).
243
+ // The name is deterministic no need for an externalRef which would block
244
+ // KRO reconciliation (KRO waits for external refs to exist before creating
245
+ // dependent resources, but the Secret only exists after CNPG bootstraps).
246
+ const dbSecretName = `${spec.name}-db-${dbOwner}`;
247
+ const inngestRepositoryName = `${spec.name}-${ns}-inngest-repo`;
248
+ // ── Inngest (with external DB + cache) ──────────────────────────────
249
+ // The actual postgres credentials are injected via the CNPG Secret
250
+ // (secretKeyRef below). Use the deterministic pooler host here instead of
251
+ // database.status.writeService so nested compositions do not leak an inner
252
+ // resource status marker into the parent deployment graph.
253
+ const inngestBootstrapApp = inngestBootstrap({
254
+ name: `${spec.name}-inngest`,
255
+ namespace: ns,
256
+ repositoryName: inngestRepositoryName,
263
257
  inngest: {
264
- eventKey: undefined,
265
- signingKey: undefined,
266
- extraEnv: [
267
- {
268
- name: 'INNGEST_EVENT_KEY',
269
- valueFrom: {
270
- secretKeyRef: {
271
- name: `${spec.name}-inngest-credentials`,
272
- key: 'INNGEST_EVENT_KEY',
258
+ eventKey: spec.processing.eventKey,
259
+ signingKey: spec.processing.signingKey,
260
+ postgres: { uri: `postgresql://${dbOwner}@${dbPooler.metadata.name}:5432/${dbName}` },
261
+ redis: { uri: `redis://${cache.metadata.name}:6379` },
262
+ sdkUrl: spec.processing.sdkUrl,
263
+ },
264
+ postgresql: { enabled: false },
265
+ redis: { enabled: false },
266
+ replicaCount: inngestReplicas,
267
+ ...(spec.processing.resources ? { resources: spec.processing.resources } : {}),
268
+ // Deploy Inngest pods in the same namespace as CNPG (for Secret access)
269
+ // and inject the real postgres URI from the CNPG Secret via secretKeyRef.
270
+ customValues: {
271
+ namespace: { create: false, name: ns },
272
+ inngest: {
273
+ eventKey: undefined,
274
+ signingKey: undefined,
275
+ extraEnv: [
276
+ {
277
+ name: 'INNGEST_EVENT_KEY',
278
+ valueFrom: {
279
+ secretKeyRef: {
280
+ name: `${spec.name}-inngest-credentials`,
281
+ key: 'INNGEST_EVENT_KEY',
282
+ },
273
283
  },
274
284
  },
275
- },
276
- {
277
- name: 'INNGEST_SIGNING_KEY',
278
- valueFrom: {
279
- secretKeyRef: {
280
- name: `${spec.name}-inngest-credentials`,
281
- key: 'INNGEST_SIGNING_KEY',
285
+ {
286
+ name: 'INNGEST_SIGNING_KEY',
287
+ valueFrom: {
288
+ secretKeyRef: {
289
+ name: `${spec.name}-inngest-credentials`,
290
+ key: 'INNGEST_SIGNING_KEY',
291
+ },
282
292
  },
283
293
  },
284
- },
285
- {
286
- name: 'INNGEST_POSTGRES_URI',
287
- valueFrom: {
288
- secretKeyRef: {
289
- name: dbSecretName,
290
- key: 'uri',
294
+ {
295
+ name: 'INNGEST_POSTGRES_URI',
296
+ valueFrom: {
297
+ secretKeyRef: {
298
+ name: dbSecretName,
299
+ key: 'uri',
300
+ },
291
301
  },
292
302
  },
293
- },
294
- ],
303
+ ],
304
+ },
295
305
  },
296
- },
297
- });
298
- // Inngest needs cache to be ready before it can connect to Redis.
299
- // cache.metadata.name is deterministic and gets inlined to a schema
300
- // ref, so KRO sees no implicit dependency. dependsOn creates an
301
- // explicit readyWhen on inngest's leaf resource.
302
- inngestBootstrapApp.dependsOn?.(cache);
303
- inngestBootstrapApp.dependsOn?.(database);
304
- inngestBootstrapApp.dependsOn?.(dbPooler);
305
- // ── Inngest credentials Secret ──────────────────────────────────────
306
- //
307
- // The Inngest event key and signing key are sensitive store them
308
- // in a K8s Secret rather than plaintext in the Deployment env.
309
- // Both the app and the Inngest server need these: the app sends
310
- // events with the event key and validates webhooks with the signing
311
- // key; the Inngest server uses them to authenticate SDK connections.
312
- const inngestSecretName = `${spec.name}-inngest-credentials`;
313
- secret({
314
- metadata: {
315
- name: inngestSecretName,
306
+ });
307
+ // Inngest needs cache to be ready before it can connect to Redis.
308
+ // cache.metadata.name is deterministic and gets inlined to a schema
309
+ // ref, so KRO sees no implicit dependency. dependsOn creates an
310
+ // explicit readyWhen on inngest's leaf resource.
311
+ inngestBootstrapApp.dependsOn?.(cache);
312
+ inngestBootstrapApp.dependsOn?.(database);
313
+ inngestBootstrapApp.dependsOn?.(dbPooler);
314
+ // ── Inngest credentials Secret ──────────────────────────────────────
315
+ //
316
+ // The Inngest event key and signing key are sensitive — store them
317
+ // in a K8s Secret rather than plaintext in the Deployment env.
318
+ // Both the app and the Inngest server need these: the app sends
319
+ // events with the event key and validates webhooks with the signing
320
+ // key; the Inngest server uses them to authenticate SDK connections.
321
+ const inngestSecretName = `${spec.name}-inngest-credentials`;
322
+ secret({
323
+ metadata: {
324
+ name: inngestSecretName,
325
+ namespace: ns,
326
+ },
327
+ stringData: {
328
+ INNGEST_EVENT_KEY: spec.processing.eventKey,
329
+ INNGEST_SIGNING_KEY: spec.processing.signingKey,
330
+ },
331
+ id: 'inngestCredentials',
332
+ });
333
+ // ── Application ─────────────────────────────────────────────────────
334
+ const appEnv = {
335
+ DATABASE_URL: `postgresql://${dbOwner}@${dbPooler.metadata.name}:5432/${dbName}`,
336
+ VALKEY_URL: `redis://${cache.metadata.name}:6379`,
337
+ REDIS_URL: `redis://${cache.metadata.name}:6379`,
338
+ INNGEST_BASE_URL: `http://${spec.name}-inngest:8288`,
339
+ // INNGEST_EVENT_KEY and INNGEST_SIGNING_KEY injected via the
340
+ // inngest credentials Secret (envFrom below) — not plaintext.
341
+ ...spec.app.env,
342
+ };
343
+ // The inngest Secret is listed FIRST so user-provided envFrom sources can
344
+ // override INNGEST_EVENT_KEY / INNGEST_SIGNING_KEY if they provide their
345
+ // own Secret containing those keys (last-write-wins in K8s envFrom ordering).
346
+ const userAppEnvFrom = spec.app.envFrom;
347
+ const appEnvFrom = isKubernetesRef(userAppEnvFrom)
348
+ ? [{ secretRef: { name: inngestSecretName } }]
349
+ : [{ secretRef: { name: inngestSecretName } }, ...(userAppEnvFrom ?? [])];
350
+ const app = simple.Deployment({
351
+ name: spec.name,
316
352
  namespace: ns,
317
- },
318
- stringData: {
319
- INNGEST_EVENT_KEY: spec.processing.eventKey,
320
- INNGEST_SIGNING_KEY: spec.processing.signingKey,
321
- },
322
- id: 'inngestCredentials',
323
- });
324
- // ── Application ─────────────────────────────────────────────────────
325
- const appEnv = {
326
- DATABASE_URL: `postgresql://${dbOwner}@${dbPooler.metadata.name}:5432/${dbName}`,
327
- VALKEY_URL: `redis://${cache.metadata.name}:6379`,
328
- REDIS_URL: `redis://${cache.metadata.name}:6379`,
329
- INNGEST_BASE_URL: `http://${spec.name}-inngest:8288`,
330
- // INNGEST_EVENT_KEY and INNGEST_SIGNING_KEY injected via the
331
- // inngest credentials Secret (envFrom below) — not plaintext.
332
- ...spec.app.env,
333
- };
334
- // The inngest Secret is listed FIRST so user-provided envFrom sources can
335
- // override INNGEST_EVENT_KEY / INNGEST_SIGNING_KEY if they provide their
336
- // own Secret containing those keys (last-write-wins in K8s envFrom ordering).
337
- const userAppEnvFrom = spec.app.envFrom;
338
- const appEnvFrom = isKubernetesRef(userAppEnvFrom)
339
- ? [{ secretRef: { name: inngestSecretName } }]
340
- : [{ secretRef: { name: inngestSecretName } }, ...(userAppEnvFrom ?? [])];
341
- const app = simple.Deployment({
342
- name: spec.name,
343
- namespace: ns,
344
- image: spec.app.image,
345
- replicas: appReplicas,
346
- ports: [{ containerPort: appPort }],
347
- env: appEnv,
348
- envFrom: appEnvFrom,
349
- id: 'app',
350
- });
351
- simple.Service({
352
- name: spec.name,
353
- namespace: ns,
354
- selector: { app: spec.name },
355
- ports: [{ port: appPort, targetPort: appPort }],
356
- id: 'appService',
353
+ image: spec.app.image,
354
+ replicas: appReplicas,
355
+ ports: [{ containerPort: appPort }],
356
+ env: appEnv,
357
+ envFrom: appEnvFrom,
358
+ id: 'app',
359
+ });
360
+ simple.Service({
361
+ name: spec.name,
362
+ namespace: ns,
363
+ selector: { app: spec.name },
364
+ ports: [{ port: appPort, targetPort: appPort }],
365
+ id: 'appService',
366
+ });
367
+ // ── Status ──────────────────────────────────────────────────────────
368
+ return {
369
+ ready: app.status.readyReplicas >= appReplicas &&
370
+ database.status.readyInstances >= (spec.database.instances ?? 1) &&
371
+ cache.status.ready &&
372
+ inngestBootstrapApp.status.ready,
373
+ databaseUrl: `postgresql://${dbOwner}@${dbPooler.metadata.name}:5432/${dbName}`,
374
+ databaseHost: `${dbPooler.metadata.name}`,
375
+ databasePort: 5432,
376
+ cacheUrl: `redis://${cache.metadata.name}:6379`,
377
+ cacheHost: `${cache.metadata.name}`,
378
+ cachePort: 6379,
379
+ inngestUrl: `http://${spec.name}-inngest:8288`,
380
+ appUrl: `http://${spec.name}:${appPort}`,
381
+ components: {
382
+ app: app.status.readyReplicas >= appReplicas,
383
+ database: database.status.readyInstances >= (spec.database.instances ?? 1),
384
+ cache: cache.status.ready,
385
+ inngest: inngestBootstrapApp.status.ready,
386
+ },
387
+ };
357
388
  });
358
- // ── Status ──────────────────────────────────────────────────────────
359
- return {
360
- ready: app.status.readyReplicas >= appReplicas &&
361
- database.status.readyInstances >= (spec.database.instances ?? 1) &&
362
- cache.status.ready &&
363
- inngestBootstrapApp.status.ready,
364
- databaseUrl: `postgresql://${dbOwner}@${dbPooler.metadata.name}:5432/${dbName}`,
365
- databaseHost: `${dbPooler.metadata.name}`,
366
- databasePort: 5432,
367
- cacheUrl: `redis://${cache.metadata.name}:6379`,
368
- cacheHost: `${cache.metadata.name}`,
369
- cachePort: 6379,
370
- inngestUrl: `http://${spec.name}-inngest:8288`,
371
- appUrl: `http://${spec.name}:${appPort}`,
372
- components: {
373
- app: app.status.readyReplicas >= appReplicas,
374
- database: database.status.readyInstances >= (spec.database.instances ?? 1),
375
- cache: cache.status.ready,
376
- inngest: inngestBootstrapApp.status.ready,
377
- },
378
- };
379
- });
389
+ }
390
+ /** Default webapp graph with the pinned Valkey operator installation. */
391
+ export const webAppWithProcessing = makeWebAppWithProcessing();
380
392
  //# sourceMappingURL=web-app-with-processing.js.map