@highstate/backend 0.9.15 → 0.9.18

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 (187) hide show
  1. package/dist/chunk-NAAIDR4U.js +8499 -0
  2. package/dist/chunk-NAAIDR4U.js.map +1 -0
  3. package/dist/chunk-OU5OQBLB.js +74 -0
  4. package/dist/chunk-OU5OQBLB.js.map +1 -0
  5. package/dist/chunk-Y7DXREVO.js +1745 -0
  6. package/dist/chunk-Y7DXREVO.js.map +1 -0
  7. package/dist/highstate.manifest.json +4 -4
  8. package/dist/index.js +7227 -2501
  9. package/dist/index.js.map +1 -1
  10. package/dist/library/package-resolution-worker.js +7 -5
  11. package/dist/library/package-resolution-worker.js.map +1 -1
  12. package/dist/library/worker/main.js +76 -185
  13. package/dist/library/worker/main.js.map +1 -1
  14. package/dist/magic-string.es-5ABAC4JN.js +1292 -0
  15. package/dist/magic-string.es-5ABAC4JN.js.map +1 -0
  16. package/dist/shared/index.js +3 -98
  17. package/dist/shared/index.js.map +1 -1
  18. package/package.json +31 -10
  19. package/src/artifact/abstractions.ts +46 -0
  20. package/src/artifact/encryption.ts +109 -0
  21. package/src/artifact/factory.ts +36 -0
  22. package/src/artifact/index.ts +3 -0
  23. package/src/artifact/local.ts +138 -0
  24. package/src/business/__traces__/secret/update-instance-secrets/create-and-delete-secrets-simultaneously.md +356 -0
  25. package/src/business/__traces__/secret/update-instance-secrets/create-new-secrets-for-instance.md +274 -0
  26. package/src/business/__traces__/secret/update-instance-secrets/delete-existing-secrets.md +223 -0
  27. package/src/business/__traces__/secret/update-instance-secrets/no-op-when-no-changes.md +147 -0
  28. package/src/business/__traces__/secret/update-instance-secrets/update-existing-secrets.md +280 -0
  29. package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration-when-other-exists.md +360 -0
  30. package/src/business/__traces__/worker/update-unit-registrations/add-new-unit-registration.md +215 -0
  31. package/src/business/__traces__/worker/update-unit-registrations/create-multiple-workers-with-different-identities.md +427 -0
  32. package/src/business/__traces__/worker/update-unit-registrations/handle-nonexistent-registration-id-gracefully.md +217 -0
  33. package/src/business/__traces__/worker/update-unit-registrations/no-op-when-no-changes.md +132 -0
  34. package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-changes.md +454 -0
  35. package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-when-image-version-changes.md +426 -0
  36. package/src/business/__traces__/worker/update-unit-registrations/recreate-worker-with-same-identity-reuses-service-account.md +372 -0
  37. package/src/business/__traces__/worker/update-unit-registrations/remove-one-of-multiple-unit-registrations.md +383 -0
  38. package/src/business/__traces__/worker/update-unit-registrations/remove-unit-registration.md +245 -0
  39. package/src/business/__traces__/worker/update-unit-registrations/update-existing-unit-registration-when-params-change.md +174 -0
  40. package/src/business/__traces__/worker/update-unit-registrations/update-params-and-image-simultaneously.md +432 -0
  41. package/src/business/__traces__/worker/update-unit-registrations/worker-with-multiple-registrations-not-deleted-when-one-removed.md +220 -0
  42. package/src/business/api-key.ts +65 -0
  43. package/src/business/artifact.ts +289 -0
  44. package/src/business/backend-unlock.ts +10 -0
  45. package/src/business/index.ts +10 -0
  46. package/src/business/instance-lock.ts +125 -0
  47. package/src/business/instance-state.ts +434 -0
  48. package/src/business/operation.ts +251 -0
  49. package/src/business/project-unlock.ts +260 -0
  50. package/src/business/project.ts +299 -0
  51. package/src/business/secret.test.ts +178 -0
  52. package/src/business/secret.ts +281 -0
  53. package/src/business/worker.test.ts +614 -0
  54. package/src/business/worker.ts +398 -0
  55. package/src/common/clock.ts +18 -0
  56. package/src/common/index.ts +5 -1
  57. package/src/common/performance.ts +44 -0
  58. package/src/common/random.ts +68 -0
  59. package/src/common/test/index.ts +2 -0
  60. package/src/common/test/render.ts +98 -0
  61. package/src/common/test/tracer.ts +359 -0
  62. package/src/common/tree.ts +33 -0
  63. package/src/common/utils.ts +40 -1
  64. package/src/config.ts +19 -11
  65. package/src/hotstate/abstractions.ts +48 -0
  66. package/src/hotstate/factory.ts +17 -0
  67. package/src/{secret → hotstate}/index.ts +1 -0
  68. package/src/hotstate/manager.ts +192 -0
  69. package/src/hotstate/memory.ts +100 -0
  70. package/src/hotstate/validation.ts +100 -0
  71. package/src/index.ts +2 -1
  72. package/src/library/abstractions.ts +24 -28
  73. package/src/library/factory.ts +2 -2
  74. package/src/library/local.ts +91 -111
  75. package/src/library/worker/evaluator.ts +36 -73
  76. package/src/library/worker/loader.lite.ts +54 -0
  77. package/src/library/worker/main.ts +15 -66
  78. package/src/library/worker/protocol.ts +6 -33
  79. package/src/lock/abstractions.ts +6 -0
  80. package/src/lock/factory.ts +15 -0
  81. package/src/lock/index.ts +4 -0
  82. package/src/lock/manager.ts +97 -0
  83. package/src/lock/memory.ts +19 -0
  84. package/src/lock/test.ts +108 -0
  85. package/src/orchestrator/manager.ts +118 -90
  86. package/src/orchestrator/operation-workset.ts +181 -93
  87. package/src/orchestrator/operation.ts +1021 -283
  88. package/src/project/abstractions.ts +27 -38
  89. package/src/project/evaluation.ts +248 -0
  90. package/src/project/factory.ts +1 -1
  91. package/src/project/index.ts +1 -2
  92. package/src/project/local.ts +107 -103
  93. package/src/pubsub/abstractions.ts +13 -0
  94. package/src/pubsub/factory.ts +19 -0
  95. package/src/{workspace → pubsub}/index.ts +1 -0
  96. package/src/pubsub/local.ts +36 -0
  97. package/src/pubsub/manager.ts +108 -0
  98. package/src/pubsub/validation.ts +33 -0
  99. package/src/runner/abstractions.ts +155 -68
  100. package/src/runner/artifact-env.ts +160 -0
  101. package/src/runner/factory.ts +20 -5
  102. package/src/runner/force-abort.ts +117 -0
  103. package/src/runner/local.ts +292 -372
  104. package/src/{common → runner}/pulumi.ts +89 -37
  105. package/src/services.ts +251 -40
  106. package/src/shared/index.ts +3 -11
  107. package/src/shared/models/backend/index.ts +3 -0
  108. package/src/shared/{library.ts → models/backend/library.ts} +4 -4
  109. package/src/shared/models/backend/project.ts +82 -0
  110. package/src/shared/models/backend/unlock-method.ts +20 -0
  111. package/src/shared/models/base.ts +68 -0
  112. package/src/shared/models/errors.ts +5 -0
  113. package/src/shared/models/index.ts +4 -0
  114. package/src/shared/models/project/api-key.ts +65 -0
  115. package/src/shared/models/project/artifact.ts +83 -0
  116. package/src/shared/models/project/index.ts +13 -0
  117. package/src/shared/models/project/lock.ts +91 -0
  118. package/src/shared/models/project/model.ts +14 -0
  119. package/src/shared/{operation.ts → models/project/operation.ts} +29 -8
  120. package/src/shared/models/project/page.ts +57 -0
  121. package/src/shared/models/project/secret.ts +98 -0
  122. package/src/shared/models/project/service-account.ts +22 -0
  123. package/src/shared/models/project/state.ts +449 -0
  124. package/src/shared/models/project/terminal.ts +98 -0
  125. package/src/shared/models/project/trigger.ts +56 -0
  126. package/src/shared/models/project/unlock-method.ts +38 -0
  127. package/src/shared/models/project/worker.ts +107 -0
  128. package/src/shared/resolvers/graph-resolver.ts +61 -18
  129. package/src/shared/resolvers/index.ts +5 -0
  130. package/src/shared/resolvers/input-hash.ts +53 -15
  131. package/src/shared/resolvers/input.ts +47 -13
  132. package/src/shared/resolvers/registry.ts +3 -2
  133. package/src/shared/resolvers/state.ts +2 -2
  134. package/src/shared/resolvers/validation.ts +82 -25
  135. package/src/shared/utils/args.ts +25 -0
  136. package/src/shared/{async-batcher.ts → utils/async-batcher.ts} +13 -1
  137. package/src/shared/utils/hash.ts +6 -0
  138. package/src/shared/utils/index.ts +4 -0
  139. package/src/shared/utils/promise-tracker.ts +23 -0
  140. package/src/state/abstractions.ts +199 -131
  141. package/src/state/encryption.ts +98 -0
  142. package/src/state/factory.ts +3 -5
  143. package/src/state/index.ts +4 -0
  144. package/src/state/keyring.ts +22 -0
  145. package/src/state/local/backend.ts +106 -0
  146. package/src/state/local/collection.ts +361 -0
  147. package/src/state/local/index.ts +2 -0
  148. package/src/state/manager.ts +875 -18
  149. package/src/state/memory/backend.ts +70 -0
  150. package/src/state/memory/collection.ts +270 -0
  151. package/src/state/memory/index.ts +2 -0
  152. package/src/state/repository/index.ts +2 -0
  153. package/src/state/repository/repository.index.ts +193 -0
  154. package/src/state/repository/repository.ts +507 -0
  155. package/src/state/test.ts +457 -0
  156. package/src/terminal/{shared.ts → abstractions.ts} +3 -3
  157. package/src/terminal/docker.ts +18 -14
  158. package/src/terminal/factory.ts +3 -3
  159. package/src/terminal/index.ts +1 -1
  160. package/src/terminal/manager.ts +131 -79
  161. package/src/terminal/run.sh.ts +21 -11
  162. package/src/unlock/abstractions.ts +49 -0
  163. package/src/unlock/index.ts +2 -0
  164. package/src/unlock/memory.ts +32 -0
  165. package/src/worker/abstractions.ts +42 -0
  166. package/src/worker/docker.ts +83 -0
  167. package/src/worker/factory.ts +20 -0
  168. package/src/worker/index.ts +3 -0
  169. package/src/worker/manager.ts +167 -0
  170. package/dist/chunk-KTGKNSKM.js +0 -979
  171. package/dist/chunk-KTGKNSKM.js.map +0 -1
  172. package/dist/chunk-WXDYCRTT.js +0 -234
  173. package/dist/chunk-WXDYCRTT.js.map +0 -1
  174. package/src/library/worker/loader.ts +0 -114
  175. package/src/preferences/shared.ts +0 -1
  176. package/src/project/lock.ts +0 -39
  177. package/src/project/manager.ts +0 -433
  178. package/src/secret/abstractions.ts +0 -59
  179. package/src/secret/factory.ts +0 -22
  180. package/src/secret/local.ts +0 -152
  181. package/src/shared/project.ts +0 -62
  182. package/src/shared/state.ts +0 -247
  183. package/src/shared/terminal.ts +0 -14
  184. package/src/state/local.ts +0 -612
  185. package/src/workspace/abstractions.ts +0 -41
  186. package/src/workspace/factory.ts +0 -14
  187. package/src/workspace/local.ts +0 -54
@@ -0,0 +1,449 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
2
+ /* eslint-disable @typescript-eslint/no-unsafe-member-access */
3
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment */
4
+ /* eslint-disable @typescript-eslint/no-explicit-any */
5
+
6
+ import { z } from "zod"
7
+ import { objectMetaSchema, userObjectMetaSchema } from "@highstate/contract"
8
+
9
+ export const instanceOperationStatusEnumSchema = z.enum([
10
+ // transient statuses
11
+ "updating",
12
+ "processing-triggers",
13
+ "previewing",
14
+ "destroying",
15
+ "refreshing",
16
+ "pending",
17
+ "cancelling",
18
+
19
+ // stable statuses
20
+ "created",
21
+ "error",
22
+ ])
23
+
24
+ export const instanceOperationStatusSchema = z.object({
25
+ /**
26
+ * The enum representing the current status of the instance from the operation perspective.
27
+ */
28
+ status: instanceOperationStatusEnumSchema,
29
+
30
+ /**
31
+ * The ID of the latest operation that this instance is associated with.
32
+ */
33
+ latestOperationId: z.string(),
34
+
35
+ /**
36
+ * The IDs of the instances that this instance depends on at the moment of latest operation.
37
+ */
38
+ dependencyIds: z.array(z.string()),
39
+
40
+ /**
41
+ * The some human-readable message describing the current status.
42
+ * Typically used to show the error message if the status is "error".
43
+ */
44
+ message: z.string().optional(),
45
+
46
+ /**
47
+ * The current count of the Pulumi resources being managed by this instance.
48
+ */
49
+ currentResourceCount: z.number().optional(),
50
+
51
+ /**
52
+ * The total count of the Pulumi resources that this instance is expected to manage.
53
+ */
54
+ totalResourceCount: z.number().optional(),
55
+
56
+ /**
57
+ * The calculated instance CRC32 input hash at the moment of latest operation completion.
58
+ *
59
+ * This hash covers:
60
+ * - the instance's configuration (name, args, secret hashes);
61
+ * - the component definition hash;
62
+ * - the unit's source hash (if applicable);
63
+ * - the input hashes and output hashes of all input instances.
64
+ */
65
+ inputHash: z.number().optional(),
66
+
67
+ /**
68
+ * The random 32-bit nonce used in input hash calculation.
69
+ *
70
+ * It is changed every time the instance secrets are updated,
71
+ * to invalidate the input hash and force running the instance again.
72
+ */
73
+ inputHashNonce: z.number().optional(),
74
+
75
+ /**
76
+ * The sha256 of the output produced by the instance at the moment of latest operation completion.
77
+ *
78
+ * Does not depend on anything except the instance's output.
79
+ */
80
+ outputHash: z.string().optional(),
81
+
82
+ /**
83
+ * The calculated sha256 dependency output hash at the moment of latest operation completion.
84
+ *
85
+ * This hash is calculated as combination of output hashes of all input instances and nothing else.
86
+ *
87
+ * The primary use case of this hash is to "short-circuit" execution:
88
+ * if the outputs of input instances have not changed, dependent instances can skip execution,
89
+ * even if their input hashes changed due to upstream config changes.
90
+ * This prevents unnecessary re-execution of the entire dependency graph when only non-output-affecting inputs are modified.
91
+ */
92
+ dependencyOutputHash: z.string().optional(),
93
+
94
+ /**
95
+ * The arguments of the instances at the moment of latest operation start.
96
+ */
97
+ args: z.record(z.string(), z.unknown()).optional(),
98
+ })
99
+
100
+ export const instanceEvaludationStatusEnumSchema = z.enum([
101
+ // transient statuses
102
+ "evaluating",
103
+
104
+ // stable statuses
105
+ "evaluated",
106
+ "error",
107
+ ])
108
+
109
+ export const instanceEvaluationStatusSchema = z.object({
110
+ /**
111
+ * The enum representing the current status of the instance from the evaluation perspective.
112
+ *
113
+ * The stable status when instance is not evaludated is forbidden.
114
+ */
115
+ status: instanceEvaludationStatusEnumSchema,
116
+
117
+ /**
118
+ * The message describing the evaluation status.
119
+ * Typically used to show the error message if the status is "error".
120
+ */
121
+ message: z.string().optional(),
122
+ })
123
+
124
+ export enum WellKnownInstanceCustomStatus {
125
+ /**
126
+ * The instance is in a healthy state.
127
+ */
128
+ Healthy = "healthy",
129
+
130
+ /**
131
+ * The instance is in a degraded state.
132
+ */
133
+ Degraded = "degraded",
134
+
135
+ /**
136
+ * The instance is in a down state/completely broken.
137
+ */
138
+ Down = "down",
139
+
140
+ /**
141
+ * The instance is in a warning state.
142
+ */
143
+ Warning = "warning",
144
+
145
+ /**
146
+ * The instance is progressing with some external sync operation,
147
+ * such as a deployment or a data migration.
148
+ */
149
+ Progressing = "progressing",
150
+
151
+ /**
152
+ * The instance is in an error state.
153
+ */
154
+ Error = "error",
155
+ }
156
+
157
+ export const instanceCustomStatusSchema = z.object({
158
+ /**
159
+ * The name of the instance's extra status.
160
+ *
161
+ * Must be unique within the instance state.
162
+ */
163
+ name: z.string(),
164
+
165
+ /**
166
+ * The enum value of the instance's extra status.
167
+ *
168
+ * May be on of the `WellKnownExtraInstanceStatus` values or a custom value.
169
+ */
170
+ status: z.string(),
171
+
172
+ /**
173
+ * The title of the instance's extra status.
174
+ */
175
+ title: z.string(),
176
+
177
+ /**
178
+ * The `iconify` icon representing the instance's extra status.
179
+ *
180
+ * If not provided and status is a well-known value, the icon will be derived from the status.
181
+ */
182
+ icon: z.string().optional(),
183
+
184
+ /**
185
+ * The HEX color of the status badge.
186
+ *
187
+ * If not provided and status is a well-known value, the color will be derived from the status.
188
+ */
189
+ color: z.string().optional(),
190
+
191
+ /**
192
+ * The message describing the instance's extra status.
193
+ *
194
+ * Can be used to provide additional context or information about the status.
195
+ *
196
+ * The message will be displayed in the 800x600 ANSI terminal in the UI,
197
+ * so differenet TUI elements should be drawn within this area.
198
+ */
199
+ message: z.string().optional(),
200
+
201
+ /**
202
+ * The order of the status in the list of statuses.
203
+ *
204
+ * Must be in the range from `0` to `100`, lower values are displayed first.
205
+ *
206
+ * If not provided, the default is `50`.
207
+ */
208
+ order: z.number().min(0).max(100).optional(),
209
+ })
210
+
211
+ export const instanceStatusFieldValueSchema = z.union([
212
+ z.string(),
213
+ z.number(),
214
+ z.boolean(),
215
+ z.array(z.string()),
216
+ ])
217
+
218
+ export const instanceStatusFieldSchema = z.object({
219
+ name: z.string(),
220
+ meta: objectMetaSchema,
221
+
222
+ complementaryTo: z.string().optional(),
223
+
224
+ value: instanceStatusFieldValueSchema.optional(),
225
+ })
226
+
227
+ export const unitInstanceStatusFieldSchema = instanceStatusFieldSchema.omit({ meta: true }).extend({
228
+ meta: userObjectMetaSchema,
229
+ })
230
+
231
+ export const instanceStateExtraSchema = z.object({
232
+ /**
233
+ * The status fields reported by the unit or attached via the API.
234
+ *
235
+ * Do not confuse with `customStatuses`.
236
+ *
237
+ * These fields are used to store additional information about the instance,
238
+ * such as URLs, display names, and other metadata.
239
+ */
240
+ statusFields: z.array(instanceStatusFieldSchema).optional(),
241
+
242
+ /**
243
+ * The extra statuses of the instance reported by the unit or attached via the API.
244
+ *
245
+ * Do not confuse with `statusFields.
246
+ */
247
+ customStatuses: z.array(instanceCustomStatusSchema).optional(),
248
+
249
+ /**
250
+ * The IDs of the pages that are owned by this instance.
251
+ *
252
+ * The keys are the local page names, and the values are the page IDs.
253
+ */
254
+ pageIds: z.record(z.string(), z.string()).optional(),
255
+
256
+ /**
257
+ * The IDs of the terminals that are owned by this instance.
258
+ *
259
+ * The keys are the local terminal names, and the values are the terminal IDs.
260
+ */
261
+ terminalIds: z.record(z.string(), z.string()).optional(),
262
+
263
+ /**
264
+ * The IDs of the triggers that are owned by this instance.
265
+ *
266
+ * The keys are the local trigger names, and the values are the trigger IDs.
267
+ */
268
+ triggerIds: z.record(z.string(), z.string()).optional(),
269
+
270
+ /**
271
+ * The IDs of the artifacts that this instance exports via outputs.
272
+ *
273
+ * The keys are the output keys, and the values are the artifact IDs.
274
+ *
275
+ * These artifacts can be both: produced by this instance or reexported from input instances.
276
+ */
277
+ exportedArtifactIds: z.record(z.string(), z.array(z.string())).optional(),
278
+
279
+ /**
280
+ * The IDs of the secrets that this instance exports via outputs.
281
+ *
282
+ * The keys are the output keys, and the values are the secret IDs.
283
+ *
284
+ * These secrets can be both: produced by this instance or reexported from input instances.
285
+ */
286
+ exportedSecretIds: z.record(z.string(), z.string().array()).optional(),
287
+
288
+ /**
289
+ * The IDs of the worker registrations that are owned by this instance.
290
+ *
291
+ * The keys are the unit worker names, and the values are the registration IDs.
292
+ */
293
+ workerRegistrationIds: z.record(z.string(), z.string()).optional(),
294
+ })
295
+
296
+ export const instanceStateSchema = z.object({
297
+ /**
298
+ * The unique identifier of the instance.
299
+ * The format is `{componentType}:{instanceName}`, so each instance must have a unique name within its component type.
300
+ */
301
+ id: z.string(),
302
+
303
+ /**
304
+ * The ID of the parent instance, if this instance is a child of another composite instance.
305
+ */
306
+ parentId: z.string().optional(),
307
+
308
+ /**
309
+ * The names of the secrets that has values in this instance.
310
+ */
311
+ secretNames: z.array(z.string()).optional(),
312
+
313
+ /**
314
+ * The current status of the instance from the operation perspective.
315
+ *
316
+ * This status persists in the storage only when the operation is completed.
317
+ *
318
+ * If the operation was interrupted, the status will be "error" with corresponding error message.
319
+ *
320
+ * If the instance was not created or was successfully destroyed, the whole "operationStatus" field will be undefined.
321
+ */
322
+ operationStatus: instanceOperationStatusSchema.optional(),
323
+
324
+ /**
325
+ * The current status of the instance from the evaluation perspective.
326
+ *
327
+ * Only applies to composite instances, will always be `undefined` for unit instances.
328
+ */
329
+ evaluationStatus: instanceEvaluationStatusSchema.optional(),
330
+
331
+ /**
332
+ * The extra components of the instance.
333
+ *
334
+ * Applies to both unit and composite instances.
335
+ */
336
+ extra: instanceStateExtraSchema.optional(),
337
+ })
338
+
339
+ export type InstanceStatusFieldValue = z.infer<typeof instanceStatusFieldValueSchema>
340
+ export type InstanceStatusField = z.infer<typeof instanceStatusFieldSchema>
341
+ export type UnitInstanceStatusField = z.infer<typeof unitInstanceStatusFieldSchema>
342
+
343
+ export type InstanceOperationStatus = z.infer<typeof instanceOperationStatusSchema>
344
+ export type InstanceOperataionStatusEnum = z.infer<typeof instanceOperationStatusEnumSchema>
345
+
346
+ export type InstanceEvaluationStatus = z.infer<typeof instanceEvaluationStatusSchema>
347
+ export type InstanceEvaluationStatusEnum = z.infer<typeof instanceEvaludationStatusEnumSchema>
348
+
349
+ export type InstanceCustomStatus = z.infer<typeof instanceCustomStatusSchema>
350
+
351
+ export type InstanceState = z.infer<typeof instanceStateSchema>
352
+
353
+ export type NullableRecord<T extends Record<string, any>> = {
354
+ [K in keyof T]: T[K] | null
355
+ }
356
+
357
+ export const instanceStateExtraPath = z.object({
358
+ statusFields: z.array(instanceStatusFieldSchema).optional().nullable(),
359
+ customStatuses: z.array(instanceCustomStatusSchema).optional().nullable(),
360
+ pageIds: z.record(z.string(), z.string()).optional().nullable(),
361
+ terminalIds: z.record(z.string(), z.string()).optional().nullable(),
362
+ triggerIds: z.record(z.string(), z.string()).optional().nullable(),
363
+ exportedArtifactIds: z.record(z.string(), z.array(z.string())).optional().nullable(),
364
+ exportedSecretIds: z.record(z.string(), z.string().array()).optional().nullable(),
365
+ workerRegistrationIds: z.record(z.string(), z.string()).optional().nullable(),
366
+ })
367
+
368
+ export const instanceStatePatchSchema = z.object({
369
+ id: z.string(),
370
+ parentId: z.string().nullish(),
371
+ secretNames: z.array(z.string()).nullish(),
372
+ operationStatus: instanceOperationStatusSchema.partial().nullish(),
373
+ evaluationStatus: instanceEvaluationStatusSchema.partial().nullish(),
374
+ extra: instanceStateExtraPath.nullish(),
375
+ })
376
+
377
+ export type InstanceStatePatch = z.infer<typeof instanceStatePatchSchema>
378
+
379
+ export function applyStatePatch(
380
+ existingState: InstanceState | null | undefined,
381
+ patch: InstanceStatePatch,
382
+ ): InstanceState {
383
+ const state: any = existingState ? { ...existingState } : { id: patch.id }
384
+
385
+ const anyPatch = patch as any
386
+
387
+ // merge the patch with the existing state with 2-level deep merge
388
+ // (merge objects nested in the state, but replace objects inside these nested objects)
389
+ for (const key of Object.keys(patch)) {
390
+ if (typeof anyPatch[key] === "undefined") {
391
+ // ignore undefined values
392
+ continue
393
+ }
394
+
395
+ if (
396
+ typeof anyPatch[key] !== "object" ||
397
+ anyPatch[key] === null ||
398
+ Array.isArray(anyPatch[key])
399
+ ) {
400
+ // if the value is not an object, just replace it
401
+ // transform null to undefined
402
+ state[key] = anyPatch[key] === null ? undefined : anyPatch[key]
403
+ continue
404
+ }
405
+
406
+ // if the value is an object, merge it with the existing state
407
+ const existingValue = state[key] ? { ...state[key] } : {}
408
+
409
+ for (const subKey of Object.keys(anyPatch[key])) {
410
+ existingValue[subKey] = anyPatch[key][subKey]
411
+ }
412
+
413
+ state[key] = existingValue
414
+ }
415
+
416
+ return state as InstanceState
417
+ }
418
+
419
+ export function isStateEmpty(state: InstanceState): boolean {
420
+ return (
421
+ !state.operationStatus &&
422
+ !state.evaluationStatus &&
423
+ (!state.extra || Object.keys(state.extra).length === 0) &&
424
+ (!state.secretNames || state.secretNames.length === 0)
425
+ )
426
+ }
427
+
428
+ export function isTransientOperationStatus(status: InstanceOperataionStatusEnum): boolean {
429
+ return status !== "created" && status !== "error"
430
+ }
431
+
432
+ export function isStableOperationStatus(status: InstanceOperataionStatusEnum): boolean {
433
+ return status === "created" || status === "error"
434
+ }
435
+
436
+ export const instanceStateEventSchema = z.discriminatedUnion("type", [
437
+ z.object({
438
+ type: z.literal("patched"),
439
+ patch: instanceStatePatchSchema,
440
+ }),
441
+ z.object({
442
+ type: z.literal("updated"),
443
+ state: instanceStateSchema,
444
+ }),
445
+ z.object({
446
+ type: z.literal("deleted"),
447
+ instanceId: z.string(),
448
+ }),
449
+ ])
@@ -0,0 +1,98 @@
1
+ import { z } from "zod"
2
+ import { fileSchema, objectMetaSchema, userObjectMetaSchema } from "@highstate/contract"
3
+
4
+ const metaFields = {
5
+ title: true,
6
+ globalTitle: true,
7
+ description: true,
8
+ icon: true,
9
+ iconColor: true,
10
+ } as const
11
+
12
+ const requiredMetaFields = {
13
+ title: true,
14
+ description: true,
15
+ } as const
16
+
17
+ /**
18
+ * The basic information about a terminal.
19
+ * The spec of the terminal is stored separately and defined in `terminalSpecSchema`.
20
+ */
21
+ export const terminalSchema = z.object({
22
+ id: z.string().uuid(), // UUIDv7
23
+
24
+ meta: objectMetaSchema
25
+ .pick({
26
+ ...metaFields,
27
+ createdAt: true,
28
+ updatedAt: true,
29
+ })
30
+ .required(requiredMetaFields),
31
+
32
+ /**
33
+ * The ID of the instance produced the terminal if applicable.
34
+ */
35
+ instanceId: z.string().optional(),
36
+ })
37
+
38
+ export type Terminal = z.infer<typeof terminalSchema>
39
+
40
+ /**
41
+ * Contains all the information needed to run a terminal,
42
+ * including the image, command, working directory, environment variables, and files.
43
+ */
44
+ export const terminalSpecSchema = z.object({
45
+ image: z.string(),
46
+ command: z.string().array(),
47
+ cwd: z.string().optional(),
48
+ env: z.record(z.string(), z.string()).optional(),
49
+ files: z.record(z.string(), fileSchema).optional(),
50
+ })
51
+
52
+ export type TerminalSpec = z.infer<typeof terminalSpecSchema>
53
+
54
+ /**
55
+ * Terminal schema for unit API.
56
+ */
57
+ export const unitTerminalSchema = z.object({
58
+ name: z.string(),
59
+ meta: userObjectMetaSchema.pick(metaFields).required(requiredMetaFields),
60
+ spec: terminalSpecSchema,
61
+ })
62
+
63
+ export type UnitTerminal = z.infer<typeof unitTerminalSchema>
64
+
65
+ /**
66
+ * Terminal session schema for database storage and frontend display.
67
+ * Contains all terminal session information.
68
+ */
69
+ export const terminalSessionSchema = z.object({
70
+ id: z.uuidv7(),
71
+
72
+ meta: objectMetaSchema
73
+ .pick({ ...metaFields, createdAt: true, updatedAt: true })
74
+ .required(requiredMetaFields)
75
+ .extend({
76
+ /**
77
+ * The time when the session was finished.
78
+ */
79
+ finishedAt: z.number().optional(),
80
+ }),
81
+
82
+ /**
83
+ * The ID of the project this session belongs to.
84
+ */
85
+ projectId: z.string(),
86
+
87
+ /**
88
+ * References the terminal this session is based on.
89
+ */
90
+ terminalId: z.string(),
91
+
92
+ /**
93
+ * References the instance produced the terminal if applicable.
94
+ */
95
+ instanceId: z.string().optional(),
96
+ })
97
+
98
+ export type TerminalSession = z.infer<typeof terminalSessionSchema>
@@ -0,0 +1,56 @@
1
+ import { z } from "zod"
2
+ import { objectMetaSchema, userObjectMetaSchema } from "@highstate/contract"
3
+
4
+ /**
5
+ * Trigger specification schema.
6
+ */
7
+ export const triggerSpecSchema = z.union([
8
+ z.object({
9
+ type: z.literal("before-destroy"),
10
+ }),
11
+ z.object({
12
+ type: z.literal("schedule"),
13
+ schedule: z.string(),
14
+ }),
15
+ ])
16
+
17
+ export type TriggerSpec = z.infer<typeof triggerSpecSchema>
18
+
19
+ /**
20
+ * Trigger info for frontend display.
21
+ * Contains only basic information visible to the frontend.
22
+ */
23
+ export const triggerSchema = z.object({
24
+ id: z.string(),
25
+ instanceId: z.string(),
26
+ meta: objectMetaSchema,
27
+ spec: triggerSpecSchema,
28
+ })
29
+
30
+ export type Trigger = z.infer<typeof triggerSchema>
31
+
32
+ /**
33
+ * Trigger schema for unit API.
34
+ * This is what units provide - excludes id since it's set by the system.
35
+ */
36
+ export const unitTriggerSchema = triggerSchema
37
+ .omit({ id: true, instanceId: true, meta: true })
38
+ .extend({
39
+ name: z.string(),
40
+ meta: userObjectMetaSchema.optional(),
41
+ })
42
+ .extend({
43
+ name: z.string(),
44
+ meta: userObjectMetaSchema.optional(),
45
+ })
46
+
47
+ export type UnitTrigger = z.infer<typeof unitTriggerSchema>
48
+
49
+ /**
50
+ * Trigger invocation schema.
51
+ */
52
+ export const triggerInvocationSchema = z.object({
53
+ name: z.string(),
54
+ })
55
+
56
+ export type TriggerInvocation = z.infer<typeof triggerInvocationSchema>
@@ -0,0 +1,38 @@
1
+ import { z } from "zod"
2
+ import { objectMetaSchema } from "@highstate/contract"
3
+
4
+ export const unlockMethodType = z.enum(["password", "passkey"])
5
+
6
+ /**
7
+ * Complete unlock method schema for database storage.
8
+ * Contains all unlock method information including encryption details.
9
+ */
10
+ export const unlockMethodSchema = z.object({
11
+ id: z.uuidv7(),
12
+
13
+ /**
14
+ * Metadata for the unlock method.
15
+ */
16
+ meta: objectMetaSchema,
17
+
18
+ /**
19
+ * The type of unlock method (password or passkey).
20
+ */
21
+ type: unlockMethodType,
22
+
23
+ /**
24
+ * The encrypted identity used to decrypt the master key.
25
+ */
26
+ encryptedIdentity: z.string(),
27
+
28
+ /**
29
+ * The recipient of the unlock method to use to encrypt the master key for this unlock method.
30
+ */
31
+ recipient: z.string(),
32
+ })
33
+
34
+ export const inputUnlockMethodSchema = unlockMethodSchema.omit({ id: true })
35
+
36
+ export type InputUnlockMethod = z.infer<typeof inputUnlockMethodSchema>
37
+ export type UnlockMethod = z.infer<typeof unlockMethodSchema>
38
+ export type UnlockMethodType = z.infer<typeof unlockMethodType>