@flowdrop/flowdrop 2.0.0-beta.3 → 2.0.0-beta.5

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 (87) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +5 -5
  3. package/dist/adapters/WorkflowAdapter.js +4 -5
  4. package/dist/adapters/agentspec/AgentSpecAdapter.js +3 -3
  5. package/dist/adapters/agentspec/defaultNodeTypes.js +9 -9
  6. package/dist/commands/executor.js +5 -6
  7. package/dist/commands/types.js +5 -5
  8. package/dist/components/App.svelte +19 -150
  9. package/dist/components/Button.stories.svelte +65 -0
  10. package/dist/components/Button.stories.svelte.d.ts +19 -0
  11. package/dist/components/Button.svelte +62 -0
  12. package/dist/components/Button.svelte.d.ts +24 -0
  13. package/dist/components/ConfigForm.svelte +4 -4
  14. package/dist/components/EditorStatusBar.stories.svelte +44 -0
  15. package/dist/components/EditorStatusBar.stories.svelte.d.ts +27 -0
  16. package/dist/components/EditorStatusBar.svelte +99 -0
  17. package/dist/components/EditorStatusBar.svelte.d.ts +15 -0
  18. package/dist/components/IconButton.svelte +80 -0
  19. package/dist/components/IconButton.svelte.d.ts +30 -0
  20. package/dist/components/Input.svelte +74 -0
  21. package/dist/components/Input.svelte.d.ts +17 -0
  22. package/dist/components/Navbar.svelte +9 -4
  23. package/dist/components/Navbar.svelte.d.ts +3 -0
  24. package/dist/components/NodeSidebar.svelte +17 -115
  25. package/dist/components/NodeSwapPicker.svelte +12 -28
  26. package/dist/components/Select.svelte +53 -0
  27. package/dist/components/Select.svelte.d.ts +15 -0
  28. package/dist/components/Textarea.svelte +39 -0
  29. package/dist/components/Textarea.svelte.d.ts +12 -0
  30. package/dist/components/ThemeToggle.svelte +15 -89
  31. package/dist/components/UniversalNode.svelte +5 -4
  32. package/dist/components/UniversalNode.svelte.d.ts +1 -1
  33. package/dist/components/console/ConsoleInput.svelte +3 -3
  34. package/dist/components/form/FormArray.svelte +37 -157
  35. package/dist/components/form/FormCheckboxGroup.svelte +1 -1
  36. package/dist/components/form/FormField.svelte +5 -44
  37. package/dist/components/form/FormFieldLight.svelte +5 -44
  38. package/dist/components/form/FormFieldset.svelte +1 -1
  39. package/dist/components/form/FormNumberField.svelte +4 -32
  40. package/dist/components/form/FormRangeField.svelte +17 -7
  41. package/dist/components/form/FormSelect.svelte +13 -79
  42. package/dist/components/form/FormTextField.svelte +3 -39
  43. package/dist/components/form/FormTextarea.svelte +4 -43
  44. package/dist/components/form/resolveFieldType.d.ts +24 -0
  45. package/dist/components/form/resolveFieldType.js +55 -0
  46. package/dist/components/icons/CloseIcon.svelte +6 -0
  47. package/dist/components/icons/CloseIcon.svelte.d.ts +26 -0
  48. package/dist/components/nodes/AtomNode.svelte +3 -3
  49. package/dist/components/nodes/AtomNode.svelte.d.ts +1 -1
  50. package/dist/components/nodes/GatewayNode.svelte +8 -11
  51. package/dist/components/nodes/GatewayNode.svelte.d.ts +1 -1
  52. package/dist/components/nodes/IdeaNode.svelte +10 -8
  53. package/dist/components/nodes/IdeaNode.svelte.d.ts +8 -4
  54. package/dist/components/nodes/NotesNode.svelte +6 -4
  55. package/dist/components/nodes/NotesNode.svelte.d.ts +8 -4
  56. package/dist/components/nodes/SimpleNode.svelte +10 -8
  57. package/dist/components/nodes/SimpleNode.svelte.d.ts +4 -4
  58. package/dist/components/nodes/SquareNode.svelte +10 -8
  59. package/dist/components/nodes/SquareNode.svelte.d.ts +4 -4
  60. package/dist/components/nodes/TerminalNode.svelte +10 -8
  61. package/dist/components/nodes/TerminalNode.svelte.d.ts +4 -4
  62. package/dist/components/nodes/ToolNode.svelte +10 -8
  63. package/dist/components/nodes/ToolNode.svelte.d.ts +6 -6
  64. package/dist/components/nodes/WorkflowNode.svelte +7 -10
  65. package/dist/components/nodes/WorkflowNode.svelte.d.ts +1 -1
  66. package/dist/components/playground/InputCollector.svelte +11 -46
  67. package/dist/components/playground/PipelineKanbanView.svelte +2 -2
  68. package/dist/components/playground/PipelineTableView.svelte +2 -2
  69. package/dist/helpers/workflowEditorHelper.js +4 -5
  70. package/dist/messages/index.d.ts +1 -1
  71. package/dist/messages/index.js +1 -1
  72. package/dist/openapi/v1/openapi.yaml +2 -2
  73. package/dist/registry/nodeComponentRegistry.d.ts +2 -1
  74. package/dist/services/dynamicSchemaService.d.ts +2 -2
  75. package/dist/services/dynamicSchemaService.js +8 -8
  76. package/dist/skins/drafter.js +41 -28
  77. package/dist/stores/playgroundStore.svelte.js +1 -1
  78. package/dist/stores/workflowStore.svelte.js +0 -18
  79. package/dist/styles/base.css +247 -5
  80. package/dist/styles/tokens.css +6 -0
  81. package/dist/svelte-app.js +68 -107
  82. package/dist/types/index.d.ts +6 -7
  83. package/dist/utils/connections.js +20 -56
  84. package/dist/utils/nodeIds.d.ts +1 -1
  85. package/dist/utils/nodeIds.js +1 -1
  86. package/dist/utils/nodeSwap.js +3 -6
  87. package/package.json +1 -1
@@ -55,6 +55,58 @@ function releaseInstance(fd, isDefault) {
55
55
  fd.destroy();
56
56
  }
57
57
  }
58
+ /**
59
+ * Resolve endpoint config, port config and categories from mount options and
60
+ * apply them to the given instance (API context, port-compatibility checker,
61
+ * categories). Shared by `mountFlowDropApp` and `mountWorkflowEditor`.
62
+ *
63
+ * @returns the resolved {@link EndpointConfig} (merged with defaults), which the
64
+ * callers forward to their mounted component.
65
+ */
66
+ async function configureInstance(fd, options) {
67
+ const { endpointConfig, portConfig, categories, authProvider } = options;
68
+ // Create endpoint configuration, merging with defaults so all required
69
+ // endpoints are present.
70
+ const { defaultEndpointConfig } = await import('./config/endpoints.js');
71
+ const config = endpointConfig
72
+ ? {
73
+ ...defaultEndpointConfig,
74
+ ...endpointConfig,
75
+ endpoints: {
76
+ ...defaultEndpointConfig.endpoints,
77
+ ...endpointConfig.endpoints
78
+ }
79
+ }
80
+ : defaultEndpointConfig;
81
+ // Initialize port configuration (fetch from API when not supplied).
82
+ let finalPortConfig = portConfig;
83
+ if (!finalPortConfig) {
84
+ try {
85
+ finalPortConfig = await fetchPortConfig(config, authProvider);
86
+ }
87
+ catch (error) {
88
+ logger.warn('Failed to fetch port config from API, using default:', error);
89
+ finalPortConfig = DEFAULT_PORT_CONFIG;
90
+ }
91
+ }
92
+ // Configure this instance's API context and port compatibility checker.
93
+ fd.api.configure(config, authProvider);
94
+ fd.portCompatibility.reinitialize(finalPortConfig);
95
+ // Initialize this instance's categories (fetch from API when not supplied).
96
+ if (categories) {
97
+ fd.categories.initialize(categories);
98
+ }
99
+ else {
100
+ try {
101
+ const fetchedCategories = await fetchCategories(config, authProvider);
102
+ fd.categories.initialize(fetchedCategories);
103
+ }
104
+ catch (error) {
105
+ logger.warn('Failed to fetch categories from API, using defaults:', error);
106
+ }
107
+ }
108
+ return config;
109
+ }
58
110
  /**
59
111
  * Mount the full FlowDrop App with navbar, sidebars, and workflow editor
60
112
  *
@@ -103,61 +155,14 @@ export async function mountFlowDropApp(container, options = {}) {
103
155
  await initializeSettings({
104
156
  defaults: initialSettings
105
157
  });
106
- // Create endpoint configuration
107
- let config;
108
- if (endpointConfig) {
109
- // Merge with default configuration to ensure all required endpoints are present
110
- const { defaultEndpointConfig } = await import('./config/endpoints.js');
111
- config = {
112
- ...defaultEndpointConfig,
113
- ...endpointConfig,
114
- endpoints: {
115
- ...defaultEndpointConfig.endpoints,
116
- ...endpointConfig.endpoints
117
- }
118
- };
119
- }
120
- else {
121
- // Use default configuration if none provided
122
- const { defaultEndpointConfig } = await import('./config/endpoints.js');
123
- config = defaultEndpointConfig;
124
- }
125
- // Initialize port configuration
126
- let finalPortConfig = portConfig;
127
- if (!finalPortConfig && config) {
128
- // Try to fetch port configuration from API
129
- try {
130
- finalPortConfig = await fetchPortConfig(config, authProvider);
131
- }
132
- catch (error) {
133
- logger.warn('Failed to fetch port config from API, using default:', error);
134
- finalPortConfig = DEFAULT_PORT_CONFIG;
135
- }
136
- }
137
- else if (!finalPortConfig) {
138
- finalPortConfig = DEFAULT_PORT_CONFIG;
139
- }
140
- // Configure this instance's API context (endpoints + auth provider) so
141
- // <App> and services resolve it via getInstance().api.
142
- if (config) {
143
- fd.api.configure(config, authProvider);
144
- }
145
- // Re-initialize this instance's port compatibility checker with the resolved
146
- // config (it was seeded with DEFAULT_PORT_CONFIG at construction).
147
- fd.portCompatibility.reinitialize(finalPortConfig);
148
- // Initialize this instance's categories
149
- if (categories) {
150
- fd.categories.initialize(categories);
151
- }
152
- else if (config) {
153
- try {
154
- const fetchedCategories = await fetchCategories(config, authProvider);
155
- fd.categories.initialize(fetchedCategories);
156
- }
157
- catch (error) {
158
- logger.warn('Failed to fetch categories from API, using defaults:', error);
159
- }
160
- }
158
+ // Resolve and apply endpoint config, port config and categories to this
159
+ // instance (see configureInstance).
160
+ const config = await configureInstance(fd, {
161
+ endpointConfig,
162
+ portConfig,
163
+ categories,
164
+ authProvider
165
+ });
161
166
  // Set up event handler callbacks in this instance's store
162
167
  if (eventHandlers?.onDirtyStateChange) {
163
168
  fd.workflow.setOnDirtyStateChange(eventHandlers.onDirtyStateChange);
@@ -338,58 +343,14 @@ export async function mountWorkflowEditor(container, options = {}) {
338
343
  const { workflow, endpointConfig, portConfig, categories, authProvider, instanceId, builtinEditors } = options;
339
344
  // Per-instance state container (see mountFlowDropApp)
340
345
  const { fd, isDefault } = acquireInstance(instanceId);
341
- // Create endpoint configuration
342
- let config;
343
- if (endpointConfig) {
344
- // Merge with default configuration to ensure all required endpoints are present
345
- const { defaultEndpointConfig } = await import('./config/endpoints.js');
346
- config = {
347
- ...defaultEndpointConfig,
348
- ...endpointConfig,
349
- endpoints: {
350
- ...defaultEndpointConfig.endpoints,
351
- ...endpointConfig.endpoints
352
- }
353
- };
354
- }
355
- else {
356
- // Use default configuration if none provided
357
- const { defaultEndpointConfig } = await import('./config/endpoints.js');
358
- config = defaultEndpointConfig;
359
- }
360
- // Initialize port configuration
361
- let finalPortConfig = portConfig;
362
- if (!finalPortConfig && config) {
363
- // Try to fetch port configuration from API
364
- try {
365
- finalPortConfig = await fetchPortConfig(config, authProvider);
366
- }
367
- catch (error) {
368
- logger.warn('Failed to fetch port config from API, using default:', error);
369
- finalPortConfig = DEFAULT_PORT_CONFIG;
370
- }
371
- }
372
- else if (!finalPortConfig) {
373
- finalPortConfig = DEFAULT_PORT_CONFIG;
374
- }
375
- // Configure this instance's API context and port compatibility checker.
376
- if (config) {
377
- fd.api.configure(config, authProvider);
378
- }
379
- fd.portCompatibility.reinitialize(finalPortConfig);
380
- // Initialize this instance's categories
381
- if (categories) {
382
- fd.categories.initialize(categories);
383
- }
384
- else if (config) {
385
- try {
386
- const fetchedCategories = await fetchCategories(config, authProvider);
387
- fd.categories.initialize(fetchedCategories);
388
- }
389
- catch (error) {
390
- logger.warn('Failed to fetch categories from API, using defaults:', error);
391
- }
392
- }
346
+ // Resolve and apply endpoint config, port config and categories to this
347
+ // instance (see configureInstance).
348
+ const config = await configureInstance(fd, {
349
+ endpointConfig,
350
+ portConfig,
351
+ categories,
352
+ authProvider
353
+ });
393
354
  // Seed the instance's workflow before mounting so the editor renders it
394
355
  // immediately. (1.x accepted this option but silently ignored it.)
395
356
  if (workflow) {
@@ -327,7 +327,7 @@ export interface AutocompleteConfig {
327
327
  * method: "GET",
328
328
  * headers: { "X-Custom-Header": "value" },
329
329
  * parameterMapping: {
330
- * nodeTypeId: "metadata.id",
330
+ * nodeTypeId: "metadata.node_type_id",
331
331
  * instanceId: "id"
332
332
  * }
333
333
  * };
@@ -352,7 +352,7 @@ export interface DynamicSchemaEndpoint {
352
352
  /**
353
353
  * Maps template variables to their source paths.
354
354
  * Keys are variable names used in the URL, values are dot-notation paths
355
- * to resolve from the node context (e.g., "metadata.id", "config.apiKey", "id")
355
+ * to resolve from the node context (e.g., "metadata.node_type_id", "config.apiKey", "id")
356
356
  */
357
357
  parameterMapping?: Record<string, string>;
358
358
  /**
@@ -381,7 +381,7 @@ export interface DynamicSchemaEndpoint {
381
381
  * url: "https://admin.example.com/nodes/{nodeTypeId}/edit/{instanceId}",
382
382
  * label: "Configure in Admin Panel",
383
383
  * parameterMapping: {
384
- * nodeTypeId: "metadata.id",
384
+ * nodeTypeId: "metadata.node_type_id",
385
385
  * instanceId: "id"
386
386
  * },
387
387
  * openInNewTab: true
@@ -408,7 +408,7 @@ export interface ExternalEditLink {
408
408
  /**
409
409
  * Maps template variables to their source paths.
410
410
  * Keys are variable names used in the URL, values are dot-notation paths
411
- * to resolve from the node context (e.g., "metadata.id", "config.apiKey", "id")
411
+ * to resolve from the node context (e.g., "metadata.node_type_id", "config.apiKey", "id")
412
412
  */
413
413
  parameterMapping?: Record<string, string>;
414
414
  /**
@@ -602,7 +602,8 @@ export interface NodeExtensions {
602
602
  * Node configuration metadata
603
603
  */
604
604
  export interface NodeMetadata {
605
- id: string;
605
+ /** The node type entity id — the runtime's resolution anchor. */
606
+ node_type_id: string;
606
607
  name: string;
607
608
  type?: NodeType;
608
609
  /**
@@ -1132,8 +1133,6 @@ export interface WorkflowNode extends Node {
1132
1133
  isProcessing?: boolean;
1133
1134
  /** Error message if the node execution failed */
1134
1135
  error?: string;
1135
- /** Alternative node identifier */
1136
- nodeId?: string;
1137
1136
  /** Node execution tracking information */
1138
1137
  executionInfo?: NodeExecutionInfo;
1139
1138
  /**
@@ -119,7 +119,7 @@ export class PortCompatibilityChecker {
119
119
  * Get all possible connections from a source node to target nodes
120
120
  */
121
121
  export function getPossibleConnections(checker, sourceNode, targetNodes, nodeTypes) {
122
- const sourceMetadata = nodeTypes.find((nt) => nt.id === sourceNode.data.metadata.id);
122
+ const sourceMetadata = nodeTypes.find((nt) => nt.node_type_id === sourceNode.data.metadata.node_type_id);
123
123
  if (!sourceMetadata)
124
124
  return [];
125
125
  const possibleConnections = [];
@@ -129,7 +129,7 @@ export function getPossibleConnections(checker, sourceNode, targetNodes, nodeTyp
129
129
  for (const targetNode of targetNodes) {
130
130
  if (targetNode.id === sourceNode.id)
131
131
  continue; // Skip self-connection
132
- const targetMetadata = nodeTypes.find((nt) => nt.id === targetNode.data.metadata.id);
132
+ const targetMetadata = nodeTypes.find((nt) => nt.node_type_id === targetNode.data.metadata.node_type_id);
133
133
  if (!targetMetadata)
134
134
  continue;
135
135
  // Get all input ports from target node
@@ -170,8 +170,8 @@ export function validateConnection(checker, sourceNodeId, sourcePortId, targetNo
170
170
  return { valid: false, error: 'Cannot connect node to itself' };
171
171
  }
172
172
  // Get node metadata
173
- const sourceMetadata = nodeTypes.find((nt) => nt.id === sourceNode.data.metadata.id);
174
- const targetMetadata = nodeTypes.find((nt) => nt.id === targetNode.data.metadata.id);
173
+ const sourceMetadata = nodeTypes.find((nt) => nt.node_type_id === sourceNode.data.metadata.node_type_id);
174
+ const targetMetadata = nodeTypes.find((nt) => nt.node_type_id === targetNode.data.metadata.node_type_id);
175
175
  if (!sourceMetadata || !targetMetadata) {
176
176
  return { valid: false, error: 'Node metadata not found' };
177
177
  }
@@ -200,14 +200,14 @@ export function getConnectionSuggestions(checker, nodeId, nodes, nodeTypes) {
200
200
  const node = nodes.find((n) => n.id === nodeId);
201
201
  if (!node)
202
202
  return [];
203
- const metadata = nodeTypes.find((nt) => nt.id === node.data.metadata.id);
203
+ const metadata = nodeTypes.find((nt) => nt.node_type_id === node.data.metadata.node_type_id);
204
204
  if (!metadata)
205
205
  return [];
206
206
  const suggestions = [];
207
207
  // Get all other nodes
208
208
  const otherNodes = nodes.filter((n) => n.id !== nodeId);
209
209
  for (const otherNode of otherNodes) {
210
- const otherMetadata = nodeTypes.find((nt) => nt.id === otherNode.data.metadata.id);
210
+ const otherMetadata = nodeTypes.find((nt) => nt.node_type_id === otherNode.data.metadata.node_type_id);
211
211
  if (!otherMetadata)
212
212
  continue;
213
213
  // Check outputs from other nodes to inputs of current node
@@ -253,8 +253,17 @@ export function getConnectionSuggestions(checker, nodeId, nodes, nodeTypes) {
253
253
  * @returns True if any cycle exists in the workflow
254
254
  */
255
255
  export function hasCycles(nodes, edges) {
256
- // Build adjacency map once (O(E)) so the DFS inner loop is O(1) per lookup
257
- // instead of scanning all edges on every recursive call (which was O(V*E)).
256
+ return detectCycles(nodes, edges);
257
+ }
258
+ /**
259
+ * Detect whether a directed graph contains a cycle, using DFS over a pre-built
260
+ * adjacency map (O(E) build, O(1) per neighbour lookup — avoids the O(V*E) of
261
+ * re-scanning every edge on each recursive call).
262
+ *
263
+ * Shared by `hasCycles` (all edges) and `hasInvalidCycles` (loopback edges
264
+ * pre-filtered out by the caller).
265
+ */
266
+ function detectCycles(nodes, edges) {
258
267
  const adjacencyMap = new Map();
259
268
  for (const node of nodes) {
260
269
  adjacencyMap.set(node.id, []);
@@ -274,7 +283,6 @@ export function hasCycles(nodes, edges) {
274
283
  return false;
275
284
  visited.add(nodeId);
276
285
  recursionStack.add(nodeId);
277
- // Use pre-built adjacency map instead of filtering all edges each call
278
286
  const neighbors = adjacencyMap.get(nodeId) || [];
279
287
  for (const target of neighbors) {
280
288
  if (hasCycleUtil(target))
@@ -283,7 +291,6 @@ export function hasCycles(nodes, edges) {
283
291
  recursionStack.delete(nodeId);
284
292
  return false;
285
293
  }
286
- // Check each node
287
294
  for (const node of nodes) {
288
295
  if (!visited.has(node.id)) {
289
296
  if (hasCycleUtil(node.id))
@@ -309,53 +316,10 @@ export function hasCycles(nodes, edges) {
309
316
  * ```
310
317
  */
311
318
  export function hasInvalidCycles(nodes, edges) {
312
- // Filter out loopback edges - these create valid cycles for loop iteration
319
+ // Filter out loopback edges - these create valid cycles for loop iteration,
320
+ // then reuse the shared detector over the remaining edges.
313
321
  const nonLoopbackEdges = edges.filter((edge) => !isLoopbackEdge(edge));
314
- // Build adjacency map from non-loopback edges once (O(E)) so the DFS inner
315
- // loop is O(1) per lookup instead of scanning all edges on every recursive
316
- // call (which was O(V*E)).
317
- const adjacencyMap = new Map();
318
- for (const node of nodes) {
319
- adjacencyMap.set(node.id, []);
320
- }
321
- for (const edge of nonLoopbackEdges) {
322
- const neighbors = adjacencyMap.get(edge.source);
323
- if (neighbors) {
324
- neighbors.push(edge.target);
325
- }
326
- }
327
- // Check for cycles using only non-loopback edges
328
- const visited = new Set();
329
- const recursionStack = new Set();
330
- /**
331
- * DFS utility to detect cycles in the graph
332
- * @param nodeId - Current node being visited
333
- * @returns True if a cycle is found from this node
334
- */
335
- function hasCycleUtil(nodeId) {
336
- if (recursionStack.has(nodeId))
337
- return true;
338
- if (visited.has(nodeId))
339
- return false;
340
- visited.add(nodeId);
341
- recursionStack.add(nodeId);
342
- // Use pre-built adjacency map instead of filtering all edges each call
343
- const neighbors = adjacencyMap.get(nodeId) || [];
344
- for (const target of neighbors) {
345
- if (hasCycleUtil(target))
346
- return true;
347
- }
348
- recursionStack.delete(nodeId);
349
- return false;
350
- }
351
- // Check each node for cycles
352
- for (const node of nodes) {
353
- if (!visited.has(node.id)) {
354
- if (hasCycleUtil(node.id))
355
- return true;
356
- }
357
- }
358
- return false;
322
+ return detectCycles(nodes, nonLoopbackEdges);
359
323
  }
360
324
  /**
361
325
  * Get the execution order for a workflow (topological sort)
@@ -12,7 +12,7 @@ interface NodeWithMetadata {
12
12
  id: string;
13
13
  data?: {
14
14
  metadata?: {
15
- id?: string;
15
+ node_type_id?: string;
16
16
  };
17
17
  };
18
18
  }
@@ -11,7 +11,7 @@
11
11
  export function generateNodeId(nodeTypeId, existingNodes) {
12
12
  // Count how many nodes of this type already exist
13
13
  const existingNodeIds = existingNodes
14
- .filter((node) => node.data?.metadata?.id === nodeTypeId)
14
+ .filter((node) => node.data?.metadata?.node_type_id === nodeTypeId)
15
15
  .map((node) => node.id);
16
16
  // Extract the numbers from existing IDs with the same prefix
17
17
  const existingNumbers = existingNodeIds
@@ -176,9 +176,6 @@ export function executeSwap(oldNode, newMetadata, preview, allNodes, allEdges) {
176
176
  label: newMetadata.name,
177
177
  config: mappedConfig,
178
178
  metadata: newMetadata,
179
- // Node components derive their handle IDs from data.nodeId — without it
180
- // every edge anchored to this node silently disappears from the canvas.
181
- nodeId: newNodeId,
182
179
  extensions
183
180
  }
184
181
  };
@@ -218,7 +215,7 @@ export function executeSwap(oldNode, newMetadata, preview, allNodes, allEdges) {
218
215
  * @returns The newer NodeMetadata if an upgrade is available, null otherwise
219
216
  */
220
217
  export function getVersionUpgrade(currentMetadata, allNodeTypes) {
221
- const available = allNodeTypes.find((n) => n.id === currentMetadata.id);
218
+ const available = allNodeTypes.find((n) => n.node_type_id === currentMetadata.node_type_id);
222
219
  if (!available)
223
220
  return null;
224
221
  if (compareSemver(available.version, currentMetadata.version) > 0) {
@@ -253,7 +250,7 @@ function classifyMatch(oldPort, matchedPort) {
253
250
  export function computeSwapPreviewWithOptions(oldNode, newMetadata, edges, allNodes, options) {
254
251
  const checker = options.checker ?? null;
255
252
  const oldNodeId = oldNode.id;
256
- const newNodeId = generateNodeId(newMetadata.id, allNodes);
253
+ const newNodeId = generateNodeId(newMetadata.node_type_id, allNodes);
257
254
  // Collect connected edges
258
255
  const connectedEdges = edges.filter((e) => e.source === oldNodeId || e.target === oldNodeId);
259
256
  // Try strategy-based port mapping
@@ -420,7 +417,7 @@ export function computeSwapPreviewWithOptions(oldNode, newMetadata, edges, allNo
420
417
  */
421
418
  export function computeInteractiveState(oldNode, newMetadata, edges, allNodes, options = {}) {
422
419
  const oldNodeId = oldNode.id;
423
- const newNodeId = generateNodeId(newMetadata.id, allNodes);
420
+ const newNodeId = generateNodeId(newMetadata.node_type_id, allNodes);
424
421
  const connectedEdges = edges.filter((e) => e.source === oldNodeId || e.target === oldNodeId);
425
422
  // Compute the base preview to get auto-matched ports
426
423
  const preview = computeSwapPreviewWithOptions(oldNode, newMetadata, edges, allNodes, options);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "A drop-in visual workflow editor for any web application. You own the backend. You own the data. You own the orchestration.",
4
4
  "license": "MIT",
5
5
  "private": false,
6
- "version": "2.0.0-beta.3",
6
+ "version": "2.0.0-beta.5",
7
7
  "author": "Shibin Das (D34dMan)",
8
8
  "bugs": {
9
9
  "url": "https://github.com/flowdrop-io/flowdrop/issues"