@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/screens.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { F as FlowNodeStatus, a as FlowViewer, b as FlowViewerClassNames, c as FlowViewerProps } from './FlowViewer-
|
|
1
|
+
export { F as FlowNodeStatus, a as FlowViewer, b as FlowViewerClassNames, c as FlowViewerProps } from './FlowViewer-BqYQl2vS.cjs';
|
|
2
2
|
import 'react';
|
|
3
|
-
import './types-
|
|
3
|
+
import './types-E48Dpesq.cjs';
|
|
4
4
|
import '@xyflow/react';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/screens.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { F as FlowNodeStatus, a as FlowViewer, b as FlowViewerClassNames, c as FlowViewerProps } from './FlowViewer-
|
|
1
|
+
export { F as FlowNodeStatus, a as FlowViewer, b as FlowViewerClassNames, c as FlowViewerProps } from './FlowViewer-_Fq8AX9V.js';
|
|
2
2
|
import 'react';
|
|
3
|
-
import './types-
|
|
3
|
+
import './types-E48Dpesq.js';
|
|
4
4
|
import '@xyflow/react';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/screens.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { FlowViewer } from './chunk-
|
|
2
|
-
export { FlowViewer } from './chunk-
|
|
3
|
-
import './chunk-
|
|
1
|
+
import { FlowViewer } from './chunk-J66LOLJR.js';
|
|
2
|
+
export { FlowViewer } from './chunk-J66LOLJR.js';
|
|
3
|
+
import './chunk-I5EPWHNM.js';
|
|
4
4
|
import './chunk-F5RPRB7A.js';
|
|
5
5
|
import './chunk-OWENS2H5.js';
|
|
6
|
-
import './chunk-
|
|
6
|
+
import './chunk-OZHBAXMA.js';
|
|
7
7
|
import './chunk-2QXKDLGT.js';
|
|
8
8
|
import { registerSchemaComponents } from '@particle-academy/fancy-screens';
|
|
9
9
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode, ComponentType } from 'react';
|
|
2
|
-
import { F as FlowGraph, a as FlowNode, P as PortDescriptor, N as NodeExecutor } from './types-
|
|
2
|
+
import { F as FlowGraph, a as FlowNode, P as PortDescriptor, N as NodeExecutor } from './types-E48Dpesq.cjs';
|
|
3
3
|
import { NodeProps } from '@xyflow/react';
|
|
4
4
|
import { P as PauseAwaiting } from './pause-9iT4tCEV.cjs';
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode, ComponentType } from 'react';
|
|
2
|
-
import { F as FlowGraph, a as FlowNode, P as PortDescriptor, N as NodeExecutor } from './types-
|
|
2
|
+
import { F as FlowGraph, a as FlowNode, P as PortDescriptor, N as NodeExecutor } from './types-E48Dpesq.js';
|
|
3
3
|
import { NodeProps } from '@xyflow/react';
|
|
4
4
|
import { P as PauseAwaiting } from './pause-9iT4tCEV.js';
|
|
5
5
|
|
|
@@ -538,6 +538,26 @@ type NodeExecutor<TIn = Record<string, unknown>, TOut = unknown> = (ctx: {
|
|
|
538
538
|
* invent a key. See `RunIdentity`.
|
|
539
539
|
*/
|
|
540
540
|
run?: RunIdentity;
|
|
541
|
+
/**
|
|
542
|
+
* The graph this node belongs to.
|
|
543
|
+
*
|
|
544
|
+
* A STRUCTURAL executor needs it: `for_each`'s `item` port fans out over a
|
|
545
|
+
* lane derived from the graph — the nodes reachable from `item`, stopping
|
|
546
|
+
* at anything also reachable from `done` — and that lane cannot be computed
|
|
547
|
+
* from `node` and `inputs` alone.
|
|
548
|
+
*
|
|
549
|
+
* Without it the `item` port was accepted by the schema, drawn by the
|
|
550
|
+
* editor, and silently ignored at run time on this runtime: downstream
|
|
551
|
+
* nodes ran ONCE against the whole collection instead of once per item,
|
|
552
|
+
* with no error. The PHP twin derives the same lane from `$ctx->graph` and
|
|
553
|
+
* has since 0.6; parity was measured against a reference graph where the
|
|
554
|
+
* two disagreed.
|
|
555
|
+
*
|
|
556
|
+
* Optional, because a host may construct a context by hand. An executor
|
|
557
|
+
* that needs it must degrade rather than throw — `for_each` falls back to
|
|
558
|
+
* publishing the collection, which is what it did everywhere before.
|
|
559
|
+
*/
|
|
560
|
+
graph?: FlowGraph;
|
|
541
561
|
/**
|
|
542
562
|
* The terminal this node's lane owns, if it is inside a terminal lane.
|
|
543
563
|
*
|
|
@@ -538,6 +538,26 @@ type NodeExecutor<TIn = Record<string, unknown>, TOut = unknown> = (ctx: {
|
|
|
538
538
|
* invent a key. See `RunIdentity`.
|
|
539
539
|
*/
|
|
540
540
|
run?: RunIdentity;
|
|
541
|
+
/**
|
|
542
|
+
* The graph this node belongs to.
|
|
543
|
+
*
|
|
544
|
+
* A STRUCTURAL executor needs it: `for_each`'s `item` port fans out over a
|
|
545
|
+
* lane derived from the graph — the nodes reachable from `item`, stopping
|
|
546
|
+
* at anything also reachable from `done` — and that lane cannot be computed
|
|
547
|
+
* from `node` and `inputs` alone.
|
|
548
|
+
*
|
|
549
|
+
* Without it the `item` port was accepted by the schema, drawn by the
|
|
550
|
+
* editor, and silently ignored at run time on this runtime: downstream
|
|
551
|
+
* nodes ran ONCE against the whole collection instead of once per item,
|
|
552
|
+
* with no error. The PHP twin derives the same lane from `$ctx->graph` and
|
|
553
|
+
* has since 0.6; parity was measured against a reference graph where the
|
|
554
|
+
* two disagreed.
|
|
555
|
+
*
|
|
556
|
+
* Optional, because a host may construct a context by hand. An executor
|
|
557
|
+
* that needs it must degrade rather than throw — `for_each` falls back to
|
|
558
|
+
* publishing the collection, which is what it did everywhere before.
|
|
559
|
+
*/
|
|
560
|
+
graph?: FlowGraph;
|
|
541
561
|
/**
|
|
542
562
|
* The terminal this node's lane owns, if it is inside a terminal lane.
|
|
543
563
|
*
|
package/dist/ux.cjs
CHANGED
|
@@ -729,6 +729,9 @@ async function runFlow(graph, executors, onEvent = () => {
|
|
|
729
729
|
executors,
|
|
730
730
|
depth,
|
|
731
731
|
run,
|
|
732
|
+
// Structural executors derive a nested lane from the graph they are
|
|
733
|
+
// in; `for_each`'s `item` port cannot be implemented without it.
|
|
734
|
+
graph,
|
|
732
735
|
terminal: terminalAccessorFor(node)
|
|
733
736
|
})
|
|
734
737
|
);
|
|
@@ -1163,6 +1166,7 @@ var branchExecutor = (ctx) => {
|
|
|
1163
1166
|
const inputs = ctx.inputs;
|
|
1164
1167
|
let taken;
|
|
1165
1168
|
const raw = config.condition;
|
|
1169
|
+
validateRoutingExpression(ctx, raw, "branch", "condition");
|
|
1166
1170
|
if (typeof raw === "string" && raw.trim() !== "") {
|
|
1167
1171
|
taken = truthy(resolve(raw, inputs));
|
|
1168
1172
|
warnIfUnresolved(ctx, raw, taken ? "true" : "false");
|
|
@@ -1217,14 +1221,102 @@ var mergeExecutor = (ctx) => {
|
|
|
1217
1221
|
}
|
|
1218
1222
|
return merged;
|
|
1219
1223
|
};
|
|
1220
|
-
var
|
|
1221
|
-
|
|
1224
|
+
var FOR_EACH_DEFAULT_MAX_ITEMS = 1e3;
|
|
1225
|
+
var FOR_EACH_HARD_MAX_ITEMS = 1e4;
|
|
1226
|
+
function reachable(adjacency, starts) {
|
|
1227
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1228
|
+
const queue = [...starts];
|
|
1229
|
+
for (let cursor = 0; cursor < queue.length; cursor += 1) {
|
|
1230
|
+
const id = queue[cursor];
|
|
1231
|
+
if (seen.has(id)) continue;
|
|
1232
|
+
seen.add(id);
|
|
1233
|
+
for (const target of adjacency.get(id) ?? []) queue.push(target);
|
|
1234
|
+
}
|
|
1235
|
+
return seen;
|
|
1236
|
+
}
|
|
1237
|
+
function forEachLane(graph, nodeId) {
|
|
1238
|
+
const handleOf = (edge) => edge.sourceHandle ?? "out";
|
|
1239
|
+
const itemEdges = graph.edges.filter((e) => e.source === nodeId && handleOf(e) === "item");
|
|
1240
|
+
if (itemEdges.length === 0) return null;
|
|
1241
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
1242
|
+
for (const edge of graph.edges) {
|
|
1243
|
+
const list = adjacency.get(edge.source) ?? [];
|
|
1244
|
+
list.push(edge.target);
|
|
1245
|
+
adjacency.set(edge.source, list);
|
|
1246
|
+
}
|
|
1247
|
+
const done = reachable(
|
|
1248
|
+
adjacency,
|
|
1249
|
+
graph.edges.filter((e) => e.source === nodeId && handleOf(e) === "done").map((e) => e.target)
|
|
1250
|
+
);
|
|
1251
|
+
const body = new Set(
|
|
1252
|
+
[...reachable(adjacency, itemEdges.map((e) => e.target))].filter(
|
|
1253
|
+
(id) => !done.has(id) && id !== nodeId
|
|
1254
|
+
)
|
|
1255
|
+
);
|
|
1256
|
+
return {
|
|
1257
|
+
graph: {
|
|
1258
|
+
nodes: graph.nodes.filter((n) => body.has(n.id)),
|
|
1259
|
+
edges: graph.edges.filter((e) => body.has(e.source) && body.has(e.target)),
|
|
1260
|
+
...graph.inputs === void 0 ? {} : { inputs: graph.inputs }
|
|
1261
|
+
},
|
|
1262
|
+
entries: itemEdges.filter((e) => body.has(e.target))
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
var forEachExecutor = async (ctx) => {
|
|
1266
|
+
const config = configOf(ctx.node);
|
|
1267
|
+
const source = resolve(config.source, ctx.inputs);
|
|
1222
1268
|
let items;
|
|
1223
1269
|
if (Array.isArray(source)) items = source;
|
|
1224
1270
|
else if (source === null || source === void 0) items = [];
|
|
1225
1271
|
else if (typeof source === "object") items = Object.values(source);
|
|
1226
1272
|
else items = [source];
|
|
1227
|
-
|
|
1273
|
+
const lane = ctx.graph ? forEachLane(ctx.graph, ctx.node.id) : null;
|
|
1274
|
+
if (lane === null || config.mode === "collect") {
|
|
1275
|
+
return { items, count: items.length };
|
|
1276
|
+
}
|
|
1277
|
+
if (lane.graph.nodes.length === 0) {
|
|
1278
|
+
ctx.abort(`for_each "${ctx.node.id}" has an item edge but its derived lane is empty`);
|
|
1279
|
+
}
|
|
1280
|
+
const maxItems = Number(config.maxItems ?? FOR_EACH_DEFAULT_MAX_ITEMS);
|
|
1281
|
+
if (!Number.isFinite(maxItems) || maxItems < 1 || maxItems > FOR_EACH_HARD_MAX_ITEMS) {
|
|
1282
|
+
ctx.abort(`for_each "${ctx.node.id}" maxItems must be between 1 and ${FOR_EACH_HARD_MAX_ITEMS}`);
|
|
1283
|
+
}
|
|
1284
|
+
if (items.length > maxItems) {
|
|
1285
|
+
ctx.abort(
|
|
1286
|
+
`for_each "${ctx.node.id}" resolved ${items.length} items exceeds its maxItems cap of ${maxItems}`
|
|
1287
|
+
);
|
|
1288
|
+
}
|
|
1289
|
+
const results = [];
|
|
1290
|
+
const failures = [];
|
|
1291
|
+
for (const [index, item] of items.entries()) {
|
|
1292
|
+
const initialInputs = {};
|
|
1293
|
+
for (const edge of lane.entries) {
|
|
1294
|
+
initialInputs[edge.target] = {
|
|
1295
|
+
...initialInputs[edge.target] ?? {},
|
|
1296
|
+
[edge.targetHandle ?? "in"]: item
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
const nested = await runFlow(lane.graph, { ...ctx.executors ?? {} }, () => {
|
|
1300
|
+
}, {
|
|
1301
|
+
initialInputs,
|
|
1302
|
+
depth: (ctx.depth ?? 0) + 1,
|
|
1303
|
+
// The index rides on the identity, so a node in iteration 3 cannot share
|
|
1304
|
+
// an idempotency key with the same node in iteration 4.
|
|
1305
|
+
run: ctx.run?.descend(ctx.node.id, index)
|
|
1306
|
+
});
|
|
1307
|
+
if (!nested.ok) {
|
|
1308
|
+
const reason = nested.error ?? "unknown error";
|
|
1309
|
+
if (decodePause(reason)) ctx.abort(reason);
|
|
1310
|
+
results.push(null);
|
|
1311
|
+
failures.push({ index, item, error: reason });
|
|
1312
|
+
continue;
|
|
1313
|
+
}
|
|
1314
|
+
results.push(nested.outputs);
|
|
1315
|
+
}
|
|
1316
|
+
return {
|
|
1317
|
+
__port: "done",
|
|
1318
|
+
value: { items, results, failures, count: items.length }
|
|
1319
|
+
};
|
|
1228
1320
|
};
|
|
1229
1321
|
var manualTriggerExecutor = (ctx) => ctx.inputs;
|
|
1230
1322
|
var outputExecutor = (ctx) => {
|
|
@@ -1244,6 +1336,7 @@ var switchCaseExecutor = (ctx) => {
|
|
|
1244
1336
|
const config = configOf(ctx.node);
|
|
1245
1337
|
const inputs = ctx.inputs;
|
|
1246
1338
|
const expression = config.value;
|
|
1339
|
+
validateRoutingExpression(ctx, expression, "switch_case", "value");
|
|
1247
1340
|
const value = text(resolve(expression, inputs));
|
|
1248
1341
|
const cases = config.cases ?? {};
|
|
1249
1342
|
const matched = Object.prototype.hasOwnProperty.call(cases, value);
|
|
@@ -1251,6 +1344,21 @@ var switchCaseExecutor = (ctx) => {
|
|
|
1251
1344
|
warnIfUnresolved(ctx, expression, port, "value");
|
|
1252
1345
|
return { __port: port, value: inputs.in ?? inputs };
|
|
1253
1346
|
};
|
|
1347
|
+
function validateRoutingExpression(ctx, value, kind, field) {
|
|
1348
|
+
if (typeof value !== "string" || value.trim() === "") return;
|
|
1349
|
+
const bare = value.trim();
|
|
1350
|
+
const subject = `${kind} "${ctx.node.id}" ${field} "${bare}"`;
|
|
1351
|
+
if (!value.includes("{{")) {
|
|
1352
|
+
ctx.abort(`${subject} is not an expression -- wrap it: {{ ${bare} }}`);
|
|
1353
|
+
}
|
|
1354
|
+
let open = 0;
|
|
1355
|
+
for (const [delimiter] of value.matchAll(/\{\{|\}\}/g)) {
|
|
1356
|
+
open = delimiter === "{{" ? open + 1 : Math.max(0, open - 1);
|
|
1357
|
+
}
|
|
1358
|
+
if (open > 0) {
|
|
1359
|
+
ctx.abort(`${subject} has an unclosed expression -- close every {{ with }}`);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1254
1362
|
|
|
1255
1363
|
// src/registry/terminal-nodes.ts
|
|
1256
1364
|
var DEFAULT_TIMEOUT_MS = 12e4;
|
|
@@ -1742,7 +1850,7 @@ var KINDS = [
|
|
|
1742
1850
|
key: "condition",
|
|
1743
1851
|
label: "Raw expression (advanced)",
|
|
1744
1852
|
example: "{{ $json.active && $json.score > 10 }}",
|
|
1745
|
-
description: "Escape hatch for logic the builder can't express. Overrides the conditions above when set."
|
|
1853
|
+
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."
|
|
1746
1854
|
}
|
|
1747
1855
|
]
|
|
1748
1856
|
},
|
|
@@ -1762,7 +1870,7 @@ var KINDS = [
|
|
|
1762
1870
|
// moves the ports on the canvas and the ports the runtime activates.
|
|
1763
1871
|
outputs: (config) => casePorts(config?.cases),
|
|
1764
1872
|
configSchema: [
|
|
1765
|
-
{ type: "expression", key: "value", label: "Switch on", example: "{{ $json.kind }}", required: true },
|
|
1873
|
+
{ 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 },
|
|
1766
1874
|
{
|
|
1767
1875
|
type: "keyvalue",
|
|
1768
1876
|
key: "cases",
|
|
@@ -1781,6 +1889,15 @@ var KINDS = [
|
|
|
1781
1889
|
name: "@particle-academy/for_each",
|
|
1782
1890
|
outputShape: [
|
|
1783
1891
|
{ path: "items", type: "array" },
|
|
1892
|
+
// `results` and `failures` are the WIRED shape -- what a lane produces
|
|
1893
|
+
// when the `item` port is connected. Declared unconditionally because a
|
|
1894
|
+
// declaration describes the kind, not one graph's use of it, and because
|
|
1895
|
+
// the shared table requires them: fancy-conformance 0.30.0 added
|
|
1896
|
+
// `results` and 0.31.0 added `failures`, both BREAKING, both so that a
|
|
1897
|
+
// runtime which has not implemented iteration fails here rather than
|
|
1898
|
+
// reporting surface parity it does not have.
|
|
1899
|
+
{ path: "results", type: "array" },
|
|
1900
|
+
{ path: "failures", type: "array" },
|
|
1784
1901
|
{ path: "count", type: "number" }
|
|
1785
1902
|
],
|
|
1786
1903
|
aliases: ["for_each", "@fancy/for_each"],
|
|
@@ -1789,7 +1906,7 @@ var KINDS = [
|
|
|
1789
1906
|
executor: forEachExecutor,
|
|
1790
1907
|
category: "logic",
|
|
1791
1908
|
label: "For Each",
|
|
1792
|
-
description: "
|
|
1909
|
+
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.",
|
|
1793
1910
|
icon: "\u21BB",
|
|
1794
1911
|
inputs: [{ id: "in" }],
|
|
1795
1912
|
outputs: [{ id: "item", label: "item" }, { id: "done", label: "done" }],
|