@bian-womp/spark-workbench 0.2.13 → 0.2.15

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
@@ -761,8 +761,9 @@ class RemoteGraphRunner extends AbstractGraphRunner {
761
761
  if (!cache)
762
762
  return out;
763
763
  for (const n of def.nodes) {
764
+ const resolved = n.resolvedHandles?.outputs;
764
765
  const desc = this.registry.nodes.get(n.typeId);
765
- const handles = Object.keys(desc?.outputs ?? {});
766
+ const handles = Object.keys(resolved ?? desc?.outputs ?? {});
766
767
  for (const h of handles) {
767
768
  const key = `${n.nodeId}.${h}`;
768
769
  const rec = cache.get(key);
@@ -780,8 +781,9 @@ class RemoteGraphRunner extends AbstractGraphRunner {
780
781
  const cache = this.valueCache;
781
782
  for (const n of def.nodes) {
782
783
  const staged = this.stagedInputs[n.nodeId] ?? {};
784
+ const resolved = n.resolvedHandles?.inputs;
783
785
  const desc = this.registry.nodes.get(n.typeId);
784
- const handles = Object.keys(desc?.inputs ?? {});
786
+ const handles = Object.keys(resolved ?? desc?.inputs ?? {});
785
787
  const cur = {};
786
788
  for (const h of handles) {
787
789
  const rec = cache.get(`${n.nodeId}.${h}`);
@@ -1196,10 +1198,18 @@ function toReactFlow(def, positions, registry, opts) {
1196
1198
  }
1197
1199
  const nodes = def.nodes.map((n) => {
1198
1200
  const desc = registry.nodes.get(n.typeId);
1199
- const inputHandles = Object.entries(desc?.inputs ?? {})
1200
- .filter(([id]) => !sparkGraph.isInputPrivate(desc?.inputs, id))
1201
- .map(([id, v]) => ({ id, typeId: sparkGraph.getInputTypeId(desc?.inputs, id) }));
1202
- const outputHandles = Object.entries(desc?.outputs ?? {}).map(([id, typeId]) => ({ id, typeId: formatDeclaredTypeSignature(typeId) }));
1201
+ // Prefer per-node resolved handles when present
1202
+ const resolvedInputs = n.resolvedHandles?.inputs;
1203
+ const resolvedOutputs = n.resolvedHandles?.outputs;
1204
+ const inputSource = resolvedInputs ?? desc?.inputs ?? {};
1205
+ const outputSource = resolvedOutputs ?? desc?.outputs ?? {};
1206
+ const inputHandles = Object.entries(inputSource)
1207
+ .filter(([id]) => !sparkGraph.isInputPrivate(inputSource, id))
1208
+ .map(([id]) => ({ id, typeId: sparkGraph.getInputTypeId(inputSource, id) }));
1209
+ const outputHandles = Object.entries(outputSource).map(([id, typeId]) => ({
1210
+ id,
1211
+ typeId: formatDeclaredTypeSignature(typeId),
1212
+ }));
1203
1213
  nodeHandleMap[n.nodeId] = {
1204
1214
  inputs: new Set(inputHandles.map((h) => h.id)),
1205
1215
  outputs: new Set(outputHandles.map((h) => h.id)),
@@ -1519,6 +1529,27 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
1519
1529
  ];
1520
1530
  return next.length > 200 ? next.slice(0, 200) : next;
1521
1531
  });
1532
+ // Helper to refresh resolved handles from remote and merge into workbench
1533
+ const refreshResolvedHandles = async () => {
1534
+ try {
1535
+ const snap = await runner.snapshotFull();
1536
+ const remoteDef = snap?.def;
1537
+ if (remoteDef && Array.isArray(remoteDef.nodes)) {
1538
+ const cur = wb.export();
1539
+ const merged = {
1540
+ ...cur,
1541
+ nodes: cur.nodes.map((n) => {
1542
+ const rn = (remoteDef.nodes || []).find((m) => m.nodeId === n.nodeId);
1543
+ if (rn && rn.resolvedHandles)
1544
+ return { ...n, resolvedHandles: rn.resolvedHandles };
1545
+ return n;
1546
+ }),
1547
+ };
1548
+ await wb.load(merged);
1549
+ }
1550
+ }
1551
+ catch { }
1552
+ };
1522
1553
  const off1 = runner.on("value", (e) => {
1523
1554
  if (e?.io === "input") {
1524
1555
  const nodeId = e?.nodeId;
@@ -1526,6 +1557,8 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
1526
1557
  ...s,
1527
1558
  [nodeId]: { ...s[nodeId], invalidated: true },
1528
1559
  }));
1560
+ // On any input change, refresh resolved handles (covers context-driven dynamic ports)
1561
+ refreshResolvedHandles();
1529
1562
  }
1530
1563
  return add("runner", "value")(e);
1531
1564
  });
@@ -1569,6 +1602,9 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
1569
1602
  return next;
1570
1603
  });
1571
1604
  }
1605
+ // After build/update, pull resolved handles from remote snapshot and merge into local def for UI
1606
+ if (e?.reason === "graph-updated" || e?.reason === "graph-built")
1607
+ refreshResolvedHandles();
1572
1608
  return add("runner", "invalidate")(e);
1573
1609
  });
1574
1610
  const off3b = runner.on("stats", (s) => {
@@ -2119,10 +2155,10 @@ const DefaultNode = React.memo(function DefaultNode({ id, data, selected, isConn
2119
2155
  position: "relative",
2120
2156
  minWidth: typeof data.renderWidth === "number" ? data.renderWidth : undefined,
2121
2157
  minHeight: typeof data.renderHeight === "number" ? data.renderHeight : undefined,
2122
- }, children: [jsxRuntime.jsx(DefaultNodeHeader, { id: id, title: typeId, status: status, validation: validation }), jsxRuntime.jsx(DefaultNodeContent, { data: data, isConnectable: isConnectable })] }));
2158
+ }, children: [jsxRuntime.jsx(DefaultNodeHeader, { id: id, title: typeId, validation: validation, showId: data.showValues }), jsxRuntime.jsx(DefaultNodeContent, { data: data, isConnectable: isConnectable })] }));
2123
2159
  });
2124
2160
  DefaultNode.displayName = "DefaultNode";
2125
- function DefaultNodeHeader({ id, title, status, validation, right, onInvalidate, }) {
2161
+ function DefaultNodeHeader({ id, title, validation, right, showId, onInvalidate, }) {
2126
2162
  const ctx = useWorkbenchContext();
2127
2163
  const handleInvalidate = React.useCallback(() => {
2128
2164
  try {
@@ -2142,11 +2178,11 @@ function DefaultNodeHeader({ id, title, status, validation, right, onInvalidate,
2142
2178
  }, children: [jsxRuntime.jsx("strong", { className: "flex-1 h-full text-sm", style: { lineHeight: `${NODE_HEADER_HEIGHT_PX}px` }, children: title }), jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [jsxRuntime.jsx("button", { className: "w-4 h-4 border border-gray-400 rounded text-[10px] leading-3 flex items-center justify-center", title: "Invalidate and re-run", onClick: (e) => {
2143
2179
  e.stopPropagation();
2144
2180
  handleInvalidate();
2145
- }, children: "\u21BB" }), right, validation.issues && validation.issues.length > 0 && (jsxRuntime.jsx(IssueBadge, { level: validation.issues.some((i) => i.level === "error")
2181
+ }, children: jsxRuntime.jsx(react$1.ArrowClockwiseIcon, { size: 10 }) }), right, validation.issues && validation.issues.length > 0 && (jsxRuntime.jsx(IssueBadge, { level: validation.issues.some((i) => i.level === "error")
2146
2182
  ? "error"
2147
2183
  : "warning", size: 12, className: "w-3 h-3", title: validation.issues
2148
2184
  .map((v) => `${v.code}: ${v.message}`)
2149
- .join("; ") })), jsxRuntime.jsxs("span", { className: "text-[10px] opacity-70", children: ["(", id, ")"] })] })] }));
2185
+ .join("; ") })), showId && jsxRuntime.jsxs("span", { className: "text-[10px] opacity-70", children: ["(", id, ")"] })] })] }));
2150
2186
  }
2151
2187
  function DefaultNodeContent({ data, isConnectable, }) {
2152
2188
  const { showValues, inputValues, outputValues, toString } = data;
@@ -2911,8 +2947,11 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
2911
2947
  if (positions && typeof positions === "object")
2912
2948
  wb.setPositions(positions);
2913
2949
  }
2950
+ else if (!runner.isRunning()) {
2951
+ alert("Engine is not running");
2952
+ }
2914
2953
  else {
2915
- alert("Graph definition is empty or engine is not running");
2954
+ alert("Graph definition is empty");
2916
2955
  }
2917
2956
  }
2918
2957
  else {