@particle-academy/fancy-flow 0.45.0 → 0.46.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/{ConfigFieldRenderer-Dzy4f6rG.d.cts → ConfigFieldRenderer-Cyir8-B8.d.cts} +2 -2
- package/dist/{ConfigFieldRenderer-WqJr-td_.d.ts → ConfigFieldRenderer-iMkZj0VK.d.ts} +2 -2
- package/dist/{FlowViewer-BbbUJe2b.d.cts → FlowViewer-CY3_vHSg.d.cts} +1 -1
- package/dist/{FlowViewer-csuaTL5t.d.ts → FlowViewer-DGW6t-80.d.ts} +1 -1
- package/dist/{capabilities-Brn74URS.d.ts → capabilities-DMUhnyZD.d.ts} +1 -1
- package/dist/{capabilities-CYCeIx6I.d.cts → capabilities-Dmd26aAs.d.cts} +1 -1
- package/dist/chunk-BHM5HGXH.js +79 -0
- package/dist/chunk-BHM5HGXH.js.map +1 -0
- package/dist/{chunk-DHUFUDEX.js → chunk-HFUBVT7W.js} +3 -3
- package/dist/{chunk-DHUFUDEX.js.map → chunk-HFUBVT7W.js.map} +1 -1
- package/dist/{chunk-VLATLVGH.js → chunk-L43CWD63.js} +129 -5
- package/dist/chunk-L43CWD63.js.map +1 -0
- package/dist/{chunk-A6RFLGWV.js → chunk-MH4ZW4DJ.js} +3 -3
- package/dist/{chunk-A6RFLGWV.js.map → chunk-MH4ZW4DJ.js.map} +1 -1
- package/dist/{chunk-QZTGV3ZL.js → chunk-P5SYH6M6.js} +3 -3
- package/dist/{chunk-QZTGV3ZL.js.map → chunk-P5SYH6M6.js.map} +1 -1
- package/dist/{chunk-WBXGZVLB.js → chunk-RMU6YCIQ.js} +11 -5
- package/dist/chunk-RMU6YCIQ.js.map +1 -0
- package/dist/durable/index.d.cts +490 -0
- package/dist/durable/index.d.ts +490 -0
- package/dist/durable.cjs +927 -0
- package/dist/durable.cjs.map +1 -0
- package/dist/durable.js +552 -0
- package/dist/durable.js.map +1 -0
- package/dist/engine.cjs +128 -2
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.cts +9 -7
- package/dist/engine.d.ts +9 -7
- package/dist/engine.js +4 -4
- package/dist/fields/react-fancy.d.cts +4 -3
- package/dist/fields/react-fancy.d.ts +4 -3
- package/dist/index.cjs +133 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -10
- package/dist/index.d.ts +12 -10
- package/dist/index.js +13 -88
- package/dist/index.js.map +1 -1
- package/dist/layout/index.d.cts +1 -1
- package/dist/layout/index.d.ts +1 -1
- package/dist/llm/prism.d.cts +2 -2
- package/dist/llm/prism.d.ts +2 -2
- package/dist/llm/vercel-ai.d.cts +2 -2
- package/dist/llm/vercel-ai.d.ts +2 -2
- package/dist/pause-9iT4tCEV.d.cts +96 -0
- package/dist/pause-9iT4tCEV.d.ts +96 -0
- package/dist/registry/index.d.cts +7 -6
- package/dist/registry/index.d.ts +7 -6
- package/dist/{registry-Budds73w.d.cts → registry-D_kyUZEf.d.cts} +1 -1
- package/dist/{registry-D0I20HJ3.d.ts → registry-LHB3MlR9.d.ts} +1 -1
- package/dist/registry.cjs +133 -3
- package/dist/registry.cjs.map +1 -1
- package/dist/registry.js +4 -4
- package/dist/{run-cohort-CV7EcwGG.d.ts → run-cohort-Cyeny2Uu.d.ts} +3 -34
- package/dist/{run-cohort-DitsaYgS.d.cts → run-cohort-DdPPowJ3.d.cts} +3 -34
- package/dist/run-flow-1KiXhy59.d.cts +55 -0
- package/dist/run-flow-CQvTDBYk.d.ts +55 -0
- package/dist/runtime/index.d.cts +5 -3
- package/dist/runtime/index.d.ts +5 -3
- package/dist/runtime.cjs +128 -2
- 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/screens.d.cts +2 -2
- package/dist/screens.d.ts +2 -2
- package/dist/screens.js +6 -6
- package/dist/{types-D6ZSKBly.d.ts → types--S2Kzx7w.d.cts} +3 -97
- package/dist/{types-nQOA8jpk.d.cts → types-ChkCRonF.d.ts} +3 -97
- package/dist/types-Jx1TwehV.d.cts +247 -0
- package/dist/types-Jx1TwehV.d.ts +247 -0
- package/dist/ux.d.cts +3 -2
- package/dist/ux.d.ts +3 -2
- package/package.json +12 -2
- package/dist/chunk-VLATLVGH.js.map +0 -1
- package/dist/chunk-WBXGZVLB.js.map +0 -1
- package/dist/types-CMSrWVYM.d.cts +0 -109
- package/dist/types-CMSrWVYM.d.ts +0 -109
package/dist/registry.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export { ANY_PORT_TYPE, BUILTIN_KINDS, DEFAULT_MAX_DEPTH, RegistryNode, buildNodeTypes, createConnectionValidator, declaredRoutes, defaultPortCompatibility, llmRouterExecutor as llmBranchExecutor, llmRouterExecutor, registerBuiltinKinds, resolveFallbackPort, subflowExecutor, subflowMode, subflowPorts } from './chunk-
|
|
1
|
+
export { ANY_PORT_TYPE, BUILTIN_KINDS, DEFAULT_MAX_DEPTH, RegistryNode, buildNodeTypes, createConnectionValidator, declaredRoutes, defaultPortCompatibility, llmRouterExecutor as llmBranchExecutor, llmRouterExecutor, registerBuiltinKinds, resolveFallbackPort, subflowExecutor, subflowMode, subflowPorts } from './chunk-RMU6YCIQ.js';
|
|
2
|
+
export { RichInputPreview, getRichInputAdapter, isRichInputEnabled, onRichInputAdapterChanged, registerRichInputAdapter } from './chunk-F5RPRB7A.js';
|
|
2
3
|
import './chunk-OWENS2H5.js';
|
|
3
|
-
export { LEGACY_PAUSE_PREFIXES, PAUSE_PREFIX, decodePause, encodePause, isPause, pauseForHuman } from './chunk-UEOE6B52.js';
|
|
4
4
|
export { capabilityStatus, getLlmClient, getWorkflowResolver, isResolutionFailure, registerLlmClient, registerWorkflowResolver } from './chunk-USL4FMFU.js';
|
|
5
|
-
|
|
5
|
+
export { LEGACY_PAUSE_PREFIXES, PAUSE_PREFIX, decodePause, encodePause, isPause, pauseForHuman } from './chunk-UEOE6B52.js';
|
|
6
|
+
import './chunk-L43CWD63.js';
|
|
6
7
|
export { nodeConfig, resolveNodePorts, resolvePortSpec } from './chunk-TITD5W4Y.js';
|
|
7
8
|
export { categoryAccent, clearNodeKindOverrides, defaultConfigFor, getNodeKind, kindIds, listNodeKinds, onNodeKindsChanged, overrideNodeKind, registerNodeKind, resolveKindId, validateConfig } from './chunk-PVROYW7C.js';
|
|
8
|
-
export { RichInputPreview, getRichInputAdapter, isRichInputEnabled, onRichInputAdapterChanged, registerRichInputAdapter } from './chunk-F5RPRB7A.js';
|
|
9
9
|
//# sourceMappingURL=registry.js.map
|
|
10
10
|
//# sourceMappingURL=registry.js.map
|
|
@@ -1,36 +1,5 @@
|
|
|
1
|
-
import { F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-
|
|
2
|
-
|
|
3
|
-
type RunOptions = {
|
|
4
|
-
/** Stop the run after this many ms. Default: no timeout. */
|
|
5
|
-
timeoutMs?: number;
|
|
6
|
-
/** Abort signal — host can cancel the run. */
|
|
7
|
-
signal?: AbortSignal;
|
|
8
|
-
/** Initial inputs supplied to entry-point nodes (no incoming edges). */
|
|
9
|
-
initialInputs?: Record<string, Record<string, unknown>>;
|
|
10
|
-
/** Nesting depth — set by `subflow` when it runs a child graph. */
|
|
11
|
-
depth?: number;
|
|
12
|
-
};
|
|
13
|
-
type RunResult = {
|
|
14
|
-
ok: boolean;
|
|
15
|
-
/** Outputs collected per node, keyed by node id. */
|
|
16
|
-
outputs: Record<string, unknown>;
|
|
17
|
-
/** Error captured if any node threw. */
|
|
18
|
-
error?: string;
|
|
19
|
-
};
|
|
20
|
-
/**
|
|
21
|
-
* runFlow — topological execution of a FlowGraph against an ExecutorRegistry.
|
|
22
|
-
*
|
|
23
|
-
* Each node runs once, when all upstream nodes have produced outputs on the
|
|
24
|
-
* connected ports. Decision nodes (or any executor that returns `{ branch:
|
|
25
|
-
* 'true' }`) can short-circuit specific output ports — only edges leaving
|
|
26
|
-
* an "active" port propagate to downstream nodes.
|
|
27
|
-
*
|
|
28
|
-
* Cycles are detected and abort the run with an error.
|
|
29
|
-
*
|
|
30
|
-
* The `onEvent` callback receives a stream of `RunEvent`s — wire it to a
|
|
31
|
-
* status feed, log panel, or store.
|
|
32
|
-
*/
|
|
33
|
-
declare function runFlow(graph: FlowGraph, executors: ExecutorRegistry, onEvent?: (event: RunEvent) => void, options?: RunOptions): Promise<RunResult>;
|
|
1
|
+
import { F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-Jx1TwehV.js';
|
|
2
|
+
import { R as RunOptions, a as RunResult } from './run-flow-CQvTDBYk.js';
|
|
34
3
|
|
|
35
4
|
/**
|
|
36
5
|
* How the flows one trigger fired should treat each other.
|
|
@@ -108,4 +77,4 @@ type CohortResult = RunResult & {
|
|
|
108
77
|
*/
|
|
109
78
|
declare function runCohort(flows: FlowGraph[], executors: ExecutorRegistry, onEvent?: (event: RunEvent, index: number) => void, options?: CohortOptions): Promise<CohortResult[]>;
|
|
110
79
|
|
|
111
|
-
export { type CohortGuard as C, type
|
|
80
|
+
export { type CohortGuard as C, type CohortOptions as a, type CohortPolicy as b, type CohortResult as c, runCohort as r };
|
|
@@ -1,36 +1,5 @@
|
|
|
1
|
-
import { F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-
|
|
2
|
-
|
|
3
|
-
type RunOptions = {
|
|
4
|
-
/** Stop the run after this many ms. Default: no timeout. */
|
|
5
|
-
timeoutMs?: number;
|
|
6
|
-
/** Abort signal — host can cancel the run. */
|
|
7
|
-
signal?: AbortSignal;
|
|
8
|
-
/** Initial inputs supplied to entry-point nodes (no incoming edges). */
|
|
9
|
-
initialInputs?: Record<string, Record<string, unknown>>;
|
|
10
|
-
/** Nesting depth — set by `subflow` when it runs a child graph. */
|
|
11
|
-
depth?: number;
|
|
12
|
-
};
|
|
13
|
-
type RunResult = {
|
|
14
|
-
ok: boolean;
|
|
15
|
-
/** Outputs collected per node, keyed by node id. */
|
|
16
|
-
outputs: Record<string, unknown>;
|
|
17
|
-
/** Error captured if any node threw. */
|
|
18
|
-
error?: string;
|
|
19
|
-
};
|
|
20
|
-
/**
|
|
21
|
-
* runFlow — topological execution of a FlowGraph against an ExecutorRegistry.
|
|
22
|
-
*
|
|
23
|
-
* Each node runs once, when all upstream nodes have produced outputs on the
|
|
24
|
-
* connected ports. Decision nodes (or any executor that returns `{ branch:
|
|
25
|
-
* 'true' }`) can short-circuit specific output ports — only edges leaving
|
|
26
|
-
* an "active" port propagate to downstream nodes.
|
|
27
|
-
*
|
|
28
|
-
* Cycles are detected and abort the run with an error.
|
|
29
|
-
*
|
|
30
|
-
* The `onEvent` callback receives a stream of `RunEvent`s — wire it to a
|
|
31
|
-
* status feed, log panel, or store.
|
|
32
|
-
*/
|
|
33
|
-
declare function runFlow(graph: FlowGraph, executors: ExecutorRegistry, onEvent?: (event: RunEvent) => void, options?: RunOptions): Promise<RunResult>;
|
|
1
|
+
import { F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-Jx1TwehV.cjs';
|
|
2
|
+
import { R as RunOptions, a as RunResult } from './run-flow-1KiXhy59.cjs';
|
|
34
3
|
|
|
35
4
|
/**
|
|
36
5
|
* How the flows one trigger fired should treat each other.
|
|
@@ -108,4 +77,4 @@ type CohortResult = RunResult & {
|
|
|
108
77
|
*/
|
|
109
78
|
declare function runCohort(flows: FlowGraph[], executors: ExecutorRegistry, onEvent?: (event: RunEvent, index: number) => void, options?: CohortOptions): Promise<CohortResult[]>;
|
|
110
79
|
|
|
111
|
-
export { type CohortGuard as C, type
|
|
80
|
+
export { type CohortGuard as C, type CohortOptions as a, type CohortPolicy as b, type CohortResult as c, runCohort as r };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { b as RunIdentity, c as RunIdentityJson, F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-Jx1TwehV.cjs';
|
|
2
|
+
|
|
3
|
+
type RunOptions = {
|
|
4
|
+
/** Stop the run after this many ms. Default: no timeout. */
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
/** Abort signal — host can cancel the run. */
|
|
7
|
+
signal?: AbortSignal;
|
|
8
|
+
/** Initial inputs supplied to entry-point nodes (no incoming edges). */
|
|
9
|
+
initialInputs?: Record<string, Record<string, unknown>>;
|
|
10
|
+
/** Nesting depth — set by `subflow` when it runs a child graph. */
|
|
11
|
+
depth?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Who is running, so a writing node can derive a stable idempotency key.
|
|
14
|
+
*
|
|
15
|
+
* A bare string is taken as the run key. **Deliberately not defaulted:** a
|
|
16
|
+
* minted-per-call key would change on every whole-run retry, which is exactly
|
|
17
|
+
* the failure an idempotency key exists to prevent — so a host that has not
|
|
18
|
+
* supplied one gets `ctx.run === undefined` and a connector that declines to
|
|
19
|
+
* write blind, rather than a plausible-looking key that double-charges.
|
|
20
|
+
*/
|
|
21
|
+
run?: RunIdentity | RunIdentityJson | string;
|
|
22
|
+
/**
|
|
23
|
+
* Outputs already checkpointed for this run, keyed by node id.
|
|
24
|
+
*
|
|
25
|
+
* A node present here is **republished, not re-executed** — its stored value
|
|
26
|
+
* goes back onto the same ports, so downstream routing reproduces exactly
|
|
27
|
+
* what it did the first time. This is what makes a per-node durable driver
|
|
28
|
+
* possible without a second copy of the routing rules, and it is how the PHP
|
|
29
|
+
* and Python runtimes have always resumed.
|
|
30
|
+
*/
|
|
31
|
+
resumeOutputs?: Record<string, unknown>;
|
|
32
|
+
};
|
|
33
|
+
type RunResult = {
|
|
34
|
+
ok: boolean;
|
|
35
|
+
/** Outputs collected per node, keyed by node id. */
|
|
36
|
+
outputs: Record<string, unknown>;
|
|
37
|
+
/** Error captured if any node threw. */
|
|
38
|
+
error?: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* runFlow — topological execution of a FlowGraph against an ExecutorRegistry.
|
|
42
|
+
*
|
|
43
|
+
* Each node runs once, when all upstream nodes have produced outputs on the
|
|
44
|
+
* connected ports. Decision nodes (or any executor that returns `{ branch:
|
|
45
|
+
* 'true' }`) can short-circuit specific output ports — only edges leaving
|
|
46
|
+
* an "active" port propagate to downstream nodes.
|
|
47
|
+
*
|
|
48
|
+
* Cycles are detected and abort the run with an error.
|
|
49
|
+
*
|
|
50
|
+
* The `onEvent` callback receives a stream of `RunEvent`s — wire it to a
|
|
51
|
+
* status feed, log panel, or store.
|
|
52
|
+
*/
|
|
53
|
+
declare function runFlow(graph: FlowGraph, executors: ExecutorRegistry, onEvent?: (event: RunEvent) => void, options?: RunOptions): Promise<RunResult>;
|
|
54
|
+
|
|
55
|
+
export { type RunOptions as R, type RunResult as a, runFlow as r };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { b as RunIdentity, c as RunIdentityJson, F as FlowGraph, E as ExecutorRegistry, R as RunEvent } from './types-Jx1TwehV.js';
|
|
2
|
+
|
|
3
|
+
type RunOptions = {
|
|
4
|
+
/** Stop the run after this many ms. Default: no timeout. */
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
/** Abort signal — host can cancel the run. */
|
|
7
|
+
signal?: AbortSignal;
|
|
8
|
+
/** Initial inputs supplied to entry-point nodes (no incoming edges). */
|
|
9
|
+
initialInputs?: Record<string, Record<string, unknown>>;
|
|
10
|
+
/** Nesting depth — set by `subflow` when it runs a child graph. */
|
|
11
|
+
depth?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Who is running, so a writing node can derive a stable idempotency key.
|
|
14
|
+
*
|
|
15
|
+
* A bare string is taken as the run key. **Deliberately not defaulted:** a
|
|
16
|
+
* minted-per-call key would change on every whole-run retry, which is exactly
|
|
17
|
+
* the failure an idempotency key exists to prevent — so a host that has not
|
|
18
|
+
* supplied one gets `ctx.run === undefined` and a connector that declines to
|
|
19
|
+
* write blind, rather than a plausible-looking key that double-charges.
|
|
20
|
+
*/
|
|
21
|
+
run?: RunIdentity | RunIdentityJson | string;
|
|
22
|
+
/**
|
|
23
|
+
* Outputs already checkpointed for this run, keyed by node id.
|
|
24
|
+
*
|
|
25
|
+
* A node present here is **republished, not re-executed** — its stored value
|
|
26
|
+
* goes back onto the same ports, so downstream routing reproduces exactly
|
|
27
|
+
* what it did the first time. This is what makes a per-node durable driver
|
|
28
|
+
* possible without a second copy of the routing rules, and it is how the PHP
|
|
29
|
+
* and Python runtimes have always resumed.
|
|
30
|
+
*/
|
|
31
|
+
resumeOutputs?: Record<string, unknown>;
|
|
32
|
+
};
|
|
33
|
+
type RunResult = {
|
|
34
|
+
ok: boolean;
|
|
35
|
+
/** Outputs collected per node, keyed by node id. */
|
|
36
|
+
outputs: Record<string, unknown>;
|
|
37
|
+
/** Error captured if any node threw. */
|
|
38
|
+
error?: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* runFlow — topological execution of a FlowGraph against an ExecutorRegistry.
|
|
42
|
+
*
|
|
43
|
+
* Each node runs once, when all upstream nodes have produced outputs on the
|
|
44
|
+
* connected ports. Decision nodes (or any executor that returns `{ branch:
|
|
45
|
+
* 'true' }`) can short-circuit specific output ports — only edges leaving
|
|
46
|
+
* an "active" port propagate to downstream nodes.
|
|
47
|
+
*
|
|
48
|
+
* Cycles are detected and abort the run with an error.
|
|
49
|
+
*
|
|
50
|
+
* The `onEvent` callback receives a stream of `RunEvent`s — wire it to a
|
|
51
|
+
* status feed, log panel, or store.
|
|
52
|
+
*/
|
|
53
|
+
declare function runFlow(graph: FlowGraph, executors: ExecutorRegistry, onEvent?: (event: RunEvent) => void, options?: RunOptions): Promise<RunResult>;
|
|
54
|
+
|
|
55
|
+
export { type RunOptions as R, type RunResult as a, runFlow as r };
|
package/dist/runtime/index.d.cts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
import {
|
|
1
|
+
import { a as RunResult, R as RunOptions } from '../run-flow-1KiXhy59.cjs';
|
|
2
|
+
export { r as runFlow } from '../run-flow-1KiXhy59.cjs';
|
|
3
|
+
import { g as NodeRunStatus, F as FlowGraph, E as ExecutorRegistry, a as FlowNode, d as FlowEdge } from '../types-Jx1TwehV.cjs';
|
|
4
|
+
export { b as RunIdentity, c as RunIdentityJson, i as escapeSegment } from '../types-Jx1TwehV.cjs';
|
|
5
|
+
export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, r as runCohort } from '../run-cohort-DdPPowJ3.cjs';
|
|
4
6
|
import { NodeChange, EdgeChange, Connection } from '@xyflow/react';
|
|
5
7
|
|
|
6
8
|
type FlowRunFeedEntry = {
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
3
|
-
import {
|
|
1
|
+
import { a as RunResult, R as RunOptions } from '../run-flow-CQvTDBYk.js';
|
|
2
|
+
export { r as runFlow } from '../run-flow-CQvTDBYk.js';
|
|
3
|
+
import { g as NodeRunStatus, F as FlowGraph, E as ExecutorRegistry, a as FlowNode, d as FlowEdge } from '../types-Jx1TwehV.js';
|
|
4
|
+
export { b as RunIdentity, c as RunIdentityJson, i as escapeSegment } from '../types-Jx1TwehV.js';
|
|
5
|
+
export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, r as runCohort } from '../run-cohort-Cyeny2Uu.js';
|
|
4
6
|
import { NodeChange, EdgeChange, Connection } from '@xyflow/react';
|
|
5
7
|
|
|
6
8
|
type FlowRunFeedEntry = {
|
package/dist/runtime.cjs
CHANGED
|
@@ -53,10 +53,121 @@ function resolveNodePorts(node, kind) {
|
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
// src/runtime/run-identity.ts
|
|
57
|
+
function escapeSegment(value) {
|
|
58
|
+
return value.replace(/%/g, "%25").replace(/\//g, "%2F").replace(/#/g, "%23");
|
|
59
|
+
}
|
|
60
|
+
function renderSegment(value, occurrence) {
|
|
61
|
+
const escaped = escapeSegment(value);
|
|
62
|
+
return occurrence === void 0 || occurrence === null ? escaped : `${escaped}#${occurrence}`;
|
|
63
|
+
}
|
|
64
|
+
function instant(value) {
|
|
65
|
+
const ms = Date.parse(value);
|
|
66
|
+
if (Number.isNaN(ms)) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`RunIdentity: firstAttemptAt is not a parseable timestamp: ${JSON.stringify(value)}`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return ms;
|
|
72
|
+
}
|
|
73
|
+
var RunIdentity = class _RunIdentity {
|
|
74
|
+
constructor(runKey, path = [], attempt = 1, firstAttemptAt = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
75
|
+
if (!runKey || runKey.trim() === "") {
|
|
76
|
+
throw new Error("RunIdentity: runKey must be a non-empty string.");
|
|
77
|
+
}
|
|
78
|
+
this.runKey = runKey;
|
|
79
|
+
this.path = Object.freeze([...path]);
|
|
80
|
+
this.attempt = Math.max(1, Math.trunc(attempt));
|
|
81
|
+
this.firstAttemptAt = firstAttemptAt;
|
|
82
|
+
Object.freeze(this);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The identity of one execution of one node — stable across retries of that
|
|
86
|
+
* execution, distinct from every other execution of the same node.
|
|
87
|
+
*
|
|
88
|
+
* Pass `occurrence` when an executor runs the same node more than once at the
|
|
89
|
+
* same level (a loop body, one item of a fan-out it drives itself).
|
|
90
|
+
*/
|
|
91
|
+
stepKey(nodeId, occurrence) {
|
|
92
|
+
return `${this.runKey}:${[...this.path, renderSegment(nodeId, occurrence)].join("/")}`;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* A child identity for work nested inside this step.
|
|
96
|
+
*
|
|
97
|
+
* `subflow` pushes the invoking node's id, so a node inside the child graph
|
|
98
|
+
* cannot collide with a same-named node in the parent. Attempt and
|
|
99
|
+
* `firstAttemptAt` are carried down unchanged: the nested work happens inside
|
|
100
|
+
* this step's attempt, and shares its clock.
|
|
101
|
+
*/
|
|
102
|
+
descend(segment, occurrence) {
|
|
103
|
+
return new _RunIdentity(
|
|
104
|
+
this.runKey,
|
|
105
|
+
[...this.path, renderSegment(segment, occurrence)],
|
|
106
|
+
this.attempt,
|
|
107
|
+
this.firstAttemptAt
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
/** A copy on a different attempt, first-attempt clock preserved. */
|
|
111
|
+
withAttempt(attempt, firstAttemptAt) {
|
|
112
|
+
return new _RunIdentity(
|
|
113
|
+
this.runKey,
|
|
114
|
+
this.path,
|
|
115
|
+
attempt,
|
|
116
|
+
firstAttemptAt ?? this.firstAttemptAt
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* May this attempt reuse the step key and still be deduplicated?
|
|
121
|
+
*
|
|
122
|
+
* Providers forget idempotency keys — Stripe after 24 hours. Past that
|
|
123
|
+
* window, resending the key creates a second charge and sending a fresh one
|
|
124
|
+
* creates a second charge, so **the caller must refuse rather than pick
|
|
125
|
+
* between them**: a loud stuck run beats a silent double write.
|
|
126
|
+
*
|
|
127
|
+
* `true` on attempt 1 whatever the elapsed time — nothing was sent on an
|
|
128
|
+
* earlier attempt, so there is nothing for the provider to have forgotten.
|
|
129
|
+
* That is what lets a run park on a human gate for a week and then write.
|
|
130
|
+
*
|
|
131
|
+
* `windowSeconds: null` means the provider does not expire keys. `0` means
|
|
132
|
+
* it does not dedupe at all, so no retry may reuse a key — it is a real
|
|
133
|
+
* window, not an absent one, and the two must not be conflated: reading `0`
|
|
134
|
+
* as `null` turns "this provider does not dedupe" into "this provider
|
|
135
|
+
* dedupes forever", which is the more dangerous of the two by a distance.
|
|
136
|
+
*/
|
|
137
|
+
isReplaySafe(windowSeconds, now2 = /* @__PURE__ */ new Date()) {
|
|
138
|
+
if (this.attempt <= 1) return true;
|
|
139
|
+
if (windowSeconds === null || windowSeconds === void 0) return true;
|
|
140
|
+
if (windowSeconds <= 0) return false;
|
|
141
|
+
const nowMs = typeof now2 === "string" ? instant(now2) : now2.getTime();
|
|
142
|
+
const elapsedSeconds = Math.max(0, (nowMs - instant(this.firstAttemptAt)) / 1e3);
|
|
143
|
+
return elapsedSeconds <= windowSeconds;
|
|
144
|
+
}
|
|
145
|
+
toJSON() {
|
|
146
|
+
return {
|
|
147
|
+
runKey: this.runKey,
|
|
148
|
+
path: [...this.path],
|
|
149
|
+
attempt: this.attempt,
|
|
150
|
+
firstAttemptAt: this.firstAttemptAt
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/** Rebuild from a queue payload. */
|
|
154
|
+
static from(value) {
|
|
155
|
+
if (value instanceof _RunIdentity) return value;
|
|
156
|
+
if (typeof value === "string") return new _RunIdentity(value);
|
|
157
|
+
return new _RunIdentity(
|
|
158
|
+
value.runKey,
|
|
159
|
+
value.path ?? [],
|
|
160
|
+
value.attempt ?? 1,
|
|
161
|
+
value.firstAttemptAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
56
166
|
// src/runtime/run-flow.ts
|
|
57
167
|
async function runFlow(graph, executors, onEvent = () => {
|
|
58
168
|
}, options = {}) {
|
|
59
|
-
const { signal, initialInputs = {}, timeoutMs, depth = 0 } = options;
|
|
169
|
+
const { signal, initialInputs = {}, timeoutMs, depth = 0, resumeOutputs = {} } = options;
|
|
170
|
+
const run = options.run === void 0 ? void 0 : RunIdentity.from(options.run);
|
|
60
171
|
const outputs = {};
|
|
61
172
|
const portValues = /* @__PURE__ */ new Map();
|
|
62
173
|
const completed = /* @__PURE__ */ new Set();
|
|
@@ -74,6 +185,18 @@ async function runFlow(graph, executors, onEvent = () => {
|
|
|
74
185
|
for (const node of order) {
|
|
75
186
|
if (signal?.aborted) throw new Error("aborted");
|
|
76
187
|
if (errors.length) break;
|
|
188
|
+
if (Object.prototype.hasOwnProperty.call(resumeOutputs, node.id)) {
|
|
189
|
+
const stored = resumeOutputs[node.id];
|
|
190
|
+
outputs[node.id] = stored;
|
|
191
|
+
const activated = activatedPorts(node, stored);
|
|
192
|
+
for (const portId of activated.ports) {
|
|
193
|
+
portValues.set(`${node.id}:${portId}`, activated.value);
|
|
194
|
+
onEvent({ type: "node-output", nodeId: node.id, portId, value: activated.value });
|
|
195
|
+
}
|
|
196
|
+
completed.add(node.id);
|
|
197
|
+
onEvent({ type: "node-status", nodeId: node.id, status: "done", text: "resumed" });
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
77
200
|
const incoming = incomingByNode.get(node.id) ?? [];
|
|
78
201
|
if (incoming.length > 0) {
|
|
79
202
|
const anyActive = incoming.some((e) => portValues.has(`${e.source}:${e.sourceHandle ?? "out"}`));
|
|
@@ -113,7 +236,8 @@ async function runFlow(graph, executors, onEvent = () => {
|
|
|
113
236
|
throw new Error(reason ?? "aborted");
|
|
114
237
|
},
|
|
115
238
|
emit: onEvent,
|
|
116
|
-
depth
|
|
239
|
+
depth,
|
|
240
|
+
run
|
|
117
241
|
})
|
|
118
242
|
);
|
|
119
243
|
outputs[node.id] = result;
|
|
@@ -9378,9 +9502,11 @@ function useFlowHistory(flow) {
|
|
|
9378
9502
|
};
|
|
9379
9503
|
}
|
|
9380
9504
|
|
|
9505
|
+
exports.RunIdentity = RunIdentity;
|
|
9381
9506
|
exports.applyOutputsToNodes = applyOutputsToNodes;
|
|
9382
9507
|
exports.applyStatusesToNodes = applyStatusesToNodes;
|
|
9383
9508
|
exports.createHistory = createHistory;
|
|
9509
|
+
exports.escapeSegment = escapeSegment;
|
|
9384
9510
|
exports.runCohort = runCohort;
|
|
9385
9511
|
exports.runFlow = runFlow;
|
|
9386
9512
|
exports.useFlowHistory = useFlowHistory;
|