@hraness/slopcamera 3.2.8 → 3.3.2
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/README.md +29 -9
- package/apps/desktop/application/context.ts +6 -0
- package/apps/desktop/application/default-registry.ts +26 -0
- package/apps/desktop/application/operation.ts +14 -1
- package/apps/desktop/application/operations/index.ts +4 -0
- package/apps/desktop/application/operations/spatial-behavior.ts +151 -0
- package/apps/desktop/application/operations/spatial-direction.ts +222 -0
- package/apps/desktop/application/operations/spatial-rendered-audit.ts +174 -0
- package/apps/desktop/application/operations/spatial-review.ts +194 -0
- package/apps/desktop/application/operations/spatial-scene.ts +25 -1
- package/apps/desktop/application/registry.ts +2 -2
- package/apps/desktop/application/spatial-asset-admission.ts +201 -0
- package/apps/desktop/application/spatial-assets.ts +160 -31
- package/apps/desktop/application/spatial-render.ts +217 -20
- package/apps/desktop/application/spatial-rendered-audit.ts +273 -0
- package/apps/desktop/application/spatial-review.ts +361 -0
- package/apps/desktop/application/spatial-spz.ts +48 -3
- package/apps/desktop/application/spatial-world-import.ts +26 -5
- package/apps/desktop/application/spatial-world-metadata.ts +105 -0
- package/apps/desktop/cli/args.ts +514 -11
- package/apps/desktop/cli/capability-manifest.ts +374 -0
- package/apps/desktop/cli/cinema-renderer.ts +608 -0
- package/apps/desktop/cli/command-host-resources.ts +29 -1
- package/apps/desktop/cli/commands.ts +1188 -4
- package/apps/desktop/cli/gateway-review-provider.ts +334 -0
- package/apps/desktop/cli/help.ts +172 -6
- package/apps/desktop/cli/main.ts +3 -3
- package/apps/desktop/cli/portable-surface.ts +6 -1
- package/apps/desktop/cli/spatial-asset-service.ts +124 -0
- package/apps/desktop/cli/spatial-design-service.ts +237 -0
- package/apps/desktop/cli/spatial-generate-service.ts +370 -0
- package/apps/desktop/cli/spatial-scene-service.ts +271 -4
- package/apps/desktop/cli/workflow-code.ts +1 -1
- package/apps/desktop/code/semantic-builder.ts +24 -0
- package/apps/desktop/contracts/cinema.ts +736 -0
- package/apps/desktop/contracts/index.ts +1 -0
- package/apps/desktop/contracts/spatial-asset.ts +16 -0
- package/apps/desktop/contracts/spatial-world.ts +26 -3
- package/apps/desktop/core/cinema-plan.ts +1320 -0
- package/apps/desktop/core/index.ts +1 -0
- package/apps/desktop/core/storage.ts +75 -0
- package/apps/desktop/dist/cli/main.js +725 -273
- package/apps/desktop/html-overlay/spatial.ts +619 -57
- package/apps/desktop/workflows/cinematic-world.ts +127 -0
- package/apps/desktop/workflows/index.ts +6 -0
- package/dist/cli.js +25 -429
- package/dist/code/advanced.js +1 -269
- package/dist/code/index.js +16 -2239
- package/dist/generate.js +1 -23
- package/dist/host-resources.js +1 -25
- package/dist/index-0bbesn4m.js +35 -0
- package/dist/index-296qhpf2.js +3 -0
- package/dist/index-3cxf2c58.js +3 -0
- package/dist/index-77fjfg9f.js +3 -0
- package/dist/index-80a36bc0.js +3 -0
- package/dist/index-a3vvs3rf.js +3 -0
- package/dist/index-b3geqczn.js +5 -0
- package/dist/index-grk47tgs.js +3 -0
- package/dist/index-gs48afpt.js +7 -0
- package/dist/index-qry58nj2.js +10 -0
- package/dist/index-zhg36tf9.js +3 -0
- package/dist/index.js +1 -226
- package/dist/operations.js +1 -28
- package/dist/skill-install-gx7afxsd.js +2 -0
- package/dist/vectorize/worker.js +1 -141
- package/dist/workflow.js +1 -15
- package/docs/README.md +5 -1
- package/docs/studio.md +12 -0
- package/package.json +7 -5
- package/skills/slopcamera/SKILL.md +7 -1
- package/skills/slopcamera/references/directed-scenes.md +48 -2
- package/skills/slopcamera/references/gateway-media.md +15 -1
- package/skills/slopcamera/references/image-galleries.md +166 -0
- package/skills/slopcamera/references/install.md +1 -1
- package/skills/slopcamera/references/music-video.md +4 -0
- package/skills/slopcamera/references/native-studio.md +19 -0
- package/skills/slopcamera/references/parametric-design.md +14 -0
- package/skills/slopcamera/references/scene-building.md +172 -0
- package/skills/slopcamera/references/social-collage-banners.md +204 -0
- package/skills/slopcamera/references/workflows-sdk.md +3 -3
- package/skills/slopcamera/scripts/compose-social-collage-banner.ts +728 -0
- package/src/capability-manifest.ts +361 -0
- package/src/cli.ts +222 -4
- package/src/code/canonical-json.ts +9 -0
- package/src/generate.ts +2 -2
- package/src/icon.ts +1111 -0
- package/src/image-gallery.ts +1049 -0
- package/src/index.ts +11 -0
- package/src/mcp/boundary.ts +11 -11
- package/src/mcp/index.ts +3 -0
- package/src/mcp/server.ts +2 -1
- package/src/mcp/tools.ts +1649 -132
- package/src/mcp/types.ts +19 -0
- package/src/operations.ts +412 -0
- package/src/portable-capability-manifest.ts +67 -0
- package/src/scene-gallery.ts +184 -0
- package/src/spatial-scene/asset-admission.ts +183 -0
- package/src/spatial-scene/audit-rendered.ts +692 -0
- package/src/spatial-scene/audit.ts +617 -0
- package/src/spatial-scene/behavior-audit.ts +252 -0
- package/src/spatial-scene/behavior-bake.ts +232 -0
- package/src/spatial-scene/behavior-fns.ts +585 -0
- package/src/spatial-scene/behavior-gallery.ts +108 -0
- package/src/spatial-scene/behavior-stdlib.ts +323 -0
- package/src/spatial-scene/behavior-trace.ts +325 -0
- package/src/spatial-scene/behavior.ts +617 -0
- package/src/spatial-scene/build.ts +632 -0
- package/src/spatial-scene/camera-rig.ts +125 -0
- package/src/spatial-scene/camera-track.ts +4 -2
- package/src/spatial-scene/character.ts +124 -0
- package/src/spatial-scene/contracts.ts +75 -7
- package/src/spatial-scene/design-templates.ts +351 -0
- package/src/spatial-scene/design.ts +327 -0
- package/src/spatial-scene/direction-compile.ts +584 -0
- package/src/spatial-scene/direction.ts +122 -0
- package/src/spatial-scene/effects.ts +149 -0
- package/src/spatial-scene/evaluate.ts +109 -29
- package/src/spatial-scene/gallery.ts +277 -0
- package/src/spatial-scene/generate.ts +239 -0
- package/src/spatial-scene/geometry-native.ts +165 -0
- package/src/spatial-scene/geometry.ts +1216 -0
- package/src/spatial-scene/gltf.ts +600 -77
- package/src/spatial-scene/identity.ts +55 -2
- package/src/spatial-scene/index.ts +36 -0
- package/src/spatial-scene/inspect.ts +35 -6
- package/src/spatial-scene/material-lighting.ts +609 -0
- package/src/spatial-scene/math.ts +21 -4
- package/src/spatial-scene/motion-evidence.ts +88 -0
- package/src/spatial-scene/parametric.ts +765 -0
- package/src/spatial-scene/particle-preparation.ts +183 -0
- package/src/spatial-scene/particle.ts +195 -0
- package/src/spatial-scene/patch.ts +109 -15
- package/src/spatial-scene/performance.ts +1613 -0
- package/src/spatial-scene/probe.ts +137 -0
- package/src/spatial-scene/recipe-pack.ts +86 -0
- package/src/spatial-scene/render-effects.ts +240 -0
- package/src/spatial-scene/review.ts +639 -0
- package/src/spatial-scene/simulation-bake.ts +206 -0
- package/src/spatial-scene/simulation.ts +187 -0
- package/src/spatial-scene/solve.ts +366 -0
- package/src/spatial-scene/temporal-audit.ts +354 -0
- package/src/version.ts +1 -1
- package/dist/index-42zsesc1.js +0 -2257
- package/dist/index-7131pg1c.js +0 -1820
- package/dist/index-7308egqr.js +0 -48
- package/dist/index-8txs6fkn.js +0 -712
- package/dist/index-fava6pge.js +0 -192
- package/dist/index-h1k0fnjq.js +0 -2363
- package/dist/index-r7gdhmsp.js +0 -424
- package/dist/index-sh6xbav6.js +0 -1219
- package/dist/index-z1w83f81.js +0 -4
- package/dist/index-zfnddgay.js +0 -2029
- package/dist/skill-install-dh0ntqba.js +0 -10
package/dist/index-42zsesc1.js
DELETED
|
@@ -1,2257 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import {
|
|
3
|
-
SlopcameraCodeError,
|
|
4
|
-
canonicalJsonSha256,
|
|
5
|
-
canonicalJsonSha256Prefixed,
|
|
6
|
-
captureJsonStructure,
|
|
7
|
-
createBoundedJsonSnapshot,
|
|
8
|
-
createBoundedJsonValueSnapshot,
|
|
9
|
-
deepFreezeJson,
|
|
10
|
-
slopcameraCodeErrorMessage,
|
|
11
|
-
utf8ByteLength
|
|
12
|
-
} from "./index-8txs6fkn.js";
|
|
13
|
-
|
|
14
|
-
// src/code/contracts.ts
|
|
15
|
-
import { z } from "zod";
|
|
16
|
-
var WORKFLOW_GRAPH_VERSION = "slopcamera-workflow-graph-v2";
|
|
17
|
-
var WORKFLOW_REF_VERSION = "slopcamera-workflow-ref-v1";
|
|
18
|
-
var GRAPH_ABI = "slopcamera-workflow-graph-abi-v2";
|
|
19
|
-
var REQUIREMENT_ENVELOPE_VERSION = "slopcamera-requirement-envelope-v2";
|
|
20
|
-
var TRUSTED_COMPUTE_VERSION = 1;
|
|
21
|
-
var WORKFLOW_COMPILATION_VERSION = "slopcamera-workflow-compilation-v1";
|
|
22
|
-
var LEGACY_WORKFLOW_GRAPH_VERSION = "studio-workflow-graph-v2";
|
|
23
|
-
var LEGACY_WORKFLOW_REF_VERSION = "studio-workflow-ref-v1";
|
|
24
|
-
var LEGACY_GRAPH_ABI = "studio-workflow-graph-abi-v2";
|
|
25
|
-
var LEGACY_REQUIREMENT_ENVELOPE_VERSION = "studio-requirement-envelope-v2";
|
|
26
|
-
var MAX_SERIALIZED_GRAPH_NODES = 4096;
|
|
27
|
-
var MAX_SERIALIZED_NODE_DEPENDENCIES = 4096;
|
|
28
|
-
var MAX_SERIALIZED_REF_PATH_SEGMENTS = 32;
|
|
29
|
-
var MAX_OPERATION_DISCOVERY_ENTRIES = 4096;
|
|
30
|
-
var MAX_TRUSTED_COMPUTE_INPUT_BYTES = 2 * 1024 * 1024;
|
|
31
|
-
var MAX_TRUSTED_COMPUTE_OUTPUT_BYTES = 2 * 1024 * 1024;
|
|
32
|
-
var MAX_TRUSTED_COMPUTE_DURATION_MS = 5 * 60 * 1000;
|
|
33
|
-
var SAFE_IDENTIFIER_PATTERN = /^[a-z][a-z0-9]*(?:[-_.][a-z0-9]+)*$/u;
|
|
34
|
-
var NODE_KEY_SEGMENT_PATTERN = /^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/u;
|
|
35
|
-
var NODE_KEY_PATTERN = /^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*(?:\/[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*)*$/u;
|
|
36
|
-
var SCHEMA_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/@-]*$/u;
|
|
37
|
-
var OPERATION_KIND_PATTERN = /^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*(?:\.[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*)+$/u;
|
|
38
|
-
var SHA256_PATTERN = /^[a-f0-9]{64}$/u;
|
|
39
|
-
var WorkflowIdSchema = z.string().min(1).max(128).regex(SAFE_IDENTIFIER_PATTERN);
|
|
40
|
-
var NodeKeySegmentSchema = z.string().min(1).max(64).regex(NODE_KEY_SEGMENT_PATTERN);
|
|
41
|
-
var NodeKeySchema = z.string().min(1).max(255).regex(NODE_KEY_PATTERN);
|
|
42
|
-
var SchemaIdSchema = z.string().min(1).max(192).regex(SCHEMA_ID_PATTERN);
|
|
43
|
-
var ComputeKeySchema = z.string().min(1).max(192).regex(SCHEMA_ID_PATTERN);
|
|
44
|
-
var OperationKindSchema = z.string().min(3).max(192).regex(OPERATION_KIND_PATTERN);
|
|
45
|
-
var Sha256Schema = z.string().regex(SHA256_PATTERN);
|
|
46
|
-
var PositiveSafeIntegerSchema = z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
|
|
47
|
-
var NonnegativeSafeIntegerSchema = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
48
|
-
var RefPathSegmentSchema = z.union([
|
|
49
|
-
z.string().min(1).max(128),
|
|
50
|
-
NonnegativeSafeIntegerSchema
|
|
51
|
-
]);
|
|
52
|
-
var JsonObjectKeySchema = z.string().refine((key) => key !== "__proto__", "JSON object keys must not use the reserved __proto__ name.");
|
|
53
|
-
var RESERVED_JSON_OBJECT = Symbol("reserved-json-object");
|
|
54
|
-
function rejectReservedJsonObjectKey(value) {
|
|
55
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.hasOwn(value, "__proto__") ? RESERVED_JSON_OBJECT : value;
|
|
56
|
-
}
|
|
57
|
-
var JsonValueSchema = z.lazy(() => z.preprocess(rejectReservedJsonObjectKey, z.union([
|
|
58
|
-
z.null(),
|
|
59
|
-
z.boolean(),
|
|
60
|
-
z.number().finite(),
|
|
61
|
-
z.string(),
|
|
62
|
-
z.array(JsonValueSchema),
|
|
63
|
-
z.record(JsonObjectKeySchema, JsonValueSchema)
|
|
64
|
-
])));
|
|
65
|
-
var SerializedRefV1Schema = z.strictObject({
|
|
66
|
-
$ref: z.strictObject({
|
|
67
|
-
nodeKey: NodeKeySchema,
|
|
68
|
-
path: z.array(RefPathSegmentSchema).max(MAX_SERIALIZED_REF_PATH_SEGMENTS).optional(),
|
|
69
|
-
schemaId: SchemaIdSchema
|
|
70
|
-
}),
|
|
71
|
-
version: z.union([
|
|
72
|
-
z.literal(WORKFLOW_REF_VERSION),
|
|
73
|
-
z.literal(LEGACY_WORKFLOW_REF_VERSION)
|
|
74
|
-
])
|
|
75
|
-
});
|
|
76
|
-
var GraphInputObjectSchema = z.lazy(() => z.record(JsonObjectKeySchema, GraphInputValueSchema).superRefine((value, context) => {
|
|
77
|
-
if (Object.hasOwn(value, "$ref")) {
|
|
78
|
-
context.addIssue({
|
|
79
|
-
code: "custom",
|
|
80
|
-
message: "The reserved $ref field must contain a complete versioned workflow reference."
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}));
|
|
84
|
-
var GraphInputValueSchema = z.lazy(() => z.preprocess(rejectReservedJsonObjectKey, z.union([
|
|
85
|
-
SerializedRefV1Schema,
|
|
86
|
-
z.null(),
|
|
87
|
-
z.boolean(),
|
|
88
|
-
z.number().finite(),
|
|
89
|
-
z.string(),
|
|
90
|
-
z.array(GraphInputValueSchema),
|
|
91
|
-
GraphInputObjectSchema
|
|
92
|
-
])));
|
|
93
|
-
var WorkflowOutputObjectSchema = z.lazy(() => z.record(JsonObjectKeySchema, WorkflowOutputBindingSchema).superRefine((value, context) => {
|
|
94
|
-
if (Object.hasOwn(value, "$ref")) {
|
|
95
|
-
context.addIssue({
|
|
96
|
-
code: "custom",
|
|
97
|
-
message: "The reserved $ref field must contain a complete versioned workflow reference."
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
}));
|
|
101
|
-
var WorkflowOutputBindingSchema = z.lazy(() => z.preprocess(rejectReservedJsonObjectKey, z.union([
|
|
102
|
-
SerializedRefV1Schema,
|
|
103
|
-
z.array(WorkflowOutputBindingSchema),
|
|
104
|
-
WorkflowOutputObjectSchema
|
|
105
|
-
])));
|
|
106
|
-
var AuthoredOperationIdentitySchema = z.strictObject({
|
|
107
|
-
kind: OperationKindSchema,
|
|
108
|
-
version: PositiveSafeIntegerSchema
|
|
109
|
-
});
|
|
110
|
-
var AuthoredComputeIdentitySchema = z.strictObject({
|
|
111
|
-
bounds: z.strictObject({
|
|
112
|
-
maxDurationMs: PositiveSafeIntegerSchema.max(MAX_TRUSTED_COMPUTE_DURATION_MS),
|
|
113
|
-
maxInputBytes: PositiveSafeIntegerSchema.max(MAX_TRUSTED_COMPUTE_INPUT_BYTES),
|
|
114
|
-
maxOutputBytes: PositiveSafeIntegerSchema.max(MAX_TRUSTED_COMPUTE_OUTPUT_BYTES)
|
|
115
|
-
}),
|
|
116
|
-
key: ComputeKeySchema,
|
|
117
|
-
version: z.literal(TRUSTED_COMPUTE_VERSION)
|
|
118
|
-
});
|
|
119
|
-
var AuthoredNodeExecutorSchema = z.discriminatedUnion("kind", [
|
|
120
|
-
z.strictObject({
|
|
121
|
-
kind: z.literal("operation"),
|
|
122
|
-
operation: AuthoredOperationIdentitySchema
|
|
123
|
-
}),
|
|
124
|
-
z.strictObject({
|
|
125
|
-
compute: AuthoredComputeIdentitySchema,
|
|
126
|
-
kind: z.literal("compute")
|
|
127
|
-
})
|
|
128
|
-
]);
|
|
129
|
-
var AuthoredGraphNodeV1Schema = z.strictObject({
|
|
130
|
-
controlDependencies: z.array(NodeKeySchema).max(MAX_SERIALIZED_NODE_DEPENDENCIES).optional(),
|
|
131
|
-
dependencies: z.array(NodeKeySchema).max(MAX_SERIALIZED_NODE_DEPENDENCIES),
|
|
132
|
-
executor: AuthoredNodeExecutorSchema,
|
|
133
|
-
input: GraphInputValueSchema,
|
|
134
|
-
inputSchemaId: SchemaIdSchema,
|
|
135
|
-
key: NodeKeySchema,
|
|
136
|
-
label: z.string().min(1).max(160).optional(),
|
|
137
|
-
outputSchemaId: SchemaIdSchema
|
|
138
|
-
});
|
|
139
|
-
function isOperationGraphNode(node) {
|
|
140
|
-
return node.executor.kind === "operation";
|
|
141
|
-
}
|
|
142
|
-
function isComputeGraphNode(node) {
|
|
143
|
-
return node.executor.kind === "compute";
|
|
144
|
-
}
|
|
145
|
-
var WorkflowIdentitySchema = z.strictObject({
|
|
146
|
-
id: WorkflowIdSchema,
|
|
147
|
-
inputSchemaId: SchemaIdSchema,
|
|
148
|
-
version: PositiveSafeIntegerSchema
|
|
149
|
-
});
|
|
150
|
-
var AuthoredWorkflowGraphV1Schema = z.strictObject({
|
|
151
|
-
nodes: z.array(AuthoredGraphNodeV1Schema).min(1).max(MAX_SERIALIZED_GRAPH_NODES),
|
|
152
|
-
outputs: WorkflowOutputBindingSchema,
|
|
153
|
-
version: z.union([
|
|
154
|
-
z.literal(WORKFLOW_GRAPH_VERSION),
|
|
155
|
-
z.literal(LEGACY_WORKFLOW_GRAPH_VERSION)
|
|
156
|
-
]),
|
|
157
|
-
workflow: WorkflowIdentitySchema
|
|
158
|
-
});
|
|
159
|
-
var OPERATION_EFFECT_CLASSES = Object.freeze([
|
|
160
|
-
"pure",
|
|
161
|
-
"local-read",
|
|
162
|
-
"local-derived-write",
|
|
163
|
-
"project-mutation",
|
|
164
|
-
"paid-cloud",
|
|
165
|
-
"live-control"
|
|
166
|
-
]);
|
|
167
|
-
var WORKFLOW_EFFECT_CLASSES = Object.freeze([
|
|
168
|
-
...OPERATION_EFFECT_CLASSES,
|
|
169
|
-
"trusted-code"
|
|
170
|
-
]);
|
|
171
|
-
var OPERATION_RESUME_CLASSES = Object.freeze([
|
|
172
|
-
"deterministic",
|
|
173
|
-
"verified-receipt",
|
|
174
|
-
"recoverable-transaction",
|
|
175
|
-
"ambiguous-after-dispatch",
|
|
176
|
-
"non-resumable-live"
|
|
177
|
-
]);
|
|
178
|
-
var WORKFLOW_RESUME_CLASSES = Object.freeze([
|
|
179
|
-
...OPERATION_RESUME_CLASSES,
|
|
180
|
-
"explicit-code-replay"
|
|
181
|
-
]);
|
|
182
|
-
var OPERATION_PREPARATION_KINDS = Object.freeze([
|
|
183
|
-
"project-state",
|
|
184
|
-
"recording-metadata",
|
|
185
|
-
"screen-capture",
|
|
186
|
-
"camera",
|
|
187
|
-
"microphone",
|
|
188
|
-
"system-audio",
|
|
189
|
-
"typed-text",
|
|
190
|
-
"window-metadata",
|
|
191
|
-
"local-media",
|
|
192
|
-
"provider-options"
|
|
193
|
-
]);
|
|
194
|
-
var OPERATION_LIFECYCLE_KINDS = Object.freeze([
|
|
195
|
-
"pure",
|
|
196
|
-
"local-artifact",
|
|
197
|
-
"project-transaction",
|
|
198
|
-
"paid-dispatch",
|
|
199
|
-
"live-control"
|
|
200
|
-
]);
|
|
201
|
-
var OPERATION_RESOURCE_KINDS = Object.freeze([
|
|
202
|
-
"cpu",
|
|
203
|
-
"local-io",
|
|
204
|
-
"ffmpeg",
|
|
205
|
-
"vision",
|
|
206
|
-
"whisper",
|
|
207
|
-
"network",
|
|
208
|
-
"paid-call",
|
|
209
|
-
"project-render",
|
|
210
|
-
"project-publication",
|
|
211
|
-
"output-publication",
|
|
212
|
-
"capture-device",
|
|
213
|
-
"browser"
|
|
214
|
-
]);
|
|
215
|
-
var OperationResourceClaimSchema = z.strictObject({
|
|
216
|
-
amount: PositiveSafeIntegerSchema,
|
|
217
|
-
resource: z.enum(OPERATION_RESOURCE_KINDS)
|
|
218
|
-
});
|
|
219
|
-
var OperationPolicySchema = z.strictObject({
|
|
220
|
-
cache: z.enum(["none", "exact-run", "content-addressed"]),
|
|
221
|
-
cancellable: z.boolean(),
|
|
222
|
-
effect: z.enum(OPERATION_EFFECT_CLASSES),
|
|
223
|
-
maxDurationMs: PositiveSafeIntegerSchema,
|
|
224
|
-
maxFanOut: NonnegativeSafeIntegerSchema,
|
|
225
|
-
maxInputBytes: NonnegativeSafeIntegerSchema,
|
|
226
|
-
maxOutputBytes: NonnegativeSafeIntegerSchema,
|
|
227
|
-
preparation: z.array(z.enum(OPERATION_PREPARATION_KINDS)).max(OPERATION_PREPARATION_KINDS.length),
|
|
228
|
-
resources: z.array(OperationResourceClaimSchema).max(OPERATION_RESOURCE_KINDS.length),
|
|
229
|
-
resume: z.enum(OPERATION_RESUME_CLASSES)
|
|
230
|
-
});
|
|
231
|
-
var TrustedComputePolicySchema = z.strictObject({
|
|
232
|
-
cache: z.literal("exact-run"),
|
|
233
|
-
cancellable: z.literal(true),
|
|
234
|
-
effect: z.literal("trusted-code"),
|
|
235
|
-
maxDurationMs: PositiveSafeIntegerSchema.max(MAX_TRUSTED_COMPUTE_DURATION_MS),
|
|
236
|
-
maxFanOut: z.literal(0),
|
|
237
|
-
maxInputBytes: PositiveSafeIntegerSchema.max(MAX_TRUSTED_COMPUTE_INPUT_BYTES),
|
|
238
|
-
maxOutputBytes: PositiveSafeIntegerSchema.max(MAX_TRUSTED_COMPUTE_OUTPUT_BYTES),
|
|
239
|
-
preparation: z.tuple([]),
|
|
240
|
-
resources: z.tuple([
|
|
241
|
-
z.strictObject({ amount: z.literal(1), resource: z.literal("cpu") })
|
|
242
|
-
]),
|
|
243
|
-
resume: z.literal("explicit-code-replay")
|
|
244
|
-
});
|
|
245
|
-
var WorkflowNodePolicySchema = z.union([
|
|
246
|
-
OperationPolicySchema,
|
|
247
|
-
TrustedComputePolicySchema
|
|
248
|
-
]);
|
|
249
|
-
function trustedComputePolicy(compute) {
|
|
250
|
-
return TrustedComputePolicySchema.parse({
|
|
251
|
-
cache: "exact-run",
|
|
252
|
-
cancellable: true,
|
|
253
|
-
effect: "trusted-code",
|
|
254
|
-
maxDurationMs: compute.bounds.maxDurationMs,
|
|
255
|
-
maxFanOut: 0,
|
|
256
|
-
maxInputBytes: compute.bounds.maxInputBytes,
|
|
257
|
-
maxOutputBytes: compute.bounds.maxOutputBytes,
|
|
258
|
-
preparation: [],
|
|
259
|
-
resources: [{ amount: 1, resource: "cpu" }],
|
|
260
|
-
resume: "explicit-code-replay"
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
var OperationDiscoverySchema = z.strictObject({
|
|
264
|
-
inputSchemaId: SchemaIdSchema,
|
|
265
|
-
kind: OperationKindSchema,
|
|
266
|
-
lifecycle: z.enum(OPERATION_LIFECYCLE_KINDS),
|
|
267
|
-
outputSchemaId: SchemaIdSchema,
|
|
268
|
-
policy: OperationPolicySchema,
|
|
269
|
-
version: PositiveSafeIntegerSchema
|
|
270
|
-
});
|
|
271
|
-
var WorkflowRegistryProjectionSchema = z.strictObject({
|
|
272
|
-
discovery: z.array(OperationDiscoverySchema).max(MAX_OPERATION_DISCOVERY_ENTRIES),
|
|
273
|
-
id: SchemaIdSchema,
|
|
274
|
-
projectionSha256: Sha256Schema,
|
|
275
|
-
trustedCompute: z.boolean()
|
|
276
|
-
});
|
|
277
|
-
var GraphCompilerLimitsSchema = z.strictObject({
|
|
278
|
-
maxDepth: PositiveSafeIntegerSchema,
|
|
279
|
-
maxEdges: NonnegativeSafeIntegerSchema,
|
|
280
|
-
maxFanOut: NonnegativeSafeIntegerSchema,
|
|
281
|
-
maxNodes: PositiveSafeIntegerSchema.max(MAX_SERIALIZED_GRAPH_NODES),
|
|
282
|
-
maxTotalOperationFanOut: NonnegativeSafeIntegerSchema
|
|
283
|
-
});
|
|
284
|
-
var UNRESOLVED_REQUIREMENT_KINDS = Object.freeze([
|
|
285
|
-
"dependency-outputs",
|
|
286
|
-
"exact-media-hashes",
|
|
287
|
-
"exact-sensitive-metadata-hashes",
|
|
288
|
-
"prices",
|
|
289
|
-
"project-generations",
|
|
290
|
-
"render-plans"
|
|
291
|
-
]);
|
|
292
|
-
var RequirementEnvelopeBoundsSchema = z.strictObject({
|
|
293
|
-
depth: NonnegativeSafeIntegerSchema,
|
|
294
|
-
edges: NonnegativeSafeIntegerSchema,
|
|
295
|
-
localMediaUploadNodes: NonnegativeSafeIntegerSchema,
|
|
296
|
-
maxDurationMs: NonnegativeSafeIntegerSchema,
|
|
297
|
-
maxInputBytes: NonnegativeSafeIntegerSchema,
|
|
298
|
-
maxOutputBytes: NonnegativeSafeIntegerSchema,
|
|
299
|
-
nodes: NonnegativeSafeIntegerSchema,
|
|
300
|
-
paidCallClaims: NonnegativeSafeIntegerSchema,
|
|
301
|
-
structuralFanOut: NonnegativeSafeIntegerSchema,
|
|
302
|
-
totalOperationFanOut: NonnegativeSafeIntegerSchema
|
|
303
|
-
});
|
|
304
|
-
var RequirementEnvelopeSchema = z.strictObject({
|
|
305
|
-
bounds: RequirementEnvelopeBoundsSchema,
|
|
306
|
-
computeKeys: z.array(ComputeKeySchema).max(MAX_SERIALIZED_GRAPH_NODES),
|
|
307
|
-
effects: z.array(z.enum(WORKFLOW_EFFECT_CLASSES)).max(WORKFLOW_EFFECT_CLASSES.length),
|
|
308
|
-
operationFamilies: z.array(NodeKeySegmentSchema).max(MAX_SERIALIZED_GRAPH_NODES),
|
|
309
|
-
operationKinds: z.array(OperationKindSchema).max(MAX_SERIALIZED_GRAPH_NODES),
|
|
310
|
-
preparation: z.array(z.enum(OPERATION_PREPARATION_KINDS)).max(OPERATION_PREPARATION_KINDS.length),
|
|
311
|
-
resources: z.array(OperationResourceClaimSchema).max(OPERATION_RESOURCE_KINDS.length),
|
|
312
|
-
resumeClasses: z.array(z.enum(WORKFLOW_RESUME_CLASSES)).max(WORKFLOW_RESUME_CLASSES.length),
|
|
313
|
-
unresolved: z.array(z.enum(UNRESOLVED_REQUIREMENT_KINDS)).max(UNRESOLVED_REQUIREMENT_KINDS.length),
|
|
314
|
-
version: z.union([
|
|
315
|
-
z.literal(REQUIREMENT_ENVELOPE_VERSION),
|
|
316
|
-
z.literal(LEGACY_REQUIREMENT_ENVELOPE_VERSION)
|
|
317
|
-
])
|
|
318
|
-
});
|
|
319
|
-
var CompiledWorkflowGraphSchema = z.strictObject({
|
|
320
|
-
compilationSha256: Sha256Schema,
|
|
321
|
-
envelope: RequirementEnvelopeSchema,
|
|
322
|
-
graph: AuthoredWorkflowGraphV1Schema,
|
|
323
|
-
graphSha256: Sha256Schema,
|
|
324
|
-
limits: GraphCompilerLimitsSchema,
|
|
325
|
-
projection: WorkflowRegistryProjectionSchema,
|
|
326
|
-
topologicalWaves: z.array(z.array(NodeKeySchema).min(1)).max(MAX_SERIALIZED_GRAPH_NODES),
|
|
327
|
-
version: z.literal(WORKFLOW_COMPILATION_VERSION)
|
|
328
|
-
});
|
|
329
|
-
var TRUSTED_COMPUTE_BRAND = Symbol.for("slopcamera.trusted-compute-definition");
|
|
330
|
-
var LEGACY_TRUSTED_COMPUTE_BRAND = Symbol.for("studio.trusted-compute-definition");
|
|
331
|
-
var WORKFLOW_REF_BRAND = Symbol.for("slopcamera.workflow-ref");
|
|
332
|
-
|
|
333
|
-
// src/code/public-operations.ts
|
|
334
|
-
import { z as z2 } from "zod";
|
|
335
|
-
var MAX_PATH_CHARACTERS = 4096;
|
|
336
|
-
var MAX_PROMPT_BYTES = 32 * 1024;
|
|
337
|
-
var MAX_GENERATED_IMAGE_BYTES = 64 * 1024 * 1024;
|
|
338
|
-
var MAX_VECTOR_INPUT_BYTES = 16 * 1024 * 1024;
|
|
339
|
-
var MAX_VECTOR_OUTPUT_BYTES = 2000000;
|
|
340
|
-
var MAX_DIAGRAM_ARTIFACT_BYTES = 64 * 1024 * 1024;
|
|
341
|
-
var BoundedPathSchema = z2.string().min(1).max(MAX_PATH_CHARACTERS).refine((value) => !value.includes("\x00"), "Paths must not contain NUL bytes.");
|
|
342
|
-
var Sha256Schema2 = z2.string().regex(/^[a-f0-9]{64}$/u);
|
|
343
|
-
var BoundedVersionStringSchema = z2.string().min(1).max(256);
|
|
344
|
-
var NonnegativeSafeIntegerSchema2 = z2.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
345
|
-
var PositiveSafeIntegerSchema2 = z2.number().int().positive().max(Number.MAX_SAFE_INTEGER);
|
|
346
|
-
function schemaWithReadonlyOutput(schema) {
|
|
347
|
-
return schema;
|
|
348
|
-
}
|
|
349
|
-
var SlopcameraImageModelSchema = z2.string().min(3).max(256).regex(/^[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._:-]*$/iu);
|
|
350
|
-
var SlopcameraDiagramCheckInputSchema = z2.strictObject({
|
|
351
|
-
path: BoundedPathSchema
|
|
352
|
-
});
|
|
353
|
-
var SlopcameraDiagramRenderInputSchema = schemaWithReadonlyOutput(z2.strictObject({
|
|
354
|
-
outDirectory: BoundedPathSchema.optional(),
|
|
355
|
-
path: BoundedPathSchema,
|
|
356
|
-
scale: z2.number().finite().positive().max(4).optional()
|
|
357
|
-
}));
|
|
358
|
-
var SlopcameraImageVectorizeInputSchema = schemaWithReadonlyOutput(z2.strictObject({
|
|
359
|
-
alphaCutoff: z2.number().int().min(1).max(64).optional(),
|
|
360
|
-
duotone: z2.tuple([
|
|
361
|
-
z2.string().regex(/^#[a-f0-9]{3}(?:[a-f0-9]{3})?$/iu),
|
|
362
|
-
z2.string().regex(/^#[a-f0-9]{3}(?:[a-f0-9]{3})?$/iu)
|
|
363
|
-
]).optional(),
|
|
364
|
-
inputPath: BoundedPathSchema,
|
|
365
|
-
outputPath: BoundedPathSchema.refine((value) => value.toLowerCase().endsWith(".svg"), "Vector output paths must end in .svg."),
|
|
366
|
-
timeoutMs: z2.number().int().min(1).max(300000).optional()
|
|
367
|
-
}));
|
|
368
|
-
var PromptSchema = z2.string().superRefine((value, context) => {
|
|
369
|
-
if (utf8ByteLength(value, MAX_PROMPT_BYTES) === undefined) {
|
|
370
|
-
context.addIssue({
|
|
371
|
-
code: "custom",
|
|
372
|
-
message: `Prompts must contain at most ${String(MAX_PROMPT_BYTES)} UTF-8 bytes.`
|
|
373
|
-
});
|
|
374
|
-
return;
|
|
375
|
-
}
|
|
376
|
-
if (value.trim().length === 0) {
|
|
377
|
-
context.addIssue({ code: "custom", message: "Prompts must not be blank." });
|
|
378
|
-
return;
|
|
379
|
-
}
|
|
380
|
-
if (/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/u.test(value)) {
|
|
381
|
-
context.addIssue({
|
|
382
|
-
code: "custom",
|
|
383
|
-
message: "Prompts must not contain control characters."
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
});
|
|
387
|
-
var SlopcameraImageGenerateInputSchema = schemaWithReadonlyOutput(z2.strictObject({
|
|
388
|
-
model: SlopcameraImageModelSchema,
|
|
389
|
-
outputPath: BoundedPathSchema.refine((value) => /\.(?:jpe?g|png|webp)$/iu.test(value), "Generated image output paths must end in .png, .jpg, .jpeg, or .webp."),
|
|
390
|
-
prompt: PromptSchema
|
|
391
|
-
}));
|
|
392
|
-
var SlopcameraLintFindingSchema = z2.strictObject({
|
|
393
|
-
code: z2.string().min(1).max(160),
|
|
394
|
-
message: z2.string().min(1).max(4096),
|
|
395
|
-
shapeIds: z2.array(z2.string().min(1).max(256)).max(4096)
|
|
396
|
-
});
|
|
397
|
-
var SlopcameraDiagramCheckOutputSchema = z2.strictObject({
|
|
398
|
-
configPath: z2.null(),
|
|
399
|
-
findings: z2.array(SlopcameraLintFindingSchema).max(4096)
|
|
400
|
-
});
|
|
401
|
-
var SlopcameraRenderArtifactsSchema = z2.strictObject({
|
|
402
|
-
darkPng: BoundedPathSchema,
|
|
403
|
-
darkSvg: BoundedPathSchema,
|
|
404
|
-
lightPng: BoundedPathSchema,
|
|
405
|
-
lightSvg: BoundedPathSchema,
|
|
406
|
-
spec: BoundedPathSchema,
|
|
407
|
-
tldr: BoundedPathSchema
|
|
408
|
-
});
|
|
409
|
-
var SlopcameraDiagramRenderOutputSchema = z2.strictObject({
|
|
410
|
-
artifacts: SlopcameraRenderArtifactsSchema,
|
|
411
|
-
configPath: z2.null(),
|
|
412
|
-
findings: z2.array(SlopcameraLintFindingSchema).max(4096)
|
|
413
|
-
});
|
|
414
|
-
var SlopcameraVectorizeQualityReceiptSchema = z2.strictObject({
|
|
415
|
-
alphaRmse: z2.number().finite().nonnegative(),
|
|
416
|
-
colorRmse: z2.number().finite().nonnegative(),
|
|
417
|
-
outsideAlphaRatio: z2.number().finite().min(0).max(1),
|
|
418
|
-
sampleHeight: PositiveSafeIntegerSchema2,
|
|
419
|
-
sampleWidth: PositiveSafeIntegerSchema2,
|
|
420
|
-
supportRecall: z2.number().finite().min(0).max(1)
|
|
421
|
-
});
|
|
422
|
-
var SlopcameraVectorizeProvenanceSchema = z2.strictObject({
|
|
423
|
-
arch: BoundedVersionStringSchema,
|
|
424
|
-
platform: BoundedVersionStringSchema,
|
|
425
|
-
sharp: BoundedVersionStringSchema,
|
|
426
|
-
sharpVersions: z2.record(z2.string().min(1).max(128), BoundedVersionStringSchema),
|
|
427
|
-
vips: BoundedVersionStringSchema,
|
|
428
|
-
vtracerSha256: Sha256Schema2,
|
|
429
|
-
vtracerSource: z2.enum(["official-release", "override"]),
|
|
430
|
-
vtracerVersion: BoundedVersionStringSchema
|
|
431
|
-
});
|
|
432
|
-
var SlopcameraVectorizeReceiptSchema = z2.strictObject({
|
|
433
|
-
alphaCutoff: z2.number().int().min(1).max(64),
|
|
434
|
-
bytes: NonnegativeSafeIntegerSchema2.max(MAX_VECTOR_OUTPUT_BYTES),
|
|
435
|
-
candidatesEvaluated: PositiveSafeIntegerSchema2,
|
|
436
|
-
format: z2.string().min(1).max(80),
|
|
437
|
-
height: PositiveSafeIntegerSchema2.max(4096),
|
|
438
|
-
inputBytes: PositiveSafeIntegerSchema2.max(MAX_VECTOR_INPUT_BYTES),
|
|
439
|
-
outputMode: z2.enum(["color", "duotone"]),
|
|
440
|
-
pathCount: NonnegativeSafeIntegerSchema2.max(12000),
|
|
441
|
-
profile: z2.enum(["balanced", "detailed", "photo"]),
|
|
442
|
-
provenance: SlopcameraVectorizeProvenanceSchema,
|
|
443
|
-
quality: SlopcameraVectorizeQualityReceiptSchema,
|
|
444
|
-
receiptVersion: z2.literal(1),
|
|
445
|
-
representation: z2.enum(["color-paths", "alpha-mask"]),
|
|
446
|
-
sourceSha256: Sha256Schema2,
|
|
447
|
-
svgSha256: Sha256Schema2,
|
|
448
|
-
width: PositiveSafeIntegerSchema2.max(4096)
|
|
449
|
-
});
|
|
450
|
-
var SlopcameraImageVectorizeOutputSchema = z2.strictObject({
|
|
451
|
-
outputPath: BoundedPathSchema,
|
|
452
|
-
receipt: SlopcameraVectorizeReceiptSchema
|
|
453
|
-
});
|
|
454
|
-
var SlopcameraImageGenerateOutputSchema = z2.strictObject({
|
|
455
|
-
bytes: PositiveSafeIntegerSchema2.max(MAX_GENERATED_IMAGE_BYTES),
|
|
456
|
-
mediaType: z2.enum(["image/jpeg", "image/png", "image/webp"]),
|
|
457
|
-
model: SlopcameraImageModelSchema,
|
|
458
|
-
outputPath: BoundedPathSchema,
|
|
459
|
-
provider: z2.literal("vercel-ai-gateway"),
|
|
460
|
-
requestId: z2.string().min(1).max(256).refine((value) => !/[\u0000-\u001f\u007f]/u.test(value), "Request ids must not contain control characters."),
|
|
461
|
-
sha256: Sha256Schema2,
|
|
462
|
-
warnings: z2.array(z2.string().min(1).max(256)).max(100)
|
|
463
|
-
});
|
|
464
|
-
var PORTABLE_SLOPCAMERA_OPERATION_KINDS = Object.freeze([
|
|
465
|
-
"slopcamera.diagram.check",
|
|
466
|
-
"slopcamera.diagram.render",
|
|
467
|
-
"slopcamera.image.generate",
|
|
468
|
-
"slopcamera.image.vectorize"
|
|
469
|
-
]);
|
|
470
|
-
function freezePolicy(policy) {
|
|
471
|
-
const preparation = Object.freeze([...policy.preparation]);
|
|
472
|
-
const resources = Object.freeze(policy.resources.map((claim) => Object.freeze({ ...claim })));
|
|
473
|
-
return Object.freeze({ ...policy, preparation, resources });
|
|
474
|
-
}
|
|
475
|
-
function portableContract(contract) {
|
|
476
|
-
return Object.freeze({ ...contract, policy: freezePolicy(contract.policy) });
|
|
477
|
-
}
|
|
478
|
-
var PORTABLE_SLOPCAMERA_OPERATION_CONTRACTS = Object.freeze({
|
|
479
|
-
"slopcamera.diagram.check": portableContract({
|
|
480
|
-
inputSchema: SlopcameraDiagramCheckInputSchema,
|
|
481
|
-
inputSchemaId: "slopcamera.operation.diagram.check.input/v2",
|
|
482
|
-
kind: "slopcamera.diagram.check",
|
|
483
|
-
lifecycle: "pure",
|
|
484
|
-
outputSchema: SlopcameraDiagramCheckOutputSchema,
|
|
485
|
-
outputSchemaId: "slopcamera.operation.diagram.check.output/v2",
|
|
486
|
-
policy: {
|
|
487
|
-
cache: "content-addressed",
|
|
488
|
-
cancellable: false,
|
|
489
|
-
effect: "local-read",
|
|
490
|
-
maxDurationMs: 30000,
|
|
491
|
-
maxFanOut: 0,
|
|
492
|
-
maxInputBytes: 4096,
|
|
493
|
-
maxOutputBytes: 256 * 1024,
|
|
494
|
-
preparation: ["local-media"],
|
|
495
|
-
resources: [
|
|
496
|
-
{ amount: 1, resource: "cpu" },
|
|
497
|
-
{ amount: 1, resource: "local-io" }
|
|
498
|
-
],
|
|
499
|
-
resume: "deterministic"
|
|
500
|
-
},
|
|
501
|
-
version: 2
|
|
502
|
-
}),
|
|
503
|
-
"slopcamera.diagram.render": portableContract({
|
|
504
|
-
inputSchema: SlopcameraDiagramRenderInputSchema,
|
|
505
|
-
inputSchemaId: "slopcamera.operation.diagram.render.input/v2",
|
|
506
|
-
kind: "slopcamera.diagram.render",
|
|
507
|
-
lifecycle: "local-artifact",
|
|
508
|
-
outputSchema: SlopcameraDiagramRenderOutputSchema,
|
|
509
|
-
outputSchemaId: "slopcamera.operation.diagram.render.output/v2",
|
|
510
|
-
policy: {
|
|
511
|
-
cache: "none",
|
|
512
|
-
cancellable: false,
|
|
513
|
-
effect: "local-derived-write",
|
|
514
|
-
maxDurationMs: 120000,
|
|
515
|
-
maxFanOut: 5,
|
|
516
|
-
maxInputBytes: 8192,
|
|
517
|
-
maxOutputBytes: 5 * MAX_DIAGRAM_ARTIFACT_BYTES,
|
|
518
|
-
preparation: ["local-media"],
|
|
519
|
-
resources: [
|
|
520
|
-
{ amount: 1, resource: "cpu" },
|
|
521
|
-
{ amount: 1, resource: "local-io" }
|
|
522
|
-
],
|
|
523
|
-
resume: "ambiguous-after-dispatch"
|
|
524
|
-
},
|
|
525
|
-
version: 2
|
|
526
|
-
}),
|
|
527
|
-
"slopcamera.image.generate": portableContract({
|
|
528
|
-
inputSchema: SlopcameraImageGenerateInputSchema,
|
|
529
|
-
inputSchemaId: "slopcamera.operation.image.generate.input/v2",
|
|
530
|
-
kind: "slopcamera.image.generate",
|
|
531
|
-
lifecycle: "paid-dispatch",
|
|
532
|
-
outputSchema: SlopcameraImageGenerateOutputSchema,
|
|
533
|
-
outputSchemaId: "slopcamera.operation.image.generate.output/v2",
|
|
534
|
-
policy: {
|
|
535
|
-
cache: "exact-run",
|
|
536
|
-
cancellable: false,
|
|
537
|
-
effect: "paid-cloud",
|
|
538
|
-
maxDurationMs: 120000,
|
|
539
|
-
maxFanOut: 1,
|
|
540
|
-
maxInputBytes: 16 * 1024,
|
|
541
|
-
maxOutputBytes: MAX_GENERATED_IMAGE_BYTES,
|
|
542
|
-
preparation: ["provider-options"],
|
|
543
|
-
resources: [
|
|
544
|
-
{ amount: 1, resource: "local-io" },
|
|
545
|
-
{ amount: 1, resource: "network" },
|
|
546
|
-
{ amount: 1, resource: "paid-call" }
|
|
547
|
-
],
|
|
548
|
-
resume: "ambiguous-after-dispatch"
|
|
549
|
-
},
|
|
550
|
-
version: 2
|
|
551
|
-
}),
|
|
552
|
-
"slopcamera.image.vectorize": portableContract({
|
|
553
|
-
inputSchema: SlopcameraImageVectorizeInputSchema,
|
|
554
|
-
inputSchemaId: "slopcamera.operation.image.vectorize.input/v2",
|
|
555
|
-
kind: "slopcamera.image.vectorize",
|
|
556
|
-
lifecycle: "local-artifact",
|
|
557
|
-
outputSchema: SlopcameraImageVectorizeOutputSchema,
|
|
558
|
-
outputSchemaId: "slopcamera.operation.image.vectorize.output/v2",
|
|
559
|
-
policy: {
|
|
560
|
-
cache: "none",
|
|
561
|
-
cancellable: false,
|
|
562
|
-
effect: "local-derived-write",
|
|
563
|
-
maxDurationMs: 300000,
|
|
564
|
-
maxFanOut: 1,
|
|
565
|
-
maxInputBytes: MAX_VECTOR_INPUT_BYTES,
|
|
566
|
-
maxOutputBytes: MAX_VECTOR_OUTPUT_BYTES,
|
|
567
|
-
preparation: ["local-media"],
|
|
568
|
-
resources: [
|
|
569
|
-
{ amount: 1, resource: "cpu" },
|
|
570
|
-
{ amount: 1, resource: "local-io" }
|
|
571
|
-
],
|
|
572
|
-
resume: "ambiguous-after-dispatch"
|
|
573
|
-
},
|
|
574
|
-
version: 2
|
|
575
|
-
})
|
|
576
|
-
});
|
|
577
|
-
function isPortableSlopcameraOperationKind(value) {
|
|
578
|
-
return PORTABLE_SLOPCAMERA_OPERATION_KINDS.includes(value);
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// src/code/boundary.ts
|
|
582
|
-
function parseCodeBoundary(schema, input, name) {
|
|
583
|
-
const result = schema.safeParse(input);
|
|
584
|
-
if (!result.success) {
|
|
585
|
-
throw new SlopcameraCodeError("invalid-data", `Invalid ${name}.`, {
|
|
586
|
-
issues: result.error.issues.map((issue) => ({
|
|
587
|
-
code: issue.code,
|
|
588
|
-
message: issue.message,
|
|
589
|
-
path: issue.path.map(String)
|
|
590
|
-
}))
|
|
591
|
-
});
|
|
592
|
-
}
|
|
593
|
-
return result.data;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// src/code/projection.ts
|
|
597
|
-
var WORKFLOW_REGISTRY_PROJECTION_HASH_DOMAIN = "slopcamera.workflow.registry-projection/v1";
|
|
598
|
-
var PUBLIC_WORKFLOW_REGISTRY_PROJECTION_ID = "slopcamera.workflow.registry.public/v1";
|
|
599
|
-
var OWNED_NORMALIZED_PROJECTIONS = new WeakSet;
|
|
600
|
-
var MAX_OPERATION_DISCOVERY_VALUES = 17 + OPERATION_PREPARATION_KINDS.length + 3 * OPERATION_RESOURCE_KINDS.length;
|
|
601
|
-
var MAX_OPERATION_DISCOVERY_LIST_VALUES = 1 + MAX_OPERATION_DISCOVERY_ENTRIES * MAX_OPERATION_DISCOVERY_VALUES;
|
|
602
|
-
var MAX_OPERATION_DISCOVERY_LIST_BYTES = 32 * 1024 * 1024;
|
|
603
|
-
var MAX_OPERATION_DISCOVERY_LIST_DEPTH = 8;
|
|
604
|
-
var MAX_WORKFLOW_REGISTRY_PROJECTION_BYTES = MAX_OPERATION_DISCOVERY_LIST_BYTES + 4096;
|
|
605
|
-
var MAX_WORKFLOW_REGISTRY_PROJECTION_DEPTH = MAX_OPERATION_DISCOVERY_LIST_DEPTH + 1;
|
|
606
|
-
var MAX_WORKFLOW_REGISTRY_PROJECTION_VALUES = MAX_OPERATION_DISCOVERY_LIST_VALUES + 5;
|
|
607
|
-
function discoveryList(source) {
|
|
608
|
-
return Array.isArray(source) ? source : source.list();
|
|
609
|
-
}
|
|
610
|
-
function boundedOperationDiscoveryList(input, name = "operation discovery list") {
|
|
611
|
-
if (!Array.isArray(input)) {
|
|
612
|
-
throw new SlopcameraCodeError("invalid-data", `${name} must be an array.`);
|
|
613
|
-
}
|
|
614
|
-
const length = input.length;
|
|
615
|
-
if (length > MAX_OPERATION_DISCOVERY_ENTRIES) {
|
|
616
|
-
throw new SlopcameraCodeError("invalid-data", `${name} cannot exceed ${String(MAX_OPERATION_DISCOVERY_ENTRIES)} entries.`);
|
|
617
|
-
}
|
|
618
|
-
const descriptors = Object.getOwnPropertyDescriptors(input);
|
|
619
|
-
if (Object.getOwnPropertySymbols(descriptors).some((symbol) => Reflect.get(descriptors, symbol)?.enumerable === true)) {
|
|
620
|
-
throw new SlopcameraCodeError("invalid-data", `${name} cannot contain enumerable symbol properties.`);
|
|
621
|
-
}
|
|
622
|
-
const keys = Object.keys(descriptors).filter((key) => descriptors[key]?.enumerable === true);
|
|
623
|
-
if (keys.length !== length || keys.some((key, index) => key !== String(index))) {
|
|
624
|
-
throw new SlopcameraCodeError("invalid-data", `${name} must be dense and cannot have named properties.`);
|
|
625
|
-
}
|
|
626
|
-
const punctuationBytes = 2 + Math.max(0, length - 1);
|
|
627
|
-
let bytes = punctuationBytes;
|
|
628
|
-
let values = 1;
|
|
629
|
-
const captured = [];
|
|
630
|
-
for (let index = 0;index < length; index += 1) {
|
|
631
|
-
const descriptor = descriptors[String(index)];
|
|
632
|
-
if (descriptor === undefined || descriptor.get !== undefined || descriptor.set !== undefined) {
|
|
633
|
-
throw new SlopcameraCodeError("invalid-data", `${name} must contain plain data elements.`);
|
|
634
|
-
}
|
|
635
|
-
const remainingBytes = MAX_OPERATION_DISCOVERY_LIST_BYTES - bytes;
|
|
636
|
-
if (remainingBytes < 1) {
|
|
637
|
-
throw new SlopcameraCodeError("invalid-data", `${name} contains more than ${String(MAX_OPERATION_DISCOVERY_LIST_BYTES)} bytes.`);
|
|
638
|
-
}
|
|
639
|
-
const snapshot = createBoundedJsonValueSnapshot(descriptor.value, remainingBytes, `${name} entry ${String(index)}`, {
|
|
640
|
-
maximumDepth: MAX_OPERATION_DISCOVERY_LIST_DEPTH - 1,
|
|
641
|
-
maximumValues: MAX_OPERATION_DISCOVERY_VALUES
|
|
642
|
-
});
|
|
643
|
-
bytes += snapshot.bytes;
|
|
644
|
-
values += snapshot.values;
|
|
645
|
-
if (values > MAX_OPERATION_DISCOVERY_LIST_VALUES) {
|
|
646
|
-
throw new SlopcameraCodeError("invalid-data", `${name} contains more than ${String(MAX_OPERATION_DISCOVERY_LIST_VALUES)} JSON values.`);
|
|
647
|
-
}
|
|
648
|
-
captured.push(snapshot.value);
|
|
649
|
-
}
|
|
650
|
-
return Object.freeze(captured);
|
|
651
|
-
}
|
|
652
|
-
function operationKey(kind, version) {
|
|
653
|
-
return `${kind}@${String(version)}`;
|
|
654
|
-
}
|
|
655
|
-
function uniqueSorted(values) {
|
|
656
|
-
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
657
|
-
}
|
|
658
|
-
function canonicalSlopcameraIdentity(value) {
|
|
659
|
-
if (value === "studio")
|
|
660
|
-
return "slopcamera";
|
|
661
|
-
return value.replace(/^studio\./u, "slopcamera.");
|
|
662
|
-
}
|
|
663
|
-
function normalizeOperationDiscoveryPreservingIdentity(input) {
|
|
664
|
-
const normalized = boundedOperationDiscoveryList(input).map((item) => {
|
|
665
|
-
const parsed = parseCodeBoundary(OperationDiscoverySchema, item, "operation discovery entry");
|
|
666
|
-
const preparation = uniqueSorted(parsed.policy.preparation);
|
|
667
|
-
if (preparation.length !== parsed.policy.preparation.length) {
|
|
668
|
-
throw new SlopcameraCodeError("invalid-data", `Duplicate preparation requirement for ${operationKey(parsed.kind, parsed.version)}.`, { kind: parsed.kind, version: parsed.version });
|
|
669
|
-
}
|
|
670
|
-
const resources = [...parsed.policy.resources].sort((left, right) => left.resource.localeCompare(right.resource));
|
|
671
|
-
if (new Set(resources.map((resource) => resource.resource)).size !== resources.length) {
|
|
672
|
-
throw new SlopcameraCodeError("invalid-data", `Duplicate resource claim for ${operationKey(parsed.kind, parsed.version)}.`, { kind: parsed.kind, version: parsed.version });
|
|
673
|
-
}
|
|
674
|
-
return parseCodeBoundary(OperationDiscoverySchema, {
|
|
675
|
-
...parsed,
|
|
676
|
-
policy: { ...parsed.policy, preparation, resources }
|
|
677
|
-
}, "normalized operation discovery entry");
|
|
678
|
-
}).sort((left, right) => left.kind.localeCompare(right.kind) || left.version - right.version);
|
|
679
|
-
const seen = new Set;
|
|
680
|
-
for (const operation of normalized) {
|
|
681
|
-
const key = operationKey(operation.kind, operation.version);
|
|
682
|
-
if (seen.has(key)) {
|
|
683
|
-
throw new SlopcameraCodeError("conflict", `Duplicate operation discovery entry: ${key}`, { kind: operation.kind, version: operation.version });
|
|
684
|
-
}
|
|
685
|
-
seen.add(key);
|
|
686
|
-
}
|
|
687
|
-
return normalized;
|
|
688
|
-
}
|
|
689
|
-
function normalizeOperationDiscovery(input) {
|
|
690
|
-
return normalizeOperationDiscoveryPreservingIdentity(input).map((operation) => parseCodeBoundary(OperationDiscoverySchema, {
|
|
691
|
-
...operation,
|
|
692
|
-
inputSchemaId: canonicalSlopcameraIdentity(operation.inputSchemaId),
|
|
693
|
-
kind: canonicalSlopcameraIdentity(operation.kind),
|
|
694
|
-
outputSchemaId: canonicalSlopcameraIdentity(operation.outputSchemaId)
|
|
695
|
-
}, "canonical operation discovery entry"));
|
|
696
|
-
}
|
|
697
|
-
function freezeDiscovery(discovery) {
|
|
698
|
-
return Object.freeze(discovery.map((operation) => Object.freeze({
|
|
699
|
-
...operation,
|
|
700
|
-
policy: Object.freeze({
|
|
701
|
-
...operation.policy,
|
|
702
|
-
preparation: Object.freeze([...operation.policy.preparation]),
|
|
703
|
-
resources: Object.freeze(operation.policy.resources.map((resource) => Object.freeze({ ...resource })))
|
|
704
|
-
})
|
|
705
|
-
})));
|
|
706
|
-
}
|
|
707
|
-
function createWorkflowRegistryProjectionHash(input) {
|
|
708
|
-
const id = canonicalSlopcameraIdentity(parseCodeBoundary(SchemaIdSchema, input.id, "registry projection id"));
|
|
709
|
-
const discovery = normalizeOperationDiscovery(input.discovery);
|
|
710
|
-
const trustedCompute = input.trustedCompute ?? false;
|
|
711
|
-
return workflowRegistryProjectionHashFromNormalized({
|
|
712
|
-
discovery,
|
|
713
|
-
id,
|
|
714
|
-
trustedCompute
|
|
715
|
-
});
|
|
716
|
-
}
|
|
717
|
-
function workflowRegistryProjectionHashFromNormalized(input, domain = WORKFLOW_REGISTRY_PROJECTION_HASH_DOMAIN) {
|
|
718
|
-
return canonicalJsonSha256Prefixed(`${domain}\x00`, {
|
|
719
|
-
discovery: input.discovery,
|
|
720
|
-
id: input.id,
|
|
721
|
-
trustedCompute: input.trustedCompute
|
|
722
|
-
});
|
|
723
|
-
}
|
|
724
|
-
function createWorkflowRegistryProjection(idInput, source, options = {}) {
|
|
725
|
-
const id = canonicalSlopcameraIdentity(parseCodeBoundary(SchemaIdSchema, idInput, "registry projection id"));
|
|
726
|
-
const discovery = normalizeOperationDiscovery(discoveryList(source));
|
|
727
|
-
const trustedCompute = options.trustedCompute ?? false;
|
|
728
|
-
const parsed = parseCodeBoundary(WorkflowRegistryProjectionSchema, {
|
|
729
|
-
discovery,
|
|
730
|
-
id,
|
|
731
|
-
projectionSha256: workflowRegistryProjectionHashFromNormalized({
|
|
732
|
-
discovery,
|
|
733
|
-
id,
|
|
734
|
-
trustedCompute
|
|
735
|
-
}),
|
|
736
|
-
trustedCompute
|
|
737
|
-
}, "workflow registry projection");
|
|
738
|
-
const projection = Object.freeze({
|
|
739
|
-
...parsed,
|
|
740
|
-
discovery: freezeDiscovery(parsed.discovery)
|
|
741
|
-
});
|
|
742
|
-
OWNED_NORMALIZED_PROJECTIONS.add(projection);
|
|
743
|
-
return projection;
|
|
744
|
-
}
|
|
745
|
-
function parseWorkflowRegistryProjection(input) {
|
|
746
|
-
if (typeof input === "object" && input !== null && OWNED_NORMALIZED_PROJECTIONS.has(input)) {
|
|
747
|
-
return input;
|
|
748
|
-
}
|
|
749
|
-
const captured = createBoundedJsonValueSnapshot(input, MAX_WORKFLOW_REGISTRY_PROJECTION_BYTES, "workflow registry projection", {
|
|
750
|
-
maximumDepth: MAX_WORKFLOW_REGISTRY_PROJECTION_DEPTH,
|
|
751
|
-
maximumValues: MAX_WORKFLOW_REGISTRY_PROJECTION_VALUES
|
|
752
|
-
}).value;
|
|
753
|
-
const parsed = parseCodeBoundary(WorkflowRegistryProjectionSchema, captured, "workflow registry projection");
|
|
754
|
-
const exactDiscovery = normalizeOperationDiscoveryPreservingIdentity(parsed.discovery);
|
|
755
|
-
const exactIdentity = {
|
|
756
|
-
discovery: exactDiscovery,
|
|
757
|
-
id: parsed.id,
|
|
758
|
-
trustedCompute: parsed.trustedCompute
|
|
759
|
-
};
|
|
760
|
-
const expectedProjectionSha256 = workflowRegistryProjectionHashFromNormalized(exactIdentity);
|
|
761
|
-
if (parsed.projectionSha256 !== expectedProjectionSha256) {
|
|
762
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow registry projection hash does not match its contents.", {
|
|
763
|
-
actualProjectionSha256: parsed.projectionSha256,
|
|
764
|
-
expectedProjectionSha256,
|
|
765
|
-
projectionId: parsed.id
|
|
766
|
-
});
|
|
767
|
-
}
|
|
768
|
-
if (canonicalJsonSha256(parsed.discovery) !== canonicalJsonSha256(exactDiscovery)) {
|
|
769
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow registry projection discovery is not normalized.", { projectionId: parsed.id });
|
|
770
|
-
}
|
|
771
|
-
return createWorkflowRegistryProjection(parsed.id, exactDiscovery, { trustedCompute: parsed.trustedCompute });
|
|
772
|
-
}
|
|
773
|
-
function publicDiscovery() {
|
|
774
|
-
return PORTABLE_SLOPCAMERA_OPERATION_KINDS.map((kind) => {
|
|
775
|
-
const contract = PORTABLE_SLOPCAMERA_OPERATION_CONTRACTS[kind];
|
|
776
|
-
return {
|
|
777
|
-
inputSchemaId: contract.inputSchemaId,
|
|
778
|
-
kind: contract.kind,
|
|
779
|
-
lifecycle: contract.lifecycle,
|
|
780
|
-
outputSchemaId: contract.outputSchemaId,
|
|
781
|
-
policy: contract.policy,
|
|
782
|
-
version: contract.version
|
|
783
|
-
};
|
|
784
|
-
});
|
|
785
|
-
}
|
|
786
|
-
function createPublicWorkflowRegistryProjection() {
|
|
787
|
-
return createWorkflowRegistryProjection(PUBLIC_WORKFLOW_REGISTRY_PROJECTION_ID, publicDiscovery(), { trustedCompute: false });
|
|
788
|
-
}
|
|
789
|
-
var PUBLIC_WORKFLOW_REGISTRY_PROJECTION = createPublicWorkflowRegistryProjection();
|
|
790
|
-
var PUBLIC_SLOPCAMERA_WORKFLOW_PROJECTION = PUBLIC_WORKFLOW_REGISTRY_PROJECTION;
|
|
791
|
-
|
|
792
|
-
// src/code/compiler.ts
|
|
793
|
-
import { z as z3 } from "zod";
|
|
794
|
-
var WORKFLOW_GRAPH_HASH_DOMAIN = "slopcamera.workflow.graph/v1";
|
|
795
|
-
var WORKFLOW_COMPILATION_HASH_DOMAIN = "slopcamera.workflow.compilation/v1";
|
|
796
|
-
var DEFAULT_GRAPH_COMPILER_LIMITS = Object.freeze({
|
|
797
|
-
maxDepth: 64,
|
|
798
|
-
maxEdges: 2048,
|
|
799
|
-
maxFanOut: 64,
|
|
800
|
-
maxNodes: 256,
|
|
801
|
-
maxTotalOperationFanOut: 4096
|
|
802
|
-
});
|
|
803
|
-
var MAX_SERIALIZED_GRAPH_BYTES = 64 * 1024 * 1024;
|
|
804
|
-
var MAX_SERIALIZED_GRAPH_DEPTH = 160;
|
|
805
|
-
var MAX_SERIALIZED_GRAPH_VALUES = 1100000;
|
|
806
|
-
var MAX_GRAPH_COMPILER_LIMIT_BYTES = 1024;
|
|
807
|
-
var MAX_GRAPH_COMPILER_LIMIT_DEPTH = 2;
|
|
808
|
-
var MAX_GRAPH_COMPILER_LIMIT_INPUT_VALUES = 16;
|
|
809
|
-
var MAX_WORKFLOW_COMPILATION_BYTES = 80 * 1024 * 1024;
|
|
810
|
-
var MAX_WORKFLOW_COMPILATION_DEPTH = 192;
|
|
811
|
-
var MAX_OPERATION_DISCOVERY_VALUES2 = 17 + OPERATION_PREPARATION_KINDS.length + 3 * OPERATION_RESOURCE_KINDS.length;
|
|
812
|
-
var MAX_WORKFLOW_PROJECTION_VALUES = 5 + MAX_OPERATION_DISCOVERY_ENTRIES * MAX_OPERATION_DISCOVERY_VALUES2;
|
|
813
|
-
var MAX_REQUIREMENT_ENVELOPE_VALUES = 21 + 3 * MAX_SERIALIZED_GRAPH_NODES + WORKFLOW_EFFECT_CLASSES.length + OPERATION_PREPARATION_KINDS.length + 3 * OPERATION_RESOURCE_KINDS.length + WORKFLOW_RESUME_CLASSES.length + UNRESOLVED_REQUIREMENT_KINDS.length;
|
|
814
|
-
var MAX_TOPOLOGICAL_WAVE_VALUES = 1 + 2 * MAX_SERIALIZED_GRAPH_NODES;
|
|
815
|
-
var MAX_GRAPH_COMPILER_LIMIT_VALUES = 6;
|
|
816
|
-
var MAX_WORKFLOW_COMPILATION_VALUES = MAX_SERIALIZED_GRAPH_VALUES + MAX_WORKFLOW_PROJECTION_VALUES + MAX_REQUIREMENT_ENVELOPE_VALUES + MAX_TOPOLOGICAL_WAVE_VALUES + MAX_GRAPH_COMPILER_LIMIT_VALUES + 4;
|
|
817
|
-
function invalidData(message, details) {
|
|
818
|
-
throw new SlopcameraCodeError("invalid-data", message, details);
|
|
819
|
-
}
|
|
820
|
-
function deepFreeze(value) {
|
|
821
|
-
if (typeof value !== "object" || value === null || Object.isFrozen(value)) {
|
|
822
|
-
return value;
|
|
823
|
-
}
|
|
824
|
-
for (const nested of Object.values(value))
|
|
825
|
-
deepFreeze(nested);
|
|
826
|
-
return Object.freeze(value);
|
|
827
|
-
}
|
|
828
|
-
function operationKey2(kind, version) {
|
|
829
|
-
return `${kind}@${String(version)}`;
|
|
830
|
-
}
|
|
831
|
-
function uniqueSorted2(values) {
|
|
832
|
-
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
833
|
-
}
|
|
834
|
-
function canonicalSlopcameraIdentity2(value) {
|
|
835
|
-
if (value === "studio")
|
|
836
|
-
return "slopcamera";
|
|
837
|
-
return value.replace(/^studio\./u, "slopcamera.");
|
|
838
|
-
}
|
|
839
|
-
function safeAdd(left, right, name) {
|
|
840
|
-
const result = left + right;
|
|
841
|
-
if (!Number.isSafeInteger(result)) {
|
|
842
|
-
return invalidData(`${name} exceeds the safe integer range.`, { left, right });
|
|
843
|
-
}
|
|
844
|
-
return result;
|
|
845
|
-
}
|
|
846
|
-
function normalizeLimits(input) {
|
|
847
|
-
if (input === undefined)
|
|
848
|
-
return DEFAULT_GRAPH_COMPILER_LIMITS;
|
|
849
|
-
const captured = createBoundedJsonValueSnapshot(input, MAX_GRAPH_COMPILER_LIMIT_BYTES, "graph compiler limits", {
|
|
850
|
-
maximumDepth: MAX_GRAPH_COMPILER_LIMIT_DEPTH,
|
|
851
|
-
maximumValues: MAX_GRAPH_COMPILER_LIMIT_INPUT_VALUES
|
|
852
|
-
}).value;
|
|
853
|
-
if (typeof captured !== "object" || captured === null || Array.isArray(captured)) {
|
|
854
|
-
return parseCodeBoundary(GraphCompilerLimitsSchema, captured, "graph compiler limits");
|
|
855
|
-
}
|
|
856
|
-
return parseCodeBoundary(GraphCompilerLimitsSchema, {
|
|
857
|
-
...DEFAULT_GRAPH_COMPILER_LIMITS,
|
|
858
|
-
...captured
|
|
859
|
-
}, "graph compiler limits");
|
|
860
|
-
}
|
|
861
|
-
function preflightAuthoredWorkflowGraph(graphInput, maximumNodes) {
|
|
862
|
-
if (typeof graphInput !== "object" || graphInput === null || Array.isArray(graphInput)) {
|
|
863
|
-
return;
|
|
864
|
-
}
|
|
865
|
-
const nodes = Object.getOwnPropertyDescriptor(graphInput, "nodes")?.value;
|
|
866
|
-
if (Array.isArray(nodes) && nodes.length > maximumNodes) {
|
|
867
|
-
return invalidData(`Workflow has ${String(nodes.length)} nodes; the limit is ${String(maximumNodes)}.`, { actual: nodes.length, limit: maximumNodes });
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
function parseAuthoredWorkflowGraphPreservingIdentity(graphInput, maximumNodes = MAX_SERIALIZED_GRAPH_NODES) {
|
|
871
|
-
preflightAuthoredWorkflowGraph(graphInput, maximumNodes);
|
|
872
|
-
const captured = createBoundedJsonValueSnapshot(graphInput, MAX_SERIALIZED_GRAPH_BYTES, "Authored workflow graph", {
|
|
873
|
-
maximumDepth: MAX_SERIALIZED_GRAPH_DEPTH,
|
|
874
|
-
maximumValues: MAX_SERIALIZED_GRAPH_VALUES
|
|
875
|
-
}).value;
|
|
876
|
-
const graph = parseCodeBoundary(AuthoredWorkflowGraphV1Schema, captured, "authored workflow graph");
|
|
877
|
-
if (graph.nodes.length > maximumNodes) {
|
|
878
|
-
return invalidData(`Workflow has ${String(graph.nodes.length)} nodes; the limit is ${String(maximumNodes)}.`, { actual: graph.nodes.length, limit: maximumNodes });
|
|
879
|
-
}
|
|
880
|
-
const sorted = {
|
|
881
|
-
...graph,
|
|
882
|
-
nodes: [...graph.nodes].sort((left, right) => left.key.localeCompare(right.key))
|
|
883
|
-
};
|
|
884
|
-
return deepFreezeJson(sorted);
|
|
885
|
-
}
|
|
886
|
-
function canonicalizeGraphValue(value) {
|
|
887
|
-
if (isSerializedRef(value)) {
|
|
888
|
-
return {
|
|
889
|
-
$ref: {
|
|
890
|
-
...value.$ref,
|
|
891
|
-
schemaId: canonicalSlopcameraIdentity2(value.$ref.schemaId)
|
|
892
|
-
},
|
|
893
|
-
version: WORKFLOW_REF_VERSION
|
|
894
|
-
};
|
|
895
|
-
}
|
|
896
|
-
if (Array.isArray(value)) {
|
|
897
|
-
return value.map(canonicalizeGraphValue);
|
|
898
|
-
}
|
|
899
|
-
if (typeof value === "object" && value !== null) {
|
|
900
|
-
return Object.fromEntries(Object.entries(value).map(([key, nested]) => [key, canonicalizeGraphValue(nested)]));
|
|
901
|
-
}
|
|
902
|
-
return value;
|
|
903
|
-
}
|
|
904
|
-
function canonicalizeAuthoredWorkflowGraph(graph) {
|
|
905
|
-
return deepFreezeJson(parseCodeBoundary(AuthoredWorkflowGraphV1Schema, {
|
|
906
|
-
...graph,
|
|
907
|
-
nodes: graph.nodes.map((node) => ({
|
|
908
|
-
...node,
|
|
909
|
-
executor: node.executor.kind === "operation" ? {
|
|
910
|
-
kind: "operation",
|
|
911
|
-
operation: {
|
|
912
|
-
...node.executor.operation,
|
|
913
|
-
kind: canonicalSlopcameraIdentity2(node.executor.operation.kind)
|
|
914
|
-
}
|
|
915
|
-
} : {
|
|
916
|
-
compute: {
|
|
917
|
-
...node.executor.compute,
|
|
918
|
-
key: canonicalSlopcameraIdentity2(node.executor.compute.key)
|
|
919
|
-
},
|
|
920
|
-
kind: "compute"
|
|
921
|
-
},
|
|
922
|
-
input: canonicalizeGraphValue(node.input),
|
|
923
|
-
inputSchemaId: canonicalSlopcameraIdentity2(node.inputSchemaId),
|
|
924
|
-
outputSchemaId: canonicalSlopcameraIdentity2(node.outputSchemaId)
|
|
925
|
-
})),
|
|
926
|
-
outputs: canonicalizeGraphValue(graph.outputs),
|
|
927
|
-
version: WORKFLOW_GRAPH_VERSION,
|
|
928
|
-
workflow: {
|
|
929
|
-
...graph.workflow,
|
|
930
|
-
id: canonicalSlopcameraIdentity2(graph.workflow.id),
|
|
931
|
-
inputSchemaId: canonicalSlopcameraIdentity2(graph.workflow.inputSchemaId)
|
|
932
|
-
}
|
|
933
|
-
}, "canonical authored workflow graph"));
|
|
934
|
-
}
|
|
935
|
-
function normalizeAuthoredWorkflowGraph(graphInput, maximumNodes = MAX_SERIALIZED_GRAPH_NODES) {
|
|
936
|
-
return canonicalizeAuthoredWorkflowGraph(parseAuthoredWorkflowGraphPreservingIdentity(graphInput, maximumNodes));
|
|
937
|
-
}
|
|
938
|
-
function workflowGraphHashFromNormalized(graph) {
|
|
939
|
-
return canonicalJsonSha256Prefixed(`${WORKFLOW_GRAPH_HASH_DOMAIN}\x00`, graph);
|
|
940
|
-
}
|
|
941
|
-
function createWorkflowGraphHash(graphInput) {
|
|
942
|
-
const graph = normalizeAuthoredWorkflowGraph(graphInput);
|
|
943
|
-
return workflowGraphHashFromNormalized(graph);
|
|
944
|
-
}
|
|
945
|
-
var createGraphHash = createWorkflowGraphHash;
|
|
946
|
-
function isSerializedRef(value) {
|
|
947
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.hasOwn(value, "$ref");
|
|
948
|
-
}
|
|
949
|
-
function isGraphValueArray(value) {
|
|
950
|
-
return Array.isArray(value);
|
|
951
|
-
}
|
|
952
|
-
function collectReferences(value) {
|
|
953
|
-
const references = [];
|
|
954
|
-
const pending = [value];
|
|
955
|
-
while (pending.length > 0) {
|
|
956
|
-
const current = pending.pop();
|
|
957
|
-
if (current === undefined)
|
|
958
|
-
continue;
|
|
959
|
-
if (isSerializedRef(current)) {
|
|
960
|
-
references.push(current);
|
|
961
|
-
continue;
|
|
962
|
-
}
|
|
963
|
-
if (isGraphValueArray(current)) {
|
|
964
|
-
for (const item of current)
|
|
965
|
-
pending.push(item);
|
|
966
|
-
continue;
|
|
967
|
-
}
|
|
968
|
-
if (typeof current === "object" && current !== null) {
|
|
969
|
-
for (const item of Object.values(current))
|
|
970
|
-
pending.push(item);
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
return references;
|
|
974
|
-
}
|
|
975
|
-
function arraysEqual(left, right) {
|
|
976
|
-
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
977
|
-
}
|
|
978
|
-
function validateReference(reference, nodesByKey, owner) {
|
|
979
|
-
const producer = nodesByKey.get(reference.$ref.nodeKey);
|
|
980
|
-
if (producer === undefined) {
|
|
981
|
-
return invalidData(`${owner} contains a dangling reference to ${reference.$ref.nodeKey}.`, { nodeKey: reference.$ref.nodeKey, owner });
|
|
982
|
-
}
|
|
983
|
-
if (producer.outputSchemaId !== reference.$ref.schemaId) {
|
|
984
|
-
return invalidData(`${owner} expects schema ${reference.$ref.schemaId} from ${producer.key}, ` + `but the producer declares ${producer.outputSchemaId}.`, {
|
|
985
|
-
actualSchemaId: producer.outputSchemaId,
|
|
986
|
-
expectedSchemaId: reference.$ref.schemaId,
|
|
987
|
-
nodeKey: producer.key,
|
|
988
|
-
owner
|
|
989
|
-
});
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
function topologicalWaves(nodes, limits) {
|
|
993
|
-
const dependencies = new Map;
|
|
994
|
-
const dependents = new Map;
|
|
995
|
-
let edgeCount = 0;
|
|
996
|
-
for (const node of nodes) {
|
|
997
|
-
const nodeDependencies = new Set(node.dependencies);
|
|
998
|
-
dependencies.set(node.key, nodeDependencies);
|
|
999
|
-
edgeCount = safeAdd(edgeCount, nodeDependencies.size, "Workflow edge count");
|
|
1000
|
-
for (const dependency of nodeDependencies) {
|
|
1001
|
-
const entries = dependents.get(dependency) ?? new Set;
|
|
1002
|
-
entries.add(node.key);
|
|
1003
|
-
dependents.set(dependency, entries);
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
if (edgeCount > limits.maxEdges) {
|
|
1007
|
-
return invalidData(`Workflow has ${String(edgeCount)} edges; the limit is ${String(limits.maxEdges)}.`, { actual: edgeCount, limit: limits.maxEdges });
|
|
1008
|
-
}
|
|
1009
|
-
const structuralFanOut = Math.max(0, ...[...dependents.values()].map((entries) => entries.size));
|
|
1010
|
-
if (structuralFanOut > limits.maxFanOut) {
|
|
1011
|
-
return invalidData(`Workflow fan-out is ${String(structuralFanOut)}; the limit is ${String(limits.maxFanOut)}.`, { actual: structuralFanOut, limit: limits.maxFanOut });
|
|
1012
|
-
}
|
|
1013
|
-
let ready = nodes.filter((node) => (dependencies.get(node.key)?.size ?? 0) === 0).map((node) => node.key).sort((left, right) => left.localeCompare(right));
|
|
1014
|
-
const remaining = new Map(nodes.map((node) => [node.key, dependencies.get(node.key)?.size ?? 0]));
|
|
1015
|
-
const waves = [];
|
|
1016
|
-
let visited = 0;
|
|
1017
|
-
while (ready.length > 0) {
|
|
1018
|
-
const wave = ready;
|
|
1019
|
-
waves.push(wave);
|
|
1020
|
-
visited += wave.length;
|
|
1021
|
-
const next = new Set;
|
|
1022
|
-
for (const nodeKey of wave) {
|
|
1023
|
-
for (const dependent of dependents.get(nodeKey) ?? []) {
|
|
1024
|
-
const nextCount = (remaining.get(dependent) ?? 0) - 1;
|
|
1025
|
-
remaining.set(dependent, nextCount);
|
|
1026
|
-
if (nextCount === 0)
|
|
1027
|
-
next.add(dependent);
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
ready = [...next].sort((left, right) => left.localeCompare(right));
|
|
1031
|
-
}
|
|
1032
|
-
if (visited !== nodes.length) {
|
|
1033
|
-
return invalidData("Workflow graph contains a dependency cycle.");
|
|
1034
|
-
}
|
|
1035
|
-
if (waves.length > limits.maxDepth) {
|
|
1036
|
-
return invalidData(`Workflow depth is ${String(waves.length)}; the limit is ${String(limits.maxDepth)}.`, { actual: waves.length, limit: limits.maxDepth });
|
|
1037
|
-
}
|
|
1038
|
-
return {
|
|
1039
|
-
depth: waves.length,
|
|
1040
|
-
edges: edgeCount,
|
|
1041
|
-
structuralFanOut,
|
|
1042
|
-
waves
|
|
1043
|
-
};
|
|
1044
|
-
}
|
|
1045
|
-
function validateGraph(graphInput, projection, limits) {
|
|
1046
|
-
const graph = normalizeAuthoredWorkflowGraph(graphInput, limits.maxNodes);
|
|
1047
|
-
if (graph.nodes.length > limits.maxNodes) {
|
|
1048
|
-
return invalidData(`Workflow has ${String(graph.nodes.length)} nodes; the limit is ${String(limits.maxNodes)}.`, { actual: graph.nodes.length, limit: limits.maxNodes });
|
|
1049
|
-
}
|
|
1050
|
-
const nodesByKey = new Map;
|
|
1051
|
-
for (const node of graph.nodes) {
|
|
1052
|
-
if (nodesByKey.has(node.key)) {
|
|
1053
|
-
return invalidData(`Duplicate workflow node key: ${node.key}`, {
|
|
1054
|
-
nodeKey: node.key
|
|
1055
|
-
});
|
|
1056
|
-
}
|
|
1057
|
-
nodesByKey.set(node.key, node);
|
|
1058
|
-
}
|
|
1059
|
-
const discoveryByKey = new Map(projection.discovery.map((operation) => [
|
|
1060
|
-
operationKey2(operation.kind, operation.version),
|
|
1061
|
-
operation
|
|
1062
|
-
]));
|
|
1063
|
-
const policiesByNode = new Map;
|
|
1064
|
-
let totalOperationFanOut = 0;
|
|
1065
|
-
for (const node of graph.nodes) {
|
|
1066
|
-
let policy;
|
|
1067
|
-
if (isOperationGraphNode(node)) {
|
|
1068
|
-
const identity = node.executor.operation;
|
|
1069
|
-
const operation = discoveryByKey.get(operationKey2(identity.kind, identity.version));
|
|
1070
|
-
if (operation === undefined) {
|
|
1071
|
-
throw new SlopcameraCodeError("unsupported-plan", `Unsupported operation: ${operationKey2(identity.kind, identity.version)}`, {
|
|
1072
|
-
kind: identity.kind,
|
|
1073
|
-
nodeKey: node.key,
|
|
1074
|
-
projectionId: projection.id,
|
|
1075
|
-
version: identity.version
|
|
1076
|
-
});
|
|
1077
|
-
}
|
|
1078
|
-
if (node.inputSchemaId !== operation.inputSchemaId || node.outputSchemaId !== operation.outputSchemaId) {
|
|
1079
|
-
return invalidData(`Operation schema identity mismatch for ${operationKey2(identity.kind, identity.version)} ` + `at node ${node.key}.`, {
|
|
1080
|
-
actualInputSchemaId: node.inputSchemaId,
|
|
1081
|
-
actualOutputSchemaId: node.outputSchemaId,
|
|
1082
|
-
expectedInputSchemaId: operation.inputSchemaId,
|
|
1083
|
-
expectedOutputSchemaId: operation.outputSchemaId,
|
|
1084
|
-
kind: identity.kind,
|
|
1085
|
-
nodeKey: node.key,
|
|
1086
|
-
version: identity.version
|
|
1087
|
-
});
|
|
1088
|
-
}
|
|
1089
|
-
policy = operation.policy;
|
|
1090
|
-
} else if (isComputeGraphNode(node)) {
|
|
1091
|
-
if (!projection.trustedCompute) {
|
|
1092
|
-
throw new SlopcameraCodeError("unsupported-plan", `Trusted compute is unsupported at node ${node.key}.`, {
|
|
1093
|
-
executorKind: "compute",
|
|
1094
|
-
nodeKey: node.key,
|
|
1095
|
-
projectionId: projection.id
|
|
1096
|
-
});
|
|
1097
|
-
}
|
|
1098
|
-
policy = trustedComputePolicy(node.executor.compute);
|
|
1099
|
-
} else {
|
|
1100
|
-
throw new SlopcameraCodeError("internal", `Unknown node executor for ${node.key}.`);
|
|
1101
|
-
}
|
|
1102
|
-
policiesByNode.set(node.key, policy);
|
|
1103
|
-
totalOperationFanOut = safeAdd(totalOperationFanOut, policy.maxFanOut, "Total operation fan-out");
|
|
1104
|
-
const references = collectReferences(node.input);
|
|
1105
|
-
for (const reference of references) {
|
|
1106
|
-
validateReference(reference, nodesByKey, `Node ${node.key}`);
|
|
1107
|
-
}
|
|
1108
|
-
const controlDependencies = node.controlDependencies ?? [];
|
|
1109
|
-
const normalizedControlDependencies = uniqueSorted2(controlDependencies);
|
|
1110
|
-
if (!arraysEqual(controlDependencies, normalizedControlDependencies)) {
|
|
1111
|
-
return invalidData(`Node ${node.key} control dependencies must be unique and sorted.`, { nodeKey: node.key });
|
|
1112
|
-
}
|
|
1113
|
-
for (const dependency of controlDependencies) {
|
|
1114
|
-
if (!nodesByKey.has(dependency)) {
|
|
1115
|
-
return invalidData(`Node ${node.key} contains a dangling control dependency to ${dependency}.`, { dependency, nodeKey: node.key });
|
|
1116
|
-
}
|
|
1117
|
-
if (dependency === node.key) {
|
|
1118
|
-
return invalidData(`Node ${node.key} cannot depend on itself.`, {
|
|
1119
|
-
nodeKey: node.key
|
|
1120
|
-
});
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
const inferredDependencies = uniqueSorted2([
|
|
1124
|
-
...references.map((reference) => reference.$ref.nodeKey),
|
|
1125
|
-
...controlDependencies
|
|
1126
|
-
]);
|
|
1127
|
-
if (!arraysEqual(node.dependencies, inferredDependencies)) {
|
|
1128
|
-
return invalidData(`Node ${node.key} dependencies do not match its embedded references and explicit control dependencies. ` + `Expected [${inferredDependencies.join(", ")}].`, { expectedDependencies: inferredDependencies, nodeKey: node.key });
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
if (totalOperationFanOut > limits.maxTotalOperationFanOut) {
|
|
1132
|
-
return invalidData(`Workflow operation fan-out bound is ${String(totalOperationFanOut)}; ` + `the limit is ${String(limits.maxTotalOperationFanOut)}.`, { actual: totalOperationFanOut, limit: limits.maxTotalOperationFanOut });
|
|
1133
|
-
}
|
|
1134
|
-
for (const reference of collectReferences(graph.outputs)) {
|
|
1135
|
-
validateReference(reference, nodesByKey, "Workflow outputs");
|
|
1136
|
-
}
|
|
1137
|
-
return {
|
|
1138
|
-
graph,
|
|
1139
|
-
policiesByNode,
|
|
1140
|
-
topology: topologicalWaves(graph.nodes, limits)
|
|
1141
|
-
};
|
|
1142
|
-
}
|
|
1143
|
-
function operationFamily(kind) {
|
|
1144
|
-
const separator = kind.indexOf(".");
|
|
1145
|
-
if (separator < 1) {
|
|
1146
|
-
throw new SlopcameraCodeError("internal", `Operation ${kind} has no namespace family.`, { kind });
|
|
1147
|
-
}
|
|
1148
|
-
return kind.slice(0, separator);
|
|
1149
|
-
}
|
|
1150
|
-
function addResource(resources, resource, amount) {
|
|
1151
|
-
resources.set(resource, safeAdd(resources.get(resource) ?? 0, amount, `Resource ${resource} claim`));
|
|
1152
|
-
}
|
|
1153
|
-
function deriveRequirementEnvelope(validated) {
|
|
1154
|
-
const computeKeys = new Set;
|
|
1155
|
-
const effects = new Set;
|
|
1156
|
-
const families = new Set;
|
|
1157
|
-
const operationKinds = new Set;
|
|
1158
|
-
const preparation = new Set;
|
|
1159
|
-
const resources = new Map;
|
|
1160
|
-
const resumeClasses = new Set;
|
|
1161
|
-
let localMediaUploadNodes = 0;
|
|
1162
|
-
let maxDurationMs = 0;
|
|
1163
|
-
let maxInputBytes = 0;
|
|
1164
|
-
let maxOutputBytes = 0;
|
|
1165
|
-
let totalOperationFanOut = 0;
|
|
1166
|
-
for (const node of validated.graph.nodes) {
|
|
1167
|
-
const policy = validated.policiesByNode.get(node.key);
|
|
1168
|
-
if (policy === undefined) {
|
|
1169
|
-
throw new SlopcameraCodeError("internal", `Node ${node.key} lost its execution policy.`);
|
|
1170
|
-
}
|
|
1171
|
-
effects.add(policy.effect);
|
|
1172
|
-
resumeClasses.add(policy.resume);
|
|
1173
|
-
if (isOperationGraphNode(node)) {
|
|
1174
|
-
families.add(operationFamily(node.executor.operation.kind));
|
|
1175
|
-
operationKinds.add(node.executor.operation.kind);
|
|
1176
|
-
} else if (isComputeGraphNode(node)) {
|
|
1177
|
-
families.add("compute");
|
|
1178
|
-
computeKeys.add(node.executor.compute.key);
|
|
1179
|
-
}
|
|
1180
|
-
for (const requirement of policy.preparation)
|
|
1181
|
-
preparation.add(requirement);
|
|
1182
|
-
for (const claim of policy.resources) {
|
|
1183
|
-
addResource(resources, claim.resource, claim.amount);
|
|
1184
|
-
}
|
|
1185
|
-
if (policy.effect === "paid-cloud" && policy.preparation.includes("local-media")) {
|
|
1186
|
-
localMediaUploadNodes = safeAdd(localMediaUploadNodes, 1, "Local media upload node count");
|
|
1187
|
-
}
|
|
1188
|
-
maxDurationMs = safeAdd(maxDurationMs, policy.maxDurationMs, "Workflow duration bound");
|
|
1189
|
-
maxInputBytes = safeAdd(maxInputBytes, policy.maxInputBytes, "Workflow input byte bound");
|
|
1190
|
-
maxOutputBytes = safeAdd(maxOutputBytes, policy.maxOutputBytes, "Workflow output byte bound");
|
|
1191
|
-
totalOperationFanOut = safeAdd(totalOperationFanOut, policy.maxFanOut, "Workflow operation fan-out bound");
|
|
1192
|
-
}
|
|
1193
|
-
const unresolved = new Set;
|
|
1194
|
-
if (validated.topology.edges > 0)
|
|
1195
|
-
unresolved.add("dependency-outputs");
|
|
1196
|
-
if (preparation.has("local-media") || preparation.has("project-state") || preparation.has("recording-metadata")) {
|
|
1197
|
-
unresolved.add("exact-media-hashes");
|
|
1198
|
-
}
|
|
1199
|
-
if (preparation.has("recording-metadata") || preparation.has("typed-text") || preparation.has("window-metadata")) {
|
|
1200
|
-
unresolved.add("exact-sensitive-metadata-hashes");
|
|
1201
|
-
}
|
|
1202
|
-
if (effects.has("paid-cloud") || resources.has("paid-call")) {
|
|
1203
|
-
unresolved.add("prices");
|
|
1204
|
-
}
|
|
1205
|
-
if (effects.has("project-mutation") || operationKinds.has("render.project") || operationKinds.has("render.project-plan")) {
|
|
1206
|
-
unresolved.add("project-generations");
|
|
1207
|
-
}
|
|
1208
|
-
if (families.has("render"))
|
|
1209
|
-
unresolved.add("render-plans");
|
|
1210
|
-
return parseCodeBoundary(RequirementEnvelopeSchema, {
|
|
1211
|
-
bounds: {
|
|
1212
|
-
depth: validated.topology.depth,
|
|
1213
|
-
edges: validated.topology.edges,
|
|
1214
|
-
localMediaUploadNodes,
|
|
1215
|
-
maxDurationMs,
|
|
1216
|
-
maxInputBytes,
|
|
1217
|
-
maxOutputBytes,
|
|
1218
|
-
nodes: validated.graph.nodes.length,
|
|
1219
|
-
paidCallClaims: resources.get("paid-call") ?? 0,
|
|
1220
|
-
structuralFanOut: validated.topology.structuralFanOut,
|
|
1221
|
-
totalOperationFanOut
|
|
1222
|
-
},
|
|
1223
|
-
computeKeys: uniqueSorted2(computeKeys),
|
|
1224
|
-
effects: uniqueSorted2(effects),
|
|
1225
|
-
operationFamilies: uniqueSorted2(families),
|
|
1226
|
-
operationKinds: uniqueSorted2(operationKinds),
|
|
1227
|
-
preparation: uniqueSorted2(preparation),
|
|
1228
|
-
resources: [...resources].map(([resource, amount]) => ({ amount, resource })).sort((left, right) => left.resource.localeCompare(right.resource)),
|
|
1229
|
-
resumeClasses: uniqueSorted2(resumeClasses),
|
|
1230
|
-
unresolved: uniqueSorted2(unresolved),
|
|
1231
|
-
version: REQUIREMENT_ENVELOPE_VERSION
|
|
1232
|
-
}, "workflow requirement envelope");
|
|
1233
|
-
}
|
|
1234
|
-
function canonicalizeRequirementEnvelope(input) {
|
|
1235
|
-
const envelope = parseCodeBoundary(RequirementEnvelopeSchema, input, "workflow requirement envelope");
|
|
1236
|
-
return parseCodeBoundary(RequirementEnvelopeSchema, {
|
|
1237
|
-
...envelope,
|
|
1238
|
-
computeKeys: envelope.computeKeys.map(canonicalSlopcameraIdentity2),
|
|
1239
|
-
operationFamilies: envelope.operationFamilies.map(canonicalSlopcameraIdentity2),
|
|
1240
|
-
operationKinds: envelope.operationKinds.map(canonicalSlopcameraIdentity2),
|
|
1241
|
-
version: REQUIREMENT_ENVELOPE_VERSION
|
|
1242
|
-
}, "canonical workflow requirement envelope");
|
|
1243
|
-
}
|
|
1244
|
-
function resolveProjection(options) {
|
|
1245
|
-
if (options.projection !== undefined) {
|
|
1246
|
-
if (options.registry !== undefined || options.projectionId !== undefined || options.trustedCompute !== undefined) {
|
|
1247
|
-
throw new SlopcameraCodeError("invalid-data", "Compile with either a projection or a registry projection source, not both.");
|
|
1248
|
-
}
|
|
1249
|
-
return parseWorkflowRegistryProjection(options.projection);
|
|
1250
|
-
}
|
|
1251
|
-
if (options.registry !== undefined) {
|
|
1252
|
-
if (options.projectionId === undefined) {
|
|
1253
|
-
throw new SlopcameraCodeError("invalid-data", "A registry projection source requires an explicit projection id.");
|
|
1254
|
-
}
|
|
1255
|
-
return createWorkflowRegistryProjection(options.projectionId, options.registry, { trustedCompute: options.trustedCompute ?? false });
|
|
1256
|
-
}
|
|
1257
|
-
if (options.projectionId !== undefined || options.trustedCompute !== undefined) {
|
|
1258
|
-
throw new SlopcameraCodeError("invalid-data", "A projection id or trusted-compute authority requires a registry projection source.");
|
|
1259
|
-
}
|
|
1260
|
-
return PUBLIC_WORKFLOW_REGISTRY_PROJECTION;
|
|
1261
|
-
}
|
|
1262
|
-
var RequiredCompilationComponentSchema = z3.unknown().refine((value) => value !== undefined, "Required");
|
|
1263
|
-
var ShallowCompiledWorkflowGraphSchema = z3.strictObject({
|
|
1264
|
-
compilationSha256: Sha256Schema,
|
|
1265
|
-
envelope: RequiredCompilationComponentSchema,
|
|
1266
|
-
graph: RequiredCompilationComponentSchema,
|
|
1267
|
-
graphSha256: Sha256Schema,
|
|
1268
|
-
limits: RequiredCompilationComponentSchema,
|
|
1269
|
-
projection: RequiredCompilationComponentSchema,
|
|
1270
|
-
topologicalWaves: RequiredCompilationComponentSchema,
|
|
1271
|
-
version: z3.literal(WORKFLOW_COMPILATION_VERSION)
|
|
1272
|
-
});
|
|
1273
|
-
function boundedCompilationInput(input, name) {
|
|
1274
|
-
return createBoundedJsonValueSnapshot(input, MAX_WORKFLOW_COMPILATION_BYTES, name, {
|
|
1275
|
-
maximumDepth: MAX_WORKFLOW_COMPILATION_DEPTH,
|
|
1276
|
-
maximumValues: MAX_WORKFLOW_COMPILATION_VALUES
|
|
1277
|
-
}).value;
|
|
1278
|
-
}
|
|
1279
|
-
function workflowCompilationHashFromValidated(compilation) {
|
|
1280
|
-
return canonicalJsonSha256Prefixed(`${WORKFLOW_COMPILATION_HASH_DOMAIN}\x00`, compilation);
|
|
1281
|
-
}
|
|
1282
|
-
function createWorkflowCompilationHash(compilationInput) {
|
|
1283
|
-
const bounded = boundedCompilationInput(compilationInput, "workflow compilation");
|
|
1284
|
-
if (typeof bounded !== "object" || bounded === null || Array.isArray(bounded)) {
|
|
1285
|
-
return invalidData("Workflow compilation must be a plain object.");
|
|
1286
|
-
}
|
|
1287
|
-
const {
|
|
1288
|
-
compilationSha256: ignoredCompilationSha256,
|
|
1289
|
-
...unsigned
|
|
1290
|
-
} = bounded;
|
|
1291
|
-
const parsed = parseCodeBoundary(CompiledWorkflowGraphSchema.omit({ compilationSha256: true }), unsigned, "unsigned workflow compilation");
|
|
1292
|
-
return workflowCompilationHashFromValidated(parsed);
|
|
1293
|
-
}
|
|
1294
|
-
function compileWorkflowGraph(options) {
|
|
1295
|
-
const limits = normalizeLimits(options.limits);
|
|
1296
|
-
const projection = resolveProjection(options);
|
|
1297
|
-
const validated = validateGraph(options.graph, projection, limits);
|
|
1298
|
-
const graphSha256 = workflowGraphHashFromNormalized(validated.graph);
|
|
1299
|
-
const unsigned = {
|
|
1300
|
-
envelope: deriveRequirementEnvelope(validated),
|
|
1301
|
-
graph: validated.graph,
|
|
1302
|
-
graphSha256,
|
|
1303
|
-
limits,
|
|
1304
|
-
projection,
|
|
1305
|
-
topologicalWaves: validated.topology.waves,
|
|
1306
|
-
version: WORKFLOW_COMPILATION_VERSION
|
|
1307
|
-
};
|
|
1308
|
-
return deepFreeze(parseCodeBoundary(CompiledWorkflowGraphSchema, {
|
|
1309
|
-
...unsigned,
|
|
1310
|
-
compilationSha256: workflowCompilationHashFromValidated(unsigned)
|
|
1311
|
-
}, "compiled workflow graph"));
|
|
1312
|
-
}
|
|
1313
|
-
function parseCompiledWorkflowGraph(input) {
|
|
1314
|
-
const bounded = boundedCompilationInput(input, "compiled workflow graph");
|
|
1315
|
-
const shallow = parseCodeBoundary(ShallowCompiledWorkflowGraphSchema, bounded, "compiled workflow graph");
|
|
1316
|
-
const {
|
|
1317
|
-
compilationSha256: parsedCompilationSha256,
|
|
1318
|
-
...unsigned
|
|
1319
|
-
} = shallow;
|
|
1320
|
-
const expected = workflowCompilationHashFromValidated(unsigned);
|
|
1321
|
-
if (parsedCompilationSha256 !== expected) {
|
|
1322
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow compilation hash does not match its contents.", {
|
|
1323
|
-
actualCompilationSha256: parsedCompilationSha256,
|
|
1324
|
-
expectedCompilationSha256: expected
|
|
1325
|
-
});
|
|
1326
|
-
}
|
|
1327
|
-
const parsed = parseCodeBoundary(CompiledWorkflowGraphSchema, bounded, "compiled workflow graph");
|
|
1328
|
-
const exactGraph = parseAuthoredWorkflowGraphPreservingIdentity(parsed.graph);
|
|
1329
|
-
if (canonicalJsonSha256(parsed.graph) !== canonicalJsonSha256(exactGraph)) {
|
|
1330
|
-
throw new SlopcameraCodeError("invalid-data", "Compiled workflow graph nodes are not normalized.");
|
|
1331
|
-
}
|
|
1332
|
-
const expectedGraphSha256 = workflowGraphHashFromNormalized(exactGraph);
|
|
1333
|
-
if (parsed.graphSha256 !== expectedGraphSha256) {
|
|
1334
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow graph hash does not match its authenticated contents.", {
|
|
1335
|
-
actualGraphSha256: parsed.graphSha256,
|
|
1336
|
-
expectedGraphSha256
|
|
1337
|
-
});
|
|
1338
|
-
}
|
|
1339
|
-
const canonicalGraph = canonicalizeAuthoredWorkflowGraph(exactGraph);
|
|
1340
|
-
const canonicalProjection = parseWorkflowRegistryProjection(parsed.projection);
|
|
1341
|
-
const canonicalLimits = normalizeLimits(parsed.limits);
|
|
1342
|
-
const recompiled = compileWorkflowGraph({
|
|
1343
|
-
graph: canonicalGraph,
|
|
1344
|
-
limits: canonicalLimits,
|
|
1345
|
-
projection: canonicalProjection
|
|
1346
|
-
});
|
|
1347
|
-
const canonicalUnsigned = {
|
|
1348
|
-
envelope: canonicalizeRequirementEnvelope(parsed.envelope),
|
|
1349
|
-
graph: canonicalGraph,
|
|
1350
|
-
graphSha256: workflowGraphHashFromNormalized(canonicalGraph),
|
|
1351
|
-
limits: canonicalLimits,
|
|
1352
|
-
projection: canonicalProjection,
|
|
1353
|
-
topologicalWaves: parsed.topologicalWaves,
|
|
1354
|
-
version: WORKFLOW_COMPILATION_VERSION
|
|
1355
|
-
};
|
|
1356
|
-
if (recompiled.compilationSha256 !== workflowCompilationHashFromValidated(canonicalUnsigned)) {
|
|
1357
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow compilation topology, requirements, or projection do not match the graph.");
|
|
1358
|
-
}
|
|
1359
|
-
return recompiled;
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
// src/code/graph-builder.ts
|
|
1363
|
-
var MAX_AUTHORING_VALUE_DEPTH = 128;
|
|
1364
|
-
var MAX_AUTHORING_VALUES = 1e6;
|
|
1365
|
-
var NORMALIZED_LEGACY_COMPUTES = new WeakMap;
|
|
1366
|
-
function consumeAuthoringValue(budget) {
|
|
1367
|
-
if (budget.consumed >= budget.maximum) {
|
|
1368
|
-
throw new SlopcameraCodeError("invalid-data", `Workflow authoring values exceed the ${String(MAX_AUTHORING_VALUES)} value limit.`);
|
|
1369
|
-
}
|
|
1370
|
-
budget.consumed += 1;
|
|
1371
|
-
}
|
|
1372
|
-
function consumeAuthoringValues(budget, additional) {
|
|
1373
|
-
requireAuthoringCapacity(budget, additional);
|
|
1374
|
-
budget.consumed += additional;
|
|
1375
|
-
}
|
|
1376
|
-
function requireAuthoringCapacity(budget, additional) {
|
|
1377
|
-
if (additional > budget.maximum - budget.consumed) {
|
|
1378
|
-
throw new SlopcameraCodeError("invalid-data", `Workflow authoring values exceed the ${String(MAX_AUTHORING_VALUES)} value limit.`);
|
|
1379
|
-
}
|
|
1380
|
-
}
|
|
1381
|
-
function encodingBudget(state) {
|
|
1382
|
-
return {
|
|
1383
|
-
consumed: 0,
|
|
1384
|
-
maximum: MAX_AUTHORING_VALUES - state.authoredValues
|
|
1385
|
-
};
|
|
1386
|
-
}
|
|
1387
|
-
function requireStateCapacity(state, additional) {
|
|
1388
|
-
if (additional > MAX_AUTHORING_VALUES - state.authoredValues) {
|
|
1389
|
-
throw new SlopcameraCodeError("invalid-data", `Workflow authoring values exceed the ${String(MAX_AUTHORING_VALUES)} value limit.`);
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
1392
|
-
function normalizeTrustedComputeDefinition(definition) {
|
|
1393
|
-
if (definition[TRUSTED_COMPUTE_BRAND] === true)
|
|
1394
|
-
return definition;
|
|
1395
|
-
if (Reflect.get(definition, LEGACY_TRUSTED_COMPUTE_BRAND) !== true) {
|
|
1396
|
-
return;
|
|
1397
|
-
}
|
|
1398
|
-
const existing = NORMALIZED_LEGACY_COMPUTES.get(definition);
|
|
1399
|
-
if (existing !== undefined) {
|
|
1400
|
-
return existing;
|
|
1401
|
-
}
|
|
1402
|
-
const normalized = Object.freeze({
|
|
1403
|
-
[TRUSTED_COMPUTE_BRAND]: true,
|
|
1404
|
-
bounds: definition.bounds,
|
|
1405
|
-
inputSchema: definition.inputSchema,
|
|
1406
|
-
inputSchemaId: definition.inputSchemaId,
|
|
1407
|
-
key: definition.key,
|
|
1408
|
-
outputSchema: definition.outputSchema,
|
|
1409
|
-
outputSchemaId: definition.outputSchemaId,
|
|
1410
|
-
run: definition.run
|
|
1411
|
-
});
|
|
1412
|
-
NORMALIZED_LEGACY_COMPUTES.set(definition, normalized);
|
|
1413
|
-
return normalized;
|
|
1414
|
-
}
|
|
1415
|
-
function discoveryKey(kind, version) {
|
|
1416
|
-
return `${kind}@${String(version)}`;
|
|
1417
|
-
}
|
|
1418
|
-
function providerDiscovery(provider) {
|
|
1419
|
-
const source = provider;
|
|
1420
|
-
const discovery = typeof source.list === "function" ? source.list() : provider.discovery;
|
|
1421
|
-
return boundedOperationDiscoveryList(discovery);
|
|
1422
|
-
}
|
|
1423
|
-
function operationContractValue(discovery) {
|
|
1424
|
-
return Object.freeze({
|
|
1425
|
-
inputSchemaId: discovery.inputSchemaId,
|
|
1426
|
-
kind: discovery.kind,
|
|
1427
|
-
outputSchemaId: discovery.outputSchemaId,
|
|
1428
|
-
version: discovery.version
|
|
1429
|
-
});
|
|
1430
|
-
}
|
|
1431
|
-
function isPlainRecord(value) {
|
|
1432
|
-
const prototype = Object.getPrototypeOf(value);
|
|
1433
|
-
return prototype === Object.prototype || prototype === null;
|
|
1434
|
-
}
|
|
1435
|
-
function rejectEnumerableSymbols(descriptors, name) {
|
|
1436
|
-
if (Object.getOwnPropertySymbols(descriptors).some((symbol) => Reflect.get(descriptors, symbol)?.enumerable === true)) {
|
|
1437
|
-
throw new SlopcameraCodeError("invalid-data", `${name} cannot contain enumerable symbol properties.`);
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
function cloneSerializedRef(reference) {
|
|
1441
|
-
return deepFreezeJson(parseCodeBoundary(SerializedRefV1Schema, reference.serialized, "workflow reference"));
|
|
1442
|
-
}
|
|
1443
|
-
function serializedReferenceValueCount(reference) {
|
|
1444
|
-
const path = reference.$ref.path;
|
|
1445
|
-
return path === undefined ? 5 : 6 + path.length;
|
|
1446
|
-
}
|
|
1447
|
-
function isOwnedRef(value, state) {
|
|
1448
|
-
return typeof value === "object" && value !== null && WORKFLOW_REF_BRAND in value && state.references.has(value);
|
|
1449
|
-
}
|
|
1450
|
-
function encodeInputValue(input, state, dependencies, ancestors, depth, budget) {
|
|
1451
|
-
if (depth > MAX_AUTHORING_VALUE_DEPTH) {
|
|
1452
|
-
throw new SlopcameraCodeError("invalid-data", `Workflow input nesting exceeds ${String(MAX_AUTHORING_VALUE_DEPTH)} levels.`);
|
|
1453
|
-
}
|
|
1454
|
-
if (isOwnedRef(input, state)) {
|
|
1455
|
-
const serialized = cloneSerializedRef(input);
|
|
1456
|
-
consumeAuthoringValues(budget, serializedReferenceValueCount(serialized));
|
|
1457
|
-
dependencies.add(serialized.$ref.nodeKey);
|
|
1458
|
-
return serialized;
|
|
1459
|
-
}
|
|
1460
|
-
consumeAuthoringValue(budget);
|
|
1461
|
-
if (typeof input === "object" && input !== null && WORKFLOW_REF_BRAND in input) {
|
|
1462
|
-
throw new SlopcameraCodeError("invalid-data", "Use a typed Ref value created by this workflow graph builder.");
|
|
1463
|
-
}
|
|
1464
|
-
if (input === null || typeof input === "boolean" || typeof input === "string") {
|
|
1465
|
-
return input;
|
|
1466
|
-
}
|
|
1467
|
-
if (typeof input === "number") {
|
|
1468
|
-
if (!Number.isFinite(input)) {
|
|
1469
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow node input numbers must be finite.");
|
|
1470
|
-
}
|
|
1471
|
-
return Object.is(input, -0) ? 0 : input;
|
|
1472
|
-
}
|
|
1473
|
-
if (typeof input !== "object") {
|
|
1474
|
-
throw new SlopcameraCodeError("invalid-data", `Workflow node input cannot contain ${typeof input} values.`);
|
|
1475
|
-
}
|
|
1476
|
-
if (ancestors.has(input)) {
|
|
1477
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow node input cannot contain cycles.");
|
|
1478
|
-
}
|
|
1479
|
-
ancestors.add(input);
|
|
1480
|
-
try {
|
|
1481
|
-
if (Array.isArray(input)) {
|
|
1482
|
-
const length = input.length;
|
|
1483
|
-
requireAuthoringCapacity(budget, length);
|
|
1484
|
-
const descriptors2 = Object.getOwnPropertyDescriptors(input);
|
|
1485
|
-
rejectEnumerableSymbols(descriptors2, "Workflow node input arrays");
|
|
1486
|
-
const keys2 = Object.keys(descriptors2).filter((key) => descriptors2[key]?.enumerable === true);
|
|
1487
|
-
if (keys2.length !== length || keys2.some((key, index) => key !== String(index))) {
|
|
1488
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow node input arrays must be dense and cannot have named properties.");
|
|
1489
|
-
}
|
|
1490
|
-
const encoded2 = [];
|
|
1491
|
-
for (let index = 0;index < length; index += 1) {
|
|
1492
|
-
const descriptor = descriptors2[String(index)];
|
|
1493
|
-
if (descriptor === undefined || descriptor.get !== undefined || descriptor.set !== undefined) {
|
|
1494
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow node input arrays must contain plain data elements.");
|
|
1495
|
-
}
|
|
1496
|
-
encoded2.push(encodeInputValue(descriptor.value, state, dependencies, ancestors, depth + 1, budget));
|
|
1497
|
-
}
|
|
1498
|
-
return encoded2;
|
|
1499
|
-
}
|
|
1500
|
-
if (!isPlainRecord(input)) {
|
|
1501
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow node input accepts only JSON values and typed workflow references.");
|
|
1502
|
-
}
|
|
1503
|
-
if (Object.hasOwn(input, "$ref")) {
|
|
1504
|
-
throw new SlopcameraCodeError("invalid-data", "Use a typed Ref value instead of constructing the reserved $ref field.");
|
|
1505
|
-
}
|
|
1506
|
-
const descriptors = Object.getOwnPropertyDescriptors(input);
|
|
1507
|
-
rejectEnumerableSymbols(descriptors, "Workflow node inputs");
|
|
1508
|
-
const keys = Object.keys(descriptors).filter((key) => descriptors[key]?.enumerable === true).sort();
|
|
1509
|
-
requireAuthoringCapacity(budget, keys.length);
|
|
1510
|
-
const encoded = {};
|
|
1511
|
-
for (const key of keys) {
|
|
1512
|
-
if (key === "__proto__") {
|
|
1513
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow inputs cannot contain the reserved __proto__ object key.");
|
|
1514
|
-
}
|
|
1515
|
-
const descriptor = descriptors[key];
|
|
1516
|
-
if (descriptor === undefined || descriptor.get !== undefined || descriptor.set !== undefined) {
|
|
1517
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow node input properties must be plain data properties.");
|
|
1518
|
-
}
|
|
1519
|
-
encoded[key] = encodeInputValue(descriptor.value, state, dependencies, ancestors, depth + 1, budget);
|
|
1520
|
-
}
|
|
1521
|
-
return encoded;
|
|
1522
|
-
} finally {
|
|
1523
|
-
ancestors.delete(input);
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
function encodeOperationInput(input, state) {
|
|
1527
|
-
const dependencies = new Set;
|
|
1528
|
-
const budget = encodingBudget(state);
|
|
1529
|
-
const value = encodeInputValue(input, state, dependencies, new Set, 0, budget);
|
|
1530
|
-
return {
|
|
1531
|
-
dependencies: [...dependencies].sort((left, right) => left.localeCompare(right)),
|
|
1532
|
-
value,
|
|
1533
|
-
values: budget.consumed
|
|
1534
|
-
};
|
|
1535
|
-
}
|
|
1536
|
-
function encodeControlDependencies(after, state) {
|
|
1537
|
-
if (after === undefined)
|
|
1538
|
-
return [];
|
|
1539
|
-
const dependencies = new Set;
|
|
1540
|
-
const appendReference = (reference) => {
|
|
1541
|
-
if (!isOwnedRef(reference, state)) {
|
|
1542
|
-
throw new SlopcameraCodeError("invalid-data", "Operation control dependencies must be typed Ref values created by this workflow graph builder.");
|
|
1543
|
-
}
|
|
1544
|
-
dependencies.add(cloneSerializedRef(reference).$ref.nodeKey);
|
|
1545
|
-
};
|
|
1546
|
-
if (!Array.isArray(after)) {
|
|
1547
|
-
appendReference(after);
|
|
1548
|
-
return [...dependencies];
|
|
1549
|
-
}
|
|
1550
|
-
const length = after.length;
|
|
1551
|
-
if (length > MAX_SERIALIZED_NODE_DEPENDENCIES) {
|
|
1552
|
-
throw new SlopcameraCodeError("invalid-data", `Operation control dependencies cannot exceed ${String(MAX_SERIALIZED_NODE_DEPENDENCIES)} entries.`);
|
|
1553
|
-
}
|
|
1554
|
-
const descriptors = Object.getOwnPropertyDescriptors(after);
|
|
1555
|
-
rejectEnumerableSymbols(descriptors, "Operation control dependencies");
|
|
1556
|
-
const keys = Object.keys(descriptors).filter((key) => descriptors[key]?.enumerable === true);
|
|
1557
|
-
if (keys.length !== length || keys.some((key, index) => key !== String(index))) {
|
|
1558
|
-
throw new SlopcameraCodeError("invalid-data", "Operation control dependencies must be a dense array without named properties.");
|
|
1559
|
-
}
|
|
1560
|
-
for (let index = 0;index < length; index += 1) {
|
|
1561
|
-
const descriptor = descriptors[String(index)];
|
|
1562
|
-
if (descriptor === undefined || descriptor.get !== undefined || descriptor.set !== undefined) {
|
|
1563
|
-
throw new SlopcameraCodeError("invalid-data", "Operation control dependencies must contain plain data elements.");
|
|
1564
|
-
}
|
|
1565
|
-
appendReference(descriptor.value);
|
|
1566
|
-
}
|
|
1567
|
-
return [...dependencies].sort((left, right) => left.localeCompare(right));
|
|
1568
|
-
}
|
|
1569
|
-
function combineDependencies(dataDependencies, controlDependencies) {
|
|
1570
|
-
return [...new Set([...dataDependencies, ...controlDependencies])].sort((left, right) => left.localeCompare(right));
|
|
1571
|
-
}
|
|
1572
|
-
function encodeOutputValue(output, state, ancestors, depth, budget) {
|
|
1573
|
-
if (depth > MAX_AUTHORING_VALUE_DEPTH) {
|
|
1574
|
-
throw new SlopcameraCodeError("invalid-data", `Workflow output nesting exceeds ${String(MAX_AUTHORING_VALUE_DEPTH)} levels.`);
|
|
1575
|
-
}
|
|
1576
|
-
if (isOwnedRef(output, state)) {
|
|
1577
|
-
const serialized = cloneSerializedRef(output);
|
|
1578
|
-
consumeAuthoringValues(budget, serializedReferenceValueCount(serialized));
|
|
1579
|
-
return serialized;
|
|
1580
|
-
}
|
|
1581
|
-
consumeAuthoringValue(budget);
|
|
1582
|
-
if (typeof output !== "object" || output === null) {
|
|
1583
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow outputs must contain only typed references, arrays, and named objects.");
|
|
1584
|
-
}
|
|
1585
|
-
if (ancestors.has(output)) {
|
|
1586
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow outputs cannot contain cycles.");
|
|
1587
|
-
}
|
|
1588
|
-
ancestors.add(output);
|
|
1589
|
-
try {
|
|
1590
|
-
if (Array.isArray(output)) {
|
|
1591
|
-
const length = output.length;
|
|
1592
|
-
requireAuthoringCapacity(budget, length);
|
|
1593
|
-
const descriptors2 = Object.getOwnPropertyDescriptors(output);
|
|
1594
|
-
rejectEnumerableSymbols(descriptors2, "Workflow output arrays");
|
|
1595
|
-
const keys2 = Object.keys(descriptors2).filter((key) => descriptors2[key]?.enumerable === true);
|
|
1596
|
-
if (keys2.length !== length || keys2.some((key, index) => key !== String(index))) {
|
|
1597
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow output arrays must be dense and cannot have named properties.");
|
|
1598
|
-
}
|
|
1599
|
-
const encoded2 = [];
|
|
1600
|
-
for (let index = 0;index < length; index += 1) {
|
|
1601
|
-
const descriptor = descriptors2[String(index)];
|
|
1602
|
-
if (descriptor === undefined || descriptor.get !== undefined || descriptor.set !== undefined) {
|
|
1603
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow output arrays must contain plain data elements.");
|
|
1604
|
-
}
|
|
1605
|
-
encoded2.push(encodeOutputValue(descriptor.value, state, ancestors, depth + 1, budget));
|
|
1606
|
-
}
|
|
1607
|
-
return encoded2;
|
|
1608
|
-
}
|
|
1609
|
-
if (!isPlainRecord(output)) {
|
|
1610
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow outputs accept only typed references, arrays, and plain objects.");
|
|
1611
|
-
}
|
|
1612
|
-
if (Object.hasOwn(output, "$ref")) {
|
|
1613
|
-
throw new SlopcameraCodeError("invalid-data", "Use a typed Ref value instead of constructing the reserved $ref field.");
|
|
1614
|
-
}
|
|
1615
|
-
const descriptors = Object.getOwnPropertyDescriptors(output);
|
|
1616
|
-
rejectEnumerableSymbols(descriptors, "Workflow outputs");
|
|
1617
|
-
const keys = Object.keys(descriptors).filter((key) => descriptors[key]?.enumerable === true).sort();
|
|
1618
|
-
requireAuthoringCapacity(budget, keys.length);
|
|
1619
|
-
const encoded = {};
|
|
1620
|
-
for (const key of keys) {
|
|
1621
|
-
if (key === "__proto__") {
|
|
1622
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow outputs cannot contain the reserved __proto__ object key.");
|
|
1623
|
-
}
|
|
1624
|
-
const descriptor = descriptors[key];
|
|
1625
|
-
if (descriptor === undefined || descriptor.get !== undefined || descriptor.set !== undefined) {
|
|
1626
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow output properties must be plain data properties.");
|
|
1627
|
-
}
|
|
1628
|
-
encoded[key] = encodeOutputValue(descriptor.value, state, ancestors, depth + 1, budget);
|
|
1629
|
-
}
|
|
1630
|
-
return encoded;
|
|
1631
|
-
} finally {
|
|
1632
|
-
ancestors.delete(output);
|
|
1633
|
-
}
|
|
1634
|
-
}
|
|
1635
|
-
function createReference(nodeKey, schemaId, state, path = []) {
|
|
1636
|
-
if (path.length > MAX_SERIALIZED_REF_PATH_SEGMENTS) {
|
|
1637
|
-
throw new SlopcameraCodeError("invalid-data", `Workflow reference paths cannot exceed ${String(MAX_SERIALIZED_REF_PATH_SEGMENTS)} segments.`);
|
|
1638
|
-
}
|
|
1639
|
-
const serialized = deepFreezeJson({
|
|
1640
|
-
$ref: {
|
|
1641
|
-
nodeKey,
|
|
1642
|
-
...path.length === 0 ? {} : { path: [...path] },
|
|
1643
|
-
schemaId
|
|
1644
|
-
},
|
|
1645
|
-
version: WORKFLOW_REF_VERSION
|
|
1646
|
-
});
|
|
1647
|
-
const reference = Object.freeze({
|
|
1648
|
-
[WORKFLOW_REF_BRAND]: () => {
|
|
1649
|
-
throw new SlopcameraCodeError("internal", "A workflow reference type marker is not executable.");
|
|
1650
|
-
},
|
|
1651
|
-
at: (index) => {
|
|
1652
|
-
if (!Number.isSafeInteger(index) || index < 0) {
|
|
1653
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow reference array indexes must be nonnegative safe integers.");
|
|
1654
|
-
}
|
|
1655
|
-
if (path.length >= MAX_SERIALIZED_REF_PATH_SEGMENTS) {
|
|
1656
|
-
throw new SlopcameraCodeError("invalid-data", `Workflow reference paths cannot exceed ${String(MAX_SERIALIZED_REF_PATH_SEGMENTS)} segments.`);
|
|
1657
|
-
}
|
|
1658
|
-
return createReference(nodeKey, schemaId, state, [...path, index]);
|
|
1659
|
-
},
|
|
1660
|
-
select: (key) => {
|
|
1661
|
-
if (typeof key !== "string" || key.length < 1 || key.length > 128) {
|
|
1662
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow reference field names must contain 1\u2013128 characters.");
|
|
1663
|
-
}
|
|
1664
|
-
if (path.length >= MAX_SERIALIZED_REF_PATH_SEGMENTS) {
|
|
1665
|
-
throw new SlopcameraCodeError("invalid-data", `Workflow reference paths cannot exceed ${String(MAX_SERIALIZED_REF_PATH_SEGMENTS)} segments.`);
|
|
1666
|
-
}
|
|
1667
|
-
return createReference(nodeKey, schemaId, state, [...path, key]);
|
|
1668
|
-
},
|
|
1669
|
-
serialized
|
|
1670
|
-
});
|
|
1671
|
-
state.references.add(reference);
|
|
1672
|
-
return reference;
|
|
1673
|
-
}
|
|
1674
|
-
function createState(provider) {
|
|
1675
|
-
const discovery = new Map;
|
|
1676
|
-
for (const input of providerDiscovery(provider)) {
|
|
1677
|
-
const item = parseCodeBoundary(OperationDiscoverySchema, input, "operation discovery entry");
|
|
1678
|
-
const key = discoveryKey(item.kind, item.version);
|
|
1679
|
-
if (discovery.has(key)) {
|
|
1680
|
-
throw new SlopcameraCodeError("conflict", `Duplicate operation discovery entry: ${key}`, { kind: item.kind, version: item.version });
|
|
1681
|
-
}
|
|
1682
|
-
discovery.set(key, item);
|
|
1683
|
-
}
|
|
1684
|
-
return {
|
|
1685
|
-
authoredValues: 7,
|
|
1686
|
-
computes: new Map,
|
|
1687
|
-
discovery,
|
|
1688
|
-
nodes: new Map,
|
|
1689
|
-
references: new WeakSet
|
|
1690
|
-
};
|
|
1691
|
-
}
|
|
1692
|
-
function defineWorkflowFragment(build) {
|
|
1693
|
-
if (typeof build !== "function") {
|
|
1694
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow fragments require a build function.");
|
|
1695
|
-
}
|
|
1696
|
-
return Object.freeze({ build });
|
|
1697
|
-
}
|
|
1698
|
-
function operationContract(provider, kind, version) {
|
|
1699
|
-
const discovery = createState(provider).discovery.get(discoveryKey(kind, version));
|
|
1700
|
-
if (discovery === undefined) {
|
|
1701
|
-
throw new SlopcameraCodeError("unsupported-plan", `Unsupported operation: ${kind}@${String(version)}`, { kind, version });
|
|
1702
|
-
}
|
|
1703
|
-
return operationContractValue(discovery);
|
|
1704
|
-
}
|
|
1705
|
-
|
|
1706
|
-
class WorkflowGraphBuilder {
|
|
1707
|
-
#namespace;
|
|
1708
|
-
#state;
|
|
1709
|
-
constructor(state, namespace) {
|
|
1710
|
-
this.#namespace = namespace;
|
|
1711
|
-
this.#state = state;
|
|
1712
|
-
}
|
|
1713
|
-
static create(provider) {
|
|
1714
|
-
return new WorkflowGraphBuilder(createState(provider), []);
|
|
1715
|
-
}
|
|
1716
|
-
namespace(segmentInput) {
|
|
1717
|
-
const segment = parseCodeBoundary(NodeKeySegmentSchema, segmentInput, "workflow namespace segment");
|
|
1718
|
-
return new WorkflowGraphBuilder(this.#state, [...this.#namespace, segment]);
|
|
1719
|
-
}
|
|
1720
|
-
fragment(namespace, fragment, input) {
|
|
1721
|
-
return fragment.build(this.namespace(namespace), input);
|
|
1722
|
-
}
|
|
1723
|
-
operation(keyInput, contract, input, options = {}) {
|
|
1724
|
-
return this.#addOperation(keyInput, {
|
|
1725
|
-
input,
|
|
1726
|
-
inputSchemaId: contract.inputSchemaId,
|
|
1727
|
-
kind: contract.kind,
|
|
1728
|
-
outputSchemaId: contract.outputSchemaId,
|
|
1729
|
-
version: contract.version
|
|
1730
|
-
}, options);
|
|
1731
|
-
}
|
|
1732
|
-
operationByKind(keyInput, request, options = {}) {
|
|
1733
|
-
const discovery = this.#state.discovery.get(discoveryKey(request.kind, request.version));
|
|
1734
|
-
if (discovery === undefined) {
|
|
1735
|
-
throw new SlopcameraCodeError("unsupported-plan", `Unsupported operation: ${request.kind}@${String(request.version)}`, { kind: request.kind, version: request.version });
|
|
1736
|
-
}
|
|
1737
|
-
return this.#addOperation(keyInput, {
|
|
1738
|
-
input: request.input,
|
|
1739
|
-
inputSchemaId: discovery.inputSchemaId,
|
|
1740
|
-
kind: request.kind,
|
|
1741
|
-
outputSchemaId: discovery.outputSchemaId,
|
|
1742
|
-
version: request.version
|
|
1743
|
-
}, options);
|
|
1744
|
-
}
|
|
1745
|
-
compute(keyInput, definition, input, options = {}) {
|
|
1746
|
-
if (typeof definition !== "object" || definition === null) {
|
|
1747
|
-
throw new SlopcameraCodeError("invalid-data", "Compute nodes require a definition created by defineCompute().");
|
|
1748
|
-
}
|
|
1749
|
-
const normalizedDefinition = normalizeTrustedComputeDefinition(definition);
|
|
1750
|
-
if (normalizedDefinition === undefined) {
|
|
1751
|
-
throw new SlopcameraCodeError("invalid-data", "Compute nodes require a definition created by defineCompute().");
|
|
1752
|
-
}
|
|
1753
|
-
const compute = parseCodeBoundary(AuthoredComputeIdentitySchema, {
|
|
1754
|
-
bounds: normalizedDefinition.bounds,
|
|
1755
|
-
key: normalizedDefinition.key,
|
|
1756
|
-
version: TRUSTED_COMPUTE_VERSION
|
|
1757
|
-
}, "trusted compute identity");
|
|
1758
|
-
const existing = this.#state.computes.get(compute.key);
|
|
1759
|
-
if (existing !== undefined && existing !== normalizedDefinition) {
|
|
1760
|
-
throw new SlopcameraCodeError("conflict", `Duplicate trusted compute key: ${compute.key}`, { key: compute.key });
|
|
1761
|
-
}
|
|
1762
|
-
const key = this.#nodeKey(keyInput);
|
|
1763
|
-
const encoded = encodeOperationInput(input, this.#state);
|
|
1764
|
-
const controlDependencies = encodeControlDependencies(options.after, this.#state);
|
|
1765
|
-
const dependencies = combineDependencies(encoded.dependencies, controlDependencies);
|
|
1766
|
-
const nodeValues = encoded.values + 15 + controlDependencies.length + dependencies.length + (options.label === undefined ? 0 : 1);
|
|
1767
|
-
requireStateCapacity(this.#state, nodeValues);
|
|
1768
|
-
const node = parseCodeBoundary(AuthoredGraphNodeV1Schema, {
|
|
1769
|
-
controlDependencies,
|
|
1770
|
-
dependencies,
|
|
1771
|
-
executor: { compute, kind: "compute" },
|
|
1772
|
-
input: encoded.value,
|
|
1773
|
-
inputSchemaId: normalizedDefinition.inputSchemaId,
|
|
1774
|
-
key,
|
|
1775
|
-
...options.label === undefined ? {} : { label: options.label },
|
|
1776
|
-
outputSchemaId: normalizedDefinition.outputSchemaId
|
|
1777
|
-
}, "authored compute node");
|
|
1778
|
-
this.#state.computes.set(compute.key, normalizedDefinition);
|
|
1779
|
-
this.#state.nodes.set(key, node);
|
|
1780
|
-
this.#state.authoredValues += nodeValues;
|
|
1781
|
-
return createReference(key, normalizedDefinition.outputSchemaId, this.#state);
|
|
1782
|
-
}
|
|
1783
|
-
computeDefinitions() {
|
|
1784
|
-
return Object.freeze([...this.#state.computes.values()].sort((left, right) => left.key.localeCompare(right.key)));
|
|
1785
|
-
}
|
|
1786
|
-
build(workflowInput, outputs) {
|
|
1787
|
-
const workflow = parseCodeBoundary(WorkflowIdentitySchema, workflowInput, "workflow identity");
|
|
1788
|
-
const outputBudget = encodingBudget(this.#state);
|
|
1789
|
-
const encodedOutputs = encodeOutputValue(outputs, this.#state, new Set, 0, outputBudget);
|
|
1790
|
-
return deepFreezeJson(parseCodeBoundary(AuthoredWorkflowGraphV1Schema, {
|
|
1791
|
-
nodes: [...this.#state.nodes.values()].sort((left, right) => left.key.localeCompare(right.key)),
|
|
1792
|
-
outputs: encodedOutputs,
|
|
1793
|
-
version: WORKFLOW_GRAPH_VERSION,
|
|
1794
|
-
workflow
|
|
1795
|
-
}, "authored workflow graph"));
|
|
1796
|
-
}
|
|
1797
|
-
#nodeKey(keyInput) {
|
|
1798
|
-
const keySegment = parseCodeBoundary(NodeKeySegmentSchema, keyInput, "workflow node key segment");
|
|
1799
|
-
const key = [...this.#namespace, keySegment].join("/");
|
|
1800
|
-
if (this.#state.nodes.has(key)) {
|
|
1801
|
-
throw new SlopcameraCodeError("conflict", `Duplicate workflow node key: ${key}`, { nodeKey: key });
|
|
1802
|
-
}
|
|
1803
|
-
if (this.#state.nodes.size >= MAX_SERIALIZED_GRAPH_NODES) {
|
|
1804
|
-
throw new SlopcameraCodeError("invalid-data", `Workflow nodes cannot exceed ${String(MAX_SERIALIZED_GRAPH_NODES)} entries.`);
|
|
1805
|
-
}
|
|
1806
|
-
return key;
|
|
1807
|
-
}
|
|
1808
|
-
#addOperation(keyInput, request, options) {
|
|
1809
|
-
const key = this.#nodeKey(keyInput);
|
|
1810
|
-
const discovery = this.#state.discovery.get(discoveryKey(request.kind, request.version));
|
|
1811
|
-
if (discovery === undefined) {
|
|
1812
|
-
throw new SlopcameraCodeError("unsupported-plan", `Unsupported operation: ${request.kind}@${String(request.version)}`, { kind: request.kind, version: request.version });
|
|
1813
|
-
}
|
|
1814
|
-
if (request.inputSchemaId !== discovery.inputSchemaId || request.outputSchemaId !== discovery.outputSchemaId) {
|
|
1815
|
-
throw new SlopcameraCodeError("invalid-data", `Operation contract schema mismatch for ${request.kind}@${String(request.version)}.`, {
|
|
1816
|
-
actualInputSchemaId: request.inputSchemaId,
|
|
1817
|
-
actualOutputSchemaId: request.outputSchemaId,
|
|
1818
|
-
expectedInputSchemaId: discovery.inputSchemaId,
|
|
1819
|
-
expectedOutputSchemaId: discovery.outputSchemaId,
|
|
1820
|
-
kind: request.kind,
|
|
1821
|
-
version: request.version
|
|
1822
|
-
});
|
|
1823
|
-
}
|
|
1824
|
-
const encoded = encodeOperationInput(request.input, this.#state);
|
|
1825
|
-
const controlDependencies = encodeControlDependencies(options.after, this.#state);
|
|
1826
|
-
const dependencies = combineDependencies(encoded.dependencies, controlDependencies);
|
|
1827
|
-
const nodeValues = encoded.values + 11 + controlDependencies.length + dependencies.length + (options.label === undefined ? 0 : 1);
|
|
1828
|
-
requireStateCapacity(this.#state, nodeValues);
|
|
1829
|
-
const node = parseCodeBoundary(AuthoredGraphNodeV1Schema, {
|
|
1830
|
-
controlDependencies,
|
|
1831
|
-
dependencies,
|
|
1832
|
-
executor: {
|
|
1833
|
-
kind: "operation",
|
|
1834
|
-
operation: { kind: discovery.kind, version: discovery.version }
|
|
1835
|
-
},
|
|
1836
|
-
input: encoded.value,
|
|
1837
|
-
inputSchemaId: discovery.inputSchemaId,
|
|
1838
|
-
key,
|
|
1839
|
-
...options.label === undefined ? {} : { label: options.label },
|
|
1840
|
-
outputSchemaId: discovery.outputSchemaId
|
|
1841
|
-
}, "authored operation node");
|
|
1842
|
-
this.#state.nodes.set(key, node);
|
|
1843
|
-
this.#state.authoredValues += nodeValues;
|
|
1844
|
-
return createReference(key, discovery.outputSchemaId, this.#state);
|
|
1845
|
-
}
|
|
1846
|
-
}
|
|
1847
|
-
|
|
1848
|
-
// src/code/portable-builder.ts
|
|
1849
|
-
function definePortableWorkflowFragment(build) {
|
|
1850
|
-
return Object.freeze({ build });
|
|
1851
|
-
}
|
|
1852
|
-
|
|
1853
|
-
class PortableWorkflowBuilder {
|
|
1854
|
-
#builder;
|
|
1855
|
-
diagram;
|
|
1856
|
-
image;
|
|
1857
|
-
constructor(builder) {
|
|
1858
|
-
this.#builder = builder;
|
|
1859
|
-
this.diagram = Object.freeze({
|
|
1860
|
-
check: (key, input, options = {}) => this.#builder.operation(key, PORTABLE_SLOPCAMERA_OPERATION_CONTRACTS["slopcamera.diagram.check"], input, options),
|
|
1861
|
-
render: (key, input, options = {}) => this.#builder.operation(key, PORTABLE_SLOPCAMERA_OPERATION_CONTRACTS["slopcamera.diagram.render"], input, options)
|
|
1862
|
-
});
|
|
1863
|
-
this.image = Object.freeze({
|
|
1864
|
-
generate: (key, input, options = {}) => this.#builder.operation(key, PORTABLE_SLOPCAMERA_OPERATION_CONTRACTS["slopcamera.image.generate"], input, options),
|
|
1865
|
-
vectorize: (key, input, options = {}) => this.#builder.operation(key, PORTABLE_SLOPCAMERA_OPERATION_CONTRACTS["slopcamera.image.vectorize"], input, options)
|
|
1866
|
-
});
|
|
1867
|
-
}
|
|
1868
|
-
static create() {
|
|
1869
|
-
return new PortableWorkflowBuilder(WorkflowGraphBuilder.create(PUBLIC_WORKFLOW_REGISTRY_PROJECTION));
|
|
1870
|
-
}
|
|
1871
|
-
namespace(segment) {
|
|
1872
|
-
return new PortableWorkflowBuilder(this.#builder.namespace(segment));
|
|
1873
|
-
}
|
|
1874
|
-
fragment(namespace, fragment, input) {
|
|
1875
|
-
return fragment.build(this.namespace(namespace), input);
|
|
1876
|
-
}
|
|
1877
|
-
build(workflow, outputs) {
|
|
1878
|
-
return this.#builder.build(workflow, outputs);
|
|
1879
|
-
}
|
|
1880
|
-
}
|
|
1881
|
-
|
|
1882
|
-
// src/code/define-workflow.ts
|
|
1883
|
-
function boundedWorkflowInput(schema, input) {
|
|
1884
|
-
const capturedInput = captureJsonStructure(input, "workflow input", {
|
|
1885
|
-
maximumBytes: MAX_TRUSTED_COMPUTE_INPUT_BYTES
|
|
1886
|
-
});
|
|
1887
|
-
const parsedInput = parseCodeBoundary(schema, capturedInput, "workflow input");
|
|
1888
|
-
return createBoundedJsonValueSnapshot(parsedInput, MAX_TRUSTED_COMPUTE_INPUT_BYTES, "JSON-safe workflow input").value;
|
|
1889
|
-
}
|
|
1890
|
-
function workflowDefinitionIdentity(options) {
|
|
1891
|
-
if (typeof options.build !== "function") {
|
|
1892
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow definitions require a build function.");
|
|
1893
|
-
}
|
|
1894
|
-
const id = parseCodeBoundary(WorkflowIdSchema, options.id, "workflow id");
|
|
1895
|
-
const inputSchemaId = parseCodeBoundary(SchemaIdSchema, options.inputSchemaId, "workflow input schema id");
|
|
1896
|
-
if (!Number.isSafeInteger(options.version) || options.version < 1) {
|
|
1897
|
-
throw new SlopcameraCodeError("invalid-data", "Workflow versions must be positive safe integers.");
|
|
1898
|
-
}
|
|
1899
|
-
return { id, inputSchemaId, version: options.version };
|
|
1900
|
-
}
|
|
1901
|
-
function assertOptionsObject(value, name) {
|
|
1902
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
1903
|
-
throw new SlopcameraCodeError("invalid-data", `${name} must be an object.`);
|
|
1904
|
-
}
|
|
1905
|
-
}
|
|
1906
|
-
function assertSchemaCapability(value, name) {
|
|
1907
|
-
if (typeof value !== "object" || value === null || typeof value.safeParse !== "function") {
|
|
1908
|
-
throw new SlopcameraCodeError("invalid-data", `${name} must provide a synchronous safeParse function.`);
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
function defineWorkflow(options) {
|
|
1912
|
-
assertOptionsObject(options, "Workflow definition options");
|
|
1913
|
-
assertSchemaCapability(options.inputSchema, "Workflow input schema");
|
|
1914
|
-
const identity = workflowDefinitionIdentity(options);
|
|
1915
|
-
return Object.freeze({
|
|
1916
|
-
build: options.build,
|
|
1917
|
-
id: identity.id,
|
|
1918
|
-
inputSchema: options.inputSchema,
|
|
1919
|
-
inputSchemaId: identity.inputSchemaId,
|
|
1920
|
-
version: identity.version
|
|
1921
|
-
});
|
|
1922
|
-
}
|
|
1923
|
-
function buildWorkflow(definition, input) {
|
|
1924
|
-
assertOptionsObject(definition, "Workflow definition");
|
|
1925
|
-
assertSchemaCapability(definition.inputSchema, "Workflow input schema");
|
|
1926
|
-
workflowDefinitionIdentity(definition);
|
|
1927
|
-
const workflowInput = boundedWorkflowInput(definition.inputSchema, input);
|
|
1928
|
-
const builder = PortableWorkflowBuilder.create();
|
|
1929
|
-
const outputs = definition.build(builder, workflowInput);
|
|
1930
|
-
const graph = builder.build({
|
|
1931
|
-
id: definition.id,
|
|
1932
|
-
inputSchemaId: definition.inputSchemaId,
|
|
1933
|
-
version: definition.version
|
|
1934
|
-
}, outputs);
|
|
1935
|
-
return Object.freeze({
|
|
1936
|
-
graph,
|
|
1937
|
-
input: workflowInput,
|
|
1938
|
-
projection: PUBLIC_WORKFLOW_REGISTRY_PROJECTION
|
|
1939
|
-
});
|
|
1940
|
-
}
|
|
1941
|
-
var buildWorkflowGraph = buildWorkflow;
|
|
1942
|
-
function defineCompute(options) {
|
|
1943
|
-
assertOptionsObject(options, "Trusted compute definition options");
|
|
1944
|
-
assertSchemaCapability(options.inputSchema, "Trusted compute input schema");
|
|
1945
|
-
assertSchemaCapability(options.outputSchema, "Trusted compute output schema");
|
|
1946
|
-
if (typeof options.run !== "function") {
|
|
1947
|
-
throw new SlopcameraCodeError("invalid-data", "Trusted compute definitions require a run function.");
|
|
1948
|
-
}
|
|
1949
|
-
const key = parseCodeBoundary(ComputeKeySchema, options.key, "trusted compute key");
|
|
1950
|
-
const inputSchemaId = parseCodeBoundary(SchemaIdSchema, options.inputSchemaId, "trusted compute input schema id");
|
|
1951
|
-
const outputSchemaId = parseCodeBoundary(SchemaIdSchema, options.outputSchemaId, "trusted compute output schema id");
|
|
1952
|
-
const identity = parseCodeBoundary(AuthoredComputeIdentitySchema, {
|
|
1953
|
-
bounds: {
|
|
1954
|
-
maxDurationMs: options.maxDurationMs ?? 30000,
|
|
1955
|
-
maxInputBytes: options.maxInputBytes ?? Math.min(1024 * 1024, MAX_TRUSTED_COMPUTE_INPUT_BYTES),
|
|
1956
|
-
maxOutputBytes: options.maxOutputBytes ?? Math.min(1024 * 1024, MAX_TRUSTED_COMPUTE_OUTPUT_BYTES)
|
|
1957
|
-
},
|
|
1958
|
-
key,
|
|
1959
|
-
version: 1
|
|
1960
|
-
}, "trusted compute definition");
|
|
1961
|
-
if (identity.bounds.maxDurationMs > MAX_TRUSTED_COMPUTE_DURATION_MS) {
|
|
1962
|
-
throw new SlopcameraCodeError("invalid-data", "Trusted compute duration exceeds the host maximum.");
|
|
1963
|
-
}
|
|
1964
|
-
return Object.freeze({
|
|
1965
|
-
[TRUSTED_COMPUTE_BRAND]: true,
|
|
1966
|
-
bounds: deepFreezeJson(identity.bounds),
|
|
1967
|
-
inputSchema: options.inputSchema,
|
|
1968
|
-
inputSchemaId,
|
|
1969
|
-
key,
|
|
1970
|
-
outputSchema: options.outputSchema,
|
|
1971
|
-
outputSchemaId,
|
|
1972
|
-
run: options.run
|
|
1973
|
-
});
|
|
1974
|
-
}
|
|
1975
|
-
function defineAdvancedWorkflow(options) {
|
|
1976
|
-
assertOptionsObject(options, "Advanced workflow definition options");
|
|
1977
|
-
assertSchemaCapability(options.inputSchema, "Advanced workflow input schema");
|
|
1978
|
-
const identity = workflowDefinitionIdentity(options);
|
|
1979
|
-
return Object.freeze({
|
|
1980
|
-
build: options.build,
|
|
1981
|
-
id: identity.id,
|
|
1982
|
-
inputSchema: options.inputSchema,
|
|
1983
|
-
inputSchemaId: identity.inputSchemaId,
|
|
1984
|
-
version: identity.version
|
|
1985
|
-
});
|
|
1986
|
-
}
|
|
1987
|
-
function buildAdvancedWorkflow(definition, provider, input) {
|
|
1988
|
-
assertOptionsObject(definition, "Advanced workflow definition");
|
|
1989
|
-
assertSchemaCapability(definition.inputSchema, "Advanced workflow input schema");
|
|
1990
|
-
workflowDefinitionIdentity(definition);
|
|
1991
|
-
const workflowInput = boundedWorkflowInput(definition.inputSchema, input);
|
|
1992
|
-
const builder = WorkflowGraphBuilder.create(provider);
|
|
1993
|
-
const outputs = definition.build(builder, workflowInput);
|
|
1994
|
-
return Object.freeze({
|
|
1995
|
-
computeDefinitions: builder.computeDefinitions(),
|
|
1996
|
-
graph: builder.build({
|
|
1997
|
-
id: definition.id,
|
|
1998
|
-
inputSchemaId: definition.inputSchemaId,
|
|
1999
|
-
version: definition.version
|
|
2000
|
-
}, outputs),
|
|
2001
|
-
input: workflowInput
|
|
2002
|
-
});
|
|
2003
|
-
}
|
|
2004
|
-
function seconds(value) {
|
|
2005
|
-
if (!Number.isFinite(value) || value < 0) {
|
|
2006
|
-
throw new SlopcameraCodeError("invalid-data", "Seconds must be a finite nonnegative number.");
|
|
2007
|
-
}
|
|
2008
|
-
const microseconds = value * 1e6;
|
|
2009
|
-
if (!Number.isSafeInteger(microseconds)) {
|
|
2010
|
-
throw new SlopcameraCodeError("invalid-data", "Seconds must resolve to an integer number of safe microseconds.");
|
|
2011
|
-
}
|
|
2012
|
-
return microseconds;
|
|
2013
|
-
}
|
|
2014
|
-
|
|
2015
|
-
// src/code/runtime.ts
|
|
2016
|
-
var WORKFLOW_NODE_RECEIPT_VERSION = "slopcamera-workflow-node-receipt-v1";
|
|
2017
|
-
var WORKFLOW_NODE_RECEIPT_HASH_DOMAIN = "slopcamera.workflow.node-receipt/v1";
|
|
2018
|
-
var MAX_WORKFLOW_RESULT_BYTES = 96 * 1024 * 1024;
|
|
2019
|
-
var MAX_WORKFLOW_RESULT_DEPTH = 320;
|
|
2020
|
-
var MAX_WORKFLOW_RESULT_VALUES = 1300000;
|
|
2021
|
-
function createSlopcameraCodeHost(options) {
|
|
2022
|
-
if (typeof options !== "object" || options === null) {
|
|
2023
|
-
throw new SlopcameraCodeError("invalid-data", "An Slopcamera Code host must be an object.");
|
|
2024
|
-
}
|
|
2025
|
-
if (typeof options.execute !== "function") {
|
|
2026
|
-
throw new SlopcameraCodeError("invalid-data", "An Slopcamera Code host requires an execute function.");
|
|
2027
|
-
}
|
|
2028
|
-
if (options.admit !== undefined && typeof options.admit !== "function") {
|
|
2029
|
-
throw new SlopcameraCodeError("invalid-data", "An Slopcamera Code host admit value must be a function when provided.");
|
|
2030
|
-
}
|
|
2031
|
-
return Object.freeze({
|
|
2032
|
-
...options.admit === undefined ? {} : { admit: options.admit },
|
|
2033
|
-
execute: options.execute
|
|
2034
|
-
});
|
|
2035
|
-
}
|
|
2036
|
-
|
|
2037
|
-
class SlopcameraWorkflowRunError extends SlopcameraCodeError {
|
|
2038
|
-
completedReceipts;
|
|
2039
|
-
failedNode;
|
|
2040
|
-
runCause;
|
|
2041
|
-
constructor(code, message, options) {
|
|
2042
|
-
const failedNode = options.failedNode === undefined ? undefined : Object.freeze({ ...options.failedNode });
|
|
2043
|
-
const completedReceipts = Object.freeze([...options.completedReceipts]);
|
|
2044
|
-
super(code, message, {
|
|
2045
|
-
completedReceiptCount: completedReceipts.length,
|
|
2046
|
-
...failedNode === undefined ? {} : { failedNode }
|
|
2047
|
-
});
|
|
2048
|
-
this.name = "SlopcameraWorkflowRunError";
|
|
2049
|
-
this.completedReceipts = completedReceipts;
|
|
2050
|
-
this.failedNode = failedNode;
|
|
2051
|
-
this.runCause = options.cause;
|
|
2052
|
-
}
|
|
2053
|
-
}
|
|
2054
|
-
function isSerializedRef2(value) {
|
|
2055
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.hasOwn(value, "$ref");
|
|
2056
|
-
}
|
|
2057
|
-
function projectedValue(reference, values) {
|
|
2058
|
-
let current = values.get(reference.$ref.nodeKey);
|
|
2059
|
-
if (current === undefined) {
|
|
2060
|
-
throw new SlopcameraCodeError("internal", `Workflow reference producer ${reference.$ref.nodeKey} has not completed.`, { nodeKey: reference.$ref.nodeKey });
|
|
2061
|
-
}
|
|
2062
|
-
for (const segment of reference.$ref.path ?? []) {
|
|
2063
|
-
if (typeof segment === "number") {
|
|
2064
|
-
if (!Array.isArray(current) || segment >= current.length) {
|
|
2065
|
-
throw new SlopcameraCodeError("invalid-data", `Workflow reference ${reference.$ref.nodeKey} has an invalid array projection.`, { nodeKey: reference.$ref.nodeKey, segment });
|
|
2066
|
-
}
|
|
2067
|
-
const currentArray = current;
|
|
2068
|
-
current = currentArray[segment];
|
|
2069
|
-
} else {
|
|
2070
|
-
if (typeof current !== "object" || current === null || Array.isArray(current) || !Object.hasOwn(current, segment)) {
|
|
2071
|
-
throw new SlopcameraCodeError("invalid-data", `Workflow reference ${reference.$ref.nodeKey} has an invalid object projection.`, { nodeKey: reference.$ref.nodeKey, segment });
|
|
2072
|
-
}
|
|
2073
|
-
current = current[segment];
|
|
2074
|
-
}
|
|
2075
|
-
if (current === undefined) {
|
|
2076
|
-
throw new SlopcameraCodeError("invalid-data", `Workflow reference ${reference.$ref.nodeKey} projected an undefined value.`, { nodeKey: reference.$ref.nodeKey, segment });
|
|
2077
|
-
}
|
|
2078
|
-
}
|
|
2079
|
-
return current;
|
|
2080
|
-
}
|
|
2081
|
-
function resolveValue(value, values) {
|
|
2082
|
-
if (isSerializedRef2(value))
|
|
2083
|
-
return projectedValue(value, values);
|
|
2084
|
-
if (Array.isArray(value)) {
|
|
2085
|
-
const items = value;
|
|
2086
|
-
return items.map((item) => resolveValue(item, values));
|
|
2087
|
-
}
|
|
2088
|
-
if (typeof value === "object" && value !== null) {
|
|
2089
|
-
const record = value;
|
|
2090
|
-
const output = {};
|
|
2091
|
-
for (const key of Object.keys(record).sort()) {
|
|
2092
|
-
const item = record[key];
|
|
2093
|
-
if (item === undefined) {
|
|
2094
|
-
throw new SlopcameraCodeError("internal", `Compiled workflow value ${key} is undefined.`);
|
|
2095
|
-
}
|
|
2096
|
-
output[key] = resolveValue(item, values);
|
|
2097
|
-
}
|
|
2098
|
-
return output;
|
|
2099
|
-
}
|
|
2100
|
-
return value;
|
|
2101
|
-
}
|
|
2102
|
-
function createNodeReceipt(index, nodeKey, kind, inputSha256, outputSha256) {
|
|
2103
|
-
const unsigned = {
|
|
2104
|
-
index,
|
|
2105
|
-
inputSha256,
|
|
2106
|
-
kind,
|
|
2107
|
-
nodeKey,
|
|
2108
|
-
operationVersion: 2,
|
|
2109
|
-
outputSha256,
|
|
2110
|
-
version: WORKFLOW_NODE_RECEIPT_VERSION
|
|
2111
|
-
};
|
|
2112
|
-
return Object.freeze({
|
|
2113
|
-
...unsigned,
|
|
2114
|
-
receiptSha256: canonicalJsonSha256Prefixed(`${WORKFLOW_NODE_RECEIPT_HASH_DOMAIN}\x00`, unsigned)
|
|
2115
|
-
});
|
|
2116
|
-
}
|
|
2117
|
-
function publicOperationNode(node) {
|
|
2118
|
-
if (isComputeGraphNode(node)) {
|
|
2119
|
-
throw new SlopcameraCodeError("unsupported-plan", `The public projection does not support trusted compute at node ${node.key}.`, {
|
|
2120
|
-
executorKind: "compute",
|
|
2121
|
-
nodeKey: node.key,
|
|
2122
|
-
projectionId: PUBLIC_WORKFLOW_REGISTRY_PROJECTION.id
|
|
2123
|
-
});
|
|
2124
|
-
}
|
|
2125
|
-
if (!isOperationGraphNode(node)) {
|
|
2126
|
-
throw new SlopcameraCodeError("unsupported-plan", `The public projection does not support the executor at node ${node.key}.`, { nodeKey: node.key, projectionId: PUBLIC_WORKFLOW_REGISTRY_PROJECTION.id });
|
|
2127
|
-
}
|
|
2128
|
-
const operation = node.executor.operation;
|
|
2129
|
-
if (operation.version !== 2 || !isPortableSlopcameraOperationKind(operation.kind)) {
|
|
2130
|
-
throw new SlopcameraCodeError("unsupported-plan", `Unsupported operation: ${operation.kind}@${String(operation.version)}`, {
|
|
2131
|
-
kind: operation.kind,
|
|
2132
|
-
nodeKey: node.key,
|
|
2133
|
-
projectionId: PUBLIC_WORKFLOW_REGISTRY_PROJECTION.id,
|
|
2134
|
-
version: operation.version
|
|
2135
|
-
});
|
|
2136
|
-
}
|
|
2137
|
-
}
|
|
2138
|
-
function throwIfAborted(signal) {
|
|
2139
|
-
if (signal.aborted) {
|
|
2140
|
-
throw new SlopcameraCodeError("cancelled", "Workflow execution was cancelled.");
|
|
2141
|
-
}
|
|
2142
|
-
}
|
|
2143
|
-
function workflowNodeFailure(error, node, completedReceipts) {
|
|
2144
|
-
const code = error instanceof SlopcameraCodeError ? error.code : "subprocess";
|
|
2145
|
-
return new SlopcameraWorkflowRunError(code, `Workflow node ${node.key} (${node.executor.operation.kind}@2) failed: ` + slopcameraCodeErrorMessage(error), {
|
|
2146
|
-
cause: error,
|
|
2147
|
-
completedReceipts,
|
|
2148
|
-
failedNode: {
|
|
2149
|
-
kind: node.executor.operation.kind,
|
|
2150
|
-
nodeKey: node.key,
|
|
2151
|
-
version: 2
|
|
2152
|
-
}
|
|
2153
|
-
});
|
|
2154
|
-
}
|
|
2155
|
-
function workflowRunFailure(error, message, completedReceipts) {
|
|
2156
|
-
const code = error instanceof SlopcameraCodeError ? error.code : "internal";
|
|
2157
|
-
return new SlopcameraWorkflowRunError(code, message, {
|
|
2158
|
-
cause: error,
|
|
2159
|
-
completedReceipts
|
|
2160
|
-
});
|
|
2161
|
-
}
|
|
2162
|
-
async function executePublicNode(host, node, values, context) {
|
|
2163
|
-
const { kind } = node.executor.operation;
|
|
2164
|
-
const contract = PORTABLE_SLOPCAMERA_OPERATION_CONTRACTS[kind];
|
|
2165
|
-
const resolvedInput = resolveValue(node.input, values);
|
|
2166
|
-
const rawInput = createBoundedJsonValueSnapshot(resolvedInput, contract.policy.maxInputBytes, `${kind} raw input at node ${node.key}`);
|
|
2167
|
-
const parsedInput = parseCodeBoundary(contract.inputSchema, rawInput.value, `${kind} input at node ${node.key}`);
|
|
2168
|
-
const boundedInput = createBoundedJsonSnapshot(parsedInput, contract.policy.maxInputBytes, `${kind} input at node ${node.key}`);
|
|
2169
|
-
const request = Object.freeze({
|
|
2170
|
-
input: boundedInput.value,
|
|
2171
|
-
kind,
|
|
2172
|
-
nodeKey: node.key,
|
|
2173
|
-
version: 2
|
|
2174
|
-
});
|
|
2175
|
-
throwIfAborted(context.signal);
|
|
2176
|
-
const dispatch = async () => await host.execute(request, context);
|
|
2177
|
-
const rawOutput = host.admit === undefined ? await dispatch() : await host.admit(Object.freeze({
|
|
2178
|
-
kind,
|
|
2179
|
-
nodeKey: node.key,
|
|
2180
|
-
policy: contract.policy,
|
|
2181
|
-
version: 2
|
|
2182
|
-
}), dispatch, context);
|
|
2183
|
-
const boundedRawOutput = createBoundedJsonValueSnapshot(rawOutput, contract.policy.maxOutputBytes, `${kind} raw output at node ${node.key}`);
|
|
2184
|
-
const parsedOutput = parseCodeBoundary(contract.outputSchema, boundedRawOutput.value, `${kind} output at node ${node.key}`);
|
|
2185
|
-
return Object.freeze({
|
|
2186
|
-
input: boundedInput,
|
|
2187
|
-
output: createBoundedJsonSnapshot(parsedOutput, contract.policy.maxOutputBytes, `${kind} output at node ${node.key}`)
|
|
2188
|
-
});
|
|
2189
|
-
}
|
|
2190
|
-
async function runBuiltWorkflow(built, options) {
|
|
2191
|
-
const compilation = compileWorkflowGraph({
|
|
2192
|
-
graph: built.graph,
|
|
2193
|
-
limits: options.limits,
|
|
2194
|
-
projection: PUBLIC_WORKFLOW_REGISTRY_PROJECTION
|
|
2195
|
-
});
|
|
2196
|
-
for (const node of compilation.graph.nodes)
|
|
2197
|
-
publicOperationNode(node);
|
|
2198
|
-
const host = createSlopcameraCodeHost(options.host);
|
|
2199
|
-
const context = Object.freeze({
|
|
2200
|
-
signal: options.signal ?? new AbortController().signal
|
|
2201
|
-
});
|
|
2202
|
-
throwIfAborted(context.signal);
|
|
2203
|
-
const nodes = new Map(compilation.graph.nodes.map((node) => [node.key, node]));
|
|
2204
|
-
const values = new Map;
|
|
2205
|
-
const receipts = [];
|
|
2206
|
-
for (const wave of compilation.topologicalWaves) {
|
|
2207
|
-
const outcomes = await Promise.all(wave.map(async (nodeKey) => {
|
|
2208
|
-
const node = nodes.get(nodeKey);
|
|
2209
|
-
if (node === undefined) {
|
|
2210
|
-
throw new SlopcameraCodeError("internal", `Compiled workflow topology lost node ${nodeKey}.`, { nodeKey });
|
|
2211
|
-
}
|
|
2212
|
-
publicOperationNode(node);
|
|
2213
|
-
try {
|
|
2214
|
-
return {
|
|
2215
|
-
executed: await executePublicNode(host, node, values, context),
|
|
2216
|
-
kind: "executed",
|
|
2217
|
-
node
|
|
2218
|
-
};
|
|
2219
|
-
} catch (error) {
|
|
2220
|
-
return { error, kind: "failed", node };
|
|
2221
|
-
}
|
|
2222
|
-
}));
|
|
2223
|
-
for (const outcome of outcomes) {
|
|
2224
|
-
if (outcome.kind !== "executed")
|
|
2225
|
-
continue;
|
|
2226
|
-
values.set(outcome.node.key, outcome.executed.output.value);
|
|
2227
|
-
receipts.push(createNodeReceipt(receipts.length, outcome.node.key, outcome.node.executor.operation.kind, outcome.executed.input.sha256, outcome.executed.output.sha256));
|
|
2228
|
-
}
|
|
2229
|
-
const failure = outcomes.find((outcome) => outcome.kind === "failed");
|
|
2230
|
-
if (failure !== undefined) {
|
|
2231
|
-
throw workflowNodeFailure(failure.error, failure.node, receipts);
|
|
2232
|
-
}
|
|
2233
|
-
if (context.signal.aborted) {
|
|
2234
|
-
const cause = new SlopcameraCodeError("cancelled", "Workflow execution was cancelled.");
|
|
2235
|
-
throw workflowRunFailure(cause, "Workflow execution was cancelled after the current wave settled.", receipts);
|
|
2236
|
-
}
|
|
2237
|
-
}
|
|
2238
|
-
let output;
|
|
2239
|
-
try {
|
|
2240
|
-
output = createBoundedJsonValueSnapshot(resolveValue(compilation.graph.outputs, values), MAX_WORKFLOW_RESULT_BYTES, "workflow output", {
|
|
2241
|
-
maximumDepth: MAX_WORKFLOW_RESULT_DEPTH,
|
|
2242
|
-
maximumValues: MAX_WORKFLOW_RESULT_VALUES
|
|
2243
|
-
}).value;
|
|
2244
|
-
} catch (error) {
|
|
2245
|
-
throw workflowRunFailure(error, `Workflow output resolution failed: ${slopcameraCodeErrorMessage(error)}`, receipts);
|
|
2246
|
-
}
|
|
2247
|
-
return Object.freeze({
|
|
2248
|
-
compilation,
|
|
2249
|
-
output,
|
|
2250
|
-
receipts: Object.freeze(receipts)
|
|
2251
|
-
});
|
|
2252
|
-
}
|
|
2253
|
-
async function runWorkflow(definition, input, options) {
|
|
2254
|
-
return await runBuiltWorkflow(buildWorkflow(definition, input), options);
|
|
2255
|
-
}
|
|
2256
|
-
|
|
2257
|
-
export { WORKFLOW_GRAPH_VERSION, WORKFLOW_REF_VERSION, GRAPH_ABI, REQUIREMENT_ENVELOPE_VERSION, TRUSTED_COMPUTE_VERSION, WORKFLOW_COMPILATION_VERSION, LEGACY_WORKFLOW_GRAPH_VERSION, LEGACY_WORKFLOW_REF_VERSION, LEGACY_GRAPH_ABI, LEGACY_REQUIREMENT_ENVELOPE_VERSION, MAX_SERIALIZED_GRAPH_NODES, MAX_SERIALIZED_NODE_DEPENDENCIES, MAX_SERIALIZED_REF_PATH_SEGMENTS, MAX_OPERATION_DISCOVERY_ENTRIES, MAX_TRUSTED_COMPUTE_INPUT_BYTES, MAX_TRUSTED_COMPUTE_OUTPUT_BYTES, MAX_TRUSTED_COMPUTE_DURATION_MS, WorkflowIdSchema, NodeKeySegmentSchema, NodeKeySchema, SchemaIdSchema, ComputeKeySchema, OperationKindSchema, Sha256Schema, PositiveSafeIntegerSchema, NonnegativeSafeIntegerSchema, RefPathSegmentSchema, JsonValueSchema, SerializedRefV1Schema, GraphInputValueSchema, WorkflowOutputBindingSchema, AuthoredOperationIdentitySchema, AuthoredComputeIdentitySchema, AuthoredNodeExecutorSchema, AuthoredGraphNodeV1Schema, isOperationGraphNode, isComputeGraphNode, WorkflowIdentitySchema, AuthoredWorkflowGraphV1Schema, OPERATION_EFFECT_CLASSES, WORKFLOW_EFFECT_CLASSES, OPERATION_RESUME_CLASSES, WORKFLOW_RESUME_CLASSES, OPERATION_PREPARATION_KINDS, OPERATION_LIFECYCLE_KINDS, OPERATION_RESOURCE_KINDS, OperationResourceClaimSchema, OperationPolicySchema, TrustedComputePolicySchema, WorkflowNodePolicySchema, trustedComputePolicy, OperationDiscoverySchema, WorkflowRegistryProjectionSchema, GraphCompilerLimitsSchema, UNRESOLVED_REQUIREMENT_KINDS, RequirementEnvelopeBoundsSchema, RequirementEnvelopeSchema, CompiledWorkflowGraphSchema, TRUSTED_COMPUTE_BRAND, LEGACY_TRUSTED_COMPUTE_BRAND, WORKFLOW_REF_BRAND, SlopcameraImageModelSchema, SlopcameraDiagramCheckInputSchema, SlopcameraDiagramRenderInputSchema, SlopcameraImageVectorizeInputSchema, SlopcameraImageGenerateInputSchema, SlopcameraLintFindingSchema, SlopcameraDiagramCheckOutputSchema, SlopcameraRenderArtifactsSchema, SlopcameraDiagramRenderOutputSchema, SlopcameraVectorizeQualityReceiptSchema, SlopcameraVectorizeProvenanceSchema, SlopcameraVectorizeReceiptSchema, SlopcameraImageVectorizeOutputSchema, SlopcameraImageGenerateOutputSchema, PORTABLE_SLOPCAMERA_OPERATION_KINDS, PORTABLE_SLOPCAMERA_OPERATION_CONTRACTS, isPortableSlopcameraOperationKind, WORKFLOW_REGISTRY_PROJECTION_HASH_DOMAIN, PUBLIC_WORKFLOW_REGISTRY_PROJECTION_ID, boundedOperationDiscoveryList, normalizeOperationDiscovery, createWorkflowRegistryProjectionHash, createWorkflowRegistryProjection, parseWorkflowRegistryProjection, createPublicWorkflowRegistryProjection, PUBLIC_WORKFLOW_REGISTRY_PROJECTION, PUBLIC_SLOPCAMERA_WORKFLOW_PROJECTION, WORKFLOW_GRAPH_HASH_DOMAIN, WORKFLOW_COMPILATION_HASH_DOMAIN, DEFAULT_GRAPH_COMPILER_LIMITS, normalizeAuthoredWorkflowGraph, createWorkflowGraphHash, createGraphHash, createWorkflowCompilationHash, compileWorkflowGraph, parseCompiledWorkflowGraph, defineWorkflowFragment, operationContract, WorkflowGraphBuilder, definePortableWorkflowFragment, PortableWorkflowBuilder, defineWorkflow, buildWorkflow, buildWorkflowGraph, defineCompute, defineAdvancedWorkflow, buildAdvancedWorkflow, seconds, WORKFLOW_NODE_RECEIPT_VERSION, WORKFLOW_NODE_RECEIPT_HASH_DOMAIN, MAX_WORKFLOW_RESULT_BYTES, MAX_WORKFLOW_RESULT_DEPTH, MAX_WORKFLOW_RESULT_VALUES, createSlopcameraCodeHost, SlopcameraWorkflowRunError, runBuiltWorkflow, runWorkflow };
|