@bian-womp/spark-workbench 0.1.15 → 0.1.17

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 (33) hide show
  1. package/lib/cjs/index.cjs +235 -11
  2. package/lib/cjs/index.cjs.map +1 -1
  3. package/lib/cjs/src/index.d.ts +1 -0
  4. package/lib/cjs/src/index.d.ts.map +1 -1
  5. package/lib/cjs/src/misc/DebugEvents.d.ts.map +1 -1
  6. package/lib/cjs/src/misc/DefaultNode.d.ts.map +1 -1
  7. package/lib/cjs/src/misc/Inspector.d.ts.map +1 -1
  8. package/lib/cjs/src/misc/WorkbenchStudio.d.ts +3 -3
  9. package/lib/cjs/src/misc/WorkbenchStudio.d.ts.map +1 -1
  10. package/lib/cjs/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
  11. package/lib/cjs/src/misc/mapping.d.ts +1 -0
  12. package/lib/cjs/src/misc/mapping.d.ts.map +1 -1
  13. package/lib/cjs/src/misc/value.d.ts +9 -0
  14. package/lib/cjs/src/misc/value.d.ts.map +1 -0
  15. package/lib/cjs/src/runtime/GraphRunner.d.ts +2 -0
  16. package/lib/cjs/src/runtime/GraphRunner.d.ts.map +1 -1
  17. package/lib/esm/index.js +233 -13
  18. package/lib/esm/index.js.map +1 -1
  19. package/lib/esm/src/index.d.ts +1 -0
  20. package/lib/esm/src/index.d.ts.map +1 -1
  21. package/lib/esm/src/misc/DebugEvents.d.ts.map +1 -1
  22. package/lib/esm/src/misc/DefaultNode.d.ts.map +1 -1
  23. package/lib/esm/src/misc/Inspector.d.ts.map +1 -1
  24. package/lib/esm/src/misc/WorkbenchStudio.d.ts +3 -3
  25. package/lib/esm/src/misc/WorkbenchStudio.d.ts.map +1 -1
  26. package/lib/esm/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
  27. package/lib/esm/src/misc/mapping.d.ts +1 -0
  28. package/lib/esm/src/misc/mapping.d.ts.map +1 -1
  29. package/lib/esm/src/misc/value.d.ts +9 -0
  30. package/lib/esm/src/misc/value.d.ts.map +1 -0
  31. package/lib/esm/src/runtime/GraphRunner.d.ts +2 -0
  32. package/lib/esm/src/runtime/GraphRunner.d.ts.map +1 -1
  33. package/package.json +4 -4
package/lib/cjs/index.cjs CHANGED
@@ -439,6 +439,7 @@ class GraphRunner {
439
439
  rc.valueCache.set(`${e.nodeId}.${e.handle}`, {
440
440
  io: e.io,
441
441
  value: e.value,
442
+ runtimeTypeId: e.runtimeTypeId,
442
443
  });
443
444
  this.emit("value", e);
444
445
  });
@@ -808,12 +809,115 @@ function useQueryParamString(key, defaultValue) {
808
809
  return [val, set];
809
810
  }
810
811
 
812
+ function resolveOutputDisplay(raw, declared) {
813
+ if (sparkGraph.isTypedOutput(raw)) {
814
+ return { typeId: String(raw.__spark_type), value: raw.__spark_value };
815
+ }
816
+ let typeId = undefined;
817
+ if (Array.isArray(declared)) {
818
+ typeId = declared.length === 1 ? declared[0] : undefined;
819
+ }
820
+ else if (typeof declared === "string") {
821
+ typeId = declared.includes("|") ? undefined : declared;
822
+ }
823
+ return { typeId, value: raw };
824
+ }
825
+ function formatDeclaredTypeSignature(declared) {
826
+ if (Array.isArray(declared))
827
+ return declared.join(" | ");
828
+ return declared ?? "";
829
+ }
830
+ // Pre-format common structures for display; return undefined to defer to caller
831
+ function preformatValueForDisplay(typeId, value, registry) {
832
+ if (value === undefined || value === null)
833
+ return "";
834
+ // Unwrap typed outputs
835
+ if (sparkGraph.isTypedOutput(value)) {
836
+ return preformatValueForDisplay(String(value.__spark_type), value.__spark_value, registry);
837
+ }
838
+ // Enums
839
+ if (typeId && typeId.includes("enum:") && registry) {
840
+ const n = Number(value);
841
+ const label = registry.enums.get(typeId)?.valueToLabel.get(n);
842
+ if (label)
843
+ return label;
844
+ }
845
+ // Use deep summarization for strings, arrays and nested objects to avoid huge HTML payloads
846
+ const summarized = summarizeDeep(value);
847
+ if (typeof summarized === "string")
848
+ return summarized;
849
+ // Resource-like objects with url/title (after summarization)
850
+ if (summarized && typeof summarized === "object") {
851
+ const urlMaybe = summarized.url;
852
+ if (typeof urlMaybe === "string") {
853
+ const title = summarized.title || "";
854
+ const shortUrl = urlMaybe.length > 32 ? urlMaybe.slice(0, 32) + "…" : urlMaybe;
855
+ return title ? `${title} (${shortUrl})` : shortUrl;
856
+ }
857
+ }
858
+ return undefined;
859
+ }
860
+ function summarizeDeep(value, registry) {
861
+ // Strings: summarize data URLs and trim extremely long strings
862
+ if (typeof value === "string") {
863
+ if (value.startsWith("data:")) {
864
+ try {
865
+ const semi = value.indexOf(";");
866
+ const comma = value.indexOf(",");
867
+ const mime = value.slice(5, semi > 0 ? semi : undefined).toUpperCase();
868
+ const b64 = comma >= 0 ? value.slice(comma + 1) : "";
869
+ const bytes = Math.floor((b64.length * 3) / 4);
870
+ return `${mime} Data (${bytes} bytes)`;
871
+ }
872
+ catch {
873
+ return value.length > 64 ? value.slice(0, 64) + "…" : value;
874
+ }
875
+ }
876
+ return value.length > 512 ? value.slice(0, 512) + "…" : value;
877
+ }
878
+ // Typed output wrapper
879
+ if (sparkGraph.isTypedOutput(value)) {
880
+ return summarizeDeep(value.__spark_value);
881
+ }
882
+ // Arrays
883
+ if (Array.isArray(value)) {
884
+ return value.map((v) => summarizeDeep(v));
885
+ }
886
+ // Objects
887
+ if (value && typeof value === "object") {
888
+ const obj = value;
889
+ const out = {};
890
+ for (const [k, v] of Object.entries(obj)) {
891
+ // Special-case any 'url' field
892
+ if (typeof v === "string" &&
893
+ k.toLowerCase() === "url" &&
894
+ v.startsWith("data:")) {
895
+ try {
896
+ const semi = v.indexOf(";");
897
+ const comma = v.indexOf(",");
898
+ const mime = v.slice(5, semi > 0 ? semi : undefined).toUpperCase();
899
+ const b64 = comma >= 0 ? v.slice(comma + 1) : "";
900
+ const bytes = Math.floor((b64.length * 3) / 4);
901
+ out[k] = `${mime} Data (${bytes} bytes)`;
902
+ continue;
903
+ }
904
+ catch {
905
+ // fallthrough
906
+ }
907
+ }
908
+ out[k] = summarizeDeep(v);
909
+ }
910
+ return out;
911
+ }
912
+ return value;
913
+ }
914
+
811
915
  function toReactFlow(def, positions, registry, opts) {
812
916
  const nodeHandleMap = {};
813
917
  const nodes = def.nodes.map((n) => {
814
918
  const desc = registry.nodes.get(n.typeId);
815
919
  const inputHandles = Object.entries(desc?.inputs ?? {}).map(([id, typeId]) => ({ id, typeId }));
816
- const outputHandles = Object.entries(desc?.outputs ?? {}).map(([id, typeId]) => ({ id, typeId }));
920
+ const outputHandles = Object.entries(desc?.outputs ?? {}).map(([id, typeId]) => ({ id, typeId: formatDeclaredTypeSignature(typeId) }));
817
921
  nodeHandleMap[n.nodeId] = {
818
922
  inputs: new Set(inputHandles.map((h) => h.id)),
819
923
  outputs: new Set(outputHandles.map((h) => h.id)),
@@ -873,6 +977,7 @@ function toReactFlow(def, positions, registry, opts) {
873
977
  : undefined,
874
978
  animated: isRunning,
875
979
  style,
980
+ label: e.typeId || undefined,
876
981
  };
877
982
  });
878
983
  return { nodes, edges };
@@ -913,6 +1018,41 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
913
1018
  const [edgeStatus, setEdgeStatus] = React.useState({});
914
1019
  const [events, setEvents] = React.useState([]);
915
1020
  const clearEvents = React.useCallback(() => setEvents([]), []);
1021
+ // Fallback progress animation: drive progress to 100% over ~2 minutes
1022
+ const FALLBACK_TOTAL_MS = 2 * 60 * 1000;
1023
+ const [fallbackStarts, setFallbackStarts] = React.useState({});
1024
+ // Track runs that emitted an error so we can keep progress on completion
1025
+ const [errorRuns, setErrorRuns] = React.useState({});
1026
+ // Periodically advance fallback progress for running nodes without explicit progress
1027
+ React.useEffect(() => {
1028
+ const interval = setInterval(() => {
1029
+ setNodeStatus((prev) => {
1030
+ let changed = false;
1031
+ const next = { ...prev };
1032
+ const now = Date.now();
1033
+ for (const id of Object.keys(prev)) {
1034
+ const st = prev[id];
1035
+ if (!st)
1036
+ continue;
1037
+ const runs = st.activeRuns ?? 0;
1038
+ const startAt = fallbackStarts[id];
1039
+ if (runs > 0 && startAt) {
1040
+ const cur = Math.max(0, Math.min(1, Number(st.progress) || 0));
1041
+ const elapsed = Math.max(0, now - startAt);
1042
+ // Approach 100% over the target window, but cap below 1 until done
1043
+ const target = Math.max(0, Math.min(0.99, elapsed / FALLBACK_TOTAL_MS));
1044
+ const merged = Math.max(cur, target);
1045
+ if (merged > cur + 0.005 && merged <= 1) {
1046
+ next[id] = { ...st, progress: merged };
1047
+ changed = true;
1048
+ }
1049
+ }
1050
+ }
1051
+ return changed ? next : prev;
1052
+ });
1053
+ }, 200);
1054
+ return () => clearInterval(interval);
1055
+ }, [fallbackStarts]);
916
1056
  // Validation
917
1057
  const [validation, setValidation] = React.useState(undefined);
918
1058
  // Selection (mirror workbench selectionChanged)
@@ -970,8 +1110,8 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
970
1110
  layers.push(layer);
971
1111
  q.splice(0, q.length, ...next);
972
1112
  }
973
- const X = 360;
974
- const Y = 180;
1113
+ const X = 480;
1114
+ const Y = 240;
975
1115
  const pos = {};
976
1116
  layers.forEach((layer, layerIndex) => {
977
1117
  layer.forEach((id, itemIndex) => {
@@ -1025,6 +1165,13 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
1025
1165
  lastError: nodeError.err,
1026
1166
  },
1027
1167
  }));
1168
+ // Mark this runId as errored
1169
+ if (nodeError.runId) {
1170
+ setErrorRuns((prev) => ({
1171
+ ...prev,
1172
+ [nodeId]: { ...(prev[nodeId] || {}), [nodeError.runId]: true },
1173
+ }));
1174
+ }
1028
1175
  }
1029
1176
  return add("runner", "error")(e);
1030
1177
  });
@@ -1057,6 +1204,8 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
1057
1204
  },
1058
1205
  };
1059
1206
  });
1207
+ // Start fallback animation window
1208
+ setFallbackStarts((prev) => ({ ...prev, [id]: Date.now() }));
1060
1209
  }
1061
1210
  else if (s.kind === "node-progress") {
1062
1211
  const id = s.nodeId;
@@ -1070,16 +1219,42 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, children, }) {
1070
1219
  }
1071
1220
  else if (s.kind === "node-done") {
1072
1221
  const id = s.nodeId;
1222
+ const runId = s.runId;
1073
1223
  setNodeStatus((prev) => {
1074
1224
  const current = prev[id]?.activeRuns ?? 0;
1225
+ const nextActive = current - 1;
1226
+ const hadError = !!(runId && errorRuns[id]?.[runId]);
1227
+ const keepProgress = hadError || nextActive > 0;
1075
1228
  return {
1076
1229
  ...prev,
1077
1230
  [id]: {
1078
1231
  ...prev[id],
1079
- activeRuns: current - 1,
1232
+ activeRuns: nextActive,
1233
+ progress: keepProgress ? prev[id]?.progress : 0,
1080
1234
  },
1081
1235
  };
1082
1236
  });
1237
+ // Clear fallback start timestamp if no more active runs
1238
+ setFallbackStarts((prev) => {
1239
+ prev[id];
1240
+ const nextPrev = { ...prev };
1241
+ // If we don't know nextActive here, conservatively clear to stop animation
1242
+ delete nextPrev[id];
1243
+ return nextPrev;
1244
+ });
1245
+ // Clear error flag for this runId
1246
+ if (runId) {
1247
+ setErrorRuns((prev) => {
1248
+ const nodeMap = { ...(prev[id] || {}) };
1249
+ delete nodeMap[runId];
1250
+ const next = { ...prev };
1251
+ if (Object.keys(nodeMap).length === 0)
1252
+ delete next[id];
1253
+ else
1254
+ next[id] = nodeMap;
1255
+ return next;
1256
+ });
1257
+ }
1083
1258
  }
1084
1259
  else if (s.kind === "edge-start") {
1085
1260
  const id = s.edgeId;
@@ -1306,7 +1481,8 @@ function DebugEvents({ autoScroll, onAutoScrollChange, hideWorkbench, onHideWork
1306
1481
  }, [rows, autoScroll]);
1307
1482
  const renderPayload = (v) => {
1308
1483
  try {
1309
- return JSON.stringify(v, null, 0);
1484
+ const summarized = summarizeDeep(v);
1485
+ return JSON.stringify(summarized, null, 0);
1310
1486
  }
1311
1487
  catch {
1312
1488
  return String(v);
@@ -1318,9 +1494,18 @@ function DebugEvents({ autoScroll, onAutoScrollChange, hideWorkbench, onHideWork
1318
1494
  function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHideWorkbenchChange, toString, toElement, setInput, }) {
1319
1495
  const safeToString = (typeId, value) => {
1320
1496
  try {
1321
- return typeof toString === "function"
1322
- ? toString(typeId, value)
1323
- : String(value ?? "");
1497
+ if (typeof toString === "function") {
1498
+ // Special-case data URLs for readability
1499
+ if (typeof value === "string" && value.startsWith("data:image/")) {
1500
+ const comma = value.indexOf(",");
1501
+ const b64 = comma >= 0 ? value.slice(comma + 1) : "";
1502
+ const bytes = Math.floor((b64.length * 3) / 4);
1503
+ const fmt = value.slice(5, value.indexOf(";")) || "image";
1504
+ return `${fmt.toUpperCase()} Data (${bytes} bytes)`;
1505
+ }
1506
+ return toString(typeId, value);
1507
+ }
1508
+ return String(value ?? "");
1324
1509
  }
1325
1510
  catch {
1326
1511
  return String(value ?? "");
@@ -1431,7 +1616,7 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
1431
1616
  const title = inIssues
1432
1617
  .map((v) => `${v.code}: ${v.message}`)
1433
1618
  .join("; ");
1434
- return (jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsxs("label", { className: "w-28", children: [h, jsxRuntime.jsx("span", { className: "text-gray-500 ml-1 text-[11px]", children: selectedDesc?.inputs?.[h] })] }), hasValidation && (jsxRuntime.jsx(IssueBadge, { level: hasErr ? "error" : "warning", size: 24, className: "ml-1 w-6 h-6", title: title })), isEnum ? (jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500 w-full", value: current !== undefined && current !== null
1619
+ return (jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsxs("label", { className: "w-32", children: [h, jsxRuntime.jsx("span", { className: "text-gray-500 ml-1 text-[11px]", children: selectedDesc?.inputs?.[h] })] }), hasValidation && (jsxRuntime.jsx(IssueBadge, { level: hasErr ? "error" : "warning", size: 24, className: "ml-1 w-6 h-6", title: title })), isEnum ? (jsxRuntime.jsxs("select", { className: "border border-gray-300 rounded px-2 py-1 focus:outline-none focus:ring-2 focus:ring-blue-500 w-full", value: current !== undefined && current !== null
1435
1620
  ? String(current)
1436
1621
  : "", onChange: (e) => {
1437
1622
  const val = e.target.value;
@@ -1447,7 +1632,10 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
1447
1632
  if (e.key === "Escape")
1448
1633
  revert();
1449
1634
  }, ...commonProps }))] }, h));
1450
- }))] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { className: "font-semibold mb-1", children: "Outputs" }), outputHandles.length === 0 ? (jsxRuntime.jsx("div", { className: "text-gray-500", children: "No outputs" })) : (outputHandles.map((h) => (jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsx("label", { className: "w-20", children: h }), jsxRuntime.jsx("div", { className: "flex-1", children: toElement(selectedDesc?.outputs?.[h], nodeOutputs[h]) }), (() => {
1635
+ }))] }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { className: "font-semibold mb-1", children: "Outputs" }), outputHandles.length === 0 ? (jsxRuntime.jsx("div", { className: "text-gray-500", children: "No outputs" })) : (outputHandles.map((h) => (jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsxRuntime.jsx("label", { className: "w-20", children: h }), jsxRuntime.jsx("div", { className: "flex-1", children: (() => {
1636
+ const { typeId, value } = resolveOutputDisplay(nodeOutputs[h], selectedDesc?.outputs?.[h]);
1637
+ return toElement(typeId, value);
1638
+ })() }), (() => {
1451
1639
  const outIssues = selectedNodeHandleValidation.outputs.filter((m) => m.handle === h);
1452
1640
  if (outIssues.length === 0)
1453
1641
  return null;
@@ -1514,7 +1702,8 @@ const DefaultNode = React.memo(function DefaultNode({ id, data, selected, isConn
1514
1702
  const title = vIssues
1515
1703
  .map((v) => `${v.code}: ${v.message}`)
1516
1704
  .join("; ");
1517
- return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx(ReactFlow.Handle, { id: entry.id, type: "source", position: ReactFlow.Position.Right, isConnectable: isConnectable, className: cx("!w-3 !h-3 !bg-white !dark:bg-stone-900 !border-gray-500 dark:!border-gray-400 !rounded-none", hasAny && (hasErr ? "!border-red-500" : "!border-amber-500")), style: { right: -5, top: topFor(i) } }), jsxRuntime.jsxs("div", { className: "absolute right-2 text-[11px] text-gray-700 dark:text-gray-300 pointer-events-none", style: { top: topFor(i) - 8, textAlign: "right" }, title: `${entry.id}: ${entry.typeId}`, children: [entry.id, hasAny && (jsxRuntime.jsx(IssueBadge, { level: hasErr ? "error" : "warning", size: 12, className: "ml-1", title: title })), showValues && (jsxRuntime.jsx("span", { className: "ml-1 opacity-60", children: toString(entry.typeId, outputValues?.[entry.id]) }))] })] }, `out-${entry.id}`));
1705
+ const resolved = resolveOutputDisplay(outputValues?.[entry.id], entry.typeId);
1706
+ return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx(ReactFlow.Handle, { id: entry.id, type: "source", position: ReactFlow.Position.Right, isConnectable: isConnectable, className: cx("!w-3 !h-3 !bg-white !dark:bg-stone-900 !border-gray-500 dark:!border-gray-400 !rounded-none", hasAny && (hasErr ? "!border-red-500" : "!border-amber-500")), style: { right: -5, top: topFor(i) } }), jsxRuntime.jsxs("div", { className: "absolute right-2 text-[11px] text-gray-700 dark:text-gray-300 pointer-events-none", style: { top: topFor(i) - 8, textAlign: "right" }, title: `${entry.id}: ${entry.typeId}`, children: [entry.id, resolved.typeId && (jsxRuntime.jsxs("span", { className: "ml-1 opacity-60", children: ["(", resolved.typeId, ")"] })), hasAny && (jsxRuntime.jsx(IssueBadge, { level: hasErr ? "error" : "warning", size: 12, className: "ml-1", title: title })), showValues && (jsxRuntime.jsx("span", { className: "ml-1 opacity-60", children: toString(resolved.typeId, resolved.value) }))] })] }, `out-${entry.id}`));
1518
1707
  })] }));
1519
1708
  });
1520
1709
  DefaultNode.displayName = "DefaultNode";
@@ -2010,6 +2199,37 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
2010
2199
  const baseToString = React.useCallback((typeId, value) => {
2011
2200
  if (value === undefined || value === null)
2012
2201
  return "";
2202
+ // Normalize typed wrapper
2203
+ if (sparkGraph.isTypedOutput(value)) {
2204
+ return baseToString(String(value.__spark_type), value.__spark_value);
2205
+ }
2206
+ const pre = preformatValueForDisplay(typeId, value, registry);
2207
+ if (pre !== undefined)
2208
+ return pre;
2209
+ if (typeof value === "object" &&
2210
+ value !== null &&
2211
+ typeof value.url === "string") {
2212
+ const title = value.title || "";
2213
+ const url = String(value.url || "");
2214
+ if (url.startsWith("data:image/")) {
2215
+ try {
2216
+ const semi = url.indexOf(";");
2217
+ const comma = url.indexOf(",");
2218
+ const mime = url
2219
+ .slice(5, semi > 0 ? semi : undefined)
2220
+ .toUpperCase();
2221
+ const b64 = comma >= 0 ? url.slice(comma + 1) : "";
2222
+ const bytes = Math.floor((b64.length * 3) / 4);
2223
+ return title
2224
+ ? `${title} (${mime} ${bytes} bytes)`
2225
+ : `${mime} Data (${bytes} bytes)`;
2226
+ }
2227
+ catch {
2228
+ return title || url.slice(0, 32) + (url.length > 32 ? "…" : "");
2229
+ }
2230
+ }
2231
+ return title || url.slice(0, 32) + (url.length > 32 ? "…" : "");
2232
+ }
2013
2233
  if (typeId && typeId.includes("enum:")) {
2014
2234
  const n = Number(value);
2015
2235
  const label = registry.enums.get(typeId)?.valueToLabel.get(n);
@@ -2107,7 +2327,11 @@ exports.WorkbenchCanvas = WorkbenchCanvas;
2107
2327
  exports.WorkbenchContext = WorkbenchContext;
2108
2328
  exports.WorkbenchProvider = WorkbenchProvider;
2109
2329
  exports.WorkbenchStudio = WorkbenchStudio;
2330
+ exports.formatDeclaredTypeSignature = formatDeclaredTypeSignature;
2110
2331
  exports.getNodeBorderClassNames = getNodeBorderClassNames;
2332
+ exports.preformatValueForDisplay = preformatValueForDisplay;
2333
+ exports.resolveOutputDisplay = resolveOutputDisplay;
2334
+ exports.summarizeDeep = summarizeDeep;
2111
2335
  exports.toReactFlow = toReactFlow;
2112
2336
  exports.useQueryParamBoolean = useQueryParamBoolean;
2113
2337
  exports.useQueryParamString = useQueryParamString;