@bian-womp/spark-workbench 0.2.92 → 0.2.94

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 (29) hide show
  1. package/lib/cjs/index.cjs +57 -63
  2. package/lib/cjs/index.cjs.map +1 -1
  3. package/lib/cjs/src/core/AbstractWorkbench.d.ts +8 -7
  4. package/lib/cjs/src/core/AbstractWorkbench.d.ts.map +1 -1
  5. package/lib/cjs/src/core/InMemoryWorkbench.d.ts +4 -2
  6. package/lib/cjs/src/core/InMemoryWorkbench.d.ts.map +1 -1
  7. package/lib/cjs/src/core/contracts.d.ts +5 -2
  8. package/lib/cjs/src/core/contracts.d.ts.map +1 -1
  9. package/lib/cjs/src/misc/WorkbenchCanvas.d.ts.map +1 -1
  10. package/lib/cjs/src/misc/WorkbenchStudio.d.ts.map +1 -1
  11. package/lib/cjs/src/misc/context/WorkbenchContext.d.ts +1 -2
  12. package/lib/cjs/src/misc/context/WorkbenchContext.d.ts.map +1 -1
  13. package/lib/cjs/src/misc/context/WorkbenchContext.provider.d.ts +1 -4
  14. package/lib/cjs/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
  15. package/lib/esm/index.js +58 -64
  16. package/lib/esm/index.js.map +1 -1
  17. package/lib/esm/src/core/AbstractWorkbench.d.ts +8 -7
  18. package/lib/esm/src/core/AbstractWorkbench.d.ts.map +1 -1
  19. package/lib/esm/src/core/InMemoryWorkbench.d.ts +4 -2
  20. package/lib/esm/src/core/InMemoryWorkbench.d.ts.map +1 -1
  21. package/lib/esm/src/core/contracts.d.ts +5 -2
  22. package/lib/esm/src/core/contracts.d.ts.map +1 -1
  23. package/lib/esm/src/misc/WorkbenchCanvas.d.ts.map +1 -1
  24. package/lib/esm/src/misc/WorkbenchStudio.d.ts.map +1 -1
  25. package/lib/esm/src/misc/context/WorkbenchContext.d.ts +1 -2
  26. package/lib/esm/src/misc/context/WorkbenchContext.d.ts.map +1 -1
  27. package/lib/esm/src/misc/context/WorkbenchContext.provider.d.ts +1 -4
  28. package/lib/esm/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
  29. package/package.json +4 -4
package/lib/cjs/index.cjs CHANGED
@@ -135,8 +135,8 @@ class AbstractWorkbench {
135
135
  }
136
136
 
137
137
  class InMemoryWorkbench extends AbstractWorkbench {
138
- constructor() {
139
- super(...arguments);
138
+ constructor(args) {
139
+ super(args);
140
140
  this._def = { nodes: [], edges: [] };
141
141
  this.listeners = new Map();
142
142
  this.positions = {};
@@ -150,12 +150,17 @@ class InMemoryWorkbench extends AbstractWorkbench {
150
150
  this.viewport = null;
151
151
  this.historyState = undefined;
152
152
  this.copiedData = null;
153
+ this._registry = sparkGraph.createSimpleGraphRegistry();
153
154
  }
154
155
  get def() {
155
156
  return this._def;
156
157
  }
158
+ get registry() {
159
+ return this._registry;
160
+ }
157
161
  setRegistry(registry) {
158
- this.registry = registry;
162
+ this._registry = registry;
163
+ this.emit("registryChanged", { registry });
159
164
  }
160
165
  async load(def) {
161
166
  this._def = { nodes: [...def.nodes], edges: [...def.edges] };
@@ -3649,7 +3654,7 @@ function computeInvalidatedFromMetadata(metadata) {
3649
3654
  const maxInputTime = Math.max(...Object.values(lastInputAt));
3650
3655
  return maxInputTime > (lastSuccessAt ?? lastRunAt ?? 0);
3651
3656
  }
3652
- function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVersion, children, }) {
3657
+ function WorkbenchProvider({ wb, runner, overrides, uiVersion, children, }) {
3653
3658
  const [nodeStatus, setNodeStatus] = React.useState({});
3654
3659
  const [edgeStatus, setEdgeStatus] = React.useState({});
3655
3660
  const [events, setEvents] = React.useState([]);
@@ -3657,6 +3662,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
3657
3662
  const [systemErrors, setSystemErrors] = React.useState([]);
3658
3663
  const [registryErrors, setRegistryErrors] = React.useState([]);
3659
3664
  const [inputValidationErrors, setInputValidationErrors] = React.useState([]);
3665
+ const [registryVersion, setRegistryVersion] = React.useState(0);
3660
3666
  const clearSystemErrors = React.useCallback(() => setSystemErrors([]), []);
3661
3667
  const clearRegistryErrors = React.useCallback(() => setRegistryErrors([]), []);
3662
3668
  const clearInputValidationErrors = React.useCallback(() => setInputValidationErrors([]), []);
@@ -3723,7 +3729,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
3723
3729
  const out = {};
3724
3730
  // Local: runtimeTypeId is not stored; derive from typed wrapper in outputsMap
3725
3731
  for (const n of wb.def.nodes) {
3726
- const effectiveHandles = computeEffectiveHandles(n, registry);
3732
+ const effectiveHandles = computeEffectiveHandles(n, wb.registry);
3727
3733
  const outputsDecl = effectiveHandles.outputs;
3728
3734
  const handles = Object.keys(outputsDecl);
3729
3735
  const cur = {};
@@ -3737,7 +3743,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
3737
3743
  out[n.nodeId] = cur;
3738
3744
  }
3739
3745
  return out;
3740
- }, [wb, wb.def, outputsMap, registry]);
3746
+ }, [wb, wb.def, outputsMap, wb.registry, registryVersion]);
3741
3747
  // Initialize nodes and derive invalidated status from persisted metadata
3742
3748
  React.useEffect(() => {
3743
3749
  const workbenchRuntimeState = wb.getRuntimeState() ?? { nodes: {} };
@@ -3815,7 +3821,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
3815
3821
  const overrideSize = overrides?.getDefaultNodeSize?.(node.typeId) ?? undefined;
3816
3822
  const size = estimateNodeSize({
3817
3823
  node,
3818
- registry,
3824
+ registry: wb.registry,
3819
3825
  showValues: true,
3820
3826
  overrides: overrideSize,
3821
3827
  });
@@ -3833,7 +3839,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
3833
3839
  curX += maxWidth + H_GAP;
3834
3840
  }
3835
3841
  wb.setPositions(pos, { commit: true, reason: "auto-layout" });
3836
- }, [wb, wb.def, registry, overrides?.getDefaultNodeSize]);
3842
+ }, [wb, wb.def, wb.registry, registryVersion, overrides?.getDefaultNodeSize]);
3837
3843
  const updateEdgeType = React.useCallback((edgeId, typeId) => wb.updateEdgeType(edgeId, typeId), [wb]);
3838
3844
  const triggerExternal = React.useCallback((nodeId, event) => runner.triggerExternal(nodeId, event), [runner]);
3839
3845
  const getNodeDisplayName = React.useCallback((nodeId) => {
@@ -3843,9 +3849,9 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
3843
3849
  const node = wb.def.nodes.find((n) => n.nodeId === nodeId);
3844
3850
  if (!node)
3845
3851
  return nodeId;
3846
- const desc = registry.nodes.get(node.typeId);
3852
+ const desc = wb.registry.nodes.get(node.typeId);
3847
3853
  return desc?.displayName || node.typeId;
3848
- }, [wb, registry]);
3854
+ }, [wb, wb.registry, registryVersion]);
3849
3855
  const setNodeName = React.useCallback((nodeId, name) => {
3850
3856
  wb.setNodeName(nodeId, name, { commit: true, reason: "rename-node" });
3851
3857
  }, [wb]);
@@ -4161,6 +4167,9 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4161
4167
  }
4162
4168
  return add("runner", "stats")(s);
4163
4169
  });
4170
+ const offWbRegistryChanged = wb.on("registryChanged", (evt) => {
4171
+ setRegistryVersion((v) => v + 1);
4172
+ });
4164
4173
  const offWbGraphChanged = wb.on("graphChanged", (event) => {
4165
4174
  // Clear validation errors for removed nodes
4166
4175
  if (event.change?.type === "removeNode") {
@@ -4317,8 +4326,8 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4317
4326
  // Registry updates: swap registry and refresh graph validation/UI
4318
4327
  const offRunnerRegistry = runner.on("registry", async (newReg) => {
4319
4328
  try {
4320
- setRegistry(newReg);
4321
4329
  wb.setRegistry(newReg);
4330
+ // Increment registry version to trigger UI updates
4322
4331
  // Trigger a graph update so the UI revalidates with new types/enums/nodes
4323
4332
  try {
4324
4333
  await runner.update(wb.def);
@@ -4389,6 +4398,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4389
4398
  offRunnerError();
4390
4399
  offRunnerInvalidate();
4391
4400
  offRunnerStats();
4401
+ offWbRegistryChanged();
4392
4402
  offWbGraphChanged();
4393
4403
  offWbGraphUiChangedForLog();
4394
4404
  offWbGraphUiChanged();
@@ -4402,7 +4412,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4402
4412
  offFlowViewport();
4403
4413
  offWbRuntimeMetadataChanged();
4404
4414
  };
4405
- }, [runner, wb, setRegistry]);
4415
+ }, [runner, wb]);
4406
4416
  const isRunning = React.useCallback(() => runner.isRunning(), [runner]);
4407
4417
  const engineKind = React.useCallback(() => runner.getRunningEngine(), [runner]);
4408
4418
  const start = React.useCallback((engine) => {
@@ -4480,8 +4490,6 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4480
4490
  const value = React.useMemo(() => ({
4481
4491
  wb,
4482
4492
  runner,
4483
- registry,
4484
- setRegistry,
4485
4493
  selectedNodeId,
4486
4494
  selectedEdgeId,
4487
4495
  setSelection,
@@ -4516,14 +4524,13 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4516
4524
  updateEdgeType,
4517
4525
  triggerExternal,
4518
4526
  uiVersion,
4527
+ registryVersion,
4519
4528
  overrides,
4520
4529
  getNodeDisplayName,
4521
4530
  setNodeName,
4522
4531
  }), [
4523
4532
  wb,
4524
4533
  runner,
4525
- registry,
4526
- setRegistry,
4527
4534
  selectedNodeId,
4528
4535
  selectedEdgeId,
4529
4536
  setSelection,
@@ -4557,6 +4564,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4557
4564
  wb,
4558
4565
  runner,
4559
4566
  uiVersion,
4567
+ registryVersion,
4560
4568
  overrides,
4561
4569
  getNodeDisplayName,
4562
4570
  setNodeName,
@@ -4584,7 +4592,7 @@ function DefaultNodeHeader({ id, typeId, validation, right, showId, onInvalidate
4584
4592
  const node = ctx.wb.def.nodes.find((n) => n.nodeId === id);
4585
4593
  if (!node)
4586
4594
  return id;
4587
- const desc = ctx.registry.nodes.get(node.typeId);
4595
+ const desc = ctx.wb.registry.nodes.get(node.typeId);
4588
4596
  return desc?.displayName || node.typeId;
4589
4597
  }, [ctx, id, typeId]);
4590
4598
  const handleInvalidate = React.useCallback(() => {
@@ -5043,7 +5051,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
5043
5051
  return String(value ?? "");
5044
5052
  }
5045
5053
  };
5046
- const { wb, registry, selectedNodeId, selectedEdgeId, inputsMap, inputDefaultsMap, outputsMap, outputTypesMap, nodeStatus, edgeStatus, validationByNode, validationByEdge, validationGlobal, valuesTick, updateEdgeType, systemErrors, registryErrors, inputValidationErrors, clearSystemErrors, clearRegistryErrors, clearInputValidationErrors, removeSystemError, removeRegistryError, removeInputValidationError, } = useWorkbenchContext();
5054
+ const { wb, registryVersion, selectedNodeId, selectedEdgeId, inputsMap, inputDefaultsMap, outputsMap, outputTypesMap, nodeStatus, edgeStatus, validationByNode, validationByEdge, validationGlobal, valuesTick, updateEdgeType, systemErrors, registryErrors, inputValidationErrors, clearSystemErrors, clearRegistryErrors, clearInputValidationErrors, removeSystemError, removeRegistryError, removeInputValidationError, } = useWorkbenchContext();
5047
5055
  const nodeValidationIssues = validationByNode.issues;
5048
5056
  const edgeValidationIssues = validationByEdge.issues;
5049
5057
  const nodeValidationHandles = validationByNode;
@@ -5052,7 +5060,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
5052
5060
  const selectedEdge = wb.def.edges.find((e) => e.id === selectedEdgeId);
5053
5061
  // Use computeEffectiveHandles to merge registry defaults with dynamically resolved handles
5054
5062
  const effectiveHandles = selectedNode
5055
- ? computeEffectiveHandles(selectedNode, registry)
5063
+ ? computeEffectiveHandles(selectedNode, wb.registry)
5056
5064
  : { inputs: {}, outputs: {}};
5057
5065
  const inputHandles = Object.entries(effectiveHandles.inputs)
5058
5066
  .filter(([k]) => !sparkGraph.isInputPrivate(effectiveHandles.inputs, k))
@@ -5179,7 +5187,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
5179
5187
  setDrafts(nextDrafts);
5180
5188
  if (!shallowEqual(originals, nextOriginals))
5181
5189
  setOriginals(nextOriginals);
5182
- }, [selectedNodeId, selectedNode, registry, valuesTick]);
5190
+ }, [selectedNodeId, selectedNode, wb.registry, registryVersion, valuesTick]);
5183
5191
  const widthClass = debug ? "w-[480px]" : "w-[320px]";
5184
5192
  const deleteEdgeById = (edgeId) => {
5185
5193
  if (!edgeId)
@@ -5199,7 +5207,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
5199
5207
  const v = e.target.value;
5200
5208
  const next = v === "" ? undefined : v;
5201
5209
  updateEdgeType(selectedEdge.id, next);
5202
- }, children: [jsxRuntime.jsx("option", { value: "", children: "(infer from source)" }), Array.from(registry.types.keys()).map((tid) => (jsxRuntime.jsx("option", { value: tid, children: tid }, tid)))] })] })] }), selectedEdgeValidation.length > 0 && (jsxRuntime.jsxs("div", { className: "mt-2 text-xs bg-red-50 border border-red-200 rounded px-2 py-1", children: [jsxRuntime.jsx("div", { className: "font-semibold mb-1", children: "Validation" }), jsxRuntime.jsx("ul", { className: "list-disc ml-4", children: selectedEdgeValidation.map((m, i) => (jsxRuntime.jsxs("li", { className: "flex items-center gap-1", children: [jsxRuntime.jsx(IssueBadge, { level: m.level, size: 24, className: "w-6 h-6" }), jsxRuntime.jsx("span", { children: `${m.code}: ${m.message}` }), jsxRuntime.jsx("button", { className: "ml-2 text-[10px] px-1 py-[2px] border border-red-300 rounded text-red-700 hover:bg-red-50", onClick: (e) => {
5210
+ }, children: [jsxRuntime.jsx("option", { value: "", children: "(infer from source)" }), Array.from(wb.registry.types.keys()).map((tid) => (jsxRuntime.jsx("option", { value: tid, children: tid }, tid)))] })] })] }), selectedEdgeValidation.length > 0 && (jsxRuntime.jsxs("div", { className: "mt-2 text-xs bg-red-50 border border-red-200 rounded px-2 py-1", children: [jsxRuntime.jsx("div", { className: "font-semibold mb-1", children: "Validation" }), jsxRuntime.jsx("ul", { className: "list-disc ml-4", children: selectedEdgeValidation.map((m, i) => (jsxRuntime.jsxs("li", { className: "flex items-center gap-1", children: [jsxRuntime.jsx(IssueBadge, { level: m.level, size: 24, className: "w-6 h-6" }), jsxRuntime.jsx("span", { children: `${m.code}: ${m.message}` }), jsxRuntime.jsx("button", { className: "ml-2 text-[10px] px-1 py-[2px] border border-red-300 rounded text-red-700 hover:bg-red-50", onClick: (e) => {
5203
5211
  e.stopPropagation();
5204
5212
  deleteEdgeById(selectedEdge.id);
5205
5213
  }, title: "Delete this edge", children: "Delete edge" })] }, i))) })] }))] })) : (jsxRuntime.jsxs("div", { children: [selectedNode && (jsxRuntime.jsxs("div", { className: "mb-2", children: [jsxRuntime.jsxs("div", { children: ["Node: ", selectedNode.nodeId] }), jsxRuntime.jsxs("div", { children: ["Type: ", selectedNode.typeId] }), !!selectedNodeStatus?.activeRuns &&
@@ -5269,7 +5277,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
5269
5277
  setOriginals((o) => ({ ...o, [h]: display }));
5270
5278
  }, ...commonProps, children: [jsxRuntime.jsx("option", { value: "", children: placeholder
5271
5279
  ? `Default: ${placeholder}`
5272
- : "(select)" }), registry.enums
5280
+ : "(select)" }), wb.registry.enums
5273
5281
  .get(typeId)
5274
5282
  ?.options.map((opt) => (jsxRuntime.jsx("option", { value: String(opt.value), children: opt.label }, opt.value)))] }), hasValue && !isLinked && (jsxRuntime.jsx("button", { className: "flex-shrink-0 p-1 hover:bg-gray-100 rounded text-gray-500 hover:text-gray-700", onClick: clearInput, title: "Clear input value", children: jsxRuntime.jsx(react$1.XCircleIcon, { size: 16 }) }))] })) : isLinked ? (jsxRuntime.jsx("div", { className: "flex items-center gap-1 flex-1", children: jsxRuntime.jsx("div", { className: "flex-1 min-w-0", children: renderLinkedInputDisplay(typeId, current) }) })) : (jsxRuntime.jsxs("div", { className: "flex items-center gap-1 flex-1", children: [jsxRuntime.jsx("input", { className: "border border-gray-300 rounded px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500 flex-1 select-text", placeholder: placeholder
5275
5283
  ? `Default: ${placeholder}`
@@ -5538,10 +5546,9 @@ function useKeyboardShortcutToast() {
5538
5546
  }
5539
5547
 
5540
5548
  const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, getDefaultNodeSize }, ref) => {
5541
- const { wb, registry, inputsMap, inputDefaultsMap, outputsMap, outputTypesMap, valuesTick, nodeStatus, edgeStatus, validationByNode, validationByEdge, uiVersion, runner, engineKind, overrides, } = useWorkbenchContext();
5549
+ const { wb, inputsMap, inputDefaultsMap, outputsMap, outputTypesMap, valuesTick, nodeStatus, edgeStatus, validationByNode, validationByEdge, uiVersion, registryVersion, runner, engineKind, overrides, } = useWorkbenchContext();
5542
5550
  const nodeValidation = validationByNode;
5543
5551
  const edgeValidation = validationByEdge.errors;
5544
- const [registryVersion, setRegistryVersion] = React.useState(0);
5545
5552
  const [historyState, setHistoryState] = React.useState(wb.getHistory());
5546
5553
  const prevNodesRef = React.useRef([]);
5547
5554
  const prevEdgesRef = React.useRef([]);
@@ -5617,7 +5624,7 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
5617
5624
  // Build nodeTypes map using UI extension registry
5618
5625
  const custom = new Map(); // Include all types present in registry AND current graph to avoid timing issues
5619
5626
  const ids = new Set([
5620
- ...Array.from(registry.nodes.keys()),
5627
+ ...Array.from(wb.registry.nodes.keys()),
5621
5628
  ...wb.def.nodes.map((n) => n.typeId),
5622
5629
  ]);
5623
5630
  for (const typeId of ids) {
@@ -5635,7 +5642,8 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
5635
5642
  const resolver = (nodeTypeId) => custom.has(nodeTypeId) ? `spark-${nodeTypeId}` : "spark-default";
5636
5643
  return { nodeTypes: types, resolveNodeType: resolver };
5637
5644
  // Include uiVersion to recompute when custom renderers are registered
5638
- }, [wb, registry, uiVersion, ui]);
5645
+ // Include registryVersion to recompute when registry enums/types change
5646
+ }, [wb, wb.registry, registryVersion, uiVersion, ui]);
5639
5647
  const edgeTypes = React.useMemo(() => {
5640
5648
  // Use default edge renderer override if registered, otherwise use DefaultEdge
5641
5649
  const customEdgeRenderer = ui.getEdgeRenderer();
@@ -5661,7 +5669,7 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
5661
5669
  inputsWithDefaults[n.nodeId] = merged;
5662
5670
  }
5663
5671
  }
5664
- const out = toReactFlow(wb.def, wb.getPositions(), wb.getSizes(), registry, {
5672
+ const out = toReactFlow(wb.def, wb.getPositions(), wb.getSizes(), wb.registry, {
5665
5673
  showValues,
5666
5674
  inputs: inputsWithDefaults,
5667
5675
  inputDefaults: inputDefaultsMap,
@@ -5922,19 +5930,13 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
5922
5930
  const onCloseSelectionMenu = React.useCallback(() => {
5923
5931
  setSelectionMenuOpen(false);
5924
5932
  }, []);
5925
- React.useEffect(() => {
5926
- const off = runner.on("registry", () => {
5927
- setRegistryVersion((v) => v + 1);
5928
- });
5929
- return () => off();
5930
- }, [runner]);
5931
5933
  React.useEffect(() => {
5932
5934
  const off = wb.on("historyChanged", (event) => {
5933
5935
  setHistoryState(event.history);
5934
5936
  });
5935
5937
  return () => off();
5936
5938
  }, [wb]);
5937
- const nodeIds = React.useMemo(() => Array.from(registry.nodes.keys()), [registry, registryVersion]);
5939
+ const nodeIds = React.useMemo(() => Array.from(wb.registry.nodes.keys()), [wb.registry, registryVersion]);
5938
5940
  const defaultContextMenuHandlers = React.useMemo(() => {
5939
5941
  // Get storage from override or use workbench's internal storage
5940
5942
  const storage = overrides?.getCopiedDataStorage
@@ -5982,7 +5984,7 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
5982
5984
  get: () => wb.getCopiedData(),
5983
5985
  set: (data) => wb.setCopiedData(data),
5984
5986
  };
5985
- const baseHandlers = createNodeContextMenuHandlers(nodeAtMenu, wb, runner, registry, outputsMap, outputTypesMap, onCloseNodeMenu, overrides?.getDefaultNodeSize, (data) => {
5987
+ const baseHandlers = createNodeContextMenuHandlers(nodeAtMenu, wb, runner, wb.registry, outputsMap, outputTypesMap, onCloseNodeMenu, overrides?.getDefaultNodeSize, (data) => {
5986
5988
  storage.set(data);
5987
5989
  });
5988
5990
  if (overrides?.getNodeContextMenuHandlers) {
@@ -5993,7 +5995,8 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
5993
5995
  nodeAtMenu,
5994
5996
  wb,
5995
5997
  runner,
5996
- registry,
5998
+ wb.registry,
5999
+ registryVersion,
5997
6000
  outputsMap,
5998
6001
  outputTypesMap,
5999
6002
  onCloseNodeMenu,
@@ -6005,8 +6008,8 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
6005
6008
  const bakeableOutputs = React.useMemo(() => {
6006
6009
  if (!nodeAtMenu)
6007
6010
  return [];
6008
- return getBakeableOutputs(nodeAtMenu, wb, registry, outputTypesMap);
6009
- }, [nodeAtMenu, wb, registry, outputTypesMap]);
6011
+ return getBakeableOutputs(nodeAtMenu, wb, wb.registry, outputTypesMap);
6012
+ }, [nodeAtMenu, wb, wb.registry, registryVersion, outputTypesMap]);
6010
6013
  // Keyboard shortcuts configuration
6011
6014
  const enableKeyboardShortcuts = overrides?.enableKeyboardShortcuts !== false; // Default to true
6012
6015
  const keyboardShortcuts = overrides?.keyboardShortcuts || {
@@ -6202,9 +6205,9 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
6202
6205
  if (savedViewport) {
6203
6206
  inst.setViewport(lod.clone(savedViewport));
6204
6207
  }
6205
- }, onConnect: onConnect, onEdgesChange: onEdgesChange, onEdgesDelete: onEdgesDelete, onNodesDelete: onNodesDelete, onNodesChange: onNodesChange, onMoveEnd: onMoveEnd, deleteKeyCode: ["Backspace", "Delete"], proOptions: { hideAttribution: true }, noDragClassName: "wb-nodrag", noWheelClassName: "wb-nowheel", noPanClassName: "wb-nopan", children: [BackgroundRenderer ? (jsxRuntime.jsx(BackgroundRenderer, {})) : (jsxRuntime.jsx(react.Background, { id: "workbench-canvas-background", variant: react.BackgroundVariant.Dots, gap: 12, size: 1 })), MinimapRenderer ? jsxRuntime.jsx(MinimapRenderer, {}) : jsxRuntime.jsx(react.MiniMap, {}), ControlsRenderer ? jsxRuntime.jsx(ControlsRenderer, {}) : jsxRuntime.jsx(react.Controls, {}), DefaultContextMenuRenderer ? (jsxRuntime.jsx(DefaultContextMenuRenderer, { open: menuOpen, clientPos: menuPos, handlers: defaultContextMenuHandlers, registry: registry, nodeIds: nodeIds, ...(enableKeyboardShortcuts !== false
6208
+ }, onConnect: onConnect, onEdgesChange: onEdgesChange, onEdgesDelete: onEdgesDelete, onNodesDelete: onNodesDelete, onNodesChange: onNodesChange, onMoveEnd: onMoveEnd, deleteKeyCode: ["Backspace", "Delete"], proOptions: { hideAttribution: true }, noDragClassName: "wb-nodrag", noWheelClassName: "wb-nowheel", noPanClassName: "wb-nopan", children: [BackgroundRenderer ? (jsxRuntime.jsx(BackgroundRenderer, {})) : (jsxRuntime.jsx(react.Background, { id: "workbench-canvas-background", variant: react.BackgroundVariant.Dots, gap: 12, size: 1 })), MinimapRenderer ? jsxRuntime.jsx(MinimapRenderer, {}) : jsxRuntime.jsx(react.MiniMap, {}), ControlsRenderer ? jsxRuntime.jsx(ControlsRenderer, {}) : jsxRuntime.jsx(react.Controls, {}), DefaultContextMenuRenderer ? (jsxRuntime.jsx(DefaultContextMenuRenderer, { open: menuOpen, clientPos: menuPos, handlers: defaultContextMenuHandlers, registry: wb.registry, nodeIds: nodeIds, ...(enableKeyboardShortcuts !== false
6206
6209
  ? { enableKeyboardShortcuts, keyboardShortcuts }
6207
- : {}) })) : (jsxRuntime.jsx(DefaultContextMenu, { open: menuOpen, clientPos: menuPos, handlers: defaultContextMenuHandlers, registry: registry, nodeIds: nodeIds, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })), !!nodeAtMenu &&
6210
+ : {}) })) : (jsxRuntime.jsx(DefaultContextMenu, { open: menuOpen, clientPos: menuPos, handlers: defaultContextMenuHandlers, registry: wb.registry, nodeIds: nodeIds, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })), !!nodeAtMenu &&
6208
6211
  nodeContextMenuHandlers &&
6209
6212
  (NodeContextMenuRenderer ? (jsxRuntime.jsx(NodeContextMenuRenderer, { open: nodeMenuOpen, clientPos: nodeMenuPos, nodeId: nodeAtMenu, handlers: nodeContextMenuHandlers, canRunPull: canRunPull, bakeableOutputs: bakeableOutputs, ...(enableKeyboardShortcuts !== false
6210
6213
  ? { enableKeyboardShortcuts, keyboardShortcuts }
@@ -6213,14 +6216,14 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
6213
6216
  (SelectionContextMenuRenderer ? (jsxRuntime.jsx(SelectionContextMenuRenderer, { open: selectionMenuOpen, clientPos: selectionMenuPos, handlers: selectionContextMenuHandlers, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })) : (jsxRuntime.jsx(SelectionContextMenu, { open: selectionMenuOpen, clientPos: selectionMenuPos, handlers: selectionContextMenuHandlers, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })))] }) }), toast && (jsxRuntime.jsx(KeyboardShortcutToast, { message: toast.message, onClose: hideToast }, toast.id))] }));
6214
6217
  });
6215
6218
 
6216
- function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, example, onExampleChange, engine, onEngineChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, overrides, onInit, onChange, }) {
6217
- const { wb, runner, registry, selectedNodeId, runAutoLayout } = useWorkbenchContext();
6219
+ function WorkbenchStudioCanvas({ autoScroll, onAutoScrollChange, example, onExampleChange, engine, onEngineChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, overrides, onInit, onChange, }) {
6220
+ const { wb, runner, selectedNodeId, runAutoLayout } = useWorkbenchContext();
6218
6221
  const [transportStatus, setTransportStatus] = React.useState({
6219
6222
  state: "local",
6220
6223
  });
6221
6224
  const selectedNode = wb.def.nodes.find((n) => n.nodeId === selectedNodeId);
6222
6225
  const effectiveHandles = selectedNode
6223
- ? computeEffectiveHandles(selectedNode, registry)
6226
+ ? computeEffectiveHandles(selectedNode, wb.registry)
6224
6227
  : { inputs: {}, outputs: {}, inputDefaults: {} };
6225
6228
  const [exampleState, setExampleState] = React.useState(example ?? "");
6226
6229
  const isGraphRunning = runner.isRunning();
@@ -6367,7 +6370,6 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
6367
6370
  // - For remote backend, registry is automatically managed by RemoteGraphRunner
6368
6371
  if (backendKind === "local") {
6369
6372
  if (r) {
6370
- setRegistry(r);
6371
6373
  wb.setRegistry(r);
6372
6374
  }
6373
6375
  }
@@ -6383,15 +6385,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
6383
6385
  runAutoLayout();
6384
6386
  setExampleState(key);
6385
6387
  onExampleChange?.(key);
6386
- }, [
6387
- runner,
6388
- wb,
6389
- onExampleChange,
6390
- runAutoLayout,
6391
- examples,
6392
- setRegistry,
6393
- backendKind,
6394
- ]);
6388
+ }, [runner, wb, onExampleChange, runAutoLayout, examples, backendKind]);
6395
6389
  const download$1 = React.useCallback(async () => {
6396
6390
  try {
6397
6391
  await download(wb, runner);
@@ -6562,11 +6556,11 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
6562
6556
  return overrides.setInput(baseSetInput, {
6563
6557
  runner,
6564
6558
  selectedNodeId,
6565
- registry,
6559
+ registry: wb.registry,
6566
6560
  });
6567
6561
  }
6568
6562
  return baseSetInput;
6569
- }, [overrides, baseSetInput, runner, selectedNodeId, registry]);
6563
+ }, [overrides, baseSetInput, runner, selectedNodeId, wb.registry]);
6570
6564
  const baseToString = React.useCallback((typeId, value) => {
6571
6565
  if (value === undefined || value === null)
6572
6566
  return "";
@@ -6574,7 +6568,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
6574
6568
  if (sparkGraph.isTypedOutput(value)) {
6575
6569
  return baseToString(sparkGraph.getTypedOutputTypeId(value), sparkGraph.getTypedOutputValue(value));
6576
6570
  }
6577
- const pre = preformatValueForDisplay(typeId, value, registry);
6571
+ const pre = preformatValueForDisplay(typeId, value, wb.registry);
6578
6572
  if (pre !== undefined)
6579
6573
  return pre;
6580
6574
  if (typeof value === "object" &&
@@ -6590,7 +6584,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
6590
6584
  }
6591
6585
  if (typeId && typeId.startsWith("enum:")) {
6592
6586
  const n = Number(value);
6593
- const label = registry.enums.get(typeId)?.valueToLabel.get(n);
6587
+ const label = wb.registry.enums.get(typeId)?.valueToLabel.get(n);
6594
6588
  return label ?? String(n);
6595
6589
  }
6596
6590
  const round4 = (n) => Math.round(Number(n) * 10000) / 10000;
@@ -6620,22 +6614,22 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
6620
6614
  return String(rounded);
6621
6615
  }
6622
6616
  return String(value);
6623
- }, [registry]);
6617
+ }, [wb.registry]);
6624
6618
  const baseToElement = React.useCallback((typeId, value) => {
6625
6619
  return (jsxRuntime.jsx("span", { className: "ml-1 opacity-60", children: baseToString(typeId, value) }));
6626
6620
  }, [baseToString]);
6627
6621
  const toString = React.useMemo(() => {
6628
6622
  if (overrides?.toString)
6629
- return overrides.toString(baseToString, { registry });
6623
+ return overrides.toString(baseToString, { registry: wb.registry });
6630
6624
  return baseToString;
6631
- }, [overrides, baseToString, registry]);
6625
+ }, [overrides, baseToString, wb.registry]);
6632
6626
  // Optional: toElement (not currently consumed by core UI)
6633
6627
  // Consumers can access it by passing through their own node renderers.
6634
6628
  const toElement = React.useMemo(() => {
6635
6629
  if (overrides?.toElement)
6636
- return overrides.toElement(baseToElement, { registry });
6630
+ return overrides.toElement(baseToElement, { registry: wb.registry });
6637
6631
  return baseToElement;
6638
- }, [overrides, baseToElement, registry]);
6632
+ }, [overrides, baseToElement, wb.registry]);
6639
6633
  return (jsxRuntime.jsxs("div", { className: "w-full h-screen flex flex-col", children: [jsxRuntime.jsxs("div", { className: "p-2 border-b border-gray-300 flex gap-2 items-center", children: [isGraphRunning ? (jsxRuntime.jsxs("span", { className: "ml-2 text-sm text-green-700", children: ["Running: ", engineKind] })) : (jsxRuntime.jsx("span", { className: "ml-2 text-sm text-gray-500", children: "Stopped" })), jsxRuntime.jsxs("span", { className: "ml-2 flex items-center gap-1 text-xs", title: transportStatus.kind || undefined, children: [transportStatus.state === "local" && (jsxRuntime.jsx(react$1.PlugsConnectedIcon, { size: 14, className: "text-gray-500" })), transportStatus.state === "connecting" && (jsxRuntime.jsx(react$1.ClockClockwiseIcon, { size: 14, className: "text-amber-600 animate-pulse" })), transportStatus.state === "connected" && (jsxRuntime.jsx(react$1.WifiHighIcon, { size: 14, className: "text-green-600" })), transportStatus.state === "disconnected" && (jsxRuntime.jsx(react$1.WifiSlashIcon, { size: 14, className: "text-red-600" })), transportStatus.state === "retrying" && (jsxRuntime.jsx(react$1.ClockClockwiseIcon, { size: 14, className: "text-amber-700 animate-pulse" }))] }), jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1", value: exampleState, onChange: (e) => applyExample(e.target.value), disabled: isGraphRunning, title: isGraphRunning ? "Stop engine before switching example" : undefined, children: [jsxRuntime.jsx("option", { value: "", children: "Select Example\u2026" }), examples.map((ex) => (jsxRuntime.jsx("option", { value: ex.id, children: ex.label }, ex.id)))] }), jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1", value: backendKind, onChange: (e) => onBackendKindChange(e.target.value), disabled: isGraphRunning, title: isGraphRunning ? "Stop engine before switching backend" : undefined, children: [jsxRuntime.jsx("option", { value: "local", children: "Local" }), jsxRuntime.jsx("option", { value: "remote-http", children: "Remote (HTTP)" }), jsxRuntime.jsx("option", { value: "remote-ws", children: "Remote (WebSocket)" })] }), backendKind === "remote-http" && !!onHttpBaseUrlChange && (jsxRuntime.jsx("input", { className: "border border-gray-300 rounded px-2 py-1 w-72", placeholder: "http://127.0.0.1:18080", value: httpBaseUrl, onChange: (e) => onHttpBaseUrlChange(e.target.value) })), backendKind === "remote-ws" && !!onWsUrlChange && (jsxRuntime.jsx("input", { className: "border border-gray-300 rounded px-2 py-1 w-72", placeholder: "ws://127.0.0.1:18081", value: wsUrl, onChange: (e) => onWsUrlChange(e.target.value) })), jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1", value: engineKind ?? engine ?? "", onChange: async (e) => {
6640
6634
  const kind = e.target.value || undefined;
6641
6635
  const currentEngine = runner.getRunningEngine();
@@ -6737,7 +6731,7 @@ function WorkbenchStudio({ engine, onEngineChange, example, onExampleChange, bac
6737
6731
  runner.dispose();
6738
6732
  onBackendKindChange(v);
6739
6733
  }, [isGraphRunning]);
6740
- return (jsxRuntime.jsx(WorkbenchProvider, { wb: wb, runner: runner, registry: registry, setRegistry: setRegistry, overrides: overrides, uiVersion: uiVersion, children: jsxRuntime.jsx(WorkbenchStudioCanvas, { setRegistry: setRegistry, autoScroll: autoScroll, onAutoScrollChange: onAutoScrollChange, example: example, onExampleChange: onExampleChange, engine: engine, onEngineChange: onEngineChange, backendKind: backendKind, onBackendKindChange: onBackendKindChangeWithDispose, httpBaseUrl: httpBaseUrl, onHttpBaseUrlChange: onHttpBaseUrlChange, wsUrl: wsUrl, onWsUrlChange: onWsUrlChange, debug: debug, onDebugChange: onDebugChange, showValues: showValues, onShowValuesChange: onShowValuesChange, hideWorkbench: hideWorkbench, onHideWorkbenchChange: onHideWorkbenchChange, overrides: overrides, onInit: onInit, onChange: onChange }) }));
6734
+ return (jsxRuntime.jsx(WorkbenchProvider, { wb: wb, runner: runner, overrides: overrides, uiVersion: uiVersion, children: jsxRuntime.jsx(WorkbenchStudioCanvas, { setRegistry: setRegistry, autoScroll: autoScroll, onAutoScrollChange: onAutoScrollChange, example: example, onExampleChange: onExampleChange, engine: engine, onEngineChange: onEngineChange, backendKind: backendKind, onBackendKindChange: onBackendKindChangeWithDispose, httpBaseUrl: httpBaseUrl, onHttpBaseUrlChange: onHttpBaseUrlChange, wsUrl: wsUrl, onWsUrlChange: onWsUrlChange, debug: debug, onDebugChange: onDebugChange, showValues: showValues, onShowValuesChange: onShowValuesChange, hideWorkbench: hideWorkbench, onHideWorkbenchChange: onHideWorkbenchChange, overrides: overrides, onInit: onInit, onChange: onChange }) }));
6741
6735
  }
6742
6736
 
6743
6737
  exports.AbstractWorkbench = AbstractWorkbench;