@particle-academy/fancy-flow 0.40.4 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/ConfigFieldRenderer-BHQDZer6.d.ts +92 -0
  2. package/dist/ConfigFieldRenderer-LotNHeG8.d.cts +92 -0
  3. package/dist/{chunk-UX65ML3J.js → chunk-55KQS3LK.js} +25 -2
  4. package/dist/chunk-55KQS3LK.js.map +1 -0
  5. package/dist/{chunk-WOO4B7M5.js → chunk-T3VQX3XB.js} +3 -3
  6. package/dist/{chunk-WOO4B7M5.js.map → chunk-T3VQX3XB.js.map} +1 -1
  7. package/dist/engine.d.cts +3 -3
  8. package/dist/engine.d.ts +3 -3
  9. package/dist/fields/react-fancy.cjs +40 -0
  10. package/dist/fields/react-fancy.cjs.map +1 -0
  11. package/dist/fields/react-fancy.d.cts +20 -0
  12. package/dist/fields/react-fancy.d.ts +20 -0
  13. package/dist/fields/react-fancy.js +37 -0
  14. package/dist/fields/react-fancy.js.map +1 -0
  15. package/dist/index.cjs +343 -33
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.d.cts +105 -127
  18. package/dist/index.d.ts +105 -127
  19. package/dist/index.js +320 -38
  20. package/dist/index.js.map +1 -1
  21. package/dist/registry/index.d.cts +3 -3
  22. package/dist/registry/index.d.ts +3 -3
  23. package/dist/{registry-BADFn97n.d.cts → registry-C9KMVpn7.d.cts} +1 -1
  24. package/dist/{registry-DYbFLEcW.d.ts → registry-FGCBprcn.d.ts} +1 -1
  25. package/dist/registry.cjs +23 -0
  26. package/dist/registry.cjs.map +1 -1
  27. package/dist/registry.js +1 -1
  28. package/dist/screens.js +3 -3
  29. package/dist/styles.css +99 -0
  30. package/dist/styles.css.map +1 -1
  31. package/dist/{types-D8Dezh9v.d.cts → types-B78Rm69S.d.cts} +94 -2
  32. package/dist/{types-D6lsIGoe.d.ts → types-JViq8reb.d.ts} +94 -2
  33. package/dist/ux.d.cts +1 -1
  34. package/dist/ux.d.ts +1 -1
  35. package/package.json +12 -2
  36. package/dist/chunk-UX65ML3J.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
- import { removeNodes, removeEdges, cloneSubgraph, alignNodes, distributeNodes, reconnectEdge, assignToLane, removeFromLane, duplicateNode, setEdgeLabel, FlowCanvas } from './chunk-WOO4B7M5.js';
2
- export { ActionNode, DecisionNode, FlowCanvas, FlowViewer, NodeShell, OutputNode, SubgraphNode, TriggerNode, alignNodes, cloneSubgraph, defaultNodeTypes, distributeNodes, reconnectEdge } from './chunk-WOO4B7M5.js';
1
+ import { removeNodes, removeEdges, cloneSubgraph, alignNodes, distributeNodes, reconnectEdge, assignToLane, removeFromLane, duplicateNode, setEdgeLabel, FlowCanvas } from './chunk-T3VQX3XB.js';
2
+ export { ActionNode, DecisionNode, FlowCanvas, FlowViewer, NodeShell, OutputNode, SubgraphNode, TriggerNode, alignNodes, cloneSubgraph, defaultNodeTypes, distributeNodes, reconnectEdge } from './chunk-T3VQX3XB.js';
3
3
  import { useFlowState, useFlowRun, useFlowHistory, applyOutputsToNodes, applyStatusesToNodes } from './chunk-A6RFLGWV.js';
4
4
  export { applyOutputsToNodes, applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState } from './chunk-A6RFLGWV.js';
5
5
  export { runCohort } from './chunk-QZTGV3ZL.js';
6
- import { buildNodeTypes, FlowEditorProvider, registerBuiltinKinds } from './chunk-UX65ML3J.js';
7
- export { ANY_PORT_TYPE, BUILTIN_KINDS, LaneNode, NoteNode, RegistryNode, buildNodeTypes, createConnectionValidator, defaultPortCompatibility, registerBuiltinKinds, useFlowEditor, useFlowEditorOptional } from './chunk-UX65ML3J.js';
6
+ import { buildNodeTypes, FlowEditorProvider, registerBuiltinKinds } from './chunk-55KQS3LK.js';
7
+ export { ANY_PORT_TYPE, BUILTIN_KINDS, LaneNode, NoteNode, RegistryNode, buildNodeTypes, createConnectionValidator, defaultPortCompatibility, registerBuiltinKinds, useFlowEditor, useFlowEditorOptional } from './chunk-55KQS3LK.js';
8
8
  import { ReactFlowProvider, useReactFlow, addEdge, applyEdgeChanges, applyNodeChanges, Position, Handle } from './chunk-OWENS2H5.js';
9
9
  export { LEGACY_PAUSE_PREFIXES, PAUSE_PREFIX, decodePause, encodePause, isPause, pauseForHuman } from './chunk-UEOE6B52.js';
10
10
  import './chunk-USL4FMFU.js';
@@ -109,6 +109,230 @@ function paletteDropHandlers(onDrop) {
109
109
  }
110
110
  };
111
111
  }
112
+
113
+ // src/expressions/variables.ts
114
+ var ROOT = "$json";
115
+ function expr(path) {
116
+ return `{{ ${path} }}`;
117
+ }
118
+ function outputFieldsFor(node) {
119
+ const kindName = node.data?.kind ?? node.type;
120
+ if (!kindName) return [];
121
+ const kind = getNodeKind(kindName);
122
+ const shape = kind?.outputShape;
123
+ if (!shape) return [];
124
+ if (typeof shape === "function") {
125
+ try {
126
+ const config = node.data?.config ?? {};
127
+ return shape(config) ?? [];
128
+ } catch {
129
+ return [];
130
+ }
131
+ }
132
+ return shape;
133
+ }
134
+ function baseVariables() {
135
+ return [
136
+ { expression: expr(ROOT), path: ROOT, type: "unknown", description: "The whole incoming value." }
137
+ ];
138
+ }
139
+ function availableVariables(graph, nodeId) {
140
+ const out = baseVariables();
141
+ const seen = /* @__PURE__ */ new Set([ROOT]);
142
+ const byId = new Map(graph.nodes.map((n) => [n.id, n]));
143
+ const upstreamIds = graph.edges.filter((e) => e.target === nodeId).map((e) => e.source);
144
+ for (const id of upstreamIds) {
145
+ if (id === nodeId) continue;
146
+ const upstream = byId.get(id);
147
+ if (!upstream) continue;
148
+ const kindName = upstream.data?.kind ?? upstream.type;
149
+ const label = upstream.data?.label ?? (kindName ? getNodeKind(kindName)?.label : void 0);
150
+ for (const field of outputFieldsFor(upstream)) {
151
+ const path = `${ROOT}.${field.path}`;
152
+ if (seen.has(path)) continue;
153
+ seen.add(path);
154
+ out.push({
155
+ expression: expr(path),
156
+ path,
157
+ type: field.type,
158
+ description: field.description,
159
+ source: label
160
+ });
161
+ }
162
+ }
163
+ return out;
164
+ }
165
+ function describeExpressionGrammar() {
166
+ return {
167
+ forms: [
168
+ { syntax: "{{ $json }}", meaning: "The whole value arriving on this node's input." },
169
+ { syntax: "{{ $json.field }}", meaning: "One key of that value. Dot-paths nest: $json.user.email." },
170
+ { syntax: "{{ $input.field }}", meaning: "An alias for $json \u2014 the same value, either spelling." },
171
+ { syntax: "{{ in }}", meaning: "The input by its context key, rather than through the alias." }
172
+ ],
173
+ note: "Dot-paths only \u2014 no arithmetic, comparisons or function calls; anything else resolves to nothing. A field that is exactly one expression keeps the resolved value's type; mixed text interpolates as a string. fancy-flow's own runFlow does not interpolate: it hands config to your executor verbatim, and the fancy-flow-php runtime is what resolves these."
174
+ };
175
+ }
176
+ function findTrigger(text, caret) {
177
+ const before = text.slice(0, caret);
178
+ const open = before.lastIndexOf("{{");
179
+ if (open === -1) return null;
180
+ if (before.indexOf("}}", open) !== -1) return null;
181
+ return { open, query: before.slice(open + 2).trim() };
182
+ }
183
+ function filterVariables(vars, query) {
184
+ const q = query.trim().toLowerCase();
185
+ if (q === "") return vars;
186
+ return vars.filter((v) => v.path.toLowerCase().includes(q));
187
+ }
188
+ function applyCompletion(text, caret, trigger, variable) {
189
+ const head = text.slice(0, trigger.open);
190
+ const tail = text.slice(caret);
191
+ return { value: `${head}${variable.expression}${tail}`, caret: head.length + variable.expression.length };
192
+ }
193
+ function ExpressionField({
194
+ value,
195
+ onChange,
196
+ placeholder,
197
+ rows = 2,
198
+ handle,
199
+ graph,
200
+ nodeId
201
+ }) {
202
+ const ref = useRef(null);
203
+ const [trigger, setTrigger] = useState(null);
204
+ const [active, setActive] = useState(0);
205
+ const [showHelp, setShowHelp] = useState(false);
206
+ const variables = useMemo(
207
+ () => graph && nodeId ? availableVariables(graph, nodeId) : baseVariables(),
208
+ [graph, nodeId]
209
+ );
210
+ const matches = useMemo(
211
+ () => trigger ? filterVariables(variables, trigger.query) : [],
212
+ [trigger, variables]
213
+ );
214
+ const help = useMemo(() => describeExpressionGrammar(), []);
215
+ const open = trigger !== null && matches.length > 0;
216
+ const sync = (el) => {
217
+ const next = findTrigger(el.value, el.selectionStart ?? el.value.length);
218
+ setTrigger(next);
219
+ setActive(0);
220
+ };
221
+ const choose = (variable) => {
222
+ const el = ref.current;
223
+ if (!el || !trigger) return;
224
+ const { value: next, caret } = applyCompletion(
225
+ el.value,
226
+ el.selectionStart ?? el.value.length,
227
+ trigger,
228
+ variable
229
+ );
230
+ onChange(next);
231
+ setTrigger(null);
232
+ requestAnimationFrame(() => {
233
+ el.focus();
234
+ el.setSelectionRange(caret, caret);
235
+ });
236
+ };
237
+ const onKeyDown = (e) => {
238
+ if (!open) return;
239
+ if (e.key === "ArrowDown") {
240
+ e.preventDefault();
241
+ setActive((i) => (i + 1) % matches.length);
242
+ } else if (e.key === "ArrowUp") {
243
+ e.preventDefault();
244
+ setActive((i) => (i - 1 + matches.length) % matches.length);
245
+ } else if (e.key === "Enter" || e.key === "Tab") {
246
+ e.preventDefault();
247
+ choose(matches[active] ?? matches[0]);
248
+ } else if (e.key === "Escape") {
249
+ e.preventDefault();
250
+ setTrigger(null);
251
+ }
252
+ };
253
+ return /* @__PURE__ */ jsxs("div", { className: "ff-expression", "data-ff-expression": handle["data-ff-field"], children: [
254
+ /* @__PURE__ */ jsx(
255
+ "textarea",
256
+ {
257
+ ...handle,
258
+ ref,
259
+ className: "ff-panel__input ff-panel__input--expression",
260
+ rows,
261
+ value: value ?? "",
262
+ placeholder: placeholder ?? "{{ $json.field }}",
263
+ spellCheck: false,
264
+ role: "combobox",
265
+ "aria-expanded": open,
266
+ "aria-autocomplete": "list",
267
+ "aria-controls": open ? `${handle.id ?? handle["data-ff-field"]}-vars` : void 0,
268
+ onChange: (e) => {
269
+ onChange(e.target.value);
270
+ sync(e.target);
271
+ },
272
+ onKeyDown,
273
+ onClick: (e) => sync(e.currentTarget),
274
+ onBlur: () => {
275
+ window.setTimeout(() => setTrigger(null), 120);
276
+ }
277
+ }
278
+ ),
279
+ /* @__PURE__ */ jsxs("div", { className: "ff-expression__bar", children: [
280
+ /* @__PURE__ */ jsxs(
281
+ "button",
282
+ {
283
+ type: "button",
284
+ className: "ff-expression__helpbtn",
285
+ "aria-expanded": showHelp,
286
+ onClick: () => setShowHelp((s) => !s),
287
+ children: [
288
+ "{{ }}",
289
+ " reference"
290
+ ]
291
+ }
292
+ ),
293
+ variables.length > 1 && /* @__PURE__ */ jsxs("span", { className: "ff-expression__hint", children: [
294
+ "type ",
295
+ /* @__PURE__ */ jsx("code", { children: "{{" }),
296
+ " for ",
297
+ variables.length,
298
+ " variables"
299
+ ] })
300
+ ] }),
301
+ open && /* @__PURE__ */ jsx(
302
+ "ul",
303
+ {
304
+ className: "ff-expression__menu",
305
+ id: `${handle.id ?? handle["data-ff-field"]}-vars`,
306
+ role: "listbox",
307
+ "data-ff-expression-menu": handle["data-ff-field"],
308
+ children: matches.map((v, i) => /* @__PURE__ */ jsx("li", { role: "option", "aria-selected": i === active, children: /* @__PURE__ */ jsxs(
309
+ "button",
310
+ {
311
+ type: "button",
312
+ className: `ff-expression__option${i === active ? " is-active" : ""}`,
313
+ "data-ff-expression-option": v.path,
314
+ onMouseDown: (e) => {
315
+ e.preventDefault();
316
+ choose(v);
317
+ },
318
+ children: [
319
+ /* @__PURE__ */ jsx("code", { className: "ff-expression__path", children: v.path }),
320
+ v.source && /* @__PURE__ */ jsx("span", { className: "ff-expression__source", children: v.source }),
321
+ v.description && /* @__PURE__ */ jsx("span", { className: "ff-expression__desc", children: v.description })
322
+ ]
323
+ }
324
+ ) }, v.expression))
325
+ }
326
+ ),
327
+ showHelp && /* @__PURE__ */ jsxs("div", { className: "ff-expression__help", role: "note", "data-ff-expression-help": true, children: [
328
+ /* @__PURE__ */ jsx("dl", { children: help.forms.map((f) => /* @__PURE__ */ jsxs("div", { children: [
329
+ /* @__PURE__ */ jsx("dt", { children: /* @__PURE__ */ jsx("code", { children: f.syntax }) }),
330
+ /* @__PURE__ */ jsx("dd", { children: f.meaning })
331
+ ] }, f.syntax)) }),
332
+ /* @__PURE__ */ jsx("p", { className: "ff-expression__note", children: help.note })
333
+ ] })
334
+ ] });
335
+ }
112
336
  function ConfigFieldRenderer({
113
337
  field,
114
338
  value,
@@ -116,7 +340,9 @@ function ConfigFieldRenderer({
116
340
  id,
117
341
  renderCredentialField,
118
342
  renderDocumentField,
119
- fieldRenderers
343
+ fieldRenderers,
344
+ graph,
345
+ nodeId
120
346
  }) {
121
347
  const handle = { id, "data-ff-field": field.key };
122
348
  const custom = fieldRenderers?.[field.type];
@@ -195,18 +421,17 @@ function ConfigFieldRenderer({
195
421
  }
196
422
  );
197
423
  case "json":
198
- return /* @__PURE__ */ jsx(JsonField, { value, onChange, rows: field.rows });
424
+ return /* @__PURE__ */ jsx(JsonField, { value, onChange, rows: field.rows, handle });
199
425
  case "expression":
200
426
  return /* @__PURE__ */ jsx(
201
- "textarea",
427
+ ExpressionField,
202
428
  {
203
- ...handle,
204
- className: "ff-panel__input ff-panel__input--expression",
205
- rows: 2,
429
+ handle,
206
430
  value: value ?? "",
431
+ onChange,
207
432
  placeholder: field.example ?? "{{ $json.field }}",
208
- spellCheck: false,
209
- onChange: (e) => onChange(e.target.value)
433
+ graph,
434
+ nodeId
210
435
  }
211
436
  );
212
437
  case "credential":
@@ -227,16 +452,19 @@ function ConfigFieldRenderer({
227
452
  return /* @__PURE__ */ jsx(
228
453
  RepeaterField,
229
454
  {
455
+ id,
230
456
  field,
231
457
  value,
232
458
  onChange,
233
459
  renderCredentialField,
234
460
  renderDocumentField,
235
- fieldRenderers
461
+ fieldRenderers,
462
+ graph,
463
+ nodeId
236
464
  }
237
465
  );
238
466
  case "keyvalue":
239
- return /* @__PURE__ */ jsx(KeyValueField, { field, value, onChange });
467
+ return /* @__PURE__ */ jsx(KeyValueField, { id, field, value, onChange });
240
468
  case "document":
241
469
  if (renderDocumentField) {
242
470
  return /* @__PURE__ */ jsx(Fragment, { children: renderDocumentField({ documentType: field.documentType, value, onChange }) });
@@ -281,9 +509,12 @@ function ChoiceField({
281
509
  );
282
510
  }
283
511
  function RepeaterField({
512
+ id,
284
513
  field,
285
514
  value,
286
515
  onChange,
516
+ graph,
517
+ nodeId,
287
518
  renderCredentialField,
288
519
  renderDocumentField,
289
520
  fieldRenderers
@@ -315,7 +546,7 @@ function RepeaterField({
315
546
  if (typeof raw === "number" || typeof raw === "boolean") return String(raw);
316
547
  return `Item ${i + 1}`;
317
548
  };
318
- return /* @__PURE__ */ jsxs("div", { className: "ff-repeater", "data-ff-repeater": field.key, children: [
549
+ return /* @__PURE__ */ jsxs("div", { id, role: "group", className: "ff-repeater", "data-ff-repeater": field.key, "data-ff-field": field.key, children: [
319
550
  rows.length === 0 && /* @__PURE__ */ jsx("p", { className: "ff-repeater__empty", children: "None yet." }),
320
551
  rows.map((row, i) => /* @__PURE__ */ jsxs("div", { className: "ff-repeater__row", "data-ff-repeater-row": i, children: [
321
552
  /* @__PURE__ */ jsxs("div", { className: "ff-repeater__row-head", children: [
@@ -364,6 +595,8 @@ function RepeaterField({
364
595
  /* @__PURE__ */ jsx(
365
596
  ConfigFieldRenderer,
366
597
  {
598
+ graph,
599
+ nodeId,
367
600
  field: sub,
368
601
  value: row[sub.key],
369
602
  onChange: (cell) => setCell(i, sub.key, cell),
@@ -390,6 +623,7 @@ function RepeaterField({
390
623
  ] });
391
624
  }
392
625
  function KeyValueField({
626
+ id,
393
627
  field,
394
628
  value,
395
629
  onChange
@@ -408,7 +642,7 @@ function KeyValueField({
408
642
  const setVal = (i, val) => commit(entries.map(([k, v], idx) => idx === i ? [k, val] : [k, v]));
409
643
  const remove = (i) => commit(entries.filter((_, idx) => idx !== i));
410
644
  const add = () => commit([...entries, ["", ""]]);
411
- return /* @__PURE__ */ jsxs("div", { className: "ff-keyvalue", "data-ff-keyvalue": field.key, children: [
645
+ return /* @__PURE__ */ jsxs("div", { id, role: "group", className: "ff-keyvalue", "data-ff-keyvalue": field.key, "data-ff-field": field.key, children: [
412
646
  entries.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ff-keyvalue__head", children: [
413
647
  /* @__PURE__ */ jsx("span", { children: field.keyLabel ?? "Key" }),
414
648
  /* @__PURE__ */ jsx("span", { children: field.valueLabel ?? "Value" }),
@@ -464,34 +698,76 @@ function KeyValueField({
464
698
  ] })
465
699
  ] });
466
700
  }
467
- function JsonField({ value, onChange, rows }) {
468
- const initial = useMemo(() => {
701
+ function JsonField({
702
+ value,
703
+ onChange,
704
+ rows,
705
+ handle
706
+ }) {
707
+ const serialized = useMemo(() => {
469
708
  try {
470
709
  return value === void 0 ? "" : JSON.stringify(value, null, 2);
471
710
  } catch {
472
711
  return "";
473
712
  }
474
713
  }, [value]);
475
- return /* @__PURE__ */ jsx(
476
- "textarea",
477
- {
478
- className: "ff-panel__input ff-panel__input--json",
479
- rows: rows ?? 6,
480
- defaultValue: initial,
481
- spellCheck: false,
482
- onBlur: (e) => {
483
- const text = e.target.value.trim();
484
- if (text === "") {
485
- onChange(void 0);
486
- return;
487
- }
488
- try {
489
- onChange(JSON.parse(text));
490
- } catch {
714
+ const [text, setText] = useState(serialized);
715
+ const [error, setError] = useState(null);
716
+ const [touched, setTouched] = useState(false);
717
+ const lastProps = useRef(serialized);
718
+ const committed = useRef(null);
719
+ if (serialized !== lastProps.current) {
720
+ lastProps.current = serialized;
721
+ if (serialized !== committed.current) {
722
+ setText(serialized);
723
+ setError(null);
724
+ setTouched(false);
725
+ }
726
+ }
727
+ const commit = (next) => {
728
+ const trimmed = next.trim();
729
+ if (trimmed === "") {
730
+ committed.current = "";
731
+ onChange(void 0);
732
+ return null;
733
+ }
734
+ try {
735
+ const parsed = JSON.parse(trimmed);
736
+ committed.current = JSON.stringify(parsed, null, 2);
737
+ onChange(parsed);
738
+ return null;
739
+ } catch (e) {
740
+ return e instanceof Error ? e.message : "Invalid JSON";
741
+ }
742
+ };
743
+ const errorId = handle.id ? `${handle.id}-error` : void 0;
744
+ const showError = touched && error !== null;
745
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
746
+ /* @__PURE__ */ jsx(
747
+ "textarea",
748
+ {
749
+ ...handle,
750
+ className: "ff-panel__input ff-panel__input--json",
751
+ rows: rows ?? 6,
752
+ value: text,
753
+ spellCheck: false,
754
+ "aria-invalid": showError || void 0,
755
+ "aria-describedby": showError ? errorId : void 0,
756
+ onChange: (e) => {
757
+ setText(e.target.value);
758
+ setError(commit(e.target.value));
759
+ },
760
+ onBlur: (e) => {
761
+ setTouched(true);
762
+ setError(commit(e.target.value));
491
763
  }
492
764
  }
493
- }
494
- );
765
+ ),
766
+ showError && /* @__PURE__ */ jsxs("p", { className: "ff-panel__issue ff-panel__issue--field", id: errorId, role: "alert", children: [
767
+ "\u26A0 ",
768
+ error
769
+ ] })
770
+ ] });
495
771
  }
496
772
  function NodeConfigPanel({
497
773
  node,
@@ -502,6 +778,7 @@ function NodeConfigPanel({
502
778
  renderCredentialField,
503
779
  renderDocumentField,
504
780
  fieldRenderers,
781
+ graph,
505
782
  className,
506
783
  style
507
784
  }) {
@@ -607,7 +884,9 @@ function NodeConfigPanel({
607
884
  onChange: (v) => setConfigValue(field.key, v),
608
885
  renderCredentialField,
609
886
  renderDocumentField: documentField,
610
- fieldRenderers
887
+ fieldRenderers,
888
+ graph,
889
+ nodeId: node.id
611
890
  }
612
891
  )
613
892
  ] }, field.key))
@@ -810,6 +1089,7 @@ function FlowEditorInner({
810
1089
  metadata,
811
1090
  showPalette = true,
812
1091
  showPanel = true,
1092
+ fieldRenderers,
813
1093
  showFeed = true,
814
1094
  extraToolbar,
815
1095
  actions = [],
@@ -1369,6 +1649,8 @@ function FlowEditorInner({
1369
1649
  className: "ff-editor__panel",
1370
1650
  node: api.selected,
1371
1651
  onChange: api.updateNode,
1652
+ fieldRenderers,
1653
+ graph: flow,
1372
1654
  onDelete: builtins.delete === false ? void 0 : (n) => api.deleteNodes([n.id])
1373
1655
  }
1374
1656
  ),
@@ -1544,6 +1826,6 @@ var flowKeys = {
1544
1826
  // src/index.ts
1545
1827
  registerBuiltinKinds();
1546
1828
 
1547
- export { ConfigFieldRenderer, FlowEditor, FlowRunControls, FlowRunFeed, NodeConfigPanel, NodePalette, NodePort, defineNode, flowKeys, flowLive, paletteDropHandlers };
1829
+ export { ConfigFieldRenderer, ExpressionField, FlowEditor, FlowRunControls, FlowRunFeed, NodeConfigPanel, NodePalette, NodePort, availableVariables, baseVariables, defineNode, describeExpressionGrammar, flowKeys, flowLive, outputFieldsFor, paletteDropHandlers };
1548
1830
  //# sourceMappingURL=index.js.map
1549
1831
  //# sourceMappingURL=index.js.map