@highstate/contract 0.9.16 → 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.
- package/dist/highstate.manifest.json +1 -1
- package/dist/index.js +541 -193
- package/dist/index.js.map +1 -1
- package/package.json +8 -7
- package/src/component.spec.ts +20 -17
- package/src/component.ts +198 -105
- package/src/entity.ts +76 -25
- package/src/evaluation.ts +71 -25
- package/src/i18n.ts +1 -1
- package/src/index.ts +40 -79
- package/src/instance.ts +146 -72
- package/src/meta.ts +120 -0
- package/src/unit.ts +32 -15
- package/src/utils.ts +22 -7
- package/src/types.ts +0 -53
package/dist/index.js
CHANGED
|
@@ -1,13 +1,274 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import z5, { z } from 'zod';
|
|
2
|
+
export { z } from 'zod';
|
|
3
|
+
import { mapValues, pickBy, isNonNullish } from 'remeda';
|
|
4
|
+
import { Ajv } from 'ajv';
|
|
5
|
+
|
|
6
|
+
// src/entity.ts
|
|
7
|
+
var userObjectMetaSchema = z.object({
|
|
8
|
+
/**
|
|
9
|
+
* Human-readable name of the object.
|
|
10
|
+
*
|
|
11
|
+
* Used in UI components for better user experience.
|
|
12
|
+
*/
|
|
13
|
+
title: z.string().optional(),
|
|
14
|
+
/**
|
|
15
|
+
* The title used globally for the object.
|
|
16
|
+
*
|
|
17
|
+
* For example, the title of an instance secret is "Password" which is okay
|
|
18
|
+
* to display in the instance secret list, but when the secret is displayed in a
|
|
19
|
+
* global secret list the name should be more descriptive, like "Proxmox Password".
|
|
20
|
+
*/
|
|
21
|
+
globalTitle: z.string().optional(),
|
|
22
|
+
/**
|
|
23
|
+
* Description of the object.
|
|
24
|
+
*
|
|
25
|
+
* Provides additional context for users and developers.
|
|
26
|
+
*/
|
|
27
|
+
description: z.string().optional(),
|
|
28
|
+
/**
|
|
29
|
+
* The color of the object.
|
|
30
|
+
*
|
|
31
|
+
* Used in UI components to visually distinguish objects.
|
|
32
|
+
*/
|
|
33
|
+
color: z.string().optional(),
|
|
34
|
+
/**
|
|
35
|
+
* Primary icon identifier.
|
|
36
|
+
*
|
|
37
|
+
* Should reference a iconify icon name, like "mdi:server" or "gg:remote".
|
|
38
|
+
*/
|
|
39
|
+
icon: z.string().optional(),
|
|
40
|
+
/**
|
|
41
|
+
* The color of the primary icon.
|
|
42
|
+
*/
|
|
43
|
+
iconColor: z.string().optional(),
|
|
44
|
+
/**
|
|
45
|
+
* The secondary icon identifier.
|
|
46
|
+
*
|
|
47
|
+
* Used to provide additional context or actions related to the object.
|
|
48
|
+
*
|
|
49
|
+
* Should reference a iconify icon name, like "mdi:edit" or "mdi:delete".
|
|
50
|
+
*/
|
|
51
|
+
secondaryIcon: z.string().optional(),
|
|
52
|
+
/**
|
|
53
|
+
* The color of the secondary icon.
|
|
54
|
+
*/
|
|
55
|
+
secondaryIconColor: z.string().optional()
|
|
56
|
+
});
|
|
57
|
+
var objectMetaSchema = userObjectMetaSchema.extend({
|
|
58
|
+
/**
|
|
59
|
+
* Creation timestamp in milliseconds.
|
|
60
|
+
*
|
|
61
|
+
* Managed automatically by the system.
|
|
62
|
+
*/
|
|
63
|
+
createdAt: z.number().optional(),
|
|
64
|
+
/**
|
|
65
|
+
* Last update timestamp in milliseconds.
|
|
66
|
+
*
|
|
67
|
+
* Managed automatically by the system.
|
|
68
|
+
*/
|
|
69
|
+
updatedAt: z.number().optional(),
|
|
70
|
+
/**
|
|
71
|
+
* The optional version of the document to support optimistic concurrency control.
|
|
72
|
+
*
|
|
73
|
+
* Managed automatically by the system.
|
|
74
|
+
*/
|
|
75
|
+
version: z.number().optional()
|
|
76
|
+
});
|
|
77
|
+
var genericNameSchema = z.string().regex(/^[a-z][a-z0-9-_.]+$/).min(2).max(64);
|
|
78
|
+
var fieldNameSchema = z.string().regex(/^[a-z][a-zA-Z0-9]+$/).min(2).max(64);
|
|
79
|
+
|
|
80
|
+
// src/i18n.ts
|
|
81
|
+
var knownAbbreviationsMap = /* @__PURE__ */ new Map();
|
|
82
|
+
function registerKnownAbbreviations(abbreviations) {
|
|
83
|
+
for (const abbr of abbreviations) {
|
|
84
|
+
const lower = abbr.toLowerCase();
|
|
85
|
+
if (!knownAbbreviationsMap.has(lower)) {
|
|
86
|
+
knownAbbreviationsMap.set(lower, abbr);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function camelCaseToHumanReadable(text2) {
|
|
91
|
+
const words = text2.split(/(?=[A-Z])|_|-|\./);
|
|
92
|
+
return words.map((word) => {
|
|
93
|
+
const lower = word.toLowerCase();
|
|
94
|
+
if (knownAbbreviationsMap.has(lower)) {
|
|
95
|
+
return knownAbbreviationsMap.get(lower);
|
|
96
|
+
}
|
|
97
|
+
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
98
|
+
}).join(" ");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/entity.ts
|
|
102
|
+
var entityModelSchema = z.object({
|
|
103
|
+
/**
|
|
104
|
+
* The static type of the entity.
|
|
105
|
+
*/
|
|
106
|
+
type: z.string(),
|
|
107
|
+
/**
|
|
108
|
+
* The JSON schema of the entity value.
|
|
109
|
+
*/
|
|
110
|
+
schema: z.custom(),
|
|
111
|
+
/**
|
|
112
|
+
* The extra metadata of the entity.
|
|
113
|
+
*/
|
|
114
|
+
meta: objectMetaSchema.required({ title: true }).pick({
|
|
115
|
+
title: true,
|
|
116
|
+
description: true,
|
|
117
|
+
color: true,
|
|
118
|
+
icon: true,
|
|
119
|
+
iconColor: true
|
|
120
|
+
}),
|
|
121
|
+
/**
|
|
122
|
+
* The CRC32 of the entity definition.
|
|
123
|
+
*/
|
|
124
|
+
definitionHash: z.number()
|
|
125
|
+
});
|
|
126
|
+
function defineEntity(options) {
|
|
127
|
+
if (!options.type) {
|
|
128
|
+
throw new Error("Entity type is required");
|
|
129
|
+
}
|
|
130
|
+
if (!options.schema) {
|
|
131
|
+
throw new Error("Entity schema is required");
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
return {
|
|
135
|
+
type: options.type,
|
|
136
|
+
schema: options.schema,
|
|
137
|
+
model: {
|
|
138
|
+
type: options.type,
|
|
139
|
+
schema: z.toJSONSchema(options.schema, { target: "draft-7" }),
|
|
140
|
+
meta: {
|
|
141
|
+
...options.meta,
|
|
142
|
+
title: options.meta?.title ?? camelCaseToHumanReadable(options.type)
|
|
143
|
+
},
|
|
144
|
+
// will be calculated by the library loader
|
|
145
|
+
definitionHash: null
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
} catch (error) {
|
|
149
|
+
throw new Error(`Failed to define entity "${options.type}"`, { cause: error });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function isEntity(value) {
|
|
153
|
+
return typeof value === "object" && value !== null && "model" in value;
|
|
154
|
+
}
|
|
155
|
+
var positionSchema = z.object({
|
|
156
|
+
x: z.number(),
|
|
157
|
+
y: z.number()
|
|
158
|
+
});
|
|
159
|
+
var instanceIdSchema = z.templateLiteral([genericNameSchema, ":", genericNameSchema]);
|
|
160
|
+
var instanceInputSchema = z.object({
|
|
161
|
+
instanceId: instanceIdSchema,
|
|
162
|
+
output: z.string()
|
|
163
|
+
});
|
|
164
|
+
var hubInputSchema = z.object({
|
|
165
|
+
hubId: z.string()
|
|
166
|
+
});
|
|
167
|
+
var instanceModelPatchSchema = z.object({
|
|
168
|
+
/**
|
|
169
|
+
* The static arguments passed to the instance.
|
|
170
|
+
*/
|
|
171
|
+
args: z.record(z.string(), z.unknown()).optional(),
|
|
172
|
+
/**
|
|
173
|
+
* The direct instances passed as inputs to the instance.
|
|
174
|
+
*/
|
|
175
|
+
inputs: z.record(z.string(), z.array(instanceInputSchema)).optional(),
|
|
176
|
+
/**
|
|
177
|
+
* The resolved unit inputs for the instance.
|
|
178
|
+
*
|
|
179
|
+
* Only for computed composite instances.
|
|
180
|
+
*/
|
|
181
|
+
hubInputs: z.record(z.string(), z.array(hubInputSchema)).optional(),
|
|
182
|
+
/**
|
|
183
|
+
* The inputs injected to the instance from the hubs.
|
|
184
|
+
*
|
|
185
|
+
* While `hubInputs` allows to pass hubs to distinct inputs,
|
|
186
|
+
* `injectionInputs` allows to pass hubs to the instance as a whole filling all inputs with matching types.
|
|
187
|
+
*
|
|
188
|
+
* Only for designer-first instances.
|
|
189
|
+
*/
|
|
190
|
+
injectionInputs: z.array(hubInputSchema).optional(),
|
|
191
|
+
/**
|
|
192
|
+
* The position of the instance on the canvas.
|
|
193
|
+
*
|
|
194
|
+
* Only for designer-first instances.
|
|
195
|
+
*/
|
|
196
|
+
position: positionSchema.optional()
|
|
197
|
+
});
|
|
198
|
+
var instanceModelSchema = z.object({
|
|
199
|
+
/**
|
|
200
|
+
* The id of the instance unique within the project.
|
|
201
|
+
*
|
|
202
|
+
* The format is `${instanceType}:${instanceName}`.
|
|
203
|
+
*/
|
|
204
|
+
id: instanceIdSchema,
|
|
205
|
+
/**
|
|
206
|
+
* The type of the instance.
|
|
207
|
+
*/
|
|
208
|
+
type: genericNameSchema,
|
|
209
|
+
/**
|
|
210
|
+
* The name of the instance.
|
|
211
|
+
*
|
|
212
|
+
* Must be unique within instances of the same type in the project.
|
|
213
|
+
*/
|
|
214
|
+
name: genericNameSchema,
|
|
215
|
+
...instanceModelPatchSchema.shape,
|
|
216
|
+
/**
|
|
217
|
+
* The id of the top level parent instance.
|
|
218
|
+
*
|
|
219
|
+
* Only for child instances of the composite instances.
|
|
220
|
+
*/
|
|
221
|
+
resolvedInputs: z.record(z.string(), z.array(instanceInputSchema)).optional(),
|
|
222
|
+
/**
|
|
223
|
+
* The position of the instance on the canvas.
|
|
224
|
+
*
|
|
225
|
+
* Only for designer-first instances.
|
|
226
|
+
*/
|
|
227
|
+
parentId: z.string().optional(),
|
|
228
|
+
/**
|
|
229
|
+
* The direct instance outputs returned by the instance as outputs.
|
|
230
|
+
*
|
|
231
|
+
* Only for computed composite instances.
|
|
232
|
+
*/
|
|
233
|
+
outputs: z.record(z.string(), z.array(instanceInputSchema)).optional(),
|
|
234
|
+
/**
|
|
235
|
+
* The resolved unit outputs for the instance.
|
|
236
|
+
*
|
|
237
|
+
* Only for computed composite instances.
|
|
238
|
+
*/
|
|
239
|
+
resolvedOutputs: z.record(z.string(), z.array(instanceInputSchema)).optional()
|
|
240
|
+
});
|
|
241
|
+
var hubModelPatchSchema = z.object({
|
|
242
|
+
/**
|
|
243
|
+
* The position of the hub on the canvas.
|
|
244
|
+
*/
|
|
245
|
+
position: positionSchema.optional(),
|
|
246
|
+
/**
|
|
247
|
+
* The inputs of the hub.
|
|
248
|
+
*/
|
|
249
|
+
inputs: z.array(instanceInputSchema).optional(),
|
|
250
|
+
/**
|
|
251
|
+
* The inputs injected to the hub from the hubs.
|
|
252
|
+
*
|
|
253
|
+
* While `inputs` allows to pass hubs to distinct inputs,
|
|
254
|
+
* `injectionInputs` allows to pass hubs to the hub as a whole filling all inputs with matching types.
|
|
255
|
+
*/
|
|
256
|
+
injectionInputs: z.array(hubInputSchema).optional()
|
|
257
|
+
});
|
|
258
|
+
var hubModelSchema = z.object({
|
|
259
|
+
/**
|
|
260
|
+
* The id of the hub unique within the project.
|
|
261
|
+
*/
|
|
262
|
+
id: z.nanoid(),
|
|
263
|
+
...hubModelPatchSchema.shape
|
|
264
|
+
});
|
|
4
265
|
function getInstanceId(instanceType, instanceName) {
|
|
5
266
|
return `${instanceType}:${instanceName}`;
|
|
6
267
|
}
|
|
7
268
|
function parseInstanceId(instanceId) {
|
|
8
269
|
const parts = instanceId.split(":");
|
|
9
270
|
if (parts.length !== 2) {
|
|
10
|
-
throw new Error(`Invalid instance
|
|
271
|
+
throw new Error(`Invalid instance ID: ${instanceId}`);
|
|
11
272
|
}
|
|
12
273
|
return parts;
|
|
13
274
|
}
|
|
@@ -40,52 +301,51 @@ function findRequiredInputs(inputs, names) {
|
|
|
40
301
|
}
|
|
41
302
|
var HighstateSignature = /* @__PURE__ */ ((HighstateSignature2) => {
|
|
42
303
|
HighstateSignature2["Artifact"] = "d55c63ac-3174-4756-808f-f778e99af0d1";
|
|
304
|
+
HighstateSignature2["Secret"] = "56ebf97b-57de-4985-8c86-bc1bc5871e6e";
|
|
305
|
+
HighstateSignature2["Yaml"] = "c857cac5-caa6-4421-b82c-e561fbce6367";
|
|
43
306
|
return HighstateSignature2;
|
|
44
307
|
})(HighstateSignature || {});
|
|
45
|
-
var
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
308
|
+
var yamlValueSchema = z.object({
|
|
309
|
+
["c857cac5-caa6-4421-b82c-e561fbce6367" /* Yaml */]: z.literal(true),
|
|
310
|
+
value: z.string()
|
|
311
|
+
});
|
|
312
|
+
var fileMetaSchema = z.object({
|
|
313
|
+
name: z.string(),
|
|
314
|
+
contentType: z.string().optional(),
|
|
315
|
+
size: z.number().optional(),
|
|
316
|
+
mode: z.number().optional(),
|
|
317
|
+
isBinary: z.boolean().optional()
|
|
51
318
|
});
|
|
52
|
-
var unitObjectMetaSchema =
|
|
53
|
-
displayName:
|
|
54
|
-
description:
|
|
55
|
-
primaryIcon:
|
|
319
|
+
var unitObjectMetaSchema = z.object({
|
|
320
|
+
displayName: z.string().optional(),
|
|
321
|
+
description: z.string().optional(),
|
|
322
|
+
primaryIcon: z.string().optional()
|
|
56
323
|
});
|
|
57
|
-
var
|
|
58
|
-
|
|
59
|
-
|
|
324
|
+
var unitSecretSchema = z.object({
|
|
325
|
+
["56ebf97b-57de-4985-8c86-bc1bc5871e6e" /* Secret */]: z.literal(true),
|
|
326
|
+
id: z.uuidv7(),
|
|
327
|
+
value: z.unknown()
|
|
60
328
|
});
|
|
61
|
-
var
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
329
|
+
var unitArtifactSchema = z.object({
|
|
330
|
+
["d55c63ac-3174-4756-808f-f778e99af0d1" /* Artifact */]: z.literal(true),
|
|
331
|
+
hash: z.string(),
|
|
332
|
+
meta: unitObjectMetaSchema.optional()
|
|
333
|
+
});
|
|
334
|
+
var fileContentSchema = z.union([
|
|
335
|
+
z.object({
|
|
336
|
+
type: z.literal("embedded"),
|
|
337
|
+
value: z.string()
|
|
65
338
|
}),
|
|
66
|
-
|
|
67
|
-
type:
|
|
68
|
-
|
|
339
|
+
z.object({
|
|
340
|
+
type: z.literal("artifact"),
|
|
341
|
+
...unitArtifactSchema.shape
|
|
69
342
|
})
|
|
70
343
|
]);
|
|
71
|
-
var fileSchema =
|
|
344
|
+
var fileSchema = z.object({
|
|
72
345
|
meta: fileMetaSchema,
|
|
73
346
|
content: fileContentSchema
|
|
74
347
|
});
|
|
75
348
|
|
|
76
|
-
// src/evaluation.ts
|
|
77
|
-
import { mapValues as mapValues3 } from "remeda";
|
|
78
|
-
|
|
79
|
-
// src/unit.ts
|
|
80
|
-
import { mapValues as mapValues2 } from "remeda";
|
|
81
|
-
|
|
82
|
-
// src/component.ts
|
|
83
|
-
import {
|
|
84
|
-
OptionalKind
|
|
85
|
-
} from "@sinclair/typebox";
|
|
86
|
-
import { isNonNullish, mapValues, pickBy } from "remeda";
|
|
87
|
-
import { Ajv } from "ajv";
|
|
88
|
-
|
|
89
349
|
// src/utils.ts
|
|
90
350
|
function text(strings, ...values) {
|
|
91
351
|
const stringValues = values.map(String);
|
|
@@ -113,40 +373,194 @@ function bytesToHumanReadable(bytes) {
|
|
|
113
373
|
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
114
374
|
return parseFloat((bytes / Math.pow(1024, i)).toFixed(2)) + " " + sizes[i];
|
|
115
375
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
if (!knownAbbreviationsMap.has(lower)) {
|
|
123
|
-
knownAbbreviationsMap.set(lower, abbr);
|
|
376
|
+
function formatInstancePath(instance) {
|
|
377
|
+
let result = instance.id;
|
|
378
|
+
while (instance.parentId) {
|
|
379
|
+
const parent = runtimeInstances.get(instance.parentId)?.instance;
|
|
380
|
+
if (!parent) {
|
|
381
|
+
break;
|
|
124
382
|
}
|
|
383
|
+
result = `${parent.id} -> ${result}`;
|
|
384
|
+
instance = parent;
|
|
125
385
|
}
|
|
386
|
+
return result;
|
|
126
387
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
388
|
+
var InstanceNameConflictError = class extends Error {
|
|
389
|
+
constructor(instanceId, firstPath, secondPath) {
|
|
390
|
+
super(
|
|
391
|
+
`Multiple instances produced with the same instance ID "${instanceId}":
|
|
392
|
+
1. ${firstPath}
|
|
393
|
+
2. ${secondPath}`
|
|
394
|
+
);
|
|
395
|
+
this.instanceId = instanceId;
|
|
396
|
+
this.firstPath = firstPath;
|
|
397
|
+
this.secondPath = secondPath;
|
|
398
|
+
this.name = "InstanceNameConflictError";
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
var currentInstance = null;
|
|
402
|
+
var runtimeInstances = /* @__PURE__ */ new Map();
|
|
403
|
+
function resetEvaluation() {
|
|
404
|
+
runtimeInstances.clear();
|
|
405
|
+
currentInstance = null;
|
|
406
|
+
}
|
|
407
|
+
function getRuntimeInstances() {
|
|
408
|
+
return Array.from(runtimeInstances.values());
|
|
409
|
+
}
|
|
410
|
+
function registerInstance(component, instance, fn) {
|
|
411
|
+
if (runtimeInstances.has(instance.id)) {
|
|
412
|
+
const existing = runtimeInstances.get(instance.id);
|
|
413
|
+
throw new InstanceNameConflictError(
|
|
414
|
+
instance.id,
|
|
415
|
+
formatInstancePath(existing.instance),
|
|
416
|
+
formatInstancePath(instance)
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
runtimeInstances.set(instance.id, { instance, component });
|
|
420
|
+
let previousParentInstance = null;
|
|
421
|
+
if (currentInstance) {
|
|
422
|
+
instance.parentId = currentInstance.id;
|
|
423
|
+
}
|
|
424
|
+
if (!isUnitModel(component.model)) {
|
|
425
|
+
previousParentInstance = currentInstance;
|
|
426
|
+
currentInstance = instance;
|
|
427
|
+
}
|
|
428
|
+
try {
|
|
429
|
+
const outputs = fn();
|
|
430
|
+
instance.resolvedOutputs = outputs;
|
|
431
|
+
instance.outputs = mapValues(
|
|
432
|
+
outputs ?? {},
|
|
433
|
+
(outputs2) => outputs2.map((output) => output[boundaryInput] ?? output)
|
|
434
|
+
);
|
|
435
|
+
return mapValues(
|
|
436
|
+
outputs,
|
|
437
|
+
(outputs2, outputKey) => outputs2.map((output) => ({
|
|
438
|
+
...output,
|
|
439
|
+
[boundaryInput]: { instanceId: instance.id, output: outputKey }
|
|
440
|
+
}))
|
|
441
|
+
);
|
|
442
|
+
} finally {
|
|
443
|
+
if (previousParentInstance) {
|
|
444
|
+
currentInstance = previousParentInstance;
|
|
133
445
|
}
|
|
134
|
-
|
|
135
|
-
}).join(" ");
|
|
446
|
+
}
|
|
136
447
|
}
|
|
137
448
|
|
|
138
449
|
// src/component.ts
|
|
450
|
+
var boundaryInput = Symbol("boundaryInput");
|
|
139
451
|
var ajv = new Ajv({ strict: false });
|
|
452
|
+
var validationEnabled = true;
|
|
453
|
+
function setValidationEnabled(enabled) {
|
|
454
|
+
validationEnabled = enabled;
|
|
455
|
+
}
|
|
456
|
+
var componentArgumentSchema = z.object({
|
|
457
|
+
/**
|
|
458
|
+
* The JSON schema of the argument value.
|
|
459
|
+
*/
|
|
460
|
+
schema: z.custom(),
|
|
461
|
+
/**
|
|
462
|
+
* Whether the argument is required.
|
|
463
|
+
*/
|
|
464
|
+
required: z.boolean(),
|
|
465
|
+
/**
|
|
466
|
+
* The extra metadata of the argument.
|
|
467
|
+
*/
|
|
468
|
+
meta: objectMetaSchema.required({ title: true }).pick({
|
|
469
|
+
title: true,
|
|
470
|
+
globalTitle: true,
|
|
471
|
+
description: true,
|
|
472
|
+
color: true,
|
|
473
|
+
icon: true,
|
|
474
|
+
iconColor: true
|
|
475
|
+
})
|
|
476
|
+
});
|
|
477
|
+
function isSchemaOptional(schema) {
|
|
478
|
+
return schema.safeParse(void 0).success;
|
|
479
|
+
}
|
|
480
|
+
var componentInputSchema = z.object({
|
|
481
|
+
/**
|
|
482
|
+
* The type of the input.
|
|
483
|
+
*/
|
|
484
|
+
type: genericNameSchema,
|
|
485
|
+
/**
|
|
486
|
+
* Whether the input is required.
|
|
487
|
+
*/
|
|
488
|
+
required: z.boolean(),
|
|
489
|
+
/**
|
|
490
|
+
* Whether the input can have multiple values.
|
|
491
|
+
*/
|
|
492
|
+
multiple: z.boolean(),
|
|
493
|
+
/**
|
|
494
|
+
* The extra metadata of the input.
|
|
495
|
+
*/
|
|
496
|
+
meta: objectMetaSchema.required({ title: true }).pick({
|
|
497
|
+
title: true,
|
|
498
|
+
description: true
|
|
499
|
+
})
|
|
500
|
+
});
|
|
501
|
+
var componentModelSchema = z.object({
|
|
502
|
+
/**
|
|
503
|
+
* The type of the component.
|
|
504
|
+
*/
|
|
505
|
+
type: genericNameSchema,
|
|
506
|
+
/**
|
|
507
|
+
* The record of the argument schemas.
|
|
508
|
+
*/
|
|
509
|
+
args: z.record(fieldNameSchema, componentArgumentSchema),
|
|
510
|
+
/**
|
|
511
|
+
* The record of the input schemas.
|
|
512
|
+
*/
|
|
513
|
+
inputs: z.record(fieldNameSchema, componentInputSchema),
|
|
514
|
+
/**
|
|
515
|
+
* The record of the output schemas.
|
|
516
|
+
*/
|
|
517
|
+
outputs: z.record(fieldNameSchema, componentInputSchema),
|
|
518
|
+
/**
|
|
519
|
+
* The extra metadata of the component.
|
|
520
|
+
*/
|
|
521
|
+
meta: objectMetaSchema.required({ title: true }).pick({
|
|
522
|
+
title: true,
|
|
523
|
+
description: true,
|
|
524
|
+
color: true,
|
|
525
|
+
icon: true,
|
|
526
|
+
iconColor: true,
|
|
527
|
+
secondaryIcon: true,
|
|
528
|
+
secondaryIconColor: true
|
|
529
|
+
}).extend({
|
|
530
|
+
/**
|
|
531
|
+
* The category of the component.
|
|
532
|
+
*
|
|
533
|
+
* Used to group components in the UI.
|
|
534
|
+
*/
|
|
535
|
+
category: z.string().optional(),
|
|
536
|
+
/**
|
|
537
|
+
* The default name prefix for the component instances.
|
|
538
|
+
*
|
|
539
|
+
* Used to generate default names for the instances.
|
|
540
|
+
*/
|
|
541
|
+
defaultNamePrefix: z.string().optional()
|
|
542
|
+
}),
|
|
543
|
+
/**
|
|
544
|
+
* The CRC32 of the component definition.
|
|
545
|
+
*/
|
|
546
|
+
definitionHash: z.number()
|
|
547
|
+
});
|
|
140
548
|
var originalCreate = Symbol("originalCreate");
|
|
141
549
|
function defineComponent(options) {
|
|
550
|
+
if (!options.type) {
|
|
551
|
+
throw new Error("Component type is required");
|
|
552
|
+
}
|
|
553
|
+
if (!options.create) {
|
|
554
|
+
throw new Error("Component create function is required");
|
|
555
|
+
}
|
|
142
556
|
function create(params) {
|
|
143
557
|
const { name, args, inputs } = params;
|
|
144
|
-
const
|
|
558
|
+
const instanceId = getInstanceId(options.type, name);
|
|
145
559
|
const flatInputs = mapValues(pickBy(inputs ?? {}, isNonNullish), (inputs2) => [inputs2].flat(2));
|
|
146
560
|
return registerInstance(
|
|
147
|
-
create
|
|
561
|
+
create,
|
|
148
562
|
{
|
|
149
|
-
id,
|
|
563
|
+
id: instanceId,
|
|
150
564
|
type: options.type,
|
|
151
565
|
name,
|
|
152
566
|
args: args ?? {},
|
|
@@ -154,18 +568,23 @@ function defineComponent(options) {
|
|
|
154
568
|
resolvedInputs: flatInputs
|
|
155
569
|
},
|
|
156
570
|
() => {
|
|
157
|
-
const
|
|
571
|
+
const componentInputs = create.model.inputs;
|
|
572
|
+
const markedInputs = mapValues(componentInputs, (componentInput, key) => {
|
|
573
|
+
const inputs2 = flatInputs[key];
|
|
574
|
+
if (!inputs2 || inputs2.length === 0) {
|
|
575
|
+
return create.model.inputs[key].multiple ? [{ instanceId, output: key }] : { instanceId, output: key };
|
|
576
|
+
}
|
|
158
577
|
const result = inputs2.map((input) => ({
|
|
159
578
|
...input,
|
|
160
|
-
[boundaryInput]: { instanceId
|
|
579
|
+
[boundaryInput]: { instanceId, output: key }
|
|
161
580
|
}));
|
|
162
581
|
return create.model.inputs?.[key]?.multiple === false ? result[0] : result;
|
|
163
582
|
});
|
|
164
583
|
const outputs = options.create({
|
|
165
|
-
id,
|
|
584
|
+
id: instanceId,
|
|
166
585
|
name,
|
|
167
586
|
args: validateArgsAndFillDefaults(
|
|
168
|
-
|
|
587
|
+
instanceId,
|
|
169
588
|
create.model,
|
|
170
589
|
args ? { ...args } : {}
|
|
171
590
|
),
|
|
@@ -175,20 +594,26 @@ function defineComponent(options) {
|
|
|
175
594
|
}
|
|
176
595
|
);
|
|
177
596
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
597
|
+
try {
|
|
598
|
+
create.entities = /* @__PURE__ */ new Map();
|
|
599
|
+
const mapInput = createInputMapper(create.entities);
|
|
600
|
+
create.model = {
|
|
601
|
+
type: options.type,
|
|
602
|
+
args: mapValues(options.args ?? {}, mapArgument),
|
|
603
|
+
inputs: mapValues(options.inputs ?? {}, mapInput),
|
|
604
|
+
outputs: mapValues(options.outputs ?? {}, mapInput),
|
|
605
|
+
meta: {
|
|
606
|
+
...options.meta,
|
|
607
|
+
title: options.meta?.title ?? camelCaseToHumanReadable(options.type)
|
|
608
|
+
},
|
|
609
|
+
definitionHash: null
|
|
610
|
+
// will be calculated by library loader
|
|
611
|
+
};
|
|
612
|
+
create[originalCreate] = options.create;
|
|
613
|
+
return create;
|
|
614
|
+
} catch (error) {
|
|
615
|
+
throw new Error(`Failed to define component "${options.type}"`, { cause: error });
|
|
616
|
+
}
|
|
192
617
|
}
|
|
193
618
|
function isComponent(value) {
|
|
194
619
|
return typeof value === "function" && "model" in value;
|
|
@@ -196,19 +621,19 @@ function isComponent(value) {
|
|
|
196
621
|
function mapArgument(value, key) {
|
|
197
622
|
if ("schema" in value) {
|
|
198
623
|
return {
|
|
199
|
-
schema: value.schema,
|
|
200
|
-
required: value.required ?? (
|
|
624
|
+
schema: z.toJSONSchema(value.schema, { target: "draft-7" }),
|
|
625
|
+
required: value.required ?? !isSchemaOptional(value.schema),
|
|
201
626
|
meta: {
|
|
202
|
-
|
|
203
|
-
|
|
627
|
+
...value.meta,
|
|
628
|
+
title: value.meta?.title ?? camelCaseToHumanReadable(key)
|
|
204
629
|
}
|
|
205
630
|
};
|
|
206
631
|
}
|
|
207
632
|
return {
|
|
208
|
-
schema: value,
|
|
209
|
-
required: !value
|
|
633
|
+
schema: z.toJSONSchema(value, { target: "draft-7" }),
|
|
634
|
+
required: !isSchemaOptional(value),
|
|
210
635
|
meta: {
|
|
211
|
-
|
|
636
|
+
title: camelCaseToHumanReadable(key)
|
|
212
637
|
}
|
|
213
638
|
};
|
|
214
639
|
}
|
|
@@ -224,9 +649,8 @@ function createInputMapper(entities) {
|
|
|
224
649
|
required: value.required ?? true,
|
|
225
650
|
multiple: value.multiple ?? false,
|
|
226
651
|
meta: {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
color: value.color
|
|
652
|
+
...value.meta,
|
|
653
|
+
title: value.meta?.title ?? camelCaseToHumanReadable(key)
|
|
230
654
|
}
|
|
231
655
|
};
|
|
232
656
|
}
|
|
@@ -236,7 +660,7 @@ function createInputMapper(entities) {
|
|
|
236
660
|
required: true,
|
|
237
661
|
multiple: false,
|
|
238
662
|
meta: {
|
|
239
|
-
|
|
663
|
+
title: camelCaseToHumanReadable(key)
|
|
240
664
|
}
|
|
241
665
|
};
|
|
242
666
|
};
|
|
@@ -245,18 +669,21 @@ function validateArgsAndFillDefaults(instanceId, model, args) {
|
|
|
245
669
|
for (const [key, argModel] of Object.entries(model.args)) {
|
|
246
670
|
let value = args[key];
|
|
247
671
|
if (!value) {
|
|
248
|
-
if (argModel.required) {
|
|
672
|
+
if (argModel.required && validationEnabled) {
|
|
249
673
|
throw new Error(`Missing required argument "${key}" for instance "${instanceId}"`);
|
|
250
674
|
}
|
|
251
675
|
value = argModel.schema.default;
|
|
252
676
|
args[key] = value;
|
|
253
677
|
}
|
|
254
|
-
if (value && !ajv.validate(argModel.schema, value)) {
|
|
678
|
+
if (validationEnabled && value && !ajv.validate(argModel.schema, value)) {
|
|
255
679
|
throw new Error(`Invalid argument "${key}" for instance "${instanceId}": ${ajv.errorsText()}`);
|
|
256
680
|
}
|
|
257
681
|
}
|
|
258
682
|
return args;
|
|
259
683
|
}
|
|
684
|
+
function isUnitModel(model) {
|
|
685
|
+
return "source" in model;
|
|
686
|
+
}
|
|
260
687
|
function $args(args) {
|
|
261
688
|
return args;
|
|
262
689
|
}
|
|
@@ -268,10 +695,20 @@ function $outputs(outputs) {
|
|
|
268
695
|
}
|
|
269
696
|
|
|
270
697
|
// src/unit.ts
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
698
|
+
var componentSecretSchema = componentArgumentSchema.extend({
|
|
699
|
+
/**
|
|
700
|
+
* The secret cannot be modified by the user, but can be modified by the unit.
|
|
701
|
+
*/
|
|
702
|
+
readonly: z5.boolean(),
|
|
703
|
+
/**
|
|
704
|
+
* The secret value is computed by the unit and should not be passed to it when invoked.
|
|
705
|
+
*/
|
|
706
|
+
computed: z5.boolean()
|
|
707
|
+
});
|
|
274
708
|
function defineUnit(options) {
|
|
709
|
+
if (!options.source) {
|
|
710
|
+
throw new Error("Unit source is required");
|
|
711
|
+
}
|
|
275
712
|
const component = defineComponent({
|
|
276
713
|
...options,
|
|
277
714
|
create({ id }) {
|
|
@@ -288,116 +725,27 @@ function defineUnit(options) {
|
|
|
288
725
|
}
|
|
289
726
|
});
|
|
290
727
|
component.model.source = options.source ?? {};
|
|
291
|
-
component.model.secrets =
|
|
728
|
+
component.model.secrets = mapValues(options.secrets ?? {}, mapSecret);
|
|
292
729
|
return component;
|
|
293
730
|
}
|
|
294
731
|
function $secrets(secrets) {
|
|
295
732
|
return secrets;
|
|
296
733
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
function getCompositeInstances() {
|
|
306
|
-
return Array.from(compositeInstances.values());
|
|
307
|
-
}
|
|
308
|
-
function registerInstance(component, instance, fn) {
|
|
309
|
-
let previousParentInstance = null;
|
|
310
|
-
if (currentCompositeInstance) {
|
|
311
|
-
instance.parentId = currentCompositeInstance.instance.id;
|
|
312
|
-
currentCompositeInstance.children.push(instance);
|
|
313
|
-
}
|
|
314
|
-
if (!isUnitModel(component)) {
|
|
315
|
-
previousParentInstance = currentCompositeInstance;
|
|
316
|
-
currentCompositeInstance = { instance, children: [] };
|
|
317
|
-
compositeInstances.set(currentCompositeInstance.instance.id, currentCompositeInstance);
|
|
318
|
-
}
|
|
319
|
-
try {
|
|
320
|
-
const outputs = fn();
|
|
321
|
-
instance.resolvedOutputs = outputs;
|
|
322
|
-
instance.outputs = mapValues3(
|
|
323
|
-
outputs ?? {},
|
|
324
|
-
(outputs2) => outputs2.map((output) => output[boundaryInput] ?? output)
|
|
325
|
-
);
|
|
326
|
-
return mapValues3(
|
|
327
|
-
outputs,
|
|
328
|
-
(outputs2, outputKey) => outputs2.map((output) => ({
|
|
329
|
-
...output,
|
|
330
|
-
[boundaryInput]: { instanceId: instance.id, output: outputKey }
|
|
331
|
-
}))
|
|
332
|
-
);
|
|
333
|
-
} finally {
|
|
334
|
-
if (previousParentInstance) {
|
|
335
|
-
currentCompositeInstance = previousParentInstance;
|
|
336
|
-
}
|
|
734
|
+
function mapSecret(value, key) {
|
|
735
|
+
if ("schema" in value) {
|
|
736
|
+
return {
|
|
737
|
+
...mapArgument(value, key),
|
|
738
|
+
readonly: value.readonly ?? false,
|
|
739
|
+
computed: value.computed ?? false
|
|
740
|
+
};
|
|
337
741
|
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// src/entity.ts
|
|
341
|
-
function defineEntity(options) {
|
|
342
742
|
return {
|
|
343
|
-
|
|
344
|
-
|
|
743
|
+
...mapArgument(value, key),
|
|
744
|
+
readonly: false,
|
|
745
|
+
computed: false
|
|
345
746
|
};
|
|
346
747
|
}
|
|
347
|
-
function isEntity(value) {
|
|
348
|
-
return typeof value === "object" && value !== null && "type" in value && "schema" in value && "meta" in value;
|
|
349
|
-
}
|
|
350
748
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
// src/index.ts
|
|
355
|
-
export * from "@sinclair/typebox";
|
|
356
|
-
import {
|
|
357
|
-
Type as BaseType
|
|
358
|
-
} from "@sinclair/typebox";
|
|
359
|
-
function StringEnum(values) {
|
|
360
|
-
return Type2.Union(values.map((value) => Type2.Literal(value)));
|
|
361
|
-
}
|
|
362
|
-
function Default(schema, defaultValue) {
|
|
363
|
-
return { ...schema, default: defaultValue };
|
|
364
|
-
}
|
|
365
|
-
var Type2 = {
|
|
366
|
-
...BaseType,
|
|
367
|
-
StringEnum,
|
|
368
|
-
Default
|
|
369
|
-
};
|
|
370
|
-
export {
|
|
371
|
-
$args,
|
|
372
|
-
$inputs,
|
|
373
|
-
$outputs,
|
|
374
|
-
$secrets,
|
|
375
|
-
HighstateSignature,
|
|
376
|
-
Type2 as Type,
|
|
377
|
-
bytesToHumanReadable,
|
|
378
|
-
camelCaseToHumanReadable,
|
|
379
|
-
defineComponent,
|
|
380
|
-
defineEntity,
|
|
381
|
-
defineUnit,
|
|
382
|
-
fileContentSchema,
|
|
383
|
-
fileMetaSchema,
|
|
384
|
-
fileSchema,
|
|
385
|
-
findInput,
|
|
386
|
-
findInputs,
|
|
387
|
-
findRequiredInput,
|
|
388
|
-
findRequiredInputs,
|
|
389
|
-
getCompositeInstances,
|
|
390
|
-
getInstanceId,
|
|
391
|
-
isComponent,
|
|
392
|
-
isEntity,
|
|
393
|
-
isUnitModel,
|
|
394
|
-
originalCreate,
|
|
395
|
-
parseInstanceId,
|
|
396
|
-
registerKnownAbbreviations,
|
|
397
|
-
resetEvaluation,
|
|
398
|
-
text,
|
|
399
|
-
trimIndentation,
|
|
400
|
-
unitArtifactSchema,
|
|
401
|
-
unitObjectMetaSchema
|
|
402
|
-
};
|
|
749
|
+
export { $args, $inputs, $outputs, $secrets, HighstateSignature, InstanceNameConflictError, bytesToHumanReadable, camelCaseToHumanReadable, componentArgumentSchema, componentInputSchema, componentModelSchema, componentSecretSchema, defineComponent, defineEntity, defineUnit, entityModelSchema, fieldNameSchema, fileContentSchema, fileMetaSchema, fileSchema, findInput, findInputs, findRequiredInput, findRequiredInputs, genericNameSchema, getInstanceId, getRuntimeInstances, hubInputSchema, hubModelPatchSchema, hubModelSchema, instanceIdSchema, instanceInputSchema, instanceModelPatchSchema, instanceModelSchema, isComponent, isEntity, isUnitModel, objectMetaSchema, originalCreate, parseInstanceId, positionSchema, registerKnownAbbreviations, resetEvaluation, setValidationEnabled, text, trimIndentation, unitArtifactSchema, unitObjectMetaSchema, unitSecretSchema, userObjectMetaSchema, yamlValueSchema };
|
|
750
|
+
//# sourceMappingURL=index.js.map
|
|
403
751
|
//# sourceMappingURL=index.js.map
|