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.
Files changed (69) hide show
  1. package/.claude/SKILLS.md +7 -0
  2. package/.claude/skills/sdn-plugin-abi-compliance/SKILL.md +56 -0
  3. package/.claude/todo/001-js-host-startup-and-deno.md +85 -0
  4. package/LICENSE +21 -0
  5. package/README.md +223 -0
  6. package/bin/sdn-flow-host.js +169 -0
  7. package/docs/.nojekyll +0 -0
  8. package/docs/ARCHITECTURE.md +200 -0
  9. package/docs/HOST_CAPABILITY_MODEL.md +317 -0
  10. package/docs/PLUGIN_ARCHITECTURE.md +145 -0
  11. package/docs/PLUGIN_COMPATIBILITY.md +61 -0
  12. package/docs/PLUGIN_COMPLIANCE_CHECKS.md +82 -0
  13. package/docs/PLUGIN_MANIFEST.md +94 -0
  14. package/docs/css/style.css +465 -0
  15. package/docs/index.html +218 -0
  16. package/docs/js/app.mjs +751 -0
  17. package/docs/js/editor-panel.mjs +203 -0
  18. package/docs/js/flow-canvas.mjs +515 -0
  19. package/docs/js/flow-model.mjs +391 -0
  20. package/docs/js/workers/emception.worker.js +146 -0
  21. package/docs/js/workers/pyodide.worker.js +134 -0
  22. package/native/flow_source_generator.cpp +1958 -0
  23. package/package.json +67 -0
  24. package/schemas/FlowRuntimeAbi.fbs +91 -0
  25. package/src/auth/canonicalize.js +5 -0
  26. package/src/auth/index.js +11 -0
  27. package/src/auth/permissions.js +8 -0
  28. package/src/compiler/CppFlowSourceGenerator.js +475 -0
  29. package/src/compiler/EmceptionCompilerAdapter.js +244 -0
  30. package/src/compiler/SignedArtifactCatalog.js +152 -0
  31. package/src/compiler/index.js +8 -0
  32. package/src/compiler/nativeFlowSourceGeneratorTool.js +144 -0
  33. package/src/compliance/index.js +13 -0
  34. package/src/compliance/pluginCompliance.js +11 -0
  35. package/src/deploy/FlowDeploymentClient.js +532 -0
  36. package/src/deploy/index.js +8 -0
  37. package/src/designer/FlowDesignerSession.js +158 -0
  38. package/src/designer/index.js +2 -0
  39. package/src/designer/requirements.js +184 -0
  40. package/src/generated/runtimeAbiLayouts.js +544 -0
  41. package/src/host/appHost.js +105 -0
  42. package/src/host/autoHost.js +113 -0
  43. package/src/host/browserHostAdapters.js +108 -0
  44. package/src/host/compiledFlowRuntimeHost.js +703 -0
  45. package/src/host/constants.js +55 -0
  46. package/src/host/dependencyRuntime.js +227 -0
  47. package/src/host/descriptorAbi.js +351 -0
  48. package/src/host/fetchService.js +237 -0
  49. package/src/host/httpHostAdapters.js +280 -0
  50. package/src/host/index.js +91 -0
  51. package/src/host/installedFlowHost.js +885 -0
  52. package/src/host/invocationAbi.js +440 -0
  53. package/src/host/normalize.js +372 -0
  54. package/src/host/packageManagers.js +369 -0
  55. package/src/host/profile.js +134 -0
  56. package/src/host/runtimeAbi.js +106 -0
  57. package/src/host/workspace.js +895 -0
  58. package/src/index.js +8 -0
  59. package/src/runtime/FlowRuntime.js +273 -0
  60. package/src/runtime/MethodRegistry.js +295 -0
  61. package/src/runtime/constants.js +44 -0
  62. package/src/runtime/index.js +19 -0
  63. package/src/runtime/normalize.js +377 -0
  64. package/src/transport/index.js +7 -0
  65. package/src/transport/pki.js +7 -0
  66. package/src/utils/crypto.js +7 -0
  67. package/src/utils/encoding.js +65 -0
  68. package/src/utils/wasmCrypto.js +69 -0
  69. package/tools/run-plugin-compliance-check.mjs +153 -0
package/src/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export * from "./runtime/index.js";
2
+ export * from "./designer/index.js";
3
+ export * from "./auth/index.js";
4
+ export * from "./host/index.js";
5
+ export * from "./transport/index.js";
6
+ export * from "./deploy/index.js";
7
+ export * from "./compiler/index.js";
8
+ export * from "./compliance/index.js";
@@ -0,0 +1,273 @@
1
+ import { BackpressurePolicy, DrainPolicy } from "./constants.js";
2
+ import { normalizeFrame, normalizeProgram } from "./normalize.js";
3
+
4
+ // Temporary migration harness used for authoring/tests until the generated C++
5
+ // runtime is the only execution path.
6
+
7
+ function groupBy(items, keySelector) {
8
+ const grouped = new Map();
9
+ for (const item of Array.isArray(items) ? items : []) {
10
+ const key = keySelector(item);
11
+ const bucket = grouped.get(key);
12
+ if (bucket) {
13
+ bucket.push(item);
14
+ } else {
15
+ grouped.set(key, [item]);
16
+ }
17
+ }
18
+ return grouped;
19
+ }
20
+
21
+ export class FlowRuntime {
22
+ #registry;
23
+
24
+ #program = null;
25
+
26
+ #nodes = new Map();
27
+
28
+ #triggerBindings = new Map();
29
+
30
+ #edgesBySource = new Map();
31
+
32
+ #maxInvocationsPerDrain;
33
+
34
+ #onSinkOutput;
35
+
36
+ constructor(options = {}) {
37
+ this.#registry = options.registry;
38
+ if (!this.#registry) {
39
+ throw new Error("FlowRuntime requires a MethodRegistry instance.");
40
+ }
41
+ this.#maxInvocationsPerDrain = options.maxInvocationsPerDrain ?? 1024;
42
+ this.#onSinkOutput = options.onSinkOutput ?? null;
43
+ }
44
+
45
+ loadProgram(program) {
46
+ const normalized = normalizeProgram(program);
47
+ this.#program = normalized;
48
+ this.#nodes.clear();
49
+ this.#triggerBindings = groupBy(
50
+ normalized.triggerBindings,
51
+ (binding) => binding.triggerId,
52
+ );
53
+ this.#edgesBySource = groupBy(
54
+ normalized.edges,
55
+ (edge) => `${edge.fromNodeId}:${edge.fromPortId}`,
56
+ );
57
+
58
+ for (const node of normalized.nodes) {
59
+ this.#nodes.set(node.nodeId, {
60
+ node,
61
+ queues: new Map(),
62
+ invocations: 0,
63
+ });
64
+ }
65
+
66
+ return normalized;
67
+ }
68
+
69
+ getProgram() {
70
+ return this.#program;
71
+ }
72
+
73
+ inspectQueues() {
74
+ const snapshot = {};
75
+ for (const [nodeId, state] of this.#nodes.entries()) {
76
+ snapshot[nodeId] = {};
77
+ for (const [portId, queue] of state.queues.entries()) {
78
+ snapshot[nodeId][portId] = queue.length;
79
+ }
80
+ }
81
+ return snapshot;
82
+ }
83
+
84
+ enqueueTriggerFrames(triggerId, frames) {
85
+ const bindings = this.#triggerBindings.get(triggerId) ?? [];
86
+ if (bindings.length === 0) {
87
+ throw new Error(`Trigger "${triggerId}" is not bound to any node input.`);
88
+ }
89
+ for (const binding of bindings) {
90
+ this.enqueueNodeFrames(
91
+ binding.targetNodeId,
92
+ binding.targetPortId,
93
+ frames,
94
+ binding.backpressurePolicy,
95
+ binding.queueDepth,
96
+ );
97
+ }
98
+ }
99
+
100
+ enqueueNodeFrames(
101
+ nodeId,
102
+ portId,
103
+ frames,
104
+ backpressurePolicy = BackpressurePolicy.QUEUE,
105
+ queueDepth = 0,
106
+ ) {
107
+ const state = this.#nodes.get(nodeId);
108
+ if (!state) {
109
+ throw new Error(`Unknown node "${nodeId}".`);
110
+ }
111
+ const queue = state.queues.get(portId) ?? [];
112
+ const normalizedFrames = Array.isArray(frames) ? frames : [frames];
113
+ for (const frameInput of normalizedFrames) {
114
+ const frame = Object.assign(normalizeFrame(frameInput), { portId });
115
+ this.#applyBackpressure(queue, frame, backpressurePolicy, queueDepth);
116
+ }
117
+ state.queues.set(portId, queue);
118
+ }
119
+
120
+ async drain(options = {}) {
121
+ const maxInvocations =
122
+ options.maxInvocations ?? this.#maxInvocationsPerDrain;
123
+ let invocations = 0;
124
+
125
+ while (invocations < maxInvocations) {
126
+ const readyState = this.#findReadyNodeState();
127
+ if (!readyState) {
128
+ break;
129
+ }
130
+ await this.#invokeNode(readyState);
131
+ invocations += 1;
132
+ }
133
+
134
+ return {
135
+ invocations,
136
+ yielded: invocations >= maxInvocations,
137
+ idle: this.isIdle(),
138
+ };
139
+ }
140
+
141
+ isIdle() {
142
+ for (const state of this.#nodes.values()) {
143
+ for (const queue of state.queues.values()) {
144
+ if (queue.length > 0) {
145
+ return false;
146
+ }
147
+ }
148
+ }
149
+ return true;
150
+ }
151
+
152
+ #findReadyNodeState() {
153
+ if (!this.#program) {
154
+ throw new Error("FlowRuntime has no loaded program.");
155
+ }
156
+ for (const node of this.#program.nodes) {
157
+ const state = this.#nodes.get(node.nodeId);
158
+ const descriptor = this.#registry.getMethod(node.pluginId, node.methodId);
159
+ if (!state || !descriptor) {
160
+ continue;
161
+ }
162
+ let ready = false;
163
+ let missingRequiredPort = false;
164
+ for (const port of descriptor.method.inputPorts) {
165
+ const queue = state.queues.get(port.portId) ?? [];
166
+ if (port.required && queue.length === 0) {
167
+ missingRequiredPort = true;
168
+ break;
169
+ }
170
+ if (queue.length > 0) {
171
+ ready = true;
172
+ }
173
+ }
174
+ if (!missingRequiredPort && ready) {
175
+ return state;
176
+ }
177
+ }
178
+ return null;
179
+ }
180
+
181
+ async #invokeNode(state) {
182
+ const descriptor = this.#registry.getMethod(
183
+ state.node.pluginId,
184
+ state.node.methodId,
185
+ );
186
+ const maxBatch = Math.max(1, descriptor.method.maxBatch ?? 1);
187
+ const inputs = [];
188
+ for (const port of descriptor.method.inputPorts) {
189
+ const queue = state.queues.get(port.portId) ?? [];
190
+ const takeCount = Math.min(queue.length, maxBatch);
191
+ for (let index = 0; index < takeCount; index += 1) {
192
+ inputs.push(queue.shift());
193
+ }
194
+ state.queues.set(port.portId, queue);
195
+ }
196
+
197
+ const drainPolicy =
198
+ state.node.drainPolicy ??
199
+ descriptor.method.drainPolicy ??
200
+ DrainPolicy.DRAIN_UNTIL_YIELD;
201
+ const response = await this.#registry.invoke({
202
+ pluginId: state.node.pluginId,
203
+ methodId: state.node.methodId,
204
+ inputs,
205
+ outputStreamCap: 0,
206
+ drainPolicy,
207
+ context: {
208
+ nodeId: state.node.nodeId,
209
+ programId: this.#program.programId,
210
+ },
211
+ });
212
+
213
+ state.invocations += 1;
214
+ this.#routeOutputs(state.node.nodeId, response.outputs ?? []);
215
+ }
216
+
217
+ #routeOutputs(nodeId, outputs) {
218
+ for (const frame of outputs) {
219
+ const sourceKey = `${nodeId}:${frame.portId}`;
220
+ const edges = this.#edgesBySource.get(sourceKey) ?? [];
221
+ if (edges.length === 0) {
222
+ if (typeof this.#onSinkOutput === "function") {
223
+ this.#onSinkOutput({ nodeId, frame });
224
+ }
225
+ continue;
226
+ }
227
+ for (const edge of edges) {
228
+ this.enqueueNodeFrames(
229
+ edge.toNodeId,
230
+ edge.toPortId,
231
+ [frame],
232
+ edge.backpressurePolicy,
233
+ edge.queueDepth,
234
+ );
235
+ }
236
+ }
237
+ }
238
+
239
+ #applyBackpressure(queue, frame, policy, queueDepth) {
240
+ const cap = Number(queueDepth ?? 0);
241
+ const bounded = cap > 0;
242
+ switch (policy) {
243
+ case BackpressurePolicy.DROP:
244
+ if (!bounded || queue.length < cap) {
245
+ queue.push(frame);
246
+ }
247
+ return;
248
+ case BackpressurePolicy.LATEST:
249
+ case BackpressurePolicy.COALESCE:
250
+ if (!bounded || queue.length < cap) {
251
+ queue.push(frame);
252
+ } else {
253
+ queue.splice(0, queue.length, frame);
254
+ }
255
+ return;
256
+ case BackpressurePolicy.BLOCK_REQUEST:
257
+ if (bounded && queue.length >= cap) {
258
+ throw new Error("Backpressure queue is full.");
259
+ }
260
+ queue.push(frame);
261
+ return;
262
+ case BackpressurePolicy.DRAIN_TO_EMPTY:
263
+ case BackpressurePolicy.QUEUE:
264
+ default:
265
+ if (bounded && queue.length >= cap) {
266
+ queue.shift();
267
+ }
268
+ queue.push(frame);
269
+ }
270
+ }
271
+ }
272
+
273
+ export default FlowRuntime;
@@ -0,0 +1,295 @@
1
+ import { DrainPolicy } from "./constants.js";
2
+ import { normalizeFrame, normalizeManifest } from "./normalize.js";
3
+
4
+ function groupFramesByPort(frames) {
5
+ const grouped = new Map();
6
+ for (const frame of frames) {
7
+ if (!frame.portId) {
8
+ throw new Error("Flow frame is missing portId.");
9
+ }
10
+ const bucket = grouped.get(frame.portId);
11
+ if (bucket) {
12
+ bucket.push(frame);
13
+ } else {
14
+ grouped.set(frame.portId, [frame]);
15
+ }
16
+ }
17
+ return grouped;
18
+ }
19
+
20
+ function countDistinctStreams(frames) {
21
+ const streamIds = new Set();
22
+ for (const frame of frames) {
23
+ streamIds.add(Number(frame.streamId ?? 0));
24
+ }
25
+ return streamIds.size;
26
+ }
27
+
28
+ function buildPortMap(ports) {
29
+ const map = new Map();
30
+ for (const port of ports) {
31
+ map.set(port.portId, port);
32
+ }
33
+ return map;
34
+ }
35
+
36
+ function typeMatches(acceptedType, frameType) {
37
+ if (!acceptedType) {
38
+ return false;
39
+ }
40
+ if (acceptedType.acceptsAnyFlatbuffer === true) {
41
+ return true;
42
+ }
43
+ if (!frameType) {
44
+ return false;
45
+ }
46
+ if (
47
+ acceptedType.schemaName &&
48
+ acceptedType.schemaName !== frameType.schemaName
49
+ ) {
50
+ return false;
51
+ }
52
+ if (
53
+ acceptedType.fileIdentifier &&
54
+ acceptedType.fileIdentifier !== frameType.fileIdentifier
55
+ ) {
56
+ return false;
57
+ }
58
+ if (
59
+ Array.isArray(acceptedType.schemaHash) &&
60
+ acceptedType.schemaHash.length > 0
61
+ ) {
62
+ if (
63
+ !Array.isArray(frameType.schemaHash) ||
64
+ frameType.schemaHash.length !== acceptedType.schemaHash.length
65
+ ) {
66
+ return false;
67
+ }
68
+ for (let index = 0; index < acceptedType.schemaHash.length; index += 1) {
69
+ if (acceptedType.schemaHash[index] !== frameType.schemaHash[index]) {
70
+ return false;
71
+ }
72
+ }
73
+ }
74
+ return true;
75
+ }
76
+
77
+ function portAcceptsFrame(port, frame) {
78
+ const acceptedTypeSets = Array.isArray(port.acceptedTypeSets)
79
+ ? port.acceptedTypeSets
80
+ : [];
81
+ if (acceptedTypeSets.length === 0) {
82
+ return true;
83
+ }
84
+ for (const typeSet of acceptedTypeSets) {
85
+ const allowedTypes = Array.isArray(typeSet.allowedTypes)
86
+ ? typeSet.allowedTypes
87
+ : [];
88
+ for (const acceptedType of allowedTypes) {
89
+ if (typeMatches(acceptedType, frame.typeRef)) {
90
+ return true;
91
+ }
92
+ }
93
+ }
94
+ return false;
95
+ }
96
+
97
+ function hydrateOutputPorts(response, method, outputStreamCap) {
98
+ const outputs = Array.isArray(response.outputs) ? response.outputs : [];
99
+ if (outputStreamCap > 0 && outputs.length > outputStreamCap) {
100
+ throw new Error(
101
+ `Method "${method.methodId}" produced ${outputs.length} output frames, exceeding outputStreamCap ${outputStreamCap}.`,
102
+ );
103
+ }
104
+ if (method.outputPorts.length === 1) {
105
+ const onlyPortId = method.outputPorts[0].portId;
106
+ for (const frame of outputs) {
107
+ if (!frame.portId) {
108
+ frame.portId = onlyPortId;
109
+ }
110
+ }
111
+ }
112
+ for (const frame of outputs) {
113
+ if (!frame.portId) {
114
+ throw new Error(
115
+ `Method "${method.methodId}" produced a frame without portId and has multiple output ports.`,
116
+ );
117
+ }
118
+ }
119
+ return {
120
+ outputs,
121
+ backlogRemaining: Number(response.backlogRemaining ?? 0),
122
+ yielded: response.yielded === true,
123
+ errorCode: Number(response.errorCode ?? 0),
124
+ errorMessage: response.errorMessage ?? null,
125
+ };
126
+ }
127
+
128
+ export class MethodRegistry {
129
+ #plugins = new Map();
130
+
131
+ #methods = new Map();
132
+
133
+ registerPlugin({ manifest, handlers = {}, plugin = null }) {
134
+ const normalizedManifest = normalizeManifest(manifest);
135
+ if (!normalizedManifest.pluginId) {
136
+ throw new Error("Plugin manifest is missing pluginId.");
137
+ }
138
+ if (this.#plugins.has(normalizedManifest.pluginId)) {
139
+ throw new Error(
140
+ `Plugin "${normalizedManifest.pluginId}" is already registered.`,
141
+ );
142
+ }
143
+
144
+ const methodMap = new Map();
145
+ for (const method of normalizedManifest.methods) {
146
+ if (!method.methodId) {
147
+ throw new Error(
148
+ `Plugin "${normalizedManifest.pluginId}" contains a method without methodId.`,
149
+ );
150
+ }
151
+ const handler = handlers[method.methodId];
152
+ if (typeof handler !== "function") {
153
+ throw new Error(
154
+ `Plugin "${normalizedManifest.pluginId}" is missing a handler for method "${method.methodId}".`,
155
+ );
156
+ }
157
+ const descriptor = {
158
+ pluginId: normalizedManifest.pluginId,
159
+ manifest: normalizedManifest,
160
+ method,
161
+ handler,
162
+ plugin,
163
+ inputPorts: buildPortMap(method.inputPorts),
164
+ outputPorts: buildPortMap(method.outputPorts),
165
+ };
166
+ methodMap.set(method.methodId, descriptor);
167
+ this.#methods.set(
168
+ `${normalizedManifest.pluginId}:${method.methodId}`,
169
+ descriptor,
170
+ );
171
+ }
172
+
173
+ const record = {
174
+ pluginId: normalizedManifest.pluginId,
175
+ manifest: normalizedManifest,
176
+ methods: methodMap,
177
+ plugin,
178
+ };
179
+ this.#plugins.set(normalizedManifest.pluginId, record);
180
+ return record;
181
+ }
182
+
183
+ unregisterPlugin(pluginId) {
184
+ const record = this.#plugins.get(pluginId);
185
+ if (!record) {
186
+ return false;
187
+ }
188
+
189
+ this.#plugins.delete(pluginId);
190
+ for (const methodId of record.methods.keys()) {
191
+ this.#methods.delete(`${pluginId}:${methodId}`);
192
+ }
193
+ return true;
194
+ }
195
+
196
+ getPlugin(pluginId) {
197
+ return this.#plugins.get(pluginId) ?? null;
198
+ }
199
+
200
+ getMethod(pluginId, methodId) {
201
+ return this.#methods.get(`${pluginId}:${methodId}`) ?? null;
202
+ }
203
+
204
+ listPlugins() {
205
+ return Array.from(this.#plugins.values());
206
+ }
207
+
208
+ async invoke({
209
+ pluginId,
210
+ methodId,
211
+ inputs = [],
212
+ outputStreamCap = 0,
213
+ drainPolicy = undefined,
214
+ context = undefined,
215
+ }) {
216
+ const descriptor = this.getMethod(pluginId, methodId);
217
+ if (!descriptor) {
218
+ throw new Error(`Unknown method "${pluginId}:${methodId}".`);
219
+ }
220
+
221
+ const normalizedInputs = Array.isArray(inputs)
222
+ ? inputs.map((frame) => normalizeFrame(frame))
223
+ : [];
224
+ const inputsByPort = groupFramesByPort(normalizedInputs);
225
+
226
+ for (const [portId, port] of descriptor.inputPorts.entries()) {
227
+ const frames = inputsByPort.get(portId) ?? [];
228
+ if (port.required && frames.length === 0) {
229
+ throw new Error(
230
+ `Method "${pluginId}:${methodId}" requires input port "${portId}".`,
231
+ );
232
+ }
233
+ if (frames.length === 0) {
234
+ continue;
235
+ }
236
+ const distinctStreams = countDistinctStreams(frames);
237
+ if (distinctStreams < port.minStreams) {
238
+ throw new Error(
239
+ `Input port "${portId}" requires at least ${port.minStreams} stream(s).`,
240
+ );
241
+ }
242
+ if (port.maxStreams > 0 && distinctStreams > port.maxStreams) {
243
+ throw new Error(
244
+ `Input port "${portId}" allows at most ${port.maxStreams} stream(s).`,
245
+ );
246
+ }
247
+ for (const frame of frames) {
248
+ if (!portAcceptsFrame(port, frame)) {
249
+ const schemaName =
250
+ frame.typeRef?.schemaName ??
251
+ frame.typeRef?.fileIdentifier ??
252
+ "<unknown>";
253
+ throw new Error(
254
+ `Input port "${portId}" rejected frame type "${schemaName}".`,
255
+ );
256
+ }
257
+ }
258
+ }
259
+
260
+ for (const portId of inputsByPort.keys()) {
261
+ if (!descriptor.inputPorts.has(portId)) {
262
+ throw new Error(
263
+ `Method "${pluginId}:${methodId}" does not declare input port "${portId}".`,
264
+ );
265
+ }
266
+ }
267
+
268
+ const requestedDrainPolicy =
269
+ drainPolicy ??
270
+ descriptor.method.drainPolicy ??
271
+ DrainPolicy.DRAIN_UNTIL_YIELD;
272
+
273
+ const result = await descriptor.handler({
274
+ pluginId,
275
+ methodId,
276
+ manifest: descriptor.manifest,
277
+ method: descriptor.method,
278
+ plugin: descriptor.plugin,
279
+ inputs: normalizedInputs,
280
+ inputsByPort,
281
+ outputStreamCap,
282
+ drainPolicy: requestedDrainPolicy,
283
+ context,
284
+ });
285
+
286
+ return hydrateOutputPorts(result ?? {}, descriptor.method, outputStreamCap);
287
+ }
288
+
289
+ clear() {
290
+ this.#plugins.clear();
291
+ this.#methods.clear();
292
+ }
293
+ }
294
+
295
+ export default MethodRegistry;
@@ -0,0 +1,44 @@
1
+ import {
2
+ DefaultManifestExports as SharedDefaultManifestExports,
3
+ DrainPolicy as SharedDrainPolicy,
4
+ ExternalInterfaceDirection as SharedExternalInterfaceDirection,
5
+ ExternalInterfaceKind as SharedExternalInterfaceKind,
6
+ RuntimeTarget as SharedRuntimeTarget,
7
+ } from "space-data-module-sdk";
8
+
9
+ export const DrainPolicy = SharedDrainPolicy;
10
+
11
+ export const BackpressurePolicy = Object.freeze({
12
+ DROP: "drop",
13
+ LATEST: "latest",
14
+ QUEUE: "queue",
15
+ BLOCK_REQUEST: "block-request",
16
+ COALESCE: "coalesce",
17
+ DRAIN_TO_EMPTY: "drain-to-empty",
18
+ });
19
+
20
+ export const TriggerKind = Object.freeze({
21
+ MANUAL: "manual",
22
+ TIMER: "timer",
23
+ PUBSUB_SUBSCRIPTION: "pubsub-subscription",
24
+ PROTOCOL_REQUEST: "protocol-request",
25
+ HTTP_REQUEST: "http-request",
26
+ ORBPRO_EVENT: "orbpro-event",
27
+ SCENE_EVENT: "scene-event",
28
+ SYSTEM_EVENT: "system-event",
29
+ });
30
+
31
+ export const NodeKind = Object.freeze({
32
+ TRIGGER: "trigger",
33
+ TRANSFORM: "transform",
34
+ ANALYZER: "analyzer",
35
+ PUBLISHER: "publisher",
36
+ RESPONDER: "responder",
37
+ RENDERER: "renderer",
38
+ SINK: "sink",
39
+ });
40
+
41
+ export const ExternalInterfaceDirection = SharedExternalInterfaceDirection;
42
+ export const ExternalInterfaceKind = SharedExternalInterfaceKind;
43
+ export const RuntimeTarget = SharedRuntimeTarget;
44
+ export const DefaultManifestExports = SharedDefaultManifestExports;
@@ -0,0 +1,19 @@
1
+ export {
2
+ BackpressurePolicy,
3
+ DefaultManifestExports,
4
+ DrainPolicy,
5
+ ExternalInterfaceDirection,
6
+ ExternalInterfaceKind,
7
+ NodeKind,
8
+ RuntimeTarget,
9
+ TriggerKind,
10
+ } from "./constants.js";
11
+ export {
12
+ normalizeArtifactDependency,
13
+ normalizeExternalInterface,
14
+ normalizeFrame,
15
+ normalizeManifest,
16
+ normalizeProgram,
17
+ } from "./normalize.js";
18
+ export { MethodRegistry } from "./MethodRegistry.js";
19
+ export { FlowRuntime } from "./FlowRuntime.js";