@particle-academy/fancy-flow 0.41.0 → 0.43.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/index.d.cts CHANGED
@@ -5,19 +5,19 @@ import { ConnectionValidatorOptions } from './registry/index.cjs';
5
5
  export { ANY_PORT_TYPE, BUILTIN_KINDS, PortCompatibility, RegistryNode, RichInputAdapter, RichInputPreview, buildNodeTypes, createConnectionValidator, defaultPortCompatibility, getRichInputAdapter, isRichInputEnabled, onRichInputAdapterChanged, registerBuiltinKinds, registerRichInputAdapter, resolveNodePorts, resolvePortSpec } from './registry/index.cjs';
6
6
  import { b as FlowNode, F as FlowGraph, e as NodeRunStatus, E as ExecutorRegistry } from './types-sOmpCitB.cjs';
7
7
  export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, a as FlowEdge, c as FlowNodeData, d as FlowNodeKind, N as NodeExecutor, f as NoteNodeData, O as OutputNodeData, P as PortDescriptor, R as RunEvent, S as SubgraphNodeData, T as TriggerNodeData } from './types-sOmpCitB.cjs';
8
- import { C as ConfigFieldRenderFn } from './ConfigFieldRenderer-4xK9hzvd.cjs';
9
- export { a as ConfigFieldRenderContext, b as ConfigFieldRenderer, c as ConfigFieldRendererProps } from './ConfigFieldRenderer-4xK9hzvd.cjs';
8
+ import { C as ConfigFieldRenderFn } from './ConfigFieldRenderer-LotNHeG8.cjs';
9
+ export { a as ConfigFieldRenderContext, b as ConfigFieldRenderer, c as ConfigFieldRendererProps } from './ConfigFieldRenderer-LotNHeG8.cjs';
10
10
  import { WorkflowSchema, WorkflowMetadata } from './schema/index.cjs';
11
11
  export { ImportIssue, ImportOptions, ImportResult, WORKFLOW_SCHEMA_URL, WORKFLOW_SCHEMA_VERSION, WorkflowSchemaEdge, WorkflowSchemaNode, exportWorkflow, importWorkflow, migrateSchema, workflowToBlob } from './schema/index.cjs';
12
12
  import { AutoLayoutOptions } from './layout/index.cjs';
13
13
  export { AutoLayoutDirection } from './layout/index.cjs';
14
- import { c as NodeCategory, d as NodeKindDefinition } from './types-cAdD1Og2.cjs';
15
- export { a as ConfigField, D as DocumentConfigField, K as KeyValueConfigField, L as LEGACY_PAUSE_PREFIXES, h as PAUSE_PREFIX, P as PauseAwaiting, i as PauseSignal, j as PortSpec, R as RenderBodyContext, t as RepeaterConfigField, u as RepeaterRowField, m as decodePause, n as encodePause, o as isPause, p as pauseForHuman } from './types-cAdD1Og2.cjs';
14
+ import { c as NodeCategory, d as NodeKindDefinition } from './types-B78Rm69S.cjs';
15
+ export { A as AvailableVariable, a as ConfigField, D as DocumentConfigField, z as ExpressionForm, B as ExpressionGrammarHelp, K as KeyValueConfigField, L as LEGACY_PAUSE_PREFIXES, O as OutputField, F as OutputShape, h as PAUSE_PREFIX, P as PauseAwaiting, i as PauseSignal, j as PortSpec, R as RenderBodyContext, t as RepeaterConfigField, u as RepeaterRowField, G as availableVariables, H as baseVariables, m as decodePause, I as describeExpressionGrammar, n as encodePause, o as isPause, Q as outputFieldsFor, p as pauseForHuman } from './types-B78Rm69S.cjs';
16
16
  export { F as FlowNodeStatus, a as FlowViewer, b as FlowViewerClassNames, c as FlowViewerProps } from './FlowViewer-nLqo7s2E.cjs';
17
17
  import { FlowRunFeedEntry } from './runtime/index.cjs';
18
18
  export { HistoryController, UseFlowHistoryReturn, UseFlowRunOptions, UseFlowRunReturn, UseFlowStateReturn, applyOutputsToNodes, applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState } from './runtime/index.cjs';
19
19
  export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, R as RunOptions, d as RunResult, r as runCohort, e as runFlow } from './run-cohort-Bjv2ZU6g.cjs';
20
- export { N as NodeKindPresentation, c as categoryAccent, b as clearNodeKindOverrides, d as defaultConfigFor, g as getNodeKind, l as listNodeKinds, o as onNodeKindsChanged, e as overrideNodeKind, r as registerNodeKind, v as validateConfig } from './registry-BNyT66SS.cjs';
20
+ export { N as NodeKindPresentation, c as categoryAccent, b as clearNodeKindOverrides, d as defaultConfigFor, g as getNodeKind, l as listNodeKinds, o as onNodeKindsChanged, e as overrideNodeKind, r as registerNodeKind, v as validateConfig } from './registry-C9KMVpn7.cjs';
21
21
  import './capabilities-BtJQTbnw.cjs';
22
22
 
23
23
  type FlowCanvasProps = Omit<ReactFlowProps<FlowNode, Edge>, "nodes" | "edges" | "height"> & {
@@ -98,6 +98,13 @@ type NodeConfigPanelProps = {
98
98
  */
99
99
  /** Host renderers keyed by field `type`. See {@link ConfigFieldRenderer}. */
100
100
  fieldRenderers?: Record<string, ConfigFieldRenderFn>;
101
+ /**
102
+ * The graph the node lives in. Supplying it is what makes the `{{ }}` variable
103
+ * picker context-aware — it reads the UPSTREAM node's declared `outputShape`
104
+ * to list what is actually reachable here (issue #5). Without it the picker
105
+ * still opens, but can only offer the whole input.
106
+ */
107
+ graph?: FlowGraph;
101
108
  renderDocumentField?: (props: {
102
109
  documentType?: string;
103
110
  value: unknown;
@@ -110,7 +117,7 @@ type NodeConfigPanelProps = {
110
117
  * NodeConfigPanel — schema-driven form for the selected node. Defers to
111
118
  * `kind.renderPanel` if the kind opts out of the auto-form.
112
119
  */
113
- declare function NodeConfigPanel({ node, onChange, onDelete, deleteLabel, header, renderCredentialField, renderDocumentField, fieldRenderers, className, style, }: NodeConfigPanelProps): react.JSX.Element;
120
+ declare function NodeConfigPanel({ node, onChange, onDelete, deleteLabel, header, renderCredentialField, renderDocumentField, fieldRenderers, graph, className, style, }: NodeConfigPanelProps): react.JSX.Element;
114
121
 
115
122
  /**
116
123
  * Clone a set of nodes AND the edges internal to that set, remapping every id.
@@ -620,4 +627,116 @@ declare const flowKeys: {
620
627
  readonly run: (runId: string) => readonly ["flow", "runs", string];
621
628
  };
622
629
 
623
- export { ActionNode, type AlignEdge, AutoLayoutOptions, ConfigFieldRenderFn, ConnectionValidatorOptions, DecisionNode, ExecutorRegistry, FlowCanvas, type FlowCanvasProps, FlowEditor, type FlowEditorAction, type FlowEditorApi, type FlowEditorBuiltins, type FlowEditorProps, type FlowEditorSlots, FlowGraph, FlowNode, type FlowNodeRenderProps, FlowRunControls, type FlowRunControlsProps, FlowRunFeed, FlowRunFeedEntry, type FlowRunFeedProps, LaneNode, NodeCategory, NodeConfigPanel, type NodeConfigPanelProps, NodeKindDefinition, NodePalette, type NodePaletteProps, NodePort, type NodePortProps, type NodePortSide, type NodePortType, NodeRunStatus, NodeShell, type NodeShellProps, NoteNode, OutputNode, SubgraphNode, TriggerNode, WorkflowMetadata, WorkflowSchema, alignNodes, cloneSubgraph, defaultNodeTypes, defineNode, distributeNodes, flowKeys, flowLive, paletteDropHandlers, reconnectEdge, useFlowEditor, useFlowEditorOptional };
630
+ type ExpressionFieldProps = {
631
+ value: string;
632
+ onChange: (next: string) => void;
633
+ placeholder?: string;
634
+ rows?: number;
635
+ /** The panel's field id + agent handle. */
636
+ handle: {
637
+ id?: string;
638
+ "data-ff-field": string;
639
+ };
640
+ /**
641
+ * The graph and the node being edited. Both are needed to answer "what can I
642
+ * write here" — without them the picker can still offer `{{ $json }}` but
643
+ * nothing node-specific, which is the static list issue #5 asked us not to
644
+ * ship.
645
+ */
646
+ graph?: FlowGraph;
647
+ nodeId?: string;
648
+ };
649
+ /**
650
+ * ExpressionField — a `{{ }}` field that tells the author what it accepts.
651
+ *
652
+ * Issue #5: the panel rendered a bare textarea with a placeholder and nothing
653
+ * else, so writing an expression required already knowing both the grammar and
654
+ * the exact shape of the upstream node's output. Two affordances close that:
655
+ * typing `{{ ` opens a picker of the variables actually reachable at THIS node,
656
+ * and a reference toggle explains the grammar.
657
+ *
658
+ * The picker deliberately lists only what the resolver can reach — see
659
+ * `availableVariables`. A suggestion that resolves to `null` at runtime is
660
+ * worse than no suggestion, because the author has no reason to doubt it.
661
+ */
662
+ declare function ExpressionField({ value, onChange, placeholder, rows, handle, graph, nodeId, }: ExpressionFieldProps): react.JSX.Element;
663
+
664
+ /**
665
+ * `{{ }}` resolution — the TypeScript twin of `FancyFlow\Nodes\Support\Expr`.
666
+ *
667
+ * ## Why this is opt-in and not wired into `runFlow`
668
+ *
669
+ * The PHP runtime resolves expressions inside its batteries-included executors.
670
+ * The JS runtime never has: `runFlow` hands `node.data.config` to your executor
671
+ * verbatim, so every host that uses `{{ }}` today already resolves it itself.
672
+ * Turning resolution on inside `runFlow` would interpolate a second time over
673
+ * values those hosts had already substituted — silently, and only for graphs
674
+ * that happen to contain `{{` in their DATA.
675
+ *
676
+ * So this exports the semantics and changes no behaviour. Call it yourself:
677
+ *
678
+ * ```ts
679
+ * const url = evaluateExpression(node.data.config.url, inputs);
680
+ * ```
681
+ *
682
+ * ## The semantics are the PHP file's, deliberately
683
+ *
684
+ * This is not a general expression language and must not grow into one. It
685
+ * resolves a dot-path against a context and nothing else — no arithmetic, no
686
+ * comparisons, no calls. Hosts that want real expressions override the executor
687
+ * (the PHP docblock points at symfony/expression-language for the same reason).
688
+ *
689
+ * Divergence here is a correctness bug rather than a style difference: the same
690
+ * graph is authored once and may run on either runtime. `suites/shared/expr`
691
+ * in `@particle-academy/fancy-conformance` is the fixture table both sides run,
692
+ * so parity is a test result instead of a claim.
693
+ */
694
+ /** Anything a context or a resolved value can be. */
695
+ type ExprValue = unknown;
696
+ /** The context an expression resolves against — the executor's `inputs`. */
697
+ type ExprContext = Record<string, ExprValue>;
698
+ /**
699
+ * Resolve a dot-path against the context, honouring the `$json` / `$input`
700
+ * alias.
701
+ *
702
+ * Both aliases point at the `in` port value when the context has one, and at
703
+ * the whole context otherwise — the same fallback the PHP does, which is what
704
+ * makes `{{ $json.x }}` work on a trigger node that has no upstream input.
705
+ *
706
+ * A path that does not resolve returns `null`, never `undefined`: PHP has one
707
+ * absent value and JS has two, and letting the difference leak would make the
708
+ * two runtimes disagree about `{{ missing }}` for no useful reason.
709
+ */
710
+ declare function resolvePath(path: string, context: ExprContext): ExprValue;
711
+ /**
712
+ * Evaluate a template against a context.
713
+ *
714
+ * A string that is EXACTLY one expression returns the resolved value with its
715
+ * type intact — `{{ $json.count }}` gives you a number, not `"3"`. Anything
716
+ * else interpolates each run as text. That distinction is load-bearing: it is
717
+ * what lets a config field carry either a value or a sentence.
718
+ *
719
+ * Non-string templates pass through untouched, so this is safe to map over a
720
+ * whole config object.
721
+ */
722
+ declare function evaluateExpression(template: ExprValue, context: ExprContext): ExprValue;
723
+ /**
724
+ * Truthiness for branch / switch decisions.
725
+ *
726
+ * Mirrors PHP's rules rather than JavaScript's, because the graph is authored
727
+ * once and may run on either side. The two disagree in exactly the places a
728
+ * workflow hits: `"0"` and `"false"` are truthy in JS and falsy here, and an
729
+ * empty array is truthy in JS and falsy here.
730
+ */
731
+ declare function truthy(value: ExprValue): boolean;
732
+ /** Coerce a value to text the way interpolation does. */
733
+ declare function text(value: ExprValue): string;
734
+ /**
735
+ * Resolve every string in a config object, one level of nesting at a time.
736
+ *
737
+ * The convenience most hosts actually want, and the shape their hand-rolled
738
+ * version usually takes. Opt-in like the rest of this module.
739
+ */
740
+ declare function evaluateConfig<T extends Record<string, ExprValue>>(config: T, context: ExprContext): T;
741
+
742
+ export { ActionNode, type AlignEdge, AutoLayoutOptions, ConfigFieldRenderFn, ConnectionValidatorOptions, DecisionNode, ExecutorRegistry, type ExprContext, type ExprValue, ExpressionField, type ExpressionFieldProps, FlowCanvas, type FlowCanvasProps, FlowEditor, type FlowEditorAction, type FlowEditorApi, type FlowEditorBuiltins, type FlowEditorProps, type FlowEditorSlots, FlowGraph, FlowNode, type FlowNodeRenderProps, FlowRunControls, type FlowRunControlsProps, FlowRunFeed, FlowRunFeedEntry, type FlowRunFeedProps, LaneNode, NodeCategory, NodeConfigPanel, type NodeConfigPanelProps, NodeKindDefinition, NodePalette, type NodePaletteProps, NodePort, type NodePortProps, type NodePortSide, type NodePortType, NodeRunStatus, NodeShell, type NodeShellProps, NoteNode, OutputNode, SubgraphNode, TriggerNode, WorkflowMetadata, WorkflowSchema, alignNodes, cloneSubgraph, defaultNodeTypes, defineNode, distributeNodes, evaluateConfig, evaluateExpression, flowKeys, flowLive, paletteDropHandlers, reconnectEdge, resolvePath, text, truthy, useFlowEditor, useFlowEditorOptional };
package/dist/index.d.ts CHANGED
@@ -5,19 +5,19 @@ import { ConnectionValidatorOptions } from './registry/index.js';
5
5
  export { ANY_PORT_TYPE, BUILTIN_KINDS, PortCompatibility, RegistryNode, RichInputAdapter, RichInputPreview, buildNodeTypes, createConnectionValidator, defaultPortCompatibility, getRichInputAdapter, isRichInputEnabled, onRichInputAdapterChanged, registerBuiltinKinds, registerRichInputAdapter, resolveNodePorts, resolvePortSpec } from './registry/index.js';
6
6
  import { b as FlowNode, F as FlowGraph, e as NodeRunStatus, E as ExecutorRegistry } from './types-sOmpCitB.js';
7
7
  export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, a as FlowEdge, c as FlowNodeData, d as FlowNodeKind, N as NodeExecutor, f as NoteNodeData, O as OutputNodeData, P as PortDescriptor, R as RunEvent, S as SubgraphNodeData, T as TriggerNodeData } from './types-sOmpCitB.js';
8
- import { C as ConfigFieldRenderFn } from './ConfigFieldRenderer-D2TejNY1.js';
9
- export { a as ConfigFieldRenderContext, b as ConfigFieldRenderer, c as ConfigFieldRendererProps } from './ConfigFieldRenderer-D2TejNY1.js';
8
+ import { C as ConfigFieldRenderFn } from './ConfigFieldRenderer-BHQDZer6.js';
9
+ export { a as ConfigFieldRenderContext, b as ConfigFieldRenderer, c as ConfigFieldRendererProps } from './ConfigFieldRenderer-BHQDZer6.js';
10
10
  import { WorkflowSchema, WorkflowMetadata } from './schema/index.js';
11
11
  export { ImportIssue, ImportOptions, ImportResult, WORKFLOW_SCHEMA_URL, WORKFLOW_SCHEMA_VERSION, WorkflowSchemaEdge, WorkflowSchemaNode, exportWorkflow, importWorkflow, migrateSchema, workflowToBlob } from './schema/index.js';
12
12
  import { AutoLayoutOptions } from './layout/index.js';
13
13
  export { AutoLayoutDirection } from './layout/index.js';
14
- import { c as NodeCategory, d as NodeKindDefinition } from './types-Cf75IbxY.js';
15
- export { a as ConfigField, D as DocumentConfigField, K as KeyValueConfigField, L as LEGACY_PAUSE_PREFIXES, h as PAUSE_PREFIX, P as PauseAwaiting, i as PauseSignal, j as PortSpec, R as RenderBodyContext, t as RepeaterConfigField, u as RepeaterRowField, m as decodePause, n as encodePause, o as isPause, p as pauseForHuman } from './types-Cf75IbxY.js';
14
+ import { c as NodeCategory, d as NodeKindDefinition } from './types-JViq8reb.js';
15
+ export { A as AvailableVariable, a as ConfigField, D as DocumentConfigField, z as ExpressionForm, B as ExpressionGrammarHelp, K as KeyValueConfigField, L as LEGACY_PAUSE_PREFIXES, O as OutputField, F as OutputShape, h as PAUSE_PREFIX, P as PauseAwaiting, i as PauseSignal, j as PortSpec, R as RenderBodyContext, t as RepeaterConfigField, u as RepeaterRowField, G as availableVariables, H as baseVariables, m as decodePause, I as describeExpressionGrammar, n as encodePause, o as isPause, Q as outputFieldsFor, p as pauseForHuman } from './types-JViq8reb.js';
16
16
  export { F as FlowNodeStatus, a as FlowViewer, b as FlowViewerClassNames, c as FlowViewerProps } from './FlowViewer-C4QAVgWv.js';
17
17
  import { FlowRunFeedEntry } from './runtime/index.js';
18
18
  export { HistoryController, UseFlowHistoryReturn, UseFlowRunOptions, UseFlowRunReturn, UseFlowStateReturn, applyOutputsToNodes, applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState } from './runtime/index.js';
19
19
  export { C as CohortGuard, a as CohortOptions, b as CohortPolicy, c as CohortResult, R as RunOptions, d as RunResult, r as runCohort, e as runFlow } from './run-cohort-BnP6ErHi.js';
20
- export { N as NodeKindPresentation, c as categoryAccent, b as clearNodeKindOverrides, d as defaultConfigFor, g as getNodeKind, l as listNodeKinds, o as onNodeKindsChanged, e as overrideNodeKind, r as registerNodeKind, v as validateConfig } from './registry-CS7kjMto.js';
20
+ export { N as NodeKindPresentation, c as categoryAccent, b as clearNodeKindOverrides, d as defaultConfigFor, g as getNodeKind, l as listNodeKinds, o as onNodeKindsChanged, e as overrideNodeKind, r as registerNodeKind, v as validateConfig } from './registry-FGCBprcn.js';
21
21
  import './capabilities-CkhKj_U_.js';
22
22
 
23
23
  type FlowCanvasProps = Omit<ReactFlowProps<FlowNode, Edge>, "nodes" | "edges" | "height"> & {
@@ -98,6 +98,13 @@ type NodeConfigPanelProps = {
98
98
  */
99
99
  /** Host renderers keyed by field `type`. See {@link ConfigFieldRenderer}. */
100
100
  fieldRenderers?: Record<string, ConfigFieldRenderFn>;
101
+ /**
102
+ * The graph the node lives in. Supplying it is what makes the `{{ }}` variable
103
+ * picker context-aware — it reads the UPSTREAM node's declared `outputShape`
104
+ * to list what is actually reachable here (issue #5). Without it the picker
105
+ * still opens, but can only offer the whole input.
106
+ */
107
+ graph?: FlowGraph;
101
108
  renderDocumentField?: (props: {
102
109
  documentType?: string;
103
110
  value: unknown;
@@ -110,7 +117,7 @@ type NodeConfigPanelProps = {
110
117
  * NodeConfigPanel — schema-driven form for the selected node. Defers to
111
118
  * `kind.renderPanel` if the kind opts out of the auto-form.
112
119
  */
113
- declare function NodeConfigPanel({ node, onChange, onDelete, deleteLabel, header, renderCredentialField, renderDocumentField, fieldRenderers, className, style, }: NodeConfigPanelProps): react.JSX.Element;
120
+ declare function NodeConfigPanel({ node, onChange, onDelete, deleteLabel, header, renderCredentialField, renderDocumentField, fieldRenderers, graph, className, style, }: NodeConfigPanelProps): react.JSX.Element;
114
121
 
115
122
  /**
116
123
  * Clone a set of nodes AND the edges internal to that set, remapping every id.
@@ -620,4 +627,116 @@ declare const flowKeys: {
620
627
  readonly run: (runId: string) => readonly ["flow", "runs", string];
621
628
  };
622
629
 
623
- export { ActionNode, type AlignEdge, AutoLayoutOptions, ConfigFieldRenderFn, ConnectionValidatorOptions, DecisionNode, ExecutorRegistry, FlowCanvas, type FlowCanvasProps, FlowEditor, type FlowEditorAction, type FlowEditorApi, type FlowEditorBuiltins, type FlowEditorProps, type FlowEditorSlots, FlowGraph, FlowNode, type FlowNodeRenderProps, FlowRunControls, type FlowRunControlsProps, FlowRunFeed, FlowRunFeedEntry, type FlowRunFeedProps, LaneNode, NodeCategory, NodeConfigPanel, type NodeConfigPanelProps, NodeKindDefinition, NodePalette, type NodePaletteProps, NodePort, type NodePortProps, type NodePortSide, type NodePortType, NodeRunStatus, NodeShell, type NodeShellProps, NoteNode, OutputNode, SubgraphNode, TriggerNode, WorkflowMetadata, WorkflowSchema, alignNodes, cloneSubgraph, defaultNodeTypes, defineNode, distributeNodes, flowKeys, flowLive, paletteDropHandlers, reconnectEdge, useFlowEditor, useFlowEditorOptional };
630
+ type ExpressionFieldProps = {
631
+ value: string;
632
+ onChange: (next: string) => void;
633
+ placeholder?: string;
634
+ rows?: number;
635
+ /** The panel's field id + agent handle. */
636
+ handle: {
637
+ id?: string;
638
+ "data-ff-field": string;
639
+ };
640
+ /**
641
+ * The graph and the node being edited. Both are needed to answer "what can I
642
+ * write here" — without them the picker can still offer `{{ $json }}` but
643
+ * nothing node-specific, which is the static list issue #5 asked us not to
644
+ * ship.
645
+ */
646
+ graph?: FlowGraph;
647
+ nodeId?: string;
648
+ };
649
+ /**
650
+ * ExpressionField — a `{{ }}` field that tells the author what it accepts.
651
+ *
652
+ * Issue #5: the panel rendered a bare textarea with a placeholder and nothing
653
+ * else, so writing an expression required already knowing both the grammar and
654
+ * the exact shape of the upstream node's output. Two affordances close that:
655
+ * typing `{{ ` opens a picker of the variables actually reachable at THIS node,
656
+ * and a reference toggle explains the grammar.
657
+ *
658
+ * The picker deliberately lists only what the resolver can reach — see
659
+ * `availableVariables`. A suggestion that resolves to `null` at runtime is
660
+ * worse than no suggestion, because the author has no reason to doubt it.
661
+ */
662
+ declare function ExpressionField({ value, onChange, placeholder, rows, handle, graph, nodeId, }: ExpressionFieldProps): react.JSX.Element;
663
+
664
+ /**
665
+ * `{{ }}` resolution — the TypeScript twin of `FancyFlow\Nodes\Support\Expr`.
666
+ *
667
+ * ## Why this is opt-in and not wired into `runFlow`
668
+ *
669
+ * The PHP runtime resolves expressions inside its batteries-included executors.
670
+ * The JS runtime never has: `runFlow` hands `node.data.config` to your executor
671
+ * verbatim, so every host that uses `{{ }}` today already resolves it itself.
672
+ * Turning resolution on inside `runFlow` would interpolate a second time over
673
+ * values those hosts had already substituted — silently, and only for graphs
674
+ * that happen to contain `{{` in their DATA.
675
+ *
676
+ * So this exports the semantics and changes no behaviour. Call it yourself:
677
+ *
678
+ * ```ts
679
+ * const url = evaluateExpression(node.data.config.url, inputs);
680
+ * ```
681
+ *
682
+ * ## The semantics are the PHP file's, deliberately
683
+ *
684
+ * This is not a general expression language and must not grow into one. It
685
+ * resolves a dot-path against a context and nothing else — no arithmetic, no
686
+ * comparisons, no calls. Hosts that want real expressions override the executor
687
+ * (the PHP docblock points at symfony/expression-language for the same reason).
688
+ *
689
+ * Divergence here is a correctness bug rather than a style difference: the same
690
+ * graph is authored once and may run on either runtime. `suites/shared/expr`
691
+ * in `@particle-academy/fancy-conformance` is the fixture table both sides run,
692
+ * so parity is a test result instead of a claim.
693
+ */
694
+ /** Anything a context or a resolved value can be. */
695
+ type ExprValue = unknown;
696
+ /** The context an expression resolves against — the executor's `inputs`. */
697
+ type ExprContext = Record<string, ExprValue>;
698
+ /**
699
+ * Resolve a dot-path against the context, honouring the `$json` / `$input`
700
+ * alias.
701
+ *
702
+ * Both aliases point at the `in` port value when the context has one, and at
703
+ * the whole context otherwise — the same fallback the PHP does, which is what
704
+ * makes `{{ $json.x }}` work on a trigger node that has no upstream input.
705
+ *
706
+ * A path that does not resolve returns `null`, never `undefined`: PHP has one
707
+ * absent value and JS has two, and letting the difference leak would make the
708
+ * two runtimes disagree about `{{ missing }}` for no useful reason.
709
+ */
710
+ declare function resolvePath(path: string, context: ExprContext): ExprValue;
711
+ /**
712
+ * Evaluate a template against a context.
713
+ *
714
+ * A string that is EXACTLY one expression returns the resolved value with its
715
+ * type intact — `{{ $json.count }}` gives you a number, not `"3"`. Anything
716
+ * else interpolates each run as text. That distinction is load-bearing: it is
717
+ * what lets a config field carry either a value or a sentence.
718
+ *
719
+ * Non-string templates pass through untouched, so this is safe to map over a
720
+ * whole config object.
721
+ */
722
+ declare function evaluateExpression(template: ExprValue, context: ExprContext): ExprValue;
723
+ /**
724
+ * Truthiness for branch / switch decisions.
725
+ *
726
+ * Mirrors PHP's rules rather than JavaScript's, because the graph is authored
727
+ * once and may run on either side. The two disagree in exactly the places a
728
+ * workflow hits: `"0"` and `"false"` are truthy in JS and falsy here, and an
729
+ * empty array is truthy in JS and falsy here.
730
+ */
731
+ declare function truthy(value: ExprValue): boolean;
732
+ /** Coerce a value to text the way interpolation does. */
733
+ declare function text(value: ExprValue): string;
734
+ /**
735
+ * Resolve every string in a config object, one level of nesting at a time.
736
+ *
737
+ * The convenience most hosts actually want, and the shape their hand-rolled
738
+ * version usually takes. Opt-in like the rest of this module.
739
+ */
740
+ declare function evaluateConfig<T extends Record<string, ExprValue>>(config: T, context: ExprContext): T;
741
+
742
+ export { ActionNode, type AlignEdge, AutoLayoutOptions, ConfigFieldRenderFn, ConnectionValidatorOptions, DecisionNode, ExecutorRegistry, type ExprContext, type ExprValue, ExpressionField, type ExpressionFieldProps, FlowCanvas, type FlowCanvasProps, FlowEditor, type FlowEditorAction, type FlowEditorApi, type FlowEditorBuiltins, type FlowEditorProps, type FlowEditorSlots, FlowGraph, FlowNode, type FlowNodeRenderProps, FlowRunControls, type FlowRunControlsProps, FlowRunFeed, FlowRunFeedEntry, type FlowRunFeedProps, LaneNode, NodeCategory, NodeConfigPanel, type NodeConfigPanelProps, NodeKindDefinition, NodePalette, type NodePaletteProps, NodePort, type NodePortProps, type NodePortSide, type NodePortType, NodeRunStatus, NodeShell, type NodeShellProps, NoteNode, OutputNode, SubgraphNode, TriggerNode, WorkflowMetadata, WorkflowSchema, alignNodes, cloneSubgraph, defaultNodeTypes, defineNode, distributeNodes, evaluateConfig, evaluateExpression, flowKeys, flowLive, paletteDropHandlers, reconnectEdge, resolvePath, text, truthy, useFlowEditor, useFlowEditorOptional };