@particle-academy/fancy-flow 0.71.0 → 0.72.1

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 (53) hide show
  1. package/dist/{chunk-3L47KJ6Q.js → chunk-3RXQGYGH.js} +3 -3
  2. package/dist/{chunk-3L47KJ6Q.js.map → chunk-3RXQGYGH.js.map} +1 -1
  3. package/dist/{chunk-PNTDTSMR.js → chunk-7DJ56PUA.js} +4 -4
  4. package/dist/{chunk-PNTDTSMR.js.map → chunk-7DJ56PUA.js.map} +1 -1
  5. package/dist/{chunk-EVGSL2EM.js → chunk-EX34GCKK.js} +162 -151
  6. package/dist/chunk-EX34GCKK.js.map +1 -0
  7. package/dist/{chunk-XI4AZD2S.js → chunk-GQ5LEA7Q.js} +3 -3
  8. package/dist/{chunk-XI4AZD2S.js.map → chunk-GQ5LEA7Q.js.map} +1 -1
  9. package/dist/{chunk-D2OBU3CE.js → chunk-K7KO3UJ3.js} +3 -3
  10. package/dist/{chunk-D2OBU3CE.js.map → chunk-K7KO3UJ3.js.map} +1 -1
  11. package/dist/{chunk-FPWJYSXX.js → chunk-LYYQO7EY.js} +4 -4
  12. package/dist/{chunk-FPWJYSXX.js.map → chunk-LYYQO7EY.js.map} +1 -1
  13. package/dist/{chunk-KQCX6KN7.js → chunk-VAF2SWTC.js} +3 -3
  14. package/dist/{chunk-KQCX6KN7.js.map → chunk-VAF2SWTC.js.map} +1 -1
  15. package/dist/durable/index.d.cts +90 -16
  16. package/dist/durable/index.d.ts +90 -16
  17. package/dist/durable.cjs +160 -83
  18. package/dist/durable.cjs.map +1 -1
  19. package/dist/durable.js +79 -14
  20. package/dist/durable.js.map +1 -1
  21. package/dist/engine.cjs +82 -71
  22. package/dist/engine.cjs.map +1 -1
  23. package/dist/engine.d.cts +2 -2
  24. package/dist/engine.d.ts +2 -2
  25. package/dist/engine.js +4 -4
  26. package/dist/index.cjs +128 -117
  27. package/dist/index.cjs.map +1 -1
  28. package/dist/index.d.cts +2 -2
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.js +12 -12
  31. package/dist/registry.cjs +82 -71
  32. package/dist/registry.cjs.map +1 -1
  33. package/dist/registry.js +2 -2
  34. package/dist/{run-cohort-DL9JzzPU.d.cts → run-cohort-DNpPa0mq.d.cts} +1 -1
  35. package/dist/{run-cohort-CjUBWg6X.d.ts → run-cohort-rgT_FX3V.d.ts} +1 -1
  36. package/dist/{run-flow-B_8hgO5_.d.cts → run-flow-BLP9rXfO.d.ts} +22 -1
  37. package/dist/{run-flow-CxEGBOxd.d.ts → run-flow-pW0PllaZ.d.cts} +22 -1
  38. package/dist/runtime/index.d.cts +3 -3
  39. package/dist/runtime/index.d.ts +3 -3
  40. package/dist/runtime.cjs +82 -71
  41. package/dist/runtime.cjs.map +1 -1
  42. package/dist/runtime.js +3 -3
  43. package/dist/schema.cjs +82 -71
  44. package/dist/schema.cjs.map +1 -1
  45. package/dist/schema.js +3 -3
  46. package/dist/screens.cjs +82 -71
  47. package/dist/screens.cjs.map +1 -1
  48. package/dist/screens.js +4 -4
  49. package/dist/ux.cjs +82 -71
  50. package/dist/ux.cjs.map +1 -1
  51. package/dist/ux.js +1 -1
  52. package/package.json +1 -1
  53. package/dist/chunk-EVGSL2EM.js.map +0 -1
package/dist/engine.cjs CHANGED
@@ -2004,24 +2004,6 @@ function resolveNodePorts(node, kind) {
2004
2004
  };
2005
2005
  }
2006
2006
 
2007
- // src/expressions/variables.ts
2008
- function outputFieldsFor(node) {
2009
- const kindName2 = node.data?.kind ?? node.type;
2010
- if (!kindName2) return [];
2011
- const kind = getNodeKind(kindName2);
2012
- const shape = kind?.outputShape;
2013
- if (!shape) return [];
2014
- if (typeof shape === "function") {
2015
- try {
2016
- const config = node.data?.config ?? {};
2017
- return shape(config) ?? [];
2018
- } catch {
2019
- return [];
2020
- }
2021
- }
2022
- return shape;
2023
- }
2024
-
2025
2007
  // src/runtime/run-identity.ts
2026
2008
  function escapeSegment(value) {
2027
2009
  return value.replace(/%/g, "%25").replace(/\//g, "%2F").replace(/#/g, "%23");
@@ -2365,6 +2347,81 @@ function specForLane(lane) {
2365
2347
  };
2366
2348
  }
2367
2349
 
2350
+ // src/expressions/variables.ts
2351
+ function outputFieldsFor(node) {
2352
+ const kindName2 = node.data?.kind ?? node.type;
2353
+ if (!kindName2) return [];
2354
+ const kind = getNodeKind(kindName2);
2355
+ const shape = kind?.outputShape;
2356
+ if (!shape) return [];
2357
+ if (typeof shape === "function") {
2358
+ try {
2359
+ const config = node.data?.config ?? {};
2360
+ return shape(config) ?? [];
2361
+ } catch {
2362
+ return [];
2363
+ }
2364
+ }
2365
+ return shape;
2366
+ }
2367
+
2368
+ // src/runtime/undelivered-edges.ts
2369
+ function undeliveredEdgeWarnings(target, incoming, portValues, completed, nodesById) {
2370
+ const events = [];
2371
+ for (const e of incoming) {
2372
+ const handle = e.sourceHandle ?? "out";
2373
+ if (portValues.has(`${e.source}:${handle}`) || !completed.has(e.source)) continue;
2374
+ if (possiblePortIds(nodesById.get(e.source)).includes(handle)) continue;
2375
+ events.push({
2376
+ type: "log",
2377
+ nodeId: target.id,
2378
+ level: "warn",
2379
+ message: undeliveredEdgeMessage(e, target, portValues, nodesById),
2380
+ detail: { edge: e.id, source: e.source, sourceHandle: handle }
2381
+ });
2382
+ }
2383
+ return events;
2384
+ }
2385
+ function possiblePortIds(node) {
2386
+ if (!node) return ["out"];
2387
+ const own = node.data?.outputs;
2388
+ if (Array.isArray(own)) return own.map((p) => p.id);
2389
+ const kind = getNodeKind(node.data?.kind ?? node.type ?? "");
2390
+ if (!kind) return ["out"];
2391
+ const config = nodeConfig(node);
2392
+ const representative = typeof kind.outputs === "function" && !configDeclaresPorts(kind.name, config);
2393
+ const ids = (resolvePortSpec(kind.outputs, representative ? defaultConfigFor(kind) : config) ?? []).map((p) => p.id);
2394
+ return ids.length > 0 ? ids : ["out"];
2395
+ }
2396
+ function configDeclaresPorts(kindName2, config) {
2397
+ const bare = kindName2.startsWith("@") ? kindName2.slice(kindName2.lastIndexOf("/") + 1) : kindName2;
2398
+ if (bare === "switch_case") {
2399
+ const cases = config.cases;
2400
+ return !!cases && typeof cases === "object" && Object.values(cases).some((port) => typeof port === "string" && port !== "");
2401
+ }
2402
+ if (bare === "llm_router") {
2403
+ const routes = config.routes;
2404
+ return Array.isArray(routes) && routes.some((route) => route?.port != null && route.port !== "");
2405
+ }
2406
+ return true;
2407
+ }
2408
+ function undeliveredEdgeMessage(edge, target, portValues, nodesById) {
2409
+ const handle = edge.sourceHandle ?? "out";
2410
+ const prefix = `${edge.source}:`;
2411
+ const available = [];
2412
+ for (const key2 of portValues.keys()) {
2413
+ if (key2.startsWith(prefix)) available.push(key2.slice(prefix.length));
2414
+ }
2415
+ let message = `Edge ${edge.id} reads port "${handle}" from node ${edge.source}, which never publishes it \u2014 nothing would reach ${target.id} at run time.`;
2416
+ if (available.length > 0) message += ` Available: ${available.join(", ")}.`;
2417
+ const source = nodesById.get(edge.source);
2418
+ if (source && outputFieldsFor(source).some((field) => field?.path === handle)) {
2419
+ message += ` Note: "${handle}" is a FIELD this node emits, not a port \u2014 read it downstream as {{ in.${handle} }} rather than naming it as a source handle.`;
2420
+ }
2421
+ if (edge.sourceHandle != null) message += " Leave sourceHandle off to read the node's output.";
2422
+ return message;
2423
+ }
2424
+
2368
2425
  // src/runtime/workflow-props.ts
2369
2426
  function typeOf(value) {
2370
2427
  if (value === null) return "null";
@@ -2423,7 +2480,7 @@ function resolveWorkflowProps(declared, passed) {
2423
2480
  // src/runtime/run-flow.ts
2424
2481
  async function runFlow(graph, executors, onEvent = () => {
2425
2482
  }, options = {}) {
2426
- const { signal, initialInputs = {}, timeoutMs, depth = 0, resumeOutputs = {}, entryNodes } = options;
2483
+ const { signal, initialInputs = {}, timeoutMs, depth = 0, resumeOutputs = {}, entryNodes, nodeExecutors } = options;
2427
2484
  const run = options.run === void 0 ? void 0 : RunIdentity.from(options.run);
2428
2485
  const outputs = {};
2429
2486
  const portValues = /* @__PURE__ */ new Map();
@@ -2486,17 +2543,8 @@ async function runFlow(graph, executors, onEvent = () => {
2486
2543
  onEvent({ type: "node-status", nodeId: node.id, status: "idle", text: "skipped" });
2487
2544
  continue;
2488
2545
  }
2489
- for (const e of incoming) {
2490
- const handle = e.sourceHandle ?? "out";
2491
- if (portValues.has(`${e.source}:${handle}`) || !completed.has(e.source)) continue;
2492
- if (possiblePortIds(nodesById.get(e.source)).includes(handle)) continue;
2493
- onEvent({
2494
- type: "log",
2495
- nodeId: node.id,
2496
- level: "warn",
2497
- message: undeliveredEdgeMessage(e, node, portValues, nodesById),
2498
- detail: { edge: e.id, source: e.source, sourceHandle: handle }
2499
- });
2546
+ for (const warning of undeliveredEdgeWarnings(node, incoming, portValues, completed, nodesById)) {
2547
+ onEvent(warning);
2500
2548
  }
2501
2549
  if (incoming.length > 0) {
2502
2550
  const anyActive = incoming.some((e) => portValues.has(`${e.source}:${e.sourceHandle ?? "out"}`));
@@ -2520,7 +2568,7 @@ async function runFlow(graph, executors, onEvent = () => {
2520
2568
  onEvent({ type: "node-status", nodeId: node.id, status: "running" });
2521
2569
  announce(onEvent, node, "start");
2522
2570
  const inputs = collectInputs(node, incoming, portValues, initialInputs, props, declaresProps);
2523
- const exec = pickExecutor(executors, node);
2571
+ const exec = pickExecutor(executors, node, nodeExecutors);
2524
2572
  if (!exec) {
2525
2573
  const tried = executorLookupIds(node);
2526
2574
  const msg = `No executor registered for kind=${node.type} \u2014 tried ${tried.map((id) => `"${id}"`).join(", ")}. Key your registry by one of those.`;
@@ -2640,7 +2688,9 @@ function executorLookupIds(node) {
2640
2688
  ids.push("*");
2641
2689
  return [...new Set(ids)];
2642
2690
  }
2643
- function pickExecutor(executors, node) {
2691
+ function pickExecutor(executors, node, nodeExecutors) {
2692
+ const pinned = nodeExecutors && Object.prototype.hasOwnProperty.call(nodeExecutors, node.id) ? nodeExecutors[node.id] : void 0;
2693
+ if (pinned) return pinned;
2644
2694
  for (const id of executorLookupIds(node)) {
2645
2695
  if (executors[id]) return executors[id];
2646
2696
  }
@@ -2660,45 +2710,6 @@ function activatedPorts(node, result) {
2660
2710
  const declared = resolveNodePorts(node, kind).outputs?.map((p) => p.id);
2661
2711
  return { ports: declared?.length ? declared : ["out"], value: result };
2662
2712
  }
2663
- function possiblePortIds(node) {
2664
- if (!node) return ["out"];
2665
- const own = node.data?.outputs;
2666
- if (Array.isArray(own)) return own.map((p) => p.id);
2667
- const kind = getNodeKind(node.data?.kind ?? node.type ?? "");
2668
- if (!kind) return ["out"];
2669
- const config = nodeConfig(node);
2670
- const representative = typeof kind.outputs === "function" && !configDeclaresPorts(kind.name, config);
2671
- const ids = (resolvePortSpec(kind.outputs, representative ? defaultConfigFor(kind) : config) ?? []).map((p) => p.id);
2672
- return ids.length > 0 ? ids : ["out"];
2673
- }
2674
- function configDeclaresPorts(kindName2, config) {
2675
- const bare = kindName2.startsWith("@") ? kindName2.slice(kindName2.lastIndexOf("/") + 1) : kindName2;
2676
- if (bare === "switch_case") {
2677
- const cases = config.cases;
2678
- return !!cases && typeof cases === "object" && Object.values(cases).some((port) => typeof port === "string" && port !== "");
2679
- }
2680
- if (bare === "llm_router") {
2681
- const routes = config.routes;
2682
- return Array.isArray(routes) && routes.some((route) => route?.port != null && route.port !== "");
2683
- }
2684
- return true;
2685
- }
2686
- function undeliveredEdgeMessage(edge, target, portValues, nodesById) {
2687
- const handle = edge.sourceHandle ?? "out";
2688
- const prefix = `${edge.source}:`;
2689
- const available = [];
2690
- for (const key2 of portValues.keys()) {
2691
- if (key2.startsWith(prefix)) available.push(key2.slice(prefix.length));
2692
- }
2693
- let message = `Edge ${edge.id} reads port "${handle}" from node ${edge.source}, which never publishes it \u2014 nothing would reach ${target.id} at run time.`;
2694
- if (available.length > 0) message += ` Available: ${available.join(", ")}.`;
2695
- const source = nodesById.get(edge.source);
2696
- if (source && outputFieldsFor(source).some((field) => field?.path === handle)) {
2697
- message += ` Note: "${handle}" is a FIELD this node emits, not a port \u2014 read it downstream as {{ in.${handle} }} rather than naming it as a source handle.`;
2698
- }
2699
- if (edge.sourceHandle != null) message += " Leave sourceHandle off to read the node's output.";
2700
- return message;
2701
- }
2702
2713
  function announce(onEvent, node, phase) {
2703
2714
  const data = node.data;
2704
2715
  const raw = phase === "start" ? data?.startingMsg : data?.stoppingMsg;