@genfeedai/workflow-ui 0.2.2 → 0.2.4

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 (47) hide show
  1. package/README.md +11 -33
  2. package/dist/canvas.d.ts +22 -22
  3. package/dist/canvas.mjs +16 -17
  4. package/dist/{chunk-WBR34V4L.mjs → chunk-2FUPL67V.mjs} +1593 -1045
  5. package/dist/{chunk-4VEN4UN7.mjs → chunk-53XDE62A.mjs} +818 -623
  6. package/dist/{chunk-PCIWWD37.mjs → chunk-7LV4UAUS.mjs} +19 -19
  7. package/dist/{chunk-7SKSRSS7.mjs → chunk-B4EAAKYF.mjs} +16 -16
  8. package/dist/{chunk-ZJD5WMR3.mjs → chunk-C6MQBJFC.mjs} +45 -13
  9. package/dist/{chunk-7H3WJJYS.mjs → chunk-ESVULCFY.mjs} +12 -6
  10. package/dist/{chunk-GWBGK3KL.mjs → chunk-FWJIAW2E.mjs} +82 -47
  11. package/dist/{chunk-R727OFBR.mjs → chunk-GPYIIWD5.mjs} +404 -350
  12. package/dist/{chunk-OQREHJXK.mjs → chunk-IYFWAJBB.mjs} +208 -203
  13. package/dist/{chunk-2JQSKIWR.mjs → chunk-MGLAKMDP.mjs} +24 -23
  14. package/dist/{chunk-LT3ZJJL6.mjs → chunk-OJWVEEMM.mjs} +497 -399
  15. package/dist/{chunk-ZD2BADZO.mjs → chunk-ORVDYXDP.mjs} +221 -175
  16. package/dist/{chunk-CV4M7CNU.mjs → chunk-QQVHGJ2G.mjs} +149 -142
  17. package/dist/{chunk-6PSJTBNV.mjs → chunk-U4QPE4CY.mjs} +387 -347
  18. package/dist/{chunk-EFXQT23N.mjs → chunk-VVQ4CH77.mjs} +5 -5
  19. package/dist/{chunk-VRN3UWE5.mjs → chunk-XRC3O5GK.mjs} +73 -73
  20. package/dist/{chunk-FT33LFII.mjs → chunk-YUIK4AHM.mjs} +1 -1
  21. package/dist/{chunk-JT4Y5H3U.mjs → chunk-ZSITTZ4S.mjs} +630 -569
  22. package/dist/hooks.d.ts +37 -37
  23. package/dist/hooks.mjs +10 -10
  24. package/dist/index.d.ts +26 -11
  25. package/dist/index.mjs +99 -20
  26. package/dist/lib.d.ts +203 -203
  27. package/dist/lib.mjs +228 -199
  28. package/dist/nodes.d.ts +2 -2
  29. package/dist/nodes.mjs +12 -13
  30. package/dist/panels.d.ts +2 -3
  31. package/dist/panels.mjs +3 -3
  32. package/dist/provider.d.ts +2 -2
  33. package/dist/provider.mjs +2 -2
  34. package/dist/stores.d.ts +5 -5
  35. package/dist/stores.mjs +5 -5
  36. package/dist/toolbar.d.ts +42 -24
  37. package/dist/toolbar.mjs +4 -5
  38. package/dist/ui.d.ts +2 -2
  39. package/dist/ui.mjs +2 -2
  40. package/dist/{useCommentNavigation-BakbiiIc.d.ts → useRequiredInputs-ByoIS-fT.d.ts} +160 -160
  41. package/dist/{promptLibraryStore-Dl3Q3cP6.d.ts → workflowStore-Bsz0nd5c.d.ts} +368 -368
  42. package/dist/workflowStore-N2F7WIG3.mjs +2 -0
  43. package/package.json +79 -77
  44. package/src/styles/workflow-ui.css +56 -19
  45. package/dist/chunk-OY7BRSGG.mjs +0 -60
  46. package/dist/workflowStore-UAAKOOIK.mjs +0 -2
  47. package/dist/{types-IEKYuYhu.d.ts → types-CRXJnajq.d.ts} +1 -1
@@ -1,105 +1,101 @@
1
- import { useWorkflowStore } from './chunk-R727OFBR.mjs';
1
+ import { useWorkflowStore } from './chunk-GPYIIWD5.mjs';
2
2
  import { create } from 'zustand';
3
3
  import { ProviderTypeEnum, NodeStatusEnum } from '@genfeedai/types';
4
4
 
5
5
  var notificationId = 0;
6
6
  var useUIStore = create((set) => ({
7
- showPalette: true,
8
- showMinimap: true,
9
- showAIGenerator: false,
10
- showDebugPanel: false,
11
- selectedNodeId: null,
12
- selectedEdgeId: null,
13
- highlightedNodeIds: [],
14
7
  activeModal: null,
15
- connectionDropMenu: null,
16
- nodeDetailNodeId: null,
17
- nodeDetailActiveTab: "preview",
18
- nodeDetailStartIndex: 0,
19
- notifications: [],
20
- togglePalette: () => {
21
- set((state) => ({ showPalette: !state.showPalette }));
22
- },
23
- toggleMinimap: () => {
24
- set((state) => ({ showMinimap: !state.showMinimap }));
25
- },
26
- toggleAIGenerator: () => {
27
- set((state) => ({ showAIGenerator: !state.showAIGenerator }));
28
- },
29
- toggleDebugPanel: () => {
30
- set((state) => ({ showDebugPanel: !state.showDebugPanel }));
31
- },
32
- setShowDebugPanel: (show) => {
33
- set({ showDebugPanel: show });
34
- },
35
- selectNode: (nodeId) => {
36
- set({ selectedNodeId: nodeId, selectedEdgeId: null });
37
- },
38
- selectEdge: (edgeId) => {
39
- set({ selectedEdgeId: edgeId, selectedNodeId: null });
40
- },
41
- setHighlightedNodeIds: (ids) => {
42
- set({ highlightedNodeIds: ids });
8
+ addNotification: (notification) => {
9
+ const id = `notification-${++notificationId}`;
10
+ set((state) => ({
11
+ notifications: [...state.notifications, { ...notification, id }]
12
+ }));
13
+ if (notification.duration !== 0) {
14
+ setTimeout(() => {
15
+ set((state) => ({
16
+ notifications: state.notifications.filter((n) => n.id !== id)
17
+ }));
18
+ }, notification.duration ?? 5e3);
19
+ }
43
20
  },
44
- openModal: (modal) => {
45
- set({ activeModal: modal });
21
+ closeConnectionDropMenu: () => {
22
+ set({ connectionDropMenu: null });
46
23
  },
47
24
  closeModal: () => {
48
25
  set({ activeModal: null });
49
26
  },
27
+ closeNodeDetailModal: () => {
28
+ set({
29
+ activeModal: null,
30
+ nodeDetailActiveTab: "preview",
31
+ nodeDetailNodeId: null,
32
+ nodeDetailStartIndex: 0
33
+ });
34
+ },
35
+ connectionDropMenu: null,
36
+ highlightedNodeIds: [],
37
+ nodeDetailActiveTab: "preview",
38
+ nodeDetailNodeId: null,
39
+ nodeDetailStartIndex: 0,
40
+ notifications: [],
50
41
  openConnectionDropMenu: (params) => {
51
42
  set({ connectionDropMenu: params });
52
43
  },
53
- closeConnectionDropMenu: () => {
54
- set({ connectionDropMenu: null });
44
+ openModal: (modal) => {
45
+ set({ activeModal: modal });
55
46
  },
56
47
  openNodeDetailModal: (nodeId, tab = "preview", startIndex = 0) => {
57
48
  set({
58
49
  activeModal: "nodeDetail",
59
- nodeDetailNodeId: nodeId,
60
50
  nodeDetailActiveTab: tab,
51
+ nodeDetailNodeId: nodeId,
61
52
  nodeDetailStartIndex: startIndex
62
53
  });
63
54
  },
64
- closeNodeDetailModal: () => {
65
- set({
66
- activeModal: null,
67
- nodeDetailNodeId: null,
68
- nodeDetailActiveTab: "preview",
69
- nodeDetailStartIndex: 0
70
- });
55
+ removeNotification: (id) => {
56
+ set((state) => ({
57
+ notifications: state.notifications.filter((n) => n.id !== id)
58
+ }));
59
+ },
60
+ selectEdge: (edgeId) => {
61
+ set({ selectedEdgeId: edgeId, selectedNodeId: null });
62
+ },
63
+ selectedEdgeId: null,
64
+ selectedNodeId: null,
65
+ selectNode: (nodeId) => {
66
+ set({ selectedEdgeId: null, selectedNodeId: nodeId });
67
+ },
68
+ setHighlightedNodeIds: (ids) => {
69
+ set({ highlightedNodeIds: ids });
71
70
  },
72
71
  setNodeDetailTab: (tab) => {
73
72
  set({ nodeDetailActiveTab: tab });
74
73
  },
75
- addNotification: (notification) => {
76
- const id = `notification-${++notificationId}`;
77
- set((state) => ({
78
- notifications: [...state.notifications, { ...notification, id }]
79
- }));
80
- if (notification.duration !== 0) {
81
- setTimeout(() => {
82
- set((state) => ({
83
- notifications: state.notifications.filter((n) => n.id !== id)
84
- }));
85
- }, notification.duration ?? 5e3);
86
- }
74
+ setShowDebugPanel: (show) => {
75
+ set({ showDebugPanel: show });
87
76
  },
88
- removeNotification: (id) => {
89
- set((state) => ({
90
- notifications: state.notifications.filter((n) => n.id !== id)
91
- }));
77
+ showAIGenerator: false,
78
+ showDebugPanel: false,
79
+ showMinimap: true,
80
+ showPalette: true,
81
+ toggleAIGenerator: () => {
82
+ set((state) => ({ showAIGenerator: !state.showAIGenerator }));
83
+ },
84
+ toggleDebugPanel: () => {
85
+ set((state) => ({ showDebugPanel: !state.showDebugPanel }));
86
+ },
87
+ toggleMinimap: () => {
88
+ set((state) => ({ showMinimap: !state.showMinimap }));
89
+ },
90
+ togglePalette: () => {
91
+ set((state) => ({ showPalette: !state.showPalette }));
92
92
  }
93
93
  }));
94
94
  var STORAGE_KEY = "genfeed-settings";
95
95
  var MAX_RECENT_MODELS = 8;
96
96
  var DEFAULT_SETTINGS = {
97
- providers: {
98
- replicate: { apiKey: null, enabled: true },
99
- fal: { apiKey: null, enabled: false },
100
- huggingface: { apiKey: null, enabled: false },
101
- "genfeed-ai": { apiKey: null, enabled: true }
102
- },
97
+ autoSaveEnabled: true,
98
+ debugMode: false,
103
99
  defaults: {
104
100
  imageModel: "nano-banana-pro",
105
101
  imageProvider: "replicate",
@@ -107,11 +103,15 @@ var DEFAULT_SETTINGS = {
107
103
  videoProvider: "replicate"
108
104
  },
109
105
  edgeStyle: "default",
110
- showMinimap: true,
111
- autoSaveEnabled: true,
112
- recentModels: [],
113
106
  hasSeenWelcome: false,
114
- debugMode: false
107
+ providers: {
108
+ fal: { apiKey: null, enabled: false },
109
+ "genfeed-ai": { apiKey: null, enabled: true },
110
+ huggingface: { apiKey: null, enabled: false },
111
+ replicate: { apiKey: null, enabled: true }
112
+ },
113
+ recentModels: [],
114
+ showMinimap: true
115
115
  };
116
116
  function loadFromStorage() {
117
117
  if (typeof window === "undefined") return {};
@@ -120,14 +120,14 @@ function loadFromStorage() {
120
120
  if (stored) {
121
121
  const parsed = JSON.parse(stored);
122
122
  return {
123
- providers: { ...DEFAULT_SETTINGS.providers, ...parsed.providers },
123
+ autoSaveEnabled: parsed.autoSaveEnabled ?? true,
124
+ debugMode: parsed.debugMode ?? false,
124
125
  defaults: { ...DEFAULT_SETTINGS.defaults, ...parsed.defaults },
125
126
  edgeStyle: parsed.edgeStyle === "bezier" ? "default" : parsed.edgeStyle ?? DEFAULT_SETTINGS.edgeStyle,
126
- showMinimap: parsed.showMinimap ?? DEFAULT_SETTINGS.showMinimap,
127
- autoSaveEnabled: parsed.autoSaveEnabled ?? true,
128
- recentModels: parsed.recentModels ?? [],
129
127
  hasSeenWelcome: parsed.hasSeenWelcome ?? false,
130
- debugMode: parsed.debugMode ?? false
128
+ providers: { ...DEFAULT_SETTINGS.providers, ...parsed.providers },
129
+ recentModels: parsed.recentModels ?? [],
130
+ showMinimap: parsed.showMinimap ?? DEFAULT_SETTINGS.showMinimap
131
131
  };
132
132
  }
133
133
  } catch {
@@ -138,11 +138,12 @@ function saveToStorage(state) {
138
138
  if (typeof window === "undefined") return;
139
139
  try {
140
140
  const toSave = {
141
+ autoSaveEnabled: state.autoSaveEnabled,
142
+ debugMode: state.debugMode,
143
+ defaults: state.defaults,
144
+ edgeStyle: state.edgeStyle,
145
+ hasSeenWelcome: state.hasSeenWelcome,
141
146
  providers: {
142
- replicate: {
143
- apiKey: state.providers.replicate.apiKey,
144
- enabled: state.providers.replicate.enabled
145
- },
146
147
  fal: {
147
148
  apiKey: state.providers.fal.apiKey,
148
149
  enabled: state.providers.fal.enabled
@@ -150,15 +151,14 @@ function saveToStorage(state) {
150
151
  huggingface: {
151
152
  apiKey: state.providers.huggingface.apiKey,
152
153
  enabled: state.providers.huggingface.enabled
154
+ },
155
+ replicate: {
156
+ apiKey: state.providers.replicate.apiKey,
157
+ enabled: state.providers.replicate.enabled
153
158
  }
154
159
  },
155
- defaults: state.defaults,
156
- edgeStyle: state.edgeStyle,
157
- showMinimap: state.showMinimap,
158
- autoSaveEnabled: state.autoSaveEnabled,
159
160
  recentModels: state.recentModels.slice(0, MAX_RECENT_MODELS),
160
- hasSeenWelcome: state.hasSeenWelcome,
161
- debugMode: state.debugMode
161
+ showMinimap: state.showMinimap
162
162
  };
163
163
  localStorage.setItem(STORAGE_KEY, JSON.stringify(toSave));
164
164
  } catch {
@@ -174,40 +174,67 @@ var useSettingsStore = create((set, get) => {
174
174
  });
175
175
  };
176
176
  return {
177
- providers: initialState.providers,
178
- defaults: initialState.defaults,
179
- edgeStyle: initialState.edgeStyle,
180
- showMinimap: initialState.showMinimap,
181
- autoSaveEnabled: initialState.autoSaveEnabled,
182
- recentModels: initialState.recentModels,
183
- hasSeenWelcome: initialState.hasSeenWelcome,
184
- debugMode: initialState.debugMode,
185
- toggleAutoSave: () => {
186
- setAndPersist((state) => ({ autoSaveEnabled: !state.autoSaveEnabled }));
177
+ addRecentModel: (model) => {
178
+ setAndPersist((state) => {
179
+ const filtered = state.recentModels.filter(
180
+ (m) => !(m.id === model.id && m.provider === model.provider)
181
+ );
182
+ const newRecentModels = [
183
+ { ...model, timestamp: Date.now() },
184
+ ...filtered
185
+ ].slice(0, MAX_RECENT_MODELS);
186
+ return { recentModels: newRecentModels };
187
+ });
187
188
  },
188
- setProviderKey: (provider, key) => {
189
+ autoSaveEnabled: initialState.autoSaveEnabled,
190
+ clearAllKeys: () => {
189
191
  setAndPersist((state) => ({
190
192
  providers: {
191
- ...state.providers,
192
- [provider]: {
193
- ...state.providers[provider],
194
- apiKey: key,
195
- enabled: key ? true : state.providers[provider].enabled
196
- }
193
+ fal: { ...state.providers.fal, apiKey: null },
194
+ "genfeed-ai": { ...state.providers["genfeed-ai"], apiKey: null },
195
+ huggingface: { ...state.providers.huggingface, apiKey: null },
196
+ replicate: { ...state.providers.replicate, apiKey: null }
197
197
  }
198
198
  }));
199
199
  },
200
- setProviderEnabled: (provider, enabled) => {
200
+ clearProviderKey: (provider) => {
201
201
  setAndPersist((state) => ({
202
202
  providers: {
203
203
  ...state.providers,
204
204
  [provider]: {
205
205
  ...state.providers[provider],
206
- enabled
206
+ apiKey: null
207
207
  }
208
208
  }
209
209
  }));
210
210
  },
211
+ debugMode: initialState.debugMode,
212
+ defaults: initialState.defaults,
213
+ edgeStyle: initialState.edgeStyle,
214
+ getProviderHeader: (provider) => {
215
+ const state = get();
216
+ const key = state.providers[provider].apiKey;
217
+ if (!key) return {};
218
+ const headerMap = {
219
+ [ProviderTypeEnum.REPLICATE]: "X-Replicate-Key",
220
+ [ProviderTypeEnum.FAL]: "X-Fal-Key",
221
+ [ProviderTypeEnum.HUGGINGFACE]: "X-HF-Key",
222
+ [ProviderTypeEnum.GENFEED_AI]: "X-Genfeed-Key"
223
+ };
224
+ return { [headerMap[provider]]: key };
225
+ },
226
+ hasSeenWelcome: initialState.hasSeenWelcome,
227
+ isProviderConfigured: (provider) => {
228
+ const state = get();
229
+ return !!state.providers[provider].apiKey;
230
+ },
231
+ // API Sync - stubbed as no-ops (consuming app provides real implementations)
232
+ isSyncing: false,
233
+ providers: initialState.providers,
234
+ recentModels: initialState.recentModels,
235
+ setDebugMode: (enabled) => {
236
+ setAndPersist(() => ({ debugMode: enabled }));
237
+ },
211
238
  setDefaultModel: (type, model, provider) => {
212
239
  setAndPersist((state) => ({
213
240
  defaults: {
@@ -218,96 +245,69 @@ var useSettingsStore = create((set, get) => {
218
245
  },
219
246
  setEdgeStyle: (style) => {
220
247
  setAndPersist(() => ({ edgeStyle: style }));
221
- import('./workflowStore-UAAKOOIK.mjs').then(({ useWorkflowStore: useWorkflowStore2 }) => {
248
+ import('./workflowStore-N2F7WIG3.mjs').then(({ useWorkflowStore: useWorkflowStore2 }) => {
222
249
  useWorkflowStore2.getState().setEdgeStyle(style);
223
250
  });
224
251
  },
225
- setShowMinimap: (show) => {
226
- setAndPersist(() => ({ showMinimap: show }));
227
- },
228
- addRecentModel: (model) => {
229
- setAndPersist((state) => {
230
- const filtered = state.recentModels.filter(
231
- (m) => !(m.id === model.id && m.provider === model.provider)
232
- );
233
- const newRecentModels = [{ ...model, timestamp: Date.now() }, ...filtered].slice(
234
- 0,
235
- MAX_RECENT_MODELS
236
- );
237
- return { recentModels: newRecentModels };
238
- });
252
+ setHasSeenWelcome: (seen) => {
253
+ setAndPersist(() => ({ hasSeenWelcome: seen }));
239
254
  },
240
- clearProviderKey: (provider) => {
255
+ setProviderEnabled: (provider, enabled) => {
241
256
  setAndPersist((state) => ({
242
257
  providers: {
243
258
  ...state.providers,
244
259
  [provider]: {
245
260
  ...state.providers[provider],
246
- apiKey: null
261
+ enabled
247
262
  }
248
263
  }
249
264
  }));
250
265
  },
251
- clearAllKeys: () => {
266
+ setProviderKey: (provider, key) => {
252
267
  setAndPersist((state) => ({
253
268
  providers: {
254
- replicate: { ...state.providers.replicate, apiKey: null },
255
- fal: { ...state.providers.fal, apiKey: null },
256
- huggingface: { ...state.providers.huggingface, apiKey: null },
257
- "genfeed-ai": { ...state.providers["genfeed-ai"], apiKey: null }
269
+ ...state.providers,
270
+ [provider]: {
271
+ ...state.providers[provider],
272
+ apiKey: key,
273
+ enabled: key ? true : state.providers[provider].enabled
274
+ }
258
275
  }
259
276
  }));
260
277
  },
261
- setHasSeenWelcome: (seen) => {
262
- setAndPersist(() => ({ hasSeenWelcome: seen }));
263
- },
264
- setDebugMode: (enabled) => {
265
- setAndPersist(() => ({ debugMode: enabled }));
266
- },
267
- isProviderConfigured: (provider) => {
268
- const state = get();
269
- return !!state.providers[provider].apiKey;
270
- },
271
- getProviderHeader: (provider) => {
272
- const state = get();
273
- const key = state.providers[provider].apiKey;
274
- if (!key) return {};
275
- const headerMap = {
276
- [ProviderTypeEnum.REPLICATE]: "X-Replicate-Key",
277
- [ProviderTypeEnum.FAL]: "X-Fal-Key",
278
- [ProviderTypeEnum.HUGGINGFACE]: "X-HF-Key",
279
- [ProviderTypeEnum.GENFEED_AI]: "X-Genfeed-Key"
280
- };
281
- return { [headerMap[provider]]: key };
278
+ setShowMinimap: (show) => {
279
+ setAndPersist(() => ({ showMinimap: show }));
282
280
  },
283
- // API Sync - stubbed as no-ops (consuming app provides real implementations)
284
- isSyncing: false,
281
+ showMinimap: initialState.showMinimap,
285
282
  syncFromServer: async () => {
286
283
  },
287
284
  syncToServer: async () => {
285
+ },
286
+ toggleAutoSave: () => {
287
+ setAndPersist((state) => ({ autoSaveEnabled: !state.autoSaveEnabled }));
288
288
  }
289
289
  };
290
290
  });
291
291
  var PROVIDER_INFO = {
292
292
  [ProviderTypeEnum.REPLICATE]: {
293
- name: "Replicate",
294
293
  description: "Access thousands of open-source AI models",
295
- docsUrl: "https://replicate.com/docs"
294
+ docsUrl: "https://replicate.com/docs",
295
+ name: "Replicate"
296
296
  },
297
297
  [ProviderTypeEnum.FAL]: {
298
- name: "fal.ai",
299
298
  description: "Fast inference for image and video generation",
300
- docsUrl: "https://fal.ai/docs"
299
+ docsUrl: "https://fal.ai/docs",
300
+ name: "fal.ai"
301
301
  },
302
302
  [ProviderTypeEnum.HUGGINGFACE]: {
303
- name: "Hugging Face",
304
303
  description: "The AI community platform with 500k+ models",
305
- docsUrl: "https://huggingface.co/docs/api-inference"
304
+ docsUrl: "https://huggingface.co/docs/api-inference",
305
+ name: "Hugging Face"
306
306
  },
307
307
  [ProviderTypeEnum.GENFEED_AI]: {
308
- name: "Genfeed AI",
309
308
  description: "Built-in models powered by Genfeed",
310
- docsUrl: "https://genfeed.ai/docs"
309
+ docsUrl: "https://genfeed.ai/docs",
310
+ name: "Genfeed AI"
311
311
  }
312
312
  };
313
313
 
@@ -344,7 +344,9 @@ function extractAllOutputValues(output) {
344
344
  if (typeof output === "object" && output !== null) {
345
345
  const obj = output;
346
346
  if ("images" in obj && Array.isArray(obj.images)) {
347
- return obj.images.filter((item) => typeof item === "string");
347
+ return obj.images.filter(
348
+ (item) => typeof item === "string"
349
+ );
348
350
  }
349
351
  if ("image" in obj && typeof obj.image === "string") {
350
352
  return [obj.image];
@@ -371,9 +373,14 @@ function getOutputUpdate(nodeId, output, workflowStore) {
371
373
  }
372
374
  return { outputImage: outputValue };
373
375
  }
374
- if (["videoGen", "animation", "videoStitch", "lipSync", "voiceChange", "motionControl"].includes(
375
- nodeType
376
- )) {
376
+ if ([
377
+ "videoGen",
378
+ "animation",
379
+ "videoStitch",
380
+ "lipSync",
381
+ "voiceChange",
382
+ "motionControl"
383
+ ].includes(nodeType)) {
377
384
  return { outputVideo: outputValue };
378
385
  }
379
386
  if (nodeType === "textToSpeech") {
@@ -392,11 +399,11 @@ function getOutputUpdate(nodeId, output, workflowStore) {
392
399
  // src/stores/execution/helpers/sseSubscription.ts
393
400
  var API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://local.genfeed.ai:3001/api";
394
401
  var statusMap = {
402
+ complete: NodeStatusEnum.COMPLETE,
403
+ error: NodeStatusEnum.ERROR,
395
404
  pending: NodeStatusEnum.IDLE,
396
405
  processing: NodeStatusEnum.PROCESSING,
397
- complete: NodeStatusEnum.COMPLETE,
398
- succeeded: NodeStatusEnum.COMPLETE,
399
- error: NodeStatusEnum.ERROR
406
+ succeeded: NodeStatusEnum.COMPLETE
400
407
  };
401
408
  function applyJobUpdates(jobs, workflowStore, debugMode, set, filterNodeId) {
402
409
  if (!jobs || jobs.length === 0) return;
@@ -413,31 +420,31 @@ function applyJobUpdates(jobs, workflowStore, debugMode, set, filterNodeId) {
413
420
  if (!existing) {
414
421
  didChange = true;
415
422
  newJobs.set(job.predictionId, {
423
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
424
+ error,
416
425
  nodeId: job.nodeId,
426
+ output,
417
427
  predictionId: job.predictionId,
418
- status,
419
428
  progress: 0,
420
- output,
421
- error,
422
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
429
+ status
423
430
  });
424
431
  } else if (existing.status !== status || existing.output !== output || existing.error !== error) {
425
432
  didChange = true;
426
433
  newJobs.set(job.predictionId, {
427
434
  ...existing,
428
- status,
435
+ error,
429
436
  output,
430
- error
437
+ status
431
438
  });
432
439
  }
433
440
  if (job.result?.debugPayload) {
434
441
  const node = workflowStore.getNodeById(job.nodeId);
435
442
  newDebugPayloads.push({
443
+ input: job.result.debugPayload.input,
444
+ model: job.result.debugPayload.model,
436
445
  nodeId: job.nodeId,
437
446
  nodeName: String(node?.data?.label || node?.data?.name || job.nodeId),
438
447
  nodeType: node?.type || "unknown",
439
- model: job.result.debugPayload.model,
440
- input: job.result.debugPayload.input,
441
448
  timestamp: job.result.debugPayload.timestamp
442
449
  });
443
450
  }
@@ -447,13 +454,15 @@ function applyJobUpdates(jobs, workflowStore, debugMode, set, filterNodeId) {
447
454
  useUIStore.getState().setShowDebugPanel(true);
448
455
  }
449
456
  return {
450
- jobs: didChange ? newJobs : state.jobs,
451
457
  debugPayloads: newDebugPayloads.length > 0 ? [
452
458
  ...state.debugPayloads.filter(
453
- (existing) => !newDebugPayloads.some((newP) => newP.nodeId === existing.nodeId)
459
+ (existing) => !newDebugPayloads.some(
460
+ (newP) => newP.nodeId === existing.nodeId
461
+ )
454
462
  ),
455
463
  ...newDebugPayloads
456
- ] : state.debugPayloads
464
+ ] : state.debugPayloads,
465
+ jobs: didChange ? newJobs : state.jobs
457
466
  };
458
467
  });
459
468
  }
@@ -467,8 +476,8 @@ async function reconcileNodeStatuses(executionId) {
467
476
  const nodeStatus = statusMap[nodeResult.status] ?? NodeStatusEnum.IDLE;
468
477
  const isSuccess = nodeResult.status === "complete" || nodeResult.status === "succeeded";
469
478
  workflowStore.updateNodeData(nodeResult.nodeId, {
470
- status: nodeStatus,
471
479
  error: isSuccess ? void 0 : nodeResult.error,
480
+ status: nodeStatus,
472
481
  ...nodeResult.output && getOutputUpdate(nodeResult.nodeId, nodeResult.output, workflowStore)
473
482
  });
474
483
  if (isSuccess && nodeResult.output) {
@@ -479,7 +488,9 @@ async function reconcileNodeStatuses(executionId) {
479
488
  }
480
489
  }
481
490
  function createExecutionSubscription(executionId, set) {
482
- const eventSource = new EventSource(`${API_BASE_URL}/executions/${executionId}/stream`);
491
+ const eventSource = new EventSource(
492
+ `${API_BASE_URL}/executions/${executionId}/stream`
493
+ );
483
494
  const propagatedNodeIds = /* @__PURE__ */ new Set();
484
495
  set({ eventSource });
485
496
  eventSource.onmessage = (event) => {
@@ -492,9 +503,13 @@ function createExecutionSubscription(executionId, set) {
492
503
  const nodeStatus = statusMap[nodeResult.status] ?? NodeStatusEnum.IDLE;
493
504
  const isSuccess = nodeResult.status === "complete" || nodeResult.status === "succeeded";
494
505
  workflowStore.updateNodeData(nodeResult.nodeId, {
495
- status: nodeStatus,
496
506
  error: isSuccess ? void 0 : nodeResult.error,
497
- ...nodeResult.output && getOutputUpdate(nodeResult.nodeId, nodeResult.output, workflowStore)
507
+ status: nodeStatus,
508
+ ...nodeResult.output && getOutputUpdate(
509
+ nodeResult.nodeId,
510
+ nodeResult.output,
511
+ workflowStore
512
+ )
498
513
  });
499
514
  if ((nodeResult.status === "complete" || nodeResult.status === "succeeded") && nodeResult.output && !propagatedNodeIds.has(nodeResult.nodeId)) {
500
515
  propagatedNodeIds.add(nodeResult.nodeId);
@@ -505,16 +520,30 @@ function createExecutionSubscription(executionId, set) {
505
520
  }
506
521
  }
507
522
  applyJobUpdates(data.jobs, workflowStore, data.debugMode, set);
508
- const isComplete = ["completed", "failed", "cancelled", "error"].includes(data.status);
509
- const hasFailedNode = (data.nodeResults || []).some((r) => r.status === "error");
523
+ const isComplete = [
524
+ "completed",
525
+ "failed",
526
+ "cancelled",
527
+ "error"
528
+ ].includes(data.status);
529
+ const hasFailedNode = (data.nodeResults || []).some(
530
+ (r) => r.status === "error"
531
+ );
510
532
  const hasPendingNodes = (data.pendingNodes || []).length > 0;
511
- const hasProcessingNodes = (data.nodeResults || []).some((r) => r.status === "processing");
533
+ const hasProcessingNodes = (data.nodeResults || []).some(
534
+ (r) => r.status === "processing"
535
+ );
512
536
  const isDone = isComplete || hasFailedNode && !hasPendingNodes && !hasProcessingNodes;
513
537
  if (isDone) {
514
538
  propagatedNodeIds.clear();
515
539
  eventSource.close();
516
540
  await reconcileNodeStatuses(executionId);
517
- set({ isRunning: false, eventSource: null, currentNodeId: null, jobs: /* @__PURE__ */ new Map() });
541
+ set({
542
+ currentNodeId: null,
543
+ eventSource: null,
544
+ isRunning: false,
545
+ jobs: /* @__PURE__ */ new Map()
546
+ });
518
547
  if (data.status === "failed" || hasFailedNode) {
519
548
  }
520
549
  }
@@ -525,13 +554,15 @@ function createExecutionSubscription(executionId, set) {
525
554
  eventSource.onerror = () => {
526
555
  eventSource.close();
527
556
  void reconcileNodeStatuses(executionId).then(() => {
528
- set({ isRunning: false, eventSource: null });
557
+ set({ eventSource: null, isRunning: false });
529
558
  });
530
559
  };
531
560
  return eventSource;
532
561
  }
533
562
  function createNodeExecutionSubscription(executionId, nodeId, set, _get) {
534
- const eventSource = new EventSource(`${API_BASE_URL}/executions/${executionId}/stream`);
563
+ const eventSource = new EventSource(
564
+ `${API_BASE_URL}/executions/${executionId}/stream`
565
+ );
535
566
  const propagatedNodeIds = /* @__PURE__ */ new Set();
536
567
  eventSource.onmessage = (event) => {
537
568
  void (async () => {
@@ -543,9 +574,13 @@ function createNodeExecutionSubscription(executionId, nodeId, set, _get) {
543
574
  const nodeStatus = statusMap[nodeResult.status] ?? NodeStatusEnum.IDLE;
544
575
  const isSuccess = nodeResult.status === "complete" || nodeResult.status === "succeeded";
545
576
  workflowStore.updateNodeData(nodeResult.nodeId, {
546
- status: nodeStatus,
547
577
  error: isSuccess ? void 0 : nodeResult.error,
548
- ...nodeResult.output && getOutputUpdate(nodeResult.nodeId, nodeResult.output, workflowStore)
578
+ status: nodeStatus,
579
+ ...nodeResult.output && getOutputUpdate(
580
+ nodeResult.nodeId,
581
+ nodeResult.output,
582
+ workflowStore
583
+ )
549
584
  });
550
585
  if ((nodeResult.status === "complete" || nodeResult.status === "succeeded") && nodeResult.output && !propagatedNodeIds.has(nodeResult.nodeId)) {
551
586
  propagatedNodeIds.add(nodeResult.nodeId);
@@ -556,10 +591,19 @@ function createNodeExecutionSubscription(executionId, nodeId, set, _get) {
556
591
  }
557
592
  }
558
593
  applyJobUpdates(data.jobs, workflowStore, data.debugMode, set, nodeId);
559
- const isComplete = ["completed", "failed", "cancelled", "error"].includes(data.status);
560
- const hasFailedNode = (data.nodeResults || []).some((r) => r.status === "error");
594
+ const isComplete = [
595
+ "completed",
596
+ "failed",
597
+ "cancelled",
598
+ "error"
599
+ ].includes(data.status);
600
+ const hasFailedNode = (data.nodeResults || []).some(
601
+ (r) => r.status === "error"
602
+ );
561
603
  const hasPendingNodes = (data.pendingNodes || []).length > 0;
562
- const hasProcessingNodes = (data.nodeResults || []).some((r) => r.status === "processing");
604
+ const hasProcessingNodes = (data.nodeResults || []).some(
605
+ (r) => r.status === "processing"
606
+ );
563
607
  const isDone = isComplete || hasFailedNode && !hasPendingNodes && !hasProcessingNodes;
564
608
  if (isDone) {
565
609
  propagatedNodeIds.clear();
@@ -568,112 +612,49 @@ function createNodeExecutionSubscription(executionId, nodeId, set, _get) {
568
612
  set((state) => {
569
613
  const newMap = new Map(state.activeNodeExecutions);
570
614
  newMap.delete(nodeId);
571
- return { activeNodeExecutions: newMap };
572
- });
573
- }
574
- } catch {
575
- }
576
- })();
577
- };
578
- eventSource.onerror = () => {
579
- eventSource.close();
580
- void reconcileNodeStatuses(executionId).then(() => {
581
- set((state) => {
582
- const newMap = new Map(state.activeNodeExecutions);
583
- newMap.delete(nodeId);
584
- return { activeNodeExecutions: newMap };
585
- });
586
- });
587
- };
588
- return eventSource;
589
- }
590
-
591
- // src/stores/execution/slices/executionSlice.ts
592
- var API_BASE_URL2 = process.env.NEXT_PUBLIC_API_URL || "http://local.genfeed.ai:3001/api";
593
- async function apiPost(path, body) {
594
- const response = await fetch(`${API_BASE_URL2}${path}`, {
595
- method: "POST",
596
- headers: { "Content-Type": "application/json" },
597
- ...body && { body: JSON.stringify(body) }
598
- });
599
- if (!response.ok) {
600
- const errorData = await response.json().catch(() => ({}));
601
- throw new Error(errorData.message || `API error: ${response.status}`);
602
- }
603
- return response.json();
604
- }
605
- var createExecutionSlice = (set, get) => ({
606
- executeWorkflow: async () => {
607
- const { isRunning, resetExecution } = get();
608
- if (isRunning) return;
609
- const workflowStore = useWorkflowStore.getState();
610
- const debugMode = useSettingsStore.getState().debugMode;
611
- const validation = workflowStore.validateWorkflow();
612
- if (!validation.isValid) {
613
- set({ validationErrors: validation });
614
- return;
615
- }
616
- set({ validationErrors: null });
617
- resetExecution();
618
- if (debugMode) {
619
- useUIStore.getState().setShowDebugPanel(true);
620
- }
621
- if (workflowStore.isDirty || !workflowStore.workflowId) {
622
- try {
623
- await workflowStore.saveWorkflow();
624
- } catch {
625
- set({
626
- validationErrors: {
627
- isValid: false,
628
- errors: [{ nodeId: "", message: "Failed to save workflow", severity: "error" }],
629
- warnings: []
630
- }
631
- });
632
- return;
633
- }
634
- }
635
- const workflowId = workflowStore.workflowId;
636
- if (!workflowId) {
637
- set({
638
- validationErrors: {
639
- isValid: false,
640
- errors: [{ nodeId: "", message: "Workflow must be saved first", severity: "error" }],
641
- warnings: []
642
- }
643
- });
644
- return;
645
- }
646
- set({ isRunning: true });
647
- for (const node of workflowStore.nodes) {
648
- workflowStore.updateNodeData(node.id, {
649
- status: NodeStatusEnum.IDLE,
650
- error: void 0,
651
- progress: void 0
652
- });
653
- }
654
- try {
655
- const execution = await apiPost(`/workflows/${workflowId}/execute`, {
656
- debugMode
657
- });
658
- const executionId = execution._id;
659
- set({ executionId });
660
- createExecutionSubscription(executionId, set);
661
- } catch (error) {
662
- set({
663
- isRunning: false,
664
- validationErrors: {
665
- isValid: false,
666
- errors: [
667
- {
668
- nodeId: "",
669
- message: error instanceof Error ? error.message : "Execution failed",
670
- severity: "error"
671
- }
672
- ],
673
- warnings: []
615
+ return { activeNodeExecutions: newMap };
616
+ });
674
617
  }
618
+ } catch {
619
+ }
620
+ })();
621
+ };
622
+ eventSource.onerror = () => {
623
+ eventSource.close();
624
+ void reconcileNodeStatuses(executionId).then(() => {
625
+ set((state) => {
626
+ const newMap = new Map(state.activeNodeExecutions);
627
+ newMap.delete(nodeId);
628
+ return { activeNodeExecutions: newMap };
675
629
  });
676
- }
630
+ });
631
+ };
632
+ return eventSource;
633
+ }
634
+
635
+ // src/stores/execution/slices/executionSlice.ts
636
+ var API_BASE_URL2 = process.env.NEXT_PUBLIC_API_URL || "http://local.genfeed.ai:3001/api";
637
+ async function apiPost(path, body) {
638
+ const response = await fetch(`${API_BASE_URL2}${path}`, {
639
+ headers: { "Content-Type": "application/json" },
640
+ method: "POST",
641
+ ...body && { body: JSON.stringify(body) }
642
+ });
643
+ if (!response.ok) {
644
+ const errorData = await response.json().catch(() => ({}));
645
+ throw new Error(
646
+ errorData.message || `API error: ${response.status}`
647
+ );
648
+ }
649
+ return response.json();
650
+ }
651
+ var createExecutionSlice = (set, get) => ({
652
+ canResumeFromFailed: () => {
653
+ const { executionId, lastFailedNodeId, isRunning } = get();
654
+ return !isRunning && Boolean(executionId) && Boolean(lastFailedNodeId);
655
+ },
656
+ clearValidationErrors: () => {
657
+ set({ validationErrors: null });
677
658
  },
678
659
  executeNode: async (nodeId) => {
679
660
  const workflowStore = useWorkflowStore.getState();
@@ -683,8 +664,8 @@ var createExecutionSlice = (set, get) => ({
683
664
  await workflowStore.saveWorkflow();
684
665
  } catch {
685
666
  workflowStore.updateNodeData(nodeId, {
686
- status: NodeStatusEnum.ERROR,
687
- error: "Failed to save workflow"
667
+ error: "Failed to save workflow",
668
+ status: NodeStatusEnum.ERROR
688
669
  });
689
670
  return;
690
671
  }
@@ -692,8 +673,8 @@ var createExecutionSlice = (set, get) => ({
692
673
  const workflowId = workflowStore.workflowId;
693
674
  if (!workflowId) {
694
675
  workflowStore.updateNodeData(nodeId, {
695
- status: NodeStatusEnum.ERROR,
696
- error: "Workflow must be saved first"
676
+ error: "Workflow must be saved first",
677
+ status: NodeStatusEnum.ERROR
697
678
  });
698
679
  return;
699
680
  }
@@ -701,16 +682,24 @@ var createExecutionSlice = (set, get) => ({
701
682
  useUIStore.getState().setShowDebugPanel(true);
702
683
  }
703
684
  try {
704
- const execution = await apiPost(`/workflows/${workflowId}/execute`, {
705
- debugMode,
706
- selectedNodeIds: [nodeId]
707
- });
685
+ const execution = await apiPost(
686
+ `/workflows/${workflowId}/execute`,
687
+ {
688
+ debugMode,
689
+ selectedNodeIds: [nodeId]
690
+ }
691
+ );
708
692
  const executionId = execution._id;
709
- const eventSource = createNodeExecutionSubscription(executionId, nodeId, set, get);
693
+ const eventSource = createNodeExecutionSubscription(
694
+ executionId,
695
+ nodeId,
696
+ set,
697
+ get
698
+ );
710
699
  const nodeExecution = {
700
+ eventSource,
711
701
  executionId,
712
- nodeIds: [nodeId],
713
- eventSource
702
+ nodeIds: [nodeId]
714
703
  };
715
704
  set((state) => {
716
705
  const newMap = new Map(state.activeNodeExecutions);
@@ -719,8 +708,8 @@ var createExecutionSlice = (set, get) => ({
719
708
  });
720
709
  } catch (error) {
721
710
  workflowStore.updateNodeData(nodeId, {
722
- status: NodeStatusEnum.ERROR,
723
- error: error instanceof Error ? error.message : "Node execution failed"
711
+ error: error instanceof Error ? error.message : "Node execution failed",
712
+ status: NodeStatusEnum.ERROR
724
713
  });
725
714
  }
726
715
  },
@@ -733,8 +722,10 @@ var createExecutionSlice = (set, get) => ({
733
722
  if (selectedNodeIds.length === 0) {
734
723
  set({
735
724
  validationErrors: {
725
+ errors: [
726
+ { message: "No nodes selected", nodeId: "", severity: "error" }
727
+ ],
736
728
  isValid: false,
737
- errors: [{ nodeId: "", message: "No nodes selected", severity: "error" }],
738
729
  warnings: []
739
730
  }
740
731
  });
@@ -748,8 +739,14 @@ var createExecutionSlice = (set, get) => ({
748
739
  } catch {
749
740
  set({
750
741
  validationErrors: {
742
+ errors: [
743
+ {
744
+ message: "Failed to save workflow",
745
+ nodeId: "",
746
+ severity: "error"
747
+ }
748
+ ],
751
749
  isValid: false,
752
- errors: [{ nodeId: "", message: "Failed to save workflow", severity: "error" }],
753
750
  warnings: []
754
751
  }
755
752
  });
@@ -760,29 +757,38 @@ var createExecutionSlice = (set, get) => ({
760
757
  if (!workflowId) {
761
758
  set({
762
759
  validationErrors: {
760
+ errors: [
761
+ {
762
+ message: "Workflow must be saved first",
763
+ nodeId: "",
764
+ severity: "error"
765
+ }
766
+ ],
763
767
  isValid: false,
764
- errors: [{ nodeId: "", message: "Workflow must be saved first", severity: "error" }],
765
768
  warnings: []
766
769
  }
767
770
  });
768
771
  return;
769
772
  }
770
- set({ isRunning: true, executingNodeIds: selectedNodeIds });
773
+ set({ executingNodeIds: selectedNodeIds, isRunning: true });
771
774
  if (debugMode) {
772
775
  useUIStore.getState().setShowDebugPanel(true);
773
776
  }
774
777
  for (const nodeId of selectedNodeIds) {
775
778
  workflowStore.updateNodeData(nodeId, {
776
- status: NodeStatusEnum.IDLE,
777
779
  error: void 0,
778
- progress: void 0
780
+ progress: void 0,
781
+ status: NodeStatusEnum.IDLE
779
782
  });
780
783
  }
781
784
  try {
782
- const execution = await apiPost(`/workflows/${workflowId}/execute`, {
783
- debugMode,
784
- selectedNodeIds
785
- });
785
+ const execution = await apiPost(
786
+ `/workflows/${workflowId}/execute`,
787
+ {
788
+ debugMode,
789
+ selectedNodeIds
790
+ }
791
+ );
786
792
  const executionId = execution._id;
787
793
  set({ executionId });
788
794
  createExecutionSubscription(executionId, set);
@@ -790,19 +796,139 @@ var createExecutionSlice = (set, get) => ({
790
796
  set({
791
797
  isRunning: false,
792
798
  validationErrors: {
799
+ errors: [
800
+ {
801
+ message: error instanceof Error ? error.message : "Partial execution failed",
802
+ nodeId: "",
803
+ severity: "error"
804
+ }
805
+ ],
806
+ isValid: false,
807
+ warnings: []
808
+ }
809
+ });
810
+ }
811
+ },
812
+ executeWorkflow: async () => {
813
+ const { isRunning, resetExecution } = get();
814
+ if (isRunning) return;
815
+ const workflowStore = useWorkflowStore.getState();
816
+ const debugMode = useSettingsStore.getState().debugMode;
817
+ const validation = workflowStore.validateWorkflow();
818
+ if (!validation.isValid) {
819
+ set({ validationErrors: validation });
820
+ return;
821
+ }
822
+ set({ validationErrors: null });
823
+ resetExecution();
824
+ if (debugMode) {
825
+ useUIStore.getState().setShowDebugPanel(true);
826
+ }
827
+ if (workflowStore.isDirty || !workflowStore.workflowId) {
828
+ try {
829
+ await workflowStore.saveWorkflow();
830
+ } catch {
831
+ set({
832
+ validationErrors: {
833
+ errors: [
834
+ {
835
+ message: "Failed to save workflow",
836
+ nodeId: "",
837
+ severity: "error"
838
+ }
839
+ ],
840
+ isValid: false,
841
+ warnings: []
842
+ }
843
+ });
844
+ return;
845
+ }
846
+ }
847
+ const workflowId = workflowStore.workflowId;
848
+ if (!workflowId) {
849
+ set({
850
+ validationErrors: {
851
+ errors: [
852
+ {
853
+ message: "Workflow must be saved first",
854
+ nodeId: "",
855
+ severity: "error"
856
+ }
857
+ ],
793
858
  isValid: false,
859
+ warnings: []
860
+ }
861
+ });
862
+ return;
863
+ }
864
+ set({ isRunning: true });
865
+ for (const node of workflowStore.nodes) {
866
+ workflowStore.updateNodeData(node.id, {
867
+ error: void 0,
868
+ progress: void 0,
869
+ status: NodeStatusEnum.IDLE
870
+ });
871
+ }
872
+ try {
873
+ const execution = await apiPost(
874
+ `/workflows/${workflowId}/execute`,
875
+ {
876
+ debugMode
877
+ }
878
+ );
879
+ const executionId = execution._id;
880
+ set({ executionId });
881
+ createExecutionSubscription(executionId, set);
882
+ } catch (error) {
883
+ set({
884
+ isRunning: false,
885
+ validationErrors: {
794
886
  errors: [
795
887
  {
888
+ message: error instanceof Error ? error.message : "Execution failed",
796
889
  nodeId: "",
797
- message: error instanceof Error ? error.message : "Partial execution failed",
798
890
  severity: "error"
799
891
  }
800
892
  ],
893
+ isValid: false,
801
894
  warnings: []
802
895
  }
803
896
  });
804
897
  }
805
898
  },
899
+ isNodeExecuting: (nodeId) => {
900
+ const { activeNodeExecutions } = get();
901
+ return activeNodeExecutions.has(nodeId);
902
+ },
903
+ resetExecution: () => {
904
+ const { eventSource, activeNodeExecutions } = get();
905
+ if (eventSource) {
906
+ eventSource.close();
907
+ }
908
+ for (const nodeExecution of activeNodeExecutions.values()) {
909
+ nodeExecution.eventSource.close();
910
+ }
911
+ set({
912
+ activeNodeExecutions: /* @__PURE__ */ new Map(),
913
+ actualCost: 0,
914
+ currentNodeId: null,
915
+ debugPayloads: [],
916
+ eventSource: null,
917
+ executingNodeIds: [],
918
+ executionId: null,
919
+ isRunning: false,
920
+ jobs: /* @__PURE__ */ new Map(),
921
+ lastFailedNodeId: null
922
+ });
923
+ const workflowStore = useWorkflowStore.getState();
924
+ for (const node of workflowStore.nodes) {
925
+ workflowStore.updateNodeData(node.id, {
926
+ error: void 0,
927
+ progress: void 0,
928
+ status: NodeStatusEnum.IDLE
929
+ });
930
+ }
931
+ },
806
932
  resumeFromFailed: async () => {
807
933
  const { isRunning, executionId, lastFailedNodeId } = get();
808
934
  if (isRunning || !executionId || !lastFailedNodeId) return;
@@ -812,8 +938,14 @@ var createExecutionSlice = (set, get) => ({
812
938
  if (!workflowId) {
813
939
  set({
814
940
  validationErrors: {
941
+ errors: [
942
+ {
943
+ message: "Workflow must be saved first",
944
+ nodeId: "",
945
+ severity: "error"
946
+ }
947
+ ],
815
948
  isValid: false,
816
- errors: [{ nodeId: "", message: "Workflow must be saved first", severity: "error" }],
817
949
  warnings: []
818
950
  }
819
951
  });
@@ -824,14 +956,17 @@ var createExecutionSlice = (set, get) => ({
824
956
  useUIStore.getState().setShowDebugPanel(true);
825
957
  }
826
958
  workflowStore.updateNodeData(lastFailedNodeId, {
827
- status: NodeStatusEnum.IDLE,
828
959
  error: void 0,
829
- progress: void 0
960
+ progress: void 0,
961
+ status: NodeStatusEnum.IDLE
830
962
  });
831
963
  try {
832
- const execution = await apiPost(`/workflows/${workflowId}/execute`, {
833
- debugMode
834
- });
964
+ const execution = await apiPost(
965
+ `/workflows/${workflowId}/execute`,
966
+ {
967
+ debugMode
968
+ }
969
+ );
835
970
  const newExecutionId = execution._id;
836
971
  set({ executionId: newExecutionId, lastFailedNodeId: null });
837
972
  createExecutionSubscription(newExecutionId, set);
@@ -839,19 +974,22 @@ var createExecutionSlice = (set, get) => ({
839
974
  set({
840
975
  isRunning: false,
841
976
  validationErrors: {
842
- isValid: false,
843
977
  errors: [
844
978
  {
845
- nodeId: "",
846
979
  message: error instanceof Error ? error.message : "Resume failed",
980
+ nodeId: "",
847
981
  severity: "error"
848
982
  }
849
983
  ],
984
+ isValid: false,
850
985
  warnings: []
851
986
  }
852
987
  });
853
988
  }
854
989
  },
990
+ setEstimatedCost: (cost) => {
991
+ set({ estimatedCost: cost });
992
+ },
855
993
  stopExecution: () => {
856
994
  const { eventSource, executionId } = get();
857
995
  if (eventSource) {
@@ -862,9 +1000,9 @@ var createExecutionSlice = (set, get) => ({
862
1000
  });
863
1001
  }
864
1002
  set({
865
- isRunning: false,
1003
+ currentNodeId: null,
866
1004
  eventSource: null,
867
- currentNodeId: null
1005
+ isRunning: false
868
1006
  });
869
1007
  },
870
1008
  stopNodeExecution: (nodeId) => {
@@ -881,50 +1019,10 @@ var createExecutionSlice = (set, get) => ({
881
1019
  });
882
1020
  }
883
1021
  const workflowStore = useWorkflowStore.getState();
884
- workflowStore.updateNodeData(nodeId, { status: NodeStatusEnum.IDLE, error: void 0 });
885
- },
886
- isNodeExecuting: (nodeId) => {
887
- const { activeNodeExecutions } = get();
888
- return activeNodeExecutions.has(nodeId);
889
- },
890
- clearValidationErrors: () => {
891
- set({ validationErrors: null });
892
- },
893
- resetExecution: () => {
894
- const { eventSource, activeNodeExecutions } = get();
895
- if (eventSource) {
896
- eventSource.close();
897
- }
898
- for (const nodeExecution of activeNodeExecutions.values()) {
899
- nodeExecution.eventSource.close();
900
- }
901
- set({
902
- isRunning: false,
903
- jobs: /* @__PURE__ */ new Map(),
904
- executionId: null,
905
- currentNodeId: null,
906
- executingNodeIds: [],
907
- eventSource: null,
908
- actualCost: 0,
909
- lastFailedNodeId: null,
910
- debugPayloads: [],
911
- activeNodeExecutions: /* @__PURE__ */ new Map()
1022
+ workflowStore.updateNodeData(nodeId, {
1023
+ error: void 0,
1024
+ status: NodeStatusEnum.IDLE
912
1025
  });
913
- const workflowStore = useWorkflowStore.getState();
914
- for (const node of workflowStore.nodes) {
915
- workflowStore.updateNodeData(node.id, {
916
- status: NodeStatusEnum.IDLE,
917
- error: void 0,
918
- progress: void 0
919
- });
920
- }
921
- },
922
- canResumeFromFailed: () => {
923
- const { executionId, lastFailedNodeId, isRunning } = get();
924
- return !isRunning && Boolean(executionId) && Boolean(lastFailedNodeId);
925
- },
926
- setEstimatedCost: (cost) => {
927
- set({ estimatedCost: cost });
928
1026
  }
929
1027
  });
930
1028
 
@@ -934,17 +1032,24 @@ var createJobSlice = (set, get) => ({
934
1032
  set((state) => {
935
1033
  const newJobs = new Map(state.jobs);
936
1034
  newJobs.set(predictionId, {
1035
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1036
+ error: null,
937
1037
  nodeId,
1038
+ output: null,
938
1039
  predictionId,
939
- status: "pending",
940
1040
  progress: 0,
941
- output: null,
942
- error: null,
943
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
1041
+ status: "pending"
944
1042
  });
945
1043
  return { jobs: newJobs };
946
1044
  });
947
1045
  },
1046
+ getJobByNodeId: (nodeId) => {
1047
+ const { jobs } = get();
1048
+ for (const job of jobs.values()) {
1049
+ if (job.nodeId === nodeId) return job;
1050
+ }
1051
+ return void 0;
1052
+ },
948
1053
  updateJob: (predictionId, updates) => {
949
1054
  set((state) => {
950
1055
  const newJobs = new Map(state.jobs);
@@ -954,13 +1059,6 @@ var createJobSlice = (set, get) => ({
954
1059
  }
955
1060
  return { jobs: newJobs };
956
1061
  });
957
- },
958
- getJobByNodeId: (nodeId) => {
959
- const { jobs } = get();
960
- for (const job of jobs.values()) {
961
- if (job.nodeId === nodeId) return job;
962
- }
963
- return void 0;
964
1062
  }
965
1063
  });
966
1064
 
@@ -968,20 +1066,8 @@ var createJobSlice = (set, get) => ({
968
1066
  var useExecutionStore = create()((...args) => {
969
1067
  const [set] = args;
970
1068
  return {
971
- // Initial state
972
- isRunning: false,
973
- executionId: null,
974
- currentNodeId: null,
975
- executingNodeIds: [],
976
- validationErrors: null,
977
- eventSource: null,
978
- lastFailedNodeId: null,
979
- pausedAtNodeId: null,
980
- jobs: /* @__PURE__ */ new Map(),
981
- estimatedCost: 0,
982
- actualCost: 0,
983
- debugPayloads: [],
984
1069
  activeNodeExecutions: /* @__PURE__ */ new Map(),
1070
+ actualCost: 0,
985
1071
  // Debug payload actions
986
1072
  addDebugPayload: (payload) => {
987
1073
  set((state) => ({
@@ -991,6 +1077,18 @@ var useExecutionStore = create()((...args) => {
991
1077
  clearDebugPayloads: () => {
992
1078
  set({ debugPayloads: [] });
993
1079
  },
1080
+ currentNodeId: null,
1081
+ debugPayloads: [],
1082
+ estimatedCost: 0,
1083
+ eventSource: null,
1084
+ executingNodeIds: [],
1085
+ executionId: null,
1086
+ // Initial state
1087
+ isRunning: false,
1088
+ jobs: /* @__PURE__ */ new Map(),
1089
+ lastFailedNodeId: null,
1090
+ pausedAtNodeId: null,
1091
+ validationErrors: null,
994
1092
  // Compose slices
995
1093
  ...createJobSlice(...args),
996
1094
  ...createExecutionSlice(...args)