@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.
Files changed (77) hide show
  1. package/dist/{ConfigFieldRenderer-Dzy4f6rG.d.cts → ConfigFieldRenderer-Cyir8-B8.d.cts} +2 -2
  2. package/dist/{ConfigFieldRenderer-WqJr-td_.d.ts → ConfigFieldRenderer-iMkZj0VK.d.ts} +2 -2
  3. package/dist/{FlowViewer-BbbUJe2b.d.cts → FlowViewer-CY3_vHSg.d.cts} +1 -1
  4. package/dist/{FlowViewer-csuaTL5t.d.ts → FlowViewer-DGW6t-80.d.ts} +1 -1
  5. package/dist/{capabilities-Brn74URS.d.ts → capabilities-DMUhnyZD.d.ts} +1 -1
  6. package/dist/{capabilities-CYCeIx6I.d.cts → capabilities-Dmd26aAs.d.cts} +1 -1
  7. package/dist/chunk-BHM5HGXH.js +79 -0
  8. package/dist/chunk-BHM5HGXH.js.map +1 -0
  9. package/dist/{chunk-DHUFUDEX.js → chunk-HFUBVT7W.js} +3 -3
  10. package/dist/{chunk-DHUFUDEX.js.map → chunk-HFUBVT7W.js.map} +1 -1
  11. package/dist/{chunk-VLATLVGH.js → chunk-L43CWD63.js} +129 -5
  12. package/dist/chunk-L43CWD63.js.map +1 -0
  13. package/dist/{chunk-A6RFLGWV.js → chunk-MH4ZW4DJ.js} +3 -3
  14. package/dist/{chunk-A6RFLGWV.js.map → chunk-MH4ZW4DJ.js.map} +1 -1
  15. package/dist/{chunk-QZTGV3ZL.js → chunk-P5SYH6M6.js} +3 -3
  16. package/dist/{chunk-QZTGV3ZL.js.map → chunk-P5SYH6M6.js.map} +1 -1
  17. package/dist/{chunk-WBXGZVLB.js → chunk-RMU6YCIQ.js} +11 -5
  18. package/dist/chunk-RMU6YCIQ.js.map +1 -0
  19. package/dist/durable/index.d.cts +490 -0
  20. package/dist/durable/index.d.ts +490 -0
  21. package/dist/durable.cjs +927 -0
  22. package/dist/durable.cjs.map +1 -0
  23. package/dist/durable.js +552 -0
  24. package/dist/durable.js.map +1 -0
  25. package/dist/engine.cjs +128 -2
  26. package/dist/engine.cjs.map +1 -1
  27. package/dist/engine.d.cts +9 -7
  28. package/dist/engine.d.ts +9 -7
  29. package/dist/engine.js +4 -4
  30. package/dist/fields/react-fancy.d.cts +4 -3
  31. package/dist/fields/react-fancy.d.ts +4 -3
  32. package/dist/index.cjs +133 -3
  33. package/dist/index.cjs.map +1 -1
  34. package/dist/index.d.cts +12 -10
  35. package/dist/index.d.ts +12 -10
  36. package/dist/index.js +13 -88
  37. package/dist/index.js.map +1 -1
  38. package/dist/layout/index.d.cts +1 -1
  39. package/dist/layout/index.d.ts +1 -1
  40. package/dist/llm/prism.d.cts +2 -2
  41. package/dist/llm/prism.d.ts +2 -2
  42. package/dist/llm/vercel-ai.d.cts +2 -2
  43. package/dist/llm/vercel-ai.d.ts +2 -2
  44. package/dist/pause-9iT4tCEV.d.cts +96 -0
  45. package/dist/pause-9iT4tCEV.d.ts +96 -0
  46. package/dist/registry/index.d.cts +7 -6
  47. package/dist/registry/index.d.ts +7 -6
  48. package/dist/{registry-Budds73w.d.cts → registry-D_kyUZEf.d.cts} +1 -1
  49. package/dist/{registry-D0I20HJ3.d.ts → registry-LHB3MlR9.d.ts} +1 -1
  50. package/dist/registry.cjs +133 -3
  51. package/dist/registry.cjs.map +1 -1
  52. package/dist/registry.js +4 -4
  53. package/dist/{run-cohort-CV7EcwGG.d.ts → run-cohort-Cyeny2Uu.d.ts} +3 -34
  54. package/dist/{run-cohort-DitsaYgS.d.cts → run-cohort-DdPPowJ3.d.cts} +3 -34
  55. package/dist/run-flow-1KiXhy59.d.cts +55 -0
  56. package/dist/run-flow-CQvTDBYk.d.ts +55 -0
  57. package/dist/runtime/index.d.cts +5 -3
  58. package/dist/runtime/index.d.ts +5 -3
  59. package/dist/runtime.cjs +128 -2
  60. package/dist/runtime.cjs.map +1 -1
  61. package/dist/runtime.js +3 -3
  62. package/dist/schema/index.d.cts +1 -1
  63. package/dist/schema/index.d.ts +1 -1
  64. package/dist/screens.d.cts +2 -2
  65. package/dist/screens.d.ts +2 -2
  66. package/dist/screens.js +6 -6
  67. package/dist/{types-D6ZSKBly.d.ts → types--S2Kzx7w.d.cts} +3 -97
  68. package/dist/{types-nQOA8jpk.d.cts → types-ChkCRonF.d.ts} +3 -97
  69. package/dist/types-Jx1TwehV.d.cts +247 -0
  70. package/dist/types-Jx1TwehV.d.ts +247 -0
  71. package/dist/ux.d.cts +3 -2
  72. package/dist/ux.d.ts +3 -2
  73. package/package.json +12 -2
  74. package/dist/chunk-VLATLVGH.js.map +0 -1
  75. package/dist/chunk-WBXGZVLB.js.map +0 -1
  76. package/dist/types-CMSrWVYM.d.cts +0 -109
  77. package/dist/types-CMSrWVYM.d.ts +0 -109
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/durable/state.ts","../src/registry/registry.ts","../src/durable/frontier.ts","../src/registry/ports.ts","../src/runtime/run-identity.ts","../src/runtime/run-flow.ts","../src/durable/replay.ts","../src/durable/retry.ts","../src/registry/pause.ts","../src/expressions/expr.ts","../src/durable/human.ts","../src/durable/coordinator.ts"],"names":[],"mappings":"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","file":"durable.cjs","sourcesContent":["/**\n * What a durable run remembers, and the seam a real database plugs into.\n *\n * A durable run is bookkeeping plus one hard requirement: **the claim is a\n * unique constraint, not a check.** Two workers racing for the same node must\n * produce a no-op, not a double run, and only the storage layer can promise\n * that. So {@link NodeClaimStore} is an interface with exactly the operations a\n * driver needs, and an adapter implements it over `INSERT … ON CONFLICT DO\n * NOTHING` (or its dialect's spelling).\n *\n * {@link InMemoryClaimStore} is the reference implementation and is genuinely\n * useful: it makes the whole per-node driver testable, and it is correct for a\n * single-process durable run.\n *\n * This is a port of `fancy_flow.durable.state`, which is itself the Python twin\n * of `fancy-flow-php`'s `NodeClaims` + `workflow_run_nodes`. Three runtimes,\n * one design — see `.ai/plans/fancy-flow-run-identity-and-steps.md`.\n */\n\n/** Where one node of one run has got to. */\nexport const NodeRunStatus = {\n CLAIMED: \"claimed\",\n COMPLETED: \"completed\",\n SKIPPED: \"skipped\",\n FAILED: \"failed\",\n PAUSED: \"paused\",\n} as const;\n\nexport type NodeRunStatusValue = (typeof NodeRunStatus)[keyof typeof NodeRunStatus];\n\n/**\n * A node the frontier may treat as decided.\n *\n * A FAILED node is settled too — it will never publish, so its successors skip\n * rather than wait forever.\n */\nexport const SETTLED: readonly NodeRunStatusValue[] = [\n NodeRunStatus.COMPLETED,\n NodeRunStatus.SKIPPED,\n NodeRunStatus.FAILED,\n];\n\n/**\n * One node's row.\n *\n * `ports` are the ports the engine's own `node-output` events reported. They\n * are STORED, never recomputed: a second copy of the routing table would agree\n * for a year and then disagree on one branch.\n */\nexport type NodeState = {\n status: NodeRunStatusValue;\n ports: readonly string[];\n output?: unknown;\n error?: string | null;\n owner?: string | null;\n /** 1-based, incremented when an owner re-enters its own claim. */\n attempts: number;\n /** ISO-8601 UTC of the FIRST claim. Never updated — it is the retry clock. */\n firstAttemptAt: string;\n};\n\n/**\n * The persistence a per-node driver needs.\n *\n * Six operations. An adapter over Postgres, SQLite or Redis implements these\n * and nothing else; every rule about WHICH node may run lives in `frontier.ts`,\n * which reads only {@link state}.\n */\nexport interface NodeClaimStore {\n /**\n * Take exclusive ownership of one node of one run.\n *\n * MUST be atomic against concurrent callers, and MUST return `true` for a\n * caller re-entering its OWN claim — that is what lets a job's retry resume\n * instead of deadlocking against the row it wrote itself.\n */\n claim(runKey: string, nodeId: string, owner: string): boolean | Promise<boolean>;\n state(runKey: string): Record<string, NodeState> | Promise<Record<string, NodeState>>;\n complete(\n runKey: string,\n nodeId: string,\n output: unknown,\n ports: readonly string[],\n ): void | Promise<void>;\n skip(runKey: string, nodeId: string): void | Promise<void>;\n fail(runKey: string, nodeId: string, error: string): void | Promise<void>;\n pause(runKey: string, nodeId: string, reason: string): void | Promise<void>;\n}\n\n/**\n * A correct, single-process {@link NodeClaimStore}.\n *\n * JavaScript's single-threaded event loop makes the claim atomic for free —\n * there is no interleaving point inside a synchronous method. It is NOT durable\n * across a restart, which is the honest limit: use it for tests, for a CLI run,\n * and for a worker that genuinely owns the whole run.\n */\nexport class InMemoryClaimStore implements NodeClaimStore {\n private readonly runs = new Map<string, Map<string, NodeState>>();\n\n claim(runKey: string, nodeId: string, owner: string): boolean {\n const run = this.run(runKey);\n const existing = run.get(nodeId);\n\n if (!existing) {\n run.set(nodeId, {\n status: NodeRunStatus.CLAIMED,\n ports: [],\n owner,\n attempts: 1,\n firstAttemptAt: new Date().toISOString(),\n });\n return true;\n }\n\n // Re-entering our own claim is how a retry gets back in. Anything else —\n // another owner, or a settled node — is a lost race, and a lost race is a\n // NO-OP rather than a duplicate run.\n const ownClaim =\n (existing.status === NodeRunStatus.CLAIMED || existing.status === NodeRunStatus.PAUSED) &&\n existing.owner === owner;\n\n if (ownClaim) {\n existing.attempts += 1;\n existing.status = NodeRunStatus.CLAIMED;\n return true;\n }\n return false;\n }\n\n state(runKey: string): Record<string, NodeState> {\n const out: Record<string, NodeState> = {};\n for (const [nodeId, entry] of this.run(runKey)) out[nodeId] = { ...entry, ports: [...entry.ports] };\n return out;\n }\n\n complete(runKey: string, nodeId: string, output: unknown, ports: readonly string[]): void {\n const entry = this.entry(runKey, nodeId);\n entry.status = NodeRunStatus.COMPLETED;\n entry.output = output;\n entry.ports = [...ports];\n entry.error = null;\n }\n\n skip(runKey: string, nodeId: string): void {\n const entry = this.entry(runKey, nodeId);\n entry.status = NodeRunStatus.SKIPPED;\n entry.ports = [];\n }\n\n fail(runKey: string, nodeId: string, error: string): void {\n const entry = this.entry(runKey, nodeId);\n entry.status = NodeRunStatus.FAILED;\n entry.error = error;\n entry.ports = [];\n }\n\n pause(runKey: string, nodeId: string, reason: string): void {\n const entry = this.entry(runKey, nodeId);\n entry.status = NodeRunStatus.PAUSED;\n entry.error = reason;\n entry.ports = [];\n }\n\n /**\n * Drop a paused node's claim so a recorded answer can re-run it.\n *\n * Not part of the interface: resuming a human gate is the host's decision and\n * its storage's business. Provided here because the in-memory store is also\n * what the tests resume through.\n */\n release(runKey: string, nodeId: string): void {\n this.run(runKey).delete(nodeId);\n }\n\n private run(runKey: string): Map<string, NodeState> {\n let run = this.runs.get(runKey);\n if (!run) {\n run = new Map();\n this.runs.set(runKey, run);\n }\n return run;\n }\n\n /** The row for one node, created as CLAIMED if a driver never claimed it. */\n private entry(runKey: string, nodeId: string): NodeState {\n const run = this.run(runKey);\n let entry = run.get(nodeId);\n if (!entry) {\n entry = {\n status: NodeRunStatus.CLAIMED,\n ports: [],\n attempts: 1,\n firstAttemptAt: new Date().toISOString(),\n };\n run.set(nodeId, entry);\n }\n return entry;\n }\n}\n\nexport function isSettled(status: string | undefined): boolean {\n return status !== undefined && (SETTLED as readonly string[]).includes(status);\n}\n","import type { ConfigField, NodeKindDefinition } from \"./types\";\n\nconst kinds = new Map<string, NodeKindDefinition<any, any, any>>();\n/** alias → canonical name. See `resolveKindId`. */\nconst aliases = new Map<string, string>();\nconst listeners = new Set<() => void>();\n/**\n * canonical name → presentation patch. See `overrideNodeKind`.\n *\n * Kept SEPARATE from `kinds` on purpose: an override has to survive its base\n * kind being re-registered (HMR, a later `registerBuiltinKinds()`, a package\n * upgrade). Merging into the definition would mean the next registration\n * silently reverts the consumer's naming.\n */\nconst overrides = new Map<string, NodeKindPresentation>();\n\n/**\n * The presentation fields a consumer may override on someone else's node kind.\n *\n * Deliberately excludes everything behavioural — `executor`, `inputs`,\n * `outputs`, `configSchema`, `sideEffects`. An \"override\" that could change\n * those is not an override, it is a fork wearing a friendly name, and it would\n * desync the graph from the runtime that executes it.\n *\n * `category` IS included: which drawer a node appears in is presentation, and a\n * consumer regrouping their palette is the same kind of act as renaming.\n */\nexport type NodeKindPresentation = Partial<\n Pick<NodeKindDefinition, \"label\" | \"description\" | \"icon\" | \"accent\" | \"category\">\n>;\n\n/**\n * registerNodeKind — install a node kind in the global registry. Returns\n * an `unregister` function. Calling with the same name replaces the prior\n * registration (handy for HMR).\n *\n * A kind's `name` is its CANONICAL id and is what gets written into saved\n * documents. Publish namespaced (`@fancy/llm_branch`, `@acme/salesforce_upsert`)\n * and list any previous bare names in `aliases`, so graphs saved before the\n * rename keep resolving.\n */\nexport function registerNodeKind<TC = any, TI = any, TO = any>(\n definition: NodeKindDefinition<TC, TI, TO>,\n): () => void {\n kinds.set(definition.name, definition as NodeKindDefinition<any, any, any>);\n for (const alias of definition.aliases ?? []) aliases.set(alias, definition.name);\n notify();\n return () => {\n if (kinds.get(definition.name) === (definition as any)) {\n kinds.delete(definition.name);\n for (const alias of definition.aliases ?? []) {\n if (aliases.get(alias) === definition.name) aliases.delete(alias);\n }\n notify();\n }\n };\n}\n\n/**\n * Resolve any id — canonical or alias — to the canonical one, or null.\n *\n * `kind` is persisted inside every saved graph, so a bare name that two\n * packages could both claim is unfixable after the fact: the ambiguous string\n * is already in the document. Canonical ids are namespaced; aliases exist so\n * documents written before namespacing keep opening.\n */\nexport function resolveKindId(id: string): string | null {\n if (kinds.has(id)) return id;\n const canonical = aliases.get(id);\n return canonical && kinds.has(canonical) ? canonical : null;\n}\n\n/**\n * Rename or re-describe a kind you did not author.\n *\n * Before this existed the only way to relabel a builtin was `registerNodeKind`\n * with a full definition — which REPLACES the kind, so a consumer wanting\n * \"Call an API\" instead of \"HTTP Request\" had to re-declare that node's\n * configSchema, ports, executor and renderer, and silently forfeited whatever\n * the builtin gained in the next release. In practice nobody renamed a node,\n * and the palette could not be localised at all.\n *\n * ```ts\n * const undo = overrideNodeKind(\"@particle-academy/http_request\", {\n * label: \"Call an API\",\n * description: \"Fetch or post JSON to a URL\",\n * });\n * ```\n *\n * Applies at `getNodeKind()` and `listNodeKinds()`, so one call reaches the\n * palette, the node cards on the canvas, `FlowViewer`, and anything else that\n * reads the registry. Returns an unsubscribe, matching `registerNodeKind`.\n *\n * Patching an unregistered id is allowed and takes effect if that kind is\n * registered later — order of module side effects is not something a consumer\n * should have to reason about.\n */\nexport function overrideNodeKind(name: string, patch: NodeKindPresentation): () => void {\n const canonical = resolveKindId(name) ?? name;\n const previous = overrides.get(canonical);\n\n overrides.set(canonical, { ...previous, ...patch });\n notify();\n\n return () => {\n if (previous) {\n overrides.set(canonical, previous);\n } else {\n overrides.delete(canonical);\n }\n notify();\n };\n}\n\n/** Remove every presentation override. Mostly for tests. */\nexport function clearNodeKindOverrides(): void {\n if (overrides.size === 0) return;\n overrides.clear();\n notify();\n}\n\nfunction withOverride(kind: NodeKindDefinition | undefined): NodeKindDefinition | null {\n if (!kind) return null;\n const patch = overrides.get(kind.name);\n return patch ? ({ ...kind, ...patch } as NodeKindDefinition) : kind;\n}\n\n/** Get a single kind by canonical id or alias, or null. */\nexport function getNodeKind(name: string): NodeKindDefinition | null {\n const canonical = resolveKindId(name);\n return canonical ? withOverride(kinds.get(canonical) as NodeKindDefinition) : null;\n}\n\n/** Every id a kind answers to — canonical first. Used to key node-type maps. */\nexport function kindIds(kind: NodeKindDefinition): string[] {\n return [kind.name, ...(kind.aliases ?? [])];\n}\n\n/** List every registered kind, optionally filtered by category. */\nexport function listNodeKinds(category?: string): NodeKindDefinition[] {\n const all = Array.from(kinds.values()).map((k) =>\n withOverride(k as NodeKindDefinition),\n ) as NodeKindDefinition[];\n // Filter AFTER applying overrides, so an override that moves a node to a\n // different category actually moves it in the palette rather than leaving it\n // filed under the old one with a new name.\n return category ? all.filter((k) => k.category === category) : all;\n}\n\n/** Subscribe to registry changes. Returns an unsubscribe function. */\nexport function onNodeKindsChanged(listener: () => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n\nfunction notify(): void {\n for (const l of listeners) l();\n}\n\n/** Fill in defaults from a kind's configSchema for newly-created nodes. */\nexport function defaultConfigFor(kind: NodeKindDefinition): Record<string, unknown> {\n const fromKind = kind.defaultConfig ? { ...(kind.defaultConfig as Record<string, unknown>) } : {};\n for (const field of kind.configSchema ?? []) {\n if (fromKind[field.key] !== undefined) continue;\n if (\"default\" in field && (field as any).default !== undefined) {\n fromKind[field.key] = (field as any).default;\n }\n }\n return fromKind;\n}\n\n/**\n * Validate a config object against a kind's schema. Returns an array of\n * issues (empty = valid). Validation is intentionally light — type\n * coercion + required-field checks. Hosts can layer Zod / Ajv on top.\n */\nexport function validateConfig(\n kind: NodeKindDefinition,\n config: Record<string, unknown>,\n): Array<{ key: string; message: string }> {\n const issues: Array<{ key: string; message: string }> = [];\n for (const field of kind.configSchema ?? []) {\n const value = config[field.key];\n if (field.required && (value === undefined || value === null || value === \"\")) {\n issues.push({ key: field.key, message: `${field.label} is required` });\n continue;\n }\n if (value === undefined || value === null) continue;\n const issue = validateField(field, value);\n if (issue) issues.push({ key: field.key, message: issue });\n }\n return issues;\n}\n\nfunction validateField(field: ConfigField, value: unknown): string | null {\n switch (field.type) {\n case \"text\":\n case \"textarea\":\n case \"expression\":\n case \"credential\":\n return typeof value === \"string\" ? null : `${field.label} must be a string`;\n case \"number\": {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return `${field.label} must be a number`;\n if (field.min !== undefined && value < field.min) return `${field.label} must be >= ${field.min}`;\n if (field.max !== undefined && value > field.max) return `${field.label} must be <= ${field.max}`;\n return null;\n }\n case \"switch\":\n return typeof value === \"boolean\" ? null : `${field.label} must be a boolean`;\n case \"select\": {\n const allowed = field.options.map((o) => o.value);\n return allowed.includes(String(value)) ? null : `${field.label} must be one of ${allowed.join(\", \")}`;\n }\n case \"json\":\n return null; // permissive — just JSON-shaped\n case \"repeater\": {\n if (!Array.isArray(value)) return `${field.label} must be a list`;\n if (field.minItems !== undefined && value.length < field.minItems) {\n return `${field.label} needs at least ${field.minItems}`;\n }\n if (field.maxItems !== undefined && value.length > field.maxItems) {\n return `${field.label} allows at most ${field.maxItems}`;\n }\n // Surface the first offending row so the author knows WHICH one.\n for (let i = 0; i < value.length; i++) {\n const row = value[i];\n if (!row || typeof row !== \"object\" || Array.isArray(row)) {\n return `${field.label} item ${i + 1} must be an object`;\n }\n for (const sub of field.fields) {\n const cell = (row as Record<string, unknown>)[sub.key];\n if (sub.required && (cell === undefined || cell === null || cell === \"\")) {\n return `${field.label} item ${i + 1}: ${sub.label} is required`;\n }\n if (cell === undefined || cell === null) continue;\n const issue = validateField(sub, cell);\n if (issue) return `${field.label} item ${i + 1}: ${issue}`;\n }\n }\n return null;\n }\n case \"keyvalue\": {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return `${field.label} must be a key/value map`;\n }\n const allowed = field.valueOptions?.map((o) => o.value);\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (typeof v !== \"string\") return `${field.label}: \"${k}\" must be a string`;\n if (allowed && !allowed.includes(v)) {\n return `${field.label}: \"${k}\" must be one of ${allowed.join(\", \")}`;\n }\n }\n return null;\n }\n case \"document\":\n return null; // opaque to fancy-flow — the host's editor owns its shape\n default:\n return null;\n }\n}\n\n/** Default accents per category. */\nexport function categoryAccent(category: string): string {\n switch (category) {\n case \"trigger\": return \"#10b981\";\n case \"logic\": return \"#f59e0b\";\n case \"data\": return \"#0ea5e9\";\n case \"ai\": return \"#8b5cf6\";\n case \"io\": return \"#3b82f6\";\n case \"human\": return \"#ec4899\";\n case \"output\": return \"#a855f7\";\n case \"layout\": return \"#64748b\";\n case \"annotation\": return \"#eab308\";\n default: return \"#71717a\";\n }\n}\n","/**\n * Which nodes can run RIGHT NOW, given what has already settled.\n *\n * ## Why this is not a second engine\n *\n * `runFlow` walks a Kahn topological order and, at each node, runs it when at\n * least one incoming edge is active. That is a total order because one process\n * executes every node. Split the graph across jobs and the same rule has to be\n * asked the other way round — not \"what is next\" but \"what is unblocked\" —\n * which is this module.\n *\n * The rule is the engine's, restated:\n *\n * - every direct predecessor has SETTLED (in topological order the engine has\n * already settled all of them by the time it reaches a node);\n * - and either the node has no incoming edges, or at least one incoming edge is\n * ACTIVE — its source completed and published on that edge's source handle.\n *\n * A node whose predecessors have all settled with no active edge is what the\n * engine reports as `idle/skipped`. Skipping SETTLES it, which can in turn\n * unblock — or skip — its own successors, so the pass repeats until nothing\n * changes. That cascade is how a dead branch collapses without leaving the run\n * stuck.\n *\n * ## The one thing it does NOT decide\n *\n * Which ports a result activated. Those rules (`__port`, `branch`, declared\n * outputs, the kind's ports, the `out` fallback) live in the engine and stay\n * there: this reads the ports back off the `node-output` events the engine\n * emitted when the node ran, stored on the claim row.\n */\n\nimport { getNodeKind, kindIds } from \"../registry/registry\";\nimport type { FlowEdge, FlowGraph } from \"../types\";\nimport { NodeRunStatus, isSettled, type NodeClaimStore, type NodeState } from \"./state\";\n\nexport type FrontierResult = {\n ready: string[];\n skipped: string[];\n};\n\nfunction isNote(type: string | undefined): boolean {\n if (!type) return false;\n if (type === \"note\") return true;\n const kind = getNodeKind(type);\n return kind ? kindIds(kind).includes(\"note\") || kind.category === \"annotation\" : false;\n}\n\nexport const Frontier = {\n compute(graph: FlowGraph, state: Record<string, NodeState>): FrontierResult {\n const incoming = new Map<string, FlowEdge[]>();\n for (const edge of graph.edges) {\n const list = incoming.get(edge.target) ?? [];\n list.push(edge);\n incoming.set(edge.target, list);\n }\n\n // Settled nodes and the ports they lit. A skipped node is settled with NO\n // ports, which is precisely what makes its successors skip too.\n const settled = new Map<string, readonly string[]>();\n const held = new Set<string>();\n for (const [nodeId, entry] of Object.entries(state)) {\n if (entry.status === NodeRunStatus.COMPLETED) settled.set(nodeId, entry.ports);\n else if (isSettled(entry.status)) settled.set(nodeId, []);\n else held.add(nodeId);\n }\n\n const ready: string[] = [];\n const skipped: string[] = [];\n\n let changed = true;\n while (changed) {\n changed = false;\n\n for (const node of graph.nodes) {\n const nodeId = node.id;\n if (settled.has(nodeId) || held.has(nodeId) || ready.includes(nodeId)) continue;\n\n const edges = incoming.get(nodeId) ?? [];\n let blocked = false;\n let active = false;\n\n for (const edge of edges) {\n if (!settled.has(edge.source)) {\n blocked = true;\n break;\n }\n // The engine's port key: an edge with no source handle reads the\n // source's `out` port.\n if (settled.get(edge.source)!.includes(edge.sourceHandle ?? \"out\")) active = true;\n }\n\n if (blocked) continue;\n\n // Reached, but down a branch that never lit.\n if (edges.length > 0 && !active) {\n settled.set(nodeId, []);\n skipped.push(nodeId);\n changed = true;\n continue;\n }\n\n // Annotations and layout are never executed. Settling them here rather\n // than dispatching a job saves a queue round trip per sticky note — and\n // a graph can carry a lot of sticky notes.\n if (isNote(node.type) || getNodeKind(node.type ?? \"\")?.category === \"layout\") {\n settled.set(nodeId, []);\n skipped.push(nodeId);\n changed = true;\n continue;\n }\n\n ready.push(nodeId);\n }\n }\n\n return { ready, skipped };\n },\n\n /** Has every node settled? The run is finished when it has. */\n isComplete(graph: FlowGraph, state: Record<string, NodeState>): boolean {\n return graph.nodes.every((node) => isSettled(state[node.id]?.status));\n },\n\n /**\n * Is any node still held by a worker, or parked for a person?\n *\n * An empty frontier means something different depending on this: with work in\n * flight the run is simply waiting, and whichever job finishes will advance\n * it. With nothing in flight and nodes still unsettled, the graph cannot\n * progress at all — which is a stuck run, and must be reported rather than\n * waited on.\n */\n hasWorkInFlight(state: Record<string, NodeState>): boolean {\n return Object.values(state).some(\n (entry) => entry.status === NodeRunStatus.CLAIMED || entry.status === NodeRunStatus.PAUSED,\n );\n },\n\n /** Persist the skip cascade so the next pass does not recompute it. */\n async settleSkips(\n store: NodeClaimStore,\n runKey: string,\n skipped: readonly string[],\n ): Promise<void> {\n for (const nodeId of skipped) await store.skip(runKey, nodeId);\n },\n};\n","import type { FlowNode, PortDescriptor } from \"../types\";\nimport type { NodeKindDefinition, PortSpec } from \"./types\";\n\n/**\n * Port resolution — the single place a node's ports are derived, shared by\n * the canvas renderer and the headless runtime.\n *\n * This module is deliberately React-free: `runFlow` (the `/engine` entry)\n * imports it, and the engine bundle must stay free of React.\n *\n * ## Why this is centralized\n *\n * Ports used to be read in two places that disagreed — the canvas consulted\n * `data.outputs ?? kind.outputs`, while the runtime consulted `data.outputs`\n * ONLY and fell back to a single `out` port. A kind that declared branch ports\n * therefore drew correctly and then routed as if it had one output, unless the\n * host remembered to mirror the ports onto every node's `data`. Both callers\n * now go through `resolveNodePorts`, so declared ports and executed ports\n * cannot drift apart.\n */\n\n/**\n * Resolve a `PortSpec` against a config object.\n *\n * A config-driven spec is author-supplied and runs on every render, so a throw\n * is contained: it degrades to \"undeclared\" (letting the caller fall back)\n * rather than taking out the canvas or aborting a run mid-flight.\n */\nexport function resolvePortSpec<TConfig>(\n spec: PortSpec<TConfig> | undefined,\n config: TConfig,\n): PortDescriptor[] | undefined {\n if (spec === undefined) return undefined;\n if (typeof spec !== \"function\") return spec;\n try {\n const resolved = (spec as (c: TConfig) => PortDescriptor[])(config);\n return Array.isArray(resolved) ? resolved : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Read the config bag off a node, tolerating the FlowNodeData union. */\nexport function nodeConfig(node: Pick<FlowNode, \"data\">): Record<string, unknown> {\n return ((node.data as any)?.config ?? {}) as Record<string, unknown>;\n}\n\n/**\n * Resolve a node's effective ports.\n *\n * Precedence: explicit `data.inputs`/`data.outputs` (a per-node host override)\n * beats the kind's declaration. `undefined` means \"nothing declared\" — the\n * caller applies its own category default.\n */\nexport function resolveNodePorts(\n node: Pick<FlowNode, \"data\">,\n kind?: Pick<NodeKindDefinition<any>, \"inputs\" | \"outputs\">,\n): { inputs?: PortDescriptor[]; outputs?: PortDescriptor[] } {\n const config = nodeConfig(node);\n const data = node.data as any;\n return {\n inputs: data?.inputs ?? resolvePortSpec(kind?.inputs, config),\n outputs: data?.outputs ?? resolvePortSpec(kind?.outputs, config),\n };\n}\n","/**\n * Who is running, which step this is, and how many times it has been tried.\n *\n * ## Why an engine needs this at all\n *\n * A node that WRITES to somebody else's system — charge a card, send a message,\n * open a pull request — can only survive a retry if the retry carries the same\n * idempotency key the first attempt did. Otherwise the provider treats the\n * second call as a new request and the customer is charged twice.\n *\n * Until this existed the executor context was `{ node, inputs, emit, abort }`,\n * which is not enough to derive one. Both obvious fallbacks are worse than\n * sending no key at all:\n *\n * - **the node id alone** is stable across retries, and also across RUNS — two\n * legitimate payments share a key and the provider silently collapses the\n * second into the first. A payment that never happened, reported as success;\n * - **a fresh random value** is unique per run, and also per ATTEMPT — a retry\n * creates a second charge, which is the thing being avoided.\n *\n * ## What actually identifies a step\n *\n * Not `(run, node)`. A node legitimately executes more than once inside one\n * run: once per subflow invocation, once per iteration of a loop an executor\n * drives itself. `(run, node)` would give every one of those the same key, and\n * a provider would honour exactly one of them.\n *\n * So a step is identified by the **path of invocations that led to it**, plus\n * an optional **occurrence** for repetition at the same level:\n *\n * ```text\n * runKey \":\" segment (\"/\" segment)* segment := escape(id) [\"#\" occurrence]\n * ```\n *\n * And the part that is easy to get backwards: **`attempt` is NOT in the key.**\n * It is carried here for logging and for {@link RunIdentity.isReplaySafe}, and\n * putting it in the key would restore the exact bug the key exists to prevent.\n *\n * Pinned cross-runtime by `shared/flow-run-identity` in\n * `@particle-academy/fancy-conformance`.\n */\n\n/** The wire shape — what a queue job payload carries. */\nexport type RunIdentityJson = {\n runKey: string;\n path?: string[];\n attempt?: number;\n firstAttemptAt?: string;\n};\n\n/**\n * Escape one segment so the composition is injective.\n *\n * `%` FIRST, or the escaping is not reversible: escaping `/` before `%` turns a\n * literal `a%2Fb` into the same text as the escaped form of `a/b`, which is the\n * collision this exists to prevent, reintroduced by its own fix.\n */\nexport function escapeSegment(value: string): string {\n // Not `replaceAll` — the package targets ES2020, and this must produce the\n // identical string on every runtime that reads the conformance table.\n return value.replace(/%/g, \"%25\").replace(/\\//g, \"%2F\").replace(/#/g, \"%23\");\n}\n\nfunction renderSegment(value: string, occurrence?: number | null): string {\n const escaped = escapeSegment(value);\n // `occurrence === 0` is a real occurrence. A truthiness check here silently\n // collapses iteration 0 into the un-iterated key.\n return occurrence === undefined || occurrence === null ? escaped : `${escaped}#${occurrence}`;\n}\n\nfunction instant(value: string): number {\n const ms = Date.parse(value);\n if (Number.isNaN(ms)) {\n throw new Error(\n `RunIdentity: firstAttemptAt is not a parseable timestamp: ${JSON.stringify(value)}`,\n );\n }\n return ms;\n}\n\n/**\n * A run, a position inside it, and how many times this position has been tried.\n *\n * Immutable. {@link descend} returns a new identity rather than mutating, so an\n * executor cannot change what its siblings see.\n */\nexport class RunIdentity {\n /** Stable for the whole run: same across retries, resumes, workers and hosts. */\n readonly runKey: string;\n\n /**\n * Enclosing invocation segments, outermost first, ALREADY RENDERED.\n *\n * Empty at the top level. A subflow pushes the invoking node's id; an\n * executor that loops pushes `id#i`.\n */\n readonly path: readonly string[];\n\n /**\n * 1-based attempt of THIS logical step. Never part of the key.\n *\n * The durable driver sets it from the node's claim row, which is exact. A\n * plain in-process `runFlow` gets whatever the host passed, which is\n * run-scoped and therefore conservative — see `isReplaySafe`.\n */\n readonly attempt: number;\n\n /** ISO-8601 UTC instant of attempt 1 of this step. */\n readonly firstAttemptAt: string;\n\n constructor(\n runKey: string,\n path: readonly string[] = [],\n attempt = 1,\n firstAttemptAt: string = new Date().toISOString(),\n ) {\n if (!runKey || runKey.trim() === \"\") {\n throw new Error(\"RunIdentity: runKey must be a non-empty string.\");\n }\n this.runKey = runKey;\n this.path = Object.freeze([...path]);\n this.attempt = Math.max(1, Math.trunc(attempt));\n this.firstAttemptAt = firstAttemptAt;\n Object.freeze(this);\n }\n\n /**\n * The identity of one execution of one node — stable across retries of that\n * execution, distinct from every other execution of the same node.\n *\n * Pass `occurrence` when an executor runs the same node more than once at the\n * same level (a loop body, one item of a fan-out it drives itself).\n */\n stepKey(nodeId: string, occurrence?: number | null): string {\n return `${this.runKey}:${[...this.path, renderSegment(nodeId, occurrence)].join(\"/\")}`;\n }\n\n /**\n * A child identity for work nested inside this step.\n *\n * `subflow` pushes the invoking node's id, so a node inside the child graph\n * cannot collide with a same-named node in the parent. Attempt and\n * `firstAttemptAt` are carried down unchanged: the nested work happens inside\n * this step's attempt, and shares its clock.\n */\n descend(segment: string, occurrence?: number | null): RunIdentity {\n return new RunIdentity(\n this.runKey,\n [...this.path, renderSegment(segment, occurrence)],\n this.attempt,\n this.firstAttemptAt,\n );\n }\n\n /** A copy on a different attempt, first-attempt clock preserved. */\n withAttempt(attempt: number, firstAttemptAt?: string): RunIdentity {\n return new RunIdentity(\n this.runKey,\n this.path,\n attempt,\n firstAttemptAt ?? this.firstAttemptAt,\n );\n }\n\n /**\n * May this attempt reuse the step key and still be deduplicated?\n *\n * Providers forget idempotency keys — Stripe after 24 hours. Past that\n * window, resending the key creates a second charge and sending a fresh one\n * creates a second charge, so **the caller must refuse rather than pick\n * between them**: a loud stuck run beats a silent double write.\n *\n * `true` on attempt 1 whatever the elapsed time — nothing was sent on an\n * earlier attempt, so there is nothing for the provider to have forgotten.\n * That is what lets a run park on a human gate for a week and then write.\n *\n * `windowSeconds: null` means the provider does not expire keys. `0` means\n * it does not dedupe at all, so no retry may reuse a key — it is a real\n * window, not an absent one, and the two must not be conflated: reading `0`\n * as `null` turns \"this provider does not dedupe\" into \"this provider\n * dedupes forever\", which is the more dangerous of the two by a distance.\n */\n isReplaySafe(windowSeconds: number | null | undefined, now: Date | string = new Date()): boolean {\n if (this.attempt <= 1) return true;\n if (windowSeconds === null || windowSeconds === undefined) return true;\n if (windowSeconds <= 0) return false;\n\n const nowMs = typeof now === \"string\" ? instant(now) : now.getTime();\n // Clock skew between two workers must not turn a legitimate retry into a\n // refusal, so a negative elapsed clamps to zero.\n const elapsedSeconds = Math.max(0, (nowMs - instant(this.firstAttemptAt)) / 1000);\n\n // Inclusive: a key written at T is remembered THROUGH T + window.\n return elapsedSeconds <= windowSeconds;\n }\n\n toJSON(): Required<RunIdentityJson> {\n return {\n runKey: this.runKey,\n path: [...this.path],\n attempt: this.attempt,\n firstAttemptAt: this.firstAttemptAt,\n };\n }\n\n /** Rebuild from a queue payload. */\n static from(value: RunIdentity | RunIdentityJson | string): RunIdentity {\n if (value instanceof RunIdentity) return value;\n if (typeof value === \"string\") return new RunIdentity(value);\n return new RunIdentity(\n value.runKey,\n value.path ?? [],\n value.attempt ?? 1,\n value.firstAttemptAt ?? new Date().toISOString(),\n );\n }\n}\n","import type {\n ExecutorRegistry,\n FlowEdge,\n FlowGraph,\n FlowNode,\n NodeExecutor,\n RunEvent,\n} from \"../types\";\n// Both modules are React-free by design — the `/engine` entry must not pull in\n// React. Import them directly rather than via the `registry` barrel, which\n// re-exports the RegistryNode component.\nimport { getNodeKind, kindIds } from \"../registry/registry\";\nimport { resolveNodePorts } from \"../registry/ports\";\nimport { RunIdentity, type RunIdentityJson } from \"./run-identity\";\n\nexport type RunOptions = {\n /** Stop the run after this many ms. Default: no timeout. */\n timeoutMs?: number;\n /** Abort signal — host can cancel the run. */\n signal?: AbortSignal;\n /** Initial inputs supplied to entry-point nodes (no incoming edges). */\n initialInputs?: Record<string, Record<string, unknown>>;\n /** Nesting depth — set by `subflow` when it runs a child graph. */\n depth?: number;\n /**\n * Who is running, so a writing node can derive a stable idempotency key.\n *\n * A bare string is taken as the run key. **Deliberately not defaulted:** a\n * minted-per-call key would change on every whole-run retry, which is exactly\n * the failure an idempotency key exists to prevent — so a host that has not\n * supplied one gets `ctx.run === undefined` and a connector that declines to\n * write blind, rather than a plausible-looking key that double-charges.\n */\n run?: RunIdentity | RunIdentityJson | string;\n /**\n * Outputs already checkpointed for this run, keyed by node id.\n *\n * A node present here is **republished, not re-executed** — its stored value\n * goes back onto the same ports, so downstream routing reproduces exactly\n * what it did the first time. This is what makes a per-node durable driver\n * possible without a second copy of the routing rules, and it is how the PHP\n * and Python runtimes have always resumed.\n */\n resumeOutputs?: Record<string, unknown>;\n};\n\nexport type RunResult = {\n ok: boolean;\n /** Outputs collected per node, keyed by node id. */\n outputs: Record<string, unknown>;\n /** Error captured if any node threw. */\n error?: string;\n};\n\n/**\n * runFlow — topological execution of a FlowGraph against an ExecutorRegistry.\n *\n * Each node runs once, when all upstream nodes have produced outputs on the\n * connected ports. Decision nodes (or any executor that returns `{ branch:\n * 'true' }`) can short-circuit specific output ports — only edges leaving\n * an \"active\" port propagate to downstream nodes.\n *\n * Cycles are detected and abort the run with an error.\n *\n * The `onEvent` callback receives a stream of `RunEvent`s — wire it to a\n * status feed, log panel, or store.\n */\nexport async function runFlow(\n graph: FlowGraph,\n executors: ExecutorRegistry,\n onEvent: (event: RunEvent) => void = () => {},\n options: RunOptions = {},\n): Promise<RunResult> {\n const { signal, initialInputs = {}, timeoutMs, depth = 0, resumeOutputs = {} } = options;\n const run = options.run === undefined ? undefined : RunIdentity.from(options.run);\n const outputs: Record<string, unknown> = {};\n const portValues = new Map<string, unknown>(); // key: `${nodeId}:${portId}`\n const completed = new Set<string>();\n const errors: string[] = [];\n\n // Topological order via Kahn's algorithm. We allow nodes to run as soon\n // as their incoming edges' source ports have produced values, so the\n // order here is just a deterministic baseline used for cycle detection.\n const order = topoSort(graph);\n if (order === null) {\n const msg = \"Cycle detected in flow graph — aborting.\";\n onEvent({ type: \"run-error\", error: msg });\n return { ok: false, outputs, error: msg };\n }\n\n const incomingByNode = indexIncoming(graph.edges);\n const timer = timeoutMs ? setTimeout(() => errors.push(`Run timed out after ${timeoutMs}ms`), timeoutMs) : null;\n\n onEvent({ type: \"run-start\" });\n\n try {\n for (const node of order) {\n if (signal?.aborted) throw new Error(\"aborted\");\n if (errors.length) break;\n\n // A checkpointed node is republished, never re-executed. Publishing the\n // stored value back onto its own ports is what makes the resume exact:\n // the branch it took, the ports it lit and the inputs its successors\n // collect are all reproduced by the engine's own rules rather than by a\n // driver's recollection of them.\n if (Object.prototype.hasOwnProperty.call(resumeOutputs, node.id)) {\n const stored = resumeOutputs[node.id];\n outputs[node.id] = stored;\n const activated = activatedPorts(node, stored);\n for (const portId of activated.ports) {\n portValues.set(`${node.id}:${portId}`, activated.value);\n onEvent({ type: \"node-output\", nodeId: node.id, portId, value: activated.value });\n }\n completed.add(node.id);\n onEvent({ type: \"node-status\", nodeId: node.id, status: \"done\", text: \"resumed\" });\n continue;\n }\n\n const incoming = incomingByNode.get(node.id) ?? [];\n\n // Run a node once any upstream branch reaches it. We iterate in\n // topological order, so by the time we reach this node every upstream\n // node has been processed — each incoming edge is therefore *settled*\n // (active or dead, never still-pending). Requiring ALL incoming edges to\n // be active wrongly skipped MERGE POINTS: when a Decision routes down one\n // branch, the other branch's edge stays dead forever, so an `every` check\n // skipped the shared continuation node and halted the run after the first\n // branch (#1). Run when AT LEAST ONE incoming edge is active —\n // collectInputs() only reads from the active ones. A genuine parallel\n // join still works: in topo order both of its inputs are already active.\n if (incoming.length > 0) {\n const anyActive = incoming.some((e) => portValues.has(`${e.source}:${e.sourceHandle ?? \"out\"}`));\n if (!anyActive) {\n onEvent({ type: \"node-status\", nodeId: node.id, status: \"idle\", text: \"skipped\" });\n continue;\n }\n }\n\n // Notes/annotations + layout (lane/pool) nodes are visual only — never\n // executed and never fed to runners. Their config (a note's text, a lane's\n // title) stays in the document for editors + MCP tools, but the engine\n // walks straight past them. Edges cross lanes freely, so grouping never\n // affects topology.\n const visualKind = getNodeKind(node.type ?? \"\");\n const isLayout = visualKind?.category === \"layout\";\n const isAnnotation = node.type === \"note\" || visualKind?.category === \"annotation\";\n if (isLayout || isAnnotation) {\n onEvent({\n type: \"node-status\",\n nodeId: node.id,\n status: \"idle\",\n text: isLayout ? \"lane\" : \"annotation\",\n });\n continue;\n }\n\n onEvent({ type: \"node-status\", nodeId: node.id, status: \"running\" });\n\n const inputs = collectInputs(node, incoming, portValues, initialInputs);\n const exec = pickExecutor(executors, node);\n if (!exec) {\n const msg = `No executor registered for kind=${node.type}`;\n errors.push(msg);\n onEvent({ type: \"node-status\", nodeId: node.id, status: \"error\", text: msg });\n onEvent({ type: \"log\", nodeId: node.id, level: \"error\", message: msg });\n break;\n }\n\n try {\n const result = await Promise.resolve(\n exec({\n node,\n inputs,\n abort: (reason) => { throw new Error(reason ?? \"aborted\"); },\n emit: onEvent,\n depth,\n run,\n }),\n );\n outputs[node.id] = result;\n\n // Decide which output ports were activated. Three conventions:\n // 1) If result is `{ __port: \"out\", value: x }`, only that port emits.\n // 2) If result has `branch: <portId>`, only that port emits (decision sugar).\n // 3) Otherwise, the value is published on every declared output port.\n const activated = activatedPorts(node, result);\n for (const portId of activated.ports) {\n portValues.set(`${node.id}:${portId}`, activated.value);\n onEvent({ type: \"node-output\", nodeId: node.id, portId, value: activated.value });\n }\n completed.add(node.id);\n onEvent({ type: \"node-status\", nodeId: node.id, status: \"done\" });\n } catch (e) {\n const msg = e instanceof Error ? e.message : String(e);\n errors.push(msg);\n onEvent({ type: \"node-status\", nodeId: node.id, status: \"error\", text: msg });\n onEvent({ type: \"log\", nodeId: node.id, level: \"error\", message: msg });\n break;\n }\n }\n } finally {\n if (timer) clearTimeout(timer);\n }\n\n const ok = errors.length === 0;\n onEvent({ type: \"run-end\", ok });\n return ok ? { ok, outputs } : { ok, outputs, error: errors[0] };\n}\n\nfunction indexIncoming(edges: FlowEdge[]): Map<string, FlowEdge[]> {\n const map = new Map<string, FlowEdge[]>();\n for (const e of edges) {\n const list = map.get(e.target) ?? [];\n list.push(e);\n map.set(e.target, list);\n }\n return map;\n}\n\nfunction topoSort(graph: FlowGraph): FlowNode[] | null {\n const inDegree = new Map<string, number>();\n for (const n of graph.nodes) inDegree.set(n.id, 0);\n for (const e of graph.edges) inDegree.set(e.target, (inDegree.get(e.target) ?? 0) + 1);\n const queue: string[] = [];\n for (const [id, d] of inDegree) if (d === 0) queue.push(id);\n const ordered: string[] = [];\n while (queue.length) {\n const id = queue.shift()!;\n ordered.push(id);\n for (const e of graph.edges) {\n if (e.source !== id) continue;\n const next = (inDegree.get(e.target) ?? 0) - 1;\n inDegree.set(e.target, next);\n if (next === 0) queue.push(e.target);\n }\n }\n if (ordered.length !== graph.nodes.length) return null;\n const byId = new Map(graph.nodes.map((n) => [n.id, n]));\n return ordered.map((id) => byId.get(id)!).filter(Boolean);\n}\n\nfunction collectInputs(\n node: FlowNode,\n incoming: FlowEdge[],\n portValues: Map<string, unknown>,\n initial: Record<string, Record<string, unknown>>,\n): Record<string, unknown> {\n const inputs: Record<string, unknown> = { ...(initial[node.id] ?? {}) };\n for (const e of incoming) {\n const portId = e.targetHandle ?? \"in\";\n const key = `${e.source}:${e.sourceHandle ?? \"out\"}`;\n // A branch that never fired has no entry in portValues. Assigning its\n // `undefined` would CLOBBER the value the branch that DID fire already\n // contributed on this same handle — emptying every merge point downstream\n // of a decision, silently, with the run still reporting success.\n //\n // This is the other half of the merge-point bug above: that fix stopped the\n // shared continuation node being skipped, but it still arrived with nothing\n // whenever a later inactive edge happened to be last in `incoming`.\n if (!portValues.has(key)) continue;\n inputs[portId] = portValues.get(key);\n }\n return inputs;\n}\n\nfunction pickExecutor(\n executors: ExecutorRegistry,\n node: FlowNode,\n): NodeExecutor | undefined {\n if (executors[node.id]) return executors[node.id];\n if (node.type && executors[node.type]) return executors[node.type];\n\n // Try every id the kind answers to. Kinds are namespaced (`@fancy/switch_case`)\n // while a host may have bound its executor under the bare name it used before\n // — or vice versa. Without this, the rename would silently stop matching and\n // the node would fall through to `*` or simply not run: a breaking change\n // wearing the costume of a rename.\n const kind = node.type ? getNodeKind(node.type) : null;\n if (kind) {\n for (const id of kindIds(kind)) {\n if (executors[id]) return executors[id];\n }\n }\n\n return executors[\"*\"];\n}\n\nfunction activatedPorts(node: FlowNode, result: unknown): { ports: string[]; value: unknown } {\n if (result && typeof result === \"object\") {\n const r = result as Record<string, unknown>;\n if (typeof r.__port === \"string\") {\n return { ports: [r.__port], value: r.value };\n }\n if (typeof r.branch === \"string\") {\n return { ports: [r.branch], value: r.value ?? r };\n }\n }\n // Resolve through the shared helper so the ports the runtime activates are\n // the same ones the canvas drew — including config-driven ports, which the\n // node's `data` does not carry. Falls back to a lone `out` when a node\n // declares nothing.\n const kind = getNodeKind((node.data as any)?.kind ?? node.type ?? \"\") ?? undefined;\n const declared = resolveNodePorts(node, kind).outputs?.map((p) => p.id);\n return { ports: declared?.length ? declared : [\"out\"], value: result };\n}\n","/**\n * Run ONE node of a graph — through the real engine, not around it.\n *\n * ## The problem this solves\n *\n * A per-node driver has to hand a node exactly the inputs it would have\n * received mid-run: the right values, on the right target handles, from the\n * right *active* edges. Those rules are the engine's (`collectInputs`,\n * `activatedPorts`, the merge-after-decision contract, the `out` fallbacks),\n * and they are the reason the three runtimes agree. Re-implementing them here\n * would be a second engine wearing a driver's clothes, and the two would drift.\n *\n * ## What it does instead\n *\n * It replays the graph with `runFlow` untouched:\n *\n * - every node already completed is fed back as `resumeOutputs`, so the engine\n * republishes it on the same ports and routes exactly as it did the first\n * time;\n * - every node EXCEPT the target is bound, by node id, to a boundary executor\n * that aborts — and a node-id binding outranks every kind binding and the\n * `*` fallback, so the fence holds whatever a host registered;\n * - so the engine walks its own topological order, skips its own dead branches,\n * collects the target's inputs its own way, runs the target — and stops at\n * the next thing it would have run.\n *\n * The target's output is `result.outputs[nodeId]`, and the ports it activated\n * arrive as the engine's own `node-output` events. Nothing about routing is\n * recomputed here.\n *\n * ## The cost, stated plainly\n *\n * Replaying the completed prefix is O(nodes) per node, so a run is O(nodes²) in\n * bookkeeping. The republish executes nothing — it re-publishes stored values —\n * so for the graph sizes workflows actually have this is noise next to a single\n * queue round trip. It buys exact fidelity to the engine, which is not\n * negotiable, and one implementation of the routing rules instead of two.\n */\n\nimport { runFlow, type RunResult } from \"../runtime/run-flow\";\nimport type { RunIdentity } from \"../runtime/run-identity\";\nimport type { ExecutorRegistry, FlowGraph, RunEvent } from \"../types\";\n\n/**\n * The abort reason the boundary executor uses.\n *\n * Not a failure: it is the engine telling us it reached a node this job is not\n * responsible for.\n */\nexport const BOUNDARY = \"fancy-flow:node-boundary\";\n\nexport type ReplayResult = {\n result: RunResult;\n /** node id -> the ports its output activated, from the engine's own events. */\n ports: Record<string, string[]>;\n outputOf(nodeId: string): unknown;\n portsOf(nodeId: string): string[];\n};\n\nexport type ReplayOptions = {\n resumeOutputs?: Record<string, unknown>;\n initialInputs?: Record<string, Record<string, unknown>>;\n onEvent?: (event: RunEvent) => void;\n depth?: number;\n run?: RunIdentity;\n};\n\n/**\n * Replay `graph` up to and through `nodeId`.\n *\n * Pass `nodeId = null` to PROBE: every node is a boundary, so nothing executes\n * and the engine reports only what it can determine structurally — a cycle, and\n * the ports each resumed output republishes on.\n */\nexport async function replayUpTo(\n graph: FlowGraph,\n nodeId: string | null,\n executors: ExecutorRegistry,\n options: ReplayOptions = {},\n): Promise<ReplayResult> {\n const fenced: ExecutorRegistry = { ...executors };\n for (const node of graph.nodes) {\n if (node.id !== nodeId) {\n fenced[node.id] = (ctx) => ctx.abort(BOUNDARY);\n }\n }\n\n const ports: Record<string, string[]> = {};\n const collect = (event: RunEvent): void => {\n if (event.type === \"node-output\") {\n (ports[event.nodeId] ??= []).push(event.portId);\n }\n options.onEvent?.(event);\n };\n\n const result = await runFlow(graph, fenced, collect, {\n initialInputs: options.initialInputs ?? {},\n resumeOutputs: options.resumeOutputs ?? {},\n depth: options.depth ?? 0,\n run: options.run,\n });\n\n return {\n result,\n ports,\n outputOf: (id) => result.outputs[id],\n portsOf: (id) => ports[id] ?? [],\n };\n}\n\n/** True when a replay ended because it reached a node it does not own. */\nexport function isBoundary(error: string | null | undefined): boolean {\n return error === BOUNDARY;\n}\n","/**\n * How many times a single node may be attempted.\n *\n * ## Why this cannot be one number\n *\n * A run-wide `tries` setting forces every workflow to pick between two bad\n * answers. At 1, a single flaky LLM or HTTP call takes the whole run down.\n * Above 1, the retry replays from the last checkpoint and everything already\n * done runs again — including the nodes that must not: `git_pr_open` opens a\n * second pull request.\n *\n * Per-node jobs make the question per node, which is where it always belonged.\n * A node declaring `sideEffects: unsafe-to-replay` is pinned to ONE attempt and\n * no backoff. Everything else takes the configured tries, or a per-kind\n * override.\n *\n * Undeclared side effects are treated as the configured default rather than\n * assumed safe: this decides retries, and inventing a safety claim on a node\n * author's behalf is how a retry loop ends up posting the same webhook twice.\n */\n\nimport { getNodeKind, kindIds, resolveKindId } from \"../registry/registry\";\nimport type { FlowNode } from \"../types\";\n\n/** A node that is not safe to run twice. Same vocabulary as the node manifest. */\nexport const UNSAFE_TO_REPLAY = \"unsafe-to-replay\";\n\nexport type RetryPolicyOptions = {\n tries?: number;\n backoffSeconds?: number;\n /** kind id -> tries. Keyed by any spelling; every id is checked. */\n perKind?: Record<string, number>;\n};\n\nexport class RetryPolicy {\n readonly tries: number;\n readonly backoffSeconds: number;\n readonly perKind: Record<string, number>;\n\n constructor(options: RetryPolicyOptions = {}) {\n this.tries = options.tries ?? 1;\n this.backoffSeconds = options.backoffSeconds ?? 0;\n this.perKind = options.perKind ?? {};\n }\n\n triesFor(node: FlowNode): number {\n if (RetryPolicy.isUnsafeToReplay(node)) return 1;\n\n for (const id of idsFor(node)) {\n if (id in this.perKind) return Math.max(1, Math.trunc(this.perKind[id]!));\n }\n\n return Math.max(1, Math.trunc(this.tries));\n }\n\n backoffFor(node: FlowNode): number {\n // Nothing to back off from: the node gets one attempt.\n if (RetryPolicy.isUnsafeToReplay(node)) return 0;\n return Math.max(0, this.backoffSeconds);\n }\n\n static isUnsafeToReplay(node: FlowNode): boolean {\n if (!node.type) return false;\n return getNodeKind(node.type)?.sideEffects === UNSAFE_TO_REPLAY;\n }\n}\n\n/**\n * Every id a per-kind override for this node could be keyed under.\n *\n * Canonical ids are namespaced while a host almost certainly writes the bare\n * one; keying on only the literal string would make the override silently stop\n * applying the day a kind is renamed.\n */\nfunction idsFor(node: FlowNode): string[] {\n if (!node.type) return [];\n const kind = getNodeKind(node.type);\n const canonical = resolveKindId(node.type);\n const ordered = [node.type, ...(canonical ? [canonical] : []), ...(kind ? kindIds(kind) : [])];\n return [...new Set(ordered)];\n}\n","/**\n * The human-pause contract.\n *\n * A workflow that waits for a person is not an error, but it travels the same\n * channel as one: the executor aborts, the engine records a reason string, and\n * the durable runner decides whether that string meant \"failed\" or \"waiting\".\n *\n * That seam existed before this module, as two `str_starts_with` checks in the\n * Laravel run job against constants owned by two BUILTIN executors. It worked,\n * and it was invisible: a third-party human-input node had no way to announce\n * that it pauses, and nothing stopped a refactor from removing the mechanism\n * out from under published packages. Reported by the MOIC Suite consumer, who\n * needed exactly that and had to reach for a private constant to get it.\n *\n * So the encoding is now public, typed, and versioned by prefix rather than\n * implied. The wire format stays a plain string on purpose — it survives the\n * existing abort → `RunResult.error` path unchanged, crosses a queue boundary,\n * and decodes identically in PHP, none of which a thrown class would do.\n *\n * @see decodePause — the one function a durable runner needs.\n */\n\n/**\n * What the run is waiting for.\n *\n * `approval` and `input` are the shapes both runtimes ship. The type stays open\n * because the whole point is that a marketplace node can define its own —\n * a signature step, a payment confirmation, a review queue — and a runner that\n * does not recognise one should report it rather than guess.\n */\nexport type PauseAwaiting = \"approval\" | \"input\" | (string & {});\n\n/** A run halted, waiting for a person. */\nexport type PauseSignal = {\n /** The node that paused — where a submission gets injected on resume. */\n nodeId: string;\n awaiting: PauseAwaiting;\n /**\n * Kind-supplied context for whoever renders the wait — a form schema, the\n * question being asked, a diff to approve. Must be JSON-serializable: it\n * crosses a queue boundary and, for durable runs, a database column.\n */\n detail?: unknown;\n};\n\n/** Marks a reason string as a pause rather than a failure. */\nexport const PAUSE_PREFIX = \"fancy-flow:pause:\";\n\n/**\n * Reason prefixes shipped before this contract, kept decodable forever.\n *\n * These are what `DurableApprovalExecutor` and `DurableUserInputExecutor`\n * emitted, and they are written into the `error` column of every run that\n * paused under an older version. Dropping them would strand those runs\n * mid-flight — a resume path that only works for new runs is not a resume path.\n */\nexport const LEGACY_PAUSE_PREFIXES: ReadonlyArray<readonly [string, PauseAwaiting]> = [\n [\"awaiting-approval:\", \"approval\"],\n [\"awaiting-input:\", \"input\"],\n];\n\n/**\n * Encode a pause as the reason string an executor aborts with.\n *\n * The payload is JSON rather than delimited fields because a node id may\n * contain a colon, and a positional encoding that breaks on user data is the\n * kind of bug that only shows up in someone else's graph.\n */\nexport function encodePause(signal: PauseSignal): string {\n const { nodeId, awaiting, detail } = signal;\n return PAUSE_PREFIX + JSON.stringify(detail === undefined ? { nodeId, awaiting } : { nodeId, awaiting, detail });\n}\n\n/**\n * Decode a run's error reason into a pause, or null if it was a real failure.\n *\n * This is the whole contract from a runner's side: call it on `result.error`,\n * and if it returns non-null, persist the run as waiting on `signal.nodeId`\n * instead of failing it. Accepts the legacy prefixes, so a runner written\n * against this handles runs that paused under an older version.\n */\nexport function decodePause(reason: string | null | undefined): PauseSignal | null {\n if (typeof reason !== \"string\") return null;\n\n if (reason.startsWith(PAUSE_PREFIX)) {\n const body = reason.slice(PAUSE_PREFIX.length);\n try {\n const parsed = JSON.parse(body) as Partial<PauseSignal>;\n // A malformed payload is a corrupt pause, not a failure to report as a\n // crash — but it is also not something to invent a node id for.\n if (typeof parsed?.nodeId !== \"string\" || typeof parsed?.awaiting !== \"string\") return null;\n return \"detail\" in parsed\n ? { nodeId: parsed.nodeId, awaiting: parsed.awaiting, detail: parsed.detail }\n : { nodeId: parsed.nodeId, awaiting: parsed.awaiting };\n } catch {\n return null;\n }\n }\n\n for (const [prefix, awaiting] of LEGACY_PAUSE_PREFIXES) {\n if (reason.startsWith(prefix)) {\n return { nodeId: reason.slice(prefix.length), awaiting };\n }\n }\n\n return null;\n}\n\n/** True when a run's error reason is actually a pause. */\nexport function isPause(reason: string | null | undefined): boolean {\n return decodePause(reason) !== null;\n}\n\n/**\n * Abort the current node as a pause.\n *\n * Called from inside an executor with its own context. Node authors should\n * reach for this rather than hand-encoding a reason, so the format stays ours\n * to change:\n *\n * ```ts\n * const values = ctx.inputs.values;\n * if (values === undefined) pauseForHuman(ctx, \"input\", { fields });\n * return values;\n * ```\n *\n * Note the `undefined` check — an empty submission (`{}`) is a real answer and\n * must resume. Truthiness here pauses forever on an empty form.\n */\nexport function pauseForHuman(\n ctx: { node: { id: string }; abort: (reason?: string) => never },\n awaiting: PauseAwaiting,\n detail?: unknown,\n): never {\n return ctx.abort(encodePause({ nodeId: ctx.node.id, awaiting, detail }));\n}\n","/**\n * `{{ }}` resolution — the TypeScript twin of `FancyFlow\\Nodes\\Support\\Expr`.\n *\n * ## Why this is opt-in and not wired into `runFlow`\n *\n * The PHP runtime resolves expressions inside its batteries-included executors.\n * The JS runtime never has: `runFlow` hands `node.data.config` to your executor\n * verbatim, so every host that uses `{{ }}` today already resolves it itself.\n * Turning resolution on inside `runFlow` would interpolate a second time over\n * values those hosts had already substituted — silently, and only for graphs\n * that happen to contain `{{` in their DATA.\n *\n * So this exports the semantics and changes no behaviour. Call it yourself:\n *\n * ```ts\n * const url = evaluateExpression(node.data.config.url, inputs);\n * ```\n *\n * ## The semantics are the PHP file's, deliberately\n *\n * This is not a general expression language and must not grow into one. It\n * resolves a dot-path against a context and nothing else — no arithmetic, no\n * comparisons, no calls. Hosts that want real expressions override the executor\n * (the PHP docblock points at symfony/expression-language for the same reason).\n *\n * Divergence here is a correctness bug rather than a style difference: the same\n * graph is authored once and may run on either runtime. `suites/shared/expr`\n * in `@particle-academy/fancy-conformance` is the fixture table both sides run,\n * so parity is a test result instead of a claim.\n */\n\n/** Anything a context or a resolved value can be. */\nexport type ExprValue = unknown;\n\n/** The context an expression resolves against — the executor's `inputs`. */\nexport type ExprContext = Record<string, ExprValue>;\n\n/**\n * `{{ … }}` is parsed by SCANNING, not by a regular expression.\n *\n * Two CodeQL `js/polynomial-redos` alerts (#2, #3) came out of the regex\n * version, and the second survived the obvious fix — which is the useful part.\n * Dropping the ambiguous `\\s*` around the capture killed one witness\n * (`'{{{{' + ' '.repeat(n)`) and CodeQL immediately produced another\n * (`'{{{{a'` repeated). That is not a pattern bug: a GLOBAL lazy scan for a\n * delimiter that never arrives is quadratic by construction — O(n) starts, each\n * scanning O(n) forward — and no amount of tuning the pattern removes it.\n *\n * `indexOf` has no backtracking at all. Each character is visited a bounded\n * number of times, so this is linear by construction rather than by careful\n * pattern-writing, and there is no next witness to find.\n *\n * The behaviour is deliberately identical to the regexes it replaces, including\n * the odd corner: `{{a}}{{b}}` is a WHOLE expression whose path is `a}}{{b`\n * (which resolves to null), because the old pattern was `$`-anchored and its\n * lazy capture had to grow to reach the end. The PHP twin does the same, and\n * `shared/expr` is what holds the two together.\n */\n\n/** The inner text of a template that is exactly one expression, else `null`. */\nfunction wholeExpression(trimmed: string): string | null {\n if (trimmed.length < 4) return null;\n if (!trimmed.startsWith(\"{{\") || !trimmed.endsWith(\"}}\")) return null;\n return trimmed.slice(2, -2);\n}\n\n/**\n * Replace every `{{ … }}` run, left to right, in a single pass.\n *\n * An unterminated `{{` is literal text — the same thing the regex did by simply\n * not matching, and the case an author hits constantly while typing.\n */\nfunction interpolate(template: string, resolve: (path: string) => string): string {\n let out = \"\";\n let i = 0;\n\n for (;;) {\n const open = template.indexOf(\"{{\", i);\n if (open === -1) return out + template.slice(i);\n\n const close = template.indexOf(\"}}\", open + 2);\n if (close === -1) return out + template.slice(i);\n\n out += template.slice(i, open) + resolve(template.slice(open + 2, close));\n i = close + 2;\n }\n}\n\n/**\n * Strings PHP's `Expr::truthy` treats as false.\n *\n * `\"0\"` and `\"false\"` are the ones that matter: a branch condition arriving as\n * text from a form or a JSON body would otherwise be truthy for every non-empty\n * string, and `\"false\"` taking the true branch is the kind of bug that looks\n * like the engine is broken.\n */\nconst FALSY_STRINGS = new Set([\"\", \"0\", \"false\", \"no\", \"off\", \"null\"]);\n\n/**\n * Resolve a dot-path against the context, honouring the `$json` / `$input`\n * alias.\n *\n * Both aliases point at the `in` port value when the context has one, and at\n * the whole context otherwise — the same fallback the PHP does, which is what\n * makes `{{ $json.x }}` work on a trigger node that has no upstream input.\n *\n * A path that does not resolve returns `null`, never `undefined`: PHP has one\n * absent value and JS has two, and letting the difference leak would make the\n * two runtimes disagree about `{{ missing }}` for no useful reason.\n */\nexport function resolvePath(path: string, context: ExprContext): ExprValue {\n const trimmed = path.trim();\n if (trimmed === \"\") return null;\n\n const segments = trimmed.split(\".\");\n let cursor: ExprValue;\n\n const head = segments[0];\n if (head === \"$json\" || head === \"$input\") {\n cursor = context !== null && typeof context === \"object\" && \"in\" in context ? context.in : context;\n segments.shift();\n } else {\n cursor = context;\n }\n\n for (const segment of segments) {\n if (cursor === null || cursor === undefined) return null;\n if (typeof cursor !== \"object\") return null;\n // Arrays are indexed by their numeric keys, matching PHP's list access.\n const next = (cursor as Record<string, ExprValue>)[segment];\n if (next === undefined) return null;\n cursor = next;\n }\n\n return cursor === undefined ? null : cursor;\n}\n\n/**\n * Evaluate a template against a context.\n *\n * A string that is EXACTLY one expression returns the resolved value with its\n * type intact — `{{ $json.count }}` gives you a number, not `\"3\"`. Anything\n * else interpolates each run as text. That distinction is load-bearing: it is\n * what lets a config field carry either a value or a sentence.\n *\n * Non-string templates pass through untouched, so this is safe to map over a\n * whole config object.\n */\nexport function evaluateExpression(template: ExprValue, context: ExprContext): ExprValue {\n if (typeof template !== \"string\") return template;\n\n const whole = wholeExpression(template.trim());\n if (whole !== null) return resolvePath(whole, context);\n\n return interpolate(template, (path) => stringify(resolvePath(path, context)));\n}\n\n/**\n * Truthiness for branch / switch decisions.\n *\n * Mirrors PHP's rules rather than JavaScript's, because the graph is authored\n * once and may run on either side. The two disagree in exactly the places a\n * workflow hits: `\"0\"` and `\"false\"` are truthy in JS and falsy here, and an\n * empty array is truthy in JS and falsy here.\n */\nexport function truthy(value: ExprValue): boolean {\n if (typeof value === \"boolean\") return value;\n if (value === null || value === undefined) return false;\n if (typeof value === \"string\") return !FALSY_STRINGS.has(value.trim().toLowerCase());\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === \"number\") return value !== 0;\n return Boolean(value);\n}\n\n/** Coerce a value to text the way interpolation does. */\nexport function text(value: ExprValue): string {\n return stringify(value);\n}\n\nfunction stringify(value: ExprValue): string {\n if (typeof value === \"string\") return value;\n if (typeof value === \"boolean\") return value ? \"true\" : \"false\";\n if (value === null || value === undefined) return \"\";\n if (typeof value === \"number\" || typeof value === \"bigint\") return String(value);\n try {\n return JSON.stringify(value) ?? \"\";\n } catch {\n return \"\";\n }\n}\n\n/**\n * Resolve every string in a config object, one level of nesting at a time.\n *\n * The convenience most hosts actually want, and the shape their hand-rolled\n * version usually takes. Opt-in like the rest of this module.\n */\nexport function evaluateConfig<T extends Record<string, ExprValue>>(config: T, context: ExprContext): T {\n const out: Record<string, ExprValue> = {};\n for (const [key, value] of Object.entries(config)) {\n out[key] = Array.isArray(value)\n ? value.map((v) => evaluateExpression(v, context))\n : value !== null && typeof value === \"object\"\n ? evaluateConfig(value as Record<string, ExprValue>, context)\n : evaluateExpression(value, context);\n }\n return out as T;\n}\n","/**\n * Human gates that cannot be walked past — and that hold no worker.\n *\n * ## The directive these implement\n *\n * A node that waits on a person must not occupy a worker, a connection or a\n * process while it waits. So the job for a human gate does its work by\n * **emitting the request** and then **finishing**: the run is persisted as\n * parked, the job returns, the worker takes the next thing off the queue. When\n * the person answers, *that* enqueues the continuation.\n *\n * Mechanically the gate aborts with an encoded pause, which is a *return*, not\n * a block. Nothing in this file sleeps, polls or awaits a person.\n *\n * ## Fail closed, and why\n *\n * A gate pauses because it **is** a human node, not because its input port\n * happens to be empty. This is not a preference; it is a fix. Both peer\n * runtimes once decided whether to pause by reading their own input, so a\n * pre-filled `values` or `approved` value ran the flow straight past the person\n * it was waiting for — silently, with the run reporting success.\n *\n * Restoring the old behaviour is possible, explicit, and per node:\n * `autoAnswerFromInput`. Turn it on for a step that is a form when a human is\n * present and a pass-through when an upstream node already produced the answer.\n * On an approval node, weigh it harder: it means the graph, not a person, can\n * approve.\n *\n * ## The other half of the fix\n *\n * Recording an answer for a node the run is not parked on THROWS rather than\n * queueing a write nobody reads. See {@link Submissions.record}.\n */\n\nimport { pauseForHuman } from \"../registry/pause\";\nimport { truthy } from \"../expressions/expr\";\nimport type { NodeExecutor } from \"../types\";\n\n/** An answer was recorded for a node the run is not waiting on. */\nexport class NotAwaitingHuman extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"NotAwaitingHuman\";\n }\n}\n\n/**\n * Answers recorded for human gates, keyed by node id.\n *\n * Deliberately separate from the run's inputs. Keeping them in one bag is\n * precisely what let a pre-filled input satisfy a gate.\n */\nexport class Submissions {\n private readonly answers = new Map<string, unknown>();\n /** The node the run is currently parked on, if any. */\n awaiting: string | null = null;\n\n /**\n * Record an answer for the node the run is parked on.\n *\n * Throws when the run is not waiting on that node. A queued answer for a node\n * that never paused is a write nobody reads — and it looks, from the outside,\n * exactly like a submission that worked.\n */\n record(nodeId: string, value: unknown): void {\n if (this.awaiting !== null && this.awaiting !== nodeId) {\n throw new NotAwaitingHuman(\n `This run is waiting on \"${this.awaiting}\", not \"${nodeId}\". Recording an answer for a ` +\n \"node the run is not parked on would be stored and never read.\",\n );\n }\n if (this.awaiting === null) {\n throw new NotAwaitingHuman(\n `This run is not waiting for anyone, so an answer for \"${nodeId}\" has nothing to resume.`,\n );\n }\n this.answers.set(nodeId, value);\n this.awaiting = null;\n }\n\n answered(nodeId: string): boolean {\n return this.answers.has(nodeId);\n }\n\n answer(nodeId: string): unknown {\n return this.answers.get(nodeId);\n }\n\n park(nodeId: string): void {\n this.awaiting = nodeId;\n }\n}\n\nfunction option(ctx: { node: { data?: unknown } }, key: string, fallback?: unknown): unknown {\n const config = ((ctx.node.data as any)?.config ?? {}) as Record<string, unknown>;\n return config[key] ?? fallback;\n}\n\n/** `user_input` — pauses until a submission for THIS node is recorded. */\nexport function durableUserInput(submissions: Submissions): NodeExecutor {\n return (ctx) => {\n if (submissions.answered(ctx.node.id)) return submissions.answer(ctx.node.id);\n\n if (option(ctx, \"autoAnswerFromInput\") === true) {\n const values = (ctx.inputs as Record<string, unknown>).values;\n if (values !== undefined) return values;\n }\n\n submissions.park(ctx.node.id);\n // Emits the request and RETURNS. A host listening to the feed sends the\n // email; the worker is free the moment this throws.\n return pauseForHuman(ctx, \"input\", {\n title: option(ctx, \"title\", \"Need your input\"),\n fields: option(ctx, \"fields\", []),\n });\n };\n}\n\n/** `human_approval` — pauses until a decision for THIS node is recorded. */\nexport function durableApproval(submissions: Submissions): NodeExecutor {\n return (ctx) => {\n const passthrough = (ctx.inputs as Record<string, unknown>).in ?? ctx.inputs;\n\n if (submissions.answered(ctx.node.id)) {\n return { branch: truthy(submissions.answer(ctx.node.id)) ? \"approved\" : \"denied\", value: passthrough };\n }\n\n if (option(ctx, \"autoAnswerFromInput\") === true) {\n const decision = (ctx.inputs as Record<string, unknown>).approved;\n if (decision !== undefined) {\n return { branch: truthy(decision) ? \"approved\" : \"denied\", value: passthrough };\n }\n }\n\n submissions.park(ctx.node.id);\n return pauseForHuman(ctx, \"approval\", {\n title: option(ctx, \"title\", \"Approve action\"),\n description: option(ctx, \"description\"),\n });\n };\n}\n","/**\n * The per-node driver, with the queue left out.\n *\n * This is the whole of \"how a queued run branches\", minus the transport. It\n * owns two operations and nothing else:\n *\n * `advance()`\n * Ask the frontier what is unblocked, settle the skip cascade, and report the\n * ready node ids. A queue adapter dispatches one job per id.\n *\n * `runNode()`\n * Claim one node, replay the graph through the real engine fenced to that\n * node, and checkpoint the output plus the ports the ENGINE said it\n * activated.\n *\n * Everything a queue library would add — enqueue, retry scheduling, worker\n * lifecycle — sits outside. That separation is the point: it makes the subtle\n * part (which node may run, and with what inputs) testable in-process, with no\n * broker, and identical under every adapter. **A queue adapter therefore\n * contains no workflow logic at all.** That is the test: if an adapter needs to\n * know what a port is, the seam is in the wrong place.\n *\n * `runToCompletion` drives both in one process. It is a real durable runner,\n * not a toy: with a persistent `NodeClaimStore` it survives a crash exactly as\n * a queued run does, because the crash-resume behaviour lives in the\n * checkpoints rather than in the loop.\n *\n * ## No worker waits on a person\n *\n * A human gate returns `paused`. `runToCompletion` returns immediately when it\n * sees one — it does not spin, sleep or poll. The run is parked in the store,\n * the process is free, and a recorded answer is what starts the next job.\n */\n\nimport { decodePause, type PauseSignal } from \"../registry/pause\";\nimport type { RunResult } from \"../runtime/run-flow\";\nimport { RunIdentity, type RunIdentityJson } from \"../runtime/run-identity\";\nimport type { ExecutorRegistry, FlowGraph, RunEvent } from \"../types\";\nimport { Frontier } from \"./frontier\";\nimport { isBoundary, replayUpTo } from \"./replay\";\nimport { RetryPolicy } from \"./retry\";\nimport {\n InMemoryClaimStore,\n NodeRunStatus,\n type NodeClaimStore,\n type NodeState,\n} from \"./state\";\n\n/** What happened to one node. */\nexport type NodeOutcome = {\n nodeId: string;\n status: \"not-claimed\" | \"completed\" | \"skipped\" | \"failed\" | \"paused\";\n output?: unknown;\n ports?: string[];\n error?: string;\n pause?: PauseSignal;\n /** False when another worker got there first. A lost race is a NO-OP. */\n claimed: boolean;\n /** 1-based attempt this execution ran as. */\n attempt: number;\n /**\n * `true` when this attempt failed and the policy still allows another.\n *\n * The claim row is left CLAIMED in that case, deliberately: a queue adapter\n * re-dispatches the job with the SAME owner token and the retry re-enters the\n * claim it already holds. Recording FAILED here instead would settle the\n * node, which SKIPS everything downstream — a run reporting a tidy finish\n * having done half its work.\n */\n retryable?: boolean;\n};\n\nexport type DurableRunResult = {\n ok: boolean;\n outputs: Record<string, unknown>;\n error?: string;\n pause?: PauseSignal;\n paused: boolean;\n};\n\nexport type CoordinatorOptions = {\n graph: FlowGraph;\n executors: ExecutorRegistry;\n /**\n * The run's stable identity. A bare string is taken as the run key.\n *\n * Required — not defaulted. A durable run without a stable key cannot key an\n * idempotent write, and minting one per construction would hand a retrying\n * host a different key each time.\n */\n run: string | RunIdentity | RunIdentityJson;\n store?: NodeClaimStore;\n initialInputs?: Record<string, Record<string, unknown>>;\n retry?: RetryPolicy;\n onEvent?: (event: RunEvent) => void;\n};\n\nexport class Coordinator {\n readonly graph: FlowGraph;\n readonly executors: ExecutorRegistry;\n readonly run: RunIdentity;\n readonly store: NodeClaimStore;\n readonly initialInputs: Record<string, Record<string, unknown>>;\n readonly retry: RetryPolicy;\n private readonly onEvent?: (event: RunEvent) => void;\n\n constructor(options: CoordinatorOptions) {\n this.graph = options.graph;\n this.executors = options.executors;\n this.run = RunIdentity.from(options.run);\n this.store = options.store ?? new InMemoryClaimStore();\n this.initialInputs = options.initialInputs ?? {};\n this.retry = options.retry ?? new RetryPolicy();\n this.onEvent = options.onEvent;\n }\n\n get runKey(): string {\n return this.run.runKey;\n }\n\n // -- the two operations ----------------------------------------------\n\n /**\n * Which nodes may be dispatched right now.\n *\n * Also settles the skip cascade, because a skip is a decision the frontier\n * just made and a second caller must not make it again.\n */\n async advance(): Promise<string[]> {\n const frontier = Frontier.compute(this.graph, await this.store.state(this.runKey));\n await Frontier.settleSkips(this.store, this.runKey, frontier.skipped);\n return frontier.ready;\n }\n\n /**\n * Claim, execute and checkpoint one node.\n *\n * The claim is taken FIRST. Two workers racing for the same node produce one\n * execution and one no-op, and the loser learns that from the store rather\n * than from a duplicate side effect.\n *\n * `owner` is the token that lets a job's own retry re-enter its claim instead\n * of deadlocking against the row it wrote itself — pass the SAME token across\n * a job's attempts.\n */\n async runNode(nodeId: string, owner?: string): Promise<NodeOutcome> {\n const token = owner ?? cryptoRandom();\n if (!(await this.store.claim(this.runKey, nodeId, token))) {\n return { nodeId, status: \"not-claimed\", claimed: false, attempt: 0 };\n }\n\n const row = (await this.store.state(this.runKey))[nodeId];\n const identity = this.identityFor(row);\n\n const replay = await replayUpTo(this.graph, nodeId, this.executors, {\n resumeOutputs: await this.completedOutputs(),\n initialInputs: this.initialInputs,\n onEvent: this.forward(nodeId),\n run: identity,\n });\n const result = replay.result;\n const attempt = identity.attempt;\n\n if (Object.prototype.hasOwnProperty.call(result.outputs, nodeId)) {\n const output = result.outputs[nodeId];\n const ports = replay.portsOf(nodeId);\n await this.store.complete(this.runKey, nodeId, output, ports);\n return { nodeId, status: \"completed\", output, ports, claimed: true, attempt };\n }\n\n // The node did not produce an output. Three reasons, and they are NOT\n // interchangeable.\n const pause = decodePause(result.error);\n if (pause && pause.nodeId === nodeId) {\n await this.store.pause(this.runKey, nodeId, result.error ?? \"\");\n return { nodeId, status: \"paused\", pause, claimed: true, attempt };\n }\n\n if (isBoundary(result.error)) {\n // The engine stopped at a node this job does not own BEFORE reaching the\n // target — so the target was never actually unblocked. That is a frontier\n // bug, not a node failure, and it must not be recorded as one: a FAILED\n // node settles, and settling it would silently skip everything\n // downstream.\n await this.store.skip(this.runKey, nodeId);\n return {\n nodeId,\n status: \"skipped\",\n error: \"replay stopped before reaching this node\",\n claimed: true,\n attempt,\n };\n }\n\n const error = result.error ?? `node ${nodeId} produced no output and no error`;\n const node = this.graph.nodes.find((n) => n.id === nodeId);\n const tries = node ? this.retry.triesFor(node) : 1;\n\n if (attempt < tries) {\n // Leave the row CLAIMED so the same owner can re-enter it. This is what\n // `fancy-flow-php` does by only marking FAILED from the job's `failed()`\n // hook — the row a worker still holds must not settle mid-retry.\n return { nodeId, status: \"failed\", error, claimed: true, attempt, retryable: true };\n }\n\n await this.store.fail(this.runKey, nodeId, error);\n return { nodeId, status: \"failed\", error, claimed: true, attempt, retryable: false };\n }\n\n // -- an in-process driver over the two ------------------------------\n\n /**\n * Drive the graph here, in this process, one node at a time.\n *\n * Every checkpoint is written exactly as a queued run writes it, so a crash\n * mid-loop resumes from the same place a crashed worker would.\n *\n * Retries honour {@link RetryPolicy}: a node declaring `unsafe-to-replay`\n * gets one attempt whatever the policy says, and the retry re-enters the same\n * claim with the same owner token — so the step key it derives is unchanged,\n * which is what makes the retry idempotent rather than duplicative.\n */\n async runToCompletion(maxPasses = 10_000): Promise<DurableRunResult> {\n for (let pass = 0; pass < maxPasses; pass++) {\n const ready = await this.advance();\n if (ready.length === 0) break;\n\n for (const nodeId of ready) {\n const outcome = await this.runNodeWithRetries(nodeId);\n\n if (outcome.status === \"paused\") {\n // A pause parks the RUN, not just the node: continuing would run the\n // human gate's siblings while a person is still deciding. The cohort\n // waits. Nothing here blocks — this RETURNS.\n return {\n ok: false,\n outputs: await this.outputs(),\n pause: outcome.pause,\n paused: true,\n };\n }\n if (outcome.status === \"failed\") {\n return { ok: false, outputs: await this.outputs(), error: outcome.error, paused: false };\n }\n }\n }\n\n const state = await this.store.state(this.runKey);\n if (!Frontier.isComplete(this.graph, state)) {\n if (Frontier.hasWorkInFlight(state)) {\n return {\n ok: false,\n outputs: await this.outputs(),\n error: \"the run is waiting on work held elsewhere\",\n paused: false,\n };\n }\n const unsettled = this.graph.nodes\n .filter((n) => ![\"completed\", \"skipped\", \"failed\"].includes(state[n.id]?.status ?? \"\"))\n .map((n) => n.id);\n return {\n ok: false,\n outputs: await this.outputs(),\n error: `the run cannot progress; unsettled nodes: ${unsettled.join(\", \")}`,\n paused: false,\n };\n }\n\n const failed = Object.values(state)\n .filter((e) => e.status === NodeRunStatus.FAILED)\n .map((e) => e.error ?? \"node failed\");\n\n return {\n ok: failed.length === 0,\n outputs: await this.outputs(),\n error: failed[0],\n paused: false,\n };\n }\n\n /**\n * Checkpointed outputs, in the graph's own node order.\n *\n * Ordered by the graph rather than by completion so two runs of the same\n * workflow produce comparable output maps even when nodes finished in a\n * different order.\n */\n async outputs(): Promise<Record<string, unknown>> {\n const state = await this.store.state(this.runKey);\n const out: Record<string, unknown> = {};\n for (const node of this.graph.nodes) {\n if (state[node.id]?.status === NodeRunStatus.COMPLETED) out[node.id] = state[node.id]!.output;\n }\n return out;\n }\n\n /** The checkpointed run, in the shape a single-process run returns. */\n async asRunResult(): Promise<RunResult> {\n const outcome = await this.runToCompletion();\n return outcome.error === undefined\n ? { ok: outcome.ok, outputs: outcome.outputs }\n : { ok: outcome.ok, outputs: outcome.outputs, error: outcome.error };\n }\n\n // -- internals -------------------------------------------------------\n\n private async runNodeWithRetries(nodeId: string): Promise<NodeOutcome> {\n // One owner token for every attempt of this node — that is what re-enters\n // the claim rather than losing the race to itself, and it is why the step\n // key a retrying node derives is the same one its first attempt sent.\n const owner = cryptoRandom();\n\n let outcome = await this.runNode(nodeId, owner);\n while (outcome.retryable) {\n outcome = await this.runNode(nodeId, owner);\n }\n return outcome;\n }\n\n /**\n * The identity handed to the node about to execute.\n *\n * `attempt` and `firstAttemptAt` come off the CLAIM ROW, so they describe\n * this step rather than the run — which is what makes the retry window check\n * exact instead of conservative.\n */\n private identityFor(row: NodeState | undefined): RunIdentity {\n if (!row) return this.run;\n return this.run.withAttempt(row.attempts, row.firstAttemptAt);\n }\n\n private async completedOutputs(): Promise<Record<string, unknown>> {\n const state = await this.store.state(this.runKey);\n const out: Record<string, unknown> = {};\n for (const [nodeId, entry] of Object.entries(state)) {\n if (entry.status === NodeRunStatus.COMPLETED) out[nodeId] = entry.output;\n }\n return out;\n }\n\n /**\n * Forward only the events the target node produced.\n *\n * A replay re-emits the whole completed prefix. Passing that through would\n * show a consumer every node running again on every job — the run feed would\n * report a 20-node workflow as 200 status changes.\n */\n private forward(nodeId: string): ((event: RunEvent) => void) | undefined {\n const sink = this.onEvent;\n if (!sink) return undefined;\n return (event) => {\n const id = \"nodeId\" in event ? event.nodeId : undefined;\n if (id === undefined || id === nodeId) sink(event);\n };\n }\n}\n\nfunction cryptoRandom(): string {\n const g = globalThis as { crypto?: { randomUUID?: () => string } };\n return g.crypto?.randomUUID?.() ?? `own_${Math.random().toString(36).slice(2)}${Date.now()}`;\n}\n"]}