@particle-academy/fancy-flow 0.47.0 → 0.48.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-iMkZj0VK.d.ts → ConfigFieldRenderer-DrD2-Qml.d.ts} +1 -1
- package/dist/{ConfigFieldRenderer-Cyir8-B8.d.cts → ConfigFieldRenderer-NuDjtun1.d.cts} +1 -1
- package/dist/{chunk-QVFVL5LQ.js → chunk-7DTUZUTB.js} +3 -3
- package/dist/{chunk-QVFVL5LQ.js.map → chunk-7DTUZUTB.js.map} +1 -1
- package/dist/{chunk-DR3GWVDG.js → chunk-DRRZEAYB.js} +3 -3
- package/dist/{chunk-DR3GWVDG.js.map → chunk-DRRZEAYB.js.map} +1 -1
- package/dist/{chunk-ZKJJWBDJ.js → chunk-E6T3FZZP.js} +3 -3
- package/dist/{chunk-ZKJJWBDJ.js.map → chunk-E6T3FZZP.js.map} +1 -1
- package/dist/{chunk-ISXRQELT.js → chunk-KTGXZBUM.js} +3 -3
- package/dist/{chunk-ISXRQELT.js.map → chunk-KTGXZBUM.js.map} +1 -1
- package/dist/{chunk-NDEX655E.js → chunk-MJ3A3TAI.js} +2 -2
- package/dist/{chunk-NDEX655E.js.map → chunk-MJ3A3TAI.js.map} +1 -1
- package/dist/{chunk-Z2GRNYR2.js → chunk-UVP43XU2.js} +4 -4
- package/dist/{chunk-Z2GRNYR2.js.map → chunk-UVP43XU2.js.map} +1 -1
- package/dist/connectors.cjs +95 -0
- package/dist/connectors.cjs.map +1 -0
- package/dist/connectors.d.cts +122 -0
- package/dist/connectors.d.ts +122 -0
- package/dist/connectors.js +90 -0
- package/dist/connectors.js.map +1 -0
- package/dist/durable.cjs.map +1 -1
- package/dist/durable.js +1 -1
- package/dist/engine.cjs.map +1 -1
- package/dist/engine.d.cts +2 -2
- package/dist/engine.d.ts +2 -2
- package/dist/engine.js +3 -3
- package/dist/fields/react-fancy.d.cts +2 -2
- package/dist/fields/react-fancy.d.ts +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +11 -11
- package/dist/registry/index.d.cts +3 -3
- package/dist/registry/index.d.ts +3 -3
- package/dist/{registry-Bt55f63_.d.ts → registry-BnnifM-t.d.cts} +2 -2
- package/dist/{registry-CkcSwmfR.d.cts → registry-DpARG95T.d.ts} +2 -2
- package/dist/registry.cjs.map +1 -1
- package/dist/registry.js +2 -2
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +3 -3
- package/dist/schema.cjs.map +1 -1
- package/dist/schema.js +2 -2
- package/dist/screens.cjs.map +1 -1
- package/dist/screens.js +4 -4
- package/dist/{types--S2Kzx7w.d.cts → types-BO8TgI2M.d.cts} +1 -1
- package/dist/{types-ChkCRonF.d.ts → types-DJAmfiJC.d.ts} +1 -1
- package/dist/ux.cjs.map +1 -1
- package/dist/ux.d.cts +1 -1
- package/dist/ux.d.ts +1 -1
- package/dist/ux.js +1 -1
- package/package.json +11 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createConnectionValidator, buildNodeTypes } from './chunk-
|
|
2
|
-
import { Handle, Position, NoteNode, reconnectEdge, index, BackgroundVariant, Background, Controls, MiniMap, getNodeKind, categoryAccent, ViewportPortal } from './chunk-
|
|
1
|
+
import { createConnectionValidator, buildNodeTypes } from './chunk-DRRZEAYB.js';
|
|
2
|
+
import { Handle, Position, NoteNode, reconnectEdge, index, BackgroundVariant, Background, Controls, MiniMap, getNodeKind, categoryAccent, ViewportPortal } from './chunk-MJ3A3TAI.js';
|
|
3
3
|
import { memo, useMemo, useRef, useState, useCallback, useEffect } from 'react';
|
|
4
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -621,5 +621,5 @@ function cx(...parts) {
|
|
|
621
621
|
}
|
|
622
622
|
|
|
623
623
|
export { ActionNode, DecisionNode, FlowCanvas, FlowViewer, NodeShell, OutputNode, SubgraphNode, TriggerNode, alignNodes, assignToLane, cloneSubgraph, defaultNodeTypes, distributeNodes, duplicateNode, reconnectEdge2 as reconnectEdge, removeEdges, removeFromLane, removeNodes, setEdgeLabel };
|
|
624
|
-
//# sourceMappingURL=chunk-
|
|
625
|
-
//# sourceMappingURL=chunk-
|
|
624
|
+
//# sourceMappingURL=chunk-UVP43XU2.js.map
|
|
625
|
+
//# sourceMappingURL=chunk-UVP43XU2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/nodes/NodeShell.tsx","../src/components/nodes/TriggerNode.tsx","../src/components/nodes/ActionNode.tsx","../src/components/nodes/DecisionNode.tsx","../src/components/nodes/OutputNode.tsx","../src/components/nodes/SubgraphNode.tsx","../src/components/nodes/index.ts","../src/components/FlowEditor/graph-ops.ts","../src/components/canvas/helper-lines.ts","../src/components/canvas/HelperLines.tsx","../src/components/canvas/use-resolved-color-mode.ts","../src/components/canvas/FlowCanvas.tsx","../src/components/FlowViewer/FlowViewer.tsx"],"names":["jsx","memo","jsxs","reconnectEdge","cx","useState","useMemo","index"],"mappings":"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","file":"chunk-Z2GRNYR2.js","sourcesContent":["import { type ReactNode, memo } from \"react\";\nimport { Handle, Position, type NodeProps } from \"@xyflow/react\";\nimport type { FlowNode, NodeRunStatus, PortDescriptor } from \"../../types\";\n\nexport type NodeShellProps = {\n /** Required: the xyflow node this is rendering. */\n node: NodeProps<FlowNode>;\n /** Accent color for the title bar / status ring. */\n accent: string;\n /** Tag/label shown to the left of the title (e.g. \"TRIGGER\", \"ACTION\"). */\n tag: string;\n /** Optional icon glyph (single-character string is fine). */\n icon?: ReactNode;\n /** Whether to show input handles on the left. Defaults true. */\n showInputs?: boolean;\n /** Whether to show output handles on the right. Defaults true. */\n showOutputs?: boolean;\n /** Body content under the title bar. */\n children?: ReactNode;\n};\n\n/**\n * Shared chrome for every kit node — title bar, accent border, status ring,\n * port handles. Specific node kinds compose this with their body content.\n */\nfunction NodeShellInner({\n node,\n accent,\n tag,\n icon,\n showInputs = true,\n showOutputs = true,\n children,\n}: NodeShellProps) {\n const data = node.data;\n const status: NodeRunStatus = data.status ?? \"idle\";\n const inputs = data.inputs ?? defaultInputs(showInputs);\n const outputs = data.outputs ?? defaultOutputs(showOutputs);\n\n return (\n <div\n className={[\"ff-node\", `ff-node--status-${status}`, node.selected ? \"ff-node--selected\" : \"\"].filter(Boolean).join(\" \")}\n style={{ borderColor: node.selected ? accent : undefined }}\n >\n <header className=\"ff-node__header\" style={{ background: accent }}>\n <span className=\"ff-node__icon\" aria-hidden>{icon ?? null}</span>\n <span className=\"ff-node__tag\">{tag}</span>\n <span className=\"ff-node__label\">{data.label}</span>\n {status !== \"idle\" && <StatusDot status={status} />}\n </header>\n\n {data.description && <p className=\"ff-node__desc\">{data.description}</p>}\n {children && <div className=\"ff-node__body\">{children}</div>}\n {data.statusText && <p className=\"ff-node__status-text\">{data.statusText}</p>}\n\n {inputs.map((p, i) => (\n <Handle\n key={p.id}\n type=\"target\"\n position={Position.Left}\n id={p.id}\n style={portStyle(i, inputs.length)}\n title={p.label ?? p.id}\n />\n ))}\n {outputs.map((p, i) => (\n <Handle\n key={p.id}\n type=\"source\"\n position={Position.Right}\n id={p.id}\n style={portStyle(i, outputs.length)}\n title={p.label ?? p.id}\n />\n ))}\n </div>\n );\n}\n\nexport const NodeShell = memo(NodeShellInner);\n\nfunction defaultInputs(show: boolean): PortDescriptor[] {\n return show ? [{ id: \"in\" }] : [];\n}\nfunction defaultOutputs(show: boolean): PortDescriptor[] {\n return show ? [{ id: \"out\" }] : [];\n}\n\nfunction portStyle(i: number, total: number): React.CSSProperties {\n if (total <= 1) return {};\n const slot = (100 / (total + 1)) * (i + 1);\n return { top: `${slot}%` };\n}\n\nfunction StatusDot({ status }: { status: NodeRunStatus }) {\n return <span className={`ff-node__dot ff-node__dot--${status}`} aria-label={`status ${status}`} />;\n}\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\n/** Entry-point node — outputs only, no inputs. */\nfunction TriggerNodeInner(props: NodeProps<FlowNode>) {\n return <NodeShell node={props} accent=\"#10b981\" tag=\"TRIGGER\" icon=\"⚡\" showInputs={false} />;\n}\nexport const TriggerNode = memo(TriggerNodeInner);\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\n/** General-purpose work node — inputs and outputs. */\nfunction ActionNodeInner(props: NodeProps<FlowNode>) {\n return <NodeShell node={props} accent=\"#3b82f6\" tag=\"ACTION\" icon=\"▸\" />;\n}\nexport const ActionNode = memo(ActionNodeInner);\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode, PortDescriptor } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\nconst DEFAULT_BRANCHES: PortDescriptor[] = [\n { id: \"true\", label: \"true\" },\n { id: \"false\", label: \"false\" },\n];\n\n/** Branching node — multiple typed outputs, one input. */\nfunction DecisionNodeInner(props: NodeProps<FlowNode>) {\n // If the host hasn't customised outputs, default to a true/false split.\n if (!props.data.outputs) {\n props = { ...props, data: { ...props.data, outputs: DEFAULT_BRANCHES } };\n }\n return <NodeShell node={props} accent=\"#f59e0b\" tag=\"DECISION\" icon=\"◇\" />;\n}\nexport const DecisionNode = memo(DecisionNodeInner);\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\n/** Terminal node — receives the workflow's final result; no outputs. */\nfunction OutputNodeInner(props: NodeProps<FlowNode>) {\n return <NodeShell node={props} accent=\"#a855f7\" tag=\"OUTPUT\" icon=\"●\" showOutputs={false} />;\n}\nexport const OutputNode = memo(OutputNodeInner);\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode, SubgraphNodeData } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\n/**\n * SubgraphNode — collapses a group of nodes behind a single facade with\n * inputs and outputs that map to the inner graph's boundary ports. The\n * runtime treats it like an action node: when running, it dispatches to\n * the registered \"subgraph\" executor (host decides expand vs inline).\n *\n * v0.1 just renders the facade. Expand/collapse interactions and inner-\n * graph editing are deferred — host apps can implement those by toggling\n * `data.collapsed` and rendering a nested <FlowCanvas> when expanded.\n */\nfunction SubgraphNodeInner(props: NodeProps<FlowNode>) {\n const data = props.data as SubgraphNodeData;\n const childCount = data.childIds?.length ?? 0;\n return (\n <NodeShell node={props} accent=\"#0ea5e9\" tag=\"SUBGRAPH\" icon=\"❐\">\n <div className=\"ff-subgraph__meta\">\n <span>{childCount} node{childCount === 1 ? \"\" : \"s\"}</span>\n <span>{data.collapsed === false ? \"expanded\" : \"collapsed\"}</span>\n </div>\n </NodeShell>\n );\n}\nexport const SubgraphNode = memo(SubgraphNodeInner);\n","import type { NodeTypes } from \"@xyflow/react\";\nimport { TriggerNode } from \"./TriggerNode\";\nimport { ActionNode } from \"./ActionNode\";\nimport { DecisionNode } from \"./DecisionNode\";\nimport { OutputNode } from \"./OutputNode\";\nimport { NoteNode } from \"./NoteNode\";\nimport { SubgraphNode } from \"./SubgraphNode\";\n\nexport { TriggerNode, ActionNode, DecisionNode, OutputNode, NoteNode, SubgraphNode };\nexport { LaneNode } from \"./LaneNode\";\nexport { NodeShell, type NodeShellProps } from \"./NodeShell\";\n\n/**\n * Default xyflow `nodeTypes` map covering the kit. Spread into your own:\n *\n * <FlowCanvas nodeTypes={{ ...defaultNodeTypes, custom: MyNode }} ... />\n */\nexport const defaultNodeTypes: NodeTypes = {\n trigger: TriggerNode,\n action: ActionNode,\n decision: DecisionNode,\n output: OutputNode,\n note: NoteNode,\n subgraph: SubgraphNode,\n};\n","import { reconnectEdge as xyReconnectEdge, type Connection, type Edge } from \"@xyflow/react\";\nimport type { FlowGraph, FlowNode } from \"../../types\";\n\n/**\n * Remove nodes AND every edge attached to them.\n *\n * Deleting a node without pruning its edges leaves danglers that point at\n * nothing — they survive a round-trip through the schema and blow up the\n * runner, so the two always move together.\n */\nexport function removeNodes(graph: FlowGraph, ids: string[]): FlowGraph {\n if (ids.length === 0) return graph;\n const doomed = new Set(ids);\n\n return {\n nodes: graph.nodes.filter((n) => !doomed.has(n.id)),\n edges: graph.edges.filter((e) => !doomed.has(e.source) && !doomed.has(e.target)),\n };\n}\n\n/** Remove edges by id, leaving nodes untouched. */\nexport function removeEdges(edges: Edge[], ids: string[]): Edge[] {\n if (ids.length === 0) return edges;\n const doomed = new Set(ids);\n\n return edges.filter((e) => !doomed.has(e.id));\n}\n\n/**\n * Set (or clear) an edge's label.\n *\n * An empty/whitespace label is removed rather than stored as `\"\"` — xyflow\n * renders an empty label as an empty chip on the wire, and a blank key would\n * survive export into the workflow schema.\n */\nexport function setEdgeLabel(edges: Edge[], id: string, label: string | undefined): Edge[] {\n const next = label?.trim();\n return edges.map((e) => {\n if (e.id !== id) return e;\n if (!next) {\n const { label: _drop, ...rest } = e;\n return rest as Edge;\n }\n return { ...e, label: next };\n });\n}\n\n/** Copy a node with a fresh id, offset so it doesn't sit exactly on top. */\nexport function duplicateNode(node: FlowNode, id: string, offset = 40): FlowNode {\n return {\n ...node,\n id,\n position: { x: node.position.x + offset, y: node.position.y + offset },\n // Deep copy so the clone's config edits don't mutate the original.\n data: JSON.parse(JSON.stringify(node.data ?? {})),\n } as FlowNode;\n}\n\n/**\n * Clone a set of nodes AND the edges internal to that set, remapping every id.\n * This is the piece `duplicateNode` lacks: a copy/paste (or duplicate-selection)\n * that preserves the wiring *between* the copied nodes. Edges with an endpoint\n * outside the set are dropped (they'd dangle). A `parentId` pointing inside the\n * set is remapped; one pointing outside is detached.\n */\nexport function cloneSubgraph(\n nodes: FlowNode[],\n edges: Edge[],\n opts: { makeId: () => string; offset?: number },\n): { nodes: FlowNode[]; edges: Edge[]; idMap: Map<string, string> } {\n const offset = opts.offset ?? 40;\n const idMap = new Map<string, string>();\n for (const n of nodes) idMap.set(n.id, opts.makeId());\n\n const clonedNodes = nodes.map((n) => {\n const cloned = duplicateNode(n, idMap.get(n.id)!, offset) as any;\n const parentId = (n as any).parentId;\n if (parentId && idMap.has(parentId)) cloned.parentId = idMap.get(parentId);\n else if (parentId) delete cloned.parentId;\n return cloned as FlowNode;\n });\n\n const clonedEdges = edges\n .filter((e) => idMap.has(e.source) && idMap.has(e.target))\n .map((e) => ({ ...e, id: opts.makeId(), source: idMap.get(e.source)!, target: idMap.get(e.target)! }));\n\n return { nodes: clonedNodes, edges: clonedEdges, idMap };\n}\n\n/**\n * Rewire one edge's endpoint(s) — wraps xyflow's `reconnectEdge`. Keeps the\n * edge's id (`shouldReplaceId: false`) so its label and identity survive the\n * rewire instead of being regenerated from the new endpoints.\n */\nexport function reconnectEdge(edges: Edge[], oldEdge: Edge, newConnection: Connection): Edge[] {\n return xyReconnectEdge(oldEdge, newConnection, edges, { shouldReplaceId: false });\n}\n\nexport type AlignEdge = \"left\" | \"hcenter\" | \"right\" | \"top\" | \"vcenter\" | \"bottom\";\n\nconst nodeW = (n: FlowNode): number => (n as any).width ?? (n as any).measured?.width ?? 0;\nconst nodeH = (n: FlowNode): number => (n as any).height ?? (n as any).measured?.height ?? 0;\n\n/** Align a selection to a shared edge/center of its bounding box. */\nexport function alignNodes(nodes: FlowNode[], edge: AlignEdge): FlowNode[] {\n if (nodes.length < 2) return nodes;\n const minL = Math.min(...nodes.map((n) => n.position.x));\n const maxR = Math.max(...nodes.map((n) => n.position.x + nodeW(n)));\n const minT = Math.min(...nodes.map((n) => n.position.y));\n const maxB = Math.max(...nodes.map((n) => n.position.y + nodeH(n)));\n const cx = (minL + maxR) / 2;\n const cy = (minT + maxB) / 2;\n return nodes.map((n) => {\n let { x, y } = n.position;\n if (edge === \"left\") x = minL;\n else if (edge === \"right\") x = maxR - nodeW(n);\n else if (edge === \"hcenter\") x = cx - nodeW(n) / 2;\n else if (edge === \"top\") y = minT;\n else if (edge === \"bottom\") y = maxB - nodeH(n);\n else if (edge === \"vcenter\") y = cy - nodeH(n) / 2;\n return { ...n, position: { x, y } };\n });\n}\n\n/**\n * Order nodes so every parent precedes its children — xyflow misrenders (and\n * warns) when a child appears before its `parentId` in the array. Stable\n * otherwise. Apply at the render boundary once grouping is in play.\n */\nexport function sortNodesParentFirst<T extends { id: string; parentId?: string }>(nodes: T[]): T[] {\n const byId = new Map(nodes.map((n) => [n.id, n] as const));\n const seen = new Set<string>();\n const out: T[] = [];\n const visit = (n: T) => {\n if (seen.has(n.id)) return;\n const pid = (n as any).parentId as string | undefined;\n if (pid && byId.has(pid) && !seen.has(pid)) visit(byId.get(pid)!);\n seen.add(n.id);\n out.push(n);\n };\n for (const n of nodes) visit(n);\n return out;\n}\n\n/** Absolute position of a node, accounting for one level of parent nesting. */\nfunction absolutePosition(node: FlowNode, nodes: FlowNode[]): { x: number; y: number } {\n const pid = (node as any).parentId as string | undefined;\n if (!pid) return node.position;\n const parent = nodes.find((n) => n.id === pid);\n return parent ? { x: node.position.x + parent.position.x, y: node.position.y + parent.position.y } : node.position;\n}\n\n/**\n * Put a node inside a lane/container: set `parentId` + `extent:'parent'` and\n * convert its position to be relative to the lane. Idempotent-safe; a no-op if\n * either id is missing or they're the same node.\n */\nexport function assignToLane(nodes: FlowNode[], nodeId: string, laneId: string): FlowNode[] {\n if (nodeId === laneId) return nodes;\n const node = nodes.find((n) => n.id === nodeId);\n const lane = nodes.find((n) => n.id === laneId);\n if (!node || !lane) return nodes;\n const abs = absolutePosition(node, nodes);\n const laneAbs = absolutePosition(lane, nodes);\n const rel = { x: abs.x - laneAbs.x, y: abs.y - laneAbs.y };\n return nodes.map((n) => (n.id === nodeId ? ({ ...n, parentId: laneId, extent: \"parent\", position: rel } as FlowNode) : n));\n}\n\n/** Take a node out of its lane: drop `parentId`/`extent`, restore absolute position. */\nexport function removeFromLane(nodes: FlowNode[], nodeId: string): FlowNode[] {\n const node = nodes.find((n) => n.id === nodeId);\n if (!node || !(node as any).parentId) return nodes;\n const abs = absolutePosition(node, nodes);\n return nodes.map((n) => {\n if (n.id !== nodeId) return n;\n const { parentId: _p, extent: _e, ...rest } = n as any;\n return { ...rest, position: abs } as FlowNode;\n });\n}\n\n/**\n * Stack lanes into contiguous rows (horizontal) or columns (vertical) — the\n * \"fixed rows/columns\" behavior. `isLane` picks which nodes are lanes; they're\n * ordered by their current cross-axis position and repacked from the first\n * lane's origin. Each lane keeps its own size (independently resizable).\n */\nexport function stackLanes(\n nodes: FlowNode[],\n isLane: (n: FlowNode) => boolean,\n opts: { orientation?: \"horizontal\" | \"vertical\"; gap?: number } = {},\n): FlowNode[] {\n const orientation = opts.orientation ?? \"horizontal\";\n const gap = opts.gap ?? 12;\n const vertical = orientation === \"vertical\";\n const lanes = nodes.filter(isLane).sort((a, b) => (vertical ? a.position.x - b.position.x : a.position.y - b.position.y));\n if (lanes.length === 0) return nodes;\n const originX = lanes[0].position.x;\n const originY = lanes[0].position.y;\n const moves = new Map<string, { x: number; y: number }>();\n let cursor = vertical ? originX : originY;\n for (const lane of lanes) {\n moves.set(lane.id, vertical ? { x: cursor, y: originY } : { x: originX, y: cursor });\n cursor += (vertical ? ((lane as any).width ?? 320) : ((lane as any).height ?? 160)) + gap;\n }\n return nodes.map((n) => (moves.has(n.id) ? { ...n, position: moves.get(n.id)! } : n));\n}\n\n/** Evenly distribute a selection's gaps along an axis (needs 3+ nodes). */\nexport function distributeNodes(nodes: FlowNode[], axis: \"h\" | \"v\"): FlowNode[] {\n if (nodes.length < 3) return nodes;\n const size = (n: FlowNode) => (axis === \"h\" ? nodeW(n) : nodeH(n));\n const coord = (n: FlowNode) => (axis === \"h\" ? n.position.x : n.position.y);\n const sorted = [...nodes].sort((a, b) => coord(a) - coord(b));\n const start = coord(sorted[0]);\n const last = sorted[sorted.length - 1];\n const end = coord(last) + size(last);\n const totalSize = sorted.reduce((s, n) => s + size(n), 0);\n const gap = (end - start - totalSize) / (sorted.length - 1);\n const posById = new Map<string, number>();\n let cursor = start;\n for (const n of sorted) {\n posById.set(n.id, cursor);\n cursor += size(n) + gap;\n }\n return nodes.map((n) => {\n const p = posById.get(n.id)!;\n return { ...n, position: axis === \"h\" ? { ...n.position, x: p } : { ...n.position, y: p } };\n });\n}\n","import type { FlowNode } from \"../../types\";\n\nexport type HelperLineChange = { id: string; position?: { x: number; y: number } };\n\nexport type HelperLinesResult = {\n /** Y of a horizontal guide line (flow coords), if the drag aligns on Y. */\n horizontal?: number;\n /** X of a vertical guide line (flow coords), if the drag aligns on X. */\n vertical?: number;\n /** The snapped position to apply to the dragged node. */\n snapPosition: { x?: number; y?: number };\n};\n\nconst w = (n: FlowNode): number => (n as any).width ?? (n as any).measured?.width ?? 0;\nconst h = (n: FlowNode): number => (n as any).height ?? (n as any).measured?.height ?? 0;\n\n/**\n * Compute alignment guide lines (and a snapped position) for a node being\n * dragged to `change.position`, against the other nodes. Standard \"helper\n * lines\" algorithm: match the dragged node's left/right/top/bottom edges to any\n * other node's edges within `distance`, snapping to the nearest. Pure + testable.\n */\nexport function getHelperLines(change: HelperLineChange, nodes: FlowNode[], distance = 6): HelperLinesResult {\n const result: HelperLinesResult = { snapPosition: { x: undefined, y: undefined } };\n const a = nodes.find((n) => n.id === change.id);\n if (!a || !change.position) return result;\n\n const A = {\n left: change.position.x,\n right: change.position.x + w(a),\n top: change.position.y,\n bottom: change.position.y + h(a),\n width: w(a),\n height: h(a),\n };\n let vDist = distance;\n let hDist = distance;\n\n for (const b of nodes) {\n if (b.id === a.id) continue;\n const B = { left: b.position.x, right: b.position.x + w(b), top: b.position.y, bottom: b.position.y + h(b) };\n\n // Vertical guides (X alignment).\n const ll = Math.abs(A.left - B.left);\n if (ll < vDist) { result.snapPosition.x = B.left; result.vertical = B.left; vDist = ll; }\n const rr = Math.abs(A.right - B.right);\n if (rr < vDist) { result.snapPosition.x = B.right - A.width; result.vertical = B.right; vDist = rr; }\n const lr = Math.abs(A.left - B.right);\n if (lr < vDist) { result.snapPosition.x = B.right; result.vertical = B.right; vDist = lr; }\n const rl = Math.abs(A.right - B.left);\n if (rl < vDist) { result.snapPosition.x = B.left - A.width; result.vertical = B.left; vDist = rl; }\n\n // Horizontal guides (Y alignment).\n const tt = Math.abs(A.top - B.top);\n if (tt < hDist) { result.snapPosition.y = B.top; result.horizontal = B.top; hDist = tt; }\n const bb = Math.abs(A.bottom - B.bottom);\n if (bb < hDist) { result.snapPosition.y = B.bottom - A.height; result.horizontal = B.bottom; hDist = bb; }\n const tb = Math.abs(A.top - B.bottom);\n if (tb < hDist) { result.snapPosition.y = B.bottom; result.horizontal = B.bottom; hDist = tb; }\n const bt = Math.abs(A.bottom - B.top);\n if (bt < hDist) { result.snapPosition.y = B.top - A.height; result.horizontal = B.top; hDist = bt; }\n }\n\n return result;\n}\n","import { ViewportPortal } from \"@xyflow/react\";\n\n/**\n * HelperLines — alignment guides drawn during a drag. Rendered in flow\n * coordinate space (ViewportPortal), so the lines track pan/zoom. Positions come\n * from `getHelperLines`.\n */\nexport function HelperLines({ horizontal, vertical }: { horizontal?: number; vertical?: number }) {\n if (horizontal === undefined && vertical === undefined) return null;\n return (\n <ViewportPortal>\n {vertical !== undefined && (\n <div\n className=\"ff-helper-line\"\n style={{ position: \"absolute\", transform: `translateX(${vertical}px)`, top: -5000, height: 10000, width: 1, pointerEvents: \"none\" }}\n />\n )}\n {horizontal !== undefined && (\n <div\n className=\"ff-helper-line\"\n style={{ position: \"absolute\", transform: `translateY(${horizontal}px)`, left: -5000, width: 10000, height: 1, pointerEvents: \"none\" }}\n />\n )}\n </ViewportPortal>\n );\n}\n","import { useEffect, useState } from \"react\";\n\n/** The resolved mode React Flow and our own `ff-` tokens both understand. */\nexport type FlowColorMode = \"light\" | \"dark\";\n\n/**\n * What a host may PASS. React Flow's own `ColorMode` includes `\"system\"`, and\n * it is meaningful here rather than something to cast away: it means \"follow\n * the environment\", which is the same job `undefined` now does.\n */\nexport type FlowColorModeInput = FlowColorMode | \"system\";\n\n/**\n * Read the app's theme off the document, the way every host in this suite\n * signals it.\n *\n * Checked in the order a host actually sets them: an explicit `data-theme`\n * beats a `.dark` class (a host that writes both, like the showcase, is\n * consistent either way), and only when neither is present does the OS\n * preference decide.\n */\nfunction readDocumentTheme(): FlowColorMode {\n if (typeof document === \"undefined\") return \"light\";\n\n const root = document.documentElement;\n const attr = root.getAttribute(\"data-theme\");\n if (attr === \"dark\" || attr === \"light\") return attr;\n if (root.classList.contains(\"dark\")) return \"dark\";\n\n return typeof window !== \"undefined\" && window.matchMedia?.(\"(prefers-color-scheme: dark)\").matches\n ? \"dark\"\n : \"light\";\n}\n\n/**\n * The colour mode the canvas should actually use.\n *\n * **Why this exists.** `colorMode` used to be passed straight through to React\n * Flow, so a host that did not supply one got React Flow's own default —\n * `light` — no matter what the surrounding app was doing. Our `ff-` styles\n * still looked right, because they hang off an ancestor `.dark`, which is\n * exactly what made the bug hard to see: the nodes we style were fine while\n * React Flow's own layer stayed light underneath. Any node whose kind is not\n * registered falls back to React Flow's default node, and on a dark page that\n * is a white box with unreadable text. Edges, handles, the selection rectangle\n * and the controls were light too.\n *\n * So an unset `colorMode` now means \"follow the app\", not \"light\". Passing one\n * explicitly still wins — a canvas deliberately pinned light on a dark page is\n * a real thing, and this does not take it away.\n *\n * The subscription matters as much as the initial read: a theme toggle changes\n * an attribute on `<html>`, which triggers no React render on its own, so\n * without an observer the canvas would be correct on load and wrong the moment\n * someone flipped the switch.\n */\nexport function useResolvedColorMode(explicit?: FlowColorModeInput): FlowColorMode {\n // Start light on the server and on first paint. Reading the DOM in the\n // initialiser would differ between server and client markup and trip\n // hydration; the effect below corrects it before anything is visible.\n const [resolved, setResolved] = useState<FlowColorMode>(\"light\");\n\n // `\"system\"` is treated exactly like an unset prop: both mean \"follow the\n // environment\", and collapsing them here keeps one resolution path.\n const pinned = explicit === \"light\" || explicit === \"dark\" ? explicit : undefined;\n\n useEffect(() => {\n if (pinned) return;\n if (typeof document === \"undefined\") return;\n\n const sync = () => setResolved(readDocumentTheme());\n sync();\n\n const observer = new MutationObserver(sync);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\", \"data-theme\"],\n });\n\n const media = window.matchMedia?.(\"(prefers-color-scheme: dark)\");\n media?.addEventListener?.(\"change\", sync);\n\n return () => {\n observer.disconnect();\n media?.removeEventListener?.(\"change\", sync);\n };\n }, [pinned]);\n\n return pinned ?? resolved;\n}\n","import {\n type CSSProperties,\n type ReactNode,\n type WheelEvent as ReactWheelEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n ReactFlow,\n Background,\n BackgroundVariant,\n Controls,\n MiniMap,\n type DefaultEdgeOptions,\n type Edge,\n type EdgeTypes,\n type FitViewOptions,\n type NodeTypes,\n type ReactFlowProps,\n} from \"@xyflow/react\";\nimport \"@xyflow/react/dist/style.css\";\nimport { defaultNodeTypes } from \"../nodes\";\nimport { createConnectionValidator, type ConnectionValidatorOptions } from \"../../registry/connection\";\nimport { sortNodesParentFirst } from \"../FlowEditor/graph-ops\";\nimport { getHelperLines } from \"./helper-lines\";\nimport { HelperLines } from \"./HelperLines\";\nimport type { FlowNode } from \"../../types\";\nimport { useResolvedColorMode } from \"./use-resolved-color-mode\";\n\n/**\n * With wheel-zoom off, Shift+wheel still zooms — and must not ALSO scroll the\n * page while it does. React Flow's own `preventScrolling` is all-or-nothing, so\n * the modifier case is handled here: swallow the gesture that zooms, leave the\n * one that doesn't alone.\n *\n * Capture phase, so it lands before React Flow's own wheel handling.\n */\nfunction preventScrollWhileZooming(event: ReactWheelEvent<HTMLDivElement>): void {\n if (event.shiftKey) event.preventDefault();\n}\n\n/**\n * The three React Flow props that together decide what the wheel does.\n *\n * Extracted because they only make sense as a set, and getting the set wrong is\n * invisible in a screenshot: the canvas looks fine and feels broken. This is\n * the unit worth testing — mounting a canvas to assert it would be testing\n * d3-zoom through jsdom.\n *\n * - **on** (default): no modifier needed, and the page never scrolls under a\n * wheel that is zooming.\n * - **off**: zoom moves to Shift+wheel and the bare wheel goes back to the\n * page. `preventScrolling` alone cannot express that — left true it swallows\n * the bare wheel (page frozen, nothing zooms), left false it lets Shift+wheel\n * zoom *and* scroll at once — so the handler covers the modifier case.\n */\nexport function wheelZoomProps(zoomOnWheel: boolean): {\n zoomActivationKeyCode: string | null;\n preventScrolling: boolean;\n onWheelCapture?: (event: ReactWheelEvent<HTMLDivElement>) => void;\n} {\n return zoomOnWheel\n ? { zoomActivationKeyCode: null, preventScrolling: true }\n : {\n zoomActivationKeyCode: \"Shift\",\n preventScrolling: false,\n onWheelCapture: preventScrollWhileZooming,\n };\n}\n\nexport type FlowCanvasProps = Omit<ReactFlowProps<FlowNode, Edge>, \"nodes\" | \"edges\" | \"height\"> & {\n nodes: FlowNode[];\n edges: Edge[];\n /** Background variant. Default: \"dots\". */\n background?: BackgroundVariant | \"none\";\n /** Show pan/zoom/fit controls. Default true. */\n showControls?: boolean;\n /** Show minimap. Default false (turn on for big graphs). */\n showMinimap?: boolean;\n /** Pixel height; FlowCanvas expects a sized container. Default 600. */\n height?: number | string;\n /**\n * Enforce port-type compatibility on new connections. `true` (default) uses\n * the built-in validator: a connection is refused only when both ports\n * declare a concrete, differing `type` (so untyped graphs are unaffected),\n * and self-loops are blocked. Pass options to tune the rule, or `false` to\n * disable. An `isValidConnection` you pass yourself always takes precedence.\n */\n validateConnections?: boolean | ConnectionValidatorOptions;\n /** Show alignment guide lines while dragging, and snap to them. Default off. */\n showHelperLines?: boolean;\n /**\n * A bare mouse wheel over the canvas zooms it. Default **true**.\n *\n * Turn it off for a canvas embedded mid-page, where a reader scrolling past\n * would otherwise get trapped zooming. With it off the wheel scrolls the page\n * and **Shift+wheel** zooms instead.\n *\n * Either way, a wheel gesture that zooms never also scrolls the page — the\n * two happening at once is the thing that makes an embedded canvas feel\n * broken.\n */\n zoomOnWheel?: boolean;\n /** Optional toolbar / palette etc. rendered above the canvas. */\n toolbar?: ReactNode;\n className?: string;\n style?: CSSProperties;\n};\n\nconst DEFAULT_FIT_VIEW: FitViewOptions = { padding: 0.2 };\nconst DEFAULT_EDGE_OPTIONS: DefaultEdgeOptions = {\n type: \"smoothstep\",\n animated: false,\n};\n\n/**\n * FlowCanvas — themed React Flow surface with the kit's nodes registered\n * by default. Pass your own `nodeTypes` to extend; the kit's defaults are\n * merged behind yours.\n *\n * Hosts wire `onNodesChange` / `onEdgesChange` / `onConnect` themselves\n * (xyflow's standard pattern). The surrounding `useFlowState` hook in\n * `runtime/use-flow-state.ts` is a convenience that wires those for you.\n */\nexport function FlowCanvas({\n nodes,\n edges,\n background = BackgroundVariant.Dots,\n showControls = true,\n showMinimap = false,\n height = 600,\n validateConnections = true,\n isValidConnection,\n colorMode,\n showHelperLines = false,\n zoomOnWheel = true,\n onNodesChange,\n toolbar,\n nodeTypes,\n edgeTypes,\n className,\n style,\n ...rest\n}: FlowCanvasProps) {\n const mergedNodeTypes = useMemo<NodeTypes>(\n () => ({ ...defaultNodeTypes, ...(nodeTypes ?? {}) }),\n [nodeTypes],\n );\n\n // Read nodes live through a ref so the validator (built once) always sees the\n // current graph without being rebuilt on every node change.\n const nodesRef = useRef(nodes);\n nodesRef.current = nodes;\n const builtinValidator = useMemo(\n () =>\n validateConnections === false\n ? undefined\n : createConnectionValidator(\n () => nodesRef.current,\n validateConnections === true ? undefined : validateConnections,\n ),\n [validateConnections],\n );\n // A caller-supplied predicate wins; otherwise fall back to port-type validation.\n const resolvedIsValidConnection = isValidConnection ?? builtinValidator;\n\n const mergedEdgeTypes = useMemo<EdgeTypes | undefined>(\n () => (edgeTypes ? { ...edgeTypes } : undefined),\n [edgeTypes],\n );\n\n // xyflow requires a parent node to precede its children in the array; grouping\n // (swimlanes) can produce any order, so normalize it here at the boundary.\n const orderedNodes = useMemo(() => sortNodesParentFirst(nodes), [nodes]);\n\n // Helper lines: on a single-node drag, snap to aligned edges + show guides.\n const [helperLines, setHelperLines] = useState<{ horizontal?: number; vertical?: number }>({});\n const handleNodesChange = useCallback(\n (changes: any[]) => {\n if (showHelperLines) {\n const pos = changes.filter((c) => c.type === \"position\" && c.position);\n if (pos.length === 1 && pos[0].dragging) {\n const lines = getHelperLines(pos[0], nodesRef.current);\n if (lines.snapPosition.x !== undefined) pos[0].position.x = lines.snapPosition.x;\n if (lines.snapPosition.y !== undefined) pos[0].position.y = lines.snapPosition.y;\n setHelperLines({ horizontal: lines.horizontal, vertical: lines.vertical });\n } else {\n setHelperLines({});\n }\n }\n onNodesChange?.(changes as any);\n },\n [showHelperLines, onNodesChange],\n );\n\n /**\n * An unset `colorMode` means \"follow the app\", NOT \"light\".\n *\n * It used to pass straight through to React Flow, whose own default is\n * light — so on a dark page React Flow's layer stayed light underneath our\n * `ff-` styles, which look right because they hang off an ancestor `.dark`.\n * Any node kind without a registered type falls back to React Flow's default\n * node: a white box with unreadable text on a dark canvas. Passing a mode\n * explicitly still wins.\n */\n const resolvedColorMode = useResolvedColorMode(colorMode);\n\n return (\n <div\n className={[\n \"ff-canvas\",\n // colorMode drives BOTH react-flow's chrome (below) and our `ff-` styles\n // via the shared `.dark` class / light opt-out — one theme signal.\n resolvedColorMode === \"dark\" ? \"dark\" : \"\",\n resolvedColorMode === \"light\" ? \"ff-canvas--light\" : \"\",\n className ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n style={{ height, ...style }}\n >\n {toolbar && <div className=\"ff-canvas__toolbar\">{toolbar}</div>}\n <div className=\"ff-canvas__surface\">\n <ReactFlow\n nodes={orderedNodes}\n edges={edges}\n onNodesChange={handleNodesChange}\n colorMode={resolvedColorMode}\n nodeTypes={mergedNodeTypes}\n edgeTypes={mergedEdgeTypes}\n fitView\n fitViewOptions={DEFAULT_FIT_VIEW}\n defaultEdgeOptions={DEFAULT_EDGE_OPTIONS}\n proOptions={{ hideAttribution: true }}\n // Wheel zooms by default; `zoomOnWheel={false}` moves that onto\n // Shift+wheel and gives the bare wheel back to the page. The three\n // props only make sense as a set — see wheelZoomProps.\n {...wheelZoomProps(zoomOnWheel)}\n isValidConnection={resolvedIsValidConnection}\n {...rest}\n >\n {background !== \"none\" && (\n <Background variant={background as BackgroundVariant} gap={20} size={1} color=\"rgba(0,0,0,0.18)\" />\n )}\n {showControls && <Controls className=\"ff-controls\" position=\"bottom-right\" />}\n {showMinimap && <MiniMap className=\"ff-minimap\" pannable zoomable />}\n {showHelperLines && <HelperLines horizontal={helperLines.horizontal} vertical={helperLines.vertical} />}\n </ReactFlow>\n </div>\n </div>\n );\n}\n","import { useMemo, type CSSProperties, type ReactNode } from \"react\";\nimport { FlowCanvas } from \"../canvas\";\nimport { buildNodeTypes } from \"../../registry\";\nimport { categoryAccent, getNodeKind } from \"../../registry/registry\";\nimport type { FlowGraph, FlowNode } from \"../../types\";\n\n/** Outcome of one node in a run, for annotating the graph after the fact. */\nexport type FlowNodeStatus = \"ok\" | \"running\" | \"failed\" | \"skipped\" | \"pending\";\n\nexport interface FlowViewerClassNames {\n root?: string;\n list?: string;\n row?: string;\n rowIndex?: string;\n rowTitle?: string;\n rowDescription?: string;\n rowStatus?: string;\n}\n\nexport interface FlowViewerProps {\n /** The graph to show. */\n graph: FlowGraph;\n /**\n * `canvas` draws the graph. `list` renders the nodes as rows — for a docs\n * page, a narrow column, print, or an audit view, where a pan-zoom surface is\n * the wrong shape and often not usable at all.\n */\n variant?: \"canvas\" | \"list\";\n /** Canvas height. Ignored by `list`. Default 480. */\n height?: number | string;\n /** Canvas minimap. Default false. */\n showMinimap?: boolean;\n /** Canvas pan/zoom/fit controls. Default true. */\n showControls?: boolean;\n /**\n * Per-node run outcome, keyed by node id. Lets the same component serve\n * \"here is the workflow\" and \"here is what happened on Tuesday\".\n */\n statuses?: Record<string, FlowNodeStatus>;\n /** Controlled selection. */\n selectedNodeId?: string | null;\n /** Omit and nothing is clickable — a viewer with no handler is inert. */\n onSelectNode?: (node: FlowNode) => void;\n className?: string;\n classNames?: FlowViewerClassNames;\n style?: CSSProperties;\n /** Rendered when the graph has no nodes. */\n empty?: ReactNode;\n}\n\nconst STATUS_LABEL: Record<FlowNodeStatus, string> = {\n ok: \"ok\",\n running: \"running\",\n failed: \"failed\",\n skipped: \"skipped\",\n pending: \"pending\",\n};\n\n/**\n * FlowViewer — a workflow, read-only.\n *\n * **Read-only by construction, not by configuration.** There is no prop that\n * makes this editable, because a viewer that can be switched into an editor is\n * a viewer somebody eventually switches into an editor by accident. Before this\n * existed the only way to show a flow was `FlowEditor` (the whole editor) or\n * `FlowCanvas` plus four React Flow flags a consumer had to know to pass —\n * assembly, not an affordance, and nothing stopped the next person shipping a\n * fully editable canvas where they wanted a picture.\n *\n * Node titles come from the registry, so `overrideNodeKind()` renames apply\n * here too.\n */\nexport function FlowViewer({\n graph,\n variant = \"canvas\",\n height = 480,\n showMinimap = false,\n showControls = true,\n statuses,\n selectedNodeId = null,\n onSelectNode,\n className,\n classNames = {},\n style,\n empty,\n}: FlowViewerProps) {\n const nodeTypes = useMemo(() => buildNodeTypes(), []);\n\n const rows = useMemo(\n () =>\n graph.nodes.map((node, index) => {\n const kind = getNodeKind(node.data?.kind ?? node.type ?? \"\");\n return {\n node,\n index,\n // The node's own label is the name the AUTHOR gave THIS node (\"Summarize\");\n // the kind label is the generic type name (\"LLM Call\"). Specific wins.\n title: node.data?.label ?? kind?.label ?? node.data?.kind ?? node.id,\n description: kind?.description ?? null,\n accent: kind?.accent ?? categoryAccent(kind?.category ?? \"custom\"),\n status: statuses?.[node.id] ?? null,\n };\n }),\n [graph.nodes, statuses],\n );\n\n if (graph.nodes.length === 0) {\n return (\n <div className={cx(\"ff-viewer ff-viewer--empty\", className, classNames.root)} style={style}>\n {empty ?? <span className=\"ff-viewer__empty\">This flow has no nodes.</span>}\n </div>\n );\n }\n\n if (variant === \"list\") {\n return (\n <div\n className={cx(\"ff-viewer ff-viewer--list\", className, classNames.root)}\n style={style}\n data-flow-viewer=\"list\"\n >\n <ol className={cx(\"ff-viewer__list\", classNames.list)}>\n {rows.map(({ node, index, title, description, accent, status }) => {\n const selected = node.id === selectedNodeId;\n const Row = onSelectNode ? \"button\" : \"div\";\n\n return (\n <li key={node.id}>\n <Row\n {...(onSelectNode\n ? { type: \"button\" as const, onClick: () => onSelectNode(node) }\n : {})}\n className={cx(\n \"ff-viewer__row\",\n selected && \"ff-viewer__row--selected\",\n onSelectNode && \"ff-viewer__row--interactive\",\n classNames.row,\n )}\n data-flow-viewer-node={node.id}\n data-flow-viewer-status={status ?? undefined}\n aria-current={selected || undefined}\n >\n <span\n className={cx(\"ff-viewer__index\", classNames.rowIndex)}\n style={{ backgroundColor: accent }}\n aria-hidden\n >\n {index + 1}\n </span>\n\n <span className=\"ff-viewer__body\">\n <span className={cx(\"ff-viewer__title\", classNames.rowTitle)}>{title}</span>\n {description && (\n <span className={cx(\"ff-viewer__desc\", classNames.rowDescription)}>\n {description}\n </span>\n )}\n </span>\n\n {status && (\n <span\n className={cx(\n \"ff-viewer__status\",\n `ff-viewer__status--${status}`,\n classNames.rowStatus,\n )}\n >\n {STATUS_LABEL[status]}\n </span>\n )}\n </Row>\n </li>\n );\n })}\n </ol>\n </div>\n );\n }\n\n return (\n <div\n className={cx(\"ff-viewer ff-viewer--canvas\", className, classNames.root)}\n style={style}\n data-flow-viewer=\"canvas\"\n >\n <FlowCanvas\n nodes={graph.nodes}\n edges={graph.edges}\n nodeTypes={nodeTypes}\n height={height}\n showControls={showControls}\n showMinimap={showMinimap}\n // The read-only contract. Every mutation path React Flow offers is\n // closed here rather than left to the caller to remember.\n nodesDraggable={false}\n nodesConnectable={false}\n nodesFocusable={Boolean(onSelectNode)}\n edgesFocusable={false}\n elementsSelectable={Boolean(onSelectNode)}\n deleteKeyCode={null}\n selectionKeyCode={null}\n multiSelectionKeyCode={null}\n connectOnClick={false}\n // A canvas embedded mid-page must not trap a reader's scroll.\n zoomOnScroll={false}\n onNodeClick={onSelectNode ? (_, node) => onSelectNode(node as FlowNode) : undefined}\n fitView\n />\n </div>\n );\n}\n\nfunction cx(...parts: Array<string | false | null | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/nodes/NodeShell.tsx","../src/components/nodes/TriggerNode.tsx","../src/components/nodes/ActionNode.tsx","../src/components/nodes/DecisionNode.tsx","../src/components/nodes/OutputNode.tsx","../src/components/nodes/SubgraphNode.tsx","../src/components/nodes/index.ts","../src/components/FlowEditor/graph-ops.ts","../src/components/canvas/helper-lines.ts","../src/components/canvas/HelperLines.tsx","../src/components/canvas/use-resolved-color-mode.ts","../src/components/canvas/FlowCanvas.tsx","../src/components/FlowViewer/FlowViewer.tsx"],"names":["jsx","memo","jsxs","reconnectEdge","cx","useState","useMemo","index"],"mappings":";;;;;AAyBA,SAAS,cAAA,CAAe;AAAA,EACtB,IAAA;AAAA,EACA,MAAA;AAAA,EACA,GAAA;AAAA,EACA,IAAA;AAAA,EACA,UAAA,GAAa,IAAA;AAAA,EACb,WAAA,GAAc,IAAA;AAAA,EACd;AACF,CAAA,EAAmB;AACjB,EAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAClB,EAAA,MAAM,MAAA,GAAwB,KAAK,MAAA,IAAU,MAAA;AAC7C,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,MAAA,IAAU,aAAA,CAAc,UAAU,CAAA;AACtD,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,IAAW,cAAA,CAAe,WAAW,CAAA;AAE1D,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,CAAC,SAAA,EAAW,CAAA,gBAAA,EAAmB,MAAM,CAAA,CAAA,EAAI,IAAA,CAAK,QAAA,GAAW,mBAAA,GAAsB,EAAE,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,MACtH,OAAO,EAAE,WAAA,EAAa,IAAA,CAAK,QAAA,GAAW,SAAS,MAAA,EAAU;AAAA,MAEzD,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,YAAO,SAAA,EAAU,iBAAA,EAAkB,OAAO,EAAE,UAAA,EAAY,QAAO,EAC9D,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,UAAK,SAAA,EAAU,eAAA,EAAgB,aAAA,EAAW,IAAA,EAAE,kBAAQ,IAAA,EAAK,CAAA;AAAA,0BAC1D,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,cAAA,EAAgB,QAAA,EAAA,GAAA,EAAI,CAAA;AAAA,0BACpC,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gBAAA,EAAkB,eAAK,KAAA,EAAM,CAAA;AAAA,UAC5C,MAAA,KAAW,MAAA,oBAAU,GAAA,CAAC,SAAA,EAAA,EAAU,MAAA,EAAgB;AAAA,SAAA,EACnD,CAAA;AAAA,QAEC,KAAK,WAAA,oBAAe,GAAA,CAAC,OAAE,SAAA,EAAU,eAAA,EAAiB,eAAK,WAAA,EAAY,CAAA;AAAA,QACnE,QAAA,oBAAY,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,iBAAiB,QAAA,EAAS,CAAA;AAAA,QACrD,KAAK,UAAA,oBAAc,GAAA,CAAC,OAAE,SAAA,EAAU,sBAAA,EAAwB,eAAK,UAAA,EAAW,CAAA;AAAA,QAExE,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,qBACd,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YAEC,IAAA,EAAK,QAAA;AAAA,YACL,UAAU,QAAA,CAAS,IAAA;AAAA,YACnB,IAAI,CAAA,CAAE,EAAA;AAAA,YACN,KAAA,EAAO,SAAA,CAAU,CAAA,EAAG,MAAA,CAAO,MAAM,CAAA;AAAA,YACjC,KAAA,EAAO,CAAA,CAAE,KAAA,IAAS,CAAA,CAAE;AAAA,WAAA;AAAA,UALf,CAAA,CAAE;AAAA,SAOV,CAAA;AAAA,QACA,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,qBACf,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YAEC,IAAA,EAAK,QAAA;AAAA,YACL,UAAU,QAAA,CAAS,KAAA;AAAA,YACnB,IAAI,CAAA,CAAE,EAAA;AAAA,YACN,KAAA,EAAO,SAAA,CAAU,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA;AAAA,YAClC,KAAA,EAAO,CAAA,CAAE,KAAA,IAAS,CAAA,CAAE;AAAA,WAAA;AAAA,UALf,CAAA,CAAE;AAAA,SAOV;AAAA;AAAA;AAAA,GACH;AAEJ;AAEO,IAAM,SAAA,GAAY,KAAK,cAAc;AAE5C,SAAS,cAAc,IAAA,EAAiC;AACtD,EAAA,OAAO,OAAO,CAAC,EAAE,IAAI,IAAA,EAAM,IAAI,EAAC;AAClC;AACA,SAAS,eAAe,IAAA,EAAiC;AACvD,EAAA,OAAO,OAAO,CAAC,EAAE,IAAI,KAAA,EAAO,IAAI,EAAC;AACnC;AAEA,SAAS,SAAA,CAAU,GAAW,KAAA,EAAoC;AAChE,EAAA,IAAI,KAAA,IAAS,CAAA,EAAG,OAAO,EAAC;AACxB,EAAA,MAAM,IAAA,GAAQ,GAAA,IAAO,KAAA,GAAQ,CAAA,CAAA,IAAO,CAAA,GAAI,CAAA,CAAA;AACxC,EAAA,OAAO,EAAE,GAAA,EAAK,CAAA,EAAG,IAAI,CAAA,CAAA,CAAA,EAAI;AAC3B;AAEA,SAAS,SAAA,CAAU,EAAE,MAAA,EAAO,EAA8B;AACxD,EAAA,uBAAO,GAAA,CAAC,UAAK,SAAA,EAAW,CAAA,2BAAA,EAA8B,MAAM,CAAA,CAAA,EAAI,YAAA,EAAY,CAAA,OAAA,EAAU,MAAM,CAAA,CAAA,EAAI,CAAA;AAClG;AC1FA,SAAS,iBAAiB,KAAA,EAA4B;AACpD,EAAA,uBAAOA,GAAAA,CAAC,SAAA,EAAA,EAAU,IAAA,EAAM,KAAA,EAAO,MAAA,EAAO,SAAA,EAAU,GAAA,EAAI,SAAA,EAAU,IAAA,EAAK,QAAA,EAAI,UAAA,EAAY,KAAA,EAAO,CAAA;AAC5F;AACO,IAAM,WAAA,GAAcC,KAAK,gBAAgB;ACHhD,SAAS,gBAAgB,KAAA,EAA4B;AACnD,EAAA,uBAAOD,GAAAA,CAAC,SAAA,EAAA,EAAU,IAAA,EAAM,KAAA,EAAO,QAAO,SAAA,EAAU,GAAA,EAAI,QAAA,EAAS,IAAA,EAAK,QAAA,EAAI,CAAA;AACxE;AACO,IAAM,UAAA,GAAaC,KAAK,eAAe;ACJ9C,IAAM,gBAAA,GAAqC;AAAA,EACzC,EAAE,EAAA,EAAI,MAAA,EAAQ,KAAA,EAAO,MAAA,EAAO;AAAA,EAC5B,EAAE,EAAA,EAAI,OAAA,EAAS,KAAA,EAAO,OAAA;AACxB,CAAA;AAGA,SAAS,kBAAkB,KAAA,EAA4B;AAErD,EAAA,IAAI,CAAC,KAAA,CAAM,IAAA,CAAK,OAAA,EAAS;AACvB,IAAA,KAAA,GAAQ,EAAE,GAAG,KAAA,EAAO,IAAA,EAAM,EAAE,GAAG,KAAA,CAAM,IAAA,EAAM,OAAA,EAAS,gBAAA,EAAiB,EAAE;AAAA,EACzE;AACA,EAAA,uBAAOD,GAAAA,CAAC,SAAA,EAAA,EAAU,IAAA,EAAM,KAAA,EAAO,QAAO,SAAA,EAAU,GAAA,EAAI,UAAA,EAAW,IAAA,EAAK,QAAA,EAAI,CAAA;AAC1E;AACO,IAAM,YAAA,GAAeC,KAAK,iBAAiB;ACZlD,SAAS,gBAAgB,KAAA,EAA4B;AACnD,EAAA,uBAAOD,GAAAA,CAAC,SAAA,EAAA,EAAU,IAAA,EAAM,KAAA,EAAO,MAAA,EAAO,SAAA,EAAU,GAAA,EAAI,QAAA,EAAS,IAAA,EAAK,QAAA,EAAI,WAAA,EAAa,KAAA,EAAO,CAAA;AAC5F;AACO,IAAM,UAAA,GAAaC,KAAK,eAAe;ACM9C,SAAS,kBAAkB,KAAA,EAA4B;AACrD,EAAA,MAAM,OAAO,KAAA,CAAM,IAAA;AACnB,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,QAAA,EAAU,MAAA,IAAU,CAAA;AAC5C,EAAA,uBACED,GAAAA,CAAC,SAAA,EAAA,EAAU,IAAA,EAAM,OAAO,MAAA,EAAO,SAAA,EAAU,GAAA,EAAI,UAAA,EAAW,MAAK,QAAA,EAC3D,QAAA,kBAAAE,IAAAA,CAAC,KAAA,EAAA,EAAI,WAAU,mBAAA,EACb,QAAA,EAAA;AAAA,oBAAAA,KAAC,MAAA,EAAA,EAAM,QAAA,EAAA;AAAA,MAAA,UAAA;AAAA,MAAW,OAAA;AAAA,MAAM,UAAA,KAAe,IAAI,EAAA,GAAK;AAAA,KAAA,EAAI,CAAA;AAAA,oBACpDF,GAAAA,CAAC,MAAA,EAAA,EAAM,eAAK,SAAA,KAAc,KAAA,GAAQ,aAAa,WAAA,EAAY;AAAA,GAAA,EAC7D,CAAA,EACF,CAAA;AAEJ;AACO,IAAM,YAAA,GAAeC,KAAK,iBAAiB;;;ACV3C,IAAM,gBAAA,GAA8B;AAAA,EACzC,OAAA,EAAS,WAAA;AAAA,EACT,MAAA,EAAQ,UAAA;AAAA,EACR,QAAA,EAAU,YAAA;AAAA,EACV,MAAA,EAAQ,UAAA;AAAA,EACR,IAAA,EAAM,QAAA;AAAA,EACN,QAAA,EAAU;AACZ;;;ACdO,SAAS,WAAA,CAAY,OAAkB,GAAA,EAA0B;AACtE,EAAA,IAAI,GAAA,CAAI,MAAA,KAAW,CAAA,EAAG,OAAO,KAAA;AAC7B,EAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAE1B,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,KAAA,CAAM,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,EAAE,CAAC,CAAA;AAAA,IAClD,OAAO,KAAA,CAAM,KAAA,CAAM,MAAA,CAAO,CAAC,MAAM,CAAC,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,MAAM,CAAA,IAAK,CAAC,OAAO,GAAA,CAAI,CAAA,CAAE,MAAM,CAAC;AAAA,GACjF;AACF;AAGO,SAAS,WAAA,CAAY,OAAe,GAAA,EAAuB;AAChE,EAAA,IAAI,GAAA,CAAI,MAAA,KAAW,CAAA,EAAG,OAAO,KAAA;AAC7B,EAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,GAAG,CAAA;AAE1B,EAAA,OAAO,KAAA,CAAM,OAAO,CAAC,CAAA,KAAM,CAAC,MAAA,CAAO,GAAA,CAAI,CAAA,CAAE,EAAE,CAAC,CAAA;AAC9C;AASO,SAAS,YAAA,CAAa,KAAA,EAAe,EAAA,EAAY,KAAA,EAAmC;AACzF,EAAA,MAAM,IAAA,GAAO,OAAO,IAAA,EAAK;AACzB,EAAA,OAAO,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM;AACtB,IAAA,IAAI,CAAA,CAAE,EAAA,KAAO,EAAA,EAAI,OAAO,CAAA;AACxB,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,MAAM,EAAE,KAAA,EAAO,KAAA,EAAO,GAAG,MAAK,GAAI,CAAA;AAClC,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,EAAE,GAAG,CAAA,EAAG,KAAA,EAAO,IAAA,EAAK;AAAA,EAC7B,CAAC,CAAA;AACH;AAGO,SAAS,aAAA,CAAc,IAAA,EAAgB,EAAA,EAAY,MAAA,GAAS,EAAA,EAAc;AAC/E,EAAA,OAAO;AAAA,IACL,GAAG,IAAA;AAAA,IACH,EAAA;AAAA,IACA,QAAA,EAAU,EAAE,CAAA,EAAG,IAAA,CAAK,QAAA,CAAS,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAG,IAAA,CAAK,QAAA,CAAS,CAAA,GAAI,MAAA,EAAO;AAAA;AAAA,IAErE,IAAA,EAAM,KAAK,KAAA,CAAM,IAAA,CAAK,UAAU,IAAA,CAAK,IAAA,IAAQ,EAAE,CAAC;AAAA,GAClD;AACF;AASO,SAAS,aAAA,CACd,KAAA,EACA,KAAA,EACA,IAAA,EACkE;AAClE,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,IAAU,EAAA;AAC9B,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAoB;AACtC,EAAA,KAAA,MAAW,CAAA,IAAK,OAAO,KAAA,CAAM,GAAA,CAAI,EAAE,EAAA,EAAI,IAAA,CAAK,QAAQ,CAAA;AAEpD,EAAA,MAAM,WAAA,GAAc,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM;AACnC,IAAA,MAAM,MAAA,GAAS,cAAc,CAAA,EAAG,KAAA,CAAM,IAAI,CAAA,CAAE,EAAE,GAAI,MAAM,CAAA;AACxD,IAAA,MAAM,WAAY,CAAA,CAAU,QAAA;AAC5B,IAAA,IAAI,QAAA,IAAY,MAAM,GAAA,CAAI,QAAQ,GAAG,MAAA,CAAO,QAAA,GAAW,KAAA,CAAM,GAAA,CAAI,QAAQ,CAAA;AAAA,SAAA,IAChE,QAAA,SAAiB,MAAA,CAAO,QAAA;AACjC,IAAA,OAAO,MAAA;AAAA,EACT,CAAC,CAAA;AAED,EAAA,MAAM,cAAc,KAAA,CACjB,MAAA,CAAO,CAAC,CAAA,KAAM,MAAM,GAAA,CAAI,CAAA,CAAE,MAAM,CAAA,IAAK,MAAM,GAAA,CAAI,CAAA,CAAE,MAAM,CAAC,CAAA,CACxD,IAAI,CAAC,CAAA,MAAO,EAAE,GAAG,GAAG,EAAA,EAAI,IAAA,CAAK,MAAA,EAAO,EAAG,QAAQ,KAAA,CAAM,GAAA,CAAI,CAAA,CAAE,MAAM,GAAI,MAAA,EAAQ,KAAA,CAAM,IAAI,CAAA,CAAE,MAAM,GAAG,CAAE,CAAA;AAEvG,EAAA,OAAO,EAAE,KAAA,EAAO,WAAA,EAAa,KAAA,EAAO,aAAa,KAAA,EAAM;AACzD;AAOO,SAASE,cAAAA,CAAc,KAAA,EAAe,OAAA,EAAe,aAAA,EAAmC;AAC7F,EAAA,OAAO,cAAgB,OAAA,EAAS,aAAA,EAAe,OAAO,EAAE,eAAA,EAAiB,OAAO,CAAA;AAClF;AAIA,IAAM,QAAQ,CAAC,CAAA,KAAyB,EAAU,KAAA,IAAU,CAAA,CAAU,UAAU,KAAA,IAAS,CAAA;AACzF,IAAM,QAAQ,CAAC,CAAA,KAAyB,EAAU,MAAA,IAAW,CAAA,CAAU,UAAU,MAAA,IAAU,CAAA;AAGpF,SAAS,UAAA,CAAW,OAAmB,IAAA,EAA6B;AACzE,EAAA,IAAI,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG,OAAO,KAAA;AAC7B,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,GAAG,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,CAAS,CAAC,CAAC,CAAA;AACvD,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,GAAG,MAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,CAAS,CAAA,GAAI,KAAA,CAAM,CAAC,CAAC,CAAC,CAAA;AAClE,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,GAAG,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,CAAS,CAAC,CAAC,CAAA;AACvD,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,GAAG,MAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,QAAA,CAAS,CAAA,GAAI,KAAA,CAAM,CAAC,CAAC,CAAC,CAAA;AAClE,EAAA,MAAMC,GAAAA,GAAAA,CAAM,OAAO,IAAA,IAAQ,CAAA;AAC3B,EAAA,MAAM,EAAA,GAAA,CAAM,OAAO,IAAA,IAAQ,CAAA;AAC3B,EAAA,OAAO,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM;AACtB,IAAA,IAAI,EAAE,CAAA,EAAG,CAAA,EAAE,GAAI,CAAA,CAAE,QAAA;AACjB,IAAA,IAAI,IAAA,KAAS,QAAQ,CAAA,GAAI,IAAA;AAAA,SAAA,IAChB,IAAA,KAAS,OAAA,EAAS,CAAA,GAAI,IAAA,GAAO,MAAM,CAAC,CAAA;AAAA,SAAA,IACpC,SAAS,SAAA,EAAW,CAAA,GAAIA,GAAAA,GAAK,KAAA,CAAM,CAAC,CAAA,GAAI,CAAA;AAAA,SAAA,IACxC,IAAA,KAAS,OAAO,CAAA,GAAI,IAAA;AAAA,SAAA,IACpB,IAAA,KAAS,QAAA,EAAU,CAAA,GAAI,IAAA,GAAO,MAAM,CAAC,CAAA;AAAA,SAAA,IACrC,SAAS,SAAA,EAAW,CAAA,GAAI,EAAA,GAAK,KAAA,CAAM,CAAC,CAAA,GAAI,CAAA;AACjD,IAAA,OAAO,EAAE,GAAG,CAAA,EAAG,UAAU,EAAE,CAAA,EAAG,GAAE,EAAE;AAAA,EACpC,CAAC,CAAA;AACH;AAOO,SAAS,qBAAkE,KAAA,EAAiB;AACjG,EAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,EAAA,EAAI,CAAC,CAAU,CAAC,CAAA;AACzD,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,MAAM,MAAW,EAAC;AAClB,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,KAAS;AACtB,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,EAAE,CAAA,EAAG;AACpB,IAAA,MAAM,MAAO,CAAA,CAAU,QAAA;AACvB,IAAA,IAAI,GAAA,IAAO,IAAA,CAAK,GAAA,CAAI,GAAG,KAAK,CAAC,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,EAAG,KAAA,CAAM,IAAA,CAAK,GAAA,CAAI,GAAG,CAAE,CAAA;AAChE,IAAA,IAAA,CAAK,GAAA,CAAI,EAAE,EAAE,CAAA;AACb,IAAA,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,EACZ,CAAA;AACA,EAAA,KAAA,MAAW,CAAA,IAAK,KAAA,EAAO,KAAA,CAAM,CAAC,CAAA;AAC9B,EAAA,OAAO,GAAA;AACT;AAGA,SAAS,gBAAA,CAAiB,MAAgB,KAAA,EAA6C;AACrF,EAAA,MAAM,MAAO,IAAA,CAAa,QAAA;AAC1B,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,IAAA,CAAK,QAAA;AACtB,EAAA,MAAM,SAAS,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,GAAG,CAAA;AAC7C,EAAA,OAAO,SAAS,EAAE,CAAA,EAAG,IAAA,CAAK,QAAA,CAAS,IAAI,MAAA,CAAO,QAAA,CAAS,CAAA,EAAG,CAAA,EAAG,KAAK,QAAA,CAAS,CAAA,GAAI,OAAO,QAAA,CAAS,CAAA,KAAM,IAAA,CAAK,QAAA;AAC5G;AAOO,SAAS,YAAA,CAAa,KAAA,EAAmB,MAAA,EAAgB,MAAA,EAA4B;AAC1F,EAAA,IAAI,MAAA,KAAW,QAAQ,OAAO,KAAA;AAC9B,EAAA,MAAM,OAAO,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,MAAM,CAAA;AAC9C,EAAA,MAAM,OAAO,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,MAAM,CAAA;AAC9C,EAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,IAAA,EAAM,OAAO,KAAA;AAC3B,EAAA,MAAM,GAAA,GAAM,gBAAA,CAAiB,IAAA,EAAM,KAAK,CAAA;AACxC,EAAA,MAAM,OAAA,GAAU,gBAAA,CAAiB,IAAA,EAAM,KAAK,CAAA;AAC5C,EAAA,MAAM,GAAA,GAAM,EAAE,CAAA,EAAG,GAAA,CAAI,CAAA,GAAI,OAAA,CAAQ,CAAA,EAAG,CAAA,EAAG,GAAA,CAAI,CAAA,GAAI,OAAA,CAAQ,CAAA,EAAE;AACzD,EAAA,OAAO,MAAM,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,OAAO,MAAA,GAAU,EAAE,GAAG,CAAA,EAAG,UAAU,MAAA,EAAQ,MAAA,EAAQ,UAAU,QAAA,EAAU,GAAA,KAAqB,CAAE,CAAA;AAC3H;AAGO,SAAS,cAAA,CAAe,OAAmB,MAAA,EAA4B;AAC5E,EAAA,MAAM,OAAO,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,OAAO,MAAM,CAAA;AAC9C,EAAA,IAAI,CAAC,IAAA,IAAQ,CAAE,IAAA,CAAa,UAAU,OAAO,KAAA;AAC7C,EAAA,MAAM,GAAA,GAAM,gBAAA,CAAiB,IAAA,EAAM,KAAK,CAAA;AACxC,EAAA,OAAO,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM;AACtB,IAAA,IAAI,CAAA,CAAE,EAAA,KAAO,MAAA,EAAQ,OAAO,CAAA;AAC5B,IAAA,MAAM,EAAE,QAAA,EAAU,EAAA,EAAI,QAAQ,EAAA,EAAI,GAAG,MAAK,GAAI,CAAA;AAC9C,IAAA,OAAO,EAAE,GAAG,IAAA,EAAM,QAAA,EAAU,GAAA,EAAI;AAAA,EAClC,CAAC,CAAA;AACH;AA8BO,SAAS,eAAA,CAAgB,OAAmB,IAAA,EAA6B;AAC9E,EAAA,IAAI,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG,OAAO,KAAA;AAC7B,EAAA,MAAM,IAAA,GAAO,CAAC,CAAA,KAAiB,IAAA,KAAS,MAAM,KAAA,CAAM,CAAC,CAAA,GAAI,KAAA,CAAM,CAAC,CAAA;AAChE,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,KAAiB,IAAA,KAAS,MAAM,CAAA,CAAE,QAAA,CAAS,CAAA,GAAI,CAAA,CAAE,QAAA,CAAS,CAAA;AACzE,EAAA,MAAM,MAAA,GAAS,CAAC,GAAG,KAAK,EAAE,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,KAAA,CAAM,CAAC,CAAA,GAAI,KAAA,CAAM,CAAC,CAAC,CAAA;AAC5D,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,MAAA,CAAO,CAAC,CAAC,CAAA;AAC7B,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,MAAA,CAAO,MAAA,GAAS,CAAC,CAAA;AACrC,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,IAAI,CAAA,GAAI,KAAK,IAAI,CAAA;AACnC,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,EAAG,MAAM,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA,EAAG,CAAC,CAAA;AACxD,EAAA,MAAM,GAAA,GAAA,CAAO,GAAA,GAAM,KAAA,GAAQ,SAAA,KAAc,OAAO,MAAA,GAAS,CAAA,CAAA;AACzD,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAoB;AACxC,EAAA,IAAI,MAAA,GAAS,KAAA;AACb,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,IAAA,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,EAAA,EAAI,MAAM,CAAA;AACxB,IAAA,MAAA,IAAU,IAAA,CAAK,CAAC,CAAA,GAAI,GAAA;AAAA,EACtB;AACA,EAAA,OAAO,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM;AACtB,IAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,GAAA,CAAI,CAAA,CAAE,EAAE,CAAA;AAC1B,IAAA,OAAO,EAAE,GAAG,CAAA,EAAG,UAAU,IAAA,KAAS,GAAA,GAAM,EAAE,GAAG,CAAA,CAAE,UAAU,CAAA,EAAG,CAAA,KAAM,EAAE,GAAG,EAAE,QAAA,EAAU,CAAA,EAAG,GAAE,EAAE;AAAA,EAC5F,CAAC,CAAA;AACH;;;ACvNA,IAAM,IAAI,CAAC,CAAA,KAAyB,EAAU,KAAA,IAAU,CAAA,CAAU,UAAU,KAAA,IAAS,CAAA;AACrF,IAAM,IAAI,CAAC,CAAA,KAAyB,EAAU,MAAA,IAAW,CAAA,CAAU,UAAU,MAAA,IAAU,CAAA;AAQhF,SAAS,cAAA,CAAe,MAAA,EAA0B,KAAA,EAAmB,QAAA,GAAW,CAAA,EAAsB;AAC3G,EAAA,MAAM,MAAA,GAA4B,EAAE,YAAA,EAAc,EAAE,GAAG,MAAA,EAAW,CAAA,EAAG,QAAU,EAAE;AACjF,EAAA,MAAM,CAAA,GAAI,MAAM,IAAA,CAAK,CAAC,MAAM,CAAA,CAAE,EAAA,KAAO,OAAO,EAAE,CAAA;AAC9C,EAAA,IAAI,CAAC,CAAA,IAAK,CAAC,MAAA,CAAO,UAAU,OAAO,MAAA;AAEnC,EAAA,MAAM,CAAA,GAAI;AAAA,IACR,IAAA,EAAM,OAAO,QAAA,CAAS,CAAA;AAAA,IACtB,KAAA,EAAO,MAAA,CAAO,QAAA,CAAS,CAAA,GAAI,EAAE,CAAC,CAAA;AAAA,IAC9B,GAAA,EAAK,OAAO,QAAA,CAAS,CAAA;AAAA,IACrB,MAAA,EAAQ,MAAA,CAAO,QAAA,CAAS,CAAA,GAAI,EAAE,CAAC,CAAA;AAAA,IAC/B,KAAA,EAAO,EAAE,CAAC,CAAA;AAAA,IACV,MAAA,EAAQ,EAAE,CAAC;AAAA,GACb;AACA,EAAA,IAAI,KAAA,GAAQ,QAAA;AACZ,EAAA,IAAI,KAAA,GAAQ,QAAA;AAEZ,EAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,IAAA,IAAI,CAAA,CAAE,EAAA,KAAO,CAAA,CAAE,EAAA,EAAI;AACnB,IAAA,MAAM,CAAA,GAAI,EAAE,IAAA,EAAM,CAAA,CAAE,SAAS,CAAA,EAAG,KAAA,EAAO,CAAA,CAAE,QAAA,CAAS,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,EAAG,GAAA,EAAK,CAAA,CAAE,QAAA,CAAS,CAAA,EAAG,MAAA,EAAQ,EAAE,QAAA,CAAS,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,EAAE;AAG3G,IAAA,MAAM,KAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,IAAA,GAAO,EAAE,IAAI,CAAA;AACnC,IAAA,IAAI,KAAK,KAAA,EAAO;AAAE,MAAA,MAAA,CAAO,YAAA,CAAa,IAAI,CAAA,CAAE,IAAA;AAAM,MAAA,MAAA,CAAO,WAAW,CAAA,CAAE,IAAA;AAAM,MAAA,KAAA,GAAQ,EAAA;AAAA,IAAI;AACxF,IAAA,MAAM,KAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,KAAA,GAAQ,EAAE,KAAK,CAAA;AACrC,IAAA,IAAI,KAAK,KAAA,EAAO;AAAE,MAAA,MAAA,CAAO,YAAA,CAAa,CAAA,GAAI,CAAA,CAAE,KAAA,GAAQ,CAAA,CAAE,KAAA;AAAO,MAAA,MAAA,CAAO,WAAW,CAAA,CAAE,KAAA;AAAO,MAAA,KAAA,GAAQ,EAAA;AAAA,IAAI;AACpG,IAAA,MAAM,KAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,IAAA,GAAO,EAAE,KAAK,CAAA;AACpC,IAAA,IAAI,KAAK,KAAA,EAAO;AAAE,MAAA,MAAA,CAAO,YAAA,CAAa,IAAI,CAAA,CAAE,KAAA;AAAO,MAAA,MAAA,CAAO,WAAW,CAAA,CAAE,KAAA;AAAO,MAAA,KAAA,GAAQ,EAAA;AAAA,IAAI;AAC1F,IAAA,MAAM,KAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,KAAA,GAAQ,EAAE,IAAI,CAAA;AACpC,IAAA,IAAI,KAAK,KAAA,EAAO;AAAE,MAAA,MAAA,CAAO,YAAA,CAAa,CAAA,GAAI,CAAA,CAAE,IAAA,GAAO,CAAA,CAAE,KAAA;AAAO,MAAA,MAAA,CAAO,WAAW,CAAA,CAAE,IAAA;AAAM,MAAA,KAAA,GAAQ,EAAA;AAAA,IAAI;AAGlG,IAAA,MAAM,KAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,GAAA,GAAM,EAAE,GAAG,CAAA;AACjC,IAAA,IAAI,KAAK,KAAA,EAAO;AAAE,MAAA,MAAA,CAAO,YAAA,CAAa,IAAI,CAAA,CAAE,GAAA;AAAK,MAAA,MAAA,CAAO,aAAa,CAAA,CAAE,GAAA;AAAK,MAAA,KAAA,GAAQ,EAAA;AAAA,IAAI;AACxF,IAAA,MAAM,KAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,MAAA,GAAS,EAAE,MAAM,CAAA;AACvC,IAAA,IAAI,KAAK,KAAA,EAAO;AAAE,MAAA,MAAA,CAAO,YAAA,CAAa,CAAA,GAAI,CAAA,CAAE,MAAA,GAAS,CAAA,CAAE,MAAA;AAAQ,MAAA,MAAA,CAAO,aAAa,CAAA,CAAE,MAAA;AAAQ,MAAA,KAAA,GAAQ,EAAA;AAAA,IAAI;AACzG,IAAA,MAAM,KAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,GAAA,GAAM,EAAE,MAAM,CAAA;AACpC,IAAA,IAAI,KAAK,KAAA,EAAO;AAAE,MAAA,MAAA,CAAO,YAAA,CAAa,IAAI,CAAA,CAAE,MAAA;AAAQ,MAAA,MAAA,CAAO,aAAa,CAAA,CAAE,MAAA;AAAQ,MAAA,KAAA,GAAQ,EAAA;AAAA,IAAI;AAC9F,IAAA,MAAM,KAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,MAAA,GAAS,EAAE,GAAG,CAAA;AACpC,IAAA,IAAI,KAAK,KAAA,EAAO;AAAE,MAAA,MAAA,CAAO,YAAA,CAAa,CAAA,GAAI,CAAA,CAAE,GAAA,GAAM,CAAA,CAAE,MAAA;AAAQ,MAAA,MAAA,CAAO,aAAa,CAAA,CAAE,GAAA;AAAK,MAAA,KAAA,GAAQ,EAAA;AAAA,IAAI;AAAA,EACrG;AAEA,EAAA,OAAO,MAAA;AACT;ACzDO,SAAS,WAAA,CAAY,EAAE,UAAA,EAAY,QAAA,EAAS,EAA+C;AAChG,EAAA,IAAI,UAAA,KAAe,MAAA,IAAa,QAAA,KAAa,MAAA,EAAW,OAAO,IAAA;AAC/D,EAAA,uBACEF,KAAC,cAAA,EAAA,EACE,QAAA,EAAA;AAAA,IAAA,QAAA,KAAa,0BACZF,GAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,gBAAA;AAAA,QACV,KAAA,EAAO,EAAE,QAAA,EAAU,UAAA,EAAY,WAAW,CAAA,WAAA,EAAc,QAAQ,CAAA,GAAA,CAAA,EAAO,GAAA,EAAK,MAAO,MAAA,EAAQ,GAAA,EAAO,KAAA,EAAO,CAAA,EAAG,eAAe,MAAA;AAAO;AAAA,KACpI;AAAA,IAED,UAAA,KAAe,0BACdA,GAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,gBAAA;AAAA,QACV,KAAA,EAAO,EAAE,QAAA,EAAU,UAAA,EAAY,WAAW,CAAA,WAAA,EAAc,UAAU,CAAA,GAAA,CAAA,EAAO,IAAA,EAAM,MAAO,KAAA,EAAO,GAAA,EAAO,MAAA,EAAQ,CAAA,EAAG,eAAe,MAAA;AAAO;AAAA;AACvI,GAAA,EAEJ,CAAA;AAEJ;ACJA,SAAS,iBAAA,GAAmC;AAC1C,EAAA,IAAI,OAAO,QAAA,KAAa,WAAA,EAAa,OAAO,OAAA;AAE5C,EAAA,MAAM,OAAO,QAAA,CAAS,eAAA;AACtB,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,YAAA,CAAa,YAAY,CAAA;AAC3C,EAAA,IAAI,IAAA,KAAS,MAAA,IAAU,IAAA,KAAS,OAAA,EAAS,OAAO,IAAA;AAChD,EAAA,IAAI,IAAA,CAAK,SAAA,CAAU,QAAA,CAAS,MAAM,GAAG,OAAO,MAAA;AAE5C,EAAA,OAAO,OAAO,WAAW,WAAA,IAAe,MAAA,CAAO,aAAa,8BAA8B,CAAA,CAAE,UACxF,MAAA,GACA,OAAA;AACN;AAwBO,SAAS,qBAAqB,QAAA,EAA8C;AAIjF,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAwB,OAAO,CAAA;AAI/D,EAAA,MAAM,MAAA,GAAS,QAAA,KAAa,OAAA,IAAW,QAAA,KAAa,SAAS,QAAA,GAAW,MAAA;AAExE,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,MAAA,EAAQ;AACZ,IAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AAErC,IAAA,MAAM,IAAA,GAAO,MAAM,WAAA,CAAY,iBAAA,EAAmB,CAAA;AAClD,IAAA,IAAA,EAAK;AAEL,IAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,IAAI,CAAA;AAC1C,IAAA,QAAA,CAAS,OAAA,CAAQ,SAAS,eAAA,EAAiB;AAAA,MACzC,UAAA,EAAY,IAAA;AAAA,MACZ,eAAA,EAAiB,CAAC,OAAA,EAAS,YAAY;AAAA,KACxC,CAAA;AAED,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,UAAA,GAAa,8BAA8B,CAAA;AAChE,IAAA,KAAA,EAAO,gBAAA,GAAmB,UAAU,IAAI,CAAA;AAExC,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,UAAA,EAAW;AACpB,MAAA,KAAA,EAAO,mBAAA,GAAsB,UAAU,IAAI,CAAA;AAAA,IAC7C,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,OAAO,MAAA,IAAU,QAAA;AACnB;AClDA,SAAS,0BAA0B,KAAA,EAA8C;AAC/E,EAAA,IAAI,KAAA,CAAM,QAAA,EAAU,KAAA,CAAM,cAAA,EAAe;AAC3C;AAiBO,SAAS,eAAe,WAAA,EAI7B;AACA,EAAA,OAAO,cACH,EAAE,qBAAA,EAAuB,IAAA,EAAM,gBAAA,EAAkB,MAAK,GACtD;AAAA,IACE,qBAAA,EAAuB,OAAA;AAAA,IACvB,gBAAA,EAAkB,KAAA;AAAA,IAClB,cAAA,EAAgB;AAAA,GAClB;AACN;AAyCA,IAAM,gBAAA,GAAmC,EAAE,OAAA,EAAS,GAAA,EAAI;AACxD,IAAM,oBAAA,GAA2C;AAAA,EAC/C,IAAA,EAAM,YAAA;AAAA,EACN,QAAA,EAAU;AACZ,CAAA;AAWO,SAAS,UAAA,CAAW;AAAA,EACzB,KAAA;AAAA,EACA,KAAA;AAAA,EACA,aAAa,iBAAA,CAAkB,IAAA;AAAA,EAC/B,YAAA,GAAe,IAAA;AAAA,EACf,WAAA,GAAc,KAAA;AAAA,EACd,MAAA,GAAS,GAAA;AAAA,EACT,mBAAA,GAAsB,IAAA;AAAA,EACtB,iBAAA;AAAA,EACA,SAAA;AAAA,EACA,eAAA,GAAkB,KAAA;AAAA,EAClB,WAAA,GAAc,IAAA;AAAA,EACd,aAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,KAAA;AAAA,EACA,GAAG;AACL,CAAA,EAAoB;AAClB,EAAA,MAAM,eAAA,GAAkB,OAAA;AAAA,IACtB,OAAO,EAAE,GAAG,kBAAkB,GAAI,SAAA,IAAa,EAAC,EAAG,CAAA;AAAA,IACnD,CAAC,SAAS;AAAA,GACZ;AAIA,EAAA,MAAM,QAAA,GAAW,OAAO,KAAK,CAAA;AAC7B,EAAA,QAAA,CAAS,OAAA,GAAU,KAAA;AACnB,EAAA,MAAM,gBAAA,GAAmB,OAAA;AAAA,IACvB,MACE,mBAAA,KAAwB,KAAA,GACpB,MAAA,GACA,yBAAA;AAAA,MACE,MAAM,QAAA,CAAS,OAAA;AAAA,MACf,mBAAA,KAAwB,OAAO,MAAA,GAAY;AAAA,KAC7C;AAAA,IACN,CAAC,mBAAmB;AAAA,GACtB;AAEA,EAAA,MAAM,4BAA4B,iBAAA,IAAqB,gBAAA;AAEvD,EAAA,MAAM,eAAA,GAAkB,OAAA;AAAA,IACtB,MAAO,SAAA,GAAY,EAAE,GAAG,WAAU,GAAI,MAAA;AAAA,IACtC,CAAC,SAAS;AAAA,GACZ;AAIA,EAAA,MAAM,YAAA,GAAe,QAAQ,MAAM,oBAAA,CAAqB,KAAK,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAGvE,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAIK,QAAAA,CAAqD,EAAE,CAAA;AAC7F,EAAA,MAAM,iBAAA,GAAoB,WAAA;AAAA,IACxB,CAAC,OAAA,KAAmB;AAClB,MAAA,IAAI,eAAA,EAAiB;AACnB,QAAA,MAAM,GAAA,GAAM,QAAQ,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,IAAA,KAAS,UAAA,IAAc,CAAA,CAAE,QAAQ,CAAA;AACrE,QAAA,IAAI,IAAI,MAAA,KAAW,CAAA,IAAK,GAAA,CAAI,CAAC,EAAE,QAAA,EAAU;AACvC,UAAA,MAAM,QAAQ,cAAA,CAAe,GAAA,CAAI,CAAC,CAAA,EAAG,SAAS,OAAO,CAAA;AACrD,UAAA,IAAI,KAAA,CAAM,YAAA,CAAa,CAAA,KAAM,MAAA,EAAW,GAAA,CAAI,CAAC,CAAA,CAAE,QAAA,CAAS,CAAA,GAAI,KAAA,CAAM,YAAA,CAAa,CAAA;AAC/E,UAAA,IAAI,KAAA,CAAM,YAAA,CAAa,CAAA,KAAM,MAAA,EAAW,GAAA,CAAI,CAAC,CAAA,CAAE,QAAA,CAAS,CAAA,GAAI,KAAA,CAAM,YAAA,CAAa,CAAA;AAC/E,UAAA,cAAA,CAAe,EAAE,UAAA,EAAY,KAAA,CAAM,YAAY,QAAA,EAAU,KAAA,CAAM,UAAU,CAAA;AAAA,QAC3E,CAAA,MAAO;AACL,UAAA,cAAA,CAAe,EAAE,CAAA;AAAA,QACnB;AAAA,MACF;AACA,MAAA,aAAA,GAAgB,OAAc,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,CAAC,iBAAiB,aAAa;AAAA,GACjC;AAYA,EAAA,MAAM,iBAAA,GAAoB,qBAAqB,SAAS,CAAA;AAExD,EAAA,uBACEH,IAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW;AAAA,QACT,WAAA;AAAA;AAAA;AAAA,QAGA,iBAAA,KAAsB,SAAS,MAAA,GAAS,EAAA;AAAA,QACxC,iBAAA,KAAsB,UAAU,kBAAA,GAAqB,EAAA;AAAA,QACrD,SAAA,IAAa;AAAA,OACf,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAAA,MACX,KAAA,EAAO,EAAE,MAAA,EAAQ,GAAG,KAAA,EAAM;AAAA,MAEzB,QAAA,EAAA;AAAA,QAAA,OAAA,oBAAWF,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sBAAsB,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,wBACzDA,GAAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sBACb,QAAA,kBAAAE,IAAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAO,YAAA;AAAA,YACP,KAAA;AAAA,YACA,aAAA,EAAe,iBAAA;AAAA,YACf,SAAA,EAAW,iBAAA;AAAA,YACX,SAAA,EAAW,eAAA;AAAA,YACX,SAAA,EAAW,eAAA;AAAA,YACX,OAAA,EAAO,IAAA;AAAA,YACP,cAAA,EAAgB,gBAAA;AAAA,YAChB,kBAAA,EAAoB,oBAAA;AAAA,YACpB,UAAA,EAAY,EAAE,eAAA,EAAiB,IAAA,EAAK;AAAA,YAInC,GAAG,eAAe,WAAW,CAAA;AAAA,YAC9B,iBAAA,EAAmB,yBAAA;AAAA,YAClB,GAAG,IAAA;AAAA,YAEH,QAAA,EAAA;AAAA,cAAA,UAAA,KAAe,MAAA,oBACdF,GAAAA,CAAC,UAAA,EAAA,EAAW,OAAA,EAAS,UAAA,EAAiC,GAAA,EAAK,EAAA,EAAI,IAAA,EAAM,CAAA,EAAG,KAAA,EAAM,kBAAA,EAAmB,CAAA;AAAA,cAElG,gCAAgBA,GAAAA,CAAC,YAAS,SAAA,EAAU,aAAA,EAAc,UAAS,cAAA,EAAe,CAAA;AAAA,cAC1E,WAAA,oBAAeA,GAAAA,CAAC,OAAA,EAAA,EAAQ,WAAU,YAAA,EAAa,QAAA,EAAQ,IAAA,EAAC,QAAA,EAAQ,IAAA,EAAC,CAAA;AAAA,cACjE,eAAA,oBAAmBA,GAAAA,CAAC,WAAA,EAAA,EAAY,YAAY,WAAA,CAAY,UAAA,EAAY,QAAA,EAAU,WAAA,CAAY,QAAA,EAAU;AAAA;AAAA;AAAA,SACvG,EACF;AAAA;AAAA;AAAA,GACF;AAEJ;AC3MA,IAAM,YAAA,GAA+C;AAAA,EACnD,EAAA,EAAI,IAAA;AAAA,EACJ,OAAA,EAAS,SAAA;AAAA,EACT,MAAA,EAAQ,QAAA;AAAA,EACR,OAAA,EAAS,SAAA;AAAA,EACT,OAAA,EAAS;AACX,CAAA;AAgBO,SAAS,UAAA,CAAW;AAAA,EACzB,KAAA;AAAA,EACA,OAAA,GAAU,QAAA;AAAA,EACV,MAAA,GAAS,GAAA;AAAA,EACT,WAAA,GAAc,KAAA;AAAA,EACd,YAAA,GAAe,IAAA;AAAA,EACf,QAAA;AAAA,EACA,cAAA,GAAiB,IAAA;AAAA,EACjB,YAAA;AAAA,EACA,SAAA;AAAA,EACA,aAAa,EAAC;AAAA,EACd,KAAA;AAAA,EACA;AACF,CAAA,EAAoB;AAClB,EAAA,MAAM,YAAYM,OAAAA,CAAQ,MAAM,cAAA,EAAe,EAAG,EAAE,CAAA;AAEpD,EAAA,MAAM,IAAA,GAAOA,OAAAA;AAAA,IACX,MACE,KAAA,CAAM,KAAA,CAAM,GAAA,CAAI,CAAC,MAAMC,MAAAA,KAAU;AAC/B,MAAA,MAAM,OAAO,WAAA,CAAY,IAAA,CAAK,MAAM,IAAA,IAAQ,IAAA,CAAK,QAAQ,EAAE,CAAA;AAC3D,MAAA,OAAO;AAAA,QACL,IAAA;AAAA,QACA,KAAA,EAAAA,MAAAA;AAAA;AAAA;AAAA,QAGA,KAAA,EAAO,KAAK,IAAA,EAAM,KAAA,IAAS,MAAM,KAAA,IAAS,IAAA,CAAK,IAAA,EAAM,IAAA,IAAQ,IAAA,CAAK,EAAA;AAAA,QAClE,WAAA,EAAa,MAAM,WAAA,IAAe,IAAA;AAAA,QAClC,QAAQ,IAAA,EAAM,MAAA,IAAU,cAAA,CAAe,IAAA,EAAM,YAAY,QAAQ,CAAA;AAAA,QACjE,MAAA,EAAQ,QAAA,GAAW,IAAA,CAAK,EAAE,CAAA,IAAK;AAAA,OACjC;AAAA,IACF,CAAC,CAAA;AAAA,IACH,CAAC,KAAA,CAAM,KAAA,EAAO,QAAQ;AAAA,GACxB;AAEA,EAAA,IAAI,KAAA,CAAM,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG;AAC5B,IAAA,uBACEP,GAAAA,CAAC,KAAA,EAAA,EAAI,WAAW,EAAA,CAAG,4BAAA,EAA8B,WAAW,UAAA,CAAW,IAAI,CAAA,EAAG,KAAA,EAC3E,mCAASA,GAAAA,CAAC,UAAK,SAAA,EAAU,kBAAA,EAAmB,qCAAuB,CAAA,EACtE,CAAA;AAAA,EAEJ;AAEA,EAAA,IAAI,YAAY,MAAA,EAAQ;AACtB,IAAA,uBACEA,GAAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAW,EAAA,CAAG,2BAAA,EAA6B,SAAA,EAAW,WAAW,IAAI,CAAA;AAAA,QACrE,KAAA;AAAA,QACA,kBAAA,EAAiB,MAAA;AAAA,QAEjB,QAAA,kBAAAA,IAAC,IAAA,EAAA,EAAG,SAAA,EAAW,GAAG,iBAAA,EAAmB,UAAA,CAAW,IAAI,CAAA,EACjD,QAAA,EAAA,IAAA,CAAK,IAAI,CAAC,EAAE,MAAM,KAAA,EAAAO,MAAAA,EAAO,OAAO,WAAA,EAAa,MAAA,EAAQ,QAAO,KAAM;AACjE,UAAA,MAAM,QAAA,GAAW,KAAK,EAAA,KAAO,cAAA;AAC7B,UAAA,MAAM,GAAA,GAAM,eAAe,QAAA,GAAW,KAAA;AAEtC,UAAA,uBACEP,GAAAA,CAAC,IAAA,EAAA,EACC,QAAA,kBAAAE,IAAAA;AAAA,YAAC,GAAA;AAAA,YAAA;AAAA,cACE,GAAI,YAAA,GACD,EAAE,IAAA,EAAM,QAAA,EAAmB,OAAA,EAAS,MAAM,YAAA,CAAa,IAAI,CAAA,EAAE,GAC7D,EAAC;AAAA,cACL,SAAA,EAAW,EAAA;AAAA,gBACT,gBAAA;AAAA,gBACA,QAAA,IAAY,0BAAA;AAAA,gBACZ,YAAA,IAAgB,6BAAA;AAAA,gBAChB,UAAA,CAAW;AAAA,eACb;AAAA,cACA,yBAAuB,IAAA,CAAK,EAAA;AAAA,cAC5B,2BAAyB,MAAA,IAAU,MAAA;AAAA,cACnC,gBAAc,QAAA,IAAY,MAAA;AAAA,cAE1B,QAAA,EAAA;AAAA,gCAAAF,GAAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAW,EAAA,CAAG,kBAAA,EAAoB,UAAA,CAAW,QAAQ,CAAA;AAAA,oBACrD,KAAA,EAAO,EAAE,eAAA,EAAiB,MAAA,EAAO;AAAA,oBACjC,aAAA,EAAW,IAAA;AAAA,oBAEV,UAAAO,MAAAA,GAAQ;AAAA;AAAA,iBACX;AAAA,gCAEAL,IAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,iBAAA,EACd,QAAA,EAAA;AAAA,kCAAAF,GAAAA,CAAC,UAAK,SAAA,EAAW,EAAA,CAAG,oBAAoB,UAAA,CAAW,QAAQ,GAAI,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,kBACpE,WAAA,oBACCA,GAAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,GAAG,iBAAA,EAAmB,UAAA,CAAW,cAAc,CAAA,EAC7D,QAAA,EAAA,WAAA,EACH;AAAA,iBAAA,EAEJ,CAAA;AAAA,gBAEC,0BACCA,GAAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAW,EAAA;AAAA,sBACT,mBAAA;AAAA,sBACA,sBAAsB,MAAM,CAAA,CAAA;AAAA,sBAC5B,UAAA,CAAW;AAAA,qBACb;AAAA,oBAEC,uBAAa,MAAM;AAAA;AAAA;AACtB;AAAA;AAAA,WAEJ,EAAA,EA3CO,KAAK,EA4Cd,CAAA;AAAA,QAEJ,CAAC,CAAA,EACH;AAAA;AAAA,KACF;AAAA,EAEJ;AAEA,EAAA,uBACEA,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,EAAA,CAAG,6BAAA,EAA+B,SAAA,EAAW,WAAW,IAAI,CAAA;AAAA,MACvE,KAAA;AAAA,MACA,kBAAA,EAAiB,QAAA;AAAA,MAEjB,QAAA,kBAAAA,GAAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,OAAO,KAAA,CAAM,KAAA;AAAA,UACb,OAAO,KAAA,CAAM,KAAA;AAAA,UACb,SAAA;AAAA,UACA,MAAA;AAAA,UACA,YAAA;AAAA,UACA,WAAA;AAAA,UAGA,cAAA,EAAgB,KAAA;AAAA,UAChB,gBAAA,EAAkB,KAAA;AAAA,UAClB,cAAA,EAAgB,QAAQ,YAAY,CAAA;AAAA,UACpC,cAAA,EAAgB,KAAA;AAAA,UAChB,kBAAA,EAAoB,QAAQ,YAAY,CAAA;AAAA,UACxC,aAAA,EAAe,IAAA;AAAA,UACf,gBAAA,EAAkB,IAAA;AAAA,UAClB,qBAAA,EAAuB,IAAA;AAAA,UACvB,cAAA,EAAgB,KAAA;AAAA,UAEhB,YAAA,EAAc,KAAA;AAAA,UACd,aAAa,YAAA,GAAe,CAAC,GAAG,IAAA,KAAS,YAAA,CAAa,IAAgB,CAAA,GAAI,MAAA;AAAA,UAC1E,OAAA,EAAO;AAAA;AAAA;AACT;AAAA,GACF;AAEJ;AAEA,SAAS,MAAM,KAAA,EAAyD;AACtE,EAAA,OAAO,KAAA,CAAM,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,GAAG,CAAA;AACvC","file":"chunk-UVP43XU2.js","sourcesContent":["import { type ReactNode, memo } from \"react\";\nimport { Handle, Position, type NodeProps } from \"@xyflow/react\";\nimport type { FlowNode, NodeRunStatus, PortDescriptor } from \"../../types\";\n\nexport type NodeShellProps = {\n /** Required: the xyflow node this is rendering. */\n node: NodeProps<FlowNode>;\n /** Accent color for the title bar / status ring. */\n accent: string;\n /** Tag/label shown to the left of the title (e.g. \"TRIGGER\", \"ACTION\"). */\n tag: string;\n /** Optional icon glyph (single-character string is fine). */\n icon?: ReactNode;\n /** Whether to show input handles on the left. Defaults true. */\n showInputs?: boolean;\n /** Whether to show output handles on the right. Defaults true. */\n showOutputs?: boolean;\n /** Body content under the title bar. */\n children?: ReactNode;\n};\n\n/**\n * Shared chrome for every kit node — title bar, accent border, status ring,\n * port handles. Specific node kinds compose this with their body content.\n */\nfunction NodeShellInner({\n node,\n accent,\n tag,\n icon,\n showInputs = true,\n showOutputs = true,\n children,\n}: NodeShellProps) {\n const data = node.data;\n const status: NodeRunStatus = data.status ?? \"idle\";\n const inputs = data.inputs ?? defaultInputs(showInputs);\n const outputs = data.outputs ?? defaultOutputs(showOutputs);\n\n return (\n <div\n className={[\"ff-node\", `ff-node--status-${status}`, node.selected ? \"ff-node--selected\" : \"\"].filter(Boolean).join(\" \")}\n style={{ borderColor: node.selected ? accent : undefined }}\n >\n <header className=\"ff-node__header\" style={{ background: accent }}>\n <span className=\"ff-node__icon\" aria-hidden>{icon ?? null}</span>\n <span className=\"ff-node__tag\">{tag}</span>\n <span className=\"ff-node__label\">{data.label}</span>\n {status !== \"idle\" && <StatusDot status={status} />}\n </header>\n\n {data.description && <p className=\"ff-node__desc\">{data.description}</p>}\n {children && <div className=\"ff-node__body\">{children}</div>}\n {data.statusText && <p className=\"ff-node__status-text\">{data.statusText}</p>}\n\n {inputs.map((p, i) => (\n <Handle\n key={p.id}\n type=\"target\"\n position={Position.Left}\n id={p.id}\n style={portStyle(i, inputs.length)}\n title={p.label ?? p.id}\n />\n ))}\n {outputs.map((p, i) => (\n <Handle\n key={p.id}\n type=\"source\"\n position={Position.Right}\n id={p.id}\n style={portStyle(i, outputs.length)}\n title={p.label ?? p.id}\n />\n ))}\n </div>\n );\n}\n\nexport const NodeShell = memo(NodeShellInner);\n\nfunction defaultInputs(show: boolean): PortDescriptor[] {\n return show ? [{ id: \"in\" }] : [];\n}\nfunction defaultOutputs(show: boolean): PortDescriptor[] {\n return show ? [{ id: \"out\" }] : [];\n}\n\nfunction portStyle(i: number, total: number): React.CSSProperties {\n if (total <= 1) return {};\n const slot = (100 / (total + 1)) * (i + 1);\n return { top: `${slot}%` };\n}\n\nfunction StatusDot({ status }: { status: NodeRunStatus }) {\n return <span className={`ff-node__dot ff-node__dot--${status}`} aria-label={`status ${status}`} />;\n}\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\n/** Entry-point node — outputs only, no inputs. */\nfunction TriggerNodeInner(props: NodeProps<FlowNode>) {\n return <NodeShell node={props} accent=\"#10b981\" tag=\"TRIGGER\" icon=\"⚡\" showInputs={false} />;\n}\nexport const TriggerNode = memo(TriggerNodeInner);\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\n/** General-purpose work node — inputs and outputs. */\nfunction ActionNodeInner(props: NodeProps<FlowNode>) {\n return <NodeShell node={props} accent=\"#3b82f6\" tag=\"ACTION\" icon=\"▸\" />;\n}\nexport const ActionNode = memo(ActionNodeInner);\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode, PortDescriptor } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\nconst DEFAULT_BRANCHES: PortDescriptor[] = [\n { id: \"true\", label: \"true\" },\n { id: \"false\", label: \"false\" },\n];\n\n/** Branching node — multiple typed outputs, one input. */\nfunction DecisionNodeInner(props: NodeProps<FlowNode>) {\n // If the host hasn't customised outputs, default to a true/false split.\n if (!props.data.outputs) {\n props = { ...props, data: { ...props.data, outputs: DEFAULT_BRANCHES } };\n }\n return <NodeShell node={props} accent=\"#f59e0b\" tag=\"DECISION\" icon=\"◇\" />;\n}\nexport const DecisionNode = memo(DecisionNodeInner);\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\n/** Terminal node — receives the workflow's final result; no outputs. */\nfunction OutputNodeInner(props: NodeProps<FlowNode>) {\n return <NodeShell node={props} accent=\"#a855f7\" tag=\"OUTPUT\" icon=\"●\" showOutputs={false} />;\n}\nexport const OutputNode = memo(OutputNodeInner);\n","import { memo } from \"react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport type { FlowNode, SubgraphNodeData } from \"../../types\";\nimport { NodeShell } from \"./NodeShell\";\n\n/**\n * SubgraphNode — collapses a group of nodes behind a single facade with\n * inputs and outputs that map to the inner graph's boundary ports. The\n * runtime treats it like an action node: when running, it dispatches to\n * the registered \"subgraph\" executor (host decides expand vs inline).\n *\n * v0.1 just renders the facade. Expand/collapse interactions and inner-\n * graph editing are deferred — host apps can implement those by toggling\n * `data.collapsed` and rendering a nested <FlowCanvas> when expanded.\n */\nfunction SubgraphNodeInner(props: NodeProps<FlowNode>) {\n const data = props.data as SubgraphNodeData;\n const childCount = data.childIds?.length ?? 0;\n return (\n <NodeShell node={props} accent=\"#0ea5e9\" tag=\"SUBGRAPH\" icon=\"❐\">\n <div className=\"ff-subgraph__meta\">\n <span>{childCount} node{childCount === 1 ? \"\" : \"s\"}</span>\n <span>{data.collapsed === false ? \"expanded\" : \"collapsed\"}</span>\n </div>\n </NodeShell>\n );\n}\nexport const SubgraphNode = memo(SubgraphNodeInner);\n","import type { NodeTypes } from \"@xyflow/react\";\nimport { TriggerNode } from \"./TriggerNode\";\nimport { ActionNode } from \"./ActionNode\";\nimport { DecisionNode } from \"./DecisionNode\";\nimport { OutputNode } from \"./OutputNode\";\nimport { NoteNode } from \"./NoteNode\";\nimport { SubgraphNode } from \"./SubgraphNode\";\n\nexport { TriggerNode, ActionNode, DecisionNode, OutputNode, NoteNode, SubgraphNode };\nexport { LaneNode } from \"./LaneNode\";\nexport { NodeShell, type NodeShellProps } from \"./NodeShell\";\n\n/**\n * Default xyflow `nodeTypes` map covering the kit. Spread into your own:\n *\n * <FlowCanvas nodeTypes={{ ...defaultNodeTypes, custom: MyNode }} ... />\n */\nexport const defaultNodeTypes: NodeTypes = {\n trigger: TriggerNode,\n action: ActionNode,\n decision: DecisionNode,\n output: OutputNode,\n note: NoteNode,\n subgraph: SubgraphNode,\n};\n","import { reconnectEdge as xyReconnectEdge, type Connection, type Edge } from \"@xyflow/react\";\nimport type { FlowGraph, FlowNode } from \"../../types\";\n\n/**\n * Remove nodes AND every edge attached to them.\n *\n * Deleting a node without pruning its edges leaves danglers that point at\n * nothing — they survive a round-trip through the schema and blow up the\n * runner, so the two always move together.\n */\nexport function removeNodes(graph: FlowGraph, ids: string[]): FlowGraph {\n if (ids.length === 0) return graph;\n const doomed = new Set(ids);\n\n return {\n nodes: graph.nodes.filter((n) => !doomed.has(n.id)),\n edges: graph.edges.filter((e) => !doomed.has(e.source) && !doomed.has(e.target)),\n };\n}\n\n/** Remove edges by id, leaving nodes untouched. */\nexport function removeEdges(edges: Edge[], ids: string[]): Edge[] {\n if (ids.length === 0) return edges;\n const doomed = new Set(ids);\n\n return edges.filter((e) => !doomed.has(e.id));\n}\n\n/**\n * Set (or clear) an edge's label.\n *\n * An empty/whitespace label is removed rather than stored as `\"\"` — xyflow\n * renders an empty label as an empty chip on the wire, and a blank key would\n * survive export into the workflow schema.\n */\nexport function setEdgeLabel(edges: Edge[], id: string, label: string | undefined): Edge[] {\n const next = label?.trim();\n return edges.map((e) => {\n if (e.id !== id) return e;\n if (!next) {\n const { label: _drop, ...rest } = e;\n return rest as Edge;\n }\n return { ...e, label: next };\n });\n}\n\n/** Copy a node with a fresh id, offset so it doesn't sit exactly on top. */\nexport function duplicateNode(node: FlowNode, id: string, offset = 40): FlowNode {\n return {\n ...node,\n id,\n position: { x: node.position.x + offset, y: node.position.y + offset },\n // Deep copy so the clone's config edits don't mutate the original.\n data: JSON.parse(JSON.stringify(node.data ?? {})),\n } as FlowNode;\n}\n\n/**\n * Clone a set of nodes AND the edges internal to that set, remapping every id.\n * This is the piece `duplicateNode` lacks: a copy/paste (or duplicate-selection)\n * that preserves the wiring *between* the copied nodes. Edges with an endpoint\n * outside the set are dropped (they'd dangle). A `parentId` pointing inside the\n * set is remapped; one pointing outside is detached.\n */\nexport function cloneSubgraph(\n nodes: FlowNode[],\n edges: Edge[],\n opts: { makeId: () => string; offset?: number },\n): { nodes: FlowNode[]; edges: Edge[]; idMap: Map<string, string> } {\n const offset = opts.offset ?? 40;\n const idMap = new Map<string, string>();\n for (const n of nodes) idMap.set(n.id, opts.makeId());\n\n const clonedNodes = nodes.map((n) => {\n const cloned = duplicateNode(n, idMap.get(n.id)!, offset) as any;\n const parentId = (n as any).parentId;\n if (parentId && idMap.has(parentId)) cloned.parentId = idMap.get(parentId);\n else if (parentId) delete cloned.parentId;\n return cloned as FlowNode;\n });\n\n const clonedEdges = edges\n .filter((e) => idMap.has(e.source) && idMap.has(e.target))\n .map((e) => ({ ...e, id: opts.makeId(), source: idMap.get(e.source)!, target: idMap.get(e.target)! }));\n\n return { nodes: clonedNodes, edges: clonedEdges, idMap };\n}\n\n/**\n * Rewire one edge's endpoint(s) — wraps xyflow's `reconnectEdge`. Keeps the\n * edge's id (`shouldReplaceId: false`) so its label and identity survive the\n * rewire instead of being regenerated from the new endpoints.\n */\nexport function reconnectEdge(edges: Edge[], oldEdge: Edge, newConnection: Connection): Edge[] {\n return xyReconnectEdge(oldEdge, newConnection, edges, { shouldReplaceId: false });\n}\n\nexport type AlignEdge = \"left\" | \"hcenter\" | \"right\" | \"top\" | \"vcenter\" | \"bottom\";\n\nconst nodeW = (n: FlowNode): number => (n as any).width ?? (n as any).measured?.width ?? 0;\nconst nodeH = (n: FlowNode): number => (n as any).height ?? (n as any).measured?.height ?? 0;\n\n/** Align a selection to a shared edge/center of its bounding box. */\nexport function alignNodes(nodes: FlowNode[], edge: AlignEdge): FlowNode[] {\n if (nodes.length < 2) return nodes;\n const minL = Math.min(...nodes.map((n) => n.position.x));\n const maxR = Math.max(...nodes.map((n) => n.position.x + nodeW(n)));\n const minT = Math.min(...nodes.map((n) => n.position.y));\n const maxB = Math.max(...nodes.map((n) => n.position.y + nodeH(n)));\n const cx = (minL + maxR) / 2;\n const cy = (minT + maxB) / 2;\n return nodes.map((n) => {\n let { x, y } = n.position;\n if (edge === \"left\") x = minL;\n else if (edge === \"right\") x = maxR - nodeW(n);\n else if (edge === \"hcenter\") x = cx - nodeW(n) / 2;\n else if (edge === \"top\") y = minT;\n else if (edge === \"bottom\") y = maxB - nodeH(n);\n else if (edge === \"vcenter\") y = cy - nodeH(n) / 2;\n return { ...n, position: { x, y } };\n });\n}\n\n/**\n * Order nodes so every parent precedes its children — xyflow misrenders (and\n * warns) when a child appears before its `parentId` in the array. Stable\n * otherwise. Apply at the render boundary once grouping is in play.\n */\nexport function sortNodesParentFirst<T extends { id: string; parentId?: string }>(nodes: T[]): T[] {\n const byId = new Map(nodes.map((n) => [n.id, n] as const));\n const seen = new Set<string>();\n const out: T[] = [];\n const visit = (n: T) => {\n if (seen.has(n.id)) return;\n const pid = (n as any).parentId as string | undefined;\n if (pid && byId.has(pid) && !seen.has(pid)) visit(byId.get(pid)!);\n seen.add(n.id);\n out.push(n);\n };\n for (const n of nodes) visit(n);\n return out;\n}\n\n/** Absolute position of a node, accounting for one level of parent nesting. */\nfunction absolutePosition(node: FlowNode, nodes: FlowNode[]): { x: number; y: number } {\n const pid = (node as any).parentId as string | undefined;\n if (!pid) return node.position;\n const parent = nodes.find((n) => n.id === pid);\n return parent ? { x: node.position.x + parent.position.x, y: node.position.y + parent.position.y } : node.position;\n}\n\n/**\n * Put a node inside a lane/container: set `parentId` + `extent:'parent'` and\n * convert its position to be relative to the lane. Idempotent-safe; a no-op if\n * either id is missing or they're the same node.\n */\nexport function assignToLane(nodes: FlowNode[], nodeId: string, laneId: string): FlowNode[] {\n if (nodeId === laneId) return nodes;\n const node = nodes.find((n) => n.id === nodeId);\n const lane = nodes.find((n) => n.id === laneId);\n if (!node || !lane) return nodes;\n const abs = absolutePosition(node, nodes);\n const laneAbs = absolutePosition(lane, nodes);\n const rel = { x: abs.x - laneAbs.x, y: abs.y - laneAbs.y };\n return nodes.map((n) => (n.id === nodeId ? ({ ...n, parentId: laneId, extent: \"parent\", position: rel } as FlowNode) : n));\n}\n\n/** Take a node out of its lane: drop `parentId`/`extent`, restore absolute position. */\nexport function removeFromLane(nodes: FlowNode[], nodeId: string): FlowNode[] {\n const node = nodes.find((n) => n.id === nodeId);\n if (!node || !(node as any).parentId) return nodes;\n const abs = absolutePosition(node, nodes);\n return nodes.map((n) => {\n if (n.id !== nodeId) return n;\n const { parentId: _p, extent: _e, ...rest } = n as any;\n return { ...rest, position: abs } as FlowNode;\n });\n}\n\n/**\n * Stack lanes into contiguous rows (horizontal) or columns (vertical) — the\n * \"fixed rows/columns\" behavior. `isLane` picks which nodes are lanes; they're\n * ordered by their current cross-axis position and repacked from the first\n * lane's origin. Each lane keeps its own size (independently resizable).\n */\nexport function stackLanes(\n nodes: FlowNode[],\n isLane: (n: FlowNode) => boolean,\n opts: { orientation?: \"horizontal\" | \"vertical\"; gap?: number } = {},\n): FlowNode[] {\n const orientation = opts.orientation ?? \"horizontal\";\n const gap = opts.gap ?? 12;\n const vertical = orientation === \"vertical\";\n const lanes = nodes.filter(isLane).sort((a, b) => (vertical ? a.position.x - b.position.x : a.position.y - b.position.y));\n if (lanes.length === 0) return nodes;\n const originX = lanes[0].position.x;\n const originY = lanes[0].position.y;\n const moves = new Map<string, { x: number; y: number }>();\n let cursor = vertical ? originX : originY;\n for (const lane of lanes) {\n moves.set(lane.id, vertical ? { x: cursor, y: originY } : { x: originX, y: cursor });\n cursor += (vertical ? ((lane as any).width ?? 320) : ((lane as any).height ?? 160)) + gap;\n }\n return nodes.map((n) => (moves.has(n.id) ? { ...n, position: moves.get(n.id)! } : n));\n}\n\n/** Evenly distribute a selection's gaps along an axis (needs 3+ nodes). */\nexport function distributeNodes(nodes: FlowNode[], axis: \"h\" | \"v\"): FlowNode[] {\n if (nodes.length < 3) return nodes;\n const size = (n: FlowNode) => (axis === \"h\" ? nodeW(n) : nodeH(n));\n const coord = (n: FlowNode) => (axis === \"h\" ? n.position.x : n.position.y);\n const sorted = [...nodes].sort((a, b) => coord(a) - coord(b));\n const start = coord(sorted[0]);\n const last = sorted[sorted.length - 1];\n const end = coord(last) + size(last);\n const totalSize = sorted.reduce((s, n) => s + size(n), 0);\n const gap = (end - start - totalSize) / (sorted.length - 1);\n const posById = new Map<string, number>();\n let cursor = start;\n for (const n of sorted) {\n posById.set(n.id, cursor);\n cursor += size(n) + gap;\n }\n return nodes.map((n) => {\n const p = posById.get(n.id)!;\n return { ...n, position: axis === \"h\" ? { ...n.position, x: p } : { ...n.position, y: p } };\n });\n}\n","import type { FlowNode } from \"../../types\";\n\nexport type HelperLineChange = { id: string; position?: { x: number; y: number } };\n\nexport type HelperLinesResult = {\n /** Y of a horizontal guide line (flow coords), if the drag aligns on Y. */\n horizontal?: number;\n /** X of a vertical guide line (flow coords), if the drag aligns on X. */\n vertical?: number;\n /** The snapped position to apply to the dragged node. */\n snapPosition: { x?: number; y?: number };\n};\n\nconst w = (n: FlowNode): number => (n as any).width ?? (n as any).measured?.width ?? 0;\nconst h = (n: FlowNode): number => (n as any).height ?? (n as any).measured?.height ?? 0;\n\n/**\n * Compute alignment guide lines (and a snapped position) for a node being\n * dragged to `change.position`, against the other nodes. Standard \"helper\n * lines\" algorithm: match the dragged node's left/right/top/bottom edges to any\n * other node's edges within `distance`, snapping to the nearest. Pure + testable.\n */\nexport function getHelperLines(change: HelperLineChange, nodes: FlowNode[], distance = 6): HelperLinesResult {\n const result: HelperLinesResult = { snapPosition: { x: undefined, y: undefined } };\n const a = nodes.find((n) => n.id === change.id);\n if (!a || !change.position) return result;\n\n const A = {\n left: change.position.x,\n right: change.position.x + w(a),\n top: change.position.y,\n bottom: change.position.y + h(a),\n width: w(a),\n height: h(a),\n };\n let vDist = distance;\n let hDist = distance;\n\n for (const b of nodes) {\n if (b.id === a.id) continue;\n const B = { left: b.position.x, right: b.position.x + w(b), top: b.position.y, bottom: b.position.y + h(b) };\n\n // Vertical guides (X alignment).\n const ll = Math.abs(A.left - B.left);\n if (ll < vDist) { result.snapPosition.x = B.left; result.vertical = B.left; vDist = ll; }\n const rr = Math.abs(A.right - B.right);\n if (rr < vDist) { result.snapPosition.x = B.right - A.width; result.vertical = B.right; vDist = rr; }\n const lr = Math.abs(A.left - B.right);\n if (lr < vDist) { result.snapPosition.x = B.right; result.vertical = B.right; vDist = lr; }\n const rl = Math.abs(A.right - B.left);\n if (rl < vDist) { result.snapPosition.x = B.left - A.width; result.vertical = B.left; vDist = rl; }\n\n // Horizontal guides (Y alignment).\n const tt = Math.abs(A.top - B.top);\n if (tt < hDist) { result.snapPosition.y = B.top; result.horizontal = B.top; hDist = tt; }\n const bb = Math.abs(A.bottom - B.bottom);\n if (bb < hDist) { result.snapPosition.y = B.bottom - A.height; result.horizontal = B.bottom; hDist = bb; }\n const tb = Math.abs(A.top - B.bottom);\n if (tb < hDist) { result.snapPosition.y = B.bottom; result.horizontal = B.bottom; hDist = tb; }\n const bt = Math.abs(A.bottom - B.top);\n if (bt < hDist) { result.snapPosition.y = B.top - A.height; result.horizontal = B.top; hDist = bt; }\n }\n\n return result;\n}\n","import { ViewportPortal } from \"@xyflow/react\";\n\n/**\n * HelperLines — alignment guides drawn during a drag. Rendered in flow\n * coordinate space (ViewportPortal), so the lines track pan/zoom. Positions come\n * from `getHelperLines`.\n */\nexport function HelperLines({ horizontal, vertical }: { horizontal?: number; vertical?: number }) {\n if (horizontal === undefined && vertical === undefined) return null;\n return (\n <ViewportPortal>\n {vertical !== undefined && (\n <div\n className=\"ff-helper-line\"\n style={{ position: \"absolute\", transform: `translateX(${vertical}px)`, top: -5000, height: 10000, width: 1, pointerEvents: \"none\" }}\n />\n )}\n {horizontal !== undefined && (\n <div\n className=\"ff-helper-line\"\n style={{ position: \"absolute\", transform: `translateY(${horizontal}px)`, left: -5000, width: 10000, height: 1, pointerEvents: \"none\" }}\n />\n )}\n </ViewportPortal>\n );\n}\n","import { useEffect, useState } from \"react\";\n\n/** The resolved mode React Flow and our own `ff-` tokens both understand. */\nexport type FlowColorMode = \"light\" | \"dark\";\n\n/**\n * What a host may PASS. React Flow's own `ColorMode` includes `\"system\"`, and\n * it is meaningful here rather than something to cast away: it means \"follow\n * the environment\", which is the same job `undefined` now does.\n */\nexport type FlowColorModeInput = FlowColorMode | \"system\";\n\n/**\n * Read the app's theme off the document, the way every host in this suite\n * signals it.\n *\n * Checked in the order a host actually sets them: an explicit `data-theme`\n * beats a `.dark` class (a host that writes both, like the showcase, is\n * consistent either way), and only when neither is present does the OS\n * preference decide.\n */\nfunction readDocumentTheme(): FlowColorMode {\n if (typeof document === \"undefined\") return \"light\";\n\n const root = document.documentElement;\n const attr = root.getAttribute(\"data-theme\");\n if (attr === \"dark\" || attr === \"light\") return attr;\n if (root.classList.contains(\"dark\")) return \"dark\";\n\n return typeof window !== \"undefined\" && window.matchMedia?.(\"(prefers-color-scheme: dark)\").matches\n ? \"dark\"\n : \"light\";\n}\n\n/**\n * The colour mode the canvas should actually use.\n *\n * **Why this exists.** `colorMode` used to be passed straight through to React\n * Flow, so a host that did not supply one got React Flow's own default —\n * `light` — no matter what the surrounding app was doing. Our `ff-` styles\n * still looked right, because they hang off an ancestor `.dark`, which is\n * exactly what made the bug hard to see: the nodes we style were fine while\n * React Flow's own layer stayed light underneath. Any node whose kind is not\n * registered falls back to React Flow's default node, and on a dark page that\n * is a white box with unreadable text. Edges, handles, the selection rectangle\n * and the controls were light too.\n *\n * So an unset `colorMode` now means \"follow the app\", not \"light\". Passing one\n * explicitly still wins — a canvas deliberately pinned light on a dark page is\n * a real thing, and this does not take it away.\n *\n * The subscription matters as much as the initial read: a theme toggle changes\n * an attribute on `<html>`, which triggers no React render on its own, so\n * without an observer the canvas would be correct on load and wrong the moment\n * someone flipped the switch.\n */\nexport function useResolvedColorMode(explicit?: FlowColorModeInput): FlowColorMode {\n // Start light on the server and on first paint. Reading the DOM in the\n // initialiser would differ between server and client markup and trip\n // hydration; the effect below corrects it before anything is visible.\n const [resolved, setResolved] = useState<FlowColorMode>(\"light\");\n\n // `\"system\"` is treated exactly like an unset prop: both mean \"follow the\n // environment\", and collapsing them here keeps one resolution path.\n const pinned = explicit === \"light\" || explicit === \"dark\" ? explicit : undefined;\n\n useEffect(() => {\n if (pinned) return;\n if (typeof document === \"undefined\") return;\n\n const sync = () => setResolved(readDocumentTheme());\n sync();\n\n const observer = new MutationObserver(sync);\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\", \"data-theme\"],\n });\n\n const media = window.matchMedia?.(\"(prefers-color-scheme: dark)\");\n media?.addEventListener?.(\"change\", sync);\n\n return () => {\n observer.disconnect();\n media?.removeEventListener?.(\"change\", sync);\n };\n }, [pinned]);\n\n return pinned ?? resolved;\n}\n","import {\n type CSSProperties,\n type ReactNode,\n type WheelEvent as ReactWheelEvent,\n useCallback,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport {\n ReactFlow,\n Background,\n BackgroundVariant,\n Controls,\n MiniMap,\n type DefaultEdgeOptions,\n type Edge,\n type EdgeTypes,\n type FitViewOptions,\n type NodeTypes,\n type ReactFlowProps,\n} from \"@xyflow/react\";\nimport \"@xyflow/react/dist/style.css\";\nimport { defaultNodeTypes } from \"../nodes\";\nimport { createConnectionValidator, type ConnectionValidatorOptions } from \"../../registry/connection\";\nimport { sortNodesParentFirst } from \"../FlowEditor/graph-ops\";\nimport { getHelperLines } from \"./helper-lines\";\nimport { HelperLines } from \"./HelperLines\";\nimport type { FlowNode } from \"../../types\";\nimport { useResolvedColorMode } from \"./use-resolved-color-mode\";\n\n/**\n * With wheel-zoom off, Shift+wheel still zooms — and must not ALSO scroll the\n * page while it does. React Flow's own `preventScrolling` is all-or-nothing, so\n * the modifier case is handled here: swallow the gesture that zooms, leave the\n * one that doesn't alone.\n *\n * Capture phase, so it lands before React Flow's own wheel handling.\n */\nfunction preventScrollWhileZooming(event: ReactWheelEvent<HTMLDivElement>): void {\n if (event.shiftKey) event.preventDefault();\n}\n\n/**\n * The three React Flow props that together decide what the wheel does.\n *\n * Extracted because they only make sense as a set, and getting the set wrong is\n * invisible in a screenshot: the canvas looks fine and feels broken. This is\n * the unit worth testing — mounting a canvas to assert it would be testing\n * d3-zoom through jsdom.\n *\n * - **on** (default): no modifier needed, and the page never scrolls under a\n * wheel that is zooming.\n * - **off**: zoom moves to Shift+wheel and the bare wheel goes back to the\n * page. `preventScrolling` alone cannot express that — left true it swallows\n * the bare wheel (page frozen, nothing zooms), left false it lets Shift+wheel\n * zoom *and* scroll at once — so the handler covers the modifier case.\n */\nexport function wheelZoomProps(zoomOnWheel: boolean): {\n zoomActivationKeyCode: string | null;\n preventScrolling: boolean;\n onWheelCapture?: (event: ReactWheelEvent<HTMLDivElement>) => void;\n} {\n return zoomOnWheel\n ? { zoomActivationKeyCode: null, preventScrolling: true }\n : {\n zoomActivationKeyCode: \"Shift\",\n preventScrolling: false,\n onWheelCapture: preventScrollWhileZooming,\n };\n}\n\nexport type FlowCanvasProps = Omit<ReactFlowProps<FlowNode, Edge>, \"nodes\" | \"edges\" | \"height\"> & {\n nodes: FlowNode[];\n edges: Edge[];\n /** Background variant. Default: \"dots\". */\n background?: BackgroundVariant | \"none\";\n /** Show pan/zoom/fit controls. Default true. */\n showControls?: boolean;\n /** Show minimap. Default false (turn on for big graphs). */\n showMinimap?: boolean;\n /** Pixel height; FlowCanvas expects a sized container. Default 600. */\n height?: number | string;\n /**\n * Enforce port-type compatibility on new connections. `true` (default) uses\n * the built-in validator: a connection is refused only when both ports\n * declare a concrete, differing `type` (so untyped graphs are unaffected),\n * and self-loops are blocked. Pass options to tune the rule, or `false` to\n * disable. An `isValidConnection` you pass yourself always takes precedence.\n */\n validateConnections?: boolean | ConnectionValidatorOptions;\n /** Show alignment guide lines while dragging, and snap to them. Default off. */\n showHelperLines?: boolean;\n /**\n * A bare mouse wheel over the canvas zooms it. Default **true**.\n *\n * Turn it off for a canvas embedded mid-page, where a reader scrolling past\n * would otherwise get trapped zooming. With it off the wheel scrolls the page\n * and **Shift+wheel** zooms instead.\n *\n * Either way, a wheel gesture that zooms never also scrolls the page — the\n * two happening at once is the thing that makes an embedded canvas feel\n * broken.\n */\n zoomOnWheel?: boolean;\n /** Optional toolbar / palette etc. rendered above the canvas. */\n toolbar?: ReactNode;\n className?: string;\n style?: CSSProperties;\n};\n\nconst DEFAULT_FIT_VIEW: FitViewOptions = { padding: 0.2 };\nconst DEFAULT_EDGE_OPTIONS: DefaultEdgeOptions = {\n type: \"smoothstep\",\n animated: false,\n};\n\n/**\n * FlowCanvas — themed React Flow surface with the kit's nodes registered\n * by default. Pass your own `nodeTypes` to extend; the kit's defaults are\n * merged behind yours.\n *\n * Hosts wire `onNodesChange` / `onEdgesChange` / `onConnect` themselves\n * (xyflow's standard pattern). The surrounding `useFlowState` hook in\n * `runtime/use-flow-state.ts` is a convenience that wires those for you.\n */\nexport function FlowCanvas({\n nodes,\n edges,\n background = BackgroundVariant.Dots,\n showControls = true,\n showMinimap = false,\n height = 600,\n validateConnections = true,\n isValidConnection,\n colorMode,\n showHelperLines = false,\n zoomOnWheel = true,\n onNodesChange,\n toolbar,\n nodeTypes,\n edgeTypes,\n className,\n style,\n ...rest\n}: FlowCanvasProps) {\n const mergedNodeTypes = useMemo<NodeTypes>(\n () => ({ ...defaultNodeTypes, ...(nodeTypes ?? {}) }),\n [nodeTypes],\n );\n\n // Read nodes live through a ref so the validator (built once) always sees the\n // current graph without being rebuilt on every node change.\n const nodesRef = useRef(nodes);\n nodesRef.current = nodes;\n const builtinValidator = useMemo(\n () =>\n validateConnections === false\n ? undefined\n : createConnectionValidator(\n () => nodesRef.current,\n validateConnections === true ? undefined : validateConnections,\n ),\n [validateConnections],\n );\n // A caller-supplied predicate wins; otherwise fall back to port-type validation.\n const resolvedIsValidConnection = isValidConnection ?? builtinValidator;\n\n const mergedEdgeTypes = useMemo<EdgeTypes | undefined>(\n () => (edgeTypes ? { ...edgeTypes } : undefined),\n [edgeTypes],\n );\n\n // xyflow requires a parent node to precede its children in the array; grouping\n // (swimlanes) can produce any order, so normalize it here at the boundary.\n const orderedNodes = useMemo(() => sortNodesParentFirst(nodes), [nodes]);\n\n // Helper lines: on a single-node drag, snap to aligned edges + show guides.\n const [helperLines, setHelperLines] = useState<{ horizontal?: number; vertical?: number }>({});\n const handleNodesChange = useCallback(\n (changes: any[]) => {\n if (showHelperLines) {\n const pos = changes.filter((c) => c.type === \"position\" && c.position);\n if (pos.length === 1 && pos[0].dragging) {\n const lines = getHelperLines(pos[0], nodesRef.current);\n if (lines.snapPosition.x !== undefined) pos[0].position.x = lines.snapPosition.x;\n if (lines.snapPosition.y !== undefined) pos[0].position.y = lines.snapPosition.y;\n setHelperLines({ horizontal: lines.horizontal, vertical: lines.vertical });\n } else {\n setHelperLines({});\n }\n }\n onNodesChange?.(changes as any);\n },\n [showHelperLines, onNodesChange],\n );\n\n /**\n * An unset `colorMode` means \"follow the app\", NOT \"light\".\n *\n * It used to pass straight through to React Flow, whose own default is\n * light — so on a dark page React Flow's layer stayed light underneath our\n * `ff-` styles, which look right because they hang off an ancestor `.dark`.\n * Any node kind without a registered type falls back to React Flow's default\n * node: a white box with unreadable text on a dark canvas. Passing a mode\n * explicitly still wins.\n */\n const resolvedColorMode = useResolvedColorMode(colorMode);\n\n return (\n <div\n className={[\n \"ff-canvas\",\n // colorMode drives BOTH react-flow's chrome (below) and our `ff-` styles\n // via the shared `.dark` class / light opt-out — one theme signal.\n resolvedColorMode === \"dark\" ? \"dark\" : \"\",\n resolvedColorMode === \"light\" ? \"ff-canvas--light\" : \"\",\n className ?? \"\",\n ]\n .filter(Boolean)\n .join(\" \")}\n style={{ height, ...style }}\n >\n {toolbar && <div className=\"ff-canvas__toolbar\">{toolbar}</div>}\n <div className=\"ff-canvas__surface\">\n <ReactFlow\n nodes={orderedNodes}\n edges={edges}\n onNodesChange={handleNodesChange}\n colorMode={resolvedColorMode}\n nodeTypes={mergedNodeTypes}\n edgeTypes={mergedEdgeTypes}\n fitView\n fitViewOptions={DEFAULT_FIT_VIEW}\n defaultEdgeOptions={DEFAULT_EDGE_OPTIONS}\n proOptions={{ hideAttribution: true }}\n // Wheel zooms by default; `zoomOnWheel={false}` moves that onto\n // Shift+wheel and gives the bare wheel back to the page. The three\n // props only make sense as a set — see wheelZoomProps.\n {...wheelZoomProps(zoomOnWheel)}\n isValidConnection={resolvedIsValidConnection}\n {...rest}\n >\n {background !== \"none\" && (\n <Background variant={background as BackgroundVariant} gap={20} size={1} color=\"rgba(0,0,0,0.18)\" />\n )}\n {showControls && <Controls className=\"ff-controls\" position=\"bottom-right\" />}\n {showMinimap && <MiniMap className=\"ff-minimap\" pannable zoomable />}\n {showHelperLines && <HelperLines horizontal={helperLines.horizontal} vertical={helperLines.vertical} />}\n </ReactFlow>\n </div>\n </div>\n );\n}\n","import { useMemo, type CSSProperties, type ReactNode } from \"react\";\nimport { FlowCanvas } from \"../canvas\";\nimport { buildNodeTypes } from \"../../registry\";\nimport { categoryAccent, getNodeKind } from \"../../registry/registry\";\nimport type { FlowGraph, FlowNode } from \"../../types\";\n\n/** Outcome of one node in a run, for annotating the graph after the fact. */\nexport type FlowNodeStatus = \"ok\" | \"running\" | \"failed\" | \"skipped\" | \"pending\";\n\nexport interface FlowViewerClassNames {\n root?: string;\n list?: string;\n row?: string;\n rowIndex?: string;\n rowTitle?: string;\n rowDescription?: string;\n rowStatus?: string;\n}\n\nexport interface FlowViewerProps {\n /** The graph to show. */\n graph: FlowGraph;\n /**\n * `canvas` draws the graph. `list` renders the nodes as rows — for a docs\n * page, a narrow column, print, or an audit view, where a pan-zoom surface is\n * the wrong shape and often not usable at all.\n */\n variant?: \"canvas\" | \"list\";\n /** Canvas height. Ignored by `list`. Default 480. */\n height?: number | string;\n /** Canvas minimap. Default false. */\n showMinimap?: boolean;\n /** Canvas pan/zoom/fit controls. Default true. */\n showControls?: boolean;\n /**\n * Per-node run outcome, keyed by node id. Lets the same component serve\n * \"here is the workflow\" and \"here is what happened on Tuesday\".\n */\n statuses?: Record<string, FlowNodeStatus>;\n /** Controlled selection. */\n selectedNodeId?: string | null;\n /** Omit and nothing is clickable — a viewer with no handler is inert. */\n onSelectNode?: (node: FlowNode) => void;\n className?: string;\n classNames?: FlowViewerClassNames;\n style?: CSSProperties;\n /** Rendered when the graph has no nodes. */\n empty?: ReactNode;\n}\n\nconst STATUS_LABEL: Record<FlowNodeStatus, string> = {\n ok: \"ok\",\n running: \"running\",\n failed: \"failed\",\n skipped: \"skipped\",\n pending: \"pending\",\n};\n\n/**\n * FlowViewer — a workflow, read-only.\n *\n * **Read-only by construction, not by configuration.** There is no prop that\n * makes this editable, because a viewer that can be switched into an editor is\n * a viewer somebody eventually switches into an editor by accident. Before this\n * existed the only way to show a flow was `FlowEditor` (the whole editor) or\n * `FlowCanvas` plus four React Flow flags a consumer had to know to pass —\n * assembly, not an affordance, and nothing stopped the next person shipping a\n * fully editable canvas where they wanted a picture.\n *\n * Node titles come from the registry, so `overrideNodeKind()` renames apply\n * here too.\n */\nexport function FlowViewer({\n graph,\n variant = \"canvas\",\n height = 480,\n showMinimap = false,\n showControls = true,\n statuses,\n selectedNodeId = null,\n onSelectNode,\n className,\n classNames = {},\n style,\n empty,\n}: FlowViewerProps) {\n const nodeTypes = useMemo(() => buildNodeTypes(), []);\n\n const rows = useMemo(\n () =>\n graph.nodes.map((node, index) => {\n const kind = getNodeKind(node.data?.kind ?? node.type ?? \"\");\n return {\n node,\n index,\n // The node's own label is the name the AUTHOR gave THIS node (\"Summarize\");\n // the kind label is the generic type name (\"LLM Call\"). Specific wins.\n title: node.data?.label ?? kind?.label ?? node.data?.kind ?? node.id,\n description: kind?.description ?? null,\n accent: kind?.accent ?? categoryAccent(kind?.category ?? \"custom\"),\n status: statuses?.[node.id] ?? null,\n };\n }),\n [graph.nodes, statuses],\n );\n\n if (graph.nodes.length === 0) {\n return (\n <div className={cx(\"ff-viewer ff-viewer--empty\", className, classNames.root)} style={style}>\n {empty ?? <span className=\"ff-viewer__empty\">This flow has no nodes.</span>}\n </div>\n );\n }\n\n if (variant === \"list\") {\n return (\n <div\n className={cx(\"ff-viewer ff-viewer--list\", className, classNames.root)}\n style={style}\n data-flow-viewer=\"list\"\n >\n <ol className={cx(\"ff-viewer__list\", classNames.list)}>\n {rows.map(({ node, index, title, description, accent, status }) => {\n const selected = node.id === selectedNodeId;\n const Row = onSelectNode ? \"button\" : \"div\";\n\n return (\n <li key={node.id}>\n <Row\n {...(onSelectNode\n ? { type: \"button\" as const, onClick: () => onSelectNode(node) }\n : {})}\n className={cx(\n \"ff-viewer__row\",\n selected && \"ff-viewer__row--selected\",\n onSelectNode && \"ff-viewer__row--interactive\",\n classNames.row,\n )}\n data-flow-viewer-node={node.id}\n data-flow-viewer-status={status ?? undefined}\n aria-current={selected || undefined}\n >\n <span\n className={cx(\"ff-viewer__index\", classNames.rowIndex)}\n style={{ backgroundColor: accent }}\n aria-hidden\n >\n {index + 1}\n </span>\n\n <span className=\"ff-viewer__body\">\n <span className={cx(\"ff-viewer__title\", classNames.rowTitle)}>{title}</span>\n {description && (\n <span className={cx(\"ff-viewer__desc\", classNames.rowDescription)}>\n {description}\n </span>\n )}\n </span>\n\n {status && (\n <span\n className={cx(\n \"ff-viewer__status\",\n `ff-viewer__status--${status}`,\n classNames.rowStatus,\n )}\n >\n {STATUS_LABEL[status]}\n </span>\n )}\n </Row>\n </li>\n );\n })}\n </ol>\n </div>\n );\n }\n\n return (\n <div\n className={cx(\"ff-viewer ff-viewer--canvas\", className, classNames.root)}\n style={style}\n data-flow-viewer=\"canvas\"\n >\n <FlowCanvas\n nodes={graph.nodes}\n edges={graph.edges}\n nodeTypes={nodeTypes}\n height={height}\n showControls={showControls}\n showMinimap={showMinimap}\n // The read-only contract. Every mutation path React Flow offers is\n // closed here rather than left to the caller to remember.\n nodesDraggable={false}\n nodesConnectable={false}\n nodesFocusable={Boolean(onSelectNode)}\n edgesFocusable={false}\n elementsSelectable={Boolean(onSelectNode)}\n deleteKeyCode={null}\n selectionKeyCode={null}\n multiSelectionKeyCode={null}\n connectOnClick={false}\n // A canvas embedded mid-page must not trap a reader's scroll.\n zoomOnScroll={false}\n onNodeClick={onSelectNode ? (_, node) => onSelectNode(node as FlowNode) : undefined}\n fitView\n />\n </div>\n );\n}\n\nfunction cx(...parts: Array<string | false | null | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n"]}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/connectors.ts
|
|
4
|
+
var SELECTABLE_SANDBOX = ["credential", "base-url", "separate-account"];
|
|
5
|
+
function connectionFields(meta) {
|
|
6
|
+
const modes = [
|
|
7
|
+
{ value: "auto", label: "Auto \u2014 sandbox locally, live in production" },
|
|
8
|
+
{ value: "fake", label: "Fake \u2014 no credentials, no network" }
|
|
9
|
+
];
|
|
10
|
+
if (SELECTABLE_SANDBOX.includes(meta.sandbox)) {
|
|
11
|
+
modes.push({ value: "sandbox", label: sandboxLabel(meta.sandbox) });
|
|
12
|
+
}
|
|
13
|
+
modes.push({ value: "live", label: "Live \u2014 the real account" });
|
|
14
|
+
return [
|
|
15
|
+
{
|
|
16
|
+
type: "credential",
|
|
17
|
+
key: "connection",
|
|
18
|
+
label: `${meta.serviceTitle} connection`,
|
|
19
|
+
credentialType: `connector:${meta.service}`,
|
|
20
|
+
description: `Which configured ${meta.serviceTitle} connection to use. Credentials live in the host's configuration, never in the workflow \u2014 a graph is exported, committed and handed to agents.`
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
type: "select",
|
|
24
|
+
key: "mode",
|
|
25
|
+
label: "Environment",
|
|
26
|
+
options: modes,
|
|
27
|
+
default: "auto",
|
|
28
|
+
description: sandboxNote(meta)
|
|
29
|
+
}
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
function sandboxLabel(kind) {
|
|
33
|
+
return kind === "base-url" ? "Sandbox \u2014 the provider's separate test host" : kind === "separate-account" ? "Sandbox \u2014 your separate test account" : "Sandbox \u2014 the provider's test estate";
|
|
34
|
+
}
|
|
35
|
+
function sandboxNote(meta) {
|
|
36
|
+
if (meta.sandbox === "restricted-reach") {
|
|
37
|
+
return `${meta.serviceTitle} has no separate test estate \u2014 an unreviewed app posts only to its own developers, or privately. Same credentials, same endpoints: only the audience changes, and nothing here selects it. A restricted run looks exactly like a successful one, so confirm reach on the provider's own surface.`;
|
|
38
|
+
}
|
|
39
|
+
if (meta.sandbox === "unverified") {
|
|
40
|
+
return `Nobody has verified what test estate ${meta.serviceTitle} offers, so "sandbox" is not offered \u2014 and "auto" means fake locally and live in production. Find out before pointing a workflow at it.`;
|
|
41
|
+
}
|
|
42
|
+
if (meta.sandbox === "none") {
|
|
43
|
+
return `${meta.serviceTitle} has no sandbox estate, so "auto" means fake locally and live in production.`;
|
|
44
|
+
}
|
|
45
|
+
return "Auto follows the environment. Setting this explicitly overrides it everywhere, including in production.";
|
|
46
|
+
}
|
|
47
|
+
function defineConnectorKind(meta, kind) {
|
|
48
|
+
return {
|
|
49
|
+
...kind,
|
|
50
|
+
// `category` stays fancy-flow's own taxonomy — it describes what the node
|
|
51
|
+
// does to the GRAPH, which is what the palette groups by. Connector-ness is
|
|
52
|
+
// a separate axis and is carried separately; overloading one field with two
|
|
53
|
+
// meanings would make "show me the triggers" and "hide the connectors"
|
|
54
|
+
// impossible to ask at the same time.
|
|
55
|
+
category: kind.category ?? (meta.role === "trigger" ? "trigger" : "io"),
|
|
56
|
+
accent: kind.accent ?? DOMAIN_ACCENT[meta.domain],
|
|
57
|
+
configSchema: [...connectionFields(meta), ...kind.configSchema ?? []],
|
|
58
|
+
connector: meta
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function summarize(meta, config, detail) {
|
|
62
|
+
const mode = typeof config.mode === "string" ? config.mode : "auto";
|
|
63
|
+
const where = mode === "fake" ? " (faked \u2014 nothing leaves this machine)" : mode === "sandbox" ? " in the sandbox" : mode === "live" ? " on the live account" : "";
|
|
64
|
+
const what = detail?.trim() ? detail.trim() : meta.operation.replace(/_/g, " ");
|
|
65
|
+
return meta.role === "trigger" ? `When ${meta.serviceTitle} reports ${what}${where}` : `Then ${meta.serviceTitle} will ${what}${where}`;
|
|
66
|
+
}
|
|
67
|
+
function ingredients(fields) {
|
|
68
|
+
return fields;
|
|
69
|
+
}
|
|
70
|
+
var DOMAIN_ACCENT = {
|
|
71
|
+
payments: "#635bff",
|
|
72
|
+
commerce: "#96bf48",
|
|
73
|
+
messaging: "#4a154b",
|
|
74
|
+
email: "#0f9d58",
|
|
75
|
+
crm: "#00a1e0",
|
|
76
|
+
support: "#03363d",
|
|
77
|
+
storage: "#ff9900",
|
|
78
|
+
calendar: "#4285f4",
|
|
79
|
+
productivity: "#2f3437",
|
|
80
|
+
database: "#336791",
|
|
81
|
+
devtools: "#24292f",
|
|
82
|
+
analytics: "#f9a03c",
|
|
83
|
+
marketing: "#1877f2",
|
|
84
|
+
ai: "#d97757",
|
|
85
|
+
forms: "#262627",
|
|
86
|
+
hr: "#5c4ee5",
|
|
87
|
+
geo: "#34a853"
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
exports.connectionFields = connectionFields;
|
|
91
|
+
exports.defineConnectorKind = defineConnectorKind;
|
|
92
|
+
exports.ingredients = ingredients;
|
|
93
|
+
exports.summarize = summarize;
|
|
94
|
+
//# sourceMappingURL=connectors.cjs.map
|
|
95
|
+
//# sourceMappingURL=connectors.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/connectors.ts"],"names":[],"mappings":"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","file":"connectors.cjs","sourcesContent":["/**\n * The authoring surface every connector node shares.\n *\n * ## Why this is in fancy-flow and not in fancy-connector-core\n *\n * `fancy-connector-core` owns the WIRE — delivery, classification, retries,\n * estate selection — and deliberately knows nothing about flow. This module\n * builds a node's `ConfigField[]` and its `NodeKindDefinition`, which are\n * fancy-flow concepts, so putting it there would couple the runtime to the\n * editor and force a non-flow consumer to install one to make an HTTP call.\n *\n * It lived as vendored source in the node marketplace until 0.48.0, which was\n * fine for a node (a copy costs a consumer no dependency) and impossible for a\n * PACKAGE — a package cannot import vendored sandbox source, so every generated\n * `<provider>-ui` package carried its own copy of a file only this repo can\n * correctly change. At the scale the connector estate is heading for that is\n * the exact \"a copy cannot be upgraded\" problem the packages exist to solve.\n *\n * ## The model, and where it came from\n *\n * IFTTT's authoring UX is the one non-engineers actually complete, and three of\n * its four ideas map onto fancy-flow without distortion:\n *\n * 1. **Service first, then capability.** You pick Stripe, *then* pick what about\n * Stripe. Not a flat wall of four hundred nodes. Here that lives in the\n * registry — `connector.service` groups a provider's nodes, and the listing\n * tools narrow in two steps.\n * 2. **The connection is a thing, not a field.** You authorize a service once\n * and every applet reuses it. Here: `connection.ts` in the runtime, and the\n * single `connection` config field below.\n * 3. **Ingredients.** A trigger's output fields become named tokens you drop\n * into a downstream action's fields. fancy-flow already has the machinery —\n * `outputShape` on the kind, `availableVariables()` reading it off direct\n * predecessors — so a connector's job is simply to DECLARE its shape. See\n * `ingredients.ts`.\n * 4. **A sentence, not a form dump.** `summarize()` below.\n *\n * ## Where it does NOT map, and what we did instead\n *\n * An IFTTT applet is one trigger and one action, so \"the ingredients\" is\n * unambiguous: there is only one upstream. A fancy-flow graph branches, fans\n * out, merges and nests, so a connector node several hops downstream has no\n * single trigger to draw from — `availableVariables()` deliberately offers only\n * DIRECT predecessors, because a grandparent's field resolves to `null` at run\n * time and a suggestion that silently produces nothing is worse than no\n * suggestion.\n *\n * We did not paper over that. Connector triggers publish their event as a\n * single object with a declared shape, so the natural thing an author does —\n * carry it forward on the wire — keeps the ingredients available at each step.\n * Reaching further up the graph is a fancy-flow concern, recorded as a finding\n * rather than reimplemented per node.\n */\n\nimport type { ConfigField, NodeKindDefinition } from \"./registry/types\";\nimport type { OutputField } from \"./expressions/variables\";\n\n// Re-exported so a connector package needs ONE import rather than two entries.\nexport type { OutputField };\n\n/** The domains the catalogue is grouped by. Mirrors the plan's taxonomy. */\nexport type ConnectorDomain =\n | \"payments\"\n | \"commerce\"\n | \"messaging\"\n | \"email\"\n | \"crm\"\n | \"support\"\n | \"storage\"\n | \"calendar\"\n | \"productivity\"\n | \"database\"\n | \"devtools\"\n | \"analytics\"\n | \"marketing\"\n | \"ai\"\n | \"forms\"\n | \"hr\"\n | \"geo\";\n\n/** What a connector node does in the graph — IFTTT's \"this\" versus \"that\". */\nexport type ConnectorRole = \"trigger\" | \"action\" | \"search\";\n\n/**\n * How the provider exposes a test estate. Kept in step with the runtime's\n * `SandboxKind`, and `vendoring.test.ts` compares the two declarations — a\n * hand-maintained mirror with nothing checking it is the shape this repository\n * keeps finding.\n *\n * Two of these are answers people skip. `unverified` means NOBODY HAS CHECKED —\n * a real state, and the right one until somebody has. `restricted-reach` is the\n * dangerous one: same credentials, same endpoints, same estate, and only the\n * AUDIENCE restricted, so it looks exactly like a successful post nobody can\n * see. Neither is `none`, and neither can be selected as a mode.\n */\nexport type SandboxKind =\n | \"credential\"\n | \"base-url\"\n | \"separate-account\"\n | \"restricted-reach\"\n | \"none\"\n | \"unverified\";\n\n/** The kinds a `sandbox` mode can actually point at. Mirrors `sandboxIsSelectable`. */\nconst SELECTABLE_SANDBOX: readonly SandboxKind[] = [\"credential\", \"base-url\", \"separate-account\"];\n\nexport type ConnectorMeta = {\n service: string;\n serviceTitle: string;\n domain: ConnectorDomain;\n role: ConnectorRole;\n /** The provider's name for this operation, so search finds what people type. */\n operation: string;\n sandbox: SandboxKind;\n /** Link to the provider documentation this node was written against. */\n docs?: string;\n};\n\n/**\n * The two fields EVERY connector node carries, in the same order, with the same\n * keys.\n *\n * Uniformity is the feature. An agent that has configured one connector has\n * configured all of them, and a human who has learned where the sandbox switch\n * lives never has to look for it again.\n */\nexport function connectionFields(meta: ConnectorMeta): ConfigField[] {\n const modes: Array<{ value: string; label: string }> = [\n { value: \"auto\", label: \"Auto — sandbox locally, live in production\" },\n { value: \"fake\", label: \"Fake — no credentials, no network\" },\n ];\n\n // Only offer sandbox where one exists. A select listing a mode the provider\n // does not have is an invitation to pick it and then read an error.\n if (SELECTABLE_SANDBOX.includes(meta.sandbox)) {\n modes.push({ value: \"sandbox\", label: sandboxLabel(meta.sandbox) });\n }\n modes.push({ value: \"live\", label: \"Live — the real account\" });\n\n return [\n {\n type: \"credential\",\n key: \"connection\",\n label: `${meta.serviceTitle} connection`,\n credentialType: `connector:${meta.service}`,\n description:\n `Which configured ${meta.serviceTitle} connection to use. Credentials live in the host's ` +\n \"configuration, never in the workflow — a graph is exported, committed and handed to agents.\",\n },\n {\n type: \"select\",\n key: \"mode\",\n label: \"Environment\",\n options: modes,\n default: \"auto\",\n description: sandboxNote(meta),\n },\n ];\n}\n\nfunction sandboxLabel(kind: SandboxKind): string {\n return kind === \"base-url\"\n ? \"Sandbox — the provider's separate test host\"\n : kind === \"separate-account\"\n ? \"Sandbox — your separate test account\"\n : \"Sandbox — the provider's test estate\";\n}\n\n/**\n * What \"auto\" means for this provider, said where the author is choosing.\n *\n * The two non-selectable kinds get their own sentence rather than sharing\n * `none`'s. `restricted-reach` in particular has to be said HERE — on the field\n * somebody is filling in — because the failure it produces is a run that looks\n * completely successful and reached nobody, and by the time that is visible the\n * author has stopped looking at this screen.\n */\nfunction sandboxNote(meta: ConnectorMeta): string {\n if (meta.sandbox === \"restricted-reach\") {\n return (\n `${meta.serviceTitle} has no separate test estate — an unreviewed app posts only to its own developers, ` +\n \"or privately. Same credentials, same endpoints: only the audience changes, and nothing here selects it. \" +\n \"A restricted run looks exactly like a successful one, so confirm reach on the provider's own surface.\"\n );\n }\n\n if (meta.sandbox === \"unverified\") {\n return (\n `Nobody has verified what test estate ${meta.serviceTitle} offers, so \"sandbox\" is not offered — and ` +\n '\"auto\" means fake locally and live in production. Find out before pointing a workflow at it.'\n );\n }\n\n if (meta.sandbox === \"none\") {\n return `${meta.serviceTitle} has no sandbox estate, so \"auto\" means fake locally and live in production.`;\n }\n\n return \"Auto follows the environment. Setting this explicitly overrides it everywhere, including in production.\";\n}\n\n/**\n * Build a connector node's authoring surface.\n *\n * Prepends the shared connection fields, applies the domain accent, and stamps\n * the metadata the registry reads. A connector that hand-rolled these would\n * drift from its siblings in exactly the small ways that make a catalogue feel\n * like a pile.\n */\nexport function defineConnectorKind(\n meta: ConnectorMeta,\n kind: Omit<NodeKindDefinition, \"category\"> & { category?: NodeKindDefinition[\"category\"] },\n): NodeKindDefinition & { connector: ConnectorMeta } {\n return {\n ...kind,\n // `category` stays fancy-flow's own taxonomy — it describes what the node\n // does to the GRAPH, which is what the palette groups by. Connector-ness is\n // a separate axis and is carried separately; overloading one field with two\n // meanings would make \"show me the triggers\" and \"hide the connectors\"\n // impossible to ask at the same time.\n category: kind.category ?? (meta.role === \"trigger\" ? \"trigger\" : \"io\"),\n accent: kind.accent ?? DOMAIN_ACCENT[meta.domain],\n configSchema: [...connectionFields(meta), ...(kind.configSchema ?? [])],\n connector: meta,\n };\n}\n\n/**\n * One line describing what a configured node will do, in IFTTT's register.\n *\n * A configured connector should read as a sentence, not as a form dump — it is\n * what makes a canvas skimmable, and it is also what an agent quotes back to a\n * human when asking whether to proceed.\n */\nexport function summarize(meta: ConnectorMeta, config: Record<string, unknown>, detail?: string): string {\n const mode = typeof config.mode === \"string\" ? config.mode : \"auto\";\n const where =\n mode === \"fake\"\n ? \" (faked — nothing leaves this machine)\"\n : mode === \"sandbox\"\n ? \" in the sandbox\"\n : mode === \"live\"\n ? \" on the live account\"\n : \"\";\n\n const what = detail?.trim() ? detail.trim() : meta.operation.replace(/_/g, \" \");\n\n return meta.role === \"trigger\"\n ? `When ${meta.serviceTitle} reports ${what}${where}`\n : `Then ${meta.serviceTitle} will ${what}${where}`;\n}\n\n/** Declare a trigger's event fields — the \"ingredients\" downstream nodes pick from. */\nexport function ingredients(fields: OutputField[]): OutputField[] {\n return fields;\n}\n\nconst DOMAIN_ACCENT: Record<ConnectorDomain, string> = {\n payments: \"#635bff\",\n commerce: \"#96bf48\",\n messaging: \"#4a154b\",\n email: \"#0f9d58\",\n crm: \"#00a1e0\",\n support: \"#03363d\",\n storage: \"#ff9900\",\n calendar: \"#4285f4\",\n productivity: \"#2f3437\",\n database: \"#336791\",\n devtools: \"#24292f\",\n analytics: \"#f9a03c\",\n marketing: \"#1877f2\",\n ai: \"#d97757\",\n forms: \"#262627\",\n hr: \"#5c4ee5\",\n geo: \"#34a853\",\n};\n"]}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { C as ConfigField, N as NodeKindDefinition, O as OutputField } from './types-BO8TgI2M.cjs';
|
|
2
|
+
import 'react';
|
|
3
|
+
import './types-Jx1TwehV.cjs';
|
|
4
|
+
import '@xyflow/react';
|
|
5
|
+
import './pause-9iT4tCEV.cjs';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The authoring surface every connector node shares.
|
|
9
|
+
*
|
|
10
|
+
* ## Why this is in fancy-flow and not in fancy-connector-core
|
|
11
|
+
*
|
|
12
|
+
* `fancy-connector-core` owns the WIRE — delivery, classification, retries,
|
|
13
|
+
* estate selection — and deliberately knows nothing about flow. This module
|
|
14
|
+
* builds a node's `ConfigField[]` and its `NodeKindDefinition`, which are
|
|
15
|
+
* fancy-flow concepts, so putting it there would couple the runtime to the
|
|
16
|
+
* editor and force a non-flow consumer to install one to make an HTTP call.
|
|
17
|
+
*
|
|
18
|
+
* It lived as vendored source in the node marketplace until 0.48.0, which was
|
|
19
|
+
* fine for a node (a copy costs a consumer no dependency) and impossible for a
|
|
20
|
+
* PACKAGE — a package cannot import vendored sandbox source, so every generated
|
|
21
|
+
* `<provider>-ui` package carried its own copy of a file only this repo can
|
|
22
|
+
* correctly change. At the scale the connector estate is heading for that is
|
|
23
|
+
* the exact "a copy cannot be upgraded" problem the packages exist to solve.
|
|
24
|
+
*
|
|
25
|
+
* ## The model, and where it came from
|
|
26
|
+
*
|
|
27
|
+
* IFTTT's authoring UX is the one non-engineers actually complete, and three of
|
|
28
|
+
* its four ideas map onto fancy-flow without distortion:
|
|
29
|
+
*
|
|
30
|
+
* 1. **Service first, then capability.** You pick Stripe, *then* pick what about
|
|
31
|
+
* Stripe. Not a flat wall of four hundred nodes. Here that lives in the
|
|
32
|
+
* registry — `connector.service` groups a provider's nodes, and the listing
|
|
33
|
+
* tools narrow in two steps.
|
|
34
|
+
* 2. **The connection is a thing, not a field.** You authorize a service once
|
|
35
|
+
* and every applet reuses it. Here: `connection.ts` in the runtime, and the
|
|
36
|
+
* single `connection` config field below.
|
|
37
|
+
* 3. **Ingredients.** A trigger's output fields become named tokens you drop
|
|
38
|
+
* into a downstream action's fields. fancy-flow already has the machinery —
|
|
39
|
+
* `outputShape` on the kind, `availableVariables()` reading it off direct
|
|
40
|
+
* predecessors — so a connector's job is simply to DECLARE its shape. See
|
|
41
|
+
* `ingredients.ts`.
|
|
42
|
+
* 4. **A sentence, not a form dump.** `summarize()` below.
|
|
43
|
+
*
|
|
44
|
+
* ## Where it does NOT map, and what we did instead
|
|
45
|
+
*
|
|
46
|
+
* An IFTTT applet is one trigger and one action, so "the ingredients" is
|
|
47
|
+
* unambiguous: there is only one upstream. A fancy-flow graph branches, fans
|
|
48
|
+
* out, merges and nests, so a connector node several hops downstream has no
|
|
49
|
+
* single trigger to draw from — `availableVariables()` deliberately offers only
|
|
50
|
+
* DIRECT predecessors, because a grandparent's field resolves to `null` at run
|
|
51
|
+
* time and a suggestion that silently produces nothing is worse than no
|
|
52
|
+
* suggestion.
|
|
53
|
+
*
|
|
54
|
+
* We did not paper over that. Connector triggers publish their event as a
|
|
55
|
+
* single object with a declared shape, so the natural thing an author does —
|
|
56
|
+
* carry it forward on the wire — keeps the ingredients available at each step.
|
|
57
|
+
* Reaching further up the graph is a fancy-flow concern, recorded as a finding
|
|
58
|
+
* rather than reimplemented per node.
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
/** The domains the catalogue is grouped by. Mirrors the plan's taxonomy. */
|
|
62
|
+
type ConnectorDomain = "payments" | "commerce" | "messaging" | "email" | "crm" | "support" | "storage" | "calendar" | "productivity" | "database" | "devtools" | "analytics" | "marketing" | "ai" | "forms" | "hr" | "geo";
|
|
63
|
+
/** What a connector node does in the graph — IFTTT's "this" versus "that". */
|
|
64
|
+
type ConnectorRole = "trigger" | "action" | "search";
|
|
65
|
+
/**
|
|
66
|
+
* How the provider exposes a test estate. Kept in step with the runtime's
|
|
67
|
+
* `SandboxKind`, and `vendoring.test.ts` compares the two declarations — a
|
|
68
|
+
* hand-maintained mirror with nothing checking it is the shape this repository
|
|
69
|
+
* keeps finding.
|
|
70
|
+
*
|
|
71
|
+
* Two of these are answers people skip. `unverified` means NOBODY HAS CHECKED —
|
|
72
|
+
* a real state, and the right one until somebody has. `restricted-reach` is the
|
|
73
|
+
* dangerous one: same credentials, same endpoints, same estate, and only the
|
|
74
|
+
* AUDIENCE restricted, so it looks exactly like a successful post nobody can
|
|
75
|
+
* see. Neither is `none`, and neither can be selected as a mode.
|
|
76
|
+
*/
|
|
77
|
+
type SandboxKind = "credential" | "base-url" | "separate-account" | "restricted-reach" | "none" | "unverified";
|
|
78
|
+
type ConnectorMeta = {
|
|
79
|
+
service: string;
|
|
80
|
+
serviceTitle: string;
|
|
81
|
+
domain: ConnectorDomain;
|
|
82
|
+
role: ConnectorRole;
|
|
83
|
+
/** The provider's name for this operation, so search finds what people type. */
|
|
84
|
+
operation: string;
|
|
85
|
+
sandbox: SandboxKind;
|
|
86
|
+
/** Link to the provider documentation this node was written against. */
|
|
87
|
+
docs?: string;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* The two fields EVERY connector node carries, in the same order, with the same
|
|
91
|
+
* keys.
|
|
92
|
+
*
|
|
93
|
+
* Uniformity is the feature. An agent that has configured one connector has
|
|
94
|
+
* configured all of them, and a human who has learned where the sandbox switch
|
|
95
|
+
* lives never has to look for it again.
|
|
96
|
+
*/
|
|
97
|
+
declare function connectionFields(meta: ConnectorMeta): ConfigField[];
|
|
98
|
+
/**
|
|
99
|
+
* Build a connector node's authoring surface.
|
|
100
|
+
*
|
|
101
|
+
* Prepends the shared connection fields, applies the domain accent, and stamps
|
|
102
|
+
* the metadata the registry reads. A connector that hand-rolled these would
|
|
103
|
+
* drift from its siblings in exactly the small ways that make a catalogue feel
|
|
104
|
+
* like a pile.
|
|
105
|
+
*/
|
|
106
|
+
declare function defineConnectorKind(meta: ConnectorMeta, kind: Omit<NodeKindDefinition, "category"> & {
|
|
107
|
+
category?: NodeKindDefinition["category"];
|
|
108
|
+
}): NodeKindDefinition & {
|
|
109
|
+
connector: ConnectorMeta;
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* One line describing what a configured node will do, in IFTTT's register.
|
|
113
|
+
*
|
|
114
|
+
* A configured connector should read as a sentence, not as a form dump — it is
|
|
115
|
+
* what makes a canvas skimmable, and it is also what an agent quotes back to a
|
|
116
|
+
* human when asking whether to proceed.
|
|
117
|
+
*/
|
|
118
|
+
declare function summarize(meta: ConnectorMeta, config: Record<string, unknown>, detail?: string): string;
|
|
119
|
+
/** Declare a trigger's event fields — the "ingredients" downstream nodes pick from. */
|
|
120
|
+
declare function ingredients(fields: OutputField[]): OutputField[];
|
|
121
|
+
|
|
122
|
+
export { type ConnectorDomain, type ConnectorMeta, type ConnectorRole, OutputField, type SandboxKind, connectionFields, defineConnectorKind, ingredients, summarize };
|