nvent 0.4.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 (192) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +389 -0
  3. package/dist/module.d.mts +193 -0
  4. package/dist/module.json +9 -0
  5. package/dist/module.mjs +974 -0
  6. package/dist/runtime/app/components/ConfirmDialog.d.vue.ts +33 -0
  7. package/dist/runtime/app/components/ConfirmDialog.vue +121 -0
  8. package/dist/runtime/app/components/ConfirmDialog.vue.d.ts +33 -0
  9. package/dist/runtime/app/components/FlowDiagram.d.vue.ts +64 -0
  10. package/dist/runtime/app/components/FlowDiagram.vue +338 -0
  11. package/dist/runtime/app/components/FlowDiagram.vue.d.ts +64 -0
  12. package/dist/runtime/app/components/FlowNodeCard.d.vue.ts +29 -0
  13. package/dist/runtime/app/components/FlowNodeCard.vue +156 -0
  14. package/dist/runtime/app/components/FlowNodeCard.vue.d.ts +29 -0
  15. package/dist/runtime/app/components/FlowRunOverview.d.vue.ts +9 -0
  16. package/dist/runtime/app/components/FlowRunOverview.vue +291 -0
  17. package/dist/runtime/app/components/FlowRunOverview.vue.d.ts +9 -0
  18. package/dist/runtime/app/components/FlowRunStatusBadge.d.vue.ts +14 -0
  19. package/dist/runtime/app/components/FlowRunStatusBadge.vue +60 -0
  20. package/dist/runtime/app/components/FlowRunStatusBadge.vue.d.ts +14 -0
  21. package/dist/runtime/app/components/FlowRunTimeline.d.vue.ts +12 -0
  22. package/dist/runtime/app/components/FlowRunTimeline.vue +127 -0
  23. package/dist/runtime/app/components/FlowRunTimeline.vue.d.ts +12 -0
  24. package/dist/runtime/app/components/FlowScheduleDialog.d.vue.ts +16 -0
  25. package/dist/runtime/app/components/FlowScheduleDialog.vue +226 -0
  26. package/dist/runtime/app/components/FlowScheduleDialog.vue.d.ts +16 -0
  27. package/dist/runtime/app/components/FlowSchedulesList.d.vue.ts +12 -0
  28. package/dist/runtime/app/components/FlowSchedulesList.vue +99 -0
  29. package/dist/runtime/app/components/FlowSchedulesList.vue.d.ts +12 -0
  30. package/dist/runtime/app/components/JobScheduling.d.vue.ts +6 -0
  31. package/dist/runtime/app/components/JobScheduling.vue +203 -0
  32. package/dist/runtime/app/components/JobScheduling.vue.d.ts +6 -0
  33. package/dist/runtime/app/components/ListItem.d.vue.ts +23 -0
  34. package/dist/runtime/app/components/ListItem.vue +70 -0
  35. package/dist/runtime/app/components/ListItem.vue.d.ts +23 -0
  36. package/dist/runtime/app/components/QueueConfigDetails.d.vue.ts +45 -0
  37. package/dist/runtime/app/components/QueueConfigDetails.vue +412 -0
  38. package/dist/runtime/app/components/QueueConfigDetails.vue.d.ts +45 -0
  39. package/dist/runtime/app/components/StatCounter.d.vue.ts +9 -0
  40. package/dist/runtime/app/components/StatCounter.vue +25 -0
  41. package/dist/runtime/app/components/StatCounter.vue.d.ts +9 -0
  42. package/dist/runtime/app/components/TimelineList.d.vue.ts +7 -0
  43. package/dist/runtime/app/components/TimelineList.vue +210 -0
  44. package/dist/runtime/app/components/TimelineList.vue.d.ts +7 -0
  45. package/dist/runtime/app/components/nhealth/component-router.d.vue.ts +46 -0
  46. package/dist/runtime/app/components/nhealth/component-router.vue +26 -0
  47. package/dist/runtime/app/components/nhealth/component-router.vue.d.ts +46 -0
  48. package/dist/runtime/app/components/nhealth/component-shell.d.vue.ts +24 -0
  49. package/dist/runtime/app/components/nhealth/component-shell.vue +89 -0
  50. package/dist/runtime/app/components/nhealth/component-shell.vue.d.ts +24 -0
  51. package/dist/runtime/app/composables/useAnalyzedFlows.d.ts +14 -0
  52. package/dist/runtime/app/composables/useAnalyzedFlows.js +7 -0
  53. package/dist/runtime/app/composables/useComponentRouter.d.ts +38 -0
  54. package/dist/runtime/app/composables/useComponentRouter.js +240 -0
  55. package/dist/runtime/app/composables/useFlowRunTimeline.d.ts +15 -0
  56. package/dist/runtime/app/composables/useFlowRunTimeline.js +66 -0
  57. package/dist/runtime/app/composables/useFlowRuns.d.ts +11 -0
  58. package/dist/runtime/app/composables/useFlowRuns.js +31 -0
  59. package/dist/runtime/app/composables/useFlowRunsInfinite.d.ts +24 -0
  60. package/dist/runtime/app/composables/useFlowRunsInfinite.js +123 -0
  61. package/dist/runtime/app/composables/useFlowRunsPolling.d.ts +8 -0
  62. package/dist/runtime/app/composables/useFlowRunsPolling.js +26 -0
  63. package/dist/runtime/app/composables/useFlowState.d.ts +125 -0
  64. package/dist/runtime/app/composables/useFlowState.js +211 -0
  65. package/dist/runtime/app/composables/useFlowWebSocket.d.ts +27 -0
  66. package/dist/runtime/app/composables/useFlowWebSocket.js +205 -0
  67. package/dist/runtime/app/composables/useFlowsNavigation.d.ts +10 -0
  68. package/dist/runtime/app/composables/useFlowsNavigation.js +57 -0
  69. package/dist/runtime/app/composables/useQueueJobs.d.ts +20 -0
  70. package/dist/runtime/app/composables/useQueueJobs.js +20 -0
  71. package/dist/runtime/app/composables/useQueueUpdates.d.ts +26 -0
  72. package/dist/runtime/app/composables/useQueueUpdates.js +122 -0
  73. package/dist/runtime/app/composables/useQueues.d.ts +43 -0
  74. package/dist/runtime/app/composables/useQueues.js +26 -0
  75. package/dist/runtime/app/composables/useQueuesLive.d.ts +19 -0
  76. package/dist/runtime/app/composables/useQueuesLive.js +143 -0
  77. package/dist/runtime/app/pages/flows/index.d.vue.ts +3 -0
  78. package/dist/runtime/app/pages/flows/index.vue +645 -0
  79. package/dist/runtime/app/pages/flows/index.vue.d.ts +3 -0
  80. package/dist/runtime/app/pages/index.d.vue.ts +3 -0
  81. package/dist/runtime/app/pages/index.vue +34 -0
  82. package/dist/runtime/app/pages/index.vue.d.ts +3 -0
  83. package/dist/runtime/app/pages/queues/index.d.vue.ts +3 -0
  84. package/dist/runtime/app/pages/queues/index.vue +229 -0
  85. package/dist/runtime/app/pages/queues/index.vue.d.ts +3 -0
  86. package/dist/runtime/app/pages/queues/job.d.vue.ts +3 -0
  87. package/dist/runtime/app/pages/queues/job.vue +262 -0
  88. package/dist/runtime/app/pages/queues/job.vue.d.ts +3 -0
  89. package/dist/runtime/app/pages/queues/jobs.d.vue.ts +3 -0
  90. package/dist/runtime/app/pages/queues/jobs.vue +291 -0
  91. package/dist/runtime/app/pages/queues/jobs.vue.d.ts +3 -0
  92. package/dist/runtime/app/plugins/vueflow.client.d.ts +6 -0
  93. package/dist/runtime/app/plugins/vueflow.client.js +15 -0
  94. package/dist/runtime/constants.d.ts +11 -0
  95. package/dist/runtime/constants.js +11 -0
  96. package/dist/runtime/python/get_config.py +64 -0
  97. package/dist/runtime/schema.d.ts +37 -0
  98. package/dist/runtime/schema.js +20 -0
  99. package/dist/runtime/server/api/_flows/[name]/clear-history.delete.d.ts +10 -0
  100. package/dist/runtime/server/api/_flows/[name]/clear-history.delete.js +44 -0
  101. package/dist/runtime/server/api/_flows/[name]/runs.get.d.ts +7 -0
  102. package/dist/runtime/server/api/_flows/[name]/runs.get.js +53 -0
  103. package/dist/runtime/server/api/_flows/[name]/schedule.post.d.ts +2 -0
  104. package/dist/runtime/server/api/_flows/[name]/schedule.post.js +57 -0
  105. package/dist/runtime/server/api/_flows/[name]/schedules/[id].delete.d.ts +2 -0
  106. package/dist/runtime/server/api/_flows/[name]/schedules/[id].delete.js +42 -0
  107. package/dist/runtime/server/api/_flows/[name]/schedules.get.d.ts +2 -0
  108. package/dist/runtime/server/api/_flows/[name]/schedules.get.js +48 -0
  109. package/dist/runtime/server/api/_flows/[name]/start.post.d.ts +2 -0
  110. package/dist/runtime/server/api/_flows/[name]/start.post.js +9 -0
  111. package/dist/runtime/server/api/_flows/index.get.d.ts +6 -0
  112. package/dist/runtime/server/api/_flows/index.get.js +5 -0
  113. package/dist/runtime/server/api/_flows/ws.d.ts +60 -0
  114. package/dist/runtime/server/api/_flows/ws.js +183 -0
  115. package/dist/runtime/server/api/_queues/[name]/job/[id].get.d.ts +2 -0
  116. package/dist/runtime/server/api/_queues/[name]/job/[id].get.js +9 -0
  117. package/dist/runtime/server/api/_queues/[name]/job/index.get.d.ts +2 -0
  118. package/dist/runtime/server/api/_queues/[name]/job/index.get.js +18 -0
  119. package/dist/runtime/server/api/_queues/index.get.d.ts +2 -0
  120. package/dist/runtime/server/api/_queues/index.get.js +63 -0
  121. package/dist/runtime/server/api/_queues/ws.d.ts +48 -0
  122. package/dist/runtime/server/api/_queues/ws.js +200 -0
  123. package/dist/runtime/server/events/adapters/fileAdapter.d.ts +2 -0
  124. package/dist/runtime/server/events/adapters/fileAdapter.js +382 -0
  125. package/dist/runtime/server/events/adapters/memoryAdapter.d.ts +2 -0
  126. package/dist/runtime/server/events/adapters/memoryAdapter.js +171 -0
  127. package/dist/runtime/server/events/adapters/redis/redisAdapter.d.ts +2 -0
  128. package/dist/runtime/server/events/adapters/redis/redisAdapter.js +348 -0
  129. package/dist/runtime/server/events/adapters/redis/redisPubSubGateway.d.ts +29 -0
  130. package/dist/runtime/server/events/adapters/redis/redisPubSubGateway.js +82 -0
  131. package/dist/runtime/server/events/eventBus.d.ts +20 -0
  132. package/dist/runtime/server/events/eventBus.js +35 -0
  133. package/dist/runtime/server/events/eventStoreFactory.d.ts +19 -0
  134. package/dist/runtime/server/events/eventStoreFactory.js +44 -0
  135. package/dist/runtime/server/events/streamNames.d.ts +17 -0
  136. package/dist/runtime/server/events/streamNames.js +17 -0
  137. package/dist/runtime/server/events/types.d.ts +63 -0
  138. package/dist/runtime/server/events/types.js +0 -0
  139. package/dist/runtime/server/events/wiring/flowWiring.d.ts +33 -0
  140. package/dist/runtime/server/events/wiring/flowWiring.js +406 -0
  141. package/dist/runtime/server/events/wiring/registry.d.ts +10 -0
  142. package/dist/runtime/server/events/wiring/registry.js +24 -0
  143. package/dist/runtime/server/plugins/00.event-store.d.ts +13 -0
  144. package/dist/runtime/server/plugins/00.event-store.js +16 -0
  145. package/dist/runtime/server/plugins/00.ws-lifecycle.d.ts +5 -0
  146. package/dist/runtime/server/plugins/00.ws-lifecycle.js +66 -0
  147. package/dist/runtime/server/plugins/flow-management.d.ts +13 -0
  148. package/dist/runtime/server/plugins/flow-management.js +65 -0
  149. package/dist/runtime/server/plugins/queue-management.d.ts +2 -0
  150. package/dist/runtime/server/plugins/queue-management.js +27 -0
  151. package/dist/runtime/server/plugins/state-cleanup.d.ts +11 -0
  152. package/dist/runtime/server/plugins/state-cleanup.js +93 -0
  153. package/dist/runtime/server/plugins/worker-management.d.ts +2 -0
  154. package/dist/runtime/server/plugins/worker-management.js +33 -0
  155. package/dist/runtime/server/queue/adapters/bullmq.d.ts +17 -0
  156. package/dist/runtime/server/queue/adapters/bullmq.js +164 -0
  157. package/dist/runtime/server/queue/queueFactory.d.ts +3 -0
  158. package/dist/runtime/server/queue/queueFactory.js +10 -0
  159. package/dist/runtime/server/queue/types.d.ts +47 -0
  160. package/dist/runtime/server/queue/types.js +0 -0
  161. package/dist/runtime/server/state/adapters/redis.d.ts +2 -0
  162. package/dist/runtime/server/state/adapters/redis.js +42 -0
  163. package/dist/runtime/server/state/stateFactory.d.ts +3 -0
  164. package/dist/runtime/server/state/stateFactory.js +17 -0
  165. package/dist/runtime/server/state/types.d.ts +23 -0
  166. package/dist/runtime/server/state/types.js +0 -0
  167. package/dist/runtime/server/tsconfig.json +3 -0
  168. package/dist/runtime/server/utils/defineQueueConfig.d.ts +154 -0
  169. package/dist/runtime/server/utils/defineQueueConfig.js +2 -0
  170. package/dist/runtime/server/utils/defineQueueWorker.d.ts +10 -0
  171. package/dist/runtime/server/utils/defineQueueWorker.js +17 -0
  172. package/dist/runtime/server/utils/useEventManager.d.ts +15 -0
  173. package/dist/runtime/server/utils/useEventManager.js +26 -0
  174. package/dist/runtime/server/utils/useEventStore.d.ts +20 -0
  175. package/dist/runtime/server/utils/useEventStore.js +119 -0
  176. package/dist/runtime/server/utils/useFlowEngine.d.ts +9 -0
  177. package/dist/runtime/server/utils/useFlowEngine.js +44 -0
  178. package/dist/runtime/server/utils/useLogs.d.ts +41 -0
  179. package/dist/runtime/server/utils/useLogs.js +74 -0
  180. package/dist/runtime/server/utils/useQueue.d.ts +31 -0
  181. package/dist/runtime/server/utils/useQueue.js +24 -0
  182. package/dist/runtime/server/utils/useServerLogger.d.ts +42 -0
  183. package/dist/runtime/server/utils/useServerLogger.js +54 -0
  184. package/dist/runtime/server/utils/wsPeerManager.d.ts +34 -0
  185. package/dist/runtime/server/utils/wsPeerManager.js +23 -0
  186. package/dist/runtime/server/worker/adapter.d.ts +4 -0
  187. package/dist/runtime/server/worker/adapter.js +65 -0
  188. package/dist/runtime/server/worker/runner/node.d.ts +27 -0
  189. package/dist/runtime/server/worker/runner/node.js +196 -0
  190. package/dist/runtime/types.d.ts +132 -0
  191. package/dist/types.d.mts +3 -0
  192. package/package.json +75 -0
@@ -0,0 +1,211 @@
1
+ import { ref, computed } from "vue";
2
+ export function reduceFlowState(events) {
3
+ const state = {
4
+ status: "running",
5
+ steps: {},
6
+ logs: []
7
+ };
8
+ for (const e of events) {
9
+ const eventType = e.type;
10
+ const stepKey = e.stepName;
11
+ switch (eventType) {
12
+ case "flow.start":
13
+ case "flow.started":
14
+ state.status = "running";
15
+ state.startedAt = e.ts;
16
+ if (e.flowName) state.meta = { ...state.meta, flowName: e.flowName };
17
+ if (e.data?.flowName) state.meta = { ...state.meta, flowName: e.data.flowName };
18
+ if (e.data?.input) state.meta = { ...state.meta, input: e.data.input };
19
+ break;
20
+ case "flow.complete":
21
+ case "flow.completed":
22
+ state.status = "completed";
23
+ state.completedAt = e.ts;
24
+ if (e.data?.result) state.meta = { ...state.meta, result: e.data.result };
25
+ break;
26
+ case "flow.failed":
27
+ state.status = "failed";
28
+ state.completedAt = e.ts;
29
+ if (e.data?.error) state.meta = { ...state.meta, error: e.data.error };
30
+ break;
31
+ case "step.started": {
32
+ if (!stepKey) break;
33
+ if (!state.steps[stepKey]) {
34
+ state.steps[stepKey] = {
35
+ status: "running",
36
+ attempt: 1
37
+ };
38
+ }
39
+ const currentStatus = state.steps[stepKey].status;
40
+ if (currentStatus !== "completed" && currentStatus !== "failed" && currentStatus !== "timeout") {
41
+ state.steps[stepKey].status = "running";
42
+ }
43
+ state.steps[stepKey].startedAt = e.ts;
44
+ state.steps[stepKey].attempt = e.attempt || state.steps[stepKey].attempt || 1;
45
+ break;
46
+ }
47
+ case "step.completed": {
48
+ if (!stepKey) break;
49
+ if (!state.steps[stepKey]) {
50
+ state.steps[stepKey] = { status: "completed", attempt: 1 };
51
+ }
52
+ state.steps[stepKey].status = "completed";
53
+ state.steps[stepKey].completedAt = e.ts;
54
+ if (e.data?.result !== void 0) state.steps[stepKey].result = e.data.result;
55
+ break;
56
+ }
57
+ case "step.failed": {
58
+ if (!stepKey) break;
59
+ if (!state.steps[stepKey]) {
60
+ state.steps[stepKey] = { status: "failed", attempt: 1 };
61
+ }
62
+ const willRetry = e.data?.willRetry || e.data?.retry;
63
+ state.steps[stepKey].status = willRetry ? "retrying" : "failed";
64
+ state.steps[stepKey].error = e.data?.error || e.data?.message;
65
+ if (!willRetry) {
66
+ state.steps[stepKey].completedAt = e.ts;
67
+ }
68
+ break;
69
+ }
70
+ case "step.retry": {
71
+ if (!stepKey) break;
72
+ if (!state.steps[stepKey]) {
73
+ state.steps[stepKey] = { status: "retrying", attempt: 1 };
74
+ }
75
+ state.steps[stepKey].status = "retrying";
76
+ state.steps[stepKey].attempt = e.data?.nextAttempt || e.attempt || 1;
77
+ state.steps[stepKey].error = e.data?.error;
78
+ break;
79
+ }
80
+ case "step.await.time":
81
+ case "step.await.event":
82
+ case "step.await.trigger": {
83
+ if (!stepKey) break;
84
+ if (!state.steps[stepKey]) {
85
+ state.steps[stepKey] = { status: "waiting", attempt: 1 };
86
+ }
87
+ state.steps[stepKey].status = "waiting";
88
+ state.steps[stepKey].awaitType = eventType.split(".")[2];
89
+ state.steps[stepKey].awaitData = e.data;
90
+ break;
91
+ }
92
+ case "step.resumed": {
93
+ if (!stepKey) break;
94
+ if (!state.steps[stepKey]) {
95
+ state.steps[stepKey] = { status: "running", attempt: 1 };
96
+ }
97
+ state.steps[stepKey].status = "running";
98
+ delete state.steps[stepKey].awaitType;
99
+ delete state.steps[stepKey].awaitData;
100
+ break;
101
+ }
102
+ case "step.await.timeout": {
103
+ if (!stepKey) break;
104
+ if (!state.steps[stepKey]) {
105
+ state.steps[stepKey] = { status: "timeout", attempt: 1 };
106
+ }
107
+ state.steps[stepKey].status = "timeout";
108
+ state.steps[stepKey].error = `Await timeout after ${e.data?.duration}ms`;
109
+ state.steps[stepKey].completedAt = e.ts;
110
+ break;
111
+ }
112
+ case "runner.log":
113
+ case "log": {
114
+ state.logs.push({
115
+ ts: e.ts,
116
+ step: stepKey,
117
+ level: e.data?.level || "info",
118
+ msg: e.data?.message || e.data?.msg || (typeof e.data === "string" ? e.data : String(e.data)),
119
+ data: e.data
120
+ });
121
+ break;
122
+ }
123
+ // Handle any unrecognized events - log for debugging
124
+ default: {
125
+ if (typeof console !== "undefined" && eventType && !eventType.startsWith("_")) {
126
+ console.debug("[useFlowState] Unhandled event type:", eventType, {
127
+ stepName: e.stepName,
128
+ stepKey,
129
+ data: e.data
130
+ });
131
+ }
132
+ }
133
+ }
134
+ }
135
+ if (!state.startedAt && events.length > 0 && events[0]) {
136
+ state.startedAt = events[0].ts;
137
+ }
138
+ if (state.status === "running" && state.startedAt && Object.keys(state.steps).length > 0) {
139
+ const hasRunningSteps = Object.values(state.steps).some(
140
+ (s) => s.status === "running" || s.status === "retrying" || s.status === "waiting"
141
+ );
142
+ const hasFailedSteps = Object.values(state.steps).some((s) => s.status === "failed");
143
+ const allStepsTerminal = Object.values(state.steps).every(
144
+ (s) => s.status === "completed" || s.status === "failed" || s.status === "timeout"
145
+ );
146
+ if (!hasRunningSteps && allStepsTerminal) {
147
+ if (hasFailedSteps) {
148
+ state.status = "failed";
149
+ } else {
150
+ state.status = "completed";
151
+ }
152
+ const latestCompletion = Object.values(state.steps).map((s) => s.completedAt).filter(Boolean).sort().pop();
153
+ if (latestCompletion) {
154
+ state.completedAt = latestCompletion;
155
+ }
156
+ }
157
+ }
158
+ return state;
159
+ }
160
+ export function useFlowState(initialEvents = []) {
161
+ const events = ref(initialEvents);
162
+ const state = computed(() => reduceFlowState(events.value));
163
+ const addEvent = (event) => {
164
+ events.value.push(event);
165
+ };
166
+ const addEvents = (newEvents) => {
167
+ events.value.push(...newEvents);
168
+ };
169
+ const reset = (newEvents = []) => {
170
+ events.value = newEvents;
171
+ };
172
+ const isRunning = computed(() => state.value.status === "running");
173
+ const isCompleted = computed(() => state.value.status === "completed");
174
+ const isFailed = computed(() => state.value.status === "failed");
175
+ const stepList = computed(() => {
176
+ return Object.entries(state.value.steps).map(([key, step]) => ({
177
+ key,
178
+ ...step
179
+ }));
180
+ });
181
+ const runningSteps = computed(() => {
182
+ return stepList.value.filter((s) => s.status === "running");
183
+ });
184
+ const waitingSteps = computed(() => {
185
+ return stepList.value.filter((s) => s.status === "waiting");
186
+ });
187
+ const failedSteps = computed(() => {
188
+ return stepList.value.filter((s) => s.status === "failed");
189
+ });
190
+ const completedSteps = computed(() => {
191
+ return stepList.value.filter((s) => s.status === "completed");
192
+ });
193
+ return {
194
+ // Raw data
195
+ events,
196
+ state,
197
+ // Methods
198
+ addEvent,
199
+ addEvents,
200
+ reset,
201
+ // Computed helpers
202
+ isRunning,
203
+ isCompleted,
204
+ isFailed,
205
+ stepList,
206
+ runningSteps,
207
+ waitingSteps,
208
+ failedSteps,
209
+ completedSteps
210
+ };
211
+ }
@@ -0,0 +1,27 @@
1
+ export interface UseFlowWebSocketOptions {
2
+ autoReconnect?: boolean;
3
+ maxRetries?: number;
4
+ baseDelayMs?: number;
5
+ maxDelayMs?: number;
6
+ onOpen?: () => void;
7
+ onError?: (err?: any) => void;
8
+ onClose?: (event?: CloseEvent) => void;
9
+ }
10
+ export interface FlowSubscription {
11
+ flowName: string;
12
+ runId: string;
13
+ onEvent: (event: any) => void;
14
+ onHistory?: (events: any[]) => void;
15
+ }
16
+ /**
17
+ * WebSocket composable for flow run events
18
+ * Replaces the SSE-based useEventSSE with a more reliable WebSocket implementation
19
+ */
20
+ export declare function useFlowWebSocket(): {
21
+ subscribe: (subscription: FlowSubscription, opts?: UseFlowWebSocketOptions) => void;
22
+ unsubscribe: () => void;
23
+ stop: () => void;
24
+ connected: import("vue").Ref<boolean, boolean>;
25
+ reconnecting: import("vue").Ref<boolean, boolean>;
26
+ };
27
+ export default useFlowWebSocket;
@@ -0,0 +1,205 @@
1
+ import { ref, onBeforeUnmount } from "#imports";
2
+ export function useFlowWebSocket() {
3
+ const ws = ref(null);
4
+ const connected = ref(false);
5
+ const reconnecting = ref(false);
6
+ let retry = 0;
7
+ let reconnectTimer = null;
8
+ let currentOptions;
9
+ let currentSubscription = null;
10
+ let pingInterval = null;
11
+ let isServerRestarting = false;
12
+ const computeDelay = (opts) => {
13
+ const base = Math.max(100, opts?.baseDelayMs ?? 1e3);
14
+ const max = Math.max(base, opts?.maxDelayMs ?? 1e4);
15
+ const exp = Math.min(max, base * Math.pow(2, retry));
16
+ const jitter = Math.floor(Math.random() * Math.min(1e3, exp / 4));
17
+ return exp + jitter;
18
+ };
19
+ const clearTimers = () => {
20
+ if (reconnectTimer) {
21
+ try {
22
+ clearTimeout(reconnectTimer);
23
+ } catch {
24
+ }
25
+ reconnectTimer = null;
26
+ }
27
+ if (pingInterval) {
28
+ try {
29
+ clearInterval(pingInterval);
30
+ } catch {
31
+ }
32
+ pingInterval = null;
33
+ }
34
+ };
35
+ const send = (data) => {
36
+ if (ws.value && ws.value.readyState === WebSocket.OPEN) {
37
+ ws.value.send(JSON.stringify(data));
38
+ }
39
+ };
40
+ const startPingInterval = () => {
41
+ clearTimers();
42
+ pingInterval = setInterval(() => {
43
+ if (ws.value && ws.value.readyState === WebSocket.OPEN) {
44
+ send({ type: "ping" });
45
+ }
46
+ }, 3e4);
47
+ };
48
+ const stop = () => {
49
+ clearTimers();
50
+ isServerRestarting = false;
51
+ try {
52
+ if (ws.value) {
53
+ ws.value.close(1e3, "Client closing");
54
+ }
55
+ } catch (err) {
56
+ console.warn("[useFlowWebSocket] Error closing WebSocket:", err);
57
+ }
58
+ ws.value = null;
59
+ connected.value = false;
60
+ reconnecting.value = false;
61
+ retry = 0;
62
+ currentSubscription = null;
63
+ };
64
+ const attemptReconnect = () => {
65
+ if (!currentOptions?.autoReconnect) {
66
+ stop();
67
+ return;
68
+ }
69
+ const max = Math.max(0, currentOptions?.maxRetries ?? 10);
70
+ if (retry >= max) {
71
+ console.error("[useFlowWebSocket] Max retries reached");
72
+ stop();
73
+ return;
74
+ }
75
+ retry++;
76
+ reconnecting.value = true;
77
+ const baseDelay = isServerRestarting ? 2e3 : computeDelay(currentOptions);
78
+ const delay = baseDelay;
79
+ console.log(`[useFlowWebSocket] Will attempt reconnection in ${delay}ms (attempt ${retry}/${max})${isServerRestarting ? " [server restart]" : ""}`);
80
+ clearTimers();
81
+ reconnectTimer = setTimeout(() => {
82
+ if (currentSubscription) {
83
+ innerSubscribe(currentSubscription, currentOptions);
84
+ }
85
+ }, delay);
86
+ };
87
+ const setupWebSocket = (socket, subscription, opts) => {
88
+ socket.onopen = () => {
89
+ console.log("[useFlowWebSocket] Connected");
90
+ connected.value = true;
91
+ reconnecting.value = false;
92
+ retry = 0;
93
+ startPingInterval();
94
+ send({
95
+ type: "subscribe",
96
+ flowName: subscription.flowName,
97
+ runId: subscription.runId
98
+ });
99
+ opts?.onOpen?.();
100
+ };
101
+ socket.onmessage = (event) => {
102
+ try {
103
+ const data = JSON.parse(event.data);
104
+ switch (data.type) {
105
+ case "connected":
106
+ console.log("[useFlowWebSocket] Server acknowledged connection");
107
+ break;
108
+ case "subscribed":
109
+ console.log("[useFlowWebSocket] Subscribed to flow:", data.flowName, data.runId);
110
+ break;
111
+ case "unsubscribed":
112
+ console.log("[useFlowWebSocket] Unsubscribed from flow:", data.flowName, data.runId);
113
+ break;
114
+ case "history":
115
+ if (subscription.onHistory) {
116
+ subscription.onHistory(data.events);
117
+ } else {
118
+ for (const eventData of data.events) {
119
+ subscription.onEvent(eventData);
120
+ }
121
+ }
122
+ break;
123
+ case "event":
124
+ subscription.onEvent(data.event);
125
+ break;
126
+ case "pong":
127
+ break;
128
+ case "server-restart":
129
+ console.log("[useFlowWebSocket] Server is restarting (HMR)");
130
+ isServerRestarting = true;
131
+ break;
132
+ case "error":
133
+ console.error("[useFlowWebSocket] Server error:", data.message);
134
+ opts?.onError?.(new Error(data.message));
135
+ break;
136
+ default:
137
+ console.warn("[useFlowWebSocket] Unknown message type:", data.type);
138
+ }
139
+ } catch (err) {
140
+ console.error("[useFlowWebSocket] Error parsing message:", err);
141
+ }
142
+ };
143
+ socket.onerror = (err) => {
144
+ console.error("[useFlowWebSocket] WebSocket error:", err);
145
+ opts?.onError?.(err);
146
+ };
147
+ socket.onclose = (event) => {
148
+ console.log("[useFlowWebSocket] Connection closed:", event.code, event.reason);
149
+ connected.value = false;
150
+ clearTimers();
151
+ opts?.onClose?.(event);
152
+ const shouldReconnect = event.code !== 1e3 && opts?.autoReconnect;
153
+ if (shouldReconnect) {
154
+ console.log("[useFlowWebSocket] Will attempt reconnection (code:", event.code, ")");
155
+ attemptReconnect();
156
+ } else {
157
+ isServerRestarting = false;
158
+ }
159
+ };
160
+ };
161
+ const innerSubscribe = (subscription, opts) => {
162
+ if (import.meta.server || typeof WebSocket === "undefined") {
163
+ console.warn("[useFlowWebSocket] WebSocket not available (SSR context)");
164
+ return;
165
+ }
166
+ if (ws.value) {
167
+ stop();
168
+ }
169
+ currentOptions = opts;
170
+ currentSubscription = subscription;
171
+ try {
172
+ const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
173
+ const wsUrl = `${protocol}//${window.location.host}/api/_flows/ws`;
174
+ const socket = new WebSocket(wsUrl);
175
+ ws.value = socket;
176
+ setupWebSocket(socket, subscription, opts);
177
+ } catch (err) {
178
+ console.error("[useFlowWebSocket] Error creating WebSocket:", err);
179
+ opts?.onError?.(err);
180
+ attemptReconnect();
181
+ }
182
+ };
183
+ const subscribe = (subscription, opts) => {
184
+ innerSubscribe(subscription, opts);
185
+ };
186
+ const unsubscribe = () => {
187
+ if (currentSubscription && ws.value && ws.value.readyState === WebSocket.OPEN) {
188
+ send({
189
+ type: "unsubscribe",
190
+ flowName: currentSubscription.flowName,
191
+ runId: currentSubscription.runId
192
+ });
193
+ }
194
+ currentSubscription = null;
195
+ };
196
+ onBeforeUnmount(() => stop());
197
+ return {
198
+ subscribe,
199
+ unsubscribe,
200
+ stop,
201
+ connected,
202
+ reconnecting
203
+ };
204
+ }
205
+ export default useFlowWebSocket;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Composable for managing flows page navigation state
3
+ * Uses URL query params for persistence across HMR
4
+ */
5
+ export declare function useFlowsNavigation(): {
6
+ selectedFlow: any;
7
+ selectedRunId: any;
8
+ timelineOpen: any;
9
+ selectedTab: any;
10
+ };
@@ -0,0 +1,57 @@
1
+ export function useFlowsNavigation() {
2
+ const route = useRoute();
3
+ const router = useRouter();
4
+ const selectedFlow = computed({
5
+ get: () => route.query.flow || "",
6
+ set: (value) => {
7
+ router.push({
8
+ query: {
9
+ ...route.query,
10
+ flow: value || void 0,
11
+ run: void 0
12
+ // Clear run when flow changes
13
+ }
14
+ });
15
+ }
16
+ });
17
+ const selectedRunId = computed({
18
+ get: () => route.query.run || "",
19
+ set: (value) => {
20
+ router.push({
21
+ query: {
22
+ ...route.query,
23
+ run: value || void 0
24
+ }
25
+ });
26
+ }
27
+ });
28
+ const timelineOpen = ref(route.query.timeline === "true");
29
+ watch(timelineOpen, (value) => {
30
+ router.push({
31
+ query: {
32
+ ...route.query,
33
+ timeline: value ? "true" : void 0
34
+ }
35
+ });
36
+ });
37
+ watch(() => route.query.timeline, (value) => {
38
+ timelineOpen.value = value === "true";
39
+ });
40
+ const selectedTab = computed({
41
+ get: () => route.query.tab || "overview",
42
+ set: (value) => {
43
+ router.push({
44
+ query: {
45
+ ...route.query,
46
+ tab: value !== "overview" ? value : void 0
47
+ }
48
+ });
49
+ }
50
+ });
51
+ return {
52
+ selectedFlow,
53
+ selectedRunId,
54
+ timelineOpen,
55
+ selectedTab
56
+ };
57
+ }
@@ -0,0 +1,20 @@
1
+ import { type Ref } from '#imports';
2
+ export interface Job {
3
+ id: string;
4
+ name: string;
5
+ data: any;
6
+ state?: 'waiting' | 'active' | 'completed' | 'failed' | 'delayed' | 'paused';
7
+ returnvalue?: any;
8
+ failedReason?: string;
9
+ timestamp?: number;
10
+ processedOn?: number;
11
+ finishedOn?: number;
12
+ }
13
+ export interface JobsResponse {
14
+ jobs: Job[];
15
+ }
16
+ /**
17
+ * Composable for fetching jobs for a queue
18
+ * Client-only to avoid hydration mismatches
19
+ */
20
+ export declare function useQueueJobs(queueName: Ref<string>, state?: Ref<string | null>): any;
@@ -0,0 +1,20 @@
1
+ import { ref } from "#imports";
2
+ export function useQueueJobs(queueName, state = ref(null)) {
3
+ return useFetch(
4
+ () => {
5
+ const params = new URLSearchParams();
6
+ if (state.value) {
7
+ params.append("state", state.value);
8
+ }
9
+ const queryString = params.toString();
10
+ return `/api/_queues/${encodeURIComponent(queueName.value)}/job${queryString ? `?${queryString}` : ""}`;
11
+ },
12
+ {
13
+ key: () => `queue-jobs-${queueName.value}-${state.value || "all"}`,
14
+ watch: [queueName, state],
15
+ immediate: true,
16
+ server: false
17
+ // Client-only
18
+ }
19
+ );
20
+ }
@@ -0,0 +1,26 @@
1
+ import { type Ref } from '#imports';
2
+ /**
3
+ * Composable for real-time queue updates via WebSocket
4
+ */
5
+ export declare function useQueueUpdates(queueName: Ref<string>): {
6
+ isConnected: import("vue").ComputedRef<boolean>;
7
+ isReconnecting: import("vue").ComputedRef<boolean>;
8
+ counts: import("vue").ComputedRef<{
9
+ active: number;
10
+ completed: number;
11
+ failed: number;
12
+ delayed: number;
13
+ waiting: number;
14
+ paused: number;
15
+ } | null>;
16
+ lastEvent: import("vue").ComputedRef<{
17
+ [x: string]: any;
18
+ eventType: "waiting" | "active" | "completed" | "failed" | "progress";
19
+ jobId?: string | undefined;
20
+ } | null>;
21
+ countsUpdatedAt: import("vue").ComputedRef<number | null>;
22
+ shouldRefreshJobs: import("vue").ComputedRef<boolean>;
23
+ resetRefreshFlag: () => void;
24
+ connect: () => void;
25
+ disconnect: () => void;
26
+ };