@flowdrop/flowdrop 2.0.0-beta.4 → 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 (44) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/adapters/WorkflowAdapter.js +4 -5
  3. package/dist/adapters/agentspec/AgentSpecAdapter.js +3 -3
  4. package/dist/adapters/agentspec/defaultNodeTypes.js +9 -9
  5. package/dist/commands/executor.js +5 -6
  6. package/dist/commands/types.js +5 -5
  7. package/dist/components/App.svelte +4 -4
  8. package/dist/components/NodeSidebar.svelte +4 -4
  9. package/dist/components/NodeSwapPicker.svelte +2 -2
  10. package/dist/components/UniversalNode.svelte +5 -4
  11. package/dist/components/UniversalNode.svelte.d.ts +1 -1
  12. package/dist/components/console/ConsoleInput.svelte +3 -3
  13. package/dist/components/nodes/AtomNode.svelte +3 -3
  14. package/dist/components/nodes/AtomNode.svelte.d.ts +1 -1
  15. package/dist/components/nodes/GatewayNode.svelte +8 -11
  16. package/dist/components/nodes/GatewayNode.svelte.d.ts +1 -1
  17. package/dist/components/nodes/IdeaNode.svelte +10 -8
  18. package/dist/components/nodes/IdeaNode.svelte.d.ts +8 -4
  19. package/dist/components/nodes/NotesNode.svelte +6 -4
  20. package/dist/components/nodes/NotesNode.svelte.d.ts +8 -4
  21. package/dist/components/nodes/SimpleNode.svelte +10 -8
  22. package/dist/components/nodes/SimpleNode.svelte.d.ts +4 -4
  23. package/dist/components/nodes/SquareNode.svelte +10 -8
  24. package/dist/components/nodes/SquareNode.svelte.d.ts +4 -4
  25. package/dist/components/nodes/TerminalNode.svelte +10 -8
  26. package/dist/components/nodes/TerminalNode.svelte.d.ts +4 -4
  27. package/dist/components/nodes/ToolNode.svelte +10 -8
  28. package/dist/components/nodes/ToolNode.svelte.d.ts +6 -6
  29. package/dist/components/nodes/WorkflowNode.svelte +7 -10
  30. package/dist/components/nodes/WorkflowNode.svelte.d.ts +1 -1
  31. package/dist/components/playground/PipelineKanbanView.svelte +2 -2
  32. package/dist/components/playground/PipelineTableView.svelte +2 -2
  33. package/dist/helpers/workflowEditorHelper.js +4 -5
  34. package/dist/registry/nodeComponentRegistry.d.ts +2 -1
  35. package/dist/services/dynamicSchemaService.d.ts +2 -2
  36. package/dist/services/dynamicSchemaService.js +8 -8
  37. package/dist/stores/playgroundStore.svelte.js +1 -1
  38. package/dist/stores/workflowStore.svelte.js +0 -18
  39. package/dist/types/index.d.ts +6 -7
  40. package/dist/utils/connections.js +6 -6
  41. package/dist/utils/nodeIds.d.ts +1 -1
  42. package/dist/utils/nodeIds.js +1 -1
  43. package/dist/utils/nodeSwap.js +3 -6
  44. package/package.json +1 -1
@@ -26,12 +26,12 @@
26
26
  import NodeConfigButton from './NodeConfigButton.svelte';
27
27
  import AlertCircleIcon from '../icons/AlertCircleIcon.svelte';
28
28
 
29
- const props = $props<{
29
+ interface Props {
30
+ id: string;
30
31
  data: {
31
32
  label: string;
32
33
  config: ConfigValues;
33
34
  metadata: NodeMetadata;
34
- nodeId?: string;
35
35
  extensions?: NodeExtensions;
36
36
  onConfigOpen?: (node: {
37
37
  id: string;
@@ -42,7 +42,9 @@
42
42
  selected?: boolean;
43
43
  isProcessing?: boolean;
44
44
  isError?: boolean;
45
- }>();
45
+ }
46
+
47
+ let props: Props = $props();
46
48
 
47
49
  const fd = getInstance();
48
50
  const checker = fd.portCompatibility;
@@ -93,7 +95,7 @@
93
95
  if (props.data.onConfigOpen) {
94
96
  // Create a WorkflowNodeType-like object for the global ConfigSidebar
95
97
  const nodeForConfig = {
96
- id: props.data.nodeId || 'unknown',
98
+ id: props.id,
97
99
  type: 'simple',
98
100
  data: props.data
99
101
  };
@@ -132,7 +134,7 @@
132
134
  hiddenPorts,
133
135
  hideUnconnectedHandles,
134
136
  fd.workflow.connectedHandles,
135
- props.data.nodeId
137
+ props.id
136
138
  )
137
139
  )
138
140
  );
@@ -151,7 +153,7 @@
151
153
  hiddenPorts,
152
154
  hideUnconnectedHandles,
153
155
  fd.workflow.connectedHandles,
154
- props.data.nodeId
156
+ props.id
155
157
  )
156
158
  )
157
159
  );
@@ -179,7 +181,7 @@
179
181
  index,
180
182
  visibleInputPorts.length
181
183
  )}px; transform: translateY(-50%); z-index: 30;"
182
- id={`${props.data.nodeId}-input-${port.id}`}
184
+ id={`${props.id}-input-${port.id}`}
183
185
  />
184
186
  {/each}
185
187
 
@@ -251,7 +253,7 @@
251
253
  index,
252
254
  visibleOutputPorts.length
253
255
  )}px; transform: translateY(-50%); z-index: 30;"
254
- id={`${props.data.nodeId}-output-${port.id}`}
256
+ id={`${props.id}-output-${port.id}`}
255
257
  />
256
258
  {/each}
257
259
 
@@ -1,10 +1,10 @@
1
1
  import type { ConfigValues, NodeMetadata, NodeExtensions } from '../../types/index.js';
2
- type $$ComponentProps = {
2
+ interface Props {
3
+ id: string;
3
4
  data: {
4
5
  label: string;
5
6
  config: ConfigValues;
6
7
  metadata: NodeMetadata;
7
- nodeId?: string;
8
8
  extensions?: NodeExtensions;
9
9
  onConfigOpen?: (node: {
10
10
  id: string;
@@ -19,7 +19,7 @@ type $$ComponentProps = {
19
19
  selected?: boolean;
20
20
  isProcessing?: boolean;
21
21
  isError?: boolean;
22
- };
23
- declare const SimpleNode: import("svelte").Component<$$ComponentProps, {}, "">;
22
+ }
23
+ declare const SimpleNode: import("svelte").Component<Props, {}, "">;
24
24
  type SimpleNode = ReturnType<typeof SimpleNode>;
25
25
  export default SimpleNode;
@@ -27,12 +27,12 @@
27
27
  import NodeConfigButton from './NodeConfigButton.svelte';
28
28
  import AlertCircleIcon from '../icons/AlertCircleIcon.svelte';
29
29
 
30
- const props = $props<{
30
+ interface Props {
31
+ id: string;
31
32
  data: {
32
33
  label: string;
33
34
  config: ConfigValues;
34
35
  metadata: NodeMetadata;
35
- nodeId?: string;
36
36
  extensions?: NodeExtensions;
37
37
  onConfigOpen?: (node: {
38
38
  id: string;
@@ -43,7 +43,9 @@
43
43
  selected?: boolean;
44
44
  isProcessing?: boolean;
45
45
  isError?: boolean;
46
- }>();
46
+ }
47
+
48
+ let props: Props = $props();
47
49
 
48
50
  const fd = getInstance();
49
51
  const checker = fd.portCompatibility;
@@ -84,7 +86,7 @@
84
86
  if (props.data.onConfigOpen) {
85
87
  // Create a WorkflowNodeType-like object for the global ConfigSidebar
86
88
  const nodeForConfig = {
87
- id: props.data.nodeId || 'unknown',
89
+ id: props.id,
88
90
  type: 'square',
89
91
  data: props.data
90
92
  };
@@ -128,7 +130,7 @@
128
130
  hiddenPorts,
129
131
  hideUnconnectedHandles,
130
132
  fd.workflow.connectedHandles,
131
- props.data.nodeId
133
+ props.id
132
134
  )
133
135
  )
134
136
  );
@@ -147,7 +149,7 @@
147
149
  hiddenPorts,
148
150
  hideUnconnectedHandles,
149
151
  fd.workflow.connectedHandles,
150
- props.data.nodeId
152
+ props.id
151
153
  )
152
154
  )
153
155
  );
@@ -176,7 +178,7 @@
176
178
  index,
177
179
  visibleInputPorts.length
178
180
  )}px; transform: translateY(-50%); z-index: 30;"
179
- id={`${props.data.nodeId}-input-${port.id}`}
181
+ id={`${props.id}-input-${port.id}`}
180
182
  />
181
183
  {/each}
182
184
 
@@ -242,7 +244,7 @@
242
244
  index,
243
245
  visibleOutputPorts.length
244
246
  )}px; transform: translateY(-50%); z-index: 30;"
245
- id={`${props.data.nodeId}-output-${port.id}`}
247
+ id={`${props.id}-output-${port.id}`}
246
248
  />
247
249
  {/each}
248
250
 
@@ -1,10 +1,10 @@
1
1
  import type { ConfigValues, NodeMetadata, NodeExtensions } from '../../types/index.js';
2
- type $$ComponentProps = {
2
+ interface Props {
3
+ id: string;
3
4
  data: {
4
5
  label: string;
5
6
  config: ConfigValues;
6
7
  metadata: NodeMetadata;
7
- nodeId?: string;
8
8
  extensions?: NodeExtensions;
9
9
  onConfigOpen?: (node: {
10
10
  id: string;
@@ -19,7 +19,7 @@ type $$ComponentProps = {
19
19
  selected?: boolean;
20
20
  isProcessing?: boolean;
21
21
  isError?: boolean;
22
- };
23
- declare const SquareNode: import("svelte").Component<$$ComponentProps, {}, "">;
22
+ }
23
+ declare const SquareNode: import("svelte").Component<Props, {}, "">;
24
24
  type SquareNode = ReturnType<typeof SquareNode>;
25
25
  export default SquareNode;
@@ -66,12 +66,12 @@
66
66
  }
67
67
  };
68
68
 
69
- const props = $props<{
69
+ interface Props {
70
+ id: string;
70
71
  data: {
71
72
  label: string;
72
73
  config: ConfigValues;
73
74
  metadata: NodeMetadata;
74
- nodeId?: string;
75
75
  extensions?: NodeExtensions;
76
76
  onConfigOpen?: (node: {
77
77
  id: string;
@@ -82,7 +82,9 @@
82
82
  selected?: boolean;
83
83
  isProcessing?: boolean;
84
84
  isError?: boolean;
85
- }>();
85
+ }
86
+
87
+ let props: Props = $props();
86
88
 
87
89
  const fd = getInstance();
88
90
  const checker = fd.portCompatibility;
@@ -111,7 +113,7 @@
111
113
  }
112
114
 
113
115
  // Check metadata id/name for hints
114
- const idLower = (props.data.metadata?.id || '').toLowerCase();
116
+ const idLower = (props.data.metadata?.node_type_id || '').toLowerCase();
115
117
  const nameLower = (props.data.metadata?.name || '').toLowerCase();
116
118
  if (idLower.includes('start') || nameLower.includes('start')) {
117
119
  return 'start';
@@ -159,7 +161,7 @@
159
161
  if (port.required) {
160
162
  return true;
161
163
  }
162
- const handleId = `${props.data.nodeId}-${type}-${port.id}`;
164
+ const handleId = `${props.id}-${type}-${port.id}`;
163
165
  return fd.workflow.connectedHandles.has(handleId);
164
166
  }
165
167
 
@@ -298,7 +300,7 @@
298
300
  function openConfigSidebar(): void {
299
301
  if (props.data.onConfigOpen) {
300
302
  const nodeForConfig = {
301
- id: props.data.nodeId || 'unknown',
303
+ id: props.id,
302
304
  type: 'terminal',
303
305
  data: props.data
304
306
  };
@@ -346,7 +348,7 @@
346
348
  checker,
347
349
  port.dataType
348
350
  )}; --fd-handle-border-color: var(--fd-handle-border); left: {pos.left}px; top: {pos.top}px; transform: translate(-50%, -50%); z-index: 30;"
349
- id={`${props.data.nodeId}-input-${port.id}`}
351
+ id={`${props.id}-input-${port.id}`}
350
352
  />
351
353
  {/each}
352
354
  {/if}
@@ -365,7 +367,7 @@
365
367
  <Handle
366
368
  type="source"
367
369
  position={Position.Right}
368
- id={`${props.data.nodeId}-output-${port.id}`}
370
+ id={`${props.id}-output-${port.id}`}
369
371
  style="--fd-handle-fill: {getDataTypeColor(
370
372
  checker,
371
373
  port.dataType
@@ -1,10 +1,10 @@
1
1
  import type { ConfigValues, NodeMetadata, NodeExtensions } from '../../types/index.js';
2
- type $$ComponentProps = {
2
+ interface Props {
3
+ id: string;
3
4
  data: {
4
5
  label: string;
5
6
  config: ConfigValues;
6
7
  metadata: NodeMetadata;
7
- nodeId?: string;
8
8
  extensions?: NodeExtensions;
9
9
  onConfigOpen?: (node: {
10
10
  id: string;
@@ -19,7 +19,7 @@ type $$ComponentProps = {
19
19
  selected?: boolean;
20
20
  isProcessing?: boolean;
21
21
  isError?: boolean;
22
- };
23
- declare const TerminalNode: import("svelte").Component<$$ComponentProps, {}, "">;
22
+ }
23
+ declare const TerminalNode: import("svelte").Component<Props, {}, "">;
24
24
  type TerminalNode = ReturnType<typeof TerminalNode>;
25
25
  export default TerminalNode;
@@ -9,7 +9,7 @@
9
9
  import Icon from '@iconify/svelte';
10
10
  import { getDataTypeColor, getCategoryColorToken } from '../../utils/colors';
11
11
  import { getInstance } from '../../stores/getInstance.svelte.js';
12
- import type { NodeMetadata, NodePort } from '../../types/index.js';
12
+ import type { ConfigValues, NodeMetadata, NodePort } from '../../types/index.js';
13
13
  import NodeConfigButton from './NodeConfigButton.svelte';
14
14
  import AlertCircleIcon from '../icons/AlertCircleIcon.svelte';
15
15
 
@@ -19,10 +19,11 @@
19
19
  description?: string;
20
20
  }
21
21
 
22
- const props = $props<{
22
+ interface Props {
23
+ id: string;
23
24
  data: {
24
25
  label: string;
25
- config: {
26
+ config: ConfigValues & {
26
27
  icon?: string;
27
28
  color?: string;
28
29
  toolName?: string;
@@ -31,7 +32,6 @@
31
32
  parameters?: ToolNodeParameter[];
32
33
  };
33
34
  metadata: NodeMetadata;
34
- nodeId?: string;
35
35
  onConfigOpen?: (node: {
36
36
  id: string;
37
37
  type: string;
@@ -45,7 +45,9 @@
45
45
  selected?: boolean;
46
46
  isProcessing?: boolean;
47
47
  isError?: boolean;
48
- }>();
48
+ }
49
+
50
+ let props: Props = $props();
49
51
 
50
52
  const fd = getInstance();
51
53
  const checker = fd.portCompatibility;
@@ -142,7 +144,7 @@
142
144
  if (props.data.onConfigOpen) {
143
145
  // Create a WorkflowNodeType-like object for the global ConfigSidebar
144
146
  const nodeForConfig = {
145
- id: props.data.nodeId || 'unknown',
147
+ id: props.id,
146
148
  type: 'tool',
147
149
  data: props.data
148
150
  };
@@ -163,7 +165,7 @@
163
165
  <Handle
164
166
  type="target"
165
167
  position={Position.Left}
166
- id={`${props.data.nodeId}-input-${toolInputPort.id}`}
168
+ id={`${props.id}-input-${toolInputPort.id}`}
167
169
  style="top: {firstPortTop}px; transform: translateY(-50%); z-index: 30; --fd-handle-fill: var(--fd-port-skin-color, {getDataTypeColor(
168
170
  checker,
169
171
  portDataType
@@ -239,7 +241,7 @@
239
241
  <Handle
240
242
  type="source"
241
243
  position={Position.Right}
242
- id={`${props.data.nodeId}-output-${toolOutputPort.id}`}
244
+ id={`${props.id}-output-${toolOutputPort.id}`}
243
245
  style="top: {firstPortTop}px; transform: translateY(-50%); z-index: 30; --fd-handle-fill: var(--fd-port-skin-color, {getDataTypeColor(
244
246
  checker,
245
247
  portDataType
@@ -1,13 +1,14 @@
1
- import type { NodeMetadata } from '../../types/index.js';
1
+ import type { ConfigValues, NodeMetadata } from '../../types/index.js';
2
2
  interface ToolNodeParameter {
3
3
  name: string;
4
4
  type?: string;
5
5
  description?: string;
6
6
  }
7
- type $$ComponentProps = {
7
+ interface Props {
8
+ id: string;
8
9
  data: {
9
10
  label: string;
10
- config: {
11
+ config: ConfigValues & {
11
12
  icon?: string;
12
13
  color?: string;
13
14
  toolName?: string;
@@ -16,7 +17,6 @@ type $$ComponentProps = {
16
17
  parameters?: ToolNodeParameter[];
17
18
  };
18
19
  metadata: NodeMetadata;
19
- nodeId?: string;
20
20
  onConfigOpen?: (node: {
21
21
  id: string;
22
22
  type: string;
@@ -30,7 +30,7 @@ type $$ComponentProps = {
30
30
  selected?: boolean;
31
31
  isProcessing?: boolean;
32
32
  isError?: boolean;
33
- };
34
- declare const ToolNode: import("svelte").Component<$$ComponentProps, {}, "">;
33
+ }
34
+ declare const ToolNode: import("svelte").Component<Props, {}, "">;
35
35
  type ToolNode = ReturnType<typeof ToolNode>;
36
36
  export default ToolNode;
@@ -27,8 +27,8 @@
27
27
  import { m } from '../../messages/index.js';
28
28
 
29
29
  interface Props {
30
+ id: string;
30
31
  data: WorkflowNode['data'] & {
31
- nodeId?: string;
32
32
  onConfigOpen?: (node: { id: string; type: string; data: WorkflowNode['data'] }) => void;
33
33
  };
34
34
  selected?: boolean;
@@ -147,7 +147,7 @@
147
147
  }
148
148
 
149
149
  // Check if port is connected
150
- const handleId = `${props.data.nodeId}-${type}-${port.id}`;
150
+ const handleId = `${props.id}-${type}-${port.id}`;
151
151
  return fd.workflow.connectedHandles.has(handleId);
152
152
  }
153
153
 
@@ -179,7 +179,7 @@
179
179
  if (props.data.onConfigOpen) {
180
180
  // Create a WorkflowNodeType-like object for the global ConfigSidebar
181
181
  const nodeForConfig = {
182
- id: props.data.nodeId || 'unknown',
182
+ id: props.id,
183
183
  type: 'workflowNode',
184
184
  data: props.data
185
185
  };
@@ -201,7 +201,7 @@
201
201
  }}
202
202
  data-handle-interaction={isHandleInteraction}
203
203
  aria-label={graph.workflowNode({ name: props.data.metadata.name })}
204
- aria-describedby="node-description-{props.data.nodeId || 'unknown'}"
204
+ aria-describedby="node-description-{props.id}"
205
205
  >
206
206
  <!-- Default Node Header: expands in multiples of 10 (title row 40px + gap 10px + description 20px per line) -->
207
207
  <div class="flowdrop-workflow-node__header">
@@ -231,10 +231,7 @@
231
231
  <div class="flowdrop-flex flowdrop-gap--2 flowdrop-items--center"></div>
232
232
  </div>
233
233
  <!-- Node Description - line-height 20px so header grows in steps of 10 -->
234
- <p
235
- class="flowdrop-workflow-node__header-desc"
236
- id="node-description-{props.data.nodeId || 'unknown'}"
237
- >
234
+ <p class="flowdrop-workflow-node__header-desc" id="node-description-{props.id}">
238
235
  {displayDescription}
239
236
  </p>
240
237
  </div>
@@ -249,7 +246,7 @@
249
246
  <Handle
250
247
  type="target"
251
248
  position={Position.Left}
252
- id={`${props.data.nodeId}-input-${port.id}`}
249
+ id={`${props.id}-input-${port.id}`}
253
250
  class="flowdrop-workflow-node__handle"
254
251
  style="top: var(--fd-node-port-row-height); transform: translateY(-50%); --fd-handle-fill: var(--fd-port-skin-color, {getDataTypeColorToken(
255
252
  checker,
@@ -330,7 +327,7 @@
330
327
  <Handle
331
328
  type="source"
332
329
  position={Position.Right}
333
- id={`${props.data.nodeId}-output-${port.id}`}
330
+ id={`${props.id}-output-${port.id}`}
334
331
  class="flowdrop-workflow-node__handle"
335
332
  style="top: var(--fd-node-port-row-height); transform: translateY(-50%); --fd-handle-fill: var(--fd-port-skin-color, {getDataTypeColorToken(
336
333
  checker,
@@ -1,7 +1,7 @@
1
1
  import type { WorkflowNode } from '../../types/index.js';
2
2
  interface Props {
3
+ id: string;
3
4
  data: WorkflowNode['data'] & {
4
- nodeId?: string;
5
5
  onConfigOpen?: (node: {
6
6
  id: string;
7
7
  type: string;
@@ -108,7 +108,7 @@
108
108
  nodesByColumn.get(colKey)?.push({
109
109
  key: job.id,
110
110
  label: job.label || node.data.label,
111
- typeId: node.data.metadata.id,
111
+ typeId: node.data.metadata.node_type_id,
112
112
  status,
113
113
  durationUs: job.executionTimeUs
114
114
  });
@@ -122,7 +122,7 @@
122
122
  nodesByColumn.get(colKey)?.push({
123
123
  key: node.id,
124
124
  label: node.data.label,
125
- typeId: node.data.metadata.id,
125
+ typeId: node.data.metadata.node_type_id,
126
126
  status
127
127
  });
128
128
  }
@@ -111,7 +111,7 @@
111
111
  jobRows.push({
112
112
  key: job.id,
113
113
  label: job.label || node.data.label,
114
- typeId: node.data.metadata.id,
114
+ typeId: node.data.metadata.node_type_id,
115
115
  nodeId: job.nodeId,
116
116
  status: resolveStatus({ status: job.status }),
117
117
  started: job.started,
@@ -137,7 +137,7 @@
137
137
  return {
138
138
  key: node.id,
139
139
  label: node.data.label,
140
- typeId: node.data.metadata.id,
140
+ typeId: node.data.metadata.node_type_id,
141
141
  nodeId: node.id,
142
142
  status: resolveStatus(statusData),
143
143
  started: statusData?.last_executed,
@@ -63,7 +63,7 @@ export class NodeOperationsHelper {
63
63
  // Use fallback sample nodes
64
64
  return [
65
65
  {
66
- id: 'text-input',
66
+ node_type_id: 'text-input',
67
67
  name: 'Text Input',
68
68
  category: 'inputs',
69
69
  description: 'Simple text input field',
@@ -73,7 +73,7 @@ export class NodeOperationsHelper {
73
73
  outputs: [{ id: 'text', name: 'text', type: 'output', dataType: 'string' }]
74
74
  },
75
75
  {
76
- id: 'text-output',
76
+ node_type_id: 'text-output',
77
77
  name: 'Text Output',
78
78
  category: 'outputs',
79
79
  description: 'Display text output',
@@ -128,7 +128,7 @@ export class NodeOperationsHelper {
128
128
  };
129
129
  }
130
130
  // Generate node ID based on node type and existing nodes
131
- const newNodeId = generateNodeId(nodeType.id, existingNodes);
131
+ const newNodeId = generateNodeId(nodeType.node_type_id, existingNodes);
132
132
  // All nodes use "universalNode" type
133
133
  // UniversalNode component handles internal switching based on metadata and config
134
134
  const newNode = {
@@ -137,8 +137,7 @@ export class NodeOperationsHelper {
137
137
  position, // Use the position calculated from the drop event
138
138
  deletable: true,
139
139
  data: {
140
- ...nodeData,
141
- nodeId: newNodeId // Use the same ID
140
+ ...nodeData
142
141
  }
143
142
  };
144
143
  return newNode;
@@ -16,9 +16,10 @@ import { BaseRegistry } from './BaseRegistry.svelte.js';
16
16
  * Any component registered in the registry must be compatible with these props.
17
17
  */
18
18
  export interface NodeComponentProps {
19
+ /** The SvelteFlow node id */
20
+ id: string;
19
21
  /** Node data containing label, config, metadata, executionInfo */
20
22
  data: WorkflowNode['data'] & {
21
- nodeId?: string;
22
23
  onConfigOpen?: (node: {
23
24
  id: string;
24
25
  type: string;
@@ -33,7 +33,7 @@ export interface DynamicSchemaResult {
33
33
  * const endpoint: DynamicSchemaEndpoint = {
34
34
  * url: "/api/nodes/{nodeTypeId}/schema",
35
35
  * method: "GET",
36
- * parameterMapping: { nodeTypeId: "metadata.id" }
36
+ * parameterMapping: { nodeTypeId: "metadata.node_type_id" }
37
37
  * };
38
38
  *
39
39
  * const result = await fetchDynamicSchema(endpoint, node);
@@ -56,7 +56,7 @@ export declare function fetchDynamicSchema(endpointConfig: EndpointConfig | null
56
56
  * ```typescript
57
57
  * const link: ExternalEditLink = {
58
58
  * url: "https://admin.example.com/nodes/{nodeTypeId}/edit/{instanceId}",
59
- * parameterMapping: { nodeTypeId: "metadata.id", instanceId: "id" }
59
+ * parameterMapping: { nodeTypeId: "metadata.node_type_id", instanceId: "id" }
60
60
  * };
61
61
  *
62
62
  * const url = resolveExternalEditUrl(link, node, workflowId);
@@ -15,16 +15,16 @@ const schemaCache = new Map();
15
15
  const DEFAULT_CACHE_TTL = DEFAULT_CACHE_TTL_MS;
16
16
  /**
17
17
  * Resolves a template variable path from the node context.
18
- * Supports dot-notation paths like "metadata.id", "config.apiKey", "id"
18
+ * Supports dot-notation paths like "metadata.node_type_id", "config.apiKey", "id"
19
19
  *
20
20
  * @param context - The node context containing all available data
21
- * @param path - Dot-notation path to resolve (e.g., "metadata.id")
21
+ * @param path - Dot-notation path to resolve (e.g., "metadata.node_type_id")
22
22
  * @returns The resolved value as a string, or undefined if not found
23
23
  *
24
24
  * @example
25
25
  * ```typescript
26
- * const context = { id: "node-1", metadata: { id: "llm-node" } };
27
- * resolveVariablePath(context, "metadata.id"); // Returns "llm-node"
26
+ * const context = { id: "node-1", metadata: { node_type_id: "llm-node" } };
27
+ * resolveVariablePath(context, "metadata.node_type_id"); // Returns "llm-node"
28
28
  * resolveVariablePath(context, "id"); // Returns "node-1"
29
29
  * ```
30
30
  */
@@ -60,8 +60,8 @@ function resolveVariablePath(context, path) {
60
60
  * @example
61
61
  * ```typescript
62
62
  * const url = "/api/nodes/{nodeTypeId}/schema?instance={instanceId}";
63
- * const mapping = { nodeTypeId: "metadata.id", instanceId: "id" };
64
- * const context = { id: "node-1", metadata: { id: "llm-node" } };
63
+ * const mapping = { nodeTypeId: "metadata.node_type_id", instanceId: "id" };
64
+ * const context = { id: "node-1", metadata: { node_type_id: "llm-node" } };
65
65
  * resolveTemplate(url, mapping, context);
66
66
  * // Returns "/api/nodes/llm-node/schema?instance=node-1"
67
67
  * ```
@@ -127,7 +127,7 @@ function isCacheValid(entry, ttl = DEFAULT_CACHE_TTL) {
127
127
  * const endpoint: DynamicSchemaEndpoint = {
128
128
  * url: "/api/nodes/{nodeTypeId}/schema",
129
129
  * method: "GET",
130
- * parameterMapping: { nodeTypeId: "metadata.id" }
130
+ * parameterMapping: { nodeTypeId: "metadata.node_type_id" }
131
131
  * };
132
132
  *
133
133
  * const result = await fetchDynamicSchema(endpoint, node);
@@ -279,7 +279,7 @@ export async function fetchDynamicSchema(endpointConfig, endpoint, node, workflo
279
279
  * ```typescript
280
280
  * const link: ExternalEditLink = {
281
281
  * url: "https://admin.example.com/nodes/{nodeTypeId}/edit/{instanceId}",
282
- * parameterMapping: { nodeTypeId: "metadata.id", instanceId: "id" }
282
+ * parameterMapping: { nodeTypeId: "metadata.node_type_id", instanceId: "id" }
283
283
  * };
284
284
  *
285
285
  * const url = resolveExternalEditUrl(link, node, workflowId);
@@ -212,7 +212,7 @@ export class PlaygroundStore {
212
212
  // Find input nodes in the workflow
213
213
  workflow.nodes.forEach((node) => {
214
214
  const category = node.data.metadata?.category;
215
- const nodeTypeId = node.data.metadata?.id ?? node.type;
215
+ const nodeTypeId = node.data.metadata?.node_type_id ?? node.type;
216
216
  // Check if this is an input-type node
217
217
  // The category can be "inputs" (standard) or variations like "input"
218
218
  const categoryStr = String(category || '');
@@ -94,23 +94,6 @@ function hasWorkflowDataChanged(currentWorkflow, newNodes, newEdges) {
94
94
  }
95
95
  return false;
96
96
  }
97
- /**
98
- * Heal nodes that are missing `data.nodeId`.
99
- *
100
- * Node components derive their handle IDs from `data.nodeId` — a node without
101
- * it renders with zero handles and SvelteFlow silently drops every edge
102
- * anchored to it, making an intact graph look corrupted on the canvas.
103
- * `data.nodeId` always equals the node's own `id`, so it is safe to restore.
104
- */
105
- function healMissingNodeIds(workflow) {
106
- if (!workflow.nodes?.some((node) => !node.data.nodeId)) {
107
- return workflow;
108
- }
109
- return {
110
- ...workflow,
111
- nodes: workflow.nodes.map((node) => node.data.nodeId ? node : { ...node, data: { ...node.data, nodeId: node.id } })
112
- };
113
- }
114
97
  // =========================================================================
115
98
  // WorkflowStore (per-instance reactive state)
116
99
  // =========================================================================
@@ -373,7 +356,6 @@ export class WorkflowStore {
373
356
  */
374
357
  initialize(workflow) {
375
358
  workflow = normalizeWorkflowMetadata(workflow);
376
- workflow = healMissingNodeIds(workflow);
377
359
  this.#workflow = workflow;
378
360
  // Reset version counters — workflow is "clean" after initialization
379
361
  this.#editVersion = 0;