@highstate/backend 0.9.14 → 0.9.16
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.
- package/dist/chunk-RCB4AFGD.js +159 -0
- package/dist/chunk-RCB4AFGD.js.map +1 -0
- package/dist/chunk-WHALQHEZ.js +2017 -0
- package/dist/chunk-WHALQHEZ.js.map +1 -0
- package/dist/highstate.manifest.json +3 -3
- package/dist/index.js +6146 -2174
- package/dist/index.js.map +1 -1
- package/dist/library/worker/main.js +51 -159
- package/dist/library/worker/main.js.map +1 -1
- package/dist/shared/index.js +159 -43
- package/package.json +25 -7
- package/src/artifact/abstractions.ts +46 -0
- package/src/artifact/encryption.ts +69 -0
- package/src/artifact/factory.ts +36 -0
- package/src/artifact/index.ts +3 -0
- package/src/artifact/local.ts +142 -0
- package/src/business/api-key.ts +65 -0
- package/src/business/artifact.ts +288 -0
- package/src/business/backend-unlock.ts +10 -0
- package/src/business/index.ts +9 -0
- package/src/business/instance-lock.ts +124 -0
- package/src/business/instance-state.ts +292 -0
- package/src/business/operation.ts +251 -0
- package/src/business/project-unlock.ts +242 -0
- package/src/business/secret.ts +187 -0
- package/src/business/worker.ts +161 -0
- package/src/common/index.ts +2 -1
- package/src/common/performance.ts +44 -0
- package/src/common/tree.ts +33 -0
- package/src/common/utils.ts +40 -1
- package/src/config.ts +14 -10
- package/src/hotstate/abstractions.ts +48 -0
- package/src/hotstate/factory.ts +17 -0
- package/src/{secret → hotstate}/index.ts +1 -0
- package/src/hotstate/manager.ts +192 -0
- package/src/hotstate/memory.ts +100 -0
- package/src/hotstate/validation.ts +101 -0
- package/src/index.ts +2 -1
- package/src/library/abstractions.ts +10 -23
- package/src/library/factory.ts +2 -2
- package/src/library/local.ts +89 -102
- package/src/library/worker/evaluator.ts +14 -47
- package/src/library/worker/loader.lite.ts +41 -0
- package/src/library/worker/main.ts +14 -65
- package/src/library/worker/protocol.ts +8 -24
- package/src/lock/abstractions.ts +6 -0
- package/src/lock/factory.ts +15 -0
- package/src/{workspace → lock}/index.ts +1 -0
- package/src/lock/manager.ts +82 -0
- package/src/lock/memory.ts +19 -0
- package/src/orchestrator/manager.ts +131 -82
- package/src/orchestrator/operation-workset.ts +188 -77
- package/src/orchestrator/operation.ts +975 -284
- package/src/project/abstractions.ts +20 -7
- package/src/project/factory.ts +1 -1
- package/src/project/index.ts +0 -1
- package/src/project/local.ts +73 -17
- package/src/project/manager.ts +272 -131
- package/src/pubsub/abstractions.ts +13 -0
- package/src/pubsub/factory.ts +19 -0
- package/src/pubsub/index.ts +3 -0
- package/src/pubsub/local.ts +36 -0
- package/src/pubsub/manager.ts +100 -0
- package/src/pubsub/validation.ts +33 -0
- package/src/runner/abstractions.ts +135 -68
- package/src/runner/artifact-env.ts +160 -0
- package/src/runner/factory.ts +20 -5
- package/src/runner/force-abort.ts +117 -0
- package/src/runner/local.ts +281 -372
- package/src/{common → runner}/pulumi.ts +86 -37
- package/src/services.ts +193 -35
- package/src/shared/index.ts +3 -11
- package/src/shared/models/backend/index.ts +3 -0
- package/src/shared/models/backend/project.ts +63 -0
- package/src/shared/models/backend/unlock-method.ts +20 -0
- package/src/shared/models/base.ts +151 -0
- package/src/shared/models/errors.ts +5 -0
- package/src/shared/models/index.ts +4 -0
- package/src/shared/models/project/api-key.ts +62 -0
- package/src/shared/models/project/artifact.ts +113 -0
- package/src/shared/models/project/component.ts +45 -0
- package/src/shared/models/project/index.ts +14 -0
- package/src/shared/{project.ts → models/project/instance.ts} +12 -0
- package/src/shared/models/project/lock.ts +91 -0
- package/src/shared/{operation.ts → models/project/operation.ts} +43 -8
- package/src/shared/models/project/page.ts +57 -0
- package/src/shared/models/project/secret.ts +112 -0
- package/src/shared/models/project/service-account.ts +22 -0
- package/src/shared/models/project/state.ts +432 -0
- package/src/shared/models/project/terminal.ts +99 -0
- package/src/shared/models/project/trigger.ts +56 -0
- package/src/shared/models/project/unlock-method.ts +31 -0
- package/src/shared/models/project/worker.ts +105 -0
- package/src/shared/resolvers/graph-resolver.ts +74 -13
- package/src/shared/resolvers/index.ts +5 -0
- package/src/shared/resolvers/input-hash.ts +53 -15
- package/src/shared/resolvers/input.ts +1 -9
- package/src/shared/resolvers/registry.ts +7 -2
- package/src/shared/resolvers/state.ts +12 -0
- package/src/shared/resolvers/validation.ts +61 -20
- package/src/shared/{async-batcher.ts → utils/async-batcher.ts} +13 -1
- package/src/shared/utils/hash.ts +6 -0
- package/src/shared/utils/index.ts +3 -0
- package/src/shared/utils/promise-tracker.ts +23 -0
- package/src/state/abstractions.ts +330 -101
- package/src/state/encryption.ts +59 -0
- package/src/state/factory.ts +3 -5
- package/src/state/index.ts +3 -0
- package/src/state/keyring.ts +22 -0
- package/src/state/local/backend.ts +299 -0
- package/src/state/local/collection.ts +342 -0
- package/src/state/local/index.ts +2 -0
- package/src/state/manager.ts +804 -18
- package/src/state/repository/index.ts +2 -0
- package/src/state/repository/repository.index.ts +193 -0
- package/src/state/repository/repository.ts +458 -0
- package/src/terminal/{shared.ts → abstractions.ts} +3 -3
- package/src/terminal/docker.ts +18 -14
- package/src/terminal/factory.ts +3 -3
- package/src/terminal/index.ts +1 -1
- package/src/terminal/manager.ts +134 -80
- package/src/terminal/run.sh.ts +22 -10
- package/src/worker/abstractions.ts +42 -0
- package/src/worker/docker.ts +83 -0
- package/src/worker/factory.ts +20 -0
- package/src/worker/index.ts +3 -0
- package/src/worker/manager.ts +139 -0
- package/dist/chunk-C2TJAQAD.js +0 -937
- package/dist/chunk-C2TJAQAD.js.map +0 -1
- package/dist/chunk-WXDYCRTT.js +0 -234
- package/dist/chunk-WXDYCRTT.js.map +0 -1
- package/src/library/worker/loader.ts +0 -114
- package/src/preferences/shared.ts +0 -1
- package/src/project/lock.ts +0 -39
- package/src/secret/abstractions.ts +0 -59
- package/src/secret/factory.ts +0 -22
- package/src/secret/local.ts +0 -152
- package/src/shared/state.ts +0 -270
- package/src/shared/terminal.ts +0 -13
- package/src/state/local.ts +0 -612
- package/src/workspace/abstractions.ts +0 -41
- package/src/workspace/factory.ts +0 -14
- package/src/workspace/local.ts +0 -54
- /package/src/shared/{library.ts → models/backend/library.ts} +0 -0
|
@@ -0,0 +1,2017 @@
|
|
|
1
|
+
// src/shared/models/base.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var userObjectMetaSchema = z.object({
|
|
4
|
+
/**
|
|
5
|
+
* Human-readable name of the object.
|
|
6
|
+
*
|
|
7
|
+
* Used in UI components for better user experience.
|
|
8
|
+
*/
|
|
9
|
+
title: z.string().optional(),
|
|
10
|
+
/**
|
|
11
|
+
* The title used globally for the object.
|
|
12
|
+
*
|
|
13
|
+
* For example, the title of an instance secret is "Password" which is okay
|
|
14
|
+
* to display in the instance secret list, but when the secret is displayed in a
|
|
15
|
+
* global secret list the name should be more descriptive, like "Proxmox Password".
|
|
16
|
+
*/
|
|
17
|
+
globalTitle: z.string().optional(),
|
|
18
|
+
/**
|
|
19
|
+
* Description of the object.
|
|
20
|
+
*
|
|
21
|
+
* Provides additional context for users and developers.
|
|
22
|
+
*/
|
|
23
|
+
description: z.string().optional(),
|
|
24
|
+
/**
|
|
25
|
+
* The color of the object.
|
|
26
|
+
*
|
|
27
|
+
* Used in UI components to visually distinguish objects.
|
|
28
|
+
*/
|
|
29
|
+
color: z.string().optional(),
|
|
30
|
+
/**
|
|
31
|
+
* Primary icon identifier.
|
|
32
|
+
*
|
|
33
|
+
* Should reference a iconify icon name, like "mdi:server" or "gg:remote".
|
|
34
|
+
*/
|
|
35
|
+
icon: z.string().optional(),
|
|
36
|
+
/**
|
|
37
|
+
* The color of the primary icon.
|
|
38
|
+
*/
|
|
39
|
+
iconColor: z.string().optional(),
|
|
40
|
+
/**
|
|
41
|
+
* The secondary icon identifier.
|
|
42
|
+
*
|
|
43
|
+
* Used to provide additional context or actions related to the object.
|
|
44
|
+
*
|
|
45
|
+
* Should reference a iconify icon name, like "mdi:edit" or "mdi:delete".
|
|
46
|
+
*/
|
|
47
|
+
secondaryIcon: z.string().optional(),
|
|
48
|
+
/**
|
|
49
|
+
* The color of the secondary icon.
|
|
50
|
+
*/
|
|
51
|
+
secondaryIconColor: z.string().optional()
|
|
52
|
+
});
|
|
53
|
+
var objectMetaSchema = userObjectMetaSchema.extend({
|
|
54
|
+
/**
|
|
55
|
+
* Creation timestamp in milliseconds.
|
|
56
|
+
*
|
|
57
|
+
* Managed automatically by the system.
|
|
58
|
+
*/
|
|
59
|
+
createdAt: z.number().optional(),
|
|
60
|
+
/**
|
|
61
|
+
* Last update timestamp in milliseconds.
|
|
62
|
+
*
|
|
63
|
+
* Managed automatically by the system.
|
|
64
|
+
*/
|
|
65
|
+
updatedAt: z.number().optional(),
|
|
66
|
+
/**
|
|
67
|
+
* The optional version of the document to support optimistic concurrency control.
|
|
68
|
+
*
|
|
69
|
+
* Managed automatically by the system.
|
|
70
|
+
*/
|
|
71
|
+
version: z.number().optional()
|
|
72
|
+
});
|
|
73
|
+
function hasObjectMeta(value) {
|
|
74
|
+
return typeof value === "object" && value !== null && "meta" in value;
|
|
75
|
+
}
|
|
76
|
+
var collectionQuerySchema = z.object({
|
|
77
|
+
/**
|
|
78
|
+
* The search string to filter documents by display name, description, or other text fields.
|
|
79
|
+
*
|
|
80
|
+
* Not implemented yet.
|
|
81
|
+
*/
|
|
82
|
+
search: z.string().optional(),
|
|
83
|
+
/**
|
|
84
|
+
* The skip count for pagination.
|
|
85
|
+
*
|
|
86
|
+
* Cannot be used with `cursor`.
|
|
87
|
+
*/
|
|
88
|
+
skip: z.number().int().nonnegative().optional(),
|
|
89
|
+
/**
|
|
90
|
+
* The sorting order for the results.
|
|
91
|
+
*
|
|
92
|
+
* By default, "asc" is used.
|
|
93
|
+
*/
|
|
94
|
+
sort: z.enum(["asc", "desc"]).default("asc"),
|
|
95
|
+
/**
|
|
96
|
+
* The ID of the document to start the query from.
|
|
97
|
+
*
|
|
98
|
+
* If "asc" sorting is used, this will return results after this ID.
|
|
99
|
+
* Otherwise, it will return results before this ID.
|
|
100
|
+
*
|
|
101
|
+
* Cannot be used with `skip`.
|
|
102
|
+
*/
|
|
103
|
+
cursor: z.string().optional(),
|
|
104
|
+
/**
|
|
105
|
+
* The count of documents to return.
|
|
106
|
+
*
|
|
107
|
+
* Defaults to 20 if not specified.
|
|
108
|
+
* Maximum value is 100.
|
|
109
|
+
*/
|
|
110
|
+
count: z.number().int().nonnegative().max(100).optional()
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// src/shared/models/backend/project.ts
|
|
114
|
+
import { z as z16 } from "zod";
|
|
115
|
+
|
|
116
|
+
// src/shared/models/project/instance.ts
|
|
117
|
+
import { z as z2 } from "zod";
|
|
118
|
+
var positionSchema = z2.object({
|
|
119
|
+
x: z2.number(),
|
|
120
|
+
y: z2.number()
|
|
121
|
+
});
|
|
122
|
+
var instanceInputSchema = z2.object({
|
|
123
|
+
instanceId: z2.string(),
|
|
124
|
+
output: z2.string()
|
|
125
|
+
});
|
|
126
|
+
var hubInstanceInputSchema = z2.object({
|
|
127
|
+
hubId: z2.string()
|
|
128
|
+
});
|
|
129
|
+
var instanceModelPatchSchema = z2.object({
|
|
130
|
+
args: z2.record(z2.unknown()).optional(),
|
|
131
|
+
inputs: z2.record(z2.array(instanceInputSchema)).optional(),
|
|
132
|
+
hubInputs: z2.record(z2.array(hubInstanceInputSchema)).optional(),
|
|
133
|
+
injectionInputs: z2.array(hubInstanceInputSchema).optional(),
|
|
134
|
+
position: positionSchema.optional()
|
|
135
|
+
});
|
|
136
|
+
var instanceModelSchema = z2.object({
|
|
137
|
+
id: z2.string(),
|
|
138
|
+
type: z2.string(),
|
|
139
|
+
name: z2.string(),
|
|
140
|
+
...instanceModelPatchSchema.shape,
|
|
141
|
+
resolvedInputs: z2.record(z2.array(instanceInputSchema)).optional(),
|
|
142
|
+
parentId: z2.string().optional(),
|
|
143
|
+
outputs: z2.record(z2.array(instanceInputSchema)).optional(),
|
|
144
|
+
resolvedOutputs: z2.record(z2.array(instanceInputSchema)).optional()
|
|
145
|
+
});
|
|
146
|
+
var compositeInstanceSchema = z2.object({
|
|
147
|
+
instance: instanceModelSchema,
|
|
148
|
+
children: z2.array(instanceModelSchema),
|
|
149
|
+
childCompositeInstanceIds: z2.array(z2.string()).optional(),
|
|
150
|
+
inputHash: z2.string().optional()
|
|
151
|
+
});
|
|
152
|
+
var compositeInstanceEventSchema = z2.discriminatedUnion("type", [
|
|
153
|
+
z2.object({
|
|
154
|
+
type: z2.literal("updated"),
|
|
155
|
+
instance: compositeInstanceSchema
|
|
156
|
+
}),
|
|
157
|
+
z2.object({
|
|
158
|
+
type: z2.literal("deleted"),
|
|
159
|
+
instanceId: z2.string()
|
|
160
|
+
})
|
|
161
|
+
]);
|
|
162
|
+
var hubModelPatchSchema = z2.object({
|
|
163
|
+
position: positionSchema.optional(),
|
|
164
|
+
inputs: z2.array(instanceInputSchema).optional(),
|
|
165
|
+
injectionInputs: z2.array(hubInstanceInputSchema).optional()
|
|
166
|
+
});
|
|
167
|
+
var hubModelSchema = z2.object({
|
|
168
|
+
id: z2.string().nanoid(),
|
|
169
|
+
position: positionSchema,
|
|
170
|
+
inputs: z2.array(instanceInputSchema).optional(),
|
|
171
|
+
injectionInputs: z2.array(hubInstanceInputSchema).optional()
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// src/shared/models/project/state.ts
|
|
175
|
+
import { z as z3 } from "zod";
|
|
176
|
+
var instanceOperationStatusEnumSchema = z3.enum([
|
|
177
|
+
// transient statuses
|
|
178
|
+
"updating",
|
|
179
|
+
"processing-triggers",
|
|
180
|
+
"previewing",
|
|
181
|
+
"destroying",
|
|
182
|
+
"refreshing",
|
|
183
|
+
"pending",
|
|
184
|
+
"cancelling",
|
|
185
|
+
// stable statuses
|
|
186
|
+
"created",
|
|
187
|
+
"error"
|
|
188
|
+
]);
|
|
189
|
+
var instanceOperationStatusSchema = z3.object({
|
|
190
|
+
/**
|
|
191
|
+
* The enum representing the current status of the instance from the operation perspective.
|
|
192
|
+
*/
|
|
193
|
+
status: instanceOperationStatusEnumSchema,
|
|
194
|
+
/**
|
|
195
|
+
* The ID of the latest operation that this instance is associated with.
|
|
196
|
+
*/
|
|
197
|
+
latestOperationId: z3.string(),
|
|
198
|
+
/**
|
|
199
|
+
* The IDs of the instances that this instance depends on at the moment of latest operation.
|
|
200
|
+
*/
|
|
201
|
+
dependencyIds: z3.array(z3.string()),
|
|
202
|
+
/**
|
|
203
|
+
* The some human-readable message describing the current status.
|
|
204
|
+
* Typically used to show the error message if the status is "error".
|
|
205
|
+
*/
|
|
206
|
+
message: z3.string().optional(),
|
|
207
|
+
/**
|
|
208
|
+
* The current count of the Pulumi resources being managed by this instance.
|
|
209
|
+
*/
|
|
210
|
+
currentResourceCount: z3.number().optional(),
|
|
211
|
+
/**
|
|
212
|
+
* The total count of the Pulumi resources that this instance is expected to manage.
|
|
213
|
+
*/
|
|
214
|
+
totalResourceCount: z3.number().optional(),
|
|
215
|
+
/**
|
|
216
|
+
* The calculated instance CRC32 input hash at the moment of latest operation completion.
|
|
217
|
+
*
|
|
218
|
+
* This hash covers:
|
|
219
|
+
* - the instance's configuration (name, args, secret hashes);
|
|
220
|
+
* - the component definition hash;
|
|
221
|
+
* - the unit's source hash (if applicable);
|
|
222
|
+
* - the input hashes and output hashes of all input instances.
|
|
223
|
+
*/
|
|
224
|
+
inputHash: z3.number().optional(),
|
|
225
|
+
/**
|
|
226
|
+
* The random 32-bit nonce used in input hash calculation.
|
|
227
|
+
*
|
|
228
|
+
* It is changed every time the instance secrets are updated,
|
|
229
|
+
* to invalidate the input hash and force running the instance again.
|
|
230
|
+
*/
|
|
231
|
+
inputHashNonce: z3.number().optional(),
|
|
232
|
+
/**
|
|
233
|
+
* The sha256 of the output produced by the instance at the moment of latest operation completion.
|
|
234
|
+
*
|
|
235
|
+
* Does not depend on anything except the instance's output.
|
|
236
|
+
*/
|
|
237
|
+
outputHash: z3.string().optional(),
|
|
238
|
+
/**
|
|
239
|
+
* The calculated sha256 dependency output hash at the moment of latest operation completion.
|
|
240
|
+
*
|
|
241
|
+
* This hash is calculated as combination of output hashes of all input instances and nothing else.
|
|
242
|
+
*
|
|
243
|
+
* The primary use case of this hash is to "short-circuit" execution:
|
|
244
|
+
* if the outputs of input instances have not changed, dependent instances can skip execution,
|
|
245
|
+
* even if their input hashes changed due to upstream config changes.
|
|
246
|
+
* This prevents unnecessary re-execution of the entire dependency graph when only non-output-affecting inputs are modified.
|
|
247
|
+
*/
|
|
248
|
+
dependencyOutputHash: z3.string().optional(),
|
|
249
|
+
/**
|
|
250
|
+
* The arguments of the instances at the moment of latest operation start.
|
|
251
|
+
*/
|
|
252
|
+
args: z3.record(z3.unknown()).optional()
|
|
253
|
+
});
|
|
254
|
+
var instanceEvaludationStatusEnumSchema = z3.enum([
|
|
255
|
+
// transient statuses
|
|
256
|
+
"evaluating",
|
|
257
|
+
// stable statuses
|
|
258
|
+
"evaluated",
|
|
259
|
+
"error"
|
|
260
|
+
]);
|
|
261
|
+
var instanceEvaluationStatusSchema = z3.object({
|
|
262
|
+
/**
|
|
263
|
+
* The enum representing the current status of the instance from the evaluation perspective.
|
|
264
|
+
*
|
|
265
|
+
* The stable status when instance is not evaludated is forbidden.
|
|
266
|
+
*/
|
|
267
|
+
status: instanceEvaludationStatusEnumSchema,
|
|
268
|
+
/**
|
|
269
|
+
* The message describing the evaluation status.
|
|
270
|
+
* Typically used to show the error message if the status is "error".
|
|
271
|
+
*/
|
|
272
|
+
message: z3.string().optional()
|
|
273
|
+
});
|
|
274
|
+
var WellKnownInstanceCustomStatus = /* @__PURE__ */ ((WellKnownInstanceCustomStatus2) => {
|
|
275
|
+
WellKnownInstanceCustomStatus2["Healthy"] = "healthy";
|
|
276
|
+
WellKnownInstanceCustomStatus2["Degraded"] = "degraded";
|
|
277
|
+
WellKnownInstanceCustomStatus2["Down"] = "down";
|
|
278
|
+
WellKnownInstanceCustomStatus2["Warning"] = "warning";
|
|
279
|
+
WellKnownInstanceCustomStatus2["Progressing"] = "progressing";
|
|
280
|
+
WellKnownInstanceCustomStatus2["Error"] = "error";
|
|
281
|
+
return WellKnownInstanceCustomStatus2;
|
|
282
|
+
})(WellKnownInstanceCustomStatus || {});
|
|
283
|
+
var instanceCustomStatusSchema = z3.object({
|
|
284
|
+
/**
|
|
285
|
+
* The name of the instance's extra status.
|
|
286
|
+
*
|
|
287
|
+
* Must be unique within the instance state.
|
|
288
|
+
*/
|
|
289
|
+
name: z3.string(),
|
|
290
|
+
/**
|
|
291
|
+
* The enum value of the instance's extra status.
|
|
292
|
+
*
|
|
293
|
+
* May be on of the `WellKnownExtraInstanceStatus` values or a custom value.
|
|
294
|
+
*/
|
|
295
|
+
status: z3.string(),
|
|
296
|
+
/**
|
|
297
|
+
* The display name of the instance's extra status.
|
|
298
|
+
*/
|
|
299
|
+
displayName: z3.string(),
|
|
300
|
+
/**
|
|
301
|
+
* The `iconify` icon representing the instance's extra status.
|
|
302
|
+
*
|
|
303
|
+
* If not provided and status is a well-known value, the icon will be derived from the status.
|
|
304
|
+
*/
|
|
305
|
+
icon: z3.string().optional(),
|
|
306
|
+
/**
|
|
307
|
+
* The HEX color of the status badge.
|
|
308
|
+
*
|
|
309
|
+
* If not provided and status is a well-known value, the color will be derived from the status.
|
|
310
|
+
*/
|
|
311
|
+
color: z3.string().optional(),
|
|
312
|
+
/**
|
|
313
|
+
* The message describing the instance's extra status.
|
|
314
|
+
*
|
|
315
|
+
* Can be used to provide additional context or information about the status.
|
|
316
|
+
*
|
|
317
|
+
* The message will be displayed in the 800x600 ANSI terminal in the UI,
|
|
318
|
+
* so differenet TUI elements should be drawn within this area.
|
|
319
|
+
*/
|
|
320
|
+
message: z3.string().optional(),
|
|
321
|
+
/**
|
|
322
|
+
* The order of the status in the list of statuses.
|
|
323
|
+
*
|
|
324
|
+
* Must be in the range from `0` to `100`, lower values are displayed first.
|
|
325
|
+
*
|
|
326
|
+
* If not provided, the default is `50`.
|
|
327
|
+
*/
|
|
328
|
+
order: z3.number().min(0).max(100).optional()
|
|
329
|
+
});
|
|
330
|
+
var instanceStatusFieldValueSchema = z3.union([
|
|
331
|
+
z3.string(),
|
|
332
|
+
z3.number(),
|
|
333
|
+
z3.boolean(),
|
|
334
|
+
z3.array(z3.string())
|
|
335
|
+
]);
|
|
336
|
+
var instanceStatusFieldSchema = z3.object({
|
|
337
|
+
name: z3.string(),
|
|
338
|
+
meta: objectMetaSchema,
|
|
339
|
+
complementaryTo: z3.string().optional(),
|
|
340
|
+
value: instanceStatusFieldValueSchema.optional()
|
|
341
|
+
});
|
|
342
|
+
var unitInstanceStatusFieldSchema = instanceStatusFieldSchema.omit({ meta: true }).extend({
|
|
343
|
+
meta: userObjectMetaSchema
|
|
344
|
+
});
|
|
345
|
+
var instanceStateExtraSchema = z3.object({
|
|
346
|
+
/**
|
|
347
|
+
* The status fields reported by the unit or attached via the API.
|
|
348
|
+
*
|
|
349
|
+
* Do not confuse with `customStatuses`.
|
|
350
|
+
*
|
|
351
|
+
* These fields are used to store additional information about the instance,
|
|
352
|
+
* such as URLs, display names, and other metadata.
|
|
353
|
+
*/
|
|
354
|
+
statusFields: z3.array(instanceStatusFieldSchema).optional(),
|
|
355
|
+
/**
|
|
356
|
+
* The extra statuses of the instance reported by the unit or attached via the API.
|
|
357
|
+
*
|
|
358
|
+
* Do not confuse with `statusFields.
|
|
359
|
+
*/
|
|
360
|
+
customStatuses: z3.array(instanceCustomStatusSchema).optional(),
|
|
361
|
+
/**
|
|
362
|
+
* The IDs of the pages that are owned by this instance.
|
|
363
|
+
*
|
|
364
|
+
* The keys are the local page names, and the values are the page IDs.
|
|
365
|
+
*/
|
|
366
|
+
pageIds: z3.record(z3.string()).optional(),
|
|
367
|
+
/**
|
|
368
|
+
* The IDs of the terminals that are owned by this instance.
|
|
369
|
+
*
|
|
370
|
+
* The keys are the local terminal names, and the values are the terminal IDs.
|
|
371
|
+
*/
|
|
372
|
+
terminalIds: z3.record(z3.string()).optional(),
|
|
373
|
+
/**
|
|
374
|
+
* The IDs of the triggers that are owned by this instance.
|
|
375
|
+
*
|
|
376
|
+
* The keys are the local trigger names, and the values are the trigger IDs.
|
|
377
|
+
*/
|
|
378
|
+
triggerIds: z3.record(z3.string()).optional(),
|
|
379
|
+
/**
|
|
380
|
+
* The IDs of the artifacts that are owned by this instance.
|
|
381
|
+
*
|
|
382
|
+
* The keys are the output keys, and the values are the artifact IDs.
|
|
383
|
+
*/
|
|
384
|
+
ownedArtifactIds: z3.record(z3.array(z3.string())).optional(),
|
|
385
|
+
/**
|
|
386
|
+
* The IDs of the artifacts that are used by this instance.
|
|
387
|
+
*
|
|
388
|
+
* This is a flat list of artifact IDs, not grouped by output keys.
|
|
389
|
+
*/
|
|
390
|
+
usedArtifactIds: z3.array(z3.string()).optional(),
|
|
391
|
+
/**
|
|
392
|
+
* The IDs of the worker registrations that are associated with this instance.
|
|
393
|
+
*/
|
|
394
|
+
workerRegistrationIds: z3.array(z3.string()).optional()
|
|
395
|
+
});
|
|
396
|
+
var instanceStateSchema = z3.object({
|
|
397
|
+
/**
|
|
398
|
+
* The unique identifier of the instance.
|
|
399
|
+
* The format is `{componentType}:{instanceName}`, so each instance must have a unique name within its component type.
|
|
400
|
+
*/
|
|
401
|
+
id: z3.string(),
|
|
402
|
+
/**
|
|
403
|
+
* The ID of the parent instance, if this instance is a child of another composite instance.
|
|
404
|
+
*/
|
|
405
|
+
parentId: z3.string().optional(),
|
|
406
|
+
/**
|
|
407
|
+
* The names of the secrets that has values in this instance.
|
|
408
|
+
*/
|
|
409
|
+
secretNames: z3.array(z3.string()).optional(),
|
|
410
|
+
/**
|
|
411
|
+
* The current status of the instance from the operation perspective.
|
|
412
|
+
*
|
|
413
|
+
* This status persists in the storage only when the operation is completed.
|
|
414
|
+
*
|
|
415
|
+
* If the operation was interrupted, the status will be "error" with corresponding error message.
|
|
416
|
+
*
|
|
417
|
+
* If the instance was not created or was successfully destroyed, the whole "operationStatus" field will be undefined.
|
|
418
|
+
*/
|
|
419
|
+
operationStatus: instanceOperationStatusSchema.optional(),
|
|
420
|
+
/**
|
|
421
|
+
* The current status of the instance from the evaluation perspective.
|
|
422
|
+
*
|
|
423
|
+
* Only applies to composite instances, will always be `undefined` for unit instances.
|
|
424
|
+
*/
|
|
425
|
+
evaluationStatus: instanceEvaluationStatusSchema.optional(),
|
|
426
|
+
/**
|
|
427
|
+
* The extra components of the instance.
|
|
428
|
+
*
|
|
429
|
+
* Applies to both unit and composite instances.
|
|
430
|
+
*/
|
|
431
|
+
extra: instanceStateExtraSchema.optional()
|
|
432
|
+
});
|
|
433
|
+
var instanceStatePatchSchema = z3.object({
|
|
434
|
+
id: z3.string(),
|
|
435
|
+
parentId: z3.string().nullish(),
|
|
436
|
+
secretNames: z3.array(z3.string()).nullish(),
|
|
437
|
+
operationStatus: instanceOperationStatusSchema.partial().nullish(),
|
|
438
|
+
evaluationStatus: instanceEvaluationStatusSchema.partial().nullish(),
|
|
439
|
+
extra: instanceStateExtraSchema.partial().nullish()
|
|
440
|
+
});
|
|
441
|
+
function applyStatePatch(existingState, patch) {
|
|
442
|
+
const state = existingState ? { ...existingState } : { id: patch.id };
|
|
443
|
+
const anyPatch = patch;
|
|
444
|
+
for (const key of Object.keys(patch)) {
|
|
445
|
+
if (typeof anyPatch[key] === "undefined") {
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
if (typeof anyPatch[key] !== "object" || anyPatch[key] === null || Array.isArray(anyPatch[key])) {
|
|
449
|
+
state[key] = anyPatch[key] === null ? void 0 : anyPatch[key];
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
const existingValue = state[key] ? { ...state[key] } : {};
|
|
453
|
+
for (const subKey of Object.keys(anyPatch[key])) {
|
|
454
|
+
existingValue[subKey] = anyPatch[key][subKey];
|
|
455
|
+
}
|
|
456
|
+
state[key] = existingValue;
|
|
457
|
+
}
|
|
458
|
+
return state;
|
|
459
|
+
}
|
|
460
|
+
function isStateEmpty(state) {
|
|
461
|
+
return !state.operationStatus && !state.evaluationStatus && (!state.extra || Object.keys(state.extra).length === 0) && (!state.secretNames || state.secretNames.length === 0);
|
|
462
|
+
}
|
|
463
|
+
function isTransientOperationStatus(status) {
|
|
464
|
+
return status !== "created" && status !== "error";
|
|
465
|
+
}
|
|
466
|
+
function isStableOperationStatus(status) {
|
|
467
|
+
return status === "created" || status === "error";
|
|
468
|
+
}
|
|
469
|
+
var instanceStateEventSchema = z3.discriminatedUnion("type", [
|
|
470
|
+
z3.object({
|
|
471
|
+
type: z3.literal("patched"),
|
|
472
|
+
patch: instanceStatePatchSchema
|
|
473
|
+
}),
|
|
474
|
+
z3.object({
|
|
475
|
+
type: z3.literal("updated"),
|
|
476
|
+
state: instanceStateSchema
|
|
477
|
+
}),
|
|
478
|
+
z3.object({
|
|
479
|
+
type: z3.literal("deleted"),
|
|
480
|
+
instanceId: z3.string()
|
|
481
|
+
})
|
|
482
|
+
]);
|
|
483
|
+
|
|
484
|
+
// src/shared/models/project/operation.ts
|
|
485
|
+
import { z as z4 } from "zod";
|
|
486
|
+
var operationTypeSchema = z4.enum(["update", "preview", "destroy", "recreate", "refresh"]);
|
|
487
|
+
var operationStatusSchema = z4.enum([
|
|
488
|
+
"pending",
|
|
489
|
+
"running",
|
|
490
|
+
"completed",
|
|
491
|
+
"failed",
|
|
492
|
+
"cancelled",
|
|
493
|
+
"failing"
|
|
494
|
+
]);
|
|
495
|
+
var operationOptionsSchema = z4.object({
|
|
496
|
+
/**
|
|
497
|
+
* Whether to force update all dependencies of the instances even if they are not changed.
|
|
498
|
+
*
|
|
499
|
+
* Only applicable for `update`, `preview`, `recreate`, and `refresh` operations.
|
|
500
|
+
*
|
|
501
|
+
* By default, `false`.
|
|
502
|
+
*/
|
|
503
|
+
forceUpdateDependencies: z4.boolean().default(false),
|
|
504
|
+
/**
|
|
505
|
+
* Whether to force update all children of the composite instances even if they are not changed.
|
|
506
|
+
*
|
|
507
|
+
* Only applicable for `update`, `preview`, `recreate`, and `refresh` operations.
|
|
508
|
+
*
|
|
509
|
+
* By default, `false`.
|
|
510
|
+
*/
|
|
511
|
+
forceUpdateChildren: z4.boolean().default(false),
|
|
512
|
+
/**
|
|
513
|
+
* Whether to destroy all dependents of the instances when destroying them.
|
|
514
|
+
*
|
|
515
|
+
* Only applicable for `destroy` and `recreate` operations.
|
|
516
|
+
*
|
|
517
|
+
* By default, `true`.
|
|
518
|
+
*/
|
|
519
|
+
destroyDependentInstances: z4.boolean().default(true),
|
|
520
|
+
/**
|
|
521
|
+
* Whether to invoke destroy triggers when destroying the instances.
|
|
522
|
+
*
|
|
523
|
+
* Only applicable for `destroy`.
|
|
524
|
+
*
|
|
525
|
+
* By default, `true`.
|
|
526
|
+
*/
|
|
527
|
+
invokeDestroyTriggers: z4.boolean().default(true),
|
|
528
|
+
/**
|
|
529
|
+
* Whether to delete unreachable resources when updating or destroying the instances.
|
|
530
|
+
* This is potentially dangerous and should be used with caution.
|
|
531
|
+
*
|
|
532
|
+
* By default, `false`.
|
|
533
|
+
*/
|
|
534
|
+
deleteUnreachableResources: z4.boolean().default(false),
|
|
535
|
+
/**
|
|
536
|
+
* Whether to delete the stack state even if the destroy operation fails.
|
|
537
|
+
* This is very dangerous and should be used only when the stack is unrecoverable.
|
|
538
|
+
*
|
|
539
|
+
* By default, `false`.
|
|
540
|
+
*/
|
|
541
|
+
forceDeleteState: z4.boolean().default(false),
|
|
542
|
+
/**
|
|
543
|
+
* Whether to allow partial updates of composite instances when updating, destroying or recreating them.
|
|
544
|
+
*
|
|
545
|
+
* If `true`, the operation will only update/destroy composite instance children that are directly referenced by other affected instances.
|
|
546
|
+
* If `false`, the operation will update/destroy all children at of the composite instances at all levels if at least one of them is referenced by affected instances.
|
|
547
|
+
*
|
|
548
|
+
* By default, `false`.
|
|
549
|
+
*/
|
|
550
|
+
allowPartialCompositeInstanceUpdates: z4.boolean().default(false),
|
|
551
|
+
/**
|
|
552
|
+
* Whether to refresh the state before running the operation.
|
|
553
|
+
*
|
|
554
|
+
* By default, `false`.
|
|
555
|
+
*/
|
|
556
|
+
refresh: z4.boolean().default(false)
|
|
557
|
+
});
|
|
558
|
+
var operationRequestSchema = z4.object({
|
|
559
|
+
projectId: z4.string(),
|
|
560
|
+
type: operationTypeSchema,
|
|
561
|
+
instanceIds: z4.array(z4.string()),
|
|
562
|
+
options: operationOptionsSchema.partial().optional()
|
|
563
|
+
});
|
|
564
|
+
var operationSchema = z4.object({
|
|
565
|
+
id: z4.string().uuid(),
|
|
566
|
+
meta: objectMetaSchema,
|
|
567
|
+
status: operationStatusSchema,
|
|
568
|
+
error: z4.string().nullable(),
|
|
569
|
+
type: operationTypeSchema,
|
|
570
|
+
requestedInstanceIds: z4.array(z4.string()),
|
|
571
|
+
instanceIdsToUpdate: z4.array(z4.string()).default(() => []),
|
|
572
|
+
instanceIdsToDestroy: z4.array(z4.string()).default(() => []),
|
|
573
|
+
options: operationOptionsSchema,
|
|
574
|
+
startedAt: z4.number(),
|
|
575
|
+
completedAt: z4.number().nullable()
|
|
576
|
+
});
|
|
577
|
+
function isFinalOperationStatus(status) {
|
|
578
|
+
return status === "completed" || status === "failed" || status === "cancelled";
|
|
579
|
+
}
|
|
580
|
+
var operationLogEntrySchema = z4.tuple([
|
|
581
|
+
z4.string().uuid(),
|
|
582
|
+
// UUIDv7
|
|
583
|
+
z4.string()
|
|
584
|
+
// The log message
|
|
585
|
+
]);
|
|
586
|
+
var operationEventSchema = z4.discriminatedUnion("type", [
|
|
587
|
+
z4.object({
|
|
588
|
+
type: z4.literal("updated"),
|
|
589
|
+
operation: operationSchema
|
|
590
|
+
}),
|
|
591
|
+
z4.object({
|
|
592
|
+
type: z4.literal("deleted"),
|
|
593
|
+
operationId: z4.string()
|
|
594
|
+
})
|
|
595
|
+
]);
|
|
596
|
+
|
|
597
|
+
// src/shared/models/project/terminal.ts
|
|
598
|
+
import { z as z6 } from "zod";
|
|
599
|
+
|
|
600
|
+
// src/shared/models/project/artifact.ts
|
|
601
|
+
import { z as z5 } from "zod";
|
|
602
|
+
import {
|
|
603
|
+
HighstateSignature
|
|
604
|
+
} from "@highstate/contract";
|
|
605
|
+
var artifactUsageSchema = z5.discriminatedUnion("type", [
|
|
606
|
+
z5.object({
|
|
607
|
+
type: z5.literal("instance"),
|
|
608
|
+
instanceId: z5.string()
|
|
609
|
+
}),
|
|
610
|
+
z5.object({
|
|
611
|
+
type: z5.literal("terminal"),
|
|
612
|
+
terminalId: z5.string()
|
|
613
|
+
}),
|
|
614
|
+
z5.object({
|
|
615
|
+
type: z5.literal("service-account"),
|
|
616
|
+
serviceAccountId: z5.string()
|
|
617
|
+
})
|
|
618
|
+
]);
|
|
619
|
+
function compareArtifactUsage(a, b) {
|
|
620
|
+
if (a.type === "instance" && b.type === "instance") {
|
|
621
|
+
return a.instanceId === b.instanceId;
|
|
622
|
+
}
|
|
623
|
+
if (a.type === "terminal" && b.type === "terminal") {
|
|
624
|
+
return a.terminalId === b.terminalId;
|
|
625
|
+
}
|
|
626
|
+
if (a.type === "service-account" && b.type === "service-account") {
|
|
627
|
+
return a.serviceAccountId === b.serviceAccountId;
|
|
628
|
+
}
|
|
629
|
+
return false;
|
|
630
|
+
}
|
|
631
|
+
var fileMetaSchema = z5.object({
|
|
632
|
+
name: z5.string(),
|
|
633
|
+
size: z5.number().optional(),
|
|
634
|
+
isBinary: z5.boolean().optional(),
|
|
635
|
+
mode: z5.number().optional()
|
|
636
|
+
});
|
|
637
|
+
var artifactSchema = z5.object({
|
|
638
|
+
/**
|
|
639
|
+
* The UUIDv7 of the artifact generated when the artifact with unique content is first stored.
|
|
640
|
+
*/
|
|
641
|
+
id: z5.string().uuid(),
|
|
642
|
+
meta: objectMetaSchema,
|
|
643
|
+
/**
|
|
644
|
+
* The SHA-256 hash of the artifact content before encryption.
|
|
645
|
+
*/
|
|
646
|
+
hash: z5.string(),
|
|
647
|
+
/**
|
|
648
|
+
* The list of usages of this artifact.
|
|
649
|
+
*
|
|
650
|
+
* When became empty, the artifact is garbage collected.
|
|
651
|
+
*/
|
|
652
|
+
usages: artifactUsageSchema.array(),
|
|
653
|
+
/**
|
|
654
|
+
* The size of the unencrypted artifact archive in bytes.
|
|
655
|
+
*/
|
|
656
|
+
size: z5.number(),
|
|
657
|
+
/**
|
|
658
|
+
* The size of each chunk of the artifact which independently encrypted.
|
|
659
|
+
*/
|
|
660
|
+
chunkSize: z5.number()
|
|
661
|
+
});
|
|
662
|
+
var unitArtifactSchema = z5.object({
|
|
663
|
+
hash: z5.string(),
|
|
664
|
+
meta: userObjectMetaSchema.optional()
|
|
665
|
+
});
|
|
666
|
+
var fileContentSchema = z5.union([
|
|
667
|
+
z5.object({
|
|
668
|
+
type: z5.literal("embedded"),
|
|
669
|
+
value: z5.string()
|
|
670
|
+
}),
|
|
671
|
+
z5.object({
|
|
672
|
+
type: z5.literal("artifact"),
|
|
673
|
+
[HighstateSignature.Artifact]: unitArtifactSchema
|
|
674
|
+
})
|
|
675
|
+
]);
|
|
676
|
+
var fileSchema = z5.object({
|
|
677
|
+
meta: fileMetaSchema,
|
|
678
|
+
content: fileContentSchema
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
// src/shared/models/project/terminal.ts
|
|
682
|
+
var metaFields = {
|
|
683
|
+
title: true,
|
|
684
|
+
globalTitle: true,
|
|
685
|
+
description: true,
|
|
686
|
+
icon: true,
|
|
687
|
+
iconColor: true
|
|
688
|
+
};
|
|
689
|
+
var requiredMetaFields = {
|
|
690
|
+
title: true,
|
|
691
|
+
description: true
|
|
692
|
+
};
|
|
693
|
+
var terminalSchema = z6.object({
|
|
694
|
+
id: z6.string().uuid(),
|
|
695
|
+
// UUIDv7
|
|
696
|
+
meta: objectMetaSchema.pick({
|
|
697
|
+
...metaFields,
|
|
698
|
+
createdAt: true,
|
|
699
|
+
updatedAt: true
|
|
700
|
+
}).required(requiredMetaFields),
|
|
701
|
+
/**
|
|
702
|
+
* The ID of the instance produced the terminal if applicable.
|
|
703
|
+
*/
|
|
704
|
+
instanceId: z6.string().optional()
|
|
705
|
+
});
|
|
706
|
+
var terminalSpecSchema = z6.object({
|
|
707
|
+
image: z6.string(),
|
|
708
|
+
command: z6.string().array(),
|
|
709
|
+
cwd: z6.string().optional(),
|
|
710
|
+
env: z6.record(z6.string()).optional(),
|
|
711
|
+
files: z6.record(fileSchema).optional()
|
|
712
|
+
});
|
|
713
|
+
var unitTerminalSchema = z6.object({
|
|
714
|
+
name: z6.string(),
|
|
715
|
+
meta: userObjectMetaSchema.pick(metaFields).required(requiredMetaFields),
|
|
716
|
+
spec: terminalSpecSchema
|
|
717
|
+
});
|
|
718
|
+
var terminalSessionSchema = z6.object({
|
|
719
|
+
id: z6.string().uuid(),
|
|
720
|
+
// UUIDv7
|
|
721
|
+
meta: objectMetaSchema.pick({ ...metaFields, createdAt: true, updatedAt: true }).required(requiredMetaFields).extend({
|
|
722
|
+
/**
|
|
723
|
+
* The time when the session was finished.
|
|
724
|
+
*/
|
|
725
|
+
finishedAt: z6.number().optional()
|
|
726
|
+
}),
|
|
727
|
+
/**
|
|
728
|
+
* The ID of the project this session belongs to.
|
|
729
|
+
*/
|
|
730
|
+
projectId: z6.string(),
|
|
731
|
+
/**
|
|
732
|
+
* References the terminal this session is based on.
|
|
733
|
+
*/
|
|
734
|
+
terminalId: z6.string(),
|
|
735
|
+
/**
|
|
736
|
+
* References the instance produced the terminal if applicable.
|
|
737
|
+
*/
|
|
738
|
+
instanceId: z6.string().optional()
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
// src/shared/models/project/page.ts
|
|
742
|
+
import { z as z7 } from "zod";
|
|
743
|
+
var pageBlockSchema = z7.union([
|
|
744
|
+
z7.object({
|
|
745
|
+
type: z7.literal("markdown"),
|
|
746
|
+
content: z7.string()
|
|
747
|
+
}),
|
|
748
|
+
z7.object({
|
|
749
|
+
type: z7.literal("qr"),
|
|
750
|
+
content: z7.string(),
|
|
751
|
+
showContent: z7.coerce.boolean(),
|
|
752
|
+
language: z7.string().optional()
|
|
753
|
+
}),
|
|
754
|
+
fileSchema.extend({
|
|
755
|
+
type: z7.literal("file")
|
|
756
|
+
})
|
|
757
|
+
]);
|
|
758
|
+
var pageSchema = z7.object({
|
|
759
|
+
id: z7.string(),
|
|
760
|
+
instanceId: z7.string().optional(),
|
|
761
|
+
meta: objectMetaSchema
|
|
762
|
+
});
|
|
763
|
+
var pageContentSchema = z7.object({
|
|
764
|
+
id: z7.string(),
|
|
765
|
+
content: z7.array(pageBlockSchema)
|
|
766
|
+
});
|
|
767
|
+
var unitPageSchema = pageContentSchema.omit({ id: true }).extend({
|
|
768
|
+
name: z7.string(),
|
|
769
|
+
meta: userObjectMetaSchema
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
// src/shared/models/project/trigger.ts
|
|
773
|
+
import { z as z8 } from "zod";
|
|
774
|
+
var triggerSpecSchema = z8.union([
|
|
775
|
+
z8.object({
|
|
776
|
+
type: z8.literal("before-destroy")
|
|
777
|
+
}),
|
|
778
|
+
z8.object({
|
|
779
|
+
type: z8.literal("schedule"),
|
|
780
|
+
schedule: z8.string()
|
|
781
|
+
})
|
|
782
|
+
]);
|
|
783
|
+
var triggerSchema = z8.object({
|
|
784
|
+
id: z8.string(),
|
|
785
|
+
instanceId: z8.string(),
|
|
786
|
+
meta: objectMetaSchema,
|
|
787
|
+
spec: triggerSpecSchema
|
|
788
|
+
});
|
|
789
|
+
var unitTriggerSchema = triggerSchema.omit({ id: true, instanceId: true, meta: true }).extend({
|
|
790
|
+
name: z8.string(),
|
|
791
|
+
meta: userObjectMetaSchema.optional()
|
|
792
|
+
}).extend({
|
|
793
|
+
name: z8.string(),
|
|
794
|
+
meta: userObjectMetaSchema.optional()
|
|
795
|
+
});
|
|
796
|
+
var triggerInvocationSchema = z8.object({
|
|
797
|
+
name: z8.string()
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
// src/shared/models/project/unlock-method.ts
|
|
801
|
+
import { z as z9 } from "zod";
|
|
802
|
+
var unlockMethodType = z9.enum(["password", "passkey"]);
|
|
803
|
+
var unlockMethodSchema = z9.object({
|
|
804
|
+
id: z9.string(),
|
|
805
|
+
meta: objectMetaSchema,
|
|
806
|
+
/**
|
|
807
|
+
* The type of unlock method (password or passkey).
|
|
808
|
+
*/
|
|
809
|
+
type: unlockMethodType,
|
|
810
|
+
/**
|
|
811
|
+
* The encrypted identity used to decrypt the master key.
|
|
812
|
+
*/
|
|
813
|
+
encryptedIdentity: z9.string(),
|
|
814
|
+
/**
|
|
815
|
+
* The recipient of the unlock method to use to encrypt the master key for this unlock method.
|
|
816
|
+
*/
|
|
817
|
+
recipient: z9.string()
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
// src/shared/models/project/secret.ts
|
|
821
|
+
import { z as z10 } from "zod";
|
|
822
|
+
var secretDescriptorSchema = z10.discriminatedUnion("type", [
|
|
823
|
+
z10.object({
|
|
824
|
+
type: z10.literal("system"),
|
|
825
|
+
secretName: z10.string()
|
|
826
|
+
}),
|
|
827
|
+
z10.object({
|
|
828
|
+
type: z10.literal("instance"),
|
|
829
|
+
instanceId: z10.string(),
|
|
830
|
+
secretName: z10.string()
|
|
831
|
+
}),
|
|
832
|
+
z10.object({
|
|
833
|
+
type: z10.literal("custom"),
|
|
834
|
+
secretPath: z10.string()
|
|
835
|
+
})
|
|
836
|
+
]);
|
|
837
|
+
var secretSchema = z10.object({
|
|
838
|
+
/**
|
|
839
|
+
* The UUIDv7 of the secret generated when the secret is first created.
|
|
840
|
+
*/
|
|
841
|
+
id: z10.string().uuid(),
|
|
842
|
+
/**
|
|
843
|
+
* The metadata of the secret object.
|
|
844
|
+
*/
|
|
845
|
+
meta: objectMetaSchema,
|
|
846
|
+
/**
|
|
847
|
+
* The real descriptor of the secret in the object form, which follows one of these formats when serialized:
|
|
848
|
+
* - `system:<secretName>`
|
|
849
|
+
* - `instance:<instanceId>:<secretName>`
|
|
850
|
+
* - `custom:<secretPath>`
|
|
851
|
+
*/
|
|
852
|
+
descriptor: secretDescriptorSchema
|
|
853
|
+
});
|
|
854
|
+
function formatSecretDescriptor(descriptor) {
|
|
855
|
+
switch (descriptor.type) {
|
|
856
|
+
case "system":
|
|
857
|
+
return `system:${descriptor.secretName}`;
|
|
858
|
+
case "instance":
|
|
859
|
+
return `instance:${descriptor.instanceId}:${descriptor.secretName}`;
|
|
860
|
+
case "custom":
|
|
861
|
+
return `custom:${descriptor.secretPath}`;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
function parseSecretDescriptor(descriptorString) {
|
|
865
|
+
const parts = descriptorString.split(":");
|
|
866
|
+
if (parts.length < 2) {
|
|
867
|
+
throw new Error(`Invalid secret descriptor format: ${descriptorString}`);
|
|
868
|
+
}
|
|
869
|
+
switch (parts[0]) {
|
|
870
|
+
case "system": {
|
|
871
|
+
if (parts.length !== 2) {
|
|
872
|
+
throw new Error(`Invalid system secret descriptor: ${descriptorString}`);
|
|
873
|
+
}
|
|
874
|
+
return { type: "system", secretName: parts[1] };
|
|
875
|
+
}
|
|
876
|
+
case "instance": {
|
|
877
|
+
const secretName = parts[parts.length - 1];
|
|
878
|
+
const instanceId = parts.slice(1, -1).join(":");
|
|
879
|
+
if (!instanceId || !secretName) {
|
|
880
|
+
throw new Error(`Invalid instance secret descriptor: ${descriptorString}`);
|
|
881
|
+
}
|
|
882
|
+
return { type: "instance", instanceId, secretName };
|
|
883
|
+
}
|
|
884
|
+
case "custom": {
|
|
885
|
+
if (parts.length !== 2) {
|
|
886
|
+
throw new Error(`Invalid custom secret descriptor: ${descriptorString}`);
|
|
887
|
+
}
|
|
888
|
+
return { type: "custom", secretPath: parts[1] };
|
|
889
|
+
}
|
|
890
|
+
default:
|
|
891
|
+
throw new Error(`Unknown secret descriptor type: ${parts[0]}`);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
var WellKnownSecretDescriptors = {
|
|
895
|
+
PulumiPassword: {
|
|
896
|
+
type: "system",
|
|
897
|
+
secretName: "pulumi-password"
|
|
898
|
+
}
|
|
899
|
+
};
|
|
900
|
+
|
|
901
|
+
// src/shared/models/project/lock.ts
|
|
902
|
+
import { z as z11 } from "zod";
|
|
903
|
+
var instanceLockSpecSchema = z11.union([
|
|
904
|
+
z11.object({
|
|
905
|
+
type: z11.literal("operation"),
|
|
906
|
+
/**
|
|
907
|
+
* The operation ID. Will be used to fetch the operation and detect whether it is still running or lost.
|
|
908
|
+
*/
|
|
909
|
+
operationId: z11.string()
|
|
910
|
+
}),
|
|
911
|
+
z11.object({
|
|
912
|
+
type: z11.literal("evaluation"),
|
|
913
|
+
/**
|
|
914
|
+
* The internal evaluation ID that is used to detect lost evaluations and restart them.
|
|
915
|
+
*/
|
|
916
|
+
evaluationId: z11.string()
|
|
917
|
+
}),
|
|
918
|
+
z11.object({
|
|
919
|
+
type: z11.literal("custom"),
|
|
920
|
+
/**
|
|
921
|
+
* The ID of the party that holds the lock.
|
|
922
|
+
*
|
|
923
|
+
* Each locker must only manage the locks it has created.
|
|
924
|
+
*/
|
|
925
|
+
lockerId: z11.string(),
|
|
926
|
+
/**
|
|
927
|
+
* The ID of the lock provided by the locker.
|
|
928
|
+
*
|
|
929
|
+
* Must be unique across all locks in the locker system.
|
|
930
|
+
*/
|
|
931
|
+
lockId: z11.string(),
|
|
932
|
+
/**
|
|
933
|
+
* The optional payload provided by the locker.
|
|
934
|
+
*
|
|
935
|
+
* Can be used to store additional information about the lock,
|
|
936
|
+
* like the ID of the lock in the locker system,
|
|
937
|
+
* or any other metadata that is relevant to the lock.
|
|
938
|
+
*/
|
|
939
|
+
payload: z11.record(z11.string()).optional()
|
|
940
|
+
})
|
|
941
|
+
]);
|
|
942
|
+
var instanceLockSchema = z11.object({
|
|
943
|
+
id: z11.string(),
|
|
944
|
+
meta: objectMetaSchema,
|
|
945
|
+
spec: instanceLockSpecSchema
|
|
946
|
+
});
|
|
947
|
+
function compareInstanceLockSpecs(a, b) {
|
|
948
|
+
if (a.type === "operation" && b.type === "operation") {
|
|
949
|
+
return a.operationId === b.operationId;
|
|
950
|
+
}
|
|
951
|
+
if (a.type === "evaluation" && b.type === "evaluation") {
|
|
952
|
+
return a.evaluationId === b.evaluationId;
|
|
953
|
+
}
|
|
954
|
+
if (a.type === "custom" && b.type === "custom") {
|
|
955
|
+
return a.lockerId === b.lockerId && a.lockId === b.lockId;
|
|
956
|
+
}
|
|
957
|
+
return false;
|
|
958
|
+
}
|
|
959
|
+
var instanceLockEventSchema = z11.discriminatedUnion("type", [
|
|
960
|
+
z11.object({
|
|
961
|
+
type: z11.literal("locked"),
|
|
962
|
+
locks: z11.array(instanceLockSchema)
|
|
963
|
+
}),
|
|
964
|
+
z11.object({
|
|
965
|
+
type: z11.literal("unlocked"),
|
|
966
|
+
instanceIds: z11.array(z11.string())
|
|
967
|
+
})
|
|
968
|
+
]);
|
|
969
|
+
|
|
970
|
+
// src/shared/models/project/component.ts
|
|
971
|
+
import { z as z12 } from "zod";
|
|
972
|
+
var metaSchema = z12.object({
|
|
973
|
+
displayName: z12.string().optional(),
|
|
974
|
+
description: z12.string().optional(),
|
|
975
|
+
color: z12.string().optional()
|
|
976
|
+
});
|
|
977
|
+
var entitySchema = z12.object({
|
|
978
|
+
type: z12.string(),
|
|
979
|
+
schema: z12.any(),
|
|
980
|
+
// TSchema from TypeBox
|
|
981
|
+
meta: metaSchema,
|
|
982
|
+
definitionHash: z12.string()
|
|
983
|
+
});
|
|
984
|
+
var componentMetaSchema = metaSchema.extend({
|
|
985
|
+
primaryIcon: z12.string().optional(),
|
|
986
|
+
primaryIconColor: z12.string().optional(),
|
|
987
|
+
secondaryIcon: z12.string().optional(),
|
|
988
|
+
secondaryIconColor: z12.string().optional(),
|
|
989
|
+
category: z12.string().optional(),
|
|
990
|
+
defaultNamePrefix: z12.string().optional()
|
|
991
|
+
});
|
|
992
|
+
var componentArgumentSchema = z12.object({
|
|
993
|
+
schema: z12.any(),
|
|
994
|
+
// ArgumentValueSchema from TypeBox
|
|
995
|
+
required: z12.boolean(),
|
|
996
|
+
meta: componentMetaSchema
|
|
997
|
+
});
|
|
998
|
+
var componentInputSchema = z12.object({
|
|
999
|
+
type: z12.string(),
|
|
1000
|
+
required: z12.boolean(),
|
|
1001
|
+
multiple: z12.boolean(),
|
|
1002
|
+
meta: componentMetaSchema
|
|
1003
|
+
});
|
|
1004
|
+
var componentModelSchema = z12.object({
|
|
1005
|
+
type: z12.string(),
|
|
1006
|
+
args: z12.record(componentArgumentSchema),
|
|
1007
|
+
inputs: z12.record(componentInputSchema),
|
|
1008
|
+
outputs: z12.record(componentInputSchema),
|
|
1009
|
+
meta: componentMetaSchema,
|
|
1010
|
+
definitionHash: z12.string()
|
|
1011
|
+
});
|
|
1012
|
+
|
|
1013
|
+
// src/shared/models/project/service-account.ts
|
|
1014
|
+
import { z as z13 } from "zod";
|
|
1015
|
+
var serviceAccountSchema = z13.object({
|
|
1016
|
+
id: z13.string().uuid(),
|
|
1017
|
+
// UUIDv7
|
|
1018
|
+
meta: objectMetaSchema.pick({
|
|
1019
|
+
title: true,
|
|
1020
|
+
description: true,
|
|
1021
|
+
icon: true,
|
|
1022
|
+
iconColor: true,
|
|
1023
|
+
createdAt: true,
|
|
1024
|
+
updatedAt: true
|
|
1025
|
+
}),
|
|
1026
|
+
/**
|
|
1027
|
+
* The ID of the artifact that stores the avatar image for this service account.
|
|
1028
|
+
*/
|
|
1029
|
+
avatarArtifactId: z13.string().optional()
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
// src/shared/models/project/worker.ts
|
|
1033
|
+
import { z as z14 } from "zod";
|
|
1034
|
+
var workerStatus = z14.enum([
|
|
1035
|
+
// transient statuses
|
|
1036
|
+
"running",
|
|
1037
|
+
"starting"
|
|
1038
|
+
]);
|
|
1039
|
+
var workerSchema = z14.object({
|
|
1040
|
+
id: z14.uuidv7(),
|
|
1041
|
+
meta: objectMetaSchema.pick({
|
|
1042
|
+
title: true,
|
|
1043
|
+
description: true,
|
|
1044
|
+
icon: true,
|
|
1045
|
+
iconColor: true,
|
|
1046
|
+
createdAt: true,
|
|
1047
|
+
updatedAt: true
|
|
1048
|
+
}),
|
|
1049
|
+
/**
|
|
1050
|
+
* The status of the worker.
|
|
1051
|
+
*/
|
|
1052
|
+
status: workerStatus,
|
|
1053
|
+
/**
|
|
1054
|
+
* The number of failed attempts to start the worker. When a worker fails to start,
|
|
1055
|
+
* this count is incremented.
|
|
1056
|
+
* If the worker fails to start more than 5 times in a row, it is
|
|
1057
|
+
* considered unhealthy and will not be started again
|
|
1058
|
+
*
|
|
1059
|
+
* This count is reset when the worker is successfully started and connected.
|
|
1060
|
+
*/
|
|
1061
|
+
failedStartAttempts: z14.number(),
|
|
1062
|
+
/**
|
|
1063
|
+
* The fully qualified base docker image without tag and digest.
|
|
1064
|
+
*
|
|
1065
|
+
* It serves as the identity of the worker and can be shared across workers.
|
|
1066
|
+
*
|
|
1067
|
+
* Multiple workers sharing the same identity also share the same service accoun
|
|
1068
|
+
* and have equal access to all its resources.
|
|
1069
|
+
*
|
|
1070
|
+
* Example: `ghcr.io/highstate-io/kubernetes-worker`
|
|
1071
|
+
*/
|
|
1072
|
+
identity: z14.string(),
|
|
1073
|
+
/**
|
|
1074
|
+
* The fully qualified docker image name for this worker.
|
|
1075
|
+
*
|
|
1076
|
+
* Example: `ghcr.io/highstate-io/kubernetes-worker:v1.0.0@sha256:abc123...`
|
|
1077
|
+
*/
|
|
1078
|
+
image: z14.string(),
|
|
1079
|
+
/**
|
|
1080
|
+
* The ID of the service account owned by this worker.
|
|
1081
|
+
*/
|
|
1082
|
+
serviceAccountId: z14.string().uuid(),
|
|
1083
|
+
/**
|
|
1084
|
+
* The ID of the API key used to authenticate this worker with the system.
|
|
1085
|
+
*
|
|
1086
|
+
* Will be generated on the first run of the worker and will be rotated every time the worker is restarted.
|
|
1087
|
+
*/
|
|
1088
|
+
apiKeyId: z14.string().uuid().optional()
|
|
1089
|
+
});
|
|
1090
|
+
var workerUnitRegistrationSchema = z14.object({
|
|
1091
|
+
id: z14.string().uuid(),
|
|
1092
|
+
// UUIDv7
|
|
1093
|
+
meta: objectMetaSchema.pick({ createdAt: true, updatedAt: true }),
|
|
1094
|
+
workerId: z14.string().uuid(),
|
|
1095
|
+
// UUIDv7
|
|
1096
|
+
instanceId: z14.string(),
|
|
1097
|
+
/**
|
|
1098
|
+
* The fully qualified base docker image with tag and digest.
|
|
1099
|
+
*/
|
|
1100
|
+
image: z14.string(),
|
|
1101
|
+
/**
|
|
1102
|
+
* The parameters to pass to the worker.
|
|
1103
|
+
*/
|
|
1104
|
+
params: z14.record(z14.string(), z14.unknown()).optional()
|
|
1105
|
+
});
|
|
1106
|
+
var unitWorkerSchema = z14.object({
|
|
1107
|
+
name: z14.string(),
|
|
1108
|
+
image: z14.string(),
|
|
1109
|
+
params: z14.record(z14.string(), z14.unknown()).optional()
|
|
1110
|
+
});
|
|
1111
|
+
function getWorkerIdentity(image) {
|
|
1112
|
+
const parts = image.split(":");
|
|
1113
|
+
if (parts.length < 2) {
|
|
1114
|
+
throw new Error(`Invalid image format: ${image}`);
|
|
1115
|
+
}
|
|
1116
|
+
return parts.slice(0, -1).join(":");
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
// src/shared/models/project/api-key.ts
|
|
1120
|
+
import { z as z15 } from "zod";
|
|
1121
|
+
var instanceActionSchema = z15.enum(["read", "write"]);
|
|
1122
|
+
var serviceAccountActionSchema = z15.enum(["full"]);
|
|
1123
|
+
var projectAccessScope = z15.discriminatedUnion("type", [
|
|
1124
|
+
z15.object({
|
|
1125
|
+
type: z15.literal("instance"),
|
|
1126
|
+
actions: instanceActionSchema.array(),
|
|
1127
|
+
instanceIds: z15.string().array()
|
|
1128
|
+
}),
|
|
1129
|
+
z15.object({
|
|
1130
|
+
type: z15.literal("service-account"),
|
|
1131
|
+
actions: serviceAccountActionSchema.array(),
|
|
1132
|
+
serviceAccountIds: z15.string().array()
|
|
1133
|
+
})
|
|
1134
|
+
]);
|
|
1135
|
+
var projectApiKeySchema = z15.object({
|
|
1136
|
+
id: z15.string().ulid(),
|
|
1137
|
+
meta: objectMetaSchema,
|
|
1138
|
+
/**
|
|
1139
|
+
* The 256-bit random token used to authenticate API requests.
|
|
1140
|
+
*/
|
|
1141
|
+
token: z15.string(),
|
|
1142
|
+
scopes: z15.array(projectAccessScope)
|
|
1143
|
+
});
|
|
1144
|
+
function hasAll(array, values) {
|
|
1145
|
+
return values.every((value) => array.includes(value));
|
|
1146
|
+
}
|
|
1147
|
+
function validateInstanceAccess(apiKey, actions, instanceIds) {
|
|
1148
|
+
return apiKey.scopes.filter((scope) => scope.type === "instance").some((scope) => hasAll(scope.actions, actions) && hasAll(scope.instanceIds, instanceIds));
|
|
1149
|
+
}
|
|
1150
|
+
var projectAccessActionDescriptions = {
|
|
1151
|
+
"service-account": {
|
|
1152
|
+
full: "Full access to the service account and all resources owned by it and granted to it."
|
|
1153
|
+
},
|
|
1154
|
+
instance: {
|
|
1155
|
+
read: "Read access to the instance, including its state all resources owned by it.",
|
|
1156
|
+
write: "Write access to the instance, including its state and all resources owned by it."
|
|
1157
|
+
}
|
|
1158
|
+
};
|
|
1159
|
+
|
|
1160
|
+
// src/shared/models/backend/project.ts
|
|
1161
|
+
var projectSchema = z16.object({
|
|
1162
|
+
/**
|
|
1163
|
+
* The identifier of the project unique across the backend.
|
|
1164
|
+
*/
|
|
1165
|
+
id: z16.string(),
|
|
1166
|
+
/**
|
|
1167
|
+
* The metadata of the project.
|
|
1168
|
+
*/
|
|
1169
|
+
meta: objectMetaSchema,
|
|
1170
|
+
/**
|
|
1171
|
+
* The identifier of the library used by the project.
|
|
1172
|
+
*/
|
|
1173
|
+
libraryId: z16.string()
|
|
1174
|
+
});
|
|
1175
|
+
var projectModelSchema = z16.object({
|
|
1176
|
+
instances: z16.array(instanceModelSchema),
|
|
1177
|
+
hubs: z16.array(hubModelSchema)
|
|
1178
|
+
});
|
|
1179
|
+
var projectUnlockSuiteSchema = z16.object({
|
|
1180
|
+
/**
|
|
1181
|
+
* The list of encrypted AGE identities that can be used to decrypt the master key of the project.
|
|
1182
|
+
*
|
|
1183
|
+
* The frontend should try to decrypt at least one of these identities
|
|
1184
|
+
* using the password or passkey.
|
|
1185
|
+
*/
|
|
1186
|
+
encryptedIdentities: z16.array(z16.string()),
|
|
1187
|
+
/**
|
|
1188
|
+
* Whether one of the identities is a passkey and user should be asked to use it.
|
|
1189
|
+
*/
|
|
1190
|
+
hasPasskey: z16.boolean()
|
|
1191
|
+
});
|
|
1192
|
+
var projectUnlockStateSchema = z16.discriminatedUnion("type", [
|
|
1193
|
+
z16.object({
|
|
1194
|
+
type: z16.literal("locked"),
|
|
1195
|
+
unlockSuite: projectUnlockSuiteSchema.optional()
|
|
1196
|
+
}),
|
|
1197
|
+
z16.object({
|
|
1198
|
+
type: z16.literal("unlocked")
|
|
1199
|
+
})
|
|
1200
|
+
]);
|
|
1201
|
+
|
|
1202
|
+
// src/shared/models/backend/library.ts
|
|
1203
|
+
function diffLibraries(oldLibrary, newLibrary) {
|
|
1204
|
+
const updates = [];
|
|
1205
|
+
for (const [componentType, newComponent] of Object.entries(newLibrary.components)) {
|
|
1206
|
+
const existingComponent = oldLibrary.components[componentType];
|
|
1207
|
+
if (existingComponent?.definitionHash !== newComponent.definitionHash) {
|
|
1208
|
+
updates.push({ type: "component-updated", component: newComponent });
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
for (const componentType of Object.keys(oldLibrary.components)) {
|
|
1212
|
+
if (!newLibrary.components[componentType]) {
|
|
1213
|
+
updates.push({ type: "component-removed", componentType });
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
for (const [entityType, newEntity] of Object.entries(newLibrary.entities)) {
|
|
1217
|
+
const existingEntity = oldLibrary.entities[entityType];
|
|
1218
|
+
if (existingEntity?.definitionHash !== newEntity.definitionHash) {
|
|
1219
|
+
updates.push({ type: "entity-updated", entity: newEntity });
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
for (const entityType of Object.keys(oldLibrary.entities)) {
|
|
1223
|
+
if (!newLibrary.entities[entityType]) {
|
|
1224
|
+
updates.push({ type: "entity-removed", entityType });
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
return updates;
|
|
1228
|
+
}
|
|
1229
|
+
function applyLibraryUpdate(components, entities, update) {
|
|
1230
|
+
switch (update.type) {
|
|
1231
|
+
case "component-updated":
|
|
1232
|
+
components[update.component.type] = update.component;
|
|
1233
|
+
break;
|
|
1234
|
+
case "entity-updated":
|
|
1235
|
+
entities[update.entity.type] = update.entity;
|
|
1236
|
+
break;
|
|
1237
|
+
case "component-removed":
|
|
1238
|
+
delete components[update.componentType];
|
|
1239
|
+
break;
|
|
1240
|
+
case "entity-removed":
|
|
1241
|
+
delete entities[update.entityType];
|
|
1242
|
+
break;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// src/shared/models/backend/unlock-method.ts
|
|
1247
|
+
import { z as z17 } from "zod";
|
|
1248
|
+
var backendUnlockMethodSchema = z17.object({
|
|
1249
|
+
id: z17.string(),
|
|
1250
|
+
meta: objectMetaSchema,
|
|
1251
|
+
/**
|
|
1252
|
+
* The AGE recipient of the unlock method to use to encrypt the master key for this unlock method.
|
|
1253
|
+
*/
|
|
1254
|
+
recipient: z17.string()
|
|
1255
|
+
});
|
|
1256
|
+
|
|
1257
|
+
// src/shared/models/errors.ts
|
|
1258
|
+
var AccessError = class extends Error {
|
|
1259
|
+
constructor(message) {
|
|
1260
|
+
super(message);
|
|
1261
|
+
}
|
|
1262
|
+
};
|
|
1263
|
+
|
|
1264
|
+
// src/shared/resolvers/graph-resolver.ts
|
|
1265
|
+
import { unique } from "remeda";
|
|
1266
|
+
var GraphResolver = class {
|
|
1267
|
+
constructor(nodes, logger, outputHandler, dependentSetHandler) {
|
|
1268
|
+
this.nodes = nodes;
|
|
1269
|
+
this.logger = logger;
|
|
1270
|
+
this.outputHandler = outputHandler;
|
|
1271
|
+
this.dependentSetHandler = dependentSetHandler;
|
|
1272
|
+
}
|
|
1273
|
+
workset = /* @__PURE__ */ new Set();
|
|
1274
|
+
dependencyMap = /* @__PURE__ */ new Map();
|
|
1275
|
+
dependentMap = /* @__PURE__ */ new Map();
|
|
1276
|
+
outputMap = /* @__PURE__ */ new Map();
|
|
1277
|
+
addToWorkset(nodeId) {
|
|
1278
|
+
this.workset.add(nodeId);
|
|
1279
|
+
}
|
|
1280
|
+
addAllNodesToWorkset() {
|
|
1281
|
+
for (const nodeId of this.nodes.keys()) {
|
|
1282
|
+
this.workset.add(nodeId);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* The map of calculated outputs.
|
|
1287
|
+
*/
|
|
1288
|
+
get outputs() {
|
|
1289
|
+
return this.outputMap;
|
|
1290
|
+
}
|
|
1291
|
+
requireOutput(nodeId) {
|
|
1292
|
+
const output = this.outputMap.get(nodeId);
|
|
1293
|
+
if (!output) {
|
|
1294
|
+
throw new Error(`Output for node ${nodeId} is not available`);
|
|
1295
|
+
}
|
|
1296
|
+
return output;
|
|
1297
|
+
}
|
|
1298
|
+
/**
|
|
1299
|
+
* Gets all identifiers of the nodes that depend on the given node directly or indirectly.
|
|
1300
|
+
*/
|
|
1301
|
+
getAllDependents(nodeId) {
|
|
1302
|
+
const result = /* @__PURE__ */ new Set();
|
|
1303
|
+
const stack = [nodeId];
|
|
1304
|
+
while (stack.length > 0) {
|
|
1305
|
+
const dependents = this.dependentMap.get(stack.pop());
|
|
1306
|
+
if (!dependents) {
|
|
1307
|
+
continue;
|
|
1308
|
+
}
|
|
1309
|
+
for (const dependentId of dependents) {
|
|
1310
|
+
if (!result.has(dependentId)) {
|
|
1311
|
+
result.add(dependentId);
|
|
1312
|
+
stack.push(dependentId);
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
return Array.from(result);
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* Gets the identifiers of the nodes that depend on the given node directly.
|
|
1320
|
+
*
|
|
1321
|
+
* Returns an empty array if there are no dependents.
|
|
1322
|
+
*/
|
|
1323
|
+
getDependents(nodeId) {
|
|
1324
|
+
const dependents = this.dependentMap.get(nodeId);
|
|
1325
|
+
if (!dependents) {
|
|
1326
|
+
return [];
|
|
1327
|
+
}
|
|
1328
|
+
return Array.from(dependents);
|
|
1329
|
+
}
|
|
1330
|
+
/**
|
|
1331
|
+
* Invalidates the node and all nodes that depend on it.
|
|
1332
|
+
*
|
|
1333
|
+
* Also adds the node to the work set for processing.
|
|
1334
|
+
*/
|
|
1335
|
+
invalidate(nodeId) {
|
|
1336
|
+
const stack = [nodeId];
|
|
1337
|
+
while (stack.length > 0) {
|
|
1338
|
+
const nodeId2 = stack.pop();
|
|
1339
|
+
if (!this.nodes.has(nodeId2)) {
|
|
1340
|
+
continue;
|
|
1341
|
+
}
|
|
1342
|
+
this.outputMap.delete(nodeId2);
|
|
1343
|
+
this.workset.add(nodeId2);
|
|
1344
|
+
const dependents = this.dependentMap.get(nodeId2);
|
|
1345
|
+
if (!dependents) {
|
|
1346
|
+
continue;
|
|
1347
|
+
}
|
|
1348
|
+
for (const dependentId of dependents) {
|
|
1349
|
+
if (this.outputMap.has(dependentId)) {
|
|
1350
|
+
stack.push(dependentId);
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* Resolves all not-resolved or invalidated nodes in the graph.
|
|
1357
|
+
*
|
|
1358
|
+
* The abort signal of the previous operation must be called before calling this method again.
|
|
1359
|
+
*/
|
|
1360
|
+
async process(signal) {
|
|
1361
|
+
while (this.workset.size > 0) {
|
|
1362
|
+
const rootNodeId = this.workset.values().next().value;
|
|
1363
|
+
const stack = [{ nodeId: rootNodeId, resolved: false, dependencies: [] }];
|
|
1364
|
+
while (stack.length > 0) {
|
|
1365
|
+
const stackItem = stack[stack.length - 1];
|
|
1366
|
+
const { nodeId, resolved } = stackItem;
|
|
1367
|
+
const node = this.nodes.get(nodeId);
|
|
1368
|
+
if (!node) {
|
|
1369
|
+
this.logger.warn({ nodeId }, "node not found in the graph, skipping");
|
|
1370
|
+
stack.pop();
|
|
1371
|
+
continue;
|
|
1372
|
+
}
|
|
1373
|
+
if (this.outputMap.has(nodeId)) {
|
|
1374
|
+
stack.pop();
|
|
1375
|
+
continue;
|
|
1376
|
+
}
|
|
1377
|
+
if (!resolved) {
|
|
1378
|
+
stackItem.dependencies = unique(this.getNodeDependencies(node));
|
|
1379
|
+
let hasUnresolvedDependencies = false;
|
|
1380
|
+
for (const depId of stackItem.dependencies) {
|
|
1381
|
+
if (!this.nodes.has(depId)) {
|
|
1382
|
+
this.logger.warn({ depId, nodeId }, "dependency not found in the graph, skipping");
|
|
1383
|
+
continue;
|
|
1384
|
+
}
|
|
1385
|
+
if (!this.outputMap.has(depId)) {
|
|
1386
|
+
stack.push({ nodeId: depId, resolved: false, dependencies: [] });
|
|
1387
|
+
hasUnresolvedDependencies = true;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
if (hasUnresolvedDependencies) {
|
|
1391
|
+
stackItem.resolved = true;
|
|
1392
|
+
continue;
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
const output = await this.processNode(node, this.logger);
|
|
1396
|
+
if (signal?.aborted) {
|
|
1397
|
+
this.logger.warn({ nodeId }, "processing aborted, skipping output");
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
const changedDependentMaps = /* @__PURE__ */ new Set();
|
|
1401
|
+
const oldDependencies = this.dependencyMap.get(nodeId) ?? [];
|
|
1402
|
+
for (const depId of oldDependencies) {
|
|
1403
|
+
const dependantSet = this.dependentMap.get(depId);
|
|
1404
|
+
if (dependantSet) {
|
|
1405
|
+
dependantSet.delete(nodeId);
|
|
1406
|
+
changedDependentMaps.add(depId);
|
|
1407
|
+
if (dependantSet.size === 0) {
|
|
1408
|
+
this.dependentMap.delete(depId);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
for (const depId of stackItem.dependencies) {
|
|
1413
|
+
let dependantSet = this.dependentMap.get(depId);
|
|
1414
|
+
if (!dependantSet) {
|
|
1415
|
+
dependantSet = /* @__PURE__ */ new Set();
|
|
1416
|
+
this.dependentMap.set(depId, dependantSet);
|
|
1417
|
+
}
|
|
1418
|
+
dependantSet.add(nodeId);
|
|
1419
|
+
changedDependentMaps.add(depId);
|
|
1420
|
+
}
|
|
1421
|
+
if (this.dependentSetHandler) {
|
|
1422
|
+
for (const depId of changedDependentMaps) {
|
|
1423
|
+
const dependents = this.dependentMap.get(depId);
|
|
1424
|
+
this.dependentSetHandler(depId, dependents ? Array.from(dependents) : []);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
this.outputMap.set(nodeId, output);
|
|
1428
|
+
this.outputHandler?.(nodeId, output);
|
|
1429
|
+
this.dependencyMap.set(nodeId, stackItem.dependencies);
|
|
1430
|
+
stack.pop();
|
|
1431
|
+
}
|
|
1432
|
+
this.workset.delete(rootNodeId);
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
};
|
|
1436
|
+
|
|
1437
|
+
// src/shared/resolvers/state.ts
|
|
1438
|
+
var StateResolver = class extends GraphResolver {
|
|
1439
|
+
getNodeDependencies(node) {
|
|
1440
|
+
return node.operationStatus?.dependencyIds ?? [];
|
|
1441
|
+
}
|
|
1442
|
+
processNode() {
|
|
1443
|
+
return;
|
|
1444
|
+
}
|
|
1445
|
+
};
|
|
1446
|
+
|
|
1447
|
+
// src/shared/resolvers/input.ts
|
|
1448
|
+
import {
|
|
1449
|
+
isUnitModel
|
|
1450
|
+
} from "@highstate/contract";
|
|
1451
|
+
import { fromEntries, mapValues } from "remeda";
|
|
1452
|
+
var InputResolver = class extends GraphResolver {
|
|
1453
|
+
getNodeDependencies(node) {
|
|
1454
|
+
const dependencies = [];
|
|
1455
|
+
if (node.kind === "hub") {
|
|
1456
|
+
for (const input of node.hub.inputs ?? []) {
|
|
1457
|
+
dependencies.push(`instance:${input.instanceId}`);
|
|
1458
|
+
}
|
|
1459
|
+
for (const input of node.hub.injectionInputs ?? []) {
|
|
1460
|
+
dependencies.push(`hub:${input.hubId}`);
|
|
1461
|
+
}
|
|
1462
|
+
return dependencies;
|
|
1463
|
+
}
|
|
1464
|
+
for (const inputs of Object.values(node.instance.inputs ?? {})) {
|
|
1465
|
+
for (const input of inputs) {
|
|
1466
|
+
dependencies.push(`instance:${input.instanceId}`);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
for (const inputs of Object.values(node.instance.hubInputs ?? {})) {
|
|
1470
|
+
for (const input of inputs) {
|
|
1471
|
+
dependencies.push(`hub:${input.hubId}`);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
for (const input of node.instance.injectionInputs ?? []) {
|
|
1475
|
+
dependencies.push(`hub:${input.hubId}`);
|
|
1476
|
+
}
|
|
1477
|
+
return dependencies;
|
|
1478
|
+
}
|
|
1479
|
+
processNode(node) {
|
|
1480
|
+
const getHubOutput = (input) => {
|
|
1481
|
+
const output = this.outputs.get(`hub:${input.hubId}`);
|
|
1482
|
+
if (!output) {
|
|
1483
|
+
return { resolvedInputs: [] };
|
|
1484
|
+
}
|
|
1485
|
+
if (output.kind !== "hub") {
|
|
1486
|
+
throw new Error("Expected hub node");
|
|
1487
|
+
}
|
|
1488
|
+
return output;
|
|
1489
|
+
};
|
|
1490
|
+
const getInstanceOutput = (input) => {
|
|
1491
|
+
const output = this.outputs.get(`instance:${input.instanceId}`);
|
|
1492
|
+
if (!output) {
|
|
1493
|
+
return {
|
|
1494
|
+
component: null,
|
|
1495
|
+
resolvedInputs: [],
|
|
1496
|
+
resolvedOutputs: []
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
if (output.kind !== "instance") {
|
|
1500
|
+
throw new Error("Expected instance node");
|
|
1501
|
+
}
|
|
1502
|
+
return {
|
|
1503
|
+
component: output.component,
|
|
1504
|
+
resolvedInputs: output.resolvedInputs[input.output] ?? [],
|
|
1505
|
+
resolvedOutputs: output.resolvedOutputs?.[input.output]
|
|
1506
|
+
};
|
|
1507
|
+
};
|
|
1508
|
+
if (node.kind === "hub") {
|
|
1509
|
+
const hubResult = /* @__PURE__ */ new Map();
|
|
1510
|
+
const addHubResult = (input) => {
|
|
1511
|
+
hubResult.set(`${input.input.instanceId}:${input.input.output}`, input);
|
|
1512
|
+
};
|
|
1513
|
+
for (const input of node.hub.inputs ?? []) {
|
|
1514
|
+
const { component } = getInstanceOutput(input);
|
|
1515
|
+
const componentInput = component?.outputs[input.output];
|
|
1516
|
+
if (!componentInput) {
|
|
1517
|
+
this.logger.warn({ msg: "output not found in the component", input, component });
|
|
1518
|
+
continue;
|
|
1519
|
+
}
|
|
1520
|
+
addHubResult({ input, type: componentInput.type });
|
|
1521
|
+
}
|
|
1522
|
+
for (const injectionInput of node.hub.injectionInputs ?? []) {
|
|
1523
|
+
const { resolvedInputs: resolvedInputs2 } = getHubOutput(injectionInput);
|
|
1524
|
+
for (const input of resolvedInputs2) {
|
|
1525
|
+
addHubResult(input);
|
|
1526
|
+
}
|
|
1527
|
+
}
|
|
1528
|
+
return {
|
|
1529
|
+
kind: "hub",
|
|
1530
|
+
resolvedInputs: Array.from(hubResult.values())
|
|
1531
|
+
};
|
|
1532
|
+
}
|
|
1533
|
+
if (node.instance.resolvedInputs) {
|
|
1534
|
+
return {
|
|
1535
|
+
kind: "instance",
|
|
1536
|
+
instance: node.instance,
|
|
1537
|
+
component: node.component,
|
|
1538
|
+
resolvedInputs: mapValues(node.instance.resolvedInputs, (inputs, inputName) => {
|
|
1539
|
+
const componentInput = node.component.inputs[inputName];
|
|
1540
|
+
if (!componentInput) {
|
|
1541
|
+
this.logger.warn({
|
|
1542
|
+
msg: "input not found in the component",
|
|
1543
|
+
inputName,
|
|
1544
|
+
component: node.component
|
|
1545
|
+
});
|
|
1546
|
+
return [];
|
|
1547
|
+
}
|
|
1548
|
+
return inputs.map((input) => ({ input, type: componentInput.type }));
|
|
1549
|
+
}),
|
|
1550
|
+
resolvedOutputs: node.instance.resolvedOutputs ?? {},
|
|
1551
|
+
resolvedInjectionInputs: [],
|
|
1552
|
+
matchedInjectionInputs: []
|
|
1553
|
+
};
|
|
1554
|
+
}
|
|
1555
|
+
const resolvedInputsMap = /* @__PURE__ */ new Map();
|
|
1556
|
+
const addInstanceResult = (inputName, input) => {
|
|
1557
|
+
let inputs = resolvedInputsMap.get(inputName);
|
|
1558
|
+
if (!inputs) {
|
|
1559
|
+
inputs = /* @__PURE__ */ new Map();
|
|
1560
|
+
resolvedInputsMap.set(inputName, inputs);
|
|
1561
|
+
}
|
|
1562
|
+
inputs.set(`${input.input.instanceId}:${input.input.output}`, input);
|
|
1563
|
+
};
|
|
1564
|
+
const addInstanceInput = (inputName, input) => {
|
|
1565
|
+
const componentInput = node.component.inputs[inputName];
|
|
1566
|
+
if (!componentInput) {
|
|
1567
|
+
this.logger.warn({
|
|
1568
|
+
msg: "input not found in the component",
|
|
1569
|
+
input,
|
|
1570
|
+
component: node.component
|
|
1571
|
+
});
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
const { component, resolvedOutputs } = getInstanceOutput(input);
|
|
1575
|
+
if (!component) {
|
|
1576
|
+
this.logger.warn({ instanceId: node.instance.id, input }, "no output found for the input");
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
if (isUnitModel(component)) {
|
|
1580
|
+
addInstanceResult(inputName, { input, type: componentInput.type });
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
if (resolvedOutputs) {
|
|
1584
|
+
for (const output of resolvedOutputs) {
|
|
1585
|
+
addInstanceResult(inputName, { input: output, type: componentInput.type });
|
|
1586
|
+
}
|
|
1587
|
+
} else {
|
|
1588
|
+
addInstanceResult(inputName, { input, type: componentInput.type });
|
|
1589
|
+
}
|
|
1590
|
+
};
|
|
1591
|
+
for (const [inputName, inputs] of Object.entries(node.instance.inputs ?? {})) {
|
|
1592
|
+
for (const input of inputs) {
|
|
1593
|
+
addInstanceInput(inputName, input);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
const injectionInputs = /* @__PURE__ */ new Map();
|
|
1597
|
+
const matchedInjectionInputs = /* @__PURE__ */ new Map();
|
|
1598
|
+
for (const injectionInput of node.instance.injectionInputs ?? []) {
|
|
1599
|
+
const { resolvedInputs: resolvedInputs2 } = getHubOutput(injectionInput);
|
|
1600
|
+
for (const input of resolvedInputs2) {
|
|
1601
|
+
injectionInputs.set(`${input.input.instanceId}:${input.input.output}`, input);
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
for (const [inputName, componentInput] of Object.entries(node.component.inputs ?? {})) {
|
|
1605
|
+
const allInputs = new Map(injectionInputs);
|
|
1606
|
+
const hubInputs = node.instance.hubInputs?.[inputName] ?? [];
|
|
1607
|
+
for (const hubInput of hubInputs) {
|
|
1608
|
+
const { resolvedInputs: resolvedInputs2 } = getHubOutput(hubInput);
|
|
1609
|
+
for (const input of resolvedInputs2) {
|
|
1610
|
+
allInputs.set(`${input.input.instanceId}:${input.input.output}`, input);
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
for (const input of allInputs.values()) {
|
|
1614
|
+
if (input.type === componentInput.type) {
|
|
1615
|
+
addInstanceInput(inputName, input.input);
|
|
1616
|
+
const key = `${input.input.instanceId}:${input.input.output}`;
|
|
1617
|
+
if (injectionInputs.has(key)) {
|
|
1618
|
+
matchedInjectionInputs.set(key, input);
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
const resolvedInputs = fromEntries(
|
|
1624
|
+
Array.from(resolvedInputsMap.entries()).map(([inputName, inputs]) => [
|
|
1625
|
+
inputName,
|
|
1626
|
+
Array.from(inputs.values())
|
|
1627
|
+
])
|
|
1628
|
+
);
|
|
1629
|
+
return {
|
|
1630
|
+
kind: "instance",
|
|
1631
|
+
instance: node.instance,
|
|
1632
|
+
component: node.component,
|
|
1633
|
+
resolvedInputs,
|
|
1634
|
+
resolvedOutputs: node.instance.resolvedOutputs,
|
|
1635
|
+
resolvedInjectionInputs: Array.from(injectionInputs.values()),
|
|
1636
|
+
matchedInjectionInputs: Array.from(matchedInjectionInputs.values())
|
|
1637
|
+
};
|
|
1638
|
+
}
|
|
1639
|
+
};
|
|
1640
|
+
function getResolvedHubInputs(output) {
|
|
1641
|
+
if (output.kind !== "hub") {
|
|
1642
|
+
throw new Error("Expected hub node");
|
|
1643
|
+
}
|
|
1644
|
+
return output.resolvedInputs;
|
|
1645
|
+
}
|
|
1646
|
+
function getResolvedInstanceInputs(output) {
|
|
1647
|
+
if (output.kind !== "instance") {
|
|
1648
|
+
throw new Error("Expected instance node");
|
|
1649
|
+
}
|
|
1650
|
+
return output.resolvedInputs;
|
|
1651
|
+
}
|
|
1652
|
+
function getResolvedInjectionInstanceInputs(output) {
|
|
1653
|
+
if (output.kind !== "instance") {
|
|
1654
|
+
throw new Error("Expected instance node");
|
|
1655
|
+
}
|
|
1656
|
+
return output.resolvedInjectionInputs;
|
|
1657
|
+
}
|
|
1658
|
+
function getMatchedInjectionInstanceInputs(output) {
|
|
1659
|
+
if (output.kind !== "instance") {
|
|
1660
|
+
throw new Error("Expected instance node");
|
|
1661
|
+
}
|
|
1662
|
+
return output.matchedInjectionInputs;
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
// src/shared/resolvers/input-hash.ts
|
|
1666
|
+
import { isUnitModel as isUnitModel2 } from "@highstate/contract";
|
|
1667
|
+
import { crc32 } from "@aws-crypto/crc32";
|
|
1668
|
+
import { encode } from "@msgpack/msgpack";
|
|
1669
|
+
import { sha256 } from "@noble/hashes/sha2";
|
|
1670
|
+
import { bytesToHex } from "@noble/ciphers/utils";
|
|
1671
|
+
|
|
1672
|
+
// src/shared/utils/promise-tracker.ts
|
|
1673
|
+
var PromiseTracker = class {
|
|
1674
|
+
trackedPromises = /* @__PURE__ */ new Set();
|
|
1675
|
+
/**
|
|
1676
|
+
* Tracks a promise to ensure its rejection is handled inside the tracker's scope.
|
|
1677
|
+
*/
|
|
1678
|
+
track(promise) {
|
|
1679
|
+
this.trackedPromises.add(promise);
|
|
1680
|
+
void promise.finally(() => this.trackedPromises.delete(promise));
|
|
1681
|
+
}
|
|
1682
|
+
/**
|
|
1683
|
+
* Waits for all tracked promises to resolve or reject.
|
|
1684
|
+
*/
|
|
1685
|
+
async waitForAll() {
|
|
1686
|
+
if (this.trackedPromises.size === 0) {
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1689
|
+
await Promise.allSettled(this.trackedPromises);
|
|
1690
|
+
}
|
|
1691
|
+
};
|
|
1692
|
+
|
|
1693
|
+
// src/shared/utils/async-batcher.ts
|
|
1694
|
+
function createAsyncBatcher(fn, { waitMs = 100, maxWaitTimeMs = 1e3 } = {}) {
|
|
1695
|
+
let batch = [];
|
|
1696
|
+
let activeTimeout = null;
|
|
1697
|
+
let maxWaitTimeout = null;
|
|
1698
|
+
let firstCallTimestamp = null;
|
|
1699
|
+
async function processBatch() {
|
|
1700
|
+
if (batch.length === 0) return;
|
|
1701
|
+
const currentBatch = batch;
|
|
1702
|
+
batch = [];
|
|
1703
|
+
await fn(currentBatch);
|
|
1704
|
+
if (maxWaitTimeout) {
|
|
1705
|
+
clearTimeout(maxWaitTimeout);
|
|
1706
|
+
maxWaitTimeout = null;
|
|
1707
|
+
}
|
|
1708
|
+
firstCallTimestamp = null;
|
|
1709
|
+
}
|
|
1710
|
+
function schedule() {
|
|
1711
|
+
if (activeTimeout) clearTimeout(activeTimeout);
|
|
1712
|
+
activeTimeout = setTimeout(() => {
|
|
1713
|
+
activeTimeout = null;
|
|
1714
|
+
void processBatch();
|
|
1715
|
+
}, waitMs);
|
|
1716
|
+
if (!firstCallTimestamp) {
|
|
1717
|
+
firstCallTimestamp = Date.now();
|
|
1718
|
+
maxWaitTimeout = setTimeout(() => {
|
|
1719
|
+
if (activeTimeout) clearTimeout(activeTimeout);
|
|
1720
|
+
activeTimeout = null;
|
|
1721
|
+
void processBatch();
|
|
1722
|
+
}, maxWaitTimeMs);
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
return {
|
|
1726
|
+
/**
|
|
1727
|
+
* Add an item to the batch.
|
|
1728
|
+
*/
|
|
1729
|
+
call(item) {
|
|
1730
|
+
batch.push(item);
|
|
1731
|
+
schedule();
|
|
1732
|
+
},
|
|
1733
|
+
/**
|
|
1734
|
+
* Immediately flush the pending batch (if any).
|
|
1735
|
+
*/
|
|
1736
|
+
async flush() {
|
|
1737
|
+
if (activeTimeout) {
|
|
1738
|
+
clearTimeout(activeTimeout);
|
|
1739
|
+
activeTimeout = null;
|
|
1740
|
+
}
|
|
1741
|
+
if (maxWaitTimeout) {
|
|
1742
|
+
clearTimeout(maxWaitTimeout);
|
|
1743
|
+
maxWaitTimeout = null;
|
|
1744
|
+
}
|
|
1745
|
+
await processBatch();
|
|
1746
|
+
}
|
|
1747
|
+
};
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
// src/shared/utils/hash.ts
|
|
1751
|
+
function int32ToBytes(value) {
|
|
1752
|
+
const buffer = new ArrayBuffer(4);
|
|
1753
|
+
const view = new DataView(buffer);
|
|
1754
|
+
view.setInt32(0, value, true);
|
|
1755
|
+
return new Uint8Array(buffer);
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
// src/shared/resolvers/input-hash.ts
|
|
1759
|
+
var InputHashResolver = class extends GraphResolver {
|
|
1760
|
+
getNodeDependencies({ resolvedInputs }) {
|
|
1761
|
+
const dependencies = [];
|
|
1762
|
+
for (const inputs of Object.values(resolvedInputs ?? {})) {
|
|
1763
|
+
for (const input of inputs) {
|
|
1764
|
+
dependencies.push(input.input.instanceId);
|
|
1765
|
+
}
|
|
1766
|
+
}
|
|
1767
|
+
return dependencies;
|
|
1768
|
+
}
|
|
1769
|
+
processNode({
|
|
1770
|
+
instance,
|
|
1771
|
+
component,
|
|
1772
|
+
resolvedInputs,
|
|
1773
|
+
sourceHash,
|
|
1774
|
+
state
|
|
1775
|
+
}) {
|
|
1776
|
+
const inputHashSink = [];
|
|
1777
|
+
inputHashSink.push(int32ToBytes(component.definitionHash));
|
|
1778
|
+
if (state?.operationStatus?.inputHashNonce) {
|
|
1779
|
+
inputHashSink.push(int32ToBytes(state.operationStatus.inputHashNonce));
|
|
1780
|
+
}
|
|
1781
|
+
if (instance.args) {
|
|
1782
|
+
inputHashSink.push(encode(instance.args));
|
|
1783
|
+
}
|
|
1784
|
+
if (sourceHash) {
|
|
1785
|
+
inputHashSink.push(int32ToBytes(sourceHash));
|
|
1786
|
+
} else if (isUnitModel2(component)) {
|
|
1787
|
+
this.logger.warn(
|
|
1788
|
+
{ instanceId: instance.id },
|
|
1789
|
+
"missing source hash for unit model, this may lead to incorrect input hash"
|
|
1790
|
+
);
|
|
1791
|
+
}
|
|
1792
|
+
const sortedInputs = Object.entries(resolvedInputs).sort(([a], [b]) => a.localeCompare(b));
|
|
1793
|
+
const dependencyInstanceIds = /* @__PURE__ */ new Set();
|
|
1794
|
+
for (const [inputKey, inputs] of sortedInputs) {
|
|
1795
|
+
if (Object.keys(inputs).length === 0) {
|
|
1796
|
+
continue;
|
|
1797
|
+
}
|
|
1798
|
+
inputHashSink.push(Buffer.from(inputKey));
|
|
1799
|
+
const instanceIds = inputs.map((input) => input.input.instanceId).sort();
|
|
1800
|
+
for (const instanceId of instanceIds) {
|
|
1801
|
+
const dependency = this.outputs.get(instanceId);
|
|
1802
|
+
if (!dependency) continue;
|
|
1803
|
+
inputHashSink.push(int32ToBytes(dependency.inputHash));
|
|
1804
|
+
inputHashSink.push(Buffer.from(dependency.outputHash));
|
|
1805
|
+
dependencyInstanceIds.add(instanceId);
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
const dependencyOutputHashSink = [];
|
|
1809
|
+
const sortedDependencyInstanceIds = Array.from(dependencyInstanceIds).sort();
|
|
1810
|
+
for (const dependencyInstanceId of sortedDependencyInstanceIds) {
|
|
1811
|
+
const dependency = this.outputs.get(dependencyInstanceId);
|
|
1812
|
+
if (!dependency) continue;
|
|
1813
|
+
dependencyOutputHashSink.push(Buffer.from(dependencyInstanceId));
|
|
1814
|
+
}
|
|
1815
|
+
return {
|
|
1816
|
+
inputHash: crc32(Buffer.concat(inputHashSink)),
|
|
1817
|
+
dependencyOutputHash: bytesToHex(sha256(Buffer.concat(dependencyOutputHashSink))),
|
|
1818
|
+
outputHash: state?.operationStatus?.outputHash ?? ""
|
|
1819
|
+
};
|
|
1820
|
+
}
|
|
1821
|
+
};
|
|
1822
|
+
|
|
1823
|
+
// src/shared/resolvers/validation.ts
|
|
1824
|
+
import { isUnitModel as isUnitModel3 } from "@highstate/contract";
|
|
1825
|
+
import { Ajv } from "ajv";
|
|
1826
|
+
import styles from "ansi-styles";
|
|
1827
|
+
var ValidationResolver = class extends GraphResolver {
|
|
1828
|
+
getNodeDependencies({ resolvedInputs }) {
|
|
1829
|
+
const dependencies = [];
|
|
1830
|
+
for (const inputs of Object.values(resolvedInputs)) {
|
|
1831
|
+
for (const input of inputs) {
|
|
1832
|
+
dependencies.push(input.input.instanceId);
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
return dependencies;
|
|
1836
|
+
}
|
|
1837
|
+
processNode({ instance, component, state, resolvedInputs }) {
|
|
1838
|
+
const ajv = new Ajv({ strict: false });
|
|
1839
|
+
this.logger.debug({ instanceId: instance.id }, "validating instance");
|
|
1840
|
+
const validationErrors = [];
|
|
1841
|
+
for (const [name, argument] of Object.entries(component.args)) {
|
|
1842
|
+
if (!argument.required && !instance.args?.[name]) {
|
|
1843
|
+
continue;
|
|
1844
|
+
}
|
|
1845
|
+
if (!ajv.validate(argument.schema, instance.args?.[name])) {
|
|
1846
|
+
this.logger.debug({ instanceId: instance.id, argumentName: name }, "invalid argument");
|
|
1847
|
+
validationErrors.push(
|
|
1848
|
+
`Invalid argument "${styles.blueBright.open}${name}${styles.reset.close}": ` + ajv.errorsText()
|
|
1849
|
+
);
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
if (isUnitModel3(component)) {
|
|
1853
|
+
for (const [secret, secretSchema2] of Object.entries(component.secrets)) {
|
|
1854
|
+
if (secretSchema2.required && !state?.secretNames?.includes(secret)) {
|
|
1855
|
+
validationErrors.push(
|
|
1856
|
+
`Missing required secret "${styles.blueBright.open}${secret}${styles.reset.close}"`
|
|
1857
|
+
);
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
for (const [key, inputs] of Object.entries(resolvedInputs)) {
|
|
1862
|
+
for (const input of inputs) {
|
|
1863
|
+
const inputInstance = this.outputs.get(input.input.instanceId);
|
|
1864
|
+
if (inputInstance?.status !== "ok") {
|
|
1865
|
+
validationErrors.push(
|
|
1866
|
+
`Invalid input "${styles.blueBright.open}${key}${styles.reset.close}":
|
|
1867
|
+
"${styles.blueBright.open}${input.input.instanceId}${styles.reset.close}" has validation errors`
|
|
1868
|
+
);
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
for (const [name, input] of Object.entries(component.inputs)) {
|
|
1873
|
+
if (!input.required) {
|
|
1874
|
+
continue;
|
|
1875
|
+
}
|
|
1876
|
+
if (!resolvedInputs[name] || !resolvedInputs[name].length) {
|
|
1877
|
+
validationErrors.push(
|
|
1878
|
+
`Missing required input "${styles.blueBright.open}${name}${styles.reset.close}" of type "${styles.greenBright.open}${input.type}${styles.reset.close}"`
|
|
1879
|
+
);
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
if (validationErrors.length === 0) {
|
|
1883
|
+
return { status: "ok" };
|
|
1884
|
+
}
|
|
1885
|
+
const numberPrefixLength = (validationErrors.length + 1).toString().length + 2;
|
|
1886
|
+
const formattedError = validationErrors.map((error, index) => {
|
|
1887
|
+
const lines = error.split("\n");
|
|
1888
|
+
const prefix = `${index + 1}. `;
|
|
1889
|
+
return lines.map((line, lineIndex) => {
|
|
1890
|
+
const linePrefix = lineIndex === 0 ? prefix : " ".repeat(numberPrefixLength);
|
|
1891
|
+
return `${linePrefix}${line}`;
|
|
1892
|
+
}).join("\r\n");
|
|
1893
|
+
}).join("\r\n");
|
|
1894
|
+
return {
|
|
1895
|
+
status: "error",
|
|
1896
|
+
errorText: formattedError
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
};
|
|
1900
|
+
|
|
1901
|
+
// src/shared/resolvers/registry.ts
|
|
1902
|
+
var resolverFactories = {
|
|
1903
|
+
InputResolver,
|
|
1904
|
+
InputHashResolver,
|
|
1905
|
+
ValidationResolver,
|
|
1906
|
+
StateResolver
|
|
1907
|
+
};
|
|
1908
|
+
|
|
1909
|
+
export {
|
|
1910
|
+
userObjectMetaSchema,
|
|
1911
|
+
objectMetaSchema,
|
|
1912
|
+
hasObjectMeta,
|
|
1913
|
+
collectionQuerySchema,
|
|
1914
|
+
positionSchema,
|
|
1915
|
+
instanceInputSchema,
|
|
1916
|
+
hubInstanceInputSchema,
|
|
1917
|
+
instanceModelPatchSchema,
|
|
1918
|
+
instanceModelSchema,
|
|
1919
|
+
compositeInstanceSchema,
|
|
1920
|
+
compositeInstanceEventSchema,
|
|
1921
|
+
hubModelPatchSchema,
|
|
1922
|
+
hubModelSchema,
|
|
1923
|
+
instanceOperationStatusEnumSchema,
|
|
1924
|
+
instanceOperationStatusSchema,
|
|
1925
|
+
instanceEvaludationStatusEnumSchema,
|
|
1926
|
+
instanceEvaluationStatusSchema,
|
|
1927
|
+
WellKnownInstanceCustomStatus,
|
|
1928
|
+
instanceCustomStatusSchema,
|
|
1929
|
+
instanceStatusFieldValueSchema,
|
|
1930
|
+
instanceStatusFieldSchema,
|
|
1931
|
+
unitInstanceStatusFieldSchema,
|
|
1932
|
+
instanceStateExtraSchema,
|
|
1933
|
+
instanceStateSchema,
|
|
1934
|
+
instanceStatePatchSchema,
|
|
1935
|
+
applyStatePatch,
|
|
1936
|
+
isStateEmpty,
|
|
1937
|
+
isTransientOperationStatus,
|
|
1938
|
+
isStableOperationStatus,
|
|
1939
|
+
instanceStateEventSchema,
|
|
1940
|
+
operationTypeSchema,
|
|
1941
|
+
operationStatusSchema,
|
|
1942
|
+
operationOptionsSchema,
|
|
1943
|
+
operationRequestSchema,
|
|
1944
|
+
operationSchema,
|
|
1945
|
+
isFinalOperationStatus,
|
|
1946
|
+
operationLogEntrySchema,
|
|
1947
|
+
operationEventSchema,
|
|
1948
|
+
artifactUsageSchema,
|
|
1949
|
+
compareArtifactUsage,
|
|
1950
|
+
fileMetaSchema,
|
|
1951
|
+
artifactSchema,
|
|
1952
|
+
unitArtifactSchema,
|
|
1953
|
+
fileContentSchema,
|
|
1954
|
+
fileSchema,
|
|
1955
|
+
terminalSchema,
|
|
1956
|
+
terminalSpecSchema,
|
|
1957
|
+
unitTerminalSchema,
|
|
1958
|
+
terminalSessionSchema,
|
|
1959
|
+
pageBlockSchema,
|
|
1960
|
+
pageSchema,
|
|
1961
|
+
pageContentSchema,
|
|
1962
|
+
unitPageSchema,
|
|
1963
|
+
triggerSpecSchema,
|
|
1964
|
+
triggerSchema,
|
|
1965
|
+
unitTriggerSchema,
|
|
1966
|
+
triggerInvocationSchema,
|
|
1967
|
+
unlockMethodType,
|
|
1968
|
+
unlockMethodSchema,
|
|
1969
|
+
secretDescriptorSchema,
|
|
1970
|
+
secretSchema,
|
|
1971
|
+
formatSecretDescriptor,
|
|
1972
|
+
parseSecretDescriptor,
|
|
1973
|
+
WellKnownSecretDescriptors,
|
|
1974
|
+
instanceLockSpecSchema,
|
|
1975
|
+
instanceLockSchema,
|
|
1976
|
+
compareInstanceLockSpecs,
|
|
1977
|
+
instanceLockEventSchema,
|
|
1978
|
+
metaSchema,
|
|
1979
|
+
entitySchema,
|
|
1980
|
+
componentMetaSchema,
|
|
1981
|
+
componentArgumentSchema,
|
|
1982
|
+
componentInputSchema,
|
|
1983
|
+
componentModelSchema,
|
|
1984
|
+
serviceAccountSchema,
|
|
1985
|
+
workerStatus,
|
|
1986
|
+
workerSchema,
|
|
1987
|
+
workerUnitRegistrationSchema,
|
|
1988
|
+
unitWorkerSchema,
|
|
1989
|
+
getWorkerIdentity,
|
|
1990
|
+
instanceActionSchema,
|
|
1991
|
+
serviceAccountActionSchema,
|
|
1992
|
+
projectAccessScope,
|
|
1993
|
+
projectApiKeySchema,
|
|
1994
|
+
validateInstanceAccess,
|
|
1995
|
+
projectAccessActionDescriptions,
|
|
1996
|
+
projectSchema,
|
|
1997
|
+
projectModelSchema,
|
|
1998
|
+
projectUnlockSuiteSchema,
|
|
1999
|
+
projectUnlockStateSchema,
|
|
2000
|
+
diffLibraries,
|
|
2001
|
+
applyLibraryUpdate,
|
|
2002
|
+
backendUnlockMethodSchema,
|
|
2003
|
+
AccessError,
|
|
2004
|
+
GraphResolver,
|
|
2005
|
+
InputResolver,
|
|
2006
|
+
getResolvedHubInputs,
|
|
2007
|
+
getResolvedInstanceInputs,
|
|
2008
|
+
getResolvedInjectionInstanceInputs,
|
|
2009
|
+
getMatchedInjectionInstanceInputs,
|
|
2010
|
+
PromiseTracker,
|
|
2011
|
+
createAsyncBatcher,
|
|
2012
|
+
int32ToBytes,
|
|
2013
|
+
InputHashResolver,
|
|
2014
|
+
ValidationResolver,
|
|
2015
|
+
resolverFactories
|
|
2016
|
+
};
|
|
2017
|
+
//# sourceMappingURL=chunk-WHALQHEZ.js.map
|