@flowdrop/flowdrop 1.15.0 → 2.0.0-beta.2

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 (235) hide show
  1. package/CHANGELOG.md +508 -0
  2. package/MIGRATION-2.0.md +629 -0
  3. package/README.md +23 -23
  4. package/dist/adapters/WorkflowAdapter.d.ts +1 -1
  5. package/dist/adapters/WorkflowAdapter.js +14 -8
  6. package/dist/adapters/agentspec/AgentSpecAdapter.js +7 -7
  7. package/dist/api/enhanced-client.js +6 -11
  8. package/dist/chat/batchFeedback.d.ts +39 -0
  9. package/dist/chat/batchFeedback.js +51 -0
  10. package/dist/commands/executor.js +15 -1
  11. package/dist/commands/storeIntegration.svelte.d.ts +4 -1
  12. package/dist/commands/storeIntegration.svelte.js +26 -21
  13. package/dist/commands/types.d.ts +2 -0
  14. package/dist/components/App.svelte +163 -192
  15. package/dist/components/App.svelte.d.ts +47 -8
  16. package/dist/components/ConfigForm.svelte +77 -49
  17. package/dist/components/ConfigModal.svelte +7 -2
  18. package/dist/components/ConnectionLine.svelte +4 -2
  19. package/dist/components/Navbar.svelte +61 -1
  20. package/dist/components/NodeSidebar.svelte +27 -45
  21. package/dist/components/NodeStatusOverlay.svelte +94 -6
  22. package/dist/components/NodeSwapPicker.svelte +10 -8
  23. package/dist/components/PipelineStatus.svelte +22 -68
  24. package/dist/components/PipelineStatus.svelte.d.ts +3 -0
  25. package/dist/components/PortCoordinateTracker.svelte +5 -6
  26. package/dist/components/SchemaForm.stories.svelte +1 -3
  27. package/dist/components/SchemaForm.svelte +22 -27
  28. package/dist/components/SchemaForm.svelte.d.ts +0 -8
  29. package/dist/components/SettingsModal.svelte +8 -3
  30. package/dist/components/SettingsPanel.svelte +20 -4
  31. package/dist/components/SwapMappingEditor.svelte +67 -49
  32. package/dist/components/SwapMappingEditor.svelte.d.ts +0 -2
  33. package/dist/components/UniversalNode.svelte +9 -7
  34. package/dist/components/WorkflowEditor.svelte +121 -111
  35. package/dist/components/WorkflowEditor.svelte.d.ts +21 -10
  36. package/dist/components/chat/AIChatPanel.svelte +98 -89
  37. package/dist/components/chat/AIChatPanel.svelte.d.ts +0 -4
  38. package/dist/components/chat/CommandPreview.svelte +2 -1
  39. package/dist/components/console/CommandConsole.svelte +7 -5
  40. package/dist/components/console/ConsoleAutocomplete.svelte +10 -11
  41. package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +6 -0
  42. package/dist/components/console/ConsoleInput.svelte +15 -6
  43. package/dist/components/console/ConsoleOutput.svelte +2 -1
  44. package/dist/components/form/FormArray.svelte +5 -9
  45. package/dist/components/form/FormArray.svelte.d.ts +2 -1
  46. package/dist/components/form/FormAutocomplete.svelte +16 -15
  47. package/dist/components/form/FormField.svelte +4 -2
  48. package/dist/components/form/FormFieldLight.svelte +34 -3
  49. package/dist/components/form/FormFieldLight.svelte.d.ts +12 -0
  50. package/dist/components/form/FormMarkdownEditor.svelte +9 -4
  51. package/dist/components/form/FormRangeField.svelte +1 -0
  52. package/dist/components/form/FormTemplateEditor.svelte +11 -3
  53. package/dist/components/form/FormToggle.svelte +5 -12
  54. package/dist/components/form/FormToggle.svelte.d.ts +4 -2
  55. package/dist/components/form/FormUISchemaRenderer.svelte +3 -1
  56. package/dist/components/form/templateAutocomplete.js +1 -5
  57. package/dist/components/form/types.d.ts +1 -14
  58. package/dist/components/interrupt/FormPrompt.svelte +3 -2
  59. package/dist/components/interrupt/InterruptBubble.svelte +25 -17
  60. package/dist/components/interrupt/ReviewPrompt.svelte +10 -3
  61. package/dist/components/interrupt/TextInputPrompt.svelte +2 -1
  62. package/dist/components/layouts/MainLayout.svelte +20 -13
  63. package/dist/components/layouts/MainLayout.svelte.d.ts +4 -0
  64. package/dist/components/nodes/AtomNode.svelte +17 -5
  65. package/dist/components/nodes/GatewayNode.svelte +19 -10
  66. package/dist/components/nodes/IdeaNode.svelte +7 -0
  67. package/dist/components/nodes/SimpleNode.svelte +11 -6
  68. package/dist/components/nodes/SquareNode.svelte +15 -8
  69. package/dist/components/nodes/TerminalNode.svelte +9 -4
  70. package/dist/components/nodes/ToolNode.svelte +7 -1
  71. package/dist/components/nodes/WorkflowNode.svelte +16 -7
  72. package/dist/components/playground/ChatInput.svelte +11 -14
  73. package/dist/components/playground/ChatPanel.svelte +6 -49
  74. package/dist/components/playground/ChatPanel.svelte.d.ts +0 -14
  75. package/dist/components/playground/ControlPanel.svelte +134 -123
  76. package/dist/components/playground/ControlPanel.svelte.d.ts +3 -0
  77. package/dist/components/playground/ExecutionLogs.svelte +11 -9
  78. package/dist/components/playground/InputCollector.svelte +11 -9
  79. package/dist/components/playground/MessageStream.svelte +17 -23
  80. package/dist/components/playground/PipelineKanbanView.svelte +69 -8
  81. package/dist/components/playground/PipelineKanbanView.svelte.d.ts +2 -0
  82. package/dist/components/playground/PipelinePanel.svelte +31 -8
  83. package/dist/components/playground/PipelinePanel.svelte.d.ts +2 -0
  84. package/dist/components/playground/PipelineTableView.svelte +188 -44
  85. package/dist/components/playground/PipelineTableView.svelte.d.ts +2 -0
  86. package/dist/components/playground/Playground.svelte +154 -105
  87. package/dist/components/playground/Playground.svelte.d.ts +5 -0
  88. package/dist/components/playground/PlaygroundApp.svelte +11 -1
  89. package/dist/components/playground/PlaygroundApp.svelte.d.ts +6 -0
  90. package/dist/components/playground/PlaygroundModal.svelte +18 -3
  91. package/dist/components/playground/PlaygroundModal.svelte.d.ts +6 -0
  92. package/dist/components/playground/PlaygroundStudio.svelte +40 -32
  93. package/dist/components/playground/PlaygroundStudio.svelte.d.ts +6 -0
  94. package/dist/components/playground/SessionManager.svelte +9 -12
  95. package/dist/components/playground/pipelineViewUtils.svelte.d.ts +30 -1
  96. package/dist/components/playground/pipelineViewUtils.svelte.js +40 -3
  97. package/dist/config/endpoints.d.ts +23 -7
  98. package/dist/config/endpoints.js +30 -10
  99. package/dist/core/index.d.ts +5 -6
  100. package/dist/core/index.js +8 -12
  101. package/dist/display/index.d.ts +6 -3
  102. package/dist/display/index.js +7 -5
  103. package/dist/editor/index.d.ts +20 -21
  104. package/dist/editor/index.js +26 -36
  105. package/dist/form/code.d.ts +25 -15
  106. package/dist/form/code.js +44 -41
  107. package/dist/form/fieldRegistry.d.ts +17 -13
  108. package/dist/form/fieldRegistry.js +32 -12
  109. package/dist/form/full.d.ts +19 -14
  110. package/dist/form/full.js +26 -28
  111. package/dist/form/index.d.ts +3 -4
  112. package/dist/form/index.js +6 -5
  113. package/dist/form/markdown.d.ts +13 -8
  114. package/dist/form/markdown.js +22 -23
  115. package/dist/helpers/proximityConnect.d.ts +3 -2
  116. package/dist/helpers/proximityConnect.js +2 -5
  117. package/dist/helpers/workflowEditorHelper.d.ts +14 -5
  118. package/dist/helpers/workflowEditorHelper.js +28 -25
  119. package/dist/index.d.ts +28 -24
  120. package/dist/index.js +27 -50
  121. package/dist/messages/defaults.d.ts +2 -5
  122. package/dist/messages/defaults.js +3 -6
  123. package/dist/messages/index.d.ts +0 -1
  124. package/dist/messages/index.js +0 -1
  125. package/dist/mocks/app-forms.d.ts +6 -2
  126. package/dist/mocks/app-forms.js +11 -4
  127. package/dist/openapi/v1/openapi.yaml +3 -3
  128. package/dist/playground/index.d.ts +4 -5
  129. package/dist/playground/index.js +4 -32
  130. package/dist/playground/mount.d.ts +25 -0
  131. package/dist/playground/mount.js +50 -20
  132. package/dist/registry/{BaseRegistry.d.ts → BaseRegistry.svelte.d.ts} +22 -1
  133. package/dist/registry/{BaseRegistry.js → BaseRegistry.svelte.js} +37 -1
  134. package/dist/registry/builtinFormats.d.ts +9 -18
  135. package/dist/registry/builtinFormats.js +9 -39
  136. package/dist/registry/builtinNodeTypes.d.ts +53 -0
  137. package/dist/registry/builtinNodeTypes.js +67 -0
  138. package/dist/registry/builtinNodes.d.ts +2 -64
  139. package/dist/registry/builtinNodes.js +7 -103
  140. package/dist/registry/index.d.ts +3 -4
  141. package/dist/registry/index.js +4 -6
  142. package/dist/registry/nodeComponentRegistry.d.ts +182 -15
  143. package/dist/registry/nodeComponentRegistry.js +235 -17
  144. package/dist/registry/workflowFormatRegistry.d.ts +14 -9
  145. package/dist/registry/workflowFormatRegistry.js +24 -8
  146. package/dist/{schema → schemas}/index.d.ts +2 -2
  147. package/dist/{schema → schemas}/index.js +2 -2
  148. package/dist/schemas/v1/workflow.schema.json +3 -3
  149. package/dist/services/agentSpecExecutionService.d.ts +0 -2
  150. package/dist/services/agentSpecExecutionService.js +0 -3
  151. package/dist/services/apiVariableService.d.ts +2 -1
  152. package/dist/services/apiVariableService.js +16 -47
  153. package/dist/services/autoSaveService.d.ts +7 -0
  154. package/dist/services/autoSaveService.js +6 -4
  155. package/dist/services/categoriesApi.js +3 -6
  156. package/dist/services/chatService.d.ts +9 -4
  157. package/dist/services/chatService.js +23 -28
  158. package/dist/services/draftStorage.d.ts +129 -13
  159. package/dist/services/draftStorage.js +185 -37
  160. package/dist/services/dynamicSchemaService.d.ts +2 -1
  161. package/dist/services/dynamicSchemaService.js +5 -22
  162. package/dist/services/globalSave.d.ts +13 -12
  163. package/dist/services/globalSave.js +29 -51
  164. package/dist/services/historyService.d.ts +9 -3
  165. package/dist/services/historyService.js +9 -3
  166. package/dist/services/interruptService.d.ts +15 -9
  167. package/dist/services/interruptService.js +35 -37
  168. package/dist/services/nodeExecutionService.d.ts +18 -3
  169. package/dist/services/nodeExecutionService.js +71 -45
  170. package/dist/services/playgroundService.d.ts +16 -10
  171. package/dist/services/playgroundService.js +42 -43
  172. package/dist/services/portConfigApi.js +3 -6
  173. package/dist/services/settingsService.d.ts +9 -4
  174. package/dist/services/settingsService.js +23 -12
  175. package/dist/services/variableService.d.ts +2 -1
  176. package/dist/services/variableService.js +2 -2
  177. package/dist/services/workflowStorage.js +6 -6
  178. package/dist/stores/apiContext.d.ts +56 -0
  179. package/dist/stores/apiContext.js +80 -0
  180. package/dist/stores/categoriesStore.svelte.d.ts +28 -23
  181. package/dist/stores/categoriesStore.svelte.js +69 -64
  182. package/dist/stores/getInstance.svelte.d.ts +39 -0
  183. package/dist/stores/getInstance.svelte.js +65 -0
  184. package/dist/stores/historyStore.svelte.d.ts +77 -93
  185. package/dist/stores/historyStore.svelte.js +134 -160
  186. package/dist/stores/instanceContainer.svelte.d.ts +111 -0
  187. package/dist/stores/instanceContainer.svelte.js +114 -0
  188. package/dist/stores/interruptStore.svelte.d.ts +112 -82
  189. package/dist/stores/interruptStore.svelte.js +253 -226
  190. package/dist/stores/pipelinePanelStore.svelte.d.ts +27 -3
  191. package/dist/stores/pipelinePanelStore.svelte.js +61 -14
  192. package/dist/stores/playgroundStore.svelte.d.ts +169 -222
  193. package/dist/stores/playgroundStore.svelte.js +513 -580
  194. package/dist/stores/portCoordinateStore.svelte.d.ts +57 -51
  195. package/dist/stores/portCoordinateStore.svelte.js +109 -98
  196. package/dist/stores/settingsStore.svelte.d.ts +4 -1
  197. package/dist/stores/settingsStore.svelte.js +47 -12
  198. package/dist/stores/workflowStore.svelte.d.ts +178 -213
  199. package/dist/stores/workflowStore.svelte.js +449 -501
  200. package/dist/stories/EdgeDecorator.svelte +5 -2
  201. package/dist/stories/NodeDecorator.svelte +5 -3
  202. package/dist/svelte-app.d.ts +60 -10
  203. package/dist/svelte-app.js +159 -54
  204. package/dist/types/auth.d.ts +9 -51
  205. package/dist/types/auth.js +4 -54
  206. package/dist/types/events.d.ts +6 -3
  207. package/dist/types/index.d.ts +37 -5
  208. package/dist/types/index.js +0 -1
  209. package/dist/types/navbar.d.ts +7 -0
  210. package/dist/types/playground.d.ts +18 -3
  211. package/dist/types/settings.d.ts +13 -0
  212. package/dist/types/settings.js +1 -0
  213. package/dist/utils/colors.d.ts +47 -21
  214. package/dist/utils/colors.js +69 -68
  215. package/dist/utils/connections.d.ts +9 -15
  216. package/dist/utils/connections.js +13 -32
  217. package/dist/utils/duration.d.ts +13 -0
  218. package/dist/utils/duration.js +45 -0
  219. package/dist/utils/edgeStyling.js +9 -5
  220. package/dist/utils/fetchWithAuth.d.ts +36 -15
  221. package/dist/utils/fetchWithAuth.js +53 -23
  222. package/dist/utils/icons.d.ts +5 -2
  223. package/dist/utils/icons.js +6 -5
  224. package/dist/utils/nodeSwap.d.ts +6 -2
  225. package/dist/utils/nodeSwap.js +62 -126
  226. package/dist/utils/nodeTypes.d.ts +17 -8
  227. package/dist/utils/nodeTypes.js +27 -20
  228. package/dist/utils/performanceUtils.js +7 -0
  229. package/package.json +7 -5
  230. package/dist/messages/deprecation.d.ts +0 -20
  231. package/dist/messages/deprecation.js +0 -33
  232. package/dist/registry/plugin.d.ts +0 -215
  233. package/dist/registry/plugin.js +0 -249
  234. package/dist/services/api.d.ts +0 -129
  235. package/dist/services/api.js +0 -217
@@ -8,8 +8,7 @@
8
8
  * construction happen in exactly one place.
9
9
  */
10
10
  import { tick } from 'svelte';
11
- import { getWorkflowStore, workflowActions, markAsSaved as storeMarkAsSaved } from '../stores/workflowStore.svelte.js';
12
- import { workflowApi, setEndpointConfig } from './api.js';
11
+ import { getDefaultInstance } from '../stores/instanceContainer.svelte.js';
13
12
  import { createEndpointConfig } from '../config/endpoints.js';
14
13
  import { v4 as uuidv4 } from 'uuid';
15
14
  import { DEFAULT_WORKFLOW_FORMAT } from '../types/index.js';
@@ -19,29 +18,19 @@ import { DEFAULT_FEATURES } from '../types/events.js';
19
18
  // Internal helpers
20
19
  // ---------------------------------------------------------------------------
21
20
  /**
22
- * Ensure API configuration is initialized.
23
- * This is needed when the global save function is called from the layout component
24
- * which doesn't initialize the API configuration like the App component does.
21
+ * Ensure the instance's API context is configured.
22
+ * This is needed when the global save function is called from the layout
23
+ * component which doesn't initialize the API configuration like <App> does.
25
24
  */
26
- async function ensureApiConfiguration() {
27
- try {
28
- const { getEndpointConfig } = await import('./api.js');
29
- const currentConfig = getEndpointConfig();
30
- if (currentConfig && currentConfig.baseUrl) {
31
- return;
32
- }
33
- }
34
- catch {
35
- // Could not check existing API configuration, initializing
25
+ function ensureApiConfiguration(fd) {
26
+ if (fd.api.isConfigured() && fd.api.config?.baseUrl) {
27
+ return;
36
28
  }
37
29
  // API configuration is not initialized — derive URL from window.location when available
38
30
  const apiBaseUrl = typeof window !== 'undefined'
39
31
  ? `${window.location.protocol}//${window.location.host}/api/flowdrop`
40
32
  : '/api/flowdrop';
41
33
  const config = createEndpointConfig(apiBaseUrl, {
42
- auth: {
43
- type: 'none'
44
- },
45
34
  timeout: 10000,
46
35
  retry: {
47
36
  enabled: true,
@@ -50,7 +39,7 @@ async function ensureApiConfiguration() {
50
39
  backoff: 'exponential'
51
40
  }
52
41
  });
53
- setEndpointConfig(config);
42
+ fd.api.configure(config);
54
43
  }
55
44
  /**
56
45
  * Flush any pending form changes by blurring the active element.
@@ -79,18 +68,21 @@ async function flushPendingFormChanges() {
79
68
  * 1. Flush pending form changes (blur active element + tick)
80
69
  * 2. Optionally call onBeforeSave — return false cancels the save
81
70
  * 3. Build the canonical Workflow object (preserving metadata, format, etc.)
82
- * 4. Persist via enhanced apiClient or legacy workflowApi
71
+ * 4. Persist via the instance's API client (fd.api.client)
83
72
  * 5. Update the store if the server assigned a new ID
84
73
  * 6. Call onMarkAsSaved / onAfterSave hooks
85
74
  * 7. Show toast notifications (respecting features.showToasts)
86
75
  */
87
76
  export async function globalSaveWorkflow(options = {}) {
88
- const { apiClient, eventHandlers, onMarkAsSaved, onSaved } = options;
77
+ const { eventHandlers, onMarkAsSaved, onSaved } = options;
89
78
  const features = { ...DEFAULT_FEATURES, ...options.features };
79
+ // Resolve the target instance; defaults to the page-default instance.
80
+ const fd = options.instance ?? getDefaultInstance();
81
+ const readWorkflow = () => fd.workflow.current;
90
82
  // Step 1 — Flush pending form changes (single location for this logic)
91
83
  await flushPendingFormChanges();
92
- // Get current workflow from global store after flush
93
- const currentWorkflow = getWorkflowStore();
84
+ // Get current workflow from the instance's store after flush
85
+ const currentWorkflow = readWorkflow();
94
86
  if (!currentWorkflow) {
95
87
  if (features.showToasts) {
96
88
  apiToasts.error('Save workflow', 'No workflow to save');
@@ -107,7 +99,7 @@ export async function globalSaveWorkflow(options = {}) {
107
99
  const loadingToast = features.showToasts ? apiToasts.loading('Saving workflow') : null;
108
100
  try {
109
101
  // Ensure API configuration is initialised (needed when called outside App.svelte)
110
- await ensureApiConfiguration();
102
+ ensureApiConfiguration(fd);
111
103
  // Step 3 — Build the canonical workflow object.
112
104
  // Preserve all existing metadata fields (format, tags, etc.) so nothing is dropped.
113
105
  //
@@ -124,35 +116,21 @@ export async function globalSaveWorkflow(options = {}) {
124
116
  edges: currentWorkflow.edges || [],
125
117
  metadata: {
126
118
  ...currentWorkflow.metadata,
127
- version: currentWorkflow.metadata?.version || '1.0.0',
119
+ schemaVersion: currentWorkflow.metadata?.schemaVersion || '1.0.0',
128
120
  format: currentWorkflow.metadata?.format || DEFAULT_WORKFLOW_FORMAT,
129
121
  createdAt: currentWorkflow.metadata?.createdAt || new Date().toISOString(),
130
122
  updatedAt: new Date().toISOString()
131
123
  }
132
124
  };
133
- // Step 4 — Persist
134
- let savedWorkflow;
135
- if (apiClient) {
136
- if (isExistingWorkflow) {
137
- savedWorkflow = await apiClient.updateWorkflow(finalWorkflow.id, finalWorkflow);
138
- }
139
- else {
140
- savedWorkflow = await apiClient.saveWorkflow(finalWorkflow);
141
- }
142
- }
143
- else {
144
- // Legacy path
145
- if (isExistingWorkflow) {
146
- savedWorkflow = await workflowApi.updateWorkflow(finalWorkflow.id, finalWorkflow);
147
- }
148
- else {
149
- const { id: _id, ...workflowData } = finalWorkflow;
150
- savedWorkflow = await workflowApi.createWorkflow(workflowData);
151
- }
152
- }
125
+ // Step 4 — Persist via this instance's API client.
126
+ // id-presence (computed above) decides update vs create — never UUID-regex.
127
+ const apiClient = fd.api.client;
128
+ const savedWorkflow = isExistingWorkflow
129
+ ? await apiClient.updateWorkflow(finalWorkflow.id, finalWorkflow)
130
+ : await apiClient.saveWorkflow(finalWorkflow);
153
131
  // Step 5 — If the server assigned a new ID, sync the store
154
132
  if (savedWorkflow.id && savedWorkflow.id !== finalWorkflow.id) {
155
- workflowActions.batchUpdate({
133
+ fd.workflow.batchUpdate({
156
134
  nodes: finalWorkflow.nodes,
157
135
  edges: finalWorkflow.edges,
158
136
  name: finalWorkflow.name,
@@ -167,8 +145,7 @@ export async function globalSaveWorkflow(options = {}) {
167
145
  onMarkAsSaved();
168
146
  }
169
147
  else {
170
- // Fallback: call the store's own markAsSaved if no callback was provided
171
- storeMarkAsSaved();
148
+ fd.workflow.markAsSaved();
172
149
  }
173
150
  // Notify caller with the definitive saved workflow (server-assigned ID)
174
151
  if (onSaved) {
@@ -190,7 +167,7 @@ export async function globalSaveWorkflow(options = {}) {
190
167
  dismissToast(loadingToast);
191
168
  const errorObj = error instanceof Error ? error : new Error('Unknown error occurred');
192
169
  // onSaveError hook
193
- const currentWorkflowForError = getWorkflowStore();
170
+ const currentWorkflowForError = readWorkflow();
194
171
  if (eventHandlers?.onSaveError && currentWorkflowForError) {
195
172
  await eventHandlers.onSaveError(errorObj, currentWorkflowForError);
196
173
  }
@@ -218,7 +195,8 @@ export async function globalExportWorkflow(options = {}) {
218
195
  try {
219
196
  // Flush pending changes before exporting (same discipline as save)
220
197
  await flushPendingFormChanges();
221
- const currentWorkflow = getWorkflowStore();
198
+ const fd = options.instance ?? getDefaultInstance();
199
+ const currentWorkflow = fd.workflow.current;
222
200
  if (!currentWorkflow) {
223
201
  if (features.showToasts) {
224
202
  apiToasts.error('Export workflow', 'No workflow to export');
@@ -234,7 +212,7 @@ export async function globalExportWorkflow(options = {}) {
234
212
  edges: currentWorkflow.edges || [],
235
213
  metadata: {
236
214
  ...currentWorkflow.metadata,
237
- version: currentWorkflow.metadata?.version || '1.0.0',
215
+ schemaVersion: currentWorkflow.metadata?.schemaVersion || '1.0.0',
238
216
  format: currentWorkflow.metadata?.format || DEFAULT_WORKFLOW_FORMAT,
239
217
  createdAt: currentWorkflow.metadata?.createdAt || new Date().toISOString(),
240
218
  updatedAt: new Date().toISOString()
@@ -202,9 +202,15 @@ export declare class HistoryService {
202
202
  private notifyChange;
203
203
  }
204
204
  /**
205
- * Singleton instance of the history service
205
+ * History service of the page-default FlowDrop instance.
206
206
  *
207
- * Use this for the main workflow editor. For isolated instances,
208
- * create a new HistoryService directly.
207
+ * Kept as a module-level export for backward compatibility (re-exported via
208
+ * `@flowdrop/flowdrop/editor`) `createFlowDropInstance({ isDefault: true })`
209
+ * adopts this exact object, so legacy `historyService.undo()` calls keep
210
+ * operating on the default editor's history stack. Holds no reactive state,
211
+ * so module-level construction is SSR-safe.
212
+ *
213
+ * For additional editor instances, the instance container creates a fresh
214
+ * `new HistoryService()` — use `getInstance().history` in components.
209
215
  */
210
216
  export declare const historyService: HistoryService;
@@ -328,9 +328,15 @@ export class HistoryService {
328
328
  // Singleton Instance
329
329
  // =========================================================================
330
330
  /**
331
- * Singleton instance of the history service
331
+ * History service of the page-default FlowDrop instance.
332
332
  *
333
- * Use this for the main workflow editor. For isolated instances,
334
- * create a new HistoryService directly.
333
+ * Kept as a module-level export for backward compatibility (re-exported via
334
+ * `@flowdrop/flowdrop/editor`) `createFlowDropInstance({ isDefault: true })`
335
+ * adopts this exact object, so legacy `historyService.undo()` calls keep
336
+ * operating on the default editor's history stack. Holds no reactive state,
337
+ * so module-level construction is SSR-safe.
338
+ *
339
+ * For additional editor instances, the instance container creates a fresh
340
+ * `new HistoryService()` — use `getInstance().history` in components.
335
341
  */
336
342
  export const historyService = new HistoryService();
@@ -8,6 +8,8 @@
8
8
  * @module services/interruptService
9
9
  */
10
10
  import type { Interrupt, InterruptPollingConfig } from '../types/interrupt.js';
11
+ import type { EndpointConfig } from '../config/endpoints.js';
12
+ import type { AuthProvider } from '../types/auth.js';
11
13
  /**
12
14
  * Interrupt Service class
13
15
  *
@@ -46,19 +48,23 @@ export declare class InterruptService {
46
48
  /**
47
49
  * Check if interrupt endpoints are configured
48
50
  *
51
+ * @param config - The instance's endpoint configuration (from fd.api.config)
49
52
  * @returns True if interrupt endpoints are available
50
53
  */
51
- isConfigured(): boolean;
54
+ isConfigured(config: EndpointConfig | null): boolean;
52
55
  /**
53
- * Get the endpoint configuration
56
+ * Validate and return the caller-supplied endpoint configuration.
54
57
  *
55
- * @throws Error if endpoint configuration is not set
58
+ * Callers thread the config from `getInstance().api.config`.
59
+ *
60
+ * @throws Error if endpoint configuration is not set or lacks interrupts
56
61
  * @returns The endpoint configuration
57
62
  */
58
63
  private getConfig;
59
64
  /**
60
65
  * Generic API request helper
61
66
  *
67
+ * @param config - The endpoint configuration
62
68
  * @param url - The URL to fetch
63
69
  * @param options - Fetch options
64
70
  * @returns The parsed JSON response
@@ -70,7 +76,7 @@ export declare class InterruptService {
70
76
  * @param interruptId - The interrupt UUID
71
77
  * @returns The interrupt details
72
78
  */
73
- getInterrupt(interruptId: string): Promise<Interrupt>;
79
+ getInterrupt(endpointConfig: EndpointConfig | null, interruptId: string, authProvider?: AuthProvider): Promise<Interrupt>;
74
80
  /**
75
81
  * Resolve an interrupt with user response
76
82
  *
@@ -78,28 +84,28 @@ export declare class InterruptService {
78
84
  * @param value - The user's response value
79
85
  * @returns The updated interrupt
80
86
  */
81
- resolveInterrupt(interruptId: string, value: unknown): Promise<Interrupt>;
87
+ resolveInterrupt(endpointConfig: EndpointConfig | null, interruptId: string, value: unknown, authProvider?: AuthProvider): Promise<Interrupt>;
82
88
  /**
83
89
  * Cancel a pending interrupt
84
90
  *
85
91
  * @param interruptId - The interrupt UUID
86
92
  * @returns The updated interrupt
87
93
  */
88
- cancelInterrupt(interruptId: string): Promise<Interrupt>;
94
+ cancelInterrupt(endpointConfig: EndpointConfig | null, interruptId: string, authProvider?: AuthProvider): Promise<Interrupt>;
89
95
  /**
90
96
  * List interrupts for a playground session
91
97
  *
92
98
  * @param sessionId - The session UUID
93
99
  * @returns Array of interrupts for the session
94
100
  */
95
- listSessionInterrupts(sessionId: string): Promise<Interrupt[]>;
101
+ listSessionInterrupts(endpointConfig: EndpointConfig | null, sessionId: string, authProvider?: AuthProvider): Promise<Interrupt[]>;
96
102
  /**
97
103
  * List interrupts for a pipeline
98
104
  *
99
105
  * @param pipelineId - The pipeline UUID
100
106
  * @returns Array of interrupts for the pipeline
101
107
  */
102
- listPipelineInterrupts(pipelineId: string): Promise<Interrupt[]>;
108
+ listPipelineInterrupts(endpointConfig: EndpointConfig | null, pipelineId: string, authProvider?: AuthProvider): Promise<Interrupt[]>;
103
109
  /**
104
110
  * Start polling for interrupts in a session
105
111
  *
@@ -109,7 +115,7 @@ export declare class InterruptService {
109
115
  * @param sessionId - The session UUID to poll
110
116
  * @param callback - Callback function to handle new interrupts
111
117
  */
112
- startPolling(sessionId: string, callback: (interrupts: Interrupt[]) => void): void;
118
+ startPolling(endpointConfig: EndpointConfig | null, sessionId: string, callback: (interrupts: Interrupt[]) => void, authProvider?: AuthProvider): void;
113
119
  /**
114
120
  * Stop polling for interrupts
115
121
  */
@@ -8,8 +8,8 @@
8
8
  * @module services/interruptService
9
9
  */
10
10
  import { defaultInterruptPollingConfig } from '../types/interrupt.js';
11
- import { buildEndpointUrl, getEndpointHeaders } from '../config/endpoints.js';
12
- import { getEndpointConfig } from './api.js';
11
+ import { buildEndpointUrl } from '../config/endpoints.js';
12
+ import { authenticatedFetch } from '../utils/fetchWithAuth.js';
13
13
  import { logger } from '../utils/logger.js';
14
14
  /**
15
15
  * Interrupt Service class
@@ -62,22 +62,23 @@ export class InterruptService {
62
62
  /**
63
63
  * Check if interrupt endpoints are configured
64
64
  *
65
+ * @param config - The instance's endpoint configuration (from fd.api.config)
65
66
  * @returns True if interrupt endpoints are available
66
67
  */
67
- isConfigured() {
68
- const config = getEndpointConfig();
68
+ isConfigured(config) {
69
69
  return Boolean(config?.endpoints?.interrupts);
70
70
  }
71
71
  /**
72
- * Get the endpoint configuration
72
+ * Validate and return the caller-supplied endpoint configuration.
73
73
  *
74
- * @throws Error if endpoint configuration is not set
74
+ * Callers thread the config from `getInstance().api.config`.
75
+ *
76
+ * @throws Error if endpoint configuration is not set or lacks interrupts
75
77
  * @returns The endpoint configuration
76
78
  */
77
- getConfig() {
78
- const config = getEndpointConfig();
79
+ getConfig(config) {
79
80
  if (!config) {
80
- throw new Error('Endpoint configuration not set. Call setEndpointConfig() first.');
81
+ throw new Error('Endpoint configuration not set. Configure the instance via fd.api.configure().');
81
82
  }
82
83
  if (!config.endpoints.interrupts) {
83
84
  throw new Error('Interrupt endpoints not configured.');
@@ -87,19 +88,16 @@ export class InterruptService {
87
88
  /**
88
89
  * Generic API request helper
89
90
  *
91
+ * @param config - The endpoint configuration
90
92
  * @param url - The URL to fetch
91
93
  * @param options - Fetch options
92
94
  * @returns The parsed JSON response
93
95
  */
94
- async request(url, options = {}) {
95
- const config = this.getConfig();
96
- const headers = getEndpointHeaders(config, 'interrupts');
97
- const response = await fetch(url, {
98
- ...options,
99
- headers: {
100
- ...headers,
101
- ...options.headers
102
- }
96
+ async request(config, url, options = {}, authProvider) {
97
+ const response = await authenticatedFetch(url, options, {
98
+ config,
99
+ endpointKey: 'interrupts',
100
+ authProvider
103
101
  });
104
102
  if (!response.ok) {
105
103
  const errorData = await response.json().catch(() => ({}));
@@ -119,12 +117,12 @@ export class InterruptService {
119
117
  * @param interruptId - The interrupt UUID
120
118
  * @returns The interrupt details
121
119
  */
122
- async getInterrupt(interruptId) {
123
- const config = this.getConfig();
120
+ async getInterrupt(endpointConfig, interruptId, authProvider) {
121
+ const config = this.getConfig(endpointConfig);
124
122
  const url = buildEndpointUrl(config, config.endpoints.interrupts.get, {
125
123
  interruptId
126
124
  });
127
- const response = await this.request(url);
125
+ const response = await this.request(config, url, {}, authProvider);
128
126
  if (!response.data) {
129
127
  throw new Error('Interrupt not found');
130
128
  }
@@ -137,16 +135,16 @@ export class InterruptService {
137
135
  * @param value - The user's response value
138
136
  * @returns The updated interrupt
139
137
  */
140
- async resolveInterrupt(interruptId, value) {
141
- const config = this.getConfig();
138
+ async resolveInterrupt(endpointConfig, interruptId, value, authProvider) {
139
+ const config = this.getConfig(endpointConfig);
142
140
  const url = buildEndpointUrl(config, config.endpoints.interrupts.resolve, {
143
141
  interruptId
144
142
  });
145
143
  const resolution = { value };
146
- const response = await this.request(url, {
144
+ const response = await this.request(config, url, {
147
145
  method: 'POST',
148
146
  body: JSON.stringify(resolution)
149
- });
147
+ }, authProvider);
150
148
  if (!response.data) {
151
149
  throw new Error('Failed to resolve interrupt: No data returned');
152
150
  }
@@ -158,14 +156,14 @@ export class InterruptService {
158
156
  * @param interruptId - The interrupt UUID
159
157
  * @returns The updated interrupt
160
158
  */
161
- async cancelInterrupt(interruptId) {
162
- const config = this.getConfig();
159
+ async cancelInterrupt(endpointConfig, interruptId, authProvider) {
160
+ const config = this.getConfig(endpointConfig);
163
161
  const url = buildEndpointUrl(config, config.endpoints.interrupts.cancel, {
164
162
  interruptId
165
163
  });
166
- const response = await this.request(url, {
164
+ const response = await this.request(config, url, {
167
165
  method: 'POST'
168
- });
166
+ }, authProvider);
169
167
  if (!response.data) {
170
168
  throw new Error('Failed to cancel interrupt: No data returned');
171
169
  }
@@ -177,12 +175,12 @@ export class InterruptService {
177
175
  * @param sessionId - The session UUID
178
176
  * @returns Array of interrupts for the session
179
177
  */
180
- async listSessionInterrupts(sessionId) {
181
- const config = this.getConfig();
178
+ async listSessionInterrupts(endpointConfig, sessionId, authProvider) {
179
+ const config = this.getConfig(endpointConfig);
182
180
  const url = buildEndpointUrl(config, config.endpoints.interrupts.listBySession, {
183
181
  sessionId
184
182
  });
185
- const response = await this.request(url);
183
+ const response = await this.request(config, url, {}, authProvider);
186
184
  return response.data ?? [];
187
185
  }
188
186
  /**
@@ -191,12 +189,12 @@ export class InterruptService {
191
189
  * @param pipelineId - The pipeline UUID
192
190
  * @returns Array of interrupts for the pipeline
193
191
  */
194
- async listPipelineInterrupts(pipelineId) {
195
- const config = this.getConfig();
192
+ async listPipelineInterrupts(endpointConfig, pipelineId, authProvider) {
193
+ const config = this.getConfig(endpointConfig);
196
194
  const url = buildEndpointUrl(config, config.endpoints.interrupts.listByPipeline, {
197
195
  pipelineId
198
196
  });
199
- const response = await this.request(url);
197
+ const response = await this.request(config, url, {}, authProvider);
200
198
  return response.data ?? [];
201
199
  }
202
200
  // =========================================================================
@@ -211,7 +209,7 @@ export class InterruptService {
211
209
  * @param sessionId - The session UUID to poll
212
210
  * @param callback - Callback function to handle new interrupts
213
211
  */
214
- startPolling(sessionId, callback) {
212
+ startPolling(endpointConfig, sessionId, callback, authProvider) {
215
213
  if (!this.pollingConfig.enabled) {
216
214
  logger.warn('[InterruptService] Polling is disabled. Enable via setPollingConfig().');
217
215
  return;
@@ -225,7 +223,7 @@ export class InterruptService {
225
223
  return;
226
224
  }
227
225
  try {
228
- const interrupts = await this.listSessionInterrupts(sessionId);
226
+ const interrupts = await this.listSessionInterrupts(endpointConfig, sessionId, authProvider);
229
227
  const pendingInterrupts = interrupts.filter((i) => i.status === 'pending');
230
228
  // Reset backoff on successful request
231
229
  this.currentBackoff = this.pollingConfig.interval ?? defaultInterruptPollingConfig.interval;
@@ -3,6 +3,7 @@
3
3
  * Handles fetching and managing node execution information from the backend
4
4
  */
5
5
  import type { NodeExecutionInfo } from '../types/index.js';
6
+ import type { EndpointConfig } from '../config/endpoints.js';
6
7
  /**
7
8
  * Service for managing node execution information
8
9
  */
@@ -18,15 +19,15 @@ export declare class NodeExecutionService {
18
19
  /**
19
20
  * Get execution information for a specific node from pipeline data
20
21
  */
21
- getNodeExecutionInfo(nodeId: string, pipelineId?: string): Promise<NodeExecutionInfo | null>;
22
+ getNodeExecutionInfo(endpointConfig: EndpointConfig | null, nodeId: string, pipelineId?: string): Promise<NodeExecutionInfo | null>;
22
23
  /**
23
24
  * Get execution information for multiple nodes from pipeline data
24
25
  */
25
- getMultipleNodeExecutionInfo(nodeIds: string[], pipelineId?: string): Promise<Record<string, NodeExecutionInfo>>;
26
+ getMultipleNodeExecutionInfo(endpointConfig: EndpointConfig | null, nodeIds: string[], pipelineId?: string): Promise<Record<string, NodeExecutionInfo>>;
26
27
  /**
27
28
  * Get all node execution counts
28
29
  */
29
- getAllNodeExecutionCounts(): Promise<Record<string, number>>;
30
+ getAllNodeExecutionCounts(endpointConfig: EndpointConfig | null): Promise<Record<string, number>>;
30
31
  /**
31
32
  * Get cached execution info for a node
32
33
  */
@@ -47,6 +48,20 @@ export declare class NodeExecutionService {
47
48
  * Update execution info for a node (for real-time updates)
48
49
  */
49
50
  updateNodeExecutionInfo(nodeId: string, executionInfo: Partial<NodeExecutionInfo>): void;
51
+ /**
52
+ * Build execution info for one node from the pipeline payload.
53
+ *
54
+ * The `node_statuses` entry is the backend-resolved summary (latest job's
55
+ * status, timing from the most recent run, `executions` count); the per-job
56
+ * history is attached from the `jobs` array so loop iterations stay
57
+ * inspectable. Falls back to the node's jobs when no entry exists (older
58
+ * backends).
59
+ */
60
+ private buildNodeExecutionInfo;
61
+ /**
62
+ * Map a pipeline job payload entry to a NodeJobExecution history item.
63
+ */
64
+ private mapJobToNodeJobExecution;
50
65
  /**
51
66
  * Map job status to execution status
52
67
  */