@bian-womp/spark-graph 0.3.71 → 0.3.73

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 (83) hide show
  1. package/lib/cjs/index.cjs +163 -268
  2. package/lib/cjs/index.cjs.map +1 -1
  3. package/lib/cjs/src/builder/GraphBuilder.d.ts.map +1 -1
  4. package/lib/cjs/src/builder/Registry.d.ts.map +1 -1
  5. package/lib/cjs/src/core/categories.d.ts.map +1 -1
  6. package/lib/cjs/src/core/order.d.ts.map +1 -1
  7. package/lib/cjs/src/core/type-utils.d.ts.map +1 -1
  8. package/lib/cjs/src/core/types.d.ts.map +1 -1
  9. package/lib/cjs/src/examples/arrays.d.ts.map +1 -1
  10. package/lib/cjs/src/examples/async.d.ts.map +1 -1
  11. package/lib/cjs/src/examples/progress.d.ts.map +1 -1
  12. package/lib/cjs/src/examples/runMode.d.ts.map +1 -1
  13. package/lib/cjs/src/examples/shared.d.ts.map +1 -1
  14. package/lib/cjs/src/examples/simple.d.ts.map +1 -1
  15. package/lib/cjs/src/examples/snapshot.d.ts.map +1 -1
  16. package/lib/cjs/src/index.d.ts +7 -7
  17. package/lib/cjs/src/index.d.ts.map +1 -1
  18. package/lib/cjs/src/misc/base.d.ts.map +1 -1
  19. package/lib/cjs/src/misc/utils/LevelLogger.d.ts.map +1 -1
  20. package/lib/cjs/src/misc/utils/json.d.ts.map +1 -1
  21. package/lib/cjs/src/misc/utils/merge.d.ts.map +1 -1
  22. package/lib/cjs/src/plugins/composite.d.ts.map +1 -1
  23. package/lib/cjs/src/runtime/Engine.d.ts.map +1 -1
  24. package/lib/cjs/src/runtime/GraphLifecycleApi.d.ts.map +1 -1
  25. package/lib/cjs/src/runtime/GraphRuntime.d.ts +7 -6
  26. package/lib/cjs/src/runtime/GraphRuntime.d.ts.map +1 -1
  27. package/lib/cjs/src/runtime/LocalEngine.d.ts.map +1 -1
  28. package/lib/cjs/src/runtime/components/EdgePropagator.d.ts +2 -7
  29. package/lib/cjs/src/runtime/components/EdgePropagator.d.ts.map +1 -1
  30. package/lib/cjs/src/runtime/components/EventEmitter.d.ts.map +1 -1
  31. package/lib/cjs/src/runtime/components/Graph.d.ts.map +1 -1
  32. package/lib/cjs/src/runtime/components/HandleResolver.d.ts.map +1 -1
  33. package/lib/cjs/src/runtime/components/NodeExecutor.d.ts.map +1 -1
  34. package/lib/cjs/src/runtime/components/RunContextManager.d.ts.map +1 -1
  35. package/lib/cjs/src/runtime/components/RuntimeValidatorManager.d.ts.map +1 -1
  36. package/lib/cjs/src/runtime/components/graph-utils.d.ts.map +1 -1
  37. package/lib/cjs/src/runtime/components/interfaces.d.ts +2 -1
  38. package/lib/cjs/src/runtime/components/interfaces.d.ts.map +1 -1
  39. package/lib/cjs/src/runtime/components/types.d.ts.map +1 -1
  40. package/lib/cjs/src/runtime/utils.d.ts +9 -0
  41. package/lib/cjs/src/runtime/utils.d.ts.map +1 -1
  42. package/lib/esm/index.js +163 -268
  43. package/lib/esm/index.js.map +1 -1
  44. package/lib/esm/src/builder/GraphBuilder.d.ts.map +1 -1
  45. package/lib/esm/src/builder/Registry.d.ts.map +1 -1
  46. package/lib/esm/src/core/categories.d.ts.map +1 -1
  47. package/lib/esm/src/core/order.d.ts.map +1 -1
  48. package/lib/esm/src/core/type-utils.d.ts.map +1 -1
  49. package/lib/esm/src/core/types.d.ts.map +1 -1
  50. package/lib/esm/src/examples/arrays.d.ts.map +1 -1
  51. package/lib/esm/src/examples/async.d.ts.map +1 -1
  52. package/lib/esm/src/examples/progress.d.ts.map +1 -1
  53. package/lib/esm/src/examples/runMode.d.ts.map +1 -1
  54. package/lib/esm/src/examples/shared.d.ts.map +1 -1
  55. package/lib/esm/src/examples/simple.d.ts.map +1 -1
  56. package/lib/esm/src/examples/snapshot.d.ts.map +1 -1
  57. package/lib/esm/src/index.d.ts +7 -7
  58. package/lib/esm/src/index.d.ts.map +1 -1
  59. package/lib/esm/src/misc/base.d.ts.map +1 -1
  60. package/lib/esm/src/misc/utils/LevelLogger.d.ts.map +1 -1
  61. package/lib/esm/src/misc/utils/json.d.ts.map +1 -1
  62. package/lib/esm/src/misc/utils/merge.d.ts.map +1 -1
  63. package/lib/esm/src/plugins/composite.d.ts.map +1 -1
  64. package/lib/esm/src/runtime/Engine.d.ts.map +1 -1
  65. package/lib/esm/src/runtime/GraphLifecycleApi.d.ts.map +1 -1
  66. package/lib/esm/src/runtime/GraphRuntime.d.ts +7 -6
  67. package/lib/esm/src/runtime/GraphRuntime.d.ts.map +1 -1
  68. package/lib/esm/src/runtime/LocalEngine.d.ts.map +1 -1
  69. package/lib/esm/src/runtime/components/EdgePropagator.d.ts +2 -7
  70. package/lib/esm/src/runtime/components/EdgePropagator.d.ts.map +1 -1
  71. package/lib/esm/src/runtime/components/EventEmitter.d.ts.map +1 -1
  72. package/lib/esm/src/runtime/components/Graph.d.ts.map +1 -1
  73. package/lib/esm/src/runtime/components/HandleResolver.d.ts.map +1 -1
  74. package/lib/esm/src/runtime/components/NodeExecutor.d.ts.map +1 -1
  75. package/lib/esm/src/runtime/components/RunContextManager.d.ts.map +1 -1
  76. package/lib/esm/src/runtime/components/RuntimeValidatorManager.d.ts.map +1 -1
  77. package/lib/esm/src/runtime/components/graph-utils.d.ts.map +1 -1
  78. package/lib/esm/src/runtime/components/interfaces.d.ts +2 -1
  79. package/lib/esm/src/runtime/components/interfaces.d.ts.map +1 -1
  80. package/lib/esm/src/runtime/components/types.d.ts.map +1 -1
  81. package/lib/esm/src/runtime/utils.d.ts +9 -0
  82. package/lib/esm/src/runtime/utils.d.ts.map +1 -1
  83. package/package.json +4 -2
package/lib/cjs/index.cjs CHANGED
@@ -4,9 +4,7 @@ function typed(typeId, value) {
4
4
  return { __spark_type: typeId, __spark_value: value };
5
5
  }
6
6
  function isTyped(v) {
7
- return (!!v &&
8
- typeof v === "object" &&
9
- Object.prototype.hasOwnProperty.call(v, "__spark_type"));
7
+ return !!v && typeof v === "object" && Object.prototype.hasOwnProperty.call(v, "__spark_type");
10
8
  }
11
9
  function unwrapTypeId(v) {
12
10
  if (isTyped(v))
@@ -66,12 +64,8 @@ function mergeInputHandleDescriptors(staticDesc, dynamicDesc) {
66
64
  (typeof dynamicDesc === "string" || Array.isArray(dynamicDesc))) {
67
65
  return dynamicDesc;
68
66
  }
69
- const staticObj = typeof staticDesc === "string" || Array.isArray(staticDesc)
70
- ? { typeId: staticDesc }
71
- : staticDesc;
72
- const dynamicObj = typeof dynamicDesc === "string" || Array.isArray(dynamicDesc)
73
- ? { typeId: dynamicDesc }
74
- : dynamicDesc;
67
+ const staticObj = typeof staticDesc === "string" || Array.isArray(staticDesc) ? { typeId: staticDesc } : staticDesc;
68
+ const dynamicObj = typeof dynamicDesc === "string" || Array.isArray(dynamicDesc) ? { typeId: dynamicDesc } : dynamicDesc;
75
69
  // Merge: dynamic takes precedence, but merge metadata objects
76
70
  const merged = {
77
71
  typeId: dynamicObj.typeId ?? staticObj.typeId,
@@ -152,7 +146,7 @@ class Registry {
152
146
  };
153
147
  this.types.set(arrayId, arrayDesc);
154
148
  }
155
- this.registerCoercion(desc.id, arrayId, (value) => Array.isArray(value) ? value : [value]);
149
+ this.registerCoercion(desc.id, arrayId, (value) => (Array.isArray(value) ? value : [value]));
156
150
  this.registerCoercion(arrayId, desc.id, (value) => {
157
151
  if (!Array.isArray(value))
158
152
  return value;
@@ -178,8 +172,8 @@ class Registry {
178
172
  const arrayId = `${typeId}[]`;
179
173
  if (this.types.has(arrayId) && !this.serializers.has(arrayId)) {
180
174
  this.serializers.set(arrayId, {
181
- serialize: (value) => Array.isArray(value) ? value.map((el) => s.serialize(el)) : value,
182
- deserialize: (data) => Array.isArray(data) ? data.map((el) => s.deserialize(el)) : data,
175
+ serialize: (value) => (Array.isArray(value) ? value.map((el) => s.serialize(el)) : value),
176
+ deserialize: (data) => (Array.isArray(data) ? data.map((el) => s.deserialize(el)) : data),
183
177
  });
184
178
  }
185
179
  return this;
@@ -355,8 +349,7 @@ class Registry {
355
349
  let i = 0;
356
350
  while (i < queue.length) {
357
351
  const q = queue[i];
358
- if (e.cost.edges < q.cost.edges ||
359
- (e.cost.edges === q.cost.edges && e.cost.async < q.cost.async)) {
352
+ if (e.cost.edges < q.cost.edges || (e.cost.edges === q.cost.edges && e.cost.async < q.cost.async)) {
360
353
  break;
361
354
  }
362
355
  i++;
@@ -475,9 +468,7 @@ class Registry {
475
468
  const rec = this.enums.get(id);
476
469
  if (!rec)
477
470
  return value;
478
- return rec.valueToLabel.has(n)
479
- ? n
480
- : Array.from(rec.valueToLabel.keys())[0] ?? 0;
471
+ return rec.valueToLabel.has(n) ? n : (Array.from(rec.valueToLabel.keys())[0] ?? 0);
481
472
  });
482
473
  this.registerCoercion(id, labelType, (value) => {
483
474
  const n = Number(value);
@@ -924,8 +915,7 @@ class Graph {
924
915
  if (inbound.length === 0)
925
916
  return true;
926
917
  for (const e of inbound) {
927
- if (node.resolvedHandles?.inputs?.[e.target.handle] &&
928
- !node.inputs[e.target.handle]) {
918
+ if (node.resolvedHandles?.inputs?.[e.target.handle] && !node.inputs[e.target.handle]) {
929
919
  return false;
930
920
  }
931
921
  }
@@ -1003,9 +993,7 @@ function getValueAtPath(obj, pathSegments) {
1003
993
  let current = obj;
1004
994
  for (let i = 0; i < pathSegments.length - 1; i++) {
1005
995
  const segment = pathSegments[i];
1006
- if (current === null ||
1007
- current === undefined ||
1008
- typeof current !== "object") {
996
+ if (current === null || current === undefined || typeof current !== "object") {
1009
997
  return null;
1010
998
  }
1011
999
  if (typeof segment === "string") {
@@ -1054,9 +1042,7 @@ function getValueAtPath(obj, pathSegments) {
1054
1042
  return null;
1055
1043
  return { value: current[index], parent: current, key: index };
1056
1044
  }
1057
- else if (current !== null &&
1058
- current !== undefined &&
1059
- typeof current === "object") {
1045
+ else if (current !== null && current !== undefined && typeof current === "object") {
1060
1046
  return {
1061
1047
  value: current[lastSegment],
1062
1048
  parent: current,
@@ -1170,29 +1156,20 @@ function findMatchingPaths(obj, pathSegments, currentPath = []) {
1170
1156
  if (Array.isArray(obj)) {
1171
1157
  const index = parseInt(currentSegment, 10);
1172
1158
  if (!isNaN(index) && index >= 0 && index < obj.length) {
1173
- results.push(...findMatchingPaths(obj[index], remainingSegments, [
1174
- ...currentPath,
1175
- index,
1176
- ]));
1159
+ results.push(...findMatchingPaths(obj[index], remainingSegments, [...currentPath, index]));
1177
1160
  }
1178
1161
  }
1179
1162
  else if (obj !== null && obj !== undefined && typeof obj === "object") {
1180
1163
  const objRecord = obj;
1181
1164
  if (currentSegment in objRecord) {
1182
- results.push(...findMatchingPaths(objRecord[currentSegment], remainingSegments, [
1183
- ...currentPath,
1184
- currentSegment,
1185
- ]));
1165
+ results.push(...findMatchingPaths(objRecord[currentSegment], remainingSegments, [...currentPath, currentSegment]));
1186
1166
  }
1187
1167
  }
1188
1168
  }
1189
1169
  else if (typeof currentSegment === "number") {
1190
1170
  if (Array.isArray(obj)) {
1191
1171
  if (currentSegment >= 0 && currentSegment < obj.length) {
1192
- results.push(...findMatchingPaths(obj[currentSegment], remainingSegments, [
1193
- ...currentPath,
1194
- currentSegment,
1195
- ]));
1172
+ results.push(...findMatchingPaths(obj[currentSegment], remainingSegments, [...currentPath, currentSegment]));
1196
1173
  }
1197
1174
  }
1198
1175
  }
@@ -1206,10 +1183,7 @@ function findMatchingPaths(obj, pathSegments, currentPath = []) {
1206
1183
  const objRecord = obj;
1207
1184
  for (const key of Object.keys(objRecord)) {
1208
1185
  if (currentSegment.test(key)) {
1209
- results.push(...findMatchingPaths(objRecord[key], remainingSegments, [
1210
- ...currentPath,
1211
- key,
1212
- ]));
1186
+ results.push(...findMatchingPaths(objRecord[key], remainingSegments, [...currentPath, key]));
1213
1187
  }
1214
1188
  }
1215
1189
  }
@@ -1220,12 +1194,8 @@ function stringifyJson(obj, oneLiner) {
1220
1194
  // No formatting requested: behave exactly like native JSON.stringify.
1221
1195
  if (!oneLiner)
1222
1196
  return JSON.stringify(obj);
1223
- const indentSize = Number.isFinite(oneLiner.indent)
1224
- ? Math.max(0, Math.floor(oneLiner.indent))
1225
- : 2;
1226
- const maxDepth = typeof oneLiner.maxDepth === "number" && Number.isFinite(oneLiner.maxDepth)
1227
- ? oneLiner.maxDepth
1228
- : undefined;
1197
+ const indentSize = Number.isFinite(oneLiner.indent) ? Math.max(0, Math.floor(oneLiner.indent)) : 2;
1198
+ const maxDepth = typeof oneLiner.maxDepth === "number" && Number.isFinite(oneLiner.maxDepth) ? oneLiner.maxDepth : undefined;
1229
1199
  const patterns = (oneLiner.paths || []).filter(Boolean);
1230
1200
  // Preserve JSON.stringify semantics for things like toJSON(), dropping functions/undefined, etc.
1231
1201
  // Note: this still throws on circular structures (same as JSON.stringify).
@@ -1428,22 +1398,13 @@ function compilePathMatcher(pattern) {
1428
1398
  res = ti < pathTokens.length && go(pi + 1, ti + 1);
1429
1399
  }
1430
1400
  else if (p === "#") {
1431
- res =
1432
- ti < pathTokens.length &&
1433
- isNumericSegment(pathTokens[ti]) &&
1434
- go(pi + 1, ti + 1);
1401
+ res = ti < pathTokens.length && isNumericSegment(pathTokens[ti]) && go(pi + 1, ti + 1);
1435
1402
  }
1436
1403
  else if (p === "[*]") {
1437
- res =
1438
- ti < pathTokens.length &&
1439
- isIndex(pathTokens[ti]) &&
1440
- go(pi + 1, ti + 1);
1404
+ res = ti < pathTokens.length && isIndex(pathTokens[ti]) && go(pi + 1, ti + 1);
1441
1405
  }
1442
1406
  else {
1443
- res =
1444
- ti < pathTokens.length &&
1445
- eq(p.toLowerCase(), pathTokens[ti].toLowerCase()) &&
1446
- go(pi + 1, ti + 1);
1407
+ res = ti < pathTokens.length && eq(p.toLowerCase(), pathTokens[ti].toLowerCase()) && go(pi + 1, ti + 1);
1447
1408
  }
1448
1409
  }
1449
1410
  memo.set(key, res);
@@ -1469,10 +1430,7 @@ function stringifySceneAndOps(obj) {
1469
1430
  "**.perUserExt.*.#",
1470
1431
  "**.perUserExt.*.*.#",
1471
1432
  ],
1472
- criteria: ({ value, key }) => (typeof value === "object" &&
1473
- value &&
1474
- Object.keys(value).sort().join(",") === "x,y,z") ||
1475
- key === "value",
1433
+ criteria: ({ value, key }) => (typeof value === "object" && value && Object.keys(value).sort().join(",") === "x,y,z") || key === "value",
1476
1434
  });
1477
1435
  }
1478
1436
 
@@ -1542,8 +1500,7 @@ class LevelLogger {
1542
1500
  parseJsonStringIfFull(str) {
1543
1501
  const trimmed = str.trim();
1544
1502
  // Check if the string starts with { or [ and ends with } or ]
1545
- if ((trimmed.startsWith("{") && trimmed.endsWith("}")) ||
1546
- (trimmed.startsWith("[") && trimmed.endsWith("]"))) {
1503
+ if ((trimmed.startsWith("{") && trimmed.endsWith("}")) || (trimmed.startsWith("[") && trimmed.endsWith("]"))) {
1547
1504
  try {
1548
1505
  const parsed = JSON.parse(trimmed);
1549
1506
  return JSON.stringify(parsed, null, 2);
@@ -1562,8 +1519,7 @@ class LevelLogger {
1562
1519
  parseJsonStringToObject(str) {
1563
1520
  const trimmed = str.trim();
1564
1521
  // Check if the string starts with { or [ and ends with } or ]
1565
- if ((trimmed.startsWith("{") && trimmed.endsWith("}")) ||
1566
- (trimmed.startsWith("[") && trimmed.endsWith("]"))) {
1522
+ if ((trimmed.startsWith("{") && trimmed.endsWith("}")) || (trimmed.startsWith("[") && trimmed.endsWith("]"))) {
1567
1523
  try {
1568
1524
  return JSON.parse(trimmed);
1569
1525
  }
@@ -1664,10 +1620,7 @@ class LevelLogger {
1664
1620
  // (starts with { or [ and contains newlines indicating it was formatted),
1665
1621
  // output it directly without stringifySceneAndOps to preserve formatting
1666
1622
  // Wrap it with json`...` to distinguish it as formatted JSON
1667
- if (parseJsonString &&
1668
- typeof v === "string" &&
1669
- v.trim().match(/^[{\[]/) &&
1670
- v.includes("\n")) {
1623
+ if (parseJsonString && typeof v === "string" && v.trim().match(/^[{\[]/) && v.includes("\n")) {
1671
1624
  return `${k}=json\`${v}\``;
1672
1625
  }
1673
1626
  // If this key had a JSON string parsed and we're formatting JSON,
@@ -1682,9 +1635,7 @@ class LevelLogger {
1682
1635
  })
1683
1636
  .join(formatJson ? "\n" : " ")}`
1684
1637
  : "";
1685
- const prefixedMessage = this.prefix
1686
- ? `${this.prefix} ${message}${contextStr}`
1687
- : `${message}${contextStr}`;
1638
+ const prefixedMessage = this.prefix ? `${this.prefix} ${message}${contextStr}` : `${message}${contextStr}`;
1688
1639
  switch (requestedLevel) {
1689
1640
  case "debug":
1690
1641
  console.info(prefixedMessage);
@@ -1919,10 +1870,7 @@ class RunContextManager {
1919
1870
  });
1920
1871
  return;
1921
1872
  }
1922
- if (ctx.pendingNodes > 0 ||
1923
- ctx.pendingEdges > 0 ||
1924
- ctx.pendingResolvers > 0 ||
1925
- ctx.pendingQueued > 0) {
1873
+ if (ctx.pendingNodes > 0 || ctx.pendingEdges > 0 || ctx.pendingResolvers > 0 || ctx.pendingQueued > 0) {
1926
1874
  return; // Still has pending work
1927
1875
  }
1928
1876
  this.logger.info("finish-run-context", {
@@ -2041,6 +1989,19 @@ function valuesEqual(a, b) {
2041
1989
  }
2042
1990
  return false;
2043
1991
  }
1992
+ /**
1993
+ * Format a node reference as <typeId>.<nodeId> for logs.
1994
+ */
1995
+ function formatNodeRef(graph, nodeId) {
1996
+ const node = graph.getNode(nodeId);
1997
+ return `${node?.typeId ?? "unknown"}.${nodeId}`;
1998
+ }
1999
+ /**
2000
+ * Format a node handle reference as <typeId>.<nodeId>.<handle> for logs.
2001
+ */
2002
+ function formatNodeHandleRef(graph, nodeId, handle) {
2003
+ return `${formatNodeRef(graph, nodeId)}.${handle}`;
2004
+ }
2044
2005
 
2045
2006
  function tryHandleResolving(def, registry, environment) {
2046
2007
  const out = new Map();
@@ -2148,9 +2109,7 @@ function extractEdgeTypes(sourceNodeId, sourceHandle, targetNodeId, targetHandle
2148
2109
  const srcDeclared = srcResolved
2149
2110
  ? srcResolved.outputs[sourceHandle]
2150
2111
  : registry.nodes.get(graph.getNode(sourceNodeId)?.typeId || "")?.outputs[sourceHandle];
2151
- const dstDeclared = getInputDeclaredTypes(dstResolved
2152
- ? dstResolved.inputs
2153
- : registry.nodes.get(graph.getNode(targetNodeId)?.typeId || "")?.inputs, targetHandle);
2112
+ const dstDeclared = getInputDeclaredTypes(dstResolved ? dstResolved.inputs : registry.nodes.get(graph.getNode(targetNodeId)?.typeId || "")?.inputs, targetHandle);
2154
2113
  return {
2155
2114
  srcDeclared,
2156
2115
  dstDeclared,
@@ -2246,9 +2205,7 @@ function buildEdgeConverters(srcDeclared, dstDeclared, registry, edgeLabel) {
2246
2205
  const { typeId, payload } = extractPayload(v);
2247
2206
  const res = getCoercion(typeId);
2248
2207
  if (!res) {
2249
- const fallbackType = isDstUnion && typeId && dstTypes.includes(typeId)
2250
- ? typeId
2251
- : undefined;
2208
+ const fallbackType = isDstUnion && typeId && dstTypes.includes(typeId) ? typeId : undefined;
2252
2209
  return wrapIfDstUnion(fallbackType, payload);
2253
2210
  }
2254
2211
  if (res.kind === "async" && res.convertAsync) {
@@ -2269,9 +2226,7 @@ function buildEdgeConverters(srcDeclared, dstDeclared, registry, edgeLabel) {
2269
2226
  const { typeId, payload } = extractPayload(v);
2270
2227
  const res = getCoercion(typeId);
2271
2228
  if (!res) {
2272
- const fallbackType = isDstUnion && typeId && dstTypes.includes(typeId)
2273
- ? typeId
2274
- : undefined;
2229
+ const fallbackType = isDstUnion && typeId && dstTypes.includes(typeId) ? typeId : undefined;
2275
2230
  return wrapIfDstUnion(fallbackType, payload);
2276
2231
  }
2277
2232
  if (res.kind === "async") {
@@ -2445,15 +2400,11 @@ class HandleResolver {
2445
2400
  // Update edge properties via Graph
2446
2401
  this.graph.updateEdgeProperties(e.id, {
2447
2402
  dstDeclared,
2448
- srcUnionTypes: Array.isArray(srcDeclared)
2449
- ? [...srcDeclared]
2450
- : undefined,
2403
+ srcUnionTypes: Array.isArray(srcDeclared) ? [...srcDeclared] : undefined,
2451
2404
  convert: conv.convert,
2452
2405
  convertAsync: conv.convertAsync,
2453
2406
  });
2454
- if (e.target.nodeId === nodeId &&
2455
- oldDstDeclared === undefined &&
2456
- dstDeclared !== undefined) {
2407
+ if (e.target.nodeId === nodeId && oldDstDeclared === undefined && dstDeclared !== undefined) {
2457
2408
  const srcNode = this.graph.getNode(e.source.nodeId);
2458
2409
  if (srcNode) {
2459
2410
  const srcValue = srcNode.outputs[e.source.handle];
@@ -2489,7 +2440,7 @@ class HandleResolver {
2489
2440
  const nodeLogValue = LOG_LEVEL_VALUES[nodeLogLevel] ?? 1;
2490
2441
  const shouldLog = nodeLogValue <= LOG_LEVEL_VALUES.debug && nodeLogLevel !== "silent";
2491
2442
  if (shouldLog) {
2492
- console.info(`[node:${nodeId}:${node.typeId}] resolveHandles-start`);
2443
+ console.info(`[node:${formatNodeRef(this.graph, nodeId)}] resolveHandles-start`);
2493
2444
  }
2494
2445
  let resolved;
2495
2446
  try {
@@ -2504,13 +2455,13 @@ class HandleResolver {
2504
2455
  catch {
2505
2456
  // Log resolveHandles-done even on error
2506
2457
  if (shouldLog) {
2507
- console.info(`[node:${nodeId}:${node.typeId}] resolveHandles-done (error)`);
2458
+ console.info(`[node:${formatNodeRef(this.graph, nodeId)}] resolveHandles-done (error)`);
2508
2459
  }
2509
2460
  return;
2510
2461
  }
2511
2462
  // Log resolveHandles-done
2512
2463
  if (shouldLog) {
2513
- console.info(`[node:${nodeId}:${node.typeId}] resolveHandles-done`);
2464
+ console.info(`[node:${formatNodeRef(this.graph, nodeId)}] resolveHandles-done`);
2514
2465
  }
2515
2466
  // If a newer recompute was scheduled, drop this result
2516
2467
  if ((this.recomputeTokenByNode.get(nodeId) ?? 0) !== token)
@@ -2572,11 +2523,10 @@ class HandleResolver {
2572
2523
  * EdgePropagator component - handles value propagation through edges
2573
2524
  */
2574
2525
  class EdgePropagator {
2575
- constructor(graph, eventEmitter, runContextManager, handleResolver, nodeExecutor, runtime) {
2526
+ constructor(graph, eventEmitter, runContextManager, nodeExecutor, runtime) {
2576
2527
  this.graph = graph;
2577
2528
  this.eventEmitter = eventEmitter;
2578
2529
  this.runContextManager = runContextManager;
2579
- this.handleResolver = handleResolver;
2580
2530
  this.nodeExecutor = nodeExecutor;
2581
2531
  this.runtime = runtime;
2582
2532
  this.arrayInputBuckets = new Map();
@@ -2606,9 +2556,7 @@ class EdgePropagator {
2606
2556
  const effectiveRunContexts = runContextIds && runContextIds.size > 0
2607
2557
  ? this.filterEffectiveRunContexts(edge, srcNodeId, runContextIds)
2608
2558
  : undefined;
2609
- if (runContextIds &&
2610
- runContextIds.size > 0 &&
2611
- !(effectiveRunContexts && effectiveRunContexts.size > 0)) {
2559
+ if (runContextIds && runContextIds.size > 0 && !(effectiveRunContexts && effectiveRunContexts.size > 0)) {
2612
2560
  return; // No valid run-contexts for this edge
2613
2561
  }
2614
2562
  // Validate union types
@@ -2649,12 +2597,16 @@ class EdgePropagator {
2649
2597
  const isUnion = Array.isArray(edge.srcUnionTypes);
2650
2598
  const isTypedValue = isTyped(value);
2651
2599
  if (isUnion && !isTypedValue) {
2600
+ const sourceTypeId = this.graph.getNode(edge.source.nodeId)?.typeId;
2601
+ const targetTypeId = this.graph.getNode(edge.target.nodeId)?.typeId;
2652
2602
  const err = new Error(`Output ${srcNodeId}.${edge.source.handle} requires typed value for union output (allowed: ${edge.srcUnionTypes.join("|")})`);
2653
2603
  this.eventEmitter.emit("error", {
2654
2604
  kind: "edge-convert",
2655
2605
  edgeId: edge.id,
2656
2606
  source: { nodeId: edge.source.nodeId, handle: edge.source.handle },
2657
2607
  target: { nodeId: edge.target.nodeId, handle: edge.target.handle },
2608
+ sourceTypeId,
2609
+ targetTypeId,
2658
2610
  err,
2659
2611
  });
2660
2612
  return false;
@@ -2670,7 +2622,14 @@ class EdgePropagator {
2670
2622
  convertedValue = edge.convert(value);
2671
2623
  }
2672
2624
  else {
2673
- console.warn(`No convert function for edge ${edge.id} of type ${edge.source.nodeId}.${edge.source.handle} -> ${edge.target.nodeId}.${edge.target.handle}`);
2625
+ const fromType = (Array.isArray(edge.srcUnionTypes) && edge.srcUnionTypes.length > 0
2626
+ ? edge.srcUnionTypes.join("|")
2627
+ : undefined) ??
2628
+ unwrapTypeId(value) ??
2629
+ edge.typeId ??
2630
+ "unknown";
2631
+ const toType = Array.isArray(edge.dstDeclared) ? edge.dstDeclared.join("|") : (edge.dstDeclared ?? "unknown");
2632
+ console.warn(`No convert function for edge ${edge.id} [${formatNodeHandleRef(this.graph, edge.source.nodeId, edge.source.handle)} -> ${formatNodeHandleRef(this.graph, edge.target.nodeId, edge.target.handle)}] from:${fromType} to:${toType}`);
2674
2633
  }
2675
2634
  this.applyToTarget(edge, convertedValue, effectiveRunContexts);
2676
2635
  }
@@ -2681,20 +2640,22 @@ class EdgePropagator {
2681
2640
  if (!edge.convertAsync)
2682
2641
  return;
2683
2642
  // Track edge run-context IDs for pendingEdges tracking
2684
- const edgeRunContextIds = effectiveRunContexts
2685
- ? Array.from(effectiveRunContexts)
2686
- : undefined;
2643
+ const edgeRunContextIds = effectiveRunContexts ? Array.from(effectiveRunContexts) : undefined;
2687
2644
  if (edgeRunContextIds) {
2688
2645
  for (const id of edgeRunContextIds) {
2689
2646
  this.runContextManager.startEdgeConversion(id, edge.id);
2690
2647
  }
2691
2648
  }
2649
+ const sourceTypeId = this.graph.getNode(edge.source.nodeId)?.typeId;
2650
+ const targetTypeId = this.graph.getNode(edge.target.nodeId)?.typeId;
2692
2651
  this.eventEmitter.emit("stats", {
2693
2652
  kind: "edge-start",
2694
2653
  edgeId: edge.id,
2695
2654
  typeId: edge.typeId,
2696
2655
  source: { nodeId: edge.source.nodeId, handle: edge.source.handle },
2697
2656
  target: { nodeId: edge.target.nodeId, handle: edge.target.handle },
2657
+ sourceTypeId,
2658
+ targetTypeId,
2698
2659
  });
2699
2660
  const controller = new AbortController();
2700
2661
  const startAt = Date.now();
@@ -2754,7 +2715,7 @@ class EdgePropagator {
2754
2715
  // Set input value (respecting skipPropagateValues)
2755
2716
  const shouldSetValue = this.shouldSetInputValue(effectiveRunContexts);
2756
2717
  if (shouldSetValue && valueChanged) {
2757
- this.setTargetInput(edge, processedValue);
2718
+ this.runtime.setTargetInput(edge, processedValue, "applyToTarget");
2758
2719
  }
2759
2720
  else if (shouldSetValue && !valueChanged) {
2760
2721
  // Even if value didn't change, update timestamp if we're forcing execution
@@ -2772,7 +2733,7 @@ class EdgePropagator {
2772
2733
  if (!dstIsArray) {
2773
2734
  return value;
2774
2735
  }
2775
- const toArray = (x) => Array.isArray(x) ? x : x === undefined ? [] : [x];
2736
+ const toArray = (x) => (Array.isArray(x) ? x : x === undefined ? [] : [x]);
2776
2737
  let forNode = this.arrayInputBuckets.get(edge.target.nodeId);
2777
2738
  if (!forNode) {
2778
2739
  forNode = new Map();
@@ -2810,13 +2771,6 @@ class EdgePropagator {
2810
2771
  }
2811
2772
  return true;
2812
2773
  }
2813
- /**
2814
- * Set target input value and emit event
2815
- */
2816
- setTargetInput(edge, value) {
2817
- this.graph.updateNodeInput(edge.target.nodeId, edge.target.handle, value);
2818
- this.handleResolver.scheduleRecomputeHandles(edge.target.nodeId);
2819
- }
2820
2774
  /**
2821
2775
  * Execute downstream if conditions are met
2822
2776
  */
@@ -2863,6 +2817,8 @@ class EdgePropagator {
2863
2817
  typeId: edge.typeId,
2864
2818
  source: { nodeId: edge.source.nodeId, handle: edge.source.handle },
2865
2819
  target: { nodeId: edge.target.nodeId, handle: edge.target.handle },
2820
+ sourceTypeId: this.graph.getNode(edge.source.nodeId)?.typeId,
2821
+ targetTypeId: this.graph.getNode(edge.target.nodeId)?.typeId,
2866
2822
  durationMs: duration,
2867
2823
  });
2868
2824
  }
@@ -2879,6 +2835,8 @@ class EdgePropagator {
2879
2835
  edgeId: edge.id,
2880
2836
  source: { nodeId: edge.source.nodeId, handle: edge.source.handle },
2881
2837
  target: { nodeId: edge.target.nodeId, handle: edge.target.handle },
2838
+ sourceTypeId: this.graph.getNode(edge.source.nodeId)?.typeId,
2839
+ targetTypeId: this.graph.getNode(edge.target.nodeId)?.typeId,
2882
2840
  err,
2883
2841
  });
2884
2842
  }
@@ -2923,9 +2881,7 @@ class EdgePropagator {
2923
2881
  return;
2924
2882
  // Get resolved handles to filter out invalid outputs
2925
2883
  const resolved = this.graph.getResolvedHandles(nodeId);
2926
- const validOutputHandles = resolved?.outputs
2927
- ? new Set(Object.keys(resolved.outputs))
2928
- : new Set();
2884
+ const validOutputHandles = resolved?.outputs ? new Set(Object.keys(resolved.outputs)) : new Set();
2929
2885
  // Use node's activeRunContexts to propagate to new nodes that were added
2930
2886
  const activeRunContextIds = this.graph.getNodeRunContextIds(nodeId);
2931
2887
  for (const [handle, value] of Object.entries(node.outputs)) {
@@ -2996,7 +2952,7 @@ class NodeExecutor {
2996
2952
  // Create log function that respects node's logLevel using LevelLogger
2997
2953
  const node = this.graph.getNode(nodeId);
2998
2954
  const nodeLogLevel = node?.logLevel ?? "info";
2999
- const logger = new LevelLogger(nodeLogLevel, `[node:${runId || nodeId}:${node?.typeId ?? ""}]`);
2955
+ const logger = new LevelLogger(nodeLogLevel, `[node:${formatNodeRef(this.graph, nodeId)}:${runId}]`);
3000
2956
  const log = (level, message, context) => {
3001
2957
  switch (level) {
3002
2958
  case "debug":
@@ -3024,11 +2980,8 @@ class NodeExecutor {
3024
2980
  execute: (opts) => {
3025
2981
  if (this.graph.allInboundHaveValue(nodeId)) {
3026
2982
  let runContextIdsToUse = this.runtime.getRunMode() === "auto" ? undefined : runContextIds;
3027
- if (this.runtime.getRunMode() === "manual" &&
3028
- (!runContextIds || runContextIds.size === 0)) {
3029
- runContextIdsToUse = new Set([
3030
- this.runContextManager.createRunContext(nodeId, opts),
3031
- ]);
2983
+ if (this.runtime.getRunMode() === "manual" && (!runContextIds || runContextIds.size === 0)) {
2984
+ runContextIdsToUse = new Set([this.runContextManager.createRunContext(nodeId, opts)]);
3032
2985
  }
3033
2986
  this.execute(nodeId, {
3034
2987
  runContextIds: runContextIdsToUse,
@@ -3064,24 +3017,22 @@ class NodeExecutor {
3064
3017
  return;
3065
3018
  const runMode = this.runtime.getRunMode();
3066
3019
  if (!runMode) {
3067
- console.trace(`NodeExecutor.execute[${nodeId}:${reason}]: no runMode, skipping execution`);
3020
+ console.trace(`NodeExecutor.execute[${formatNodeRef(this.graph, nodeId)}:${reason}]: no runMode, skipping execution`);
3068
3021
  return;
3069
3022
  }
3070
3023
  // In manual mode, require runContextIds unless autoRun policy is set
3071
3024
  if (runMode === "manual" && (!runContextIds || runContextIds.size === 0)) {
3072
3025
  // If autoRun is true, auto-generate a run context (similar to createExecutionContext pattern)
3073
3026
  if (node.policy?.autoRun === true) {
3074
- runContextIds = new Set([
3075
- this.runContextManager.createRunContext(nodeId, { propagate: false }),
3076
- ]);
3027
+ runContextIds = new Set([this.runContextManager.createRunContext(nodeId, { propagate: false })]);
3077
3028
  }
3078
3029
  else {
3079
- console.trace(`NodeExecutor.execute[${nodeId}:${reason}]: no runContextIds provided in manual mode, skipping execution`);
3030
+ console.trace(`NodeExecutor.execute[${formatNodeRef(this.graph, nodeId)}:${reason}]: no runContextIds provided in manual mode, skipping execution`);
3080
3031
  return;
3081
3032
  }
3082
3033
  }
3083
3034
  if (runMode === "auto" && runContextIds && runContextIds.size > 0) {
3084
- console.trace(`NodeExecutor.execute[${nodeId}:${reason}]: runContextIds provided in auto mode, ignoring`);
3035
+ console.trace(`NodeExecutor.execute[${formatNodeRef(this.graph, nodeId)}:${reason}]: runContextIds provided in auto mode, ignoring`);
3085
3036
  runContextIds = undefined;
3086
3037
  }
3087
3038
  // Early validation for auto-mode paused state
@@ -3096,6 +3047,7 @@ class NodeExecutor {
3096
3047
  code: runtimeValidationError.code || "RUNTIME_VALIDATION_BLOCKED",
3097
3048
  details: {
3098
3049
  nodeId,
3050
+ nodeTypeId: node?.typeId,
3099
3051
  ...runtimeValidationError.details,
3100
3052
  },
3101
3053
  });
@@ -3106,8 +3058,7 @@ class NodeExecutor {
3106
3058
  if (runContextIds) {
3107
3059
  this.graph.addNodeRunContextIds(nodeId, runContextIds);
3108
3060
  }
3109
- if (!canSkipHandleResolution &&
3110
- !this.handleResolver.getPendingResolution(nodeId)) {
3061
+ if (!canSkipHandleResolution && !this.handleResolver.getPendingResolution(nodeId)) {
3111
3062
  this.handleResolver.scheduleRecomputeHandles(nodeId);
3112
3063
  }
3113
3064
  // Check if handles are being resolved - wait for resolution before executing
@@ -3158,9 +3109,7 @@ class NodeExecutor {
3158
3109
  return false;
3159
3110
  const policy = node.policy ?? {};
3160
3111
  const lastScheduledAt = node.lastScheduledAt;
3161
- return !!(policy.debounceMs &&
3162
- lastScheduledAt &&
3163
- now - lastScheduledAt < policy.debounceMs);
3112
+ return !!(policy.debounceMs && lastScheduledAt && now - lastScheduledAt < policy.debounceMs);
3164
3113
  }
3165
3114
  /**
3166
3115
  * Handle debounced scheduling by replacing the latest queued item
@@ -3443,6 +3392,7 @@ class NodeExecutor {
3443
3392
  this.eventEmitter.emit("error", {
3444
3393
  kind: "node-run",
3445
3394
  nodeId,
3395
+ nodeTypeId: node.typeId,
3446
3396
  runId: plan.runId,
3447
3397
  err,
3448
3398
  });
@@ -3475,9 +3425,7 @@ class NodeExecutor {
3475
3425
  return;
3476
3426
  const controllers = this.graph.getNodeControllers(nodeId);
3477
3427
  const lastEndAt = Date.now();
3478
- const lastDurationMs = node.stats.lastStartAt && lastEndAt
3479
- ? lastEndAt - node.stats.lastStartAt
3480
- : undefined;
3428
+ const lastDurationMs = node.stats.lastStartAt && lastEndAt ? lastEndAt - node.stats.lastStartAt : undefined;
3481
3429
  this.graph.updateNodeStats(nodeId, {
3482
3430
  active: Math.max(0, controllers.size),
3483
3431
  lastEndAt,
@@ -3645,7 +3593,7 @@ class RuntimeValidatorManager {
3645
3593
  }
3646
3594
  catch (err) {
3647
3595
  // Don't let validator errors break execution - log and continue
3648
- console.error(`Runtime validator error for node ${nodeId}:`, err);
3596
+ console.error(`Runtime validator error for node ${formatNodeRef(this.graph, nodeId)}:`, err);
3649
3597
  }
3650
3598
  }
3651
3599
  return null;
@@ -3666,7 +3614,7 @@ class GraphRuntime {
3666
3614
  this.graph = new Graph(this.eventEmitter);
3667
3615
  this.runContextManager = new RunContextManager(this.graph, "warn");
3668
3616
  this.handleResolver = new HandleResolver(this.graph, this.eventEmitter, this.runContextManager, this);
3669
- this.edgePropagator = new EdgePropagator(this.graph, this.eventEmitter, this.runContextManager, this.handleResolver, this, this);
3617
+ this.edgePropagator = new EdgePropagator(this.graph, this.eventEmitter, this.runContextManager, this, this);
3670
3618
  // Create NodeExecutor with EdgePropagator and HandleResolver
3671
3619
  this.nodeExecutor = new NodeExecutor(this.graph, this.eventEmitter, this.runContextManager, this.handleResolver, this, this);
3672
3620
  // Create RuntimeValidatorManager
@@ -3755,6 +3703,30 @@ class GraphRuntime {
3755
3703
  on(event, handler) {
3756
3704
  return this.eventEmitter.on(event, handler);
3757
3705
  }
3706
+ /**
3707
+ * Check if an event is an invalidate event that should trigger re-execution
3708
+ */
3709
+ isInvalidateEvent(event) {
3710
+ if (!event || typeof event !== "object")
3711
+ return false;
3712
+ // Check if event has action === "invalidate"
3713
+ const e = event;
3714
+ return e.action === "invalidate";
3715
+ }
3716
+ executeNodeAutoRun(nodeId, opts) {
3717
+ const node = this.graph.getNode(nodeId);
3718
+ const shouldAutoRun = this.runMode === "auto" || node?.policy?.autoRun === true;
3719
+ let runContextIdsToUse = undefined;
3720
+ if (this.runMode === "manual") {
3721
+ runContextIdsToUse = new Set([this.runContextManager.createRunContext(nodeId, { propagate: false })]);
3722
+ }
3723
+ if (shouldAutoRun && this.graph.allInboundHaveValue(nodeId)) {
3724
+ this.execute(nodeId, {
3725
+ runContextIds: runContextIdsToUse,
3726
+ reason: opts?.reason ?? "executeNodeAutoRun",
3727
+ });
3728
+ }
3729
+ }
3758
3730
  setInputs(nodeId, inputs) {
3759
3731
  const node = this.graph.getNode(nodeId);
3760
3732
  if (!node)
@@ -3780,11 +3752,7 @@ class GraphRuntime {
3780
3752
  : desc
3781
3753
  ? getInputDeclaredTypes(desc.inputs, handle)
3782
3754
  : undefined;
3783
- const typeIds = Array.isArray(declaredTypes)
3784
- ? declaredTypes
3785
- : declaredTypes
3786
- ? [declaredTypes]
3787
- : [];
3755
+ const typeIds = Array.isArray(declaredTypes) ? declaredTypes : declaredTypes ? [declaredTypes] : [];
3788
3756
  if (typeIds.length > 0) {
3789
3757
  const isValidForAny = typeIds.some((tId) => {
3790
3758
  const typeDesc = registry.types.get(tId);
@@ -3795,10 +3763,11 @@ class GraphRuntime {
3795
3763
  });
3796
3764
  if (value !== undefined && !isValidForAny) {
3797
3765
  const typeLabel = typeIds.join("|");
3798
- const errorMessage = `Invalid value for input ${nodeId}.${handle} (type ${typeLabel}): ${JSON.stringify(value)}`;
3766
+ const errorMessage = `Invalid value for input ${formatNodeRef(this.graph, nodeId)}.${handle} (type ${typeLabel}): ${JSON.stringify(value)}`;
3799
3767
  this.eventEmitter.emit("error", {
3800
3768
  kind: "input-validation",
3801
3769
  nodeId,
3770
+ nodeTypeId: node.typeId,
3802
3771
  handle,
3803
3772
  typeId: typeLabel,
3804
3773
  value,
@@ -3813,8 +3782,6 @@ class GraphRuntime {
3813
3782
  const same = valuesEqual(prev, value);
3814
3783
  if (!same) {
3815
3784
  this.graph.updateNodeInput(nodeId, handle, value);
3816
- // Emit value event for input updates
3817
- this.eventEmitter.emit("value", { nodeId, handle, value, io: "input" });
3818
3785
  anyChanged = true;
3819
3786
  }
3820
3787
  }
@@ -3866,16 +3833,6 @@ class GraphRuntime {
3866
3833
  // Forward event to node's onExternalEvent handler for custom actions
3867
3834
  node.runtime.onExternalEvent?.(event, node.state);
3868
3835
  }
3869
- /**
3870
- * Check if an event is an invalidate event that should trigger re-execution
3871
- */
3872
- isInvalidateEvent(event) {
3873
- if (!event || typeof event !== "object")
3874
- return false;
3875
- // Check if event has action === "invalidate"
3876
- const e = event;
3877
- return e.action === "invalidate";
3878
- }
3879
3836
  cancelNodeRuns(nodeIds) {
3880
3837
  this.nodeExecutor.cancelNodeRuns(nodeIds);
3881
3838
  }
@@ -3903,6 +3860,7 @@ class GraphRuntime {
3903
3860
  this.nodeExecutor.setEnvironment(this.environment);
3904
3861
  for (const nodeId of this.graph.getNodeIds()) {
3905
3862
  this.handleResolver.scheduleRecomputeHandles(nodeId);
3863
+ this.executeNodeAutoRun(nodeId, { reason: "setEnvironment" });
3906
3864
  }
3907
3865
  }
3908
3866
  setCustomNodeData(customNodeData) {
@@ -4050,21 +4008,10 @@ class GraphRuntime {
4050
4008
  }
4051
4009
  }
4052
4010
  }
4053
- executeNodeAutoRun(nodeId, opts) {
4054
- const node = this.graph.getNode(nodeId);
4055
- const shouldAutoRun = this.runMode === "auto" || node?.policy?.autoRun === true;
4056
- let runContextIdsToUse = undefined;
4057
- if (this.runMode === "manual") {
4058
- runContextIdsToUse = new Set([
4059
- this.runContextManager.createRunContext(nodeId, { propagate: false }),
4060
- ]);
4061
- }
4062
- if (shouldAutoRun && this.graph.allInboundHaveValue(nodeId)) {
4063
- this.execute(nodeId, {
4064
- runContextIds: runContextIdsToUse,
4065
- reason: opts?.reason ?? "executeNodeAutoRun",
4066
- });
4067
- }
4011
+ setTargetInput(edge, value, reason) {
4012
+ this.graph.updateNodeInput(edge.target.nodeId, edge.target.handle, value);
4013
+ this.handleResolver.scheduleRecomputeHandles(edge.target.nodeId);
4014
+ this.executeNodeAutoRun(edge.target.nodeId, { reason });
4068
4015
  }
4069
4016
  copyOutputs(fromNodeId, toNodeId, options) {
4070
4017
  const fromNode = this.getNodeData(fromNodeId);
@@ -4230,8 +4177,7 @@ class GraphRuntime {
4230
4177
  set.add(e.target.handle);
4231
4178
  beforeInbound.set(e.target.nodeId, set);
4232
4179
  // Build beforeOutTargets map
4233
- const tmap = beforeOutTargets.get(e.source.nodeId) ??
4234
- new Map();
4180
+ const tmap = beforeOutTargets.get(e.source.nodeId) ?? new Map();
4235
4181
  const tset = tmap.get(e.source.handle) ?? new Set();
4236
4182
  tset.add(`${e.target.nodeId}.${e.target.handle}`);
4237
4183
  tmap.set(e.source.handle, tset);
@@ -4251,8 +4197,7 @@ class GraphRuntime {
4251
4197
  const changedHandles = {};
4252
4198
  for (const [nodeId, newHandles] of result.resolved) {
4253
4199
  const oldHandles = this.graph.getResolvedHandles(nodeId);
4254
- if (!oldHandles ||
4255
- JSON.stringify(oldHandles) !== JSON.stringify(newHandles)) {
4200
+ if (!oldHandles || JSON.stringify(oldHandles) !== JSON.stringify(newHandles)) {
4256
4201
  changedHandles[nodeId] = newHandles;
4257
4202
  }
4258
4203
  }
@@ -4304,8 +4249,7 @@ class GraphRuntime {
4304
4249
  // Propagate changes on edges added
4305
4250
  const afterOutTargets = new Map();
4306
4251
  this.graph.forEachEdge((e) => {
4307
- const targetMap = afterOutTargets.get(e.source.nodeId) ??
4308
- new Map();
4252
+ const targetMap = afterOutTargets.get(e.source.nodeId) ?? new Map();
4309
4253
  const targetSet = targetMap.get(e.source.handle) ?? new Set();
4310
4254
  targetSet.add(`${e.target.nodeId}.${e.target.handle}`);
4311
4255
  targetMap.set(e.source.handle, targetSet);
@@ -4330,10 +4274,7 @@ class GraphRuntime {
4330
4274
  for (const nodeId of nodesToCheck) {
4331
4275
  const beforeMap = beforeOutTargets.get(nodeId) ?? new Map();
4332
4276
  const afterMap = afterOutTargets.get(nodeId) ?? new Map();
4333
- const handles = new Set([
4334
- ...Array.from(beforeMap.keys()),
4335
- ...Array.from(afterMap.keys()),
4336
- ]);
4277
+ const handles = new Set([...Array.from(beforeMap.keys()), ...Array.from(afterMap.keys())]);
4337
4278
  for (const handle of handles) {
4338
4279
  const beforeTargetSet = beforeMap.get(handle) ?? new Set();
4339
4280
  const afterTargetSet = afterMap.get(handle) ?? new Set();
@@ -4454,7 +4395,10 @@ class GraphBuilder {
4454
4395
  effByNodeId.set(n.nodeId, getEffectiveHandles(n));
4455
4396
  const nodeType = this.registry.nodes.get(n.typeId);
4456
4397
  if (!nodeType) {
4457
- pushIssue("error", "NODE_TYPE_MISSING", `Unknown node type ${n.typeId}`, { typeId: n.typeId, nodeId: n.nodeId });
4398
+ pushIssue("error", "NODE_TYPE_MISSING", `Unknown node type ${n.typeId}`, {
4399
+ typeId: n.typeId,
4400
+ nodeId: n.nodeId,
4401
+ });
4458
4402
  continue;
4459
4403
  }
4460
4404
  if (!this.registry.categories.has(nodeType.categoryId)) {
@@ -4474,9 +4418,7 @@ class GraphBuilder {
4474
4418
  typeof paramValue === "number" &&
4475
4419
  !enumTypes.some((et) => validateEnumValue(et, paramValue, n.nodeId))) {
4476
4420
  const enumDef = this.registry.enums.get(enumTypes[0]);
4477
- const validValues = enumDef
4478
- ? Array.from(enumDef.valueToLabel.keys()).join(", ")
4479
- : "unknown";
4421
+ const validValues = enumDef ? Array.from(enumDef.valueToLabel.keys()).join(", ") : "unknown";
4480
4422
  pushIssue("error", "ENUM_VALUE_INVALID", `Node ${n.nodeId} param ${paramKey} has invalid enum value ${paramValue}. Valid values: ${validValues}`, {
4481
4423
  nodeId: n.nodeId,
4482
4424
  input: paramKey,
@@ -4496,9 +4438,7 @@ class GraphBuilder {
4496
4438
  typeof defaultValue === "number" &&
4497
4439
  !enumTypes.some((et) => validateEnumValue(et, defaultValue, n.nodeId))) {
4498
4440
  const enumDef = this.registry.enums.get(enumTypes[0]);
4499
- const validValues = enumDef
4500
- ? Array.from(enumDef.valueToLabel.keys()).join(", ")
4501
- : "unknown";
4441
+ const validValues = enumDef ? Array.from(enumDef.valueToLabel.keys()).join(", ") : "unknown";
4502
4442
  pushIssue("warning", "ENUM_DEFAULT_INVALID", `Node ${n.nodeId} input default ${handle} has invalid enum value ${defaultValue}. Valid values: ${validValues}`, {
4503
4443
  nodeId: n.nodeId,
4504
4444
  input: handle,
@@ -4541,7 +4481,9 @@ class GraphBuilder {
4541
4481
  if (e.typeId) {
4542
4482
  const type = this.registry.types.get(e.typeId);
4543
4483
  if (!type) {
4544
- pushIssue("error", "TYPE_MISSING", `Edge ${e.id} explicit type ${e.typeId} is missing or unknown`, { edgeId: e.id });
4484
+ pushIssue("error", "TYPE_MISSING", `Edge ${e.id} explicit type ${e.typeId} is missing or unknown`, {
4485
+ edgeId: e.id,
4486
+ });
4545
4487
  }
4546
4488
  }
4547
4489
  if (srcNode) {
@@ -4630,19 +4572,13 @@ class GraphBuilder {
4630
4572
  const outputTypes = {};
4631
4573
  for (const [outerIn, map] of Object.entries(exposure.inputs)) {
4632
4574
  const innerNode = def.nodes.find((n) => n.nodeId === map.nodeId);
4633
- const innerDesc = innerNode
4634
- ? this.registry.nodes.get(innerNode.typeId)
4635
- : undefined;
4636
- const typeIds = innerDesc
4637
- ? getInputDeclaredTypes(innerDesc.inputs, map.handle)
4638
- : undefined;
4575
+ const innerDesc = innerNode ? this.registry.nodes.get(innerNode.typeId) : undefined;
4576
+ const typeIds = innerDesc ? getInputDeclaredTypes(innerDesc.inputs, map.handle) : undefined;
4639
4577
  inputTypes[outerIn] = typeIds ?? "unknown";
4640
4578
  }
4641
4579
  for (const [outerOut, map] of Object.entries(exposure.outputs)) {
4642
4580
  const innerNode = def.nodes.find((n) => n.nodeId === map.nodeId);
4643
- const innerDesc = innerNode
4644
- ? this.registry.nodes.get(innerNode.typeId)
4645
- : undefined;
4581
+ const innerDesc = innerNode ? this.registry.nodes.get(innerNode.typeId) : undefined;
4646
4582
  const typeId = innerDesc ? innerDesc.outputs[map.handle] : undefined;
4647
4583
  const single = Array.isArray(typeId) ? typeId[0] : typeId;
4648
4584
  outputTypes[outerOut] = single ?? "unknown";
@@ -4845,7 +4781,7 @@ const CompositeCategory = (registry) => ({
4845
4781
  });
4846
4782
 
4847
4783
  // Helpers
4848
- const asArray = (v) => Array.isArray(v) ? v : [Number(v)];
4784
+ const asArray = (v) => (Array.isArray(v) ? v : [Number(v)]);
4849
4785
  const broadcast = (a, b) => {
4850
4786
  const aa = asArray(a);
4851
4787
  const bb = asArray(b);
@@ -4858,7 +4794,7 @@ const broadcast = (a, b) => {
4858
4794
  const len = Math.max(aa.length, bb.length);
4859
4795
  return [new Array(len).fill(aa[0] ?? 0), new Array(len).fill(bb[0] ?? 0)];
4860
4796
  };
4861
- const asBoolArray = (v) => Array.isArray(v) ? v.map((x) => Boolean(x)) : [Boolean(v)];
4797
+ const asBoolArray = (v) => (Array.isArray(v) ? v.map((x) => Boolean(x)) : [Boolean(v)]);
4862
4798
  const broadcastBool = (a, b) => {
4863
4799
  const aa = asBoolArray(a);
4864
4800
  const bb = asBoolArray(b);
@@ -4869,10 +4805,7 @@ const broadcastBool = (a, b) => {
4869
4805
  if (bb.length === 1)
4870
4806
  return [aa, new Array(aa.length).fill(bb[0])];
4871
4807
  const len = Math.max(aa.length, bb.length);
4872
- return [
4873
- new Array(len).fill(aa[0] ?? false),
4874
- new Array(len).fill(bb[0] ?? false),
4875
- ];
4808
+ return [new Array(len).fill(aa[0] ?? false), new Array(len).fill(bb[0] ?? false)];
4876
4809
  };
4877
4810
  const clamp = (x, min, max) => Math.min(max, Math.max(min, x));
4878
4811
  const lerp = (a, b, t) => a + (b - a) * t;
@@ -4922,8 +4855,7 @@ function jsonPointerSet(obj, pointer, value) {
4922
4855
  if (next === undefined || next === null) {
4923
4856
  // create container heuristically
4924
4857
  const nextKey = parts[i + 1];
4925
- cur[key] =
4926
- typeof nextKey === "string" && /^[0-9]+$/.test(nextKey) ? [] : {};
4858
+ cur[key] = typeof nextKey === "string" && /^[0-9]+$/.test(nextKey) ? [] : {};
4927
4859
  }
4928
4860
  cur = cur[key];
4929
4861
  }
@@ -5057,9 +4989,7 @@ function setupBasicGraphRegistry(id) {
5057
4989
  }, { withArray: false });
5058
4990
  registry.registerType({
5059
4991
  id: "base.vec3",
5060
- validate: (v) => Array.isArray(v) &&
5061
- v.length === 3 &&
5062
- v.every((x) => typeof x === "number"),
4992
+ validate: (v) => Array.isArray(v) && v.length === 3 && v.every((x) => typeof x === "number"),
5063
4993
  bakeTarget: { nodeTypeId: "base.input.vec3", inputHandle: "Value" },
5064
4994
  }, { withArray: true, arrayPickFirstDefined: true });
5065
4995
  // float -> vec3 : map x to [x,0,0]
@@ -5104,9 +5034,7 @@ function setupBasicGraphRegistry(id) {
5104
5034
  });
5105
5035
  registry.registerCoercion("base.object", "base.vec3", (v) => {
5106
5036
  try {
5107
- if (Array.isArray(v) &&
5108
- v.length === 3 &&
5109
- v.every((x) => typeof x === "number")) {
5037
+ if (Array.isArray(v) && v.length === 3 && v.every((x) => typeof x === "number")) {
5110
5038
  return v;
5111
5039
  }
5112
5040
  return undefined;
@@ -5236,9 +5164,7 @@ function setupBasicGraphRegistry(id) {
5236
5164
  const [a, b] = broadcast(ins.ValueA, ins.ValueB);
5237
5165
  const t = Number(ins.Factor ?? 0);
5238
5166
  const len = Math.max(a.length, b.length);
5239
- const out = new Array(len)
5240
- .fill(0)
5241
- .map((_, i) => lerp(Number(a[i] ?? 0), Number(b[i] ?? 0), t));
5167
+ const out = new Array(len).fill(0).map((_, i) => lerp(Number(a[i] ?? 0), Number(b[i] ?? 0), t));
5242
5168
  return { Value: out };
5243
5169
  },
5244
5170
  });
@@ -5266,9 +5192,7 @@ function setupBasicGraphRegistry(id) {
5266
5192
  const out = vals.map((v) => {
5267
5193
  const t = (Number(v) - fromMin) / (fromMax - fromMin || 1);
5268
5194
  const r = toMin + t * (toMax - toMin);
5269
- return doClamp
5270
- ? clamp(r, Math.min(toMin, toMax), Math.max(toMin, toMax))
5271
- : r;
5195
+ return doClamp ? clamp(r, Math.min(toMin, toMax), Math.max(toMin, toMax)) : r;
5272
5196
  });
5273
5197
  return { Value: out };
5274
5198
  },
@@ -5312,8 +5236,8 @@ function setupBasicGraphRegistry(id) {
5312
5236
  const sum = arr.reduce((s, x) => s + Number(x || 0), 0);
5313
5237
  return arr.length ? sum / arr.length : 0;
5314
5238
  },
5315
- [BaseMathOperation.MinAll]: (arr) => arr.length ? Math.min(...arr.map((x) => Number(x))) : 0,
5316
- [BaseMathOperation.MaxAll]: (arr) => arr.length ? Math.max(...arr.map((x) => Number(x))) : 0,
5239
+ [BaseMathOperation.MinAll]: (arr) => (arr.length ? Math.min(...arr.map((x) => Number(x))) : 0),
5240
+ [BaseMathOperation.MaxAll]: (arr) => (arr.length ? Math.max(...arr.map((x) => Number(x))) : 0),
5317
5241
  };
5318
5242
  if (aggregateByOp[op] !== undefined)
5319
5243
  return { Result: [aggregateByOp[op](a)] };
@@ -5330,8 +5254,8 @@ function setupBasicGraphRegistry(id) {
5330
5254
  const fn = binaryByOp[op] || binaryByOp[BaseMathOperation.Add];
5331
5255
  const len = Math.max(a.length, b.length);
5332
5256
  const out = new Array(len).fill(0).map((_, i) => {
5333
- const ax = a.length === 1 && len > 1 ? a[0] : a[i] ?? 0;
5334
- const bx = b.length === 1 && len > 1 ? b[0] : b[i] ?? 0;
5257
+ const ax = a.length === 1 && len > 1 ? a[0] : (a[i] ?? 0);
5258
+ const bx = b.length === 1 && len > 1 ? b[0] : (b[i] ?? 0);
5335
5259
  return fn(Number(ax), Number(bx));
5336
5260
  });
5337
5261
  return { Result: out };
@@ -5472,9 +5396,7 @@ function setupBasicGraphRegistry(id) {
5472
5396
  impl: (ins) => {
5473
5397
  const arr = Array.isArray(ins.Items) ? ins.Items : [];
5474
5398
  const s = Math.trunc(Number(ins.Start ?? 0));
5475
- const e = Number.isFinite(Number(ins.End))
5476
- ? Math.trunc(Number(ins.End))
5477
- : undefined;
5399
+ const e = Number.isFinite(Number(ins.End)) ? Math.trunc(Number(ins.End)) : undefined;
5478
5400
  return { Result: arr.slice(s, e) };
5479
5401
  },
5480
5402
  });
@@ -5749,11 +5671,7 @@ function setupBasicGraphRegistry(id) {
5749
5671
  outputs: { Keys: "base.string[]" },
5750
5672
  impl: (ins) => {
5751
5673
  const obj = ins.Object;
5752
- const keys = isPlainObject(obj)
5753
- ? Object.keys(obj)
5754
- : Array.isArray(obj)
5755
- ? Object.keys(obj)
5756
- : [];
5674
+ const keys = isPlainObject(obj) ? Object.keys(obj) : Array.isArray(obj) ? Object.keys(obj) : [];
5757
5675
  return { Keys: keys };
5758
5676
  },
5759
5677
  });
@@ -5764,11 +5682,7 @@ function setupBasicGraphRegistry(id) {
5764
5682
  outputs: { Values: "base.object" },
5765
5683
  impl: (ins) => {
5766
5684
  const obj = ins.Object;
5767
- const vals = isPlainObject(obj)
5768
- ? Object.values(obj)
5769
- : Array.isArray(obj)
5770
- ? Object.values(obj)
5771
- : [];
5685
+ const vals = isPlainObject(obj) ? Object.values(obj) : Array.isArray(obj) ? Object.values(obj) : [];
5772
5686
  return { Values: vals };
5773
5687
  },
5774
5688
  });
@@ -5780,11 +5694,7 @@ function setupBasicGraphRegistry(id) {
5780
5694
  impl: (ins) => {
5781
5695
  const root = structuredClone(ins.Object);
5782
5696
  const opsRaw = ins.Ops;
5783
- const ops = Array.isArray(opsRaw)
5784
- ? opsRaw
5785
- : opsRaw
5786
- ? [opsRaw]
5787
- : [];
5697
+ const ops = Array.isArray(opsRaw) ? opsRaw : opsRaw ? [opsRaw] : [];
5788
5698
  let cur = root;
5789
5699
  for (const op of ops) {
5790
5700
  if (!op || typeof op !== "object")
@@ -5875,9 +5785,7 @@ function registerDelayNode(registry) {
5875
5785
  impl: async (ins, ctx) => {
5876
5786
  const ms = Number(ins.DelayMs ?? 200);
5877
5787
  const valueRaw = ins.Value;
5878
- if (valueRaw === undefined ||
5879
- valueRaw === null ||
5880
- Number.isNaN(Number(valueRaw))) {
5788
+ if (valueRaw === undefined || valueRaw === null || Number.isNaN(Number(valueRaw))) {
5881
5789
  return; // wait until x is present to avoid NaN emissions
5882
5790
  }
5883
5791
  await new Promise((resolve, reject) => {
@@ -5947,9 +5855,7 @@ function generateId(prefix, used = new Set()) {
5947
5855
  id = `${prefix}${Math.random().toString(36).slice(2, 8)}`;
5948
5856
  attempts++;
5949
5857
  if (attempts > 1000) {
5950
- id = `${prefix}${Date.now().toString(36)}${Math.random()
5951
- .toString(36)
5952
- .slice(2, 4)}`;
5858
+ id = `${prefix}${Date.now().toString(36)}${Math.random().toString(36).slice(2, 4)}`;
5953
5859
  }
5954
5860
  } while (used.has(id));
5955
5861
  return id;
@@ -5990,12 +5896,10 @@ function installLogging(engine) {
5990
5896
  console.warn(`[error] input-validation: ${e.nodeId}.${e.handle} (type ${e.typeId})`, e.message);
5991
5897
  }
5992
5898
  else if (e.kind === "registry") {
5993
- console.warn(`[error] registry:`, e.err?.message ?? e.err, e.attempt !== undefined
5994
- ? `(attempt ${e.attempt}/${e.maxAttempts ?? "?"})`
5995
- : "");
5899
+ console.warn(`[error] registry:`, e.err?.message ?? e.err, e.attempt !== undefined ? `(attempt ${e.attempt}/${e.maxAttempts ?? "?"})` : "");
5996
5900
  }
5997
5901
  else if (e.kind === "system") {
5998
- console.warn(`[error] system: ${e.message}`, e.code ? `(code: ${e.code})` : "", e.err ? e.err?.message ?? e.err : "", e.details ? JSON.stringify(e.details) : "");
5902
+ console.warn(`[error] system: ${e.message}`, e.code ? `(code: ${e.code})` : "", e.err ? (e.err?.message ?? e.err) : "", e.details ? JSON.stringify(e.details) : "");
5999
5903
  }
6000
5904
  else {
6001
5905
  // Log any other error kinds (shouldn't happen, but handle gracefully)
@@ -6320,11 +6224,7 @@ function buildTypeMaps(def) {
6320
6224
  }
6321
6225
  if (node.resolvedHandles?.outputs) {
6322
6226
  for (const [handleId, handleDesc] of Object.entries(node.resolvedHandles.outputs)) {
6323
- const typeId = typeof handleDesc === "string"
6324
- ? handleDesc
6325
- : Array.isArray(handleDesc)
6326
- ? handleDesc[0]
6327
- : undefined;
6227
+ const typeId = typeof handleDesc === "string" ? handleDesc : Array.isArray(handleDesc) ? handleDesc[0] : undefined;
6328
6228
  if (typeId)
6329
6229
  nodeOutputTypes.set(handleId, typeId);
6330
6230
  }
@@ -6375,8 +6275,7 @@ function applyConversion(items, values, converter, type) {
6375
6275
  });
6376
6276
  if (convertedValue === null) {
6377
6277
  delete values[item.nodeId]?.[item.handleId];
6378
- if (values[item.nodeId] &&
6379
- Object.keys(values[item.nodeId]).length === 0) {
6278
+ if (values[item.nodeId] && Object.keys(values[item.nodeId]).length === 0) {
6380
6279
  delete values[item.nodeId];
6381
6280
  }
6382
6281
  }
@@ -6422,7 +6321,7 @@ function convertSnapshot(snapshot, converter) {
6422
6321
  }
6423
6322
  const { converted: convertedInputs, toConvert: inputsToConvert } = collectValuesToConvert(snapshot.inputs ?? {}, nodeTypeMap, inputHandleTypeMap, outputHandleTypeMap, "input");
6424
6323
  const { converted: convertedOutputs, toConvert: outputsToConvert } = collectValuesToConvert(snapshot.outputs ?? {}, nodeTypeMap, inputHandleTypeMap, outputHandleTypeMap, "output");
6425
- const { converted: convertedInputDefaults, toConvert: inputDefaultsToConvert, } = collectValuesToConvert(inputDefaults, nodeTypeMap, inputHandleTypeMap, outputHandleTypeMap, "inputDefault");
6324
+ const { converted: convertedInputDefaults, toConvert: inputDefaultsToConvert } = collectValuesToConvert(inputDefaults, nodeTypeMap, inputHandleTypeMap, outputHandleTypeMap, "inputDefault");
6426
6325
  applyConversion(inputsToConvert, convertedInputs, converter, "input");
6427
6326
  applyConversion(outputsToConvert, convertedOutputs, converter, "output");
6428
6327
  applyConversion(inputDefaultsToConvert, convertedInputDefaults, converter, "inputDefault");
@@ -6612,7 +6511,7 @@ function matchesPattern(value, pattern) {
6612
6511
  */
6613
6512
  function buildValueConverter(config) {
6614
6513
  return (converterConfig) => {
6615
- const { nodeId, handleId, value, type, nodeTypeId, handleDataType, runtimeTypeId, } = converterConfig;
6514
+ const { nodeId, handleId, value, type, nodeTypeId, handleDataType, runtimeTypeId } = converterConfig;
6616
6515
  const isValueTyped = isTyped(value);
6617
6516
  for (const mapping of config.mappings) {
6618
6517
  if (mapping.type && mapping.type !== type)
@@ -6655,8 +6554,7 @@ function buildValueConverter(config) {
6655
6554
  }
6656
6555
  }
6657
6556
  else {
6658
- if (typeof matchValue === "string" ||
6659
- typeof matchValue === "number") {
6557
+ if (typeof matchValue === "string" || typeof matchValue === "number") {
6660
6558
  const key = String(matchValue);
6661
6559
  if (key in mapping.valueMap) {
6662
6560
  newValue = mapping.valueMap[key];
@@ -6690,8 +6588,7 @@ function buildValueConverter(config) {
6690
6588
  }
6691
6589
  }
6692
6590
  else {
6693
- if (typeof innerValue === "string" ||
6694
- typeof innerValue === "number") {
6591
+ if (typeof innerValue === "string" || typeof innerValue === "number") {
6695
6592
  const key = String(innerValue);
6696
6593
  if (key in mapping.valueMap) {
6697
6594
  newValue = mapping.valueMap[key];
@@ -6718,8 +6615,7 @@ function buildValueConverter(config) {
6718
6615
  : firstSegment instanceof RegExp
6719
6616
  ? null
6720
6617
  : String(firstSegment);
6721
- if (firstSegmentStr !== "__spark_value" &&
6722
- firstSegmentStr !== "__spark_type") {
6618
+ if (firstSegmentStr !== "__spark_value" && firstSegmentStr !== "__spark_type") {
6723
6619
  pathSegments = ["__spark_value", ...pathSegments];
6724
6620
  }
6725
6621
  }
@@ -6739,8 +6635,7 @@ function buildValueConverter(config) {
6739
6635
  }
6740
6636
  }
6741
6637
  else {
6742
- if (typeof matchValue === "string" ||
6743
- typeof matchValue === "number") {
6638
+ if (typeof matchValue === "string" || typeof matchValue === "number") {
6744
6639
  const key = String(matchValue);
6745
6640
  if (key in mapping.valueMap) {
6746
6641
  newValue = mapping.valueMap[key];