@genfeedai/workflow-ui 0.1.0

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