@bian-womp/spark-graph 0.2.44 → 0.2.46

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/lib/cjs/index.cjs CHANGED
@@ -683,6 +683,9 @@ class GraphRuntime {
683
683
  }
684
684
  const ctx = {
685
685
  state: node.state,
686
+ environment: this.environment,
687
+ runId,
688
+ abortSignal: controller.signal,
686
689
  setState: (next) => Object.assign(node.state, next),
687
690
  emit: (handle, value) => {
688
691
  const m = policy.asyncConcurrency ?? "switch";
@@ -691,11 +694,11 @@ class GraphRuntime {
691
694
  this.propagate(nodeId, handle, value);
692
695
  },
693
696
  invalidateDownstream: () => this.invalidateDownstream(nodeId),
694
- getInput: (handle) => capturedInputs[handle],
695
- environment: this.environment,
696
- runId: runId,
697
- abortSignal: controller.signal,
698
- createAbortController: () => new AbortController(),
697
+ scheduleInputsChanged: () => {
698
+ if (this.allInboundHaveValue(nodeId)) {
699
+ this.scheduleInputsChanged(nodeId);
700
+ }
701
+ },
699
702
  reportProgress: (p) => {
700
703
  node.stats.progress = Math.max(0, Math.min(1, Number(p) || 0));
701
704
  this.emit("stats", {
@@ -846,10 +849,7 @@ class GraphRuntime {
846
849
  if (dynamicHandles.has(handle))
847
850
  continue; // Skip defaults for dynamic handles
848
851
  // Clone to avoid shared references
849
- effective[handle] =
850
- typeof structuredClone === "function"
851
- ? structuredClone(defaultValue)
852
- : JSON.parse(JSON.stringify(defaultValue));
852
+ effective[handle] = structuredClone(defaultValue);
853
853
  }
854
854
  return effective;
855
855
  }
@@ -1153,27 +1153,11 @@ class GraphRuntime {
1153
1153
  launch(invalidate = false) {
1154
1154
  // call onActivated for nodes that implement it
1155
1155
  for (const node of this.nodes.values()) {
1156
- const ctrl = new AbortController();
1157
- const effectiveInputs = this.getEffectiveInputs(node.nodeId);
1158
- const ctx = {
1159
- state: node.state,
1160
- setState: (next) => Object.assign(node.state, next),
1161
- emit: (handle, value) => this.propagate(node.nodeId, handle, value),
1162
- invalidateDownstream: () => this.invalidateDownstream(node.nodeId),
1163
- getInput: (handle) => effectiveInputs[handle],
1164
- environment: this.environment,
1165
- runId: `${node.nodeId}:activation`,
1166
- abortSignal: ctrl.signal,
1167
- createAbortController: () => new AbortController(),
1168
- reportProgress: (p) => {
1169
- node.stats.progress = Math.max(0, Math.min(1, Number(p) || 0));
1170
- },
1171
- };
1172
1156
  node.lifecycle?.init?.(node.params ?? {}, {
1173
1157
  state: node.state,
1174
1158
  setState: (next) => Object.assign(node.state, next),
1175
1159
  });
1176
- node.runtime.onActivated?.(ctx);
1160
+ node.runtime.onActivated?.();
1177
1161
  }
1178
1162
  if (invalidate) {
1179
1163
  // After activation, schedule nodes that have all inbound inputs present
@@ -1187,22 +1171,6 @@ class GraphRuntime {
1187
1171
  const node = this.nodes.get(nodeId);
1188
1172
  if (!node)
1189
1173
  return;
1190
- const ctrl = new AbortController();
1191
- const effectiveInputs = this.getEffectiveInputs(nodeId);
1192
- const ctx = {
1193
- state: node.state,
1194
- setState: (next) => Object.assign(node.state, next),
1195
- emit: (handle, value) => this.propagate(nodeId, handle, value),
1196
- invalidateDownstream: () => this.invalidateDownstream(nodeId),
1197
- getInput: (handle) => effectiveInputs[handle],
1198
- environment: this.environment,
1199
- runId: `${nodeId}:external`,
1200
- abortSignal: ctrl.signal,
1201
- createAbortController: () => new AbortController(),
1202
- reportProgress: (p) => {
1203
- node.stats.progress = Math.max(0, Math.min(1, Number(p) || 0));
1204
- },
1205
- };
1206
1174
  // Built-in support: invalidate event reruns or re-emits without per-node wiring
1207
1175
  if (event &&
1208
1176
  typeof event === "object" &&
@@ -1213,7 +1181,7 @@ class GraphRuntime {
1213
1181
  this.invalidateDownstream(nodeId);
1214
1182
  }
1215
1183
  else {
1216
- node.runtime.onExternalEvent?.(event, ctx);
1184
+ node.runtime.onExternalEvent?.(event, node.state);
1217
1185
  }
1218
1186
  }
1219
1187
  dispose() {
@@ -1266,10 +1234,7 @@ class GraphRuntime {
1266
1234
  const hasInbound = this.edges.some((e) => e.target.nodeId === n.nodeId && e.target.handle === handle);
1267
1235
  if (!hasInbound && value !== undefined) {
1268
1236
  // Clone to avoid shared references
1269
- initialInputs[handle] =
1270
- typeof structuredClone === "function"
1271
- ? structuredClone(value)
1272
- : JSON.parse(JSON.stringify(value));
1237
+ initialInputs[handle] = structuredClone(value);
1273
1238
  }
1274
1239
  }
1275
1240
  return {
@@ -1328,30 +1293,12 @@ class GraphRuntime {
1328
1293
  this.paused = true;
1329
1294
  try {
1330
1295
  const ins = payload?.inputs || {};
1331
- const outsPayload = payload?.outputs || {};
1332
1296
  for (const [nodeId, map] of Object.entries(ins)) {
1333
1297
  const node = this.nodes.get(nodeId);
1334
1298
  if (!node)
1335
1299
  continue;
1336
1300
  for (const [h, v] of Object.entries(map || {})) {
1337
- // If this handle has inbound wiring, prefer upstream outputs from snapshot to populate it.
1338
- // Fallback: if not all upstream output values are present in the snapshot, hydrate the saved input
1339
- // so the initial view matches last saved state (important for array inputs with multiple edges).
1340
- const inboundEdges = this.edges.filter((e) => e.target.nodeId === nodeId && e.target.handle === h);
1341
- if (inboundEdges.length > 0) {
1342
- // Check if ALL upstream outputs exist in snapshot (required for correct array input restoration)
1343
- const allUpstreamOutputsExist = inboundEdges.every((e) => {
1344
- const srcMap = outsPayload[e.source.nodeId] || {};
1345
- return Object.prototype.hasOwnProperty.call(srcMap, e.source.handle);
1346
- });
1347
- // Only skip input hydration if all upstream outputs are present (re-emit will populate correctly)
1348
- if (allUpstreamOutputsExist)
1349
- continue;
1350
- }
1351
- node.inputs[h] =
1352
- typeof structuredClone === "function"
1353
- ? structuredClone(v)
1354
- : JSON.parse(JSON.stringify(v));
1301
+ node.inputs[h] = structuredClone(v);
1355
1302
  // emit input value event
1356
1303
  this.emit("value", {
1357
1304
  nodeId,
@@ -1368,10 +1315,7 @@ class GraphRuntime {
1368
1315
  if (!node)
1369
1316
  continue;
1370
1317
  for (const [h, v] of Object.entries(map || {})) {
1371
- node.outputs[h] =
1372
- typeof structuredClone === "function"
1373
- ? structuredClone(v)
1374
- : JSON.parse(JSON.stringify(v));
1318
+ node.outputs[h] = structuredClone(v);
1375
1319
  // emit output value event
1376
1320
  this.emit("value", {
1377
1321
  nodeId,
@@ -1455,24 +1399,11 @@ class GraphRuntime {
1455
1399
  };
1456
1400
  this.nodes.set(n.nodeId, rn);
1457
1401
  // Activate new node
1458
- const ctrl = new AbortController();
1459
- const effectiveInputs = this.getEffectiveInputs(rn.nodeId);
1460
- const ctx = {
1461
- state: rn.state,
1462
- setState: (next) => Object.assign(rn.state, next),
1463
- emit: (handle, value) => this.propagate(rn.nodeId, handle, value),
1464
- invalidateDownstream: () => this.invalidateDownstream(rn.nodeId),
1465
- getInput: (handle) => effectiveInputs[handle],
1466
- environment: this.environment,
1467
- runId: `${rn.nodeId}:activation`,
1468
- abortSignal: ctrl.signal,
1469
- createAbortController: () => new AbortController(),
1470
- };
1471
1402
  rn.lifecycle?.init?.(rn.params ?? {}, {
1472
1403
  state: rn.state,
1473
1404
  setState: (next) => Object.assign(rn.state, next),
1474
1405
  });
1475
- rn.runtime.onActivated?.(ctx);
1406
+ rn.runtime.onActivated?.();
1476
1407
  }
1477
1408
  else {
1478
1409
  // update params/policy and initialInputs
@@ -2115,13 +2046,13 @@ const ComputeCategory = {
2115
2046
  ctx.emit(h, v);
2116
2047
  }
2117
2048
  },
2118
- onExternalEvent(event, ctx) {
2049
+ onExternalEvent(event, state) {
2119
2050
  try {
2120
2051
  const e = event;
2121
- // Preferred: call a function on ctx.state keyed by e.action
2052
+ // Preferred: call a function on state keyed by e.action
2122
2053
  const action = e?.action;
2123
- if (action && typeof ctx.state?.[action] === "function") {
2124
- const fn = ctx.state[action];
2054
+ if (action && typeof state?.[action] === "function") {
2055
+ const fn = state[action];
2125
2056
  // Normalize args: prefer explicit args array, else wrap single value;
2126
2057
  let args = [];
2127
2058
  if (Array.isArray(e?.args))