@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/esm/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { generateId, GraphBuilder, getTypedOutputValue, isTypedOutput, getInputTypeId, createEngine, StepEngine, PullEngine, BatchedEngine, getTypedOutputTypeId, isInputPrivate, offsetImportedPositions, createSimpleGraphRegistry, createSimpleGraphDef, createAsyncGraphDef, createAsyncGraphRegistry, createProgressGraphDef, createProgressGraphRegistry, createValidationGraphDef, createValidationGraphRegistry } from '@bian-womp/spark-graph';
1
+ import { generateId, createSimpleGraphRegistry, GraphBuilder, getTypedOutputValue, isTypedOutput, getInputTypeId, createEngine, StepEngine, PullEngine, BatchedEngine, getTypedOutputTypeId, isInputPrivate, offsetImportedPositions, createSimpleGraphDef, createAsyncGraphDef, createAsyncGraphRegistry, createProgressGraphDef, createProgressGraphRegistry, createValidationGraphDef, createValidationGraphRegistry } from '@bian-womp/spark-graph';
2
2
  import lod from 'lodash';
3
3
  import { RuntimeApiClient } from '@bian-womp/spark-remote';
4
4
  import { Position, Handle, NodeResizer, getBezierPath, BaseEdge, useReactFlow, ReactFlowProvider, ReactFlow, Background, BackgroundVariant, MiniMap, Controls } from '@xyflow/react';
@@ -133,8 +133,8 @@ class AbstractWorkbench {
133
133
  }
134
134
 
135
135
  class InMemoryWorkbench extends AbstractWorkbench {
136
- constructor() {
137
- super(...arguments);
136
+ constructor(args) {
137
+ super(args);
138
138
  this._def = { nodes: [], edges: [] };
139
139
  this.listeners = new Map();
140
140
  this.positions = {};
@@ -148,12 +148,17 @@ class InMemoryWorkbench extends AbstractWorkbench {
148
148
  this.viewport = null;
149
149
  this.historyState = undefined;
150
150
  this.copiedData = null;
151
+ this._registry = createSimpleGraphRegistry();
151
152
  }
152
153
  get def() {
153
154
  return this._def;
154
155
  }
156
+ get registry() {
157
+ return this._registry;
158
+ }
155
159
  setRegistry(registry) {
156
- this.registry = registry;
160
+ this._registry = registry;
161
+ this.emit("registryChanged", { registry });
157
162
  }
158
163
  async load(def) {
159
164
  this._def = { nodes: [...def.nodes], edges: [...def.edges] };
@@ -3647,7 +3652,7 @@ function computeInvalidatedFromMetadata(metadata) {
3647
3652
  const maxInputTime = Math.max(...Object.values(lastInputAt));
3648
3653
  return maxInputTime > (lastSuccessAt ?? lastRunAt ?? 0);
3649
3654
  }
3650
- function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVersion, children, }) {
3655
+ function WorkbenchProvider({ wb, runner, overrides, uiVersion, children, }) {
3651
3656
  const [nodeStatus, setNodeStatus] = useState({});
3652
3657
  const [edgeStatus, setEdgeStatus] = useState({});
3653
3658
  const [events, setEvents] = useState([]);
@@ -3655,6 +3660,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
3655
3660
  const [systemErrors, setSystemErrors] = useState([]);
3656
3661
  const [registryErrors, setRegistryErrors] = useState([]);
3657
3662
  const [inputValidationErrors, setInputValidationErrors] = useState([]);
3663
+ const [registryVersion, setRegistryVersion] = useState(0);
3658
3664
  const clearSystemErrors = useCallback(() => setSystemErrors([]), []);
3659
3665
  const clearRegistryErrors = useCallback(() => setRegistryErrors([]), []);
3660
3666
  const clearInputValidationErrors = useCallback(() => setInputValidationErrors([]), []);
@@ -3721,7 +3727,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
3721
3727
  const out = {};
3722
3728
  // Local: runtimeTypeId is not stored; derive from typed wrapper in outputsMap
3723
3729
  for (const n of wb.def.nodes) {
3724
- const effectiveHandles = computeEffectiveHandles(n, registry);
3730
+ const effectiveHandles = computeEffectiveHandles(n, wb.registry);
3725
3731
  const outputsDecl = effectiveHandles.outputs;
3726
3732
  const handles = Object.keys(outputsDecl);
3727
3733
  const cur = {};
@@ -3735,7 +3741,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
3735
3741
  out[n.nodeId] = cur;
3736
3742
  }
3737
3743
  return out;
3738
- }, [wb, wb.def, outputsMap, registry]);
3744
+ }, [wb, wb.def, outputsMap, wb.registry, registryVersion]);
3739
3745
  // Initialize nodes and derive invalidated status from persisted metadata
3740
3746
  useEffect(() => {
3741
3747
  const workbenchRuntimeState = wb.getRuntimeState() ?? { nodes: {} };
@@ -3813,7 +3819,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
3813
3819
  const overrideSize = overrides?.getDefaultNodeSize?.(node.typeId) ?? undefined;
3814
3820
  const size = estimateNodeSize({
3815
3821
  node,
3816
- registry,
3822
+ registry: wb.registry,
3817
3823
  showValues: true,
3818
3824
  overrides: overrideSize,
3819
3825
  });
@@ -3831,7 +3837,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
3831
3837
  curX += maxWidth + H_GAP;
3832
3838
  }
3833
3839
  wb.setPositions(pos, { commit: true, reason: "auto-layout" });
3834
- }, [wb, wb.def, registry, overrides?.getDefaultNodeSize]);
3840
+ }, [wb, wb.def, wb.registry, registryVersion, overrides?.getDefaultNodeSize]);
3835
3841
  const updateEdgeType = useCallback((edgeId, typeId) => wb.updateEdgeType(edgeId, typeId), [wb]);
3836
3842
  const triggerExternal = useCallback((nodeId, event) => runner.triggerExternal(nodeId, event), [runner]);
3837
3843
  const getNodeDisplayName = useCallback((nodeId) => {
@@ -3841,9 +3847,9 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
3841
3847
  const node = wb.def.nodes.find((n) => n.nodeId === nodeId);
3842
3848
  if (!node)
3843
3849
  return nodeId;
3844
- const desc = registry.nodes.get(node.typeId);
3850
+ const desc = wb.registry.nodes.get(node.typeId);
3845
3851
  return desc?.displayName || node.typeId;
3846
- }, [wb, registry]);
3852
+ }, [wb, wb.registry, registryVersion]);
3847
3853
  const setNodeName = useCallback((nodeId, name) => {
3848
3854
  wb.setNodeName(nodeId, name, { commit: true, reason: "rename-node" });
3849
3855
  }, [wb]);
@@ -4159,6 +4165,9 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4159
4165
  }
4160
4166
  return add("runner", "stats")(s);
4161
4167
  });
4168
+ const offWbRegistryChanged = wb.on("registryChanged", (evt) => {
4169
+ setRegistryVersion((v) => v + 1);
4170
+ });
4162
4171
  const offWbGraphChanged = wb.on("graphChanged", (event) => {
4163
4172
  // Clear validation errors for removed nodes
4164
4173
  if (event.change?.type === "removeNode") {
@@ -4315,8 +4324,8 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4315
4324
  // Registry updates: swap registry and refresh graph validation/UI
4316
4325
  const offRunnerRegistry = runner.on("registry", async (newReg) => {
4317
4326
  try {
4318
- setRegistry(newReg);
4319
4327
  wb.setRegistry(newReg);
4328
+ // Increment registry version to trigger UI updates
4320
4329
  // Trigger a graph update so the UI revalidates with new types/enums/nodes
4321
4330
  try {
4322
4331
  await runner.update(wb.def);
@@ -4387,6 +4396,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4387
4396
  offRunnerError();
4388
4397
  offRunnerInvalidate();
4389
4398
  offRunnerStats();
4399
+ offWbRegistryChanged();
4390
4400
  offWbGraphChanged();
4391
4401
  offWbGraphUiChangedForLog();
4392
4402
  offWbGraphUiChanged();
@@ -4400,7 +4410,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4400
4410
  offFlowViewport();
4401
4411
  offWbRuntimeMetadataChanged();
4402
4412
  };
4403
- }, [runner, wb, setRegistry]);
4413
+ }, [runner, wb]);
4404
4414
  const isRunning = useCallback(() => runner.isRunning(), [runner]);
4405
4415
  const engineKind = useCallback(() => runner.getRunningEngine(), [runner]);
4406
4416
  const start = useCallback((engine) => {
@@ -4478,8 +4488,6 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4478
4488
  const value = useMemo(() => ({
4479
4489
  wb,
4480
4490
  runner,
4481
- registry,
4482
- setRegistry,
4483
4491
  selectedNodeId,
4484
4492
  selectedEdgeId,
4485
4493
  setSelection,
@@ -4514,14 +4522,13 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4514
4522
  updateEdgeType,
4515
4523
  triggerExternal,
4516
4524
  uiVersion,
4525
+ registryVersion,
4517
4526
  overrides,
4518
4527
  getNodeDisplayName,
4519
4528
  setNodeName,
4520
4529
  }), [
4521
4530
  wb,
4522
4531
  runner,
4523
- registry,
4524
- setRegistry,
4525
4532
  selectedNodeId,
4526
4533
  selectedEdgeId,
4527
4534
  setSelection,
@@ -4555,6 +4562,7 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
4555
4562
  wb,
4556
4563
  runner,
4557
4564
  uiVersion,
4565
+ registryVersion,
4558
4566
  overrides,
4559
4567
  getNodeDisplayName,
4560
4568
  setNodeName,
@@ -4582,7 +4590,7 @@ function DefaultNodeHeader({ id, typeId, validation, right, showId, onInvalidate
4582
4590
  const node = ctx.wb.def.nodes.find((n) => n.nodeId === id);
4583
4591
  if (!node)
4584
4592
  return id;
4585
- const desc = ctx.registry.nodes.get(node.typeId);
4593
+ const desc = ctx.wb.registry.nodes.get(node.typeId);
4586
4594
  return desc?.displayName || node.typeId;
4587
4595
  }, [ctx, id, typeId]);
4588
4596
  const handleInvalidate = React.useCallback(() => {
@@ -5041,7 +5049,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
5041
5049
  return String(value ?? "");
5042
5050
  }
5043
5051
  };
5044
- 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();
5052
+ 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();
5045
5053
  const nodeValidationIssues = validationByNode.issues;
5046
5054
  const edgeValidationIssues = validationByEdge.issues;
5047
5055
  const nodeValidationHandles = validationByNode;
@@ -5050,7 +5058,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
5050
5058
  const selectedEdge = wb.def.edges.find((e) => e.id === selectedEdgeId);
5051
5059
  // Use computeEffectiveHandles to merge registry defaults with dynamically resolved handles
5052
5060
  const effectiveHandles = selectedNode
5053
- ? computeEffectiveHandles(selectedNode, registry)
5061
+ ? computeEffectiveHandles(selectedNode, wb.registry)
5054
5062
  : { inputs: {}, outputs: {}};
5055
5063
  const inputHandles = Object.entries(effectiveHandles.inputs)
5056
5064
  .filter(([k]) => !isInputPrivate(effectiveHandles.inputs, k))
@@ -5177,7 +5185,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
5177
5185
  setDrafts(nextDrafts);
5178
5186
  if (!shallowEqual(originals, nextOriginals))
5179
5187
  setOriginals(nextOriginals);
5180
- }, [selectedNodeId, selectedNode, registry, valuesTick]);
5188
+ }, [selectedNodeId, selectedNode, wb.registry, registryVersion, valuesTick]);
5181
5189
  const widthClass = debug ? "w-[480px]" : "w-[320px]";
5182
5190
  const deleteEdgeById = (edgeId) => {
5183
5191
  if (!edgeId)
@@ -5197,7 +5205,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
5197
5205
  const v = e.target.value;
5198
5206
  const next = v === "" ? undefined : v;
5199
5207
  updateEdgeType(selectedEdge.id, next);
5200
- }, children: [jsx("option", { value: "", children: "(infer from source)" }), Array.from(registry.types.keys()).map((tid) => (jsx("option", { value: tid, children: tid }, tid)))] })] })] }), selectedEdgeValidation.length > 0 && (jsxs("div", { className: "mt-2 text-xs bg-red-50 border border-red-200 rounded px-2 py-1", children: [jsx("div", { className: "font-semibold mb-1", children: "Validation" }), jsx("ul", { className: "list-disc ml-4", children: selectedEdgeValidation.map((m, i) => (jsxs("li", { className: "flex items-center gap-1", children: [jsx(IssueBadge, { level: m.level, size: 24, className: "w-6 h-6" }), jsx("span", { children: `${m.code}: ${m.message}` }), 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) => {
5208
+ }, children: [jsx("option", { value: "", children: "(infer from source)" }), Array.from(wb.registry.types.keys()).map((tid) => (jsx("option", { value: tid, children: tid }, tid)))] })] })] }), selectedEdgeValidation.length > 0 && (jsxs("div", { className: "mt-2 text-xs bg-red-50 border border-red-200 rounded px-2 py-1", children: [jsx("div", { className: "font-semibold mb-1", children: "Validation" }), jsx("ul", { className: "list-disc ml-4", children: selectedEdgeValidation.map((m, i) => (jsxs("li", { className: "flex items-center gap-1", children: [jsx(IssueBadge, { level: m.level, size: 24, className: "w-6 h-6" }), jsx("span", { children: `${m.code}: ${m.message}` }), 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) => {
5201
5209
  e.stopPropagation();
5202
5210
  deleteEdgeById(selectedEdge.id);
5203
5211
  }, title: "Delete this edge", children: "Delete edge" })] }, i))) })] }))] })) : (jsxs("div", { children: [selectedNode && (jsxs("div", { className: "mb-2", children: [jsxs("div", { children: ["Node: ", selectedNode.nodeId] }), jsxs("div", { children: ["Type: ", selectedNode.typeId] }), !!selectedNodeStatus?.activeRuns &&
@@ -5267,7 +5275,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
5267
5275
  setOriginals((o) => ({ ...o, [h]: display }));
5268
5276
  }, ...commonProps, children: [jsx("option", { value: "", children: placeholder
5269
5277
  ? `Default: ${placeholder}`
5270
- : "(select)" }), registry.enums
5278
+ : "(select)" }), wb.registry.enums
5271
5279
  .get(typeId)
5272
5280
  ?.options.map((opt) => (jsx("option", { value: String(opt.value), children: opt.label }, opt.value)))] }), hasValue && !isLinked && (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: jsx(XCircleIcon, { size: 16 }) }))] })) : isLinked ? (jsx("div", { className: "flex items-center gap-1 flex-1", children: jsx("div", { className: "flex-1 min-w-0", children: renderLinkedInputDisplay(typeId, current) }) })) : (jsxs("div", { className: "flex items-center gap-1 flex-1", children: [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
5273
5281
  ? `Default: ${placeholder}`
@@ -5536,10 +5544,9 @@ function useKeyboardShortcutToast() {
5536
5544
  }
5537
5545
 
5538
5546
  const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, getDefaultNodeSize }, ref) => {
5539
- const { wb, registry, inputsMap, inputDefaultsMap, outputsMap, outputTypesMap, valuesTick, nodeStatus, edgeStatus, validationByNode, validationByEdge, uiVersion, runner, engineKind, overrides, } = useWorkbenchContext();
5547
+ const { wb, inputsMap, inputDefaultsMap, outputsMap, outputTypesMap, valuesTick, nodeStatus, edgeStatus, validationByNode, validationByEdge, uiVersion, registryVersion, runner, engineKind, overrides, } = useWorkbenchContext();
5540
5548
  const nodeValidation = validationByNode;
5541
5549
  const edgeValidation = validationByEdge.errors;
5542
- const [registryVersion, setRegistryVersion] = useState(0);
5543
5550
  const [historyState, setHistoryState] = useState(wb.getHistory());
5544
5551
  const prevNodesRef = useRef([]);
5545
5552
  const prevEdgesRef = useRef([]);
@@ -5615,7 +5622,7 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
5615
5622
  // Build nodeTypes map using UI extension registry
5616
5623
  const custom = new Map(); // Include all types present in registry AND current graph to avoid timing issues
5617
5624
  const ids = new Set([
5618
- ...Array.from(registry.nodes.keys()),
5625
+ ...Array.from(wb.registry.nodes.keys()),
5619
5626
  ...wb.def.nodes.map((n) => n.typeId),
5620
5627
  ]);
5621
5628
  for (const typeId of ids) {
@@ -5633,7 +5640,8 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
5633
5640
  const resolver = (nodeTypeId) => custom.has(nodeTypeId) ? `spark-${nodeTypeId}` : "spark-default";
5634
5641
  return { nodeTypes: types, resolveNodeType: resolver };
5635
5642
  // Include uiVersion to recompute when custom renderers are registered
5636
- }, [wb, registry, uiVersion, ui]);
5643
+ // Include registryVersion to recompute when registry enums/types change
5644
+ }, [wb, wb.registry, registryVersion, uiVersion, ui]);
5637
5645
  const edgeTypes = useMemo(() => {
5638
5646
  // Use default edge renderer override if registered, otherwise use DefaultEdge
5639
5647
  const customEdgeRenderer = ui.getEdgeRenderer();
@@ -5659,7 +5667,7 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
5659
5667
  inputsWithDefaults[n.nodeId] = merged;
5660
5668
  }
5661
5669
  }
5662
- const out = toReactFlow(wb.def, wb.getPositions(), wb.getSizes(), registry, {
5670
+ const out = toReactFlow(wb.def, wb.getPositions(), wb.getSizes(), wb.registry, {
5663
5671
  showValues,
5664
5672
  inputs: inputsWithDefaults,
5665
5673
  inputDefaults: inputDefaultsMap,
@@ -5920,19 +5928,13 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
5920
5928
  const onCloseSelectionMenu = useCallback(() => {
5921
5929
  setSelectionMenuOpen(false);
5922
5930
  }, []);
5923
- useEffect(() => {
5924
- const off = runner.on("registry", () => {
5925
- setRegistryVersion((v) => v + 1);
5926
- });
5927
- return () => off();
5928
- }, [runner]);
5929
5931
  useEffect(() => {
5930
5932
  const off = wb.on("historyChanged", (event) => {
5931
5933
  setHistoryState(event.history);
5932
5934
  });
5933
5935
  return () => off();
5934
5936
  }, [wb]);
5935
- const nodeIds = useMemo(() => Array.from(registry.nodes.keys()), [registry, registryVersion]);
5937
+ const nodeIds = useMemo(() => Array.from(wb.registry.nodes.keys()), [wb.registry, registryVersion]);
5936
5938
  const defaultContextMenuHandlers = useMemo(() => {
5937
5939
  // Get storage from override or use workbench's internal storage
5938
5940
  const storage = overrides?.getCopiedDataStorage
@@ -5980,7 +5982,7 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
5980
5982
  get: () => wb.getCopiedData(),
5981
5983
  set: (data) => wb.setCopiedData(data),
5982
5984
  };
5983
- const baseHandlers = createNodeContextMenuHandlers(nodeAtMenu, wb, runner, registry, outputsMap, outputTypesMap, onCloseNodeMenu, overrides?.getDefaultNodeSize, (data) => {
5985
+ const baseHandlers = createNodeContextMenuHandlers(nodeAtMenu, wb, runner, wb.registry, outputsMap, outputTypesMap, onCloseNodeMenu, overrides?.getDefaultNodeSize, (data) => {
5984
5986
  storage.set(data);
5985
5987
  });
5986
5988
  if (overrides?.getNodeContextMenuHandlers) {
@@ -5991,7 +5993,8 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
5991
5993
  nodeAtMenu,
5992
5994
  wb,
5993
5995
  runner,
5994
- registry,
5996
+ wb.registry,
5997
+ registryVersion,
5995
5998
  outputsMap,
5996
5999
  outputTypesMap,
5997
6000
  onCloseNodeMenu,
@@ -6003,8 +6006,8 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
6003
6006
  const bakeableOutputs = useMemo(() => {
6004
6007
  if (!nodeAtMenu)
6005
6008
  return [];
6006
- return getBakeableOutputs(nodeAtMenu, wb, registry, outputTypesMap);
6007
- }, [nodeAtMenu, wb, registry, outputTypesMap]);
6009
+ return getBakeableOutputs(nodeAtMenu, wb, wb.registry, outputTypesMap);
6010
+ }, [nodeAtMenu, wb, wb.registry, registryVersion, outputTypesMap]);
6008
6011
  // Keyboard shortcuts configuration
6009
6012
  const enableKeyboardShortcuts = overrides?.enableKeyboardShortcuts !== false; // Default to true
6010
6013
  const keyboardShortcuts = overrides?.keyboardShortcuts || {
@@ -6200,9 +6203,9 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
6200
6203
  if (savedViewport) {
6201
6204
  inst.setViewport(lod.clone(savedViewport));
6202
6205
  }
6203
- }, 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 ? (jsx(BackgroundRenderer, {})) : (jsx(Background, { id: "workbench-canvas-background", variant: BackgroundVariant.Dots, gap: 12, size: 1 })), MinimapRenderer ? jsx(MinimapRenderer, {}) : jsx(MiniMap, {}), ControlsRenderer ? jsx(ControlsRenderer, {}) : jsx(Controls, {}), DefaultContextMenuRenderer ? (jsx(DefaultContextMenuRenderer, { open: menuOpen, clientPos: menuPos, handlers: defaultContextMenuHandlers, registry: registry, nodeIds: nodeIds, ...(enableKeyboardShortcuts !== false
6206
+ }, 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 ? (jsx(BackgroundRenderer, {})) : (jsx(Background, { id: "workbench-canvas-background", variant: BackgroundVariant.Dots, gap: 12, size: 1 })), MinimapRenderer ? jsx(MinimapRenderer, {}) : jsx(MiniMap, {}), ControlsRenderer ? jsx(ControlsRenderer, {}) : jsx(Controls, {}), DefaultContextMenuRenderer ? (jsx(DefaultContextMenuRenderer, { open: menuOpen, clientPos: menuPos, handlers: defaultContextMenuHandlers, registry: wb.registry, nodeIds: nodeIds, ...(enableKeyboardShortcuts !== false
6204
6207
  ? { enableKeyboardShortcuts, keyboardShortcuts }
6205
- : {}) })) : (jsx(DefaultContextMenu, { open: menuOpen, clientPos: menuPos, handlers: defaultContextMenuHandlers, registry: registry, nodeIds: nodeIds, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })), !!nodeAtMenu &&
6208
+ : {}) })) : (jsx(DefaultContextMenu, { open: menuOpen, clientPos: menuPos, handlers: defaultContextMenuHandlers, registry: wb.registry, nodeIds: nodeIds, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })), !!nodeAtMenu &&
6206
6209
  nodeContextMenuHandlers &&
6207
6210
  (NodeContextMenuRenderer ? (jsx(NodeContextMenuRenderer, { open: nodeMenuOpen, clientPos: nodeMenuPos, nodeId: nodeAtMenu, handlers: nodeContextMenuHandlers, canRunPull: canRunPull, bakeableOutputs: bakeableOutputs, ...(enableKeyboardShortcuts !== false
6208
6211
  ? { enableKeyboardShortcuts, keyboardShortcuts }
@@ -6211,14 +6214,14 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
6211
6214
  (SelectionContextMenuRenderer ? (jsx(SelectionContextMenuRenderer, { open: selectionMenuOpen, clientPos: selectionMenuPos, handlers: selectionContextMenuHandlers, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })) : (jsx(SelectionContextMenu, { open: selectionMenuOpen, clientPos: selectionMenuPos, handlers: selectionContextMenuHandlers, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })))] }) }), toast && (jsx(KeyboardShortcutToast, { message: toast.message, onClose: hideToast }, toast.id))] }));
6212
6215
  });
6213
6216
 
6214
- function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, example, onExampleChange, engine, onEngineChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, overrides, onInit, onChange, }) {
6215
- const { wb, runner, registry, selectedNodeId, runAutoLayout } = useWorkbenchContext();
6217
+ function WorkbenchStudioCanvas({ autoScroll, onAutoScrollChange, example, onExampleChange, engine, onEngineChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, overrides, onInit, onChange, }) {
6218
+ const { wb, runner, selectedNodeId, runAutoLayout } = useWorkbenchContext();
6216
6219
  const [transportStatus, setTransportStatus] = useState({
6217
6220
  state: "local",
6218
6221
  });
6219
6222
  const selectedNode = wb.def.nodes.find((n) => n.nodeId === selectedNodeId);
6220
6223
  const effectiveHandles = selectedNode
6221
- ? computeEffectiveHandles(selectedNode, registry)
6224
+ ? computeEffectiveHandles(selectedNode, wb.registry)
6222
6225
  : { inputs: {}, outputs: {}, inputDefaults: {} };
6223
6226
  const [exampleState, setExampleState] = useState(example ?? "");
6224
6227
  const isGraphRunning = runner.isRunning();
@@ -6365,7 +6368,6 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
6365
6368
  // - For remote backend, registry is automatically managed by RemoteGraphRunner
6366
6369
  if (backendKind === "local") {
6367
6370
  if (r) {
6368
- setRegistry(r);
6369
6371
  wb.setRegistry(r);
6370
6372
  }
6371
6373
  }
@@ -6381,15 +6383,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
6381
6383
  runAutoLayout();
6382
6384
  setExampleState(key);
6383
6385
  onExampleChange?.(key);
6384
- }, [
6385
- runner,
6386
- wb,
6387
- onExampleChange,
6388
- runAutoLayout,
6389
- examples,
6390
- setRegistry,
6391
- backendKind,
6392
- ]);
6386
+ }, [runner, wb, onExampleChange, runAutoLayout, examples, backendKind]);
6393
6387
  const download$1 = useCallback(async () => {
6394
6388
  try {
6395
6389
  await download(wb, runner);
@@ -6560,11 +6554,11 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
6560
6554
  return overrides.setInput(baseSetInput, {
6561
6555
  runner,
6562
6556
  selectedNodeId,
6563
- registry,
6557
+ registry: wb.registry,
6564
6558
  });
6565
6559
  }
6566
6560
  return baseSetInput;
6567
- }, [overrides, baseSetInput, runner, selectedNodeId, registry]);
6561
+ }, [overrides, baseSetInput, runner, selectedNodeId, wb.registry]);
6568
6562
  const baseToString = useCallback((typeId, value) => {
6569
6563
  if (value === undefined || value === null)
6570
6564
  return "";
@@ -6572,7 +6566,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
6572
6566
  if (isTypedOutput(value)) {
6573
6567
  return baseToString(getTypedOutputTypeId(value), getTypedOutputValue(value));
6574
6568
  }
6575
- const pre = preformatValueForDisplay(typeId, value, registry);
6569
+ const pre = preformatValueForDisplay(typeId, value, wb.registry);
6576
6570
  if (pre !== undefined)
6577
6571
  return pre;
6578
6572
  if (typeof value === "object" &&
@@ -6588,7 +6582,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
6588
6582
  }
6589
6583
  if (typeId && typeId.startsWith("enum:")) {
6590
6584
  const n = Number(value);
6591
- const label = registry.enums.get(typeId)?.valueToLabel.get(n);
6585
+ const label = wb.registry.enums.get(typeId)?.valueToLabel.get(n);
6592
6586
  return label ?? String(n);
6593
6587
  }
6594
6588
  const round4 = (n) => Math.round(Number(n) * 10000) / 10000;
@@ -6618,22 +6612,22 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
6618
6612
  return String(rounded);
6619
6613
  }
6620
6614
  return String(value);
6621
- }, [registry]);
6615
+ }, [wb.registry]);
6622
6616
  const baseToElement = useCallback((typeId, value) => {
6623
6617
  return (jsx("span", { className: "ml-1 opacity-60", children: baseToString(typeId, value) }));
6624
6618
  }, [baseToString]);
6625
6619
  const toString = useMemo(() => {
6626
6620
  if (overrides?.toString)
6627
- return overrides.toString(baseToString, { registry });
6621
+ return overrides.toString(baseToString, { registry: wb.registry });
6628
6622
  return baseToString;
6629
- }, [overrides, baseToString, registry]);
6623
+ }, [overrides, baseToString, wb.registry]);
6630
6624
  // Optional: toElement (not currently consumed by core UI)
6631
6625
  // Consumers can access it by passing through their own node renderers.
6632
6626
  const toElement = useMemo(() => {
6633
6627
  if (overrides?.toElement)
6634
- return overrides.toElement(baseToElement, { registry });
6628
+ return overrides.toElement(baseToElement, { registry: wb.registry });
6635
6629
  return baseToElement;
6636
- }, [overrides, baseToElement, registry]);
6630
+ }, [overrides, baseToElement, wb.registry]);
6637
6631
  return (jsxs("div", { className: "w-full h-screen flex flex-col", children: [jsxs("div", { className: "p-2 border-b border-gray-300 flex gap-2 items-center", children: [isGraphRunning ? (jsxs("span", { className: "ml-2 text-sm text-green-700", children: ["Running: ", engineKind] })) : (jsx("span", { className: "ml-2 text-sm text-gray-500", children: "Stopped" })), jsxs("span", { className: "ml-2 flex items-center gap-1 text-xs", title: transportStatus.kind || undefined, children: [transportStatus.state === "local" && (jsx(PlugsConnectedIcon, { size: 14, className: "text-gray-500" })), transportStatus.state === "connecting" && (jsx(ClockClockwiseIcon, { size: 14, className: "text-amber-600 animate-pulse" })), transportStatus.state === "connected" && (jsx(WifiHighIcon, { size: 14, className: "text-green-600" })), transportStatus.state === "disconnected" && (jsx(WifiSlashIcon, { size: 14, className: "text-red-600" })), transportStatus.state === "retrying" && (jsx(ClockClockwiseIcon, { size: 14, className: "text-amber-700 animate-pulse" }))] }), 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: [jsx("option", { value: "", children: "Select Example\u2026" }), examples.map((ex) => (jsx("option", { value: ex.id, children: ex.label }, ex.id)))] }), 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: [jsx("option", { value: "local", children: "Local" }), jsx("option", { value: "remote-http", children: "Remote (HTTP)" }), jsx("option", { value: "remote-ws", children: "Remote (WebSocket)" })] }), backendKind === "remote-http" && !!onHttpBaseUrlChange && (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 && (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) })), jsxs("select", { className: "border border-gray-300 rounded px-2 py-1", value: engineKind ?? engine ?? "", onChange: async (e) => {
6638
6632
  const kind = e.target.value || undefined;
6639
6633
  const currentEngine = runner.getRunningEngine();
@@ -6735,7 +6729,7 @@ function WorkbenchStudio({ engine, onEngineChange, example, onExampleChange, bac
6735
6729
  runner.dispose();
6736
6730
  onBackendKindChange(v);
6737
6731
  }, [isGraphRunning]);
6738
- return (jsx(WorkbenchProvider, { wb: wb, runner: runner, registry: registry, setRegistry: setRegistry, overrides: overrides, uiVersion: uiVersion, children: 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 }) }));
6732
+ return (jsx(WorkbenchProvider, { wb: wb, runner: runner, overrides: overrides, uiVersion: uiVersion, children: 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 }) }));
6739
6733
  }
6740
6734
 
6741
6735
  export { AbstractWorkbench, CLIWorkbench, DefaultEdge, DefaultNode, DefaultNodeContent, DefaultNodeHeader, DefaultUIExtensionRegistry, InMemoryWorkbench, Inspector, LocalGraphRunner, NodeHandles, RemoteGraphRunner, WorkbenchCanvas, WorkbenchContext, WorkbenchProvider, WorkbenchStudio, captureCanvasThumbnail, computeEffectiveHandles, countVisibleHandles, createCopyHandler, createDefaultContextMenuHandlers, createHandleBounds, createHandleLayout, createNodeContextMenuHandlers, createNodeCopyHandler, createSelectionContextMenuHandlers, download, downloadCanvasThumbnail, estimateNodeSize, excludeViewportFromUIState, formatDataUrlAsLabel, formatDeclaredTypeSignature, getBakeableOutputs, getHandleBoundsX, getHandleBoundsY, getHandleClassName, getHandleLayoutY, getNodeBorderClassNames, isValidViewport, layoutNode, mergeUIState, preformatValueForDisplay, prettyHandle, resolveOutputDisplay, summarizeDeep, toReactFlow, upload, useQueryParamBoolean, useQueryParamString, useThrottledValue, useWorkbenchBridge, useWorkbenchContext, useWorkbenchGraphTick, useWorkbenchGraphUiTick, useWorkbenchVersionTick };