sdn-flow 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/SKILLS.md +7 -0
- package/.claude/skills/sdn-plugin-abi-compliance/SKILL.md +56 -0
- package/.claude/todo/001-js-host-startup-and-deno.md +85 -0
- package/LICENSE +21 -0
- package/README.md +223 -0
- package/bin/sdn-flow-host.js +169 -0
- package/docs/.nojekyll +0 -0
- package/docs/ARCHITECTURE.md +200 -0
- package/docs/HOST_CAPABILITY_MODEL.md +317 -0
- package/docs/PLUGIN_ARCHITECTURE.md +145 -0
- package/docs/PLUGIN_COMPATIBILITY.md +61 -0
- package/docs/PLUGIN_COMPLIANCE_CHECKS.md +82 -0
- package/docs/PLUGIN_MANIFEST.md +94 -0
- package/docs/css/style.css +465 -0
- package/docs/index.html +218 -0
- package/docs/js/app.mjs +751 -0
- package/docs/js/editor-panel.mjs +203 -0
- package/docs/js/flow-canvas.mjs +515 -0
- package/docs/js/flow-model.mjs +391 -0
- package/docs/js/workers/emception.worker.js +146 -0
- package/docs/js/workers/pyodide.worker.js +134 -0
- package/native/flow_source_generator.cpp +1958 -0
- package/package.json +67 -0
- package/schemas/FlowRuntimeAbi.fbs +91 -0
- package/src/auth/canonicalize.js +5 -0
- package/src/auth/index.js +11 -0
- package/src/auth/permissions.js +8 -0
- package/src/compiler/CppFlowSourceGenerator.js +475 -0
- package/src/compiler/EmceptionCompilerAdapter.js +244 -0
- package/src/compiler/SignedArtifactCatalog.js +152 -0
- package/src/compiler/index.js +8 -0
- package/src/compiler/nativeFlowSourceGeneratorTool.js +144 -0
- package/src/compliance/index.js +13 -0
- package/src/compliance/pluginCompliance.js +11 -0
- package/src/deploy/FlowDeploymentClient.js +532 -0
- package/src/deploy/index.js +8 -0
- package/src/designer/FlowDesignerSession.js +158 -0
- package/src/designer/index.js +2 -0
- package/src/designer/requirements.js +184 -0
- package/src/generated/runtimeAbiLayouts.js +544 -0
- package/src/host/appHost.js +105 -0
- package/src/host/autoHost.js +113 -0
- package/src/host/browserHostAdapters.js +108 -0
- package/src/host/compiledFlowRuntimeHost.js +703 -0
- package/src/host/constants.js +55 -0
- package/src/host/dependencyRuntime.js +227 -0
- package/src/host/descriptorAbi.js +351 -0
- package/src/host/fetchService.js +237 -0
- package/src/host/httpHostAdapters.js +280 -0
- package/src/host/index.js +91 -0
- package/src/host/installedFlowHost.js +885 -0
- package/src/host/invocationAbi.js +440 -0
- package/src/host/normalize.js +372 -0
- package/src/host/packageManagers.js +369 -0
- package/src/host/profile.js +134 -0
- package/src/host/runtimeAbi.js +106 -0
- package/src/host/workspace.js +895 -0
- package/src/index.js +8 -0
- package/src/runtime/FlowRuntime.js +273 -0
- package/src/runtime/MethodRegistry.js +295 -0
- package/src/runtime/constants.js +44 -0
- package/src/runtime/index.js +19 -0
- package/src/runtime/normalize.js +377 -0
- package/src/transport/index.js +7 -0
- package/src/transport/pki.js +7 -0
- package/src/utils/crypto.js +7 -0
- package/src/utils/encoding.js +65 -0
- package/src/utils/wasmCrypto.js +69 -0
- package/tools/run-plugin-compliance-check.mjs +153 -0
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
import { bindCompiledInvocationAbi } from "./invocationAbi.js";
|
|
2
|
+
import { bindCompiledDescriptorAbi } from "./descriptorAbi.js";
|
|
3
|
+
import { instantiateEmbeddedDependencies } from "./dependencyRuntime.js";
|
|
4
|
+
|
|
5
|
+
const INVALID_INDEX = 0xffffffff;
|
|
6
|
+
|
|
7
|
+
function getInstantiatedExports(target = null) {
|
|
8
|
+
if (
|
|
9
|
+
target?.instance?.exports &&
|
|
10
|
+
typeof target.instance.exports === "object"
|
|
11
|
+
) {
|
|
12
|
+
return target.instance.exports;
|
|
13
|
+
}
|
|
14
|
+
if (target?.exports && typeof target.exports === "object") {
|
|
15
|
+
return target.exports;
|
|
16
|
+
}
|
|
17
|
+
if (target && typeof target === "object") {
|
|
18
|
+
return target;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function mergeImportObjects(base = {}, extra = {}) {
|
|
24
|
+
const merged = { ...(base ?? {}) };
|
|
25
|
+
for (const [moduleName, moduleValue] of Object.entries(extra ?? {})) {
|
|
26
|
+
const existing = merged[moduleName];
|
|
27
|
+
if (
|
|
28
|
+
existing &&
|
|
29
|
+
typeof existing === "object" &&
|
|
30
|
+
!Array.isArray(existing) &&
|
|
31
|
+
moduleValue &&
|
|
32
|
+
typeof moduleValue === "object" &&
|
|
33
|
+
!Array.isArray(moduleValue)
|
|
34
|
+
) {
|
|
35
|
+
merged[moduleName] = {
|
|
36
|
+
...existing,
|
|
37
|
+
...moduleValue,
|
|
38
|
+
};
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
merged[moduleName] = moduleValue;
|
|
42
|
+
}
|
|
43
|
+
return merged;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function resolveArtifactImportObject(
|
|
47
|
+
imports,
|
|
48
|
+
artifact,
|
|
49
|
+
additionalImports = {},
|
|
50
|
+
) {
|
|
51
|
+
if (typeof imports === "function") {
|
|
52
|
+
return mergeImportObjects(imports(artifact) ?? {}, additionalImports);
|
|
53
|
+
}
|
|
54
|
+
if (imports instanceof Map) {
|
|
55
|
+
return mergeImportObjects(
|
|
56
|
+
imports.get(artifact?.programId) ??
|
|
57
|
+
imports.get(artifact?.artifactId) ??
|
|
58
|
+
imports.get("default") ??
|
|
59
|
+
{},
|
|
60
|
+
additionalImports,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
if (imports && typeof imports === "object") {
|
|
64
|
+
if (
|
|
65
|
+
"env" in imports ||
|
|
66
|
+
"wasi_snapshot_preview1" in imports ||
|
|
67
|
+
"default" in imports
|
|
68
|
+
) {
|
|
69
|
+
return mergeImportObjects(imports, additionalImports);
|
|
70
|
+
}
|
|
71
|
+
return mergeImportObjects(
|
|
72
|
+
imports[artifact?.programId] ??
|
|
73
|
+
imports[artifact?.artifactId] ??
|
|
74
|
+
imports.default ??
|
|
75
|
+
{},
|
|
76
|
+
additionalImports,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
return mergeImportObjects({}, additionalImports);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function resolveNamedExport(exports, symbol) {
|
|
83
|
+
if (!symbol || !exports || typeof exports !== "object") {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
if (typeof exports[symbol] === "function") {
|
|
87
|
+
return {
|
|
88
|
+
name: symbol,
|
|
89
|
+
value: exports[symbol],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const underscored = `_${symbol}`;
|
|
93
|
+
if (typeof exports[underscored] === "function") {
|
|
94
|
+
return {
|
|
95
|
+
name: underscored,
|
|
96
|
+
value: exports[underscored],
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function writeCString(memory, pointer, value) {
|
|
103
|
+
const bytes = new Uint8Array(memory.buffer);
|
|
104
|
+
const encoded = new TextEncoder().encode(`${String(value ?? "")}\0`);
|
|
105
|
+
bytes.set(encoded, Number(pointer) >>> 0);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function allocateCString(bound, memory, value) {
|
|
109
|
+
const encoded = new TextEncoder().encode(`${String(value ?? "")}\0`);
|
|
110
|
+
const pointer =
|
|
111
|
+
Number(bound.resolvedByRole.mallocSymbol(encoded.length)) >>> 0;
|
|
112
|
+
writeCString(memory, pointer, value);
|
|
113
|
+
return pointer;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function allocateArgv(bound, memory, argv = []) {
|
|
117
|
+
const pointers = argv.map((value) => allocateCString(bound, memory, value));
|
|
118
|
+
const argvPointer =
|
|
119
|
+
Number(bound.resolvedByRole.mallocSymbol((pointers.length + 1) * 4)) >>> 0;
|
|
120
|
+
const view = new DataView(memory.buffer);
|
|
121
|
+
pointers.forEach((pointer, index) => {
|
|
122
|
+
view.setUint32(argvPointer + index * 4, pointer, true);
|
|
123
|
+
});
|
|
124
|
+
view.setUint32(argvPointer + pointers.length * 4, 0, true);
|
|
125
|
+
return {
|
|
126
|
+
argvPointer,
|
|
127
|
+
stringPointers: pointers,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function releaseArgv(bound, allocation = null) {
|
|
132
|
+
if (!allocation) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
for (const pointer of allocation.stringPointers ?? []) {
|
|
136
|
+
bound.resolvedByRole.freeSymbol(pointer);
|
|
137
|
+
}
|
|
138
|
+
if (allocation.argvPointer) {
|
|
139
|
+
bound.resolvedByRole.freeSymbol(allocation.argvPointer);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function resolveCompiledArtifactRuntime({
|
|
144
|
+
artifact,
|
|
145
|
+
instance = null,
|
|
146
|
+
wasmExports = null,
|
|
147
|
+
artifactImports = {},
|
|
148
|
+
internalImports = {},
|
|
149
|
+
instantiateArtifact = WebAssembly.instantiate,
|
|
150
|
+
} = {}) {
|
|
151
|
+
if (instance || wasmExports) {
|
|
152
|
+
return {
|
|
153
|
+
instance,
|
|
154
|
+
wasmExports,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (!(artifact?.wasm instanceof Uint8Array)) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
"Compiled flow host requires artifact.wasm bytes when no instance or wasmExports are supplied.",
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
if (typeof instantiateArtifact !== "function") {
|
|
163
|
+
throw new TypeError(
|
|
164
|
+
"bindCompiledFlowRuntimeHost requires instantiateArtifact to be a function when instantiating the root artifact.",
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
const instantiated = await instantiateArtifact(
|
|
168
|
+
artifact.wasm,
|
|
169
|
+
resolveArtifactImportObject(artifactImports, artifact, internalImports),
|
|
170
|
+
);
|
|
171
|
+
return {
|
|
172
|
+
instance: instantiated?.instance ?? instantiated ?? null,
|
|
173
|
+
wasmExports: getInstantiatedExports(instantiated),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function normalizeHandlers(handlers = {}) {
|
|
178
|
+
if (handlers instanceof Map) {
|
|
179
|
+
return handlers;
|
|
180
|
+
}
|
|
181
|
+
return new Map(Object.entries(handlers));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function createHandlerKeys({
|
|
185
|
+
pluginId = null,
|
|
186
|
+
methodId = null,
|
|
187
|
+
dependencyId = null,
|
|
188
|
+
nodeId = null,
|
|
189
|
+
} = {}) {
|
|
190
|
+
return [
|
|
191
|
+
dependencyId && methodId ? `${dependencyId}:${methodId}` : null,
|
|
192
|
+
pluginId && methodId ? `${pluginId}:${methodId}` : null,
|
|
193
|
+
nodeId && methodId ? `${nodeId}:${methodId}` : null,
|
|
194
|
+
dependencyId,
|
|
195
|
+
pluginId,
|
|
196
|
+
nodeId,
|
|
197
|
+
methodId,
|
|
198
|
+
].filter(Boolean);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function resolveHandler(
|
|
202
|
+
handlers,
|
|
203
|
+
{ pluginId = null, methodId = null, dependencyId = null, nodeId = null } = {},
|
|
204
|
+
) {
|
|
205
|
+
for (const key of createHandlerKeys({
|
|
206
|
+
pluginId,
|
|
207
|
+
methodId,
|
|
208
|
+
dependencyId,
|
|
209
|
+
nodeId,
|
|
210
|
+
})) {
|
|
211
|
+
if (handlers.has(key)) {
|
|
212
|
+
return handlers.get(key);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function isPromiseLike(value) {
|
|
219
|
+
return (
|
|
220
|
+
value !== null &&
|
|
221
|
+
typeof value === "object" &&
|
|
222
|
+
typeof value.then === "function"
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function resolveInvocationBinding(host, invocation = null) {
|
|
227
|
+
const dispatchDescriptor =
|
|
228
|
+
invocation?.dispatchDescriptorIndex === INVALID_INDEX
|
|
229
|
+
? null
|
|
230
|
+
: host.readNodeDispatchDescriptorAt(invocation?.dispatchDescriptorIndex);
|
|
231
|
+
const dependencyDescriptor =
|
|
232
|
+
dispatchDescriptor?.dependencyIndex === INVALID_INDEX
|
|
233
|
+
? null
|
|
234
|
+
: host.readDependencyDescriptorAt(dispatchDescriptor?.dependencyIndex);
|
|
235
|
+
return {
|
|
236
|
+
dispatchDescriptor,
|
|
237
|
+
dependencyDescriptor,
|
|
238
|
+
handler: host.findHandler({
|
|
239
|
+
pluginId: invocation?.pluginId,
|
|
240
|
+
methodId: invocation?.methodId,
|
|
241
|
+
dependencyId:
|
|
242
|
+
dispatchDescriptor?.dependencyId ?? dependencyDescriptor?.dependencyId,
|
|
243
|
+
nodeId: dispatchDescriptor?.nodeId ?? null,
|
|
244
|
+
}),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async function executeCurrentInvocationInternal(
|
|
249
|
+
host,
|
|
250
|
+
{
|
|
251
|
+
nodeIndex = INVALID_INDEX,
|
|
252
|
+
outputStreamCap = 16,
|
|
253
|
+
consumed = 0,
|
|
254
|
+
dependencyInvoker = null,
|
|
255
|
+
dependencyStreamBridge = null,
|
|
256
|
+
} = {},
|
|
257
|
+
) {
|
|
258
|
+
const invocation = host.readCurrentInvocation();
|
|
259
|
+
const { dispatchDescriptor, dependencyDescriptor, handler } =
|
|
260
|
+
resolveInvocationBinding(host, invocation);
|
|
261
|
+
const instantiatedDependency =
|
|
262
|
+
(typeof dependencyInvoker === "function" ||
|
|
263
|
+
typeof dependencyStreamBridge === "function") &&
|
|
264
|
+
dependencyDescriptor
|
|
265
|
+
? await host.getInstantiatedDependency({
|
|
266
|
+
dependencyId:
|
|
267
|
+
dispatchDescriptor?.dependencyId ??
|
|
268
|
+
dependencyDescriptor?.dependencyId,
|
|
269
|
+
pluginId: invocation?.pluginId,
|
|
270
|
+
dependencyIndex:
|
|
271
|
+
dispatchDescriptor?.dependencyIndex ??
|
|
272
|
+
dependencyDescriptor?.dependencyIndex,
|
|
273
|
+
})
|
|
274
|
+
: null;
|
|
275
|
+
|
|
276
|
+
if (
|
|
277
|
+
typeof handler !== "function" &&
|
|
278
|
+
typeof dependencyInvoker !== "function" &&
|
|
279
|
+
typeof dependencyStreamBridge !== "function"
|
|
280
|
+
) {
|
|
281
|
+
throw new Error(
|
|
282
|
+
`No compiled flow host handler is registered for ${invocation?.pluginId}:${invocation?.methodId}.`,
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const inputs = (invocation.frames ?? []).map((frame) => ({
|
|
287
|
+
...frame,
|
|
288
|
+
bytes: host.readFrameBytes(frame),
|
|
289
|
+
}));
|
|
290
|
+
const invocationArgs = {
|
|
291
|
+
nodeIndex,
|
|
292
|
+
pluginId: invocation?.pluginId,
|
|
293
|
+
methodId: invocation?.methodId,
|
|
294
|
+
dispatchDescriptor,
|
|
295
|
+
dependencyDescriptor,
|
|
296
|
+
instantiatedDependency,
|
|
297
|
+
inputs,
|
|
298
|
+
outputStreamCap,
|
|
299
|
+
invocation,
|
|
300
|
+
};
|
|
301
|
+
const result =
|
|
302
|
+
typeof handler === "function"
|
|
303
|
+
? await handler(invocationArgs)
|
|
304
|
+
: typeof dependencyInvoker === "function"
|
|
305
|
+
? await dependencyInvoker(invocationArgs)
|
|
306
|
+
: await dependencyStreamBridge(invocationArgs);
|
|
307
|
+
const routedOutputs = Number(
|
|
308
|
+
host.applyNodeInvocationResult(nodeIndex, {
|
|
309
|
+
statusCode:
|
|
310
|
+
result?.statusCode ?? result?.status_code ?? result?.errorCode ?? 0,
|
|
311
|
+
backlogRemaining:
|
|
312
|
+
result?.backlogRemaining ?? result?.backlog_remaining ?? 0,
|
|
313
|
+
yielded: result?.yielded ?? false,
|
|
314
|
+
outputs: result?.outputs ?? [],
|
|
315
|
+
}),
|
|
316
|
+
);
|
|
317
|
+
return {
|
|
318
|
+
executed: true,
|
|
319
|
+
idle: false,
|
|
320
|
+
nodeIndex,
|
|
321
|
+
pluginId: invocation?.pluginId,
|
|
322
|
+
methodId: invocation?.methodId,
|
|
323
|
+
dispatchDescriptor,
|
|
324
|
+
dependencyDescriptor,
|
|
325
|
+
instantiatedDependency,
|
|
326
|
+
consumed,
|
|
327
|
+
routedOutputs,
|
|
328
|
+
outputs: result?.outputs ?? [],
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export async function bindCompiledFlowRuntimeHost({
|
|
333
|
+
artifact,
|
|
334
|
+
instance = null,
|
|
335
|
+
wasmExports = null,
|
|
336
|
+
memory = null,
|
|
337
|
+
artifactImports = {},
|
|
338
|
+
instantiateArtifact = WebAssembly.instantiate,
|
|
339
|
+
handlers = {},
|
|
340
|
+
dependencyInvoker = null,
|
|
341
|
+
dependencyStreamBridge = null,
|
|
342
|
+
dependencyImports = {},
|
|
343
|
+
instantiateDependency = WebAssembly.instantiate,
|
|
344
|
+
} = {}) {
|
|
345
|
+
const hostContext = {
|
|
346
|
+
current: null,
|
|
347
|
+
};
|
|
348
|
+
const internalImports = {
|
|
349
|
+
sdn_flow_host: {
|
|
350
|
+
dispatch_current_invocation(outputStreamCap = 16) {
|
|
351
|
+
const currentHost = hostContext.current;
|
|
352
|
+
if (!currentHost) {
|
|
353
|
+
throw new Error(
|
|
354
|
+
"Compiled flow host dispatch import was called before host initialization completed.",
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
return (
|
|
358
|
+
Number(
|
|
359
|
+
currentHost.dispatchCurrentInvocation({
|
|
360
|
+
outputStreamCap: Number(outputStreamCap) >>> 0,
|
|
361
|
+
}),
|
|
362
|
+
) >>> 0
|
|
363
|
+
);
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
const resolvedRuntime = await resolveCompiledArtifactRuntime({
|
|
368
|
+
artifact,
|
|
369
|
+
instance,
|
|
370
|
+
wasmExports,
|
|
371
|
+
artifactImports,
|
|
372
|
+
internalImports,
|
|
373
|
+
instantiateArtifact,
|
|
374
|
+
});
|
|
375
|
+
const resolvedInstance = resolvedRuntime.instance ?? instance;
|
|
376
|
+
const resolvedWasmExports = resolvedRuntime.wasmExports ?? wasmExports;
|
|
377
|
+
const resolvedMemory = memory ?? resolvedWasmExports?.memory ?? null;
|
|
378
|
+
const [bound, descriptors] = await Promise.all([
|
|
379
|
+
bindCompiledInvocationAbi({
|
|
380
|
+
artifact,
|
|
381
|
+
instance: resolvedInstance,
|
|
382
|
+
wasmExports: resolvedWasmExports,
|
|
383
|
+
memory: resolvedMemory,
|
|
384
|
+
}),
|
|
385
|
+
bindCompiledDescriptorAbi({
|
|
386
|
+
artifact,
|
|
387
|
+
instance: resolvedInstance,
|
|
388
|
+
wasmExports: resolvedWasmExports,
|
|
389
|
+
memory: resolvedMemory,
|
|
390
|
+
}),
|
|
391
|
+
]);
|
|
392
|
+
const normalizedHandlers = normalizeHandlers(handlers);
|
|
393
|
+
let dependencyRuntime = null;
|
|
394
|
+
|
|
395
|
+
async function getDependencyRuntime() {
|
|
396
|
+
if (!dependencyRuntime) {
|
|
397
|
+
dependencyRuntime = await instantiateEmbeddedDependencies({
|
|
398
|
+
artifact,
|
|
399
|
+
instance: resolvedInstance,
|
|
400
|
+
wasmExports: resolvedWasmExports,
|
|
401
|
+
memory: resolvedMemory,
|
|
402
|
+
imports: dependencyImports,
|
|
403
|
+
instantiate: instantiateDependency,
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
return dependencyRuntime;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
const host = {
|
|
410
|
+
...bound,
|
|
411
|
+
descriptors,
|
|
412
|
+
handlers: normalizedHandlers,
|
|
413
|
+
instance: resolvedInstance,
|
|
414
|
+
wasmExports: resolvedWasmExports,
|
|
415
|
+
memory: resolvedMemory,
|
|
416
|
+
artifactImports: resolveArtifactImportObject(
|
|
417
|
+
artifactImports,
|
|
418
|
+
artifact,
|
|
419
|
+
internalImports,
|
|
420
|
+
),
|
|
421
|
+
instantiateArtifact,
|
|
422
|
+
dependencyInvoker,
|
|
423
|
+
dependencyStreamBridge,
|
|
424
|
+
dependencyImports,
|
|
425
|
+
resolveEntrypoint(entrypoint = artifact?.entrypoint ?? "main") {
|
|
426
|
+
return resolveNamedExport(resolvedWasmExports, entrypoint);
|
|
427
|
+
},
|
|
428
|
+
runEntrypoint({
|
|
429
|
+
entrypoint = artifact?.entrypoint ?? "main",
|
|
430
|
+
args = [],
|
|
431
|
+
argv = null,
|
|
432
|
+
programName = artifact?.programId ??
|
|
433
|
+
artifact?.artifactId ??
|
|
434
|
+
"flow-runtime",
|
|
435
|
+
} = {}) {
|
|
436
|
+
const resolvedEntrypoint = this.resolveEntrypoint(entrypoint);
|
|
437
|
+
if (!resolvedEntrypoint) {
|
|
438
|
+
throw new Error(
|
|
439
|
+
`Compiled flow host entrypoint "${entrypoint}" is not present on the instantiated runtime.`,
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
if (
|
|
443
|
+
resolvedEntrypoint.name === "_start" ||
|
|
444
|
+
resolvedEntrypoint.name === "start" ||
|
|
445
|
+
resolvedEntrypoint.value.length === 0
|
|
446
|
+
) {
|
|
447
|
+
return {
|
|
448
|
+
entrypoint: resolvedEntrypoint.name,
|
|
449
|
+
argc: 0,
|
|
450
|
+
argv: [],
|
|
451
|
+
exitCode: Number(resolvedEntrypoint.value() ?? 0),
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
const normalizedArgv = Array.isArray(argv)
|
|
456
|
+
? argv.map((value) => String(value))
|
|
457
|
+
: [String(programName), ...args.map((value) => String(value))];
|
|
458
|
+
const allocation = allocateArgv(bound, resolvedMemory, normalizedArgv);
|
|
459
|
+
try {
|
|
460
|
+
const exitCode = Number(
|
|
461
|
+
resolvedEntrypoint.value(
|
|
462
|
+
normalizedArgv.length,
|
|
463
|
+
allocation.argvPointer,
|
|
464
|
+
) ?? 0,
|
|
465
|
+
);
|
|
466
|
+
return {
|
|
467
|
+
entrypoint: resolvedEntrypoint.name,
|
|
468
|
+
argc: normalizedArgv.length,
|
|
469
|
+
argv: normalizedArgv,
|
|
470
|
+
exitCode,
|
|
471
|
+
};
|
|
472
|
+
} finally {
|
|
473
|
+
releaseArgv(bound, allocation);
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
readNodeDispatchDescriptorAt(index) {
|
|
477
|
+
return descriptors.readNodeDispatchDescriptorAt(index);
|
|
478
|
+
},
|
|
479
|
+
readDependencyDescriptorAt(index) {
|
|
480
|
+
return descriptors.readDependencyDescriptorAt(index);
|
|
481
|
+
},
|
|
482
|
+
findHandler(binding = {}) {
|
|
483
|
+
return resolveHandler(normalizedHandlers, binding);
|
|
484
|
+
},
|
|
485
|
+
async instantiateDependencies() {
|
|
486
|
+
return getDependencyRuntime();
|
|
487
|
+
},
|
|
488
|
+
async destroyDependencies(...args) {
|
|
489
|
+
const runtime = await getDependencyRuntime();
|
|
490
|
+
return runtime.destroyAll(...args);
|
|
491
|
+
},
|
|
492
|
+
getInstantiatedDependencySync(binding = {}) {
|
|
493
|
+
if (!dependencyRuntime) {
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
return dependencyRuntime.getDependency(binding);
|
|
497
|
+
},
|
|
498
|
+
async getInstantiatedDependency(binding = {}) {
|
|
499
|
+
const runtime = await getDependencyRuntime();
|
|
500
|
+
return runtime.getDependency(binding);
|
|
501
|
+
},
|
|
502
|
+
dispatchCurrentInvocation({ outputStreamCap = 16 } = {}) {
|
|
503
|
+
const nodeIndex =
|
|
504
|
+
this.readCurrentInvocation()?.nodeIndex ?? INVALID_INDEX;
|
|
505
|
+
const invocation = this.readCurrentInvocation();
|
|
506
|
+
const { dispatchDescriptor, dependencyDescriptor, handler } =
|
|
507
|
+
resolveInvocationBinding(this, invocation);
|
|
508
|
+
const instantiatedDependency =
|
|
509
|
+
(typeof dependencyInvoker === "function" ||
|
|
510
|
+
typeof dependencyStreamBridge === "function") &&
|
|
511
|
+
dependencyDescriptor
|
|
512
|
+
? this.getInstantiatedDependencySync({
|
|
513
|
+
dependencyId:
|
|
514
|
+
dispatchDescriptor?.dependencyId ??
|
|
515
|
+
dependencyDescriptor?.dependencyId,
|
|
516
|
+
pluginId: invocation?.pluginId,
|
|
517
|
+
dependencyIndex:
|
|
518
|
+
dispatchDescriptor?.dependencyIndex ??
|
|
519
|
+
dependencyDescriptor?.dependencyIndex,
|
|
520
|
+
})
|
|
521
|
+
: null;
|
|
522
|
+
|
|
523
|
+
if (
|
|
524
|
+
typeof handler !== "function" &&
|
|
525
|
+
typeof dependencyInvoker !== "function" &&
|
|
526
|
+
typeof dependencyStreamBridge !== "function"
|
|
527
|
+
) {
|
|
528
|
+
throw new Error(
|
|
529
|
+
`No compiled flow host handler is registered for ${invocation?.pluginId}:${invocation?.methodId}.`,
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
if (
|
|
533
|
+
dependencyDescriptor &&
|
|
534
|
+
(typeof dependencyInvoker === "function" ||
|
|
535
|
+
typeof dependencyStreamBridge === "function") &&
|
|
536
|
+
!instantiatedDependency
|
|
537
|
+
) {
|
|
538
|
+
throw new Error(
|
|
539
|
+
"Compiled flow host dispatch import requires dependencies to be instantiated before in-module dispatch.",
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const inputs = (invocation?.frames ?? []).map((frame) => ({
|
|
544
|
+
...frame,
|
|
545
|
+
bytes: this.readFrameBytes(frame),
|
|
546
|
+
}));
|
|
547
|
+
const invocationArgs = {
|
|
548
|
+
nodeIndex,
|
|
549
|
+
pluginId: invocation?.pluginId,
|
|
550
|
+
methodId: invocation?.methodId,
|
|
551
|
+
dispatchDescriptor,
|
|
552
|
+
dependencyDescriptor,
|
|
553
|
+
instantiatedDependency,
|
|
554
|
+
inputs,
|
|
555
|
+
outputStreamCap,
|
|
556
|
+
invocation,
|
|
557
|
+
};
|
|
558
|
+
const result =
|
|
559
|
+
typeof handler === "function"
|
|
560
|
+
? handler(invocationArgs)
|
|
561
|
+
: typeof dependencyInvoker === "function"
|
|
562
|
+
? dependencyInvoker(invocationArgs)
|
|
563
|
+
: dependencyStreamBridge(invocationArgs);
|
|
564
|
+
if (isPromiseLike(result)) {
|
|
565
|
+
throw new Error(
|
|
566
|
+
"Compiled flow host in-module dispatch currently requires synchronous handlers/dependency bridges.",
|
|
567
|
+
);
|
|
568
|
+
}
|
|
569
|
+
return Number(
|
|
570
|
+
this.applyNodeInvocationResult(nodeIndex, {
|
|
571
|
+
statusCode:
|
|
572
|
+
result?.statusCode ?? result?.status_code ?? result?.errorCode ?? 0,
|
|
573
|
+
backlogRemaining:
|
|
574
|
+
result?.backlogRemaining ?? result?.backlog_remaining ?? 0,
|
|
575
|
+
yielded: result?.yielded ?? false,
|
|
576
|
+
outputs: result?.outputs ?? [],
|
|
577
|
+
}),
|
|
578
|
+
);
|
|
579
|
+
},
|
|
580
|
+
async executeNextReadyNode({ frameBudget = 1, outputStreamCap = 16 } = {}) {
|
|
581
|
+
const nodeIndex = Number(bound.resolvedByRole.readyNodeSymbol()) >>> 0;
|
|
582
|
+
if (nodeIndex === INVALID_INDEX) {
|
|
583
|
+
return {
|
|
584
|
+
executed: false,
|
|
585
|
+
idle: true,
|
|
586
|
+
nodeIndex,
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
const consumed = Number(
|
|
590
|
+
bound.resolvedByRole.beginInvocationSymbol(nodeIndex, frameBudget),
|
|
591
|
+
);
|
|
592
|
+
return executeCurrentInvocationInternal(this, {
|
|
593
|
+
nodeIndex,
|
|
594
|
+
outputStreamCap,
|
|
595
|
+
consumed,
|
|
596
|
+
dependencyInvoker,
|
|
597
|
+
dependencyStreamBridge,
|
|
598
|
+
});
|
|
599
|
+
},
|
|
600
|
+
async dispatchNextReadyNodeWithHost({
|
|
601
|
+
frameBudget = 1,
|
|
602
|
+
outputStreamCap = 16,
|
|
603
|
+
} = {}) {
|
|
604
|
+
const drainExport = this.resolveEntrypoint(
|
|
605
|
+
artifact?.runtimeExports?.dispatchHostInvocationSymbol ??
|
|
606
|
+
"sdn_flow_dispatch_next_ready_node_with_host",
|
|
607
|
+
);
|
|
608
|
+
if (!drainExport) {
|
|
609
|
+
return this.executeNextReadyNode({
|
|
610
|
+
frameBudget,
|
|
611
|
+
outputStreamCap,
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
const nodeIndex =
|
|
615
|
+
Number(
|
|
616
|
+
drainExport.value(frameBudget, outputStreamCap) ?? INVALID_INDEX,
|
|
617
|
+
) >>> 0;
|
|
618
|
+
if (nodeIndex === INVALID_INDEX) {
|
|
619
|
+
return {
|
|
620
|
+
executed: false,
|
|
621
|
+
idle: true,
|
|
622
|
+
nodeIndex,
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
const invocation = this.readCurrentInvocation();
|
|
626
|
+
const { dispatchDescriptor, dependencyDescriptor } =
|
|
627
|
+
resolveInvocationBinding(this, invocation);
|
|
628
|
+
return {
|
|
629
|
+
executed: true,
|
|
630
|
+
idle: false,
|
|
631
|
+
nodeIndex,
|
|
632
|
+
pluginId: invocation?.pluginId ?? null,
|
|
633
|
+
methodId: invocation?.methodId ?? null,
|
|
634
|
+
dispatchDescriptor,
|
|
635
|
+
dependencyDescriptor,
|
|
636
|
+
};
|
|
637
|
+
},
|
|
638
|
+
async drainWithHostDispatch({
|
|
639
|
+
frameBudget = 1,
|
|
640
|
+
outputStreamCap = 16,
|
|
641
|
+
maxIterations = 1024,
|
|
642
|
+
} = {}) {
|
|
643
|
+
const drainExport = this.resolveEntrypoint(
|
|
644
|
+
artifact?.runtimeExports?.drainWithHostDispatchSymbol ??
|
|
645
|
+
"sdn_flow_drain_with_host_dispatch",
|
|
646
|
+
);
|
|
647
|
+
if (!drainExport) {
|
|
648
|
+
return this.drain({
|
|
649
|
+
frameBudget,
|
|
650
|
+
outputStreamCap,
|
|
651
|
+
maxIterations,
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
const iterations =
|
|
655
|
+
Number(
|
|
656
|
+
drainExport.value(frameBudget, outputStreamCap, maxIterations) ?? 0,
|
|
657
|
+
) >>> 0;
|
|
658
|
+
return {
|
|
659
|
+
idle:
|
|
660
|
+
Number(bound.resolvedByRole.readyNodeSymbol()) >>> 0 ===
|
|
661
|
+
INVALID_INDEX,
|
|
662
|
+
iterations,
|
|
663
|
+
};
|
|
664
|
+
},
|
|
665
|
+
async drain({
|
|
666
|
+
frameBudget = 1,
|
|
667
|
+
outputStreamCap = 16,
|
|
668
|
+
maxIterations = 1024,
|
|
669
|
+
} = {}) {
|
|
670
|
+
const executions = [];
|
|
671
|
+
for (let iteration = 0; iteration < maxIterations; iteration += 1) {
|
|
672
|
+
const execution = await this.executeNextReadyNode({
|
|
673
|
+
frameBudget,
|
|
674
|
+
outputStreamCap,
|
|
675
|
+
});
|
|
676
|
+
if (!execution.executed) {
|
|
677
|
+
return {
|
|
678
|
+
idle: execution.idle,
|
|
679
|
+
iterations: executions.length,
|
|
680
|
+
executions,
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
executions.push(execution);
|
|
684
|
+
}
|
|
685
|
+
return {
|
|
686
|
+
idle: false,
|
|
687
|
+
iterations: executions.length,
|
|
688
|
+
executions,
|
|
689
|
+
maxIterationsReached: true,
|
|
690
|
+
};
|
|
691
|
+
},
|
|
692
|
+
};
|
|
693
|
+
if (
|
|
694
|
+
typeof dependencyInvoker === "function" ||
|
|
695
|
+
typeof dependencyStreamBridge === "function"
|
|
696
|
+
) {
|
|
697
|
+
await getDependencyRuntime();
|
|
698
|
+
}
|
|
699
|
+
hostContext.current = host;
|
|
700
|
+
return host;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
export default bindCompiledFlowRuntimeHost;
|