@bian-womp/spark-workbench 0.1.2 → 0.1.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"WorkbenchStudio.d.ts","sourceRoot":"","sources":["../../../../../src/examples/reactflow/WorkbenchStudio.tsx"],"names":[],"mappings":"AAkbA,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,MAAM,EACN,cAAc,EACd,OAAO,EACP,eAAe,EACf,WAAW,EACX,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,KAAK,EACL,aAAa,EACb,KAAK,EACL,aAAa,EACb,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,qBAAqB,EACrB,UAAU,EACV,kBAAkB,GACnB,EAAE;IACD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAClD,WAAW,EAAE,OAAO,GAAG,aAAa,GAAG,WAAW,CAAC;IACnD,mBAAmB,EAAE,CAAC,CAAC,EAAE,OAAO,GAAG,aAAa,GAAG,WAAW,KAAK,IAAI,CAAC;IACxE,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,UAAU,EAAE,OAAO,CAAC;IACpB,kBAAkB,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,aAAa,EAAE,OAAO,CAAC;IACvB,qBAAqB,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,UAAU,EAAE,OAAO,CAAC;IACpB,kBAAkB,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C,2CAiDA"}
1
+ {"version":3,"file":"WorkbenchStudio.d.ts","sourceRoot":"","sources":["../../../../../src/examples/reactflow/WorkbenchStudio.tsx"],"names":[],"mappings":"AA0gBA,MAAM,CAAC,OAAO,UAAU,eAAe,CAAC,EACtC,MAAM,EACN,cAAc,EACd,OAAO,EACP,eAAe,EACf,WAAW,EACX,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,KAAK,EACL,aAAa,EACb,KAAK,EACL,aAAa,EACb,UAAU,EACV,kBAAkB,EAClB,aAAa,EACb,qBAAqB,EACrB,UAAU,EACV,kBAAkB,GACnB,EAAE;IACD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAClD,WAAW,EAAE,OAAO,GAAG,aAAa,GAAG,WAAW,CAAC;IACnD,mBAAmB,EAAE,CAAC,CAAC,EAAE,OAAO,GAAG,aAAa,GAAG,WAAW,KAAK,IAAI,CAAC;IACxE,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACpC,UAAU,EAAE,OAAO,CAAC;IACpB,kBAAkB,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,aAAa,EAAE,OAAO,CAAC;IACvB,qBAAqB,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,UAAU,EAAE,OAAO,CAAC;IACpB,kBAAkB,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C,2CAiDA"}
@@ -1 +1 @@
1
- {"version":3,"file":"Inspector.d.ts","sourceRoot":"","sources":["../../../../src/misc/Inspector.tsx"],"names":[],"mappings":"AAKA,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,qBAAqB,EACrB,SAAS,EACT,QAAQ,GACT,EAAE;IACD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,qBAAqB,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,SAAS,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;IACxD,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;CACxE,2CA4UA"}
1
+ {"version":3,"file":"Inspector.d.ts","sourceRoot":"","sources":["../../../../src/misc/Inspector.tsx"],"names":[],"mappings":"AAKA,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,qBAAqB,EACrB,SAAS,EACT,QAAQ,GACT,EAAE;IACD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kBAAkB,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1C,qBAAqB,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,SAAS,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;IACxD,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;CACxE,2CA6UA"}
package/lib/esm/index.js CHANGED
@@ -1,11 +1,11 @@
1
- import { GraphBuilder, StepEngine, HybridEngine, PullEngine, BatchedEngine, PushEngine, createSimpleGraphRegistry, createSimpleGraphDef, createValidationGraphRegistry, createValidationGraphDef, createProgressGraphRegistry, createProgressGraphDef, createAsyncGraphRegistry, createAsyncGraphDef } from '@bian-womp/spark-graph';
1
+ import { GraphBuilder, StepEngine, HybridEngine, PullEngine, BatchedEngine, PushEngine, createSimpleGraphRegistry, createSimpleGraphDef, createValidationGraphRegistry, createValidationGraphDef, createProgressGraphRegistry, createProgressGraphDef, createAsyncGraphRegistry, createAsyncGraphDef, Registry } from '@bian-womp/spark-graph';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
3
  import React, { createContext, useContext, useMemo, useState, useCallback, useEffect, useRef } from 'react';
4
+ import { HttpPollingTransport, WebSocketTransport, RemoteRunner } from '@bian-womp/spark-remote';
4
5
  import ReactFlow, { Handle, Position, useReactFlow, Background, MiniMap, Controls } from 'reactflow';
5
6
  import 'reactflow/dist/style.css';
6
7
  import cx from 'classnames';
7
8
  import { XCircleIcon, WarningCircleIcon } from '@phosphor-icons/react';
8
- import { HttpPollingTransport, WebSocketTransport, RemoteRunner } from '@bian-womp/spark-remote';
9
9
 
10
10
  class DefaultUIExtensionRegistry {
11
11
  constructor() {
@@ -1155,7 +1155,8 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
1155
1155
  return (jsxs("div", { className: `${widthClass} border-l border-gray-300 p-3 flex flex-col h-full min-h-0 overflow-hidden`, children: [jsx("div", { className: "font-semibold mb-2", children: "Inspector" }), jsx("div", { className: "flex-1 overflow-auto", children: !selectedNode && !selectedEdge ? (jsxs("div", { children: [jsx("div", { className: "text-gray-500", children: "Select a node or edge." }), globalValidationIssues && globalValidationIssues.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: globalValidationIssues.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}` })] }, i))) })] }))] })) : selectedEdge ? (jsxs("div", { children: [jsxs("div", { className: "mb-2", children: [jsxs("div", { children: ["Edge: ", selectedEdge.id] }), jsxs("div", { children: [selectedEdge.source.nodeId, ".", selectedEdge.source.handle, " \u2192", " ", selectedEdge.target.nodeId, ".", selectedEdge.target.handle] }), jsxs("div", { children: ["Type: ", selectedEdge.typeId] })] }), 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}` })] }, i))) })] }))] })) : (jsxs("div", { children: [selectedNode && (jsxs("div", { className: "mb-2", children: [jsxs("div", { children: ["Node: ", selectedNode.nodeId] }), jsxs("div", { children: ["Type: ", selectedNode.typeId] }), !!selectedNodeStatus?.lastError && (jsx("div", { className: "mt-2 text-sm text-red-700 bg-red-50 border border-red-200 rounded px-2 py-1 break-words", children: String(selectedNodeStatus.lastError?.message ??
1156
1156
  selectedNodeStatus.lastError) }))] })), jsxs("div", { className: "mb-2", children: [jsx("div", { className: "font-semibold mb-1", children: "Inputs" }), inputHandles.length === 0 ? (jsx("div", { className: "text-gray-500", children: "No inputs" })) : (inputHandles.map((h) => {
1157
1157
  const typeId = (selectedDesc?.inputs ?? {})[h];
1158
- const isLinked = def.edges.some((e) => e.target.nodeId === selectedNodeId && e.target.handle === h);
1158
+ const isLinked = def.edges.some((e) => e.target.nodeId === selectedNodeId &&
1159
+ e.target.handle === h);
1159
1160
  const commonProps = {
1160
1161
  style: { flex: 1 },
1161
1162
  disabled: isLinked,
@@ -1174,7 +1175,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
1174
1175
  const orig = originals[h] ?? toDisplay(typeId, current);
1175
1176
  setDrafts((d) => ({ ...d, [h]: orig }));
1176
1177
  };
1177
- const isEnum = typeId?.startsWith("enum:");
1178
+ const isEnum = typeId?.includes("enum:");
1178
1179
  const inIssues = selectedNodeHandleValidation.inputs.filter((m) => m.handle === h);
1179
1180
  const hasValidation = inIssues.length > 0;
1180
1181
  const hasErr = inIssues.some((m) => m.level === "error");
@@ -1537,6 +1538,60 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
1537
1538
  setExampleState(key);
1538
1539
  onExampleChange?.(key);
1539
1540
  }, [runner, wb, onExampleChange, runAutoLayout]);
1541
+ const hydrateFromBackend = useCallback(async (kind, base) => {
1542
+ try {
1543
+ const transport = kind === "remote-http"
1544
+ ? new HttpPollingTransport(base)
1545
+ : new WebSocketTransport(base);
1546
+ await transport.connect();
1547
+ const rr = new RemoteRunner(transport);
1548
+ const desc = await rr.describeRegistry();
1549
+ const r = new Registry();
1550
+ // Types
1551
+ for (const t of desc.types) {
1552
+ r.registerType({
1553
+ id: t.id,
1554
+ displayName: t.displayName,
1555
+ validate: (_v) => true,
1556
+ });
1557
+ }
1558
+ // Categories: create placeholders for display name
1559
+ for (const c of desc.categories || []) {
1560
+ // If you later expose real category descriptors, register them here
1561
+ // For now, rely on ComputeCategory for behavior
1562
+ const category = {
1563
+ id: c.id,
1564
+ displayName: c.displayName,
1565
+ createRuntime: () => ({
1566
+ async onInputsChanged() { },
1567
+ }),
1568
+ policy: { mode: "push", asyncConcurrency: "switch" },
1569
+ };
1570
+ r.categories.register(category);
1571
+ }
1572
+ // Coercions (client-side no-op to satisfy validation) if provided
1573
+ for (const c of desc.coercions) {
1574
+ r.registerCoercion(c.from, c.to, (v) => v);
1575
+ }
1576
+ // Nodes (use no-op impl for compute)
1577
+ for (const n of desc.nodes) {
1578
+ r.registerNode({
1579
+ id: n.id,
1580
+ categoryId: n.categoryId,
1581
+ displayName: n.displayName,
1582
+ inputs: n.inputs || {},
1583
+ outputs: n.outputs || {},
1584
+ impl: () => { },
1585
+ });
1586
+ }
1587
+ setRegistry(r);
1588
+ wb.setRegistry(r);
1589
+ await transport.close();
1590
+ }
1591
+ catch (err) {
1592
+ console.error("Failed to hydrate registry from backend:", err);
1593
+ }
1594
+ }, [setRegistry, wb]);
1540
1595
  // Ensure initial example is loaded (and sync when example prop changes)
1541
1596
  useEffect(() => {
1542
1597
  applyExample(example ?? "simple");
@@ -1559,6 +1614,15 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
1559
1614
  // ignore
1560
1615
  }
1561
1616
  }, [engine, runner, wb]);
1617
+ // When switching to remote backend, auto-hydrate registry from backend
1618
+ useEffect(() => {
1619
+ if (backendKind === "remote-http" && httpBaseUrl) {
1620
+ void hydrateFromBackend("remote-http", httpBaseUrl);
1621
+ }
1622
+ else if (backendKind === "remote-ws" && wsUrl) {
1623
+ void hydrateFromBackend("remote-ws", wsUrl);
1624
+ }
1625
+ }, [backendKind, httpBaseUrl, wsUrl, hydrateFromBackend]);
1562
1626
  useEffect(() => {
1563
1627
  if (autoLayoutRan.current)
1564
1628
  return;
@@ -1595,33 +1659,33 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
1595
1659
  .map(map);
1596
1660
  };
1597
1661
  switch (typeId) {
1598
- case "float": {
1662
+ case "base.float": {
1599
1663
  const n = Number(raw);
1600
1664
  value = Number.isFinite(n) ? n : 0;
1601
1665
  break;
1602
1666
  }
1603
- case "bool": {
1667
+ case "base.bool": {
1604
1668
  value = Boolean(raw);
1605
1669
  break;
1606
1670
  }
1607
- case "string": {
1671
+ case "base.string": {
1608
1672
  value = String(raw);
1609
1673
  break;
1610
1674
  }
1611
- case "float[]": {
1675
+ case "base.float[]": {
1612
1676
  value = parseArray(String(raw), (x) => Number(x));
1613
1677
  break;
1614
1678
  }
1615
- case "bool[]": {
1679
+ case "base.bool[]": {
1616
1680
  value = parseArray(String(raw), (x) => /^(true|1)$/i.test(x));
1617
1681
  break;
1618
1682
  }
1619
- case "vec3": {
1683
+ case "base.vec3": {
1620
1684
  const arr = parseArray(String(raw), (x) => Number(x));
1621
1685
  value = [arr[0] ?? 0, arr[1] ?? 0, arr[2] ?? 0];
1622
1686
  break;
1623
1687
  }
1624
- case "vec3[]": {
1688
+ case "base.vec3[]": {
1625
1689
  try {
1626
1690
  const parsed = JSON.parse(String(raw));
1627
1691
  if (Array.isArray(parsed)) {
@@ -1653,13 +1717,13 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
1653
1717
  const toDisplay = useCallback((typeId, value) => {
1654
1718
  if (value === undefined || value === null)
1655
1719
  return "";
1656
- if (typeId && typeId.startsWith("enum:")) {
1720
+ if (typeId && typeId.includes("enum:")) {
1657
1721
  const n = Number(value);
1658
1722
  const label = registry.getEnumLabel(typeId, n);
1659
1723
  return label ?? String(n);
1660
1724
  }
1661
1725
  const round4 = (n) => Math.round(Number(n) * 10000) / 10000;
1662
- if (typeId === "vec3" && Array.isArray(value)) {
1726
+ if (typeId === "base.vec3" && Array.isArray(value)) {
1663
1727
  const a = value;
1664
1728
  return [round4(a[0] ?? 0), round4(a[1] ?? 0), round4(a[2] ?? 0)].join(",");
1665
1729
  }