@particle-academy/fancy-flow 0.77.1 → 0.79.0
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.
- package/dist/{FlowViewer-Ak8kbY0e.d.cts → FlowViewer-BqYQl2vS.d.cts} +1 -1
- package/dist/{FlowViewer-BAV29Zpi.d.ts → FlowViewer-_Fq8AX9V.d.ts} +1 -1
- package/dist/{HumanPrompt-xYPCL2jO.d.cts → HumanPrompt-Sl1wD9Bx.d.cts} +2 -2
- package/dist/{HumanPrompt-Ge_ccCgS.d.ts → HumanPrompt-_SKIdSpx.d.ts} +2 -2
- package/dist/{chunk-T6WIIGSK.js → chunk-I5EPWHNM.js} +3 -3
- package/dist/{chunk-T6WIIGSK.js.map → chunk-I5EPWHNM.js.map} +1 -1
- package/dist/{chunk-EGXA4SYJ.js → chunk-J66LOLJR.js} +4 -4
- package/dist/{chunk-EGXA4SYJ.js.map → chunk-J66LOLJR.js.map} +1 -1
- package/dist/{chunk-G5RAGPVD.js → chunk-KMONOPAK.js} +3 -3
- package/dist/{chunk-G5RAGPVD.js.map → chunk-KMONOPAK.js.map} +1 -1
- package/dist/{chunk-ARSOSEJV.js → chunk-LBE4L3DS.js} +4 -4
- package/dist/{chunk-ARSOSEJV.js.map → chunk-LBE4L3DS.js.map} +1 -1
- package/dist/{chunk-EEIWAIXW.js → chunk-OZHBAXMA.js} +125 -8
- package/dist/chunk-OZHBAXMA.js.map +1 -0
- package/dist/{chunk-2VI24UPB.js → chunk-QMJVUT7C.js} +3 -3
- package/dist/{chunk-2VI24UPB.js.map → chunk-QMJVUT7C.js.map} +1 -1
- package/dist/{chunk-CQAMEPPI.js → chunk-R4G7SPLD.js} +3 -3
- package/dist/{chunk-CQAMEPPI.js.map → chunk-R4G7SPLD.js.map} +1 -1
- package/dist/connectors.d.cts +2 -2
- package/dist/connectors.d.ts +2 -2
- package/dist/durable/index.d.cts +2 -2
- package/dist/durable/index.d.ts +2 -2
- package/dist/durable.cjs +123 -6
- package/dist/durable.cjs.map +1 -1
- package/dist/durable.js +1 -1
- package/dist/engine.cjs +123 -6
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.cts +6 -6
- package/dist/engine.d.ts +6 -6
- package/dist/engine.js +4 -4
- package/dist/fields/react-fancy.d.cts +3 -3
- package/dist/fields/react-fancy.d.ts +3 -3
- package/dist/index.cjs +123 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -10
- package/dist/index.d.ts +10 -10
- package/dist/index.js +12 -12
- package/dist/layout/index.d.cts +1 -1
- package/dist/layout/index.d.ts +1 -1
- package/dist/llm/prism.d.cts +1 -1
- package/dist/llm/prism.d.ts +1 -1
- package/dist/llm/vercel-ai.d.cts +1 -1
- package/dist/llm/vercel-ai.d.ts +1 -1
- package/dist/registry/index.d.cts +5 -5
- package/dist/registry/index.d.ts +5 -5
- package/dist/{registry-JUcN_xWK.d.ts → registry-C4GcH583.d.ts} +1 -1
- package/dist/{registry-B6SiTaLZ.d.cts → registry-DWIY3bMP.d.cts} +1 -1
- package/dist/registry.cjs +123 -6
- package/dist/registry.cjs.map +1 -1
- package/dist/registry.js +2 -2
- package/dist/{run-cohort-rgT_FX3V.d.ts → run-cohort-DAfhZm-p.d.ts} +2 -2
- package/dist/{run-cohort-DNpPa0mq.d.cts → run-cohort-DRJvUWO9.d.cts} +2 -2
- package/dist/{run-flow-pW0PllaZ.d.cts → run-flow-Bdrn4lQV.d.cts} +1 -1
- package/dist/{run-flow-BLP9rXfO.d.ts → run-flow-D2iOjWsj.d.ts} +1 -1
- package/dist/runtime/index.d.cts +5 -5
- package/dist/runtime/index.d.ts +5 -5
- package/dist/runtime.cjs +123 -6
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +3 -3
- package/dist/schema/index.d.cts +1 -1
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema.cjs +123 -6
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.js +3 -3
- package/dist/screens.cjs +123 -6
- package/dist/screens.cjs.map +1 -1
- package/dist/screens.d.cts +2 -2
- package/dist/screens.d.ts +2 -2
- package/dist/screens.js +4 -4
- package/dist/terminal/fancy-term-host.d.cts +1 -1
- package/dist/terminal/fancy-term-host.d.ts +1 -1
- package/dist/{types-BdkXxjFh.d.cts → types-B1jftRa9.d.cts} +1 -1
- package/dist/{types-CbekKMMO.d.ts → types-D5SBBpbe.d.ts} +1 -1
- package/dist/{types-B-Syk9-M.d.ts → types-E48Dpesq.d.cts} +20 -0
- package/dist/{types-B-Syk9-M.d.cts → types-E48Dpesq.d.ts} +20 -0
- package/dist/ux.cjs +123 -6
- package/dist/ux.cjs.map +1 -1
- package/dist/ux.d.cts +2 -2
- package/dist/ux.d.ts +2 -2
- package/dist/ux.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-EEIWAIXW.js.map +0 -1
package/dist/durable.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getNodeKind, runFlow, resolveKindId, kindIds, pauseForHuman, truthy, RunIdentity, decodePause, undeliveredEdgeWarnings } from './chunk-
|
|
1
|
+
import { getNodeKind, runFlow, resolveKindId, kindIds, pauseForHuman, truthy, RunIdentity, decodePause, undeliveredEdgeWarnings } from './chunk-OZHBAXMA.js';
|
|
2
2
|
import './chunk-2QXKDLGT.js';
|
|
3
3
|
|
|
4
4
|
// src/durable/state.ts
|
package/dist/engine.cjs
CHANGED
|
@@ -439,6 +439,7 @@ var branchExecutor = (ctx) => {
|
|
|
439
439
|
const inputs = ctx.inputs;
|
|
440
440
|
let taken;
|
|
441
441
|
const raw = config.condition;
|
|
442
|
+
validateRoutingExpression(ctx, raw, "branch", "condition");
|
|
442
443
|
if (typeof raw === "string" && raw.trim() !== "") {
|
|
443
444
|
taken = truthy(resolve(raw, inputs));
|
|
444
445
|
warnIfUnresolved(ctx, raw, taken ? "true" : "false");
|
|
@@ -493,14 +494,102 @@ var mergeExecutor = (ctx) => {
|
|
|
493
494
|
}
|
|
494
495
|
return merged;
|
|
495
496
|
};
|
|
496
|
-
var
|
|
497
|
-
|
|
497
|
+
var FOR_EACH_DEFAULT_MAX_ITEMS = 1e3;
|
|
498
|
+
var FOR_EACH_HARD_MAX_ITEMS = 1e4;
|
|
499
|
+
function reachable(adjacency, starts) {
|
|
500
|
+
const seen = /* @__PURE__ */ new Set();
|
|
501
|
+
const queue = [...starts];
|
|
502
|
+
for (let cursor = 0; cursor < queue.length; cursor += 1) {
|
|
503
|
+
const id = queue[cursor];
|
|
504
|
+
if (seen.has(id)) continue;
|
|
505
|
+
seen.add(id);
|
|
506
|
+
for (const target of adjacency.get(id) ?? []) queue.push(target);
|
|
507
|
+
}
|
|
508
|
+
return seen;
|
|
509
|
+
}
|
|
510
|
+
function forEachLane(graph, nodeId) {
|
|
511
|
+
const handleOf = (edge) => edge.sourceHandle ?? "out";
|
|
512
|
+
const itemEdges = graph.edges.filter((e) => e.source === nodeId && handleOf(e) === "item");
|
|
513
|
+
if (itemEdges.length === 0) return null;
|
|
514
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
515
|
+
for (const edge of graph.edges) {
|
|
516
|
+
const list = adjacency.get(edge.source) ?? [];
|
|
517
|
+
list.push(edge.target);
|
|
518
|
+
adjacency.set(edge.source, list);
|
|
519
|
+
}
|
|
520
|
+
const done = reachable(
|
|
521
|
+
adjacency,
|
|
522
|
+
graph.edges.filter((e) => e.source === nodeId && handleOf(e) === "done").map((e) => e.target)
|
|
523
|
+
);
|
|
524
|
+
const body = new Set(
|
|
525
|
+
[...reachable(adjacency, itemEdges.map((e) => e.target))].filter(
|
|
526
|
+
(id) => !done.has(id) && id !== nodeId
|
|
527
|
+
)
|
|
528
|
+
);
|
|
529
|
+
return {
|
|
530
|
+
graph: {
|
|
531
|
+
nodes: graph.nodes.filter((n) => body.has(n.id)),
|
|
532
|
+
edges: graph.edges.filter((e) => body.has(e.source) && body.has(e.target)),
|
|
533
|
+
...graph.inputs === void 0 ? {} : { inputs: graph.inputs }
|
|
534
|
+
},
|
|
535
|
+
entries: itemEdges.filter((e) => body.has(e.target))
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
var forEachExecutor = async (ctx) => {
|
|
539
|
+
const config = configOf(ctx.node);
|
|
540
|
+
const source = resolve(config.source, ctx.inputs);
|
|
498
541
|
let items;
|
|
499
542
|
if (Array.isArray(source)) items = source;
|
|
500
543
|
else if (source === null || source === void 0) items = [];
|
|
501
544
|
else if (typeof source === "object") items = Object.values(source);
|
|
502
545
|
else items = [source];
|
|
503
|
-
|
|
546
|
+
const lane = ctx.graph ? forEachLane(ctx.graph, ctx.node.id) : null;
|
|
547
|
+
if (lane === null || config.mode === "collect") {
|
|
548
|
+
return { items, count: items.length };
|
|
549
|
+
}
|
|
550
|
+
if (lane.graph.nodes.length === 0) {
|
|
551
|
+
ctx.abort(`for_each "${ctx.node.id}" has an item edge but its derived lane is empty`);
|
|
552
|
+
}
|
|
553
|
+
const maxItems = Number(config.maxItems ?? FOR_EACH_DEFAULT_MAX_ITEMS);
|
|
554
|
+
if (!Number.isFinite(maxItems) || maxItems < 1 || maxItems > FOR_EACH_HARD_MAX_ITEMS) {
|
|
555
|
+
ctx.abort(`for_each "${ctx.node.id}" maxItems must be between 1 and ${FOR_EACH_HARD_MAX_ITEMS}`);
|
|
556
|
+
}
|
|
557
|
+
if (items.length > maxItems) {
|
|
558
|
+
ctx.abort(
|
|
559
|
+
`for_each "${ctx.node.id}" resolved ${items.length} items exceeds its maxItems cap of ${maxItems}`
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
const results = [];
|
|
563
|
+
const failures = [];
|
|
564
|
+
for (const [index, item] of items.entries()) {
|
|
565
|
+
const initialInputs = {};
|
|
566
|
+
for (const edge of lane.entries) {
|
|
567
|
+
initialInputs[edge.target] = {
|
|
568
|
+
...initialInputs[edge.target] ?? {},
|
|
569
|
+
[edge.targetHandle ?? "in"]: item
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
const nested = await runFlow(lane.graph, { ...ctx.executors ?? {} }, () => {
|
|
573
|
+
}, {
|
|
574
|
+
initialInputs,
|
|
575
|
+
depth: (ctx.depth ?? 0) + 1,
|
|
576
|
+
// The index rides on the identity, so a node in iteration 3 cannot share
|
|
577
|
+
// an idempotency key with the same node in iteration 4.
|
|
578
|
+
run: ctx.run?.descend(ctx.node.id, index)
|
|
579
|
+
});
|
|
580
|
+
if (!nested.ok) {
|
|
581
|
+
const reason = nested.error ?? "unknown error";
|
|
582
|
+
if (decodePause(reason)) ctx.abort(reason);
|
|
583
|
+
results.push(null);
|
|
584
|
+
failures.push({ index, item, error: reason });
|
|
585
|
+
continue;
|
|
586
|
+
}
|
|
587
|
+
results.push(nested.outputs);
|
|
588
|
+
}
|
|
589
|
+
return {
|
|
590
|
+
__port: "done",
|
|
591
|
+
value: { items, results, failures, count: items.length }
|
|
592
|
+
};
|
|
504
593
|
};
|
|
505
594
|
var manualTriggerExecutor = (ctx) => ctx.inputs;
|
|
506
595
|
var outputExecutor = (ctx) => {
|
|
@@ -520,6 +609,7 @@ var switchCaseExecutor = (ctx) => {
|
|
|
520
609
|
const config = configOf(ctx.node);
|
|
521
610
|
const inputs = ctx.inputs;
|
|
522
611
|
const expression = config.value;
|
|
612
|
+
validateRoutingExpression(ctx, expression, "switch_case", "value");
|
|
523
613
|
const value = text(resolve(expression, inputs));
|
|
524
614
|
const cases = config.cases ?? {};
|
|
525
615
|
const matched = Object.prototype.hasOwnProperty.call(cases, value);
|
|
@@ -527,6 +617,21 @@ var switchCaseExecutor = (ctx) => {
|
|
|
527
617
|
warnIfUnresolved(ctx, expression, port, "value");
|
|
528
618
|
return { __port: port, value: inputs.in ?? inputs };
|
|
529
619
|
};
|
|
620
|
+
function validateRoutingExpression(ctx, value, kind, field) {
|
|
621
|
+
if (typeof value !== "string" || value.trim() === "") return;
|
|
622
|
+
const bare = value.trim();
|
|
623
|
+
const subject = `${kind} "${ctx.node.id}" ${field} "${bare}"`;
|
|
624
|
+
if (!value.includes("{{")) {
|
|
625
|
+
ctx.abort(`${subject} is not an expression -- wrap it: {{ ${bare} }}`);
|
|
626
|
+
}
|
|
627
|
+
let open = 0;
|
|
628
|
+
for (const [delimiter] of value.matchAll(/\{\{|\}\}/g)) {
|
|
629
|
+
open = delimiter === "{{" ? open + 1 : Math.max(0, open - 1);
|
|
630
|
+
}
|
|
631
|
+
if (open > 0) {
|
|
632
|
+
ctx.abort(`${subject} has an unclosed expression -- close every {{ with }}`);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
530
635
|
|
|
531
636
|
// src/registry/terminal-nodes.ts
|
|
532
637
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
@@ -1018,7 +1123,7 @@ var KINDS = [
|
|
|
1018
1123
|
key: "condition",
|
|
1019
1124
|
label: "Raw expression (advanced)",
|
|
1020
1125
|
example: "{{ $json.active && $json.score > 10 }}",
|
|
1021
|
-
description: "Escape hatch for logic the builder can't express. Overrides the conditions above when set."
|
|
1126
|
+
description: "Escape hatch for logic the builder can't express. Overrides the conditions above when set. String values must be {{ }}-wrapped expressions; bare strings and unclosed templates abort the run."
|
|
1022
1127
|
}
|
|
1023
1128
|
]
|
|
1024
1129
|
},
|
|
@@ -1038,7 +1143,7 @@ var KINDS = [
|
|
|
1038
1143
|
// moves the ports on the canvas and the ports the runtime activates.
|
|
1039
1144
|
outputs: (config) => casePorts(config?.cases),
|
|
1040
1145
|
configSchema: [
|
|
1041
|
-
{ type: "expression", key: "value", label: "Switch on", example: "{{ $json.kind }}", required: true },
|
|
1146
|
+
{ type: "expression", key: "value", label: "Switch on", description: "String values must be {{ }}-wrapped expressions; bare strings and unclosed templates abort the run.", example: "{{ $json.kind }}", required: true },
|
|
1042
1147
|
{
|
|
1043
1148
|
type: "keyvalue",
|
|
1044
1149
|
key: "cases",
|
|
@@ -1057,6 +1162,15 @@ var KINDS = [
|
|
|
1057
1162
|
name: "@particle-academy/for_each",
|
|
1058
1163
|
outputShape: [
|
|
1059
1164
|
{ path: "items", type: "array" },
|
|
1165
|
+
// `results` and `failures` are the WIRED shape -- what a lane produces
|
|
1166
|
+
// when the `item` port is connected. Declared unconditionally because a
|
|
1167
|
+
// declaration describes the kind, not one graph's use of it, and because
|
|
1168
|
+
// the shared table requires them: fancy-conformance 0.30.0 added
|
|
1169
|
+
// `results` and 0.31.0 added `failures`, both BREAKING, both so that a
|
|
1170
|
+
// runtime which has not implemented iteration fails here rather than
|
|
1171
|
+
// reporting surface parity it does not have.
|
|
1172
|
+
{ path: "results", type: "array" },
|
|
1173
|
+
{ path: "failures", type: "array" },
|
|
1060
1174
|
{ path: "count", type: "number" }
|
|
1061
1175
|
],
|
|
1062
1176
|
aliases: ["for_each", "@fancy/for_each"],
|
|
@@ -1065,7 +1179,7 @@ var KINDS = [
|
|
|
1065
1179
|
executor: forEachExecutor,
|
|
1066
1180
|
category: "logic",
|
|
1067
1181
|
label: "For Each",
|
|
1068
|
-
description: "
|
|
1182
|
+
description: "Wire `item` to a lane and it runs once per item, aggregating `results` and `failures` on `done`. Leave `item` unwired (or set `mode: collect`) and it just publishes the list and its size -- one node, one checkpoint.",
|
|
1069
1183
|
icon: "\u21BB",
|
|
1070
1184
|
inputs: [{ id: "in" }],
|
|
1071
1185
|
outputs: [{ id: "item", label: "item" }, { id: "done", label: "done" }],
|
|
@@ -2631,6 +2745,9 @@ async function runFlow(graph, executors, onEvent = () => {
|
|
|
2631
2745
|
executors,
|
|
2632
2746
|
depth,
|
|
2633
2747
|
run,
|
|
2748
|
+
// Structural executors derive a nested lane from the graph they are
|
|
2749
|
+
// in; `for_each`'s `item` port cannot be implemented without it.
|
|
2750
|
+
graph,
|
|
2634
2751
|
terminal: terminalAccessorFor(node)
|
|
2635
2752
|
})
|
|
2636
2753
|
);
|