@flowdrop/flowdrop 1.4.0 → 1.5.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 (100) hide show
  1. package/README.md +68 -24
  2. package/dist/adapters/WorkflowAdapter.js +2 -22
  3. package/dist/adapters/agentspec/autoLayout.d.ts +51 -5
  4. package/dist/adapters/agentspec/autoLayout.js +120 -23
  5. package/dist/chat/commandClassifier.d.ts +19 -0
  6. package/dist/chat/commandClassifier.js +30 -0
  7. package/dist/chat/index.d.ts +27 -0
  8. package/dist/chat/index.js +32 -0
  9. package/dist/chat/responseParser.d.ts +21 -0
  10. package/dist/chat/responseParser.js +87 -0
  11. package/dist/commands/batch.d.ts +18 -0
  12. package/dist/commands/batch.js +56 -0
  13. package/dist/commands/executor.d.ts +37 -0
  14. package/dist/commands/executor.js +1044 -0
  15. package/dist/commands/index.d.ts +14 -0
  16. package/dist/commands/index.js +17 -0
  17. package/dist/commands/parser.d.ts +16 -0
  18. package/dist/commands/parser.js +278 -0
  19. package/dist/commands/positioner.d.ts +19 -0
  20. package/dist/commands/positioner.js +33 -0
  21. package/dist/commands/storeIntegration.svelte.d.ts +16 -0
  22. package/dist/commands/storeIntegration.svelte.js +67 -0
  23. package/dist/commands/types.d.ts +343 -0
  24. package/dist/commands/types.js +45 -0
  25. package/dist/components/App.svelte +351 -12
  26. package/dist/components/App.svelte.d.ts +3 -0
  27. package/dist/components/CanvasController.svelte +38 -0
  28. package/dist/components/CanvasController.svelte.d.ts +32 -0
  29. package/dist/components/ConfigMappingRow.svelte +130 -0
  30. package/dist/components/ConfigMappingRow.svelte.d.ts +8 -0
  31. package/dist/components/ConfigPanel.svelte +56 -7
  32. package/dist/components/ConfigPanel.svelte.d.ts +2 -0
  33. package/dist/components/FlowDropEdge.svelte +2 -10
  34. package/dist/components/LogsSidebar.svelte +5 -5
  35. package/dist/components/NodeSidebar.svelte +15 -49
  36. package/dist/components/NodeSwapPicker.svelte +537 -0
  37. package/dist/components/NodeSwapPicker.svelte.d.ts +16 -0
  38. package/dist/components/PortMappingRow.svelte +209 -0
  39. package/dist/components/PortMappingRow.svelte.d.ts +12 -0
  40. package/dist/components/SwapMappingEditor.svelte +550 -0
  41. package/dist/components/SwapMappingEditor.svelte.d.ts +12 -0
  42. package/dist/components/WorkflowEditor.svelte +99 -4
  43. package/dist/components/WorkflowEditor.svelte.d.ts +8 -0
  44. package/dist/components/chat/AIChatPanel.svelte +658 -0
  45. package/dist/components/chat/AIChatPanel.svelte.d.ts +13 -0
  46. package/dist/components/chat/CommandPreview.svelte +184 -0
  47. package/dist/components/chat/CommandPreview.svelte.d.ts +9 -0
  48. package/dist/components/console/CommandConsole.stories.svelte +93 -0
  49. package/dist/components/console/CommandConsole.stories.svelte.d.ts +27 -0
  50. package/dist/components/console/CommandConsole.svelte +259 -0
  51. package/dist/components/console/CommandConsole.svelte.d.ts +11 -0
  52. package/dist/components/console/ConsoleAutocomplete.svelte +139 -0
  53. package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +21 -0
  54. package/dist/components/console/ConsoleInput.svelte +712 -0
  55. package/dist/components/console/ConsoleInput.svelte.d.ts +16 -0
  56. package/dist/components/console/ConsoleOutput.svelte +121 -0
  57. package/dist/components/console/ConsoleOutput.svelte.d.ts +11 -0
  58. package/dist/components/console/formatters.d.ts +26 -0
  59. package/dist/components/console/formatters.js +118 -0
  60. package/dist/components/interrupt/index.d.ts +1 -0
  61. package/dist/components/interrupt/index.js +1 -0
  62. package/dist/config/endpoints.d.ts +8 -0
  63. package/dist/config/endpoints.js +5 -0
  64. package/dist/core/index.d.ts +5 -0
  65. package/dist/core/index.js +9 -0
  66. package/dist/editor/index.d.ts +3 -1
  67. package/dist/editor/index.js +4 -2
  68. package/dist/helpers/proximityConnect.js +8 -1
  69. package/dist/helpers/workflowEditorHelper.d.ts +3 -53
  70. package/dist/helpers/workflowEditorHelper.js +13 -228
  71. package/dist/playground/index.d.ts +1 -1
  72. package/dist/playground/index.js +1 -1
  73. package/dist/schemas/v1/workflow.schema.json +107 -22
  74. package/dist/services/chatService.d.ts +65 -0
  75. package/dist/services/chatService.js +131 -0
  76. package/dist/services/historyService.d.ts +6 -4
  77. package/dist/services/historyService.js +21 -6
  78. package/dist/stores/interruptStore.svelte.js +6 -1
  79. package/dist/stores/playgroundStore.svelte.d.ts +1 -1
  80. package/dist/stores/playgroundStore.svelte.js +11 -2
  81. package/dist/stores/portCoordinateStore.svelte.d.ts +4 -0
  82. package/dist/stores/portCoordinateStore.svelte.js +20 -26
  83. package/dist/stores/workflowStore.svelte.d.ts +31 -2
  84. package/dist/stores/workflowStore.svelte.js +84 -64
  85. package/dist/types/chat.d.ts +63 -0
  86. package/dist/types/chat.js +9 -0
  87. package/dist/types/events.d.ts +28 -2
  88. package/dist/types/events.js +1 -0
  89. package/dist/types/index.d.ts +8 -0
  90. package/dist/types/settings.d.ts +6 -0
  91. package/dist/types/settings.js +3 -0
  92. package/dist/utils/edgeStyling.d.ts +42 -0
  93. package/dist/utils/edgeStyling.js +176 -0
  94. package/dist/utils/nodeIds.d.ts +31 -0
  95. package/dist/utils/nodeIds.js +42 -0
  96. package/dist/utils/nodeSwap.d.ts +221 -0
  97. package/dist/utils/nodeSwap.js +686 -0
  98. package/package.json +6 -1
  99. package/dist/helpers/nodeLayoutHelper.d.ts +0 -14
  100. package/dist/helpers/nodeLayoutHelper.js +0 -19
@@ -0,0 +1,14 @@
1
+ /**
2
+ * FlowDrop Command DSL
3
+ *
4
+ * A deterministic command language for programmatic workflow manipulation.
5
+ * Excludes storeIntegration.svelte.ts (Svelte-coupled, import separately).
6
+ *
7
+ * @module commands
8
+ */
9
+ export type { AddNodeCommand, DeleteNodeCommand, RenameNodeCommand, SetConfigCommand, GetConfigCommand, ConnectCommand, DisconnectPortsCommand, DisconnectNodeCommand, ListNodesCommand, ListEdgesCommand, ListTypesCommand, InfoCommand, UndoCommand, RedoCommand, ConfigOpenCommand, SelectNodeCommand, HelpCommand, ClearCommand, SwapNodeCommand, MoveNodeCommand, AutoLayoutCommand, BeautifyLayoutCommand, CanvasFitViewCommand, CanvasZoomInCommand, CanvasZoomOutCommand, CanvasZoomToCommand, CanvasPanToCommand, CanvasResetViewCommand, Command, ParseResult, CommandErrorCode, AddNodeResultData, ListNodesResultData, ListEdgesResultData, ListTypesResultData, InfoResultData, GetConfigResultData, SetConfigResultData, HelpResultData, SwapNodeResultData, CommandResultData, CommandResultOk, CommandResultError, CommandResult, BatchResult, UIAction, CommandDispatch, CommandContext, } from "./types.js";
10
+ export { buildTypeMap } from "./types.js";
11
+ export { parseCommand } from "./parser.js";
12
+ export { executeCommand, toShortId, toShortTypeId, resolveNode, COMMAND_HELP, } from "./executor.js";
13
+ export { executeBatch } from "./batch.js";
14
+ export { computeAutoPosition } from "./positioner.js";
@@ -0,0 +1,17 @@
1
+ /**
2
+ * FlowDrop Command DSL
3
+ *
4
+ * A deterministic command language for programmatic workflow manipulation.
5
+ * Excludes storeIntegration.svelte.ts (Svelte-coupled, import separately).
6
+ *
7
+ * @module commands
8
+ */
9
+ export { buildTypeMap } from "./types.js";
10
+ // Parser
11
+ export { parseCommand } from "./parser.js";
12
+ // Executor
13
+ export { executeCommand, toShortId, toShortTypeId, resolveNode, COMMAND_HELP, } from "./executor.js";
14
+ // Batch executor
15
+ export { executeBatch } from "./batch.js";
16
+ // Positioner
17
+ export { computeAutoPosition } from "./positioner.js";
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Command Parser
3
+ *
4
+ * Parses DSL command strings into typed Command objects using
5
+ * regex-based pattern matching with ordered rules (first match wins).
6
+ *
7
+ * @module commands/parser
8
+ */
9
+ import type { ParseResult } from "./types.js";
10
+ /**
11
+ * Parse a command string into a typed Command object.
12
+ *
13
+ * Command verbs are case-insensitive; identifiers are case-sensitive.
14
+ * Returns ParseResult with ok: true on success, ok: false on failure.
15
+ */
16
+ export declare function parseCommand(input: string): ParseResult;
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Command Parser
3
+ *
4
+ * Parses DSL command strings into typed Command objects using
5
+ * regex-based pattern matching with ordered rules (first match wins).
6
+ *
7
+ * @module commands/parser
8
+ */
9
+ /**
10
+ * Parse a coordinate pair like "200,300" or "-50, 100"
11
+ */
12
+ function parseCoords(x, y) {
13
+ return { x: Number(x), y: Number(y) };
14
+ }
15
+ const rules = [
16
+ // add <type> at <x>,<y>
17
+ {
18
+ pattern: /^add\s+(\S+)\s+at\s+(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)$/i,
19
+ parse: (m) => ({
20
+ type: "add_node",
21
+ nodeTypeId: m[1],
22
+ position: parseCoords(m[2], m[3]),
23
+ }),
24
+ },
25
+ // add <type>
26
+ {
27
+ pattern: /^add\s+(\S+)$/i,
28
+ parse: (m) => ({
29
+ type: "add_node",
30
+ nodeTypeId: m[1],
31
+ }),
32
+ },
33
+ // delete <nodeId>
34
+ {
35
+ pattern: /^delete\s+(\S+)$/i,
36
+ parse: (m) => ({
37
+ type: "delete_node",
38
+ nodeId: m[1],
39
+ }),
40
+ },
41
+ // rename <nodeId> <label...>
42
+ {
43
+ pattern: /^rename\s+(\S+)\s+(.+)$/i,
44
+ parse: (m) => ({
45
+ type: "rename_node",
46
+ nodeId: m[1],
47
+ label: m[2].trim(),
48
+ }),
49
+ },
50
+ // set <nodeId>:<key> """<multiline value>"""
51
+ {
52
+ pattern: /^set\s+(\S+?):(\S+)\s+"""([\s\S]*)"""$/,
53
+ parse: (m) => ({
54
+ type: "set_config",
55
+ nodeId: m[1],
56
+ key: m[2],
57
+ // trim one leading/trailing newline added by the textarea wrapper
58
+ value: m[3].replace(/^\n/, "").replace(/\n$/, ""),
59
+ }),
60
+ },
61
+ // set <nodeId>:<key> <value...>
62
+ {
63
+ pattern: /^set\s+(\S+?):(\S+)\s+(.+)$/i,
64
+ parse: (m) => ({
65
+ type: "set_config",
66
+ nodeId: m[1],
67
+ key: m[2],
68
+ value: m[3],
69
+ }),
70
+ },
71
+ // get <nodeId>:<key>
72
+ {
73
+ pattern: /^get\s+(\S+?):(\S+)$/i,
74
+ parse: (m) => ({
75
+ type: "get_config",
76
+ nodeId: m[1],
77
+ key: m[2],
78
+ }),
79
+ },
80
+ // info <nodeId>
81
+ {
82
+ pattern: /^info\s+(\S+)$/i,
83
+ parse: (m) => ({
84
+ type: "info",
85
+ nodeId: m[1],
86
+ }),
87
+ },
88
+ // config <nodeId>
89
+ {
90
+ pattern: /^config\s+(\S+)$/i,
91
+ parse: (m) => ({
92
+ type: "config_open",
93
+ nodeId: m[1],
94
+ }),
95
+ },
96
+ // select <nodeId>
97
+ {
98
+ pattern: /^select\s+(\S+)$/i,
99
+ parse: (m) => ({
100
+ type: "select_node",
101
+ nodeId: m[1],
102
+ }),
103
+ },
104
+ // connect <nid>:<port> to <nid>:<port>
105
+ {
106
+ pattern: /^connect\s+(\S+?):(\S+)\s+to\s+(\S+?):(\S+)$/i,
107
+ parse: (m) => ({
108
+ type: "connect",
109
+ sourceNodeId: m[1],
110
+ sourcePort: m[2],
111
+ targetNodeId: m[3],
112
+ targetPort: m[4],
113
+ }),
114
+ },
115
+ // disconnect <nid>:<port> from <nid>:<port>
116
+ {
117
+ pattern: /^disconnect\s+(\S+?):(\S+)\s+from\s+(\S+?):(\S+)$/i,
118
+ parse: (m) => ({
119
+ type: "disconnect_ports",
120
+ sourceNodeId: m[1],
121
+ sourcePort: m[2],
122
+ targetNodeId: m[3],
123
+ targetPort: m[4],
124
+ }),
125
+ },
126
+ // disconnect <nodeId> (disconnect all)
127
+ {
128
+ pattern: /^disconnect\s+(\S+)$/i,
129
+ parse: (m) => ({
130
+ type: "disconnect_node",
131
+ nodeId: m[1],
132
+ }),
133
+ },
134
+ // list nodes
135
+ {
136
+ pattern: /^list\s+nodes$/i,
137
+ parse: () => ({ type: "list_nodes" }),
138
+ },
139
+ // list edges
140
+ {
141
+ pattern: /^list\s+edges$/i,
142
+ parse: () => ({ type: "list_edges" }),
143
+ },
144
+ // list types
145
+ {
146
+ pattern: /^list\s+types$/i,
147
+ parse: () => ({ type: "list_types" }),
148
+ },
149
+ // undo
150
+ {
151
+ pattern: /^undo$/i,
152
+ parse: () => ({ type: "undo" }),
153
+ },
154
+ // redo
155
+ {
156
+ pattern: /^redo$/i,
157
+ parse: () => ({ type: "redo" }),
158
+ },
159
+ // help <command>
160
+ {
161
+ pattern: /^help\s+(\S+)$/i,
162
+ parse: (m) => ({
163
+ type: "help",
164
+ command: m[1],
165
+ }),
166
+ },
167
+ // help
168
+ {
169
+ pattern: /^help$/i,
170
+ parse: () => ({ type: "help" }),
171
+ },
172
+ // clear
173
+ {
174
+ pattern: /^clear$/i,
175
+ parse: () => ({ type: "clear" }),
176
+ },
177
+ // swap <nodeId> with <type> (Phase 2)
178
+ {
179
+ pattern: /^swap\s+(\S+)\s+with\s+(\S+)$/i,
180
+ parse: (m) => ({
181
+ type: "swap_node",
182
+ nodeId: m[1],
183
+ newTypeId: m[2],
184
+ }),
185
+ },
186
+ // move <nodeId> to <x>,<y> (Phase 2)
187
+ {
188
+ pattern: /^move\s+(\S+)\s+to\s+(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)$/i,
189
+ parse: (m) => ({
190
+ type: "move_node",
191
+ nodeId: m[1],
192
+ position: parseCoords(m[2], m[3]),
193
+ }),
194
+ },
195
+ // layout auto [--direction horizontal|vertical] (Phase 2)
196
+ {
197
+ pattern: /^layout\s+auto\s+--direction\s+(horizontal|vertical)$/i,
198
+ parse: (m) => ({
199
+ type: "auto_layout",
200
+ direction: m[1].toLowerCase(),
201
+ }),
202
+ },
203
+ // layout auto (Phase 2)
204
+ {
205
+ pattern: /^layout\s+auto$/i,
206
+ parse: () => ({ type: "auto_layout" }),
207
+ },
208
+ // layout beautify — preserve relative positions, normalize spacing
209
+ {
210
+ pattern: /^layout\s+beautify$/i,
211
+ parse: () => ({ type: "beautify_layout" }),
212
+ },
213
+ // canvas fitview | canvas fit
214
+ {
215
+ pattern: /^canvas\s+fit(?:\s*view)?$/i,
216
+ parse: () => ({ type: "canvas_fit_view" }),
217
+ },
218
+ // canvas zoom in
219
+ {
220
+ pattern: /^canvas\s+zoom\s+in$/i,
221
+ parse: () => ({ type: "canvas_zoom_in" }),
222
+ },
223
+ // canvas zoom out
224
+ {
225
+ pattern: /^canvas\s+zoom\s+out$/i,
226
+ parse: () => ({ type: "canvas_zoom_out" }),
227
+ },
228
+ // canvas zoom <level>
229
+ {
230
+ pattern: /^canvas\s+zoom\s+(\d+(?:\.\d+)?)$/i,
231
+ parse: (m) => ({ type: "canvas_zoom_to", level: Number(m[1]) }),
232
+ },
233
+ // canvas pan <x>,<y>
234
+ {
235
+ pattern: /^canvas\s+pan\s+(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)$/i,
236
+ parse: (m) => ({
237
+ type: "canvas_pan_to",
238
+ position: parseCoords(m[1], m[2]),
239
+ }),
240
+ },
241
+ // canvas reset
242
+ {
243
+ pattern: /^canvas\s+reset$/i,
244
+ parse: () => ({ type: "canvas_reset_view" }),
245
+ },
246
+ ];
247
+ // ============================================================================
248
+ // Public API
249
+ // ============================================================================
250
+ /**
251
+ * Parse a command string into a typed Command object.
252
+ *
253
+ * Command verbs are case-insensitive; identifiers are case-sensitive.
254
+ * Returns ParseResult with ok: true on success, ok: false on failure.
255
+ */
256
+ export function parseCommand(input) {
257
+ const trimmed = input.trim();
258
+ if (!trimmed) {
259
+ return { ok: false, error: "Empty command", input };
260
+ }
261
+ for (const rule of rules) {
262
+ const match = trimmed.match(rule.pattern);
263
+ if (match) {
264
+ return { ok: true, command: rule.parse(match) };
265
+ }
266
+ }
267
+ // Extract verb for better error message
268
+ const verb = trimmed.split(/\s+/)[0].toLowerCase();
269
+ const knownVerbs = [
270
+ "add", "delete", "rename", "set", "get", "info", "config",
271
+ "select", "connect", "disconnect", "list", "undo", "redo",
272
+ "help", "clear", "swap", "move", "layout", "canvas",
273
+ ];
274
+ if (knownVerbs.includes(verb)) {
275
+ return { ok: false, error: `Invalid syntax for '${verb}' command`, input };
276
+ }
277
+ return { ok: false, error: `Unknown command: ${verb}`, input };
278
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Auto-positioner for command-created nodes.
3
+ *
4
+ * Computes a reasonable canvas position when no explicit coordinates are given.
5
+ *
6
+ * @module commands/positioner
7
+ */
8
+ import type { WorkflowNode } from "../types/index.js";
9
+ /**
10
+ * Computes an auto-position for a new node based on existing nodes.
11
+ *
12
+ * - Empty canvas: returns `{ x: 100, y: 100 }`.
13
+ * - Non-empty canvas: places new node 250px to the right of the rightmost node,
14
+ * at the same y as the rightmost node.
15
+ */
16
+ export declare function computeAutoPosition(existingNodes: Pick<WorkflowNode, "position">[]): {
17
+ x: number;
18
+ y: number;
19
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Auto-positioner for command-created nodes.
3
+ *
4
+ * Computes a reasonable canvas position when no explicit coordinates are given.
5
+ *
6
+ * @module commands/positioner
7
+ */
8
+ /** Default starting position for the first node on an empty canvas. */
9
+ const DEFAULT_START = { x: 100, y: 100 };
10
+ /** Horizontal gap between the rightmost existing node and a new node. */
11
+ const HORIZONTAL_GAP = 250;
12
+ /**
13
+ * Computes an auto-position for a new node based on existing nodes.
14
+ *
15
+ * - Empty canvas: returns `{ x: 100, y: 100 }`.
16
+ * - Non-empty canvas: places new node 250px to the right of the rightmost node,
17
+ * at the same y as the rightmost node.
18
+ */
19
+ export function computeAutoPosition(existingNodes) {
20
+ if (existingNodes.length === 0) {
21
+ return { ...DEFAULT_START };
22
+ }
23
+ let rightmost = existingNodes[0];
24
+ for (const node of existingNodes) {
25
+ if (node.position.x > rightmost.position.x) {
26
+ rightmost = node;
27
+ }
28
+ }
29
+ return {
30
+ x: rightmost.position.x + HORIZONTAL_GAP,
31
+ y: rightmost.position.y,
32
+ };
33
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Store Integration Bridge
3
+ *
4
+ * Bridges the command system to the live Svelte stores.
5
+ * This is the only Svelte-coupled file in commands/.
6
+ */
7
+ import { type CommandContext, type UIAction } from "./types.js";
8
+ import type { NodeMetadata } from "../types/index.js";
9
+ /**
10
+ * Creates a CommandContext that bridges the command system to the live Svelte stores.
11
+ *
12
+ * @param nodeTypes - Available node type definitions
13
+ * @param onUIAction - Optional callback for UI-side actions (open config panel, select node)
14
+ * @returns CommandContext connected to live stores, or null if no workflow is loaded
15
+ */
16
+ export declare function createStoreCommandContext(nodeTypes: NodeMetadata[], onUIAction?: (action: UIAction) => void): CommandContext | null;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Store Integration Bridge
3
+ *
4
+ * Bridges the command system to the live Svelte stores.
5
+ * This is the only Svelte-coupled file in commands/.
6
+ */
7
+ import { getWorkflowStore, workflowActions, } from "../stores/workflowStore.svelte.js";
8
+ import { historyService } from "../services/historyService.js";
9
+ import { buildTypeMap, } from "./types.js";
10
+ /**
11
+ * Creates a CommandContext that bridges the command system to the live Svelte stores.
12
+ *
13
+ * @param nodeTypes - Available node type definitions
14
+ * @param onUIAction - Optional callback for UI-side actions (open config panel, select node)
15
+ * @returns CommandContext connected to live stores, or null if no workflow is loaded
16
+ */
17
+ export function createStoreCommandContext(nodeTypes, onUIAction) {
18
+ const workflow = getWorkflowStore();
19
+ if (!workflow) {
20
+ return null;
21
+ }
22
+ const dispatch = {
23
+ addNode: (node) => workflowActions.addNode(node),
24
+ removeNode: (nodeId) => workflowActions.removeNode(nodeId),
25
+ updateNode: (nodeId, updates) => workflowActions.updateNode(nodeId, updates),
26
+ addEdge: (edge) => workflowActions.addEdge(edge),
27
+ removeEdge: (edgeId) => workflowActions.removeEdge(edgeId),
28
+ batchUpdate: (updates) => workflowActions.batchUpdate(updates),
29
+ undo: () => {
30
+ const previousState = historyService.undo();
31
+ if (previousState) {
32
+ workflowActions.restoreFromHistory(previousState);
33
+ return true;
34
+ }
35
+ return false;
36
+ },
37
+ redo: () => {
38
+ const nextState = historyService.redo();
39
+ if (nextState) {
40
+ workflowActions.restoreFromHistory(nextState);
41
+ return true;
42
+ }
43
+ return false;
44
+ },
45
+ startTransaction: (description) => {
46
+ const currentWorkflow = getWorkflowStore();
47
+ if (currentWorkflow) {
48
+ historyService.startTransaction(currentWorkflow, description);
49
+ }
50
+ },
51
+ commitTransaction: () => historyService.commitTransaction(),
52
+ cancelTransaction: () => {
53
+ const snapshot = historyService.cancelTransaction();
54
+ if (snapshot) {
55
+ workflowActions.restoreFromHistory(snapshot);
56
+ }
57
+ },
58
+ emitUIAction: onUIAction,
59
+ swapNode: (updates) => workflowActions.swapNode(updates),
60
+ };
61
+ return {
62
+ getWorkflow: () => getWorkflowStore(),
63
+ nodeTypes,
64
+ typeMap: buildTypeMap(nodeTypes),
65
+ dispatch,
66
+ };
67
+ }