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,974 @@
1
+ import { dirname, join, extname, relative } from 'node:path';
2
+ import { useLogger, defineNuxtModule, createResolver, addServerScanDir, addImportsDir, addPlugin, addComponentsDir, addComponent, addTemplate, addServerImports, updateTemplates } from '@nuxt/kit';
3
+ import defu from 'defu';
4
+ import { existsSync, realpathSync } from 'node:fs';
5
+ import { globby } from 'globby';
6
+ import { pathToFileURL, fileURLToPath } from 'node:url';
7
+ import { readFile } from 'node:fs/promises';
8
+ import { parseModule } from 'magicast';
9
+ import { spawn } from 'node:child_process';
10
+ import chokidar from 'chokidar';
11
+ import { join as join$1 } from 'pathe';
12
+ import { debounce } from 'perfect-debounce';
13
+
14
+ async function loadJsConfig(absPath) {
15
+ const cacheBust = `?t=${Date.now()}`;
16
+ const mod = await import(pathToFileURL(absPath).href + cacheBust);
17
+ const cfg = mod?.config;
18
+ const queueName = cfg && typeof cfg.queue === "object" && cfg.queue ? cfg.queue?.name : void 0;
19
+ const isolate = cfg?.runner?.ts?.isolate || cfg?.runner?.isolate || cfg?.isolate;
20
+ const runtype = isolate === "task" ? "task" : isolate === "inprocess" ? "inprocess" : void 0;
21
+ const flowCfg = cfg?.flow;
22
+ let flow;
23
+ if (flowCfg) {
24
+ const subscribes = Array.isArray(flowCfg.subscribes) ? flowCfg.subscribes : typeof flowCfg.subscribes === "string" ? [flowCfg.subscribes] : void 0;
25
+ const names = Array.isArray(flowCfg.name) ? flowCfg.name.filter((s) => typeof s === "string" && s.length > 0) : typeof flowCfg.name === "string" && flowCfg.name.length > 0 ? [flowCfg.name] : [];
26
+ if (names.length) {
27
+ flow = {
28
+ names,
29
+ role: flowCfg.role,
30
+ step: flowCfg.step,
31
+ emits: flowCfg.emits,
32
+ subscribes
33
+ };
34
+ }
35
+ }
36
+ const queueCfg = cfg?.queue && typeof cfg.queue === "object" ? {
37
+ name: cfg.queue.name,
38
+ defaultJobOptions: cfg.queue.defaultJobOptions,
39
+ prefix: cfg.queue.prefix,
40
+ limiter: cfg.queue.limiter
41
+ } : void 0;
42
+ const workerCfg = cfg?.worker && typeof cfg.worker === "object" ? { ...cfg.worker } : void 0;
43
+ const hasDefaultExport = !!(mod && mod.default);
44
+ return { queueName, flow, runtype, queue: queueCfg, worker: workerCfg, hasDefaultExport };
45
+ }
46
+
47
+ async function loadTsConfig(absPath) {
48
+ try {
49
+ const source = await readFile(absPath, "utf-8");
50
+ const mod = parseModule(source);
51
+ const hasDefaultExport = !!mod.exports.default;
52
+ const configExport = mod.exports.config;
53
+ if (!configExport) {
54
+ return { hasDefaultExport };
55
+ }
56
+ const cfg = extractConfigValue(configExport);
57
+ const queueName = cfg && typeof cfg.queue === "object" && cfg.queue ? cfg.queue?.name : void 0;
58
+ const isolate = cfg?.runner?.ts?.isolate || cfg?.runner?.isolate || cfg?.isolate;
59
+ const runtype = isolate === "task" ? "task" : isolate === "inprocess" ? "inprocess" : void 0;
60
+ const flowCfg = cfg?.flow;
61
+ let flow;
62
+ if (flowCfg) {
63
+ const subscribes = Array.isArray(flowCfg.subscribes) ? flowCfg.subscribes : typeof flowCfg.subscribes === "string" ? [flowCfg.subscribes] : void 0;
64
+ const names = Array.isArray(flowCfg.name) ? flowCfg.name.filter((s) => typeof s === "string" && s.length > 0) : typeof flowCfg.name === "string" && flowCfg.name.length > 0 ? [flowCfg.name] : [];
65
+ if (names.length) {
66
+ flow = {
67
+ names,
68
+ role: flowCfg.role,
69
+ step: flowCfg.step,
70
+ emits: flowCfg.emits,
71
+ subscribes
72
+ };
73
+ }
74
+ }
75
+ const queueCfg = cfg?.queue && typeof cfg.queue === "object" ? {
76
+ name: cfg.queue.name,
77
+ defaultJobOptions: cfg.queue.defaultJobOptions,
78
+ prefix: cfg.queue.prefix,
79
+ limiter: cfg.queue.limiter
80
+ } : void 0;
81
+ const workerCfg = cfg?.worker && typeof cfg.worker === "object" ? { ...cfg.worker } : void 0;
82
+ return { queueName, flow, runtype, queue: queueCfg, worker: workerCfg, hasDefaultExport };
83
+ } catch (error) {
84
+ throw new Error(`Failed to parse config from ${absPath}: ${error}`);
85
+ }
86
+ }
87
+ function extractConfigValue(value) {
88
+ if (value && typeof value === "object" && "$ast" in value) {
89
+ return astToValue(value.$ast);
90
+ }
91
+ return value;
92
+ }
93
+ function astToValue(node) {
94
+ if (!node) return void 0;
95
+ switch (node.type) {
96
+ case "CallExpression":
97
+ if (node.arguments?.length > 0) {
98
+ return astToValue(node.arguments[0]);
99
+ }
100
+ return void 0;
101
+ case "ObjectExpression":
102
+ return node.properties?.reduce((obj, prop) => {
103
+ if (prop.type === "ObjectProperty" || prop.type === "Property") {
104
+ const key = prop.key.type === "Identifier" ? prop.key.name : prop.key.value;
105
+ obj[key] = astToValue(prop.value);
106
+ }
107
+ return obj;
108
+ }, {}) || {};
109
+ case "ArrayExpression":
110
+ return node.elements?.map((el) => astToValue(el)) || [];
111
+ case "Literal":
112
+ case "StringLiteral":
113
+ case "NumericLiteral":
114
+ case "BooleanLiteral":
115
+ return node.value;
116
+ case "Identifier":
117
+ return void 0;
118
+ case "TemplateLiteral":
119
+ if (node.expressions?.length === 0 && node.quasis?.length === 1) {
120
+ return node.quasis[0].value.cooked;
121
+ }
122
+ return void 0;
123
+ default:
124
+ return void 0;
125
+ }
126
+ }
127
+
128
+ async function loadPyConfig(absPath, logger) {
129
+ const moduleDir = dirname(fileURLToPath(import.meta.url));
130
+ const helper = join(moduleDir, "..", "..", "runtime", "python", "get_config.py");
131
+ let pyConfig;
132
+ if (existsSync(helper)) {
133
+ pyConfig = await new Promise((resolve) => {
134
+ try {
135
+ const child = spawn("python3", [helper, absPath], {
136
+ stdio: ["ignore", "pipe", "pipe", "pipe"],
137
+ env: { ...process.env, NODE_CHANNEL_FD: "3" }
138
+ });
139
+ let dataBuf = "";
140
+ const fd = child.stdio[3];
141
+ const stream = fd || child.stdout;
142
+ stream.setEncoding("utf-8");
143
+ stream.on("data", (chunk) => {
144
+ dataBuf += chunk;
145
+ });
146
+ child.on("error", () => resolve(void 0));
147
+ child.on("close", () => {
148
+ const line = dataBuf.split("\n").find((l) => l.trim().length > 0);
149
+ if (!line) return resolve(void 0);
150
+ try {
151
+ resolve(JSON.parse(line));
152
+ } catch {
153
+ resolve(void 0);
154
+ }
155
+ });
156
+ } catch {
157
+ resolve(void 0);
158
+ }
159
+ });
160
+ } else {
161
+ logger?.warn?.("Python helper not found, skipping config extraction:", helper);
162
+ }
163
+ let queueName;
164
+ let flow;
165
+ if (pyConfig) {
166
+ queueName = pyConfig?.queue && typeof pyConfig.queue === "object" ? pyConfig.queue?.name : void 0;
167
+ const flowCfg = pyConfig?.flow;
168
+ if (flowCfg && typeof flowCfg === "object") {
169
+ const subscribes = Array.isArray(flowCfg.subscribes) ? flowCfg.subscribes : typeof flowCfg.subscribes === "string" ? [flowCfg.subscribes] : void 0;
170
+ const names = Array.isArray(flowCfg.name) ? flowCfg.name.filter((s) => typeof s === "string" && s.length > 0) : typeof flowCfg.name === "string" && flowCfg.name.length > 0 ? [flowCfg.name] : [];
171
+ if (names.length) {
172
+ flow = {
173
+ names,
174
+ role: flowCfg.role,
175
+ step: flowCfg.step,
176
+ emits: flowCfg.emits,
177
+ subscribes
178
+ };
179
+ }
180
+ }
181
+ }
182
+ return { queueName, flow, hasDefaultExport: true };
183
+ }
184
+
185
+ async function scanWorkers(layers, queuesDir = "queues") {
186
+ const logger = useLogger();
187
+ const workerByVirtualPath = /* @__PURE__ */ new Map();
188
+ const seenFiles = /* @__PURE__ */ new Set();
189
+ const flowSources = [];
190
+ for (const layer of layers) {
191
+ const base = join(layer.serverDir, queuesDir);
192
+ if (!existsSync(base)) continue;
193
+ const files = await globby("**/*.{ts,js,mjs,cjs,mts,cts,py}", { cwd: base, dot: false });
194
+ for (const rel of files) {
195
+ const abs = join(base, rel);
196
+ try {
197
+ let key = abs;
198
+ try {
199
+ key = realpathSync(abs);
200
+ } catch {
201
+ }
202
+ key = key.replace(/\\/g, "/");
203
+ if (seenFiles.has(key)) continue;
204
+ seenFiles.add(key);
205
+ const ext = extname(abs).toLowerCase();
206
+ const id = rel.replace(/\.[^.]+$/, "");
207
+ let queueName;
208
+ let flow;
209
+ if (ext === ".js" || ext === ".mjs" || ext === ".cjs") {
210
+ const meta = await loadJsConfig(abs);
211
+ flow = meta.flow;
212
+ const hasDefaultExport = !!meta.hasDefaultExport;
213
+ if (hasDefaultExport) {
214
+ const kind = "ts";
215
+ const virtualPath = relative(layer.serverDir, abs).replace(/\\/g, "/");
216
+ queueName = String(meta.queue?.name || meta.queueName || (id.split("/").pop() || id));
217
+ workerByVirtualPath.set(virtualPath, {
218
+ id,
219
+ kind,
220
+ filePath: virtualPath,
221
+ absPath: abs,
222
+ exportName: "default",
223
+ queue: {
224
+ name: queueName,
225
+ defaultJobOptions: meta.queue?.defaultJobOptions,
226
+ prefix: meta.queue?.prefix,
227
+ limiter: meta.queue?.limiter
228
+ },
229
+ worker: meta.worker,
230
+ flow,
231
+ runtype: meta.runtype
232
+ });
233
+ }
234
+ } else if (ext === ".py") {
235
+ const meta = await loadPyConfig(abs, logger);
236
+ flow = meta.flow;
237
+ const kind = "py";
238
+ const virtualPath = relative(layer.serverDir, abs).replace(/\\/g, "/");
239
+ queueName = String(meta.queue?.name || meta.queueName || (id.split("/").pop() || id));
240
+ workerByVirtualPath.set(virtualPath, {
241
+ id,
242
+ kind,
243
+ filePath: virtualPath,
244
+ absPath: abs,
245
+ exportName: "default",
246
+ queue: {
247
+ name: queueName,
248
+ defaultJobOptions: meta.queue?.defaultJobOptions,
249
+ prefix: meta.queue?.prefix,
250
+ limiter: meta.queue?.limiter
251
+ },
252
+ flow
253
+ });
254
+ } else {
255
+ try {
256
+ const meta = await loadTsConfig(abs);
257
+ flow = meta.flow;
258
+ const hasDefaultExport = !!meta.hasDefaultExport;
259
+ if (hasDefaultExport) {
260
+ const kind = "ts";
261
+ const virtualPath = relative(layer.serverDir, abs).replace(/\\/g, "/");
262
+ queueName = String(meta.queue?.name || meta.queueName || (id.split("/").pop() || id));
263
+ workerByVirtualPath.set(virtualPath, {
264
+ id,
265
+ kind,
266
+ filePath: virtualPath,
267
+ absPath: abs,
268
+ exportName: "default",
269
+ queue: {
270
+ name: queueName,
271
+ defaultJobOptions: meta.queue?.defaultJobOptions,
272
+ prefix: meta.queue?.prefix,
273
+ limiter: meta.queue?.limiter
274
+ },
275
+ worker: meta.worker,
276
+ flow,
277
+ runtype: meta.runtype
278
+ });
279
+ }
280
+ } catch (err) {
281
+ logger.warn("Failed to load TS worker (jiti):", rel, err);
282
+ }
283
+ }
284
+ if (!queueName) {
285
+ queueName = id.split("/").pop() || id;
286
+ }
287
+ if (flow) {
288
+ flowSources.push({ flow, queue: String(queueName), id });
289
+ }
290
+ } catch (e) {
291
+ logger.warn("Failed to load worker file:", rel, e);
292
+ }
293
+ }
294
+ }
295
+ const workers = Array.from(workerByVirtualPath.values());
296
+ return { workers, flowSources };
297
+ }
298
+
299
+ function buildFlows(flowSources) {
300
+ const flows = {};
301
+ const eventIndex = {};
302
+ const seenFlowKeys = /* @__PURE__ */ new Set();
303
+ for (const src of flowSources) {
304
+ const { flow: f, queue, id } = src;
305
+ if (!f?.names?.length || !f.step) continue;
306
+ const rawSteps = Array.isArray(f.step) ? f.step : [f.step];
307
+ const steps = rawSteps.filter((s) => typeof s === "string" && s.length > 0);
308
+ if (steps.length === 0) continue;
309
+ for (const flowId of f.names) {
310
+ if (!flows[flowId]) flows[flowId] = { steps: {} };
311
+ const bucket = flows[flowId] = flows[flowId] || { steps: {} };
312
+ if (f.role === "entry") {
313
+ const mainStep = steps[0];
314
+ const key = `${flowId}:${f.role}:${mainStep}`;
315
+ if (!seenFlowKeys.has(key)) {
316
+ seenFlowKeys.add(key);
317
+ bucket.entry = { step: mainStep, queue, workerId: id };
318
+ }
319
+ for (const s of steps.slice(1)) {
320
+ const skey = `${flowId}:step:${s}`;
321
+ if (seenFlowKeys.has(skey)) continue;
322
+ seenFlowKeys.add(skey);
323
+ bucket.steps[s] = { queue, workerId: id, subscribes: f.subscribes };
324
+ }
325
+ } else {
326
+ for (const s of steps) {
327
+ const skey = `${flowId}:${f.role}:${s}`;
328
+ if (seenFlowKeys.has(skey)) continue;
329
+ seenFlowKeys.add(skey);
330
+ bucket.steps[s] = { queue, workerId: id, subscribes: f.subscribes };
331
+ }
332
+ }
333
+ if (f.subscribes) {
334
+ for (const kind of f.subscribes) {
335
+ if (!eventIndex[kind]) eventIndex[kind] = [];
336
+ for (const s of steps) {
337
+ eventIndex[kind].push({ flowId, step: s, queue, workerId: id });
338
+ }
339
+ }
340
+ }
341
+ }
342
+ }
343
+ return { flows, eventIndex };
344
+ }
345
+
346
+ function mergeWorkerConfig(worker, defaults) {
347
+ const merged = { ...worker };
348
+ if (defaults.queue || worker.queue) {
349
+ merged.queue = defu(
350
+ worker.queue || {},
351
+ defaults.queue || {}
352
+ );
353
+ }
354
+ if (defaults.worker || worker.worker) {
355
+ merged.worker = defu(
356
+ worker.worker || {},
357
+ defaults.worker || {}
358
+ );
359
+ }
360
+ return merged;
361
+ }
362
+ function mergeAllWorkerConfigs(workers, defaults) {
363
+ return workers.map((worker) => mergeWorkerConfig(worker, defaults));
364
+ }
365
+
366
+ function parseSubscription(token) {
367
+ const [prefix, ...rest] = token.split(":");
368
+ if (rest.length > 0) {
369
+ const type = prefix;
370
+ return { type, value: rest.join(":") };
371
+ }
372
+ return { type: "implicit", value: token };
373
+ }
374
+ function findEmitter(token, entryStep, steps) {
375
+ const { type, value } = parseSubscription(token);
376
+ if (entryStep) {
377
+ const entryEmits = steps[entryStep]?.emits || [];
378
+ if (entryEmits.includes(token) || entryEmits.includes(value)) {
379
+ return entryStep;
380
+ }
381
+ }
382
+ for (const [stepName, step] of Object.entries(steps)) {
383
+ const emits = step.emits || [];
384
+ if (emits.includes(token)) {
385
+ return stepName;
386
+ }
387
+ switch (type) {
388
+ case "step":
389
+ if (stepName === value) return stepName;
390
+ break;
391
+ case "queue":
392
+ if (step.queue === value) return stepName;
393
+ break;
394
+ case "worker":
395
+ if (step.workerId === value) return stepName;
396
+ break;
397
+ case "implicit":
398
+ if (stepName === value || step.queue === value || emits.includes(value)) {
399
+ return stepName;
400
+ }
401
+ break;
402
+ }
403
+ }
404
+ return null;
405
+ }
406
+ function buildDependencyGraph(entryStep, steps) {
407
+ const dependencies = {};
408
+ for (const [stepName, step] of Object.entries(steps)) {
409
+ const deps = /* @__PURE__ */ new Set();
410
+ const subscribes = step.subscribes || [];
411
+ for (const token of subscribes) {
412
+ const emitter = findEmitter(token, entryStep, steps);
413
+ if (emitter && emitter !== stepName) {
414
+ deps.add(emitter);
415
+ }
416
+ }
417
+ dependencies[stepName] = Array.from(deps);
418
+ }
419
+ return dependencies;
420
+ }
421
+ function calculateLevels(entryStep, dependencies) {
422
+ const levels = {};
423
+ const visited = /* @__PURE__ */ new Set();
424
+ const visiting = /* @__PURE__ */ new Set();
425
+ function visit(stepName) {
426
+ if (visited.has(stepName)) {
427
+ return levels[stepName] ?? 0;
428
+ }
429
+ if (visiting.has(stepName)) {
430
+ console.warn(`Circular dependency detected involving step: ${stepName}`);
431
+ return 0;
432
+ }
433
+ visiting.add(stepName);
434
+ const deps = dependencies[stepName] || [];
435
+ let maxDepLevel = -1;
436
+ if (stepName === entryStep) {
437
+ maxDepLevel = -1;
438
+ } else if (deps.length === 0 && entryStep) {
439
+ maxDepLevel = 0;
440
+ } else {
441
+ for (const dep of deps) {
442
+ const depLevel = visit(dep);
443
+ maxDepLevel = Math.max(maxDepLevel, depLevel);
444
+ }
445
+ }
446
+ levels[stepName] = maxDepLevel + 1;
447
+ visiting.delete(stepName);
448
+ visited.add(stepName);
449
+ return levels[stepName];
450
+ }
451
+ const allSteps = Object.keys(dependencies);
452
+ for (const step of allSteps) {
453
+ visit(step);
454
+ }
455
+ return levels;
456
+ }
457
+ function findTriggeredSteps(stepName, step, allSteps) {
458
+ const emits = step.emits || [];
459
+ const triggered = /* @__PURE__ */ new Set();
460
+ for (const [targetName, targetStep] of Object.entries(allSteps)) {
461
+ if (targetName === stepName) continue;
462
+ const subscribes = targetStep.subscribes || [];
463
+ for (const token of subscribes) {
464
+ const { type, value } = parseSubscription(token);
465
+ let matches = false;
466
+ switch (type) {
467
+ case "step":
468
+ matches = stepName === value;
469
+ break;
470
+ case "queue":
471
+ matches = step.queue === value;
472
+ break;
473
+ case "worker":
474
+ matches = step.workerId === value;
475
+ break;
476
+ case "implicit":
477
+ matches = stepName === value || step.queue === value || emits.includes(value);
478
+ break;
479
+ }
480
+ if (matches || emits.includes(token)) {
481
+ triggered.add(targetName);
482
+ }
483
+ }
484
+ }
485
+ return Array.from(triggered);
486
+ }
487
+ function analyzeFlow(flow) {
488
+ const entryStepName = flow.entry?.step;
489
+ const steps = flow.steps || {};
490
+ const dependencies = buildDependencyGraph(entryStepName, steps);
491
+ const levels = calculateLevels(entryStepName, dependencies);
492
+ const analyzedSteps = {};
493
+ for (const [stepName, step] of Object.entries(steps)) {
494
+ analyzedSteps[stepName] = {
495
+ ...step,
496
+ name: stepName,
497
+ dependsOn: dependencies[stepName] || [],
498
+ triggers: findTriggeredSteps(stepName, step, steps),
499
+ level: levels[stepName] ?? 1
500
+ };
501
+ }
502
+ const maxLevel = Math.max(0, ...Object.values(levels));
503
+ const levelGroups = Array.from({ length: maxLevel + 1 }, () => []);
504
+ for (const [stepName, level] of Object.entries(levels)) {
505
+ const levelArray = levelGroups[level];
506
+ if (levelArray) {
507
+ levelArray.push(stepName);
508
+ }
509
+ }
510
+ return {
511
+ id: flow.id,
512
+ entry: flow.entry,
513
+ steps: analyzedSteps,
514
+ levels: levelGroups,
515
+ maxLevel
516
+ };
517
+ }
518
+
519
+ async function compileRegistryFromServerWorkers(layers, queuesDir = "queues", defaults) {
520
+ const { workers, flowSources } = await scanWorkers(layers, queuesDir);
521
+ const mergedWorkers = defaults ? mergeAllWorkerConfigs(workers, defaults) : workers;
522
+ const { flows, eventIndex } = buildFlows(flowSources);
523
+ const compiled = {
524
+ workers: mergedWorkers,
525
+ flows,
526
+ eventIndex
527
+ };
528
+ return compiled;
529
+ }
530
+
531
+ const logger = useLogger("nuxt-queue");
532
+ function watchQueueFiles(options) {
533
+ const { nuxt, layerInfos, queuesDir, onRefresh } = options;
534
+ const dirsToWatch = layerInfos.map((layer) => {
535
+ const serverDir = layer.serverDir || join$1(layer.rootDir, "server");
536
+ return join$1(serverDir, queuesDir);
537
+ }).filter(Boolean);
538
+ if (dirsToWatch.length === 0) {
539
+ logger.warn("No queue directories found to watch");
540
+ return;
541
+ }
542
+ logger.info("Watching queue directories:", dirsToWatch);
543
+ const watcher = chokidar.watch(dirsToWatch, {
544
+ ignoreInitial: true,
545
+ persistent: true,
546
+ ignorePermissionErrors: true,
547
+ ignored: [
548
+ "**/node_modules/**",
549
+ "**/__pycache__/**",
550
+ "**/.git/**",
551
+ "**/dist/**",
552
+ "**/.nuxt/**"
553
+ ],
554
+ // Watch only specific file types
555
+ awaitWriteFinish: {
556
+ stabilityThreshold: 100,
557
+ pollInterval: 100
558
+ }
559
+ });
560
+ logger.info("Chokidar watcher initialized");
561
+ logger.info("Watched patterns:", dirsToWatch.map((dir) => `${dir}/**/*.{ts,js,py}`));
562
+ watcher.on("ready", () => {
563
+ const watched = watcher.getWatched();
564
+ const fileCount = Object.values(watched).reduce((sum, files) => sum + files.length, 0);
565
+ logger.success(`Queue file watcher ready - watching ${fileCount} files`);
566
+ });
567
+ const debouncedRefresh = debounce(onRefresh, 150);
568
+ watcher.on("all", (event, path) => {
569
+ logger.info(`Watcher event: ${event} - ${path}`);
570
+ });
571
+ watcher.on("add", async (path) => {
572
+ logger.info(`Queue file added: ${path}`);
573
+ await debouncedRefresh("add", path);
574
+ });
575
+ watcher.on("change", async (path) => {
576
+ logger.info(`Queue file changed: ${path}`);
577
+ await debouncedRefresh("change", path);
578
+ });
579
+ watcher.on("unlink", async (path) => {
580
+ logger.info(`Queue file removed: ${path}`);
581
+ await debouncedRefresh("unlink", path);
582
+ });
583
+ watcher.on("error", (error) => {
584
+ logger.error("Watcher error:", error);
585
+ });
586
+ nuxt.hook("close", () => {
587
+ logger.info("Closing queue file watcher");
588
+ watcher.close();
589
+ });
590
+ return watcher;
591
+ }
592
+
593
+ function generateRegistryTemplate(registry) {
594
+ return `// auto-generated by nuxt-queue
595
+ export const registry = ${JSON.stringify(registry, null, 2)};
596
+
597
+ export const useQueueRegistry = () => registry;
598
+
599
+ export default useQueueRegistry;
600
+ `;
601
+ }
602
+ function generateHandlersTemplate(registry) {
603
+ const regWorkers = registry?.workers || [];
604
+ const lines = [];
605
+ const entries = [];
606
+ regWorkers.filter((w) => w?.kind === "ts" && (w?.runtype ? w.runtype !== "task" : registry?.runner?.ts?.isolate !== "task")).forEach((w, i) => {
607
+ const varName = `h${i}`;
608
+ const src = w && (w.absPath || w.abs || w.cwd && w.file && join(w.cwd, w.file) || w.entry || w.path) || "";
609
+ if (!src) return;
610
+ const importPath = String(src);
611
+ lines.push(`import ${varName} from '${importPath}'`);
612
+ const queue = String(w?.queue?.name || `w${i}`);
613
+ const id = String(w?.id || `w${i}`);
614
+ const absPath = importPath;
615
+ entries.push(`{ queue: '${queue}', id: '${id}', absPath: '${absPath}', handler: ${varName} }`);
616
+ });
617
+ return `// auto-generated by nuxt-queue
618
+ ${lines.join("\n")}
619
+
620
+ export const handlers = [
621
+ ${entries.join(",\n ")}
622
+ ]
623
+
624
+ export const useWorkerHandlers = () => handlers;
625
+
626
+ export default useWorkerHandlers;
627
+ `;
628
+ }
629
+ function generateAnalyzedFlowsTemplate(registry) {
630
+ const flows = registry?.flows || {};
631
+ const workers = registry?.workers || [];
632
+ const workerMetaMap = /* @__PURE__ */ new Map();
633
+ for (const worker of workers) {
634
+ workerMetaMap.set(worker.id, {
635
+ runtime: worker.kind === "py" ? "python" : "nodejs",
636
+ runtype: worker.runtype,
637
+ queue: worker.queue,
638
+ worker: worker.worker,
639
+ emits: worker.flow?.emits
640
+ });
641
+ }
642
+ const analyzedFlows = Object.entries(flows).map(([id, meta]) => {
643
+ const workerMeta = meta?.entry ? workerMetaMap.get(meta.entry.workerId) : void 0;
644
+ const entry = meta?.entry ? {
645
+ ...meta.entry,
646
+ runtime: workerMeta?.runtime,
647
+ runtype: workerMeta?.runtype,
648
+ emits: workerMeta?.emits
649
+ } : void 0;
650
+ const steps = meta?.steps ? Object.fromEntries(
651
+ Object.entries(meta.steps).map(([stepName, stepData]) => {
652
+ const stepWorkerMeta = workerMetaMap.get(stepData.workerId);
653
+ return [
654
+ stepName,
655
+ {
656
+ ...stepData,
657
+ runtime: stepWorkerMeta?.runtime,
658
+ runtype: stepWorkerMeta?.runtype,
659
+ emits: stepWorkerMeta?.emits
660
+ }
661
+ ];
662
+ })
663
+ ) : {};
664
+ const flowMeta = {
665
+ id,
666
+ entry,
667
+ steps
668
+ };
669
+ const analyzed = analyzeFlow(flowMeta);
670
+ return {
671
+ ...flowMeta,
672
+ analyzed: {
673
+ levels: analyzed.levels,
674
+ maxLevel: analyzed.maxLevel,
675
+ steps: analyzed.steps
676
+ }
677
+ };
678
+ });
679
+ return `// auto-generated by nuxt-queue
680
+ export const analyzedFlows = ${JSON.stringify(analyzedFlows, null, 2)};
681
+
682
+ export const useAnalyzedFlows = () => analyzedFlows;
683
+
684
+ export default useAnalyzedFlows;
685
+ `;
686
+ }
687
+
688
+ function normalizeModuleOptions(options) {
689
+ const defaults = {
690
+ dir: "queues",
691
+ ui: true,
692
+ debug: {},
693
+ queue: {
694
+ adapter: "redis",
695
+ redis: {
696
+ host: "127.0.0.1",
697
+ port: 6379
698
+ },
699
+ defaultConfig: {
700
+ // Queue options
701
+ prefix: "nq",
702
+ defaultJobOptions: {},
703
+ // Worker options
704
+ worker: {
705
+ concurrency: 2,
706
+ autorun: true
707
+ }
708
+ }
709
+ },
710
+ state: {
711
+ adapter: "redis",
712
+ namespace: "nq",
713
+ autoScope: "always",
714
+ cleanup: {
715
+ strategy: "never"
716
+ },
717
+ redis: {
718
+ host: "127.0.0.1",
719
+ port: 6379
720
+ }
721
+ },
722
+ eventStore: {
723
+ adapter: "memory",
724
+ options: {
725
+ file: {
726
+ dir: ".data/nq-events",
727
+ ext: ".ndjson",
728
+ pollMs: 1e3
729
+ }
730
+ },
731
+ retention: {
732
+ eventTTL: 604800,
733
+ // 7 days
734
+ metadataTTL: 2592e3
735
+ // 30 days
736
+ }
737
+ }
738
+ };
739
+ if (options.store) {
740
+ const storeConfig = expandStoreShortcut(options.store);
741
+ return defu(options, storeConfig, defaults);
742
+ }
743
+ return defu(options, defaults);
744
+ }
745
+ function expandStoreShortcut(store) {
746
+ if (!store) return {};
747
+ const storeAdapter = store.adapter;
748
+ if (storeAdapter === "redis") {
749
+ const redisConfig = store.redis || {
750
+ host: "127.0.0.1",
751
+ port: 6379
752
+ };
753
+ return {
754
+ queue: {
755
+ adapter: "redis",
756
+ redis: redisConfig,
757
+ defaultConfig: {}
758
+ },
759
+ state: {
760
+ adapter: "redis",
761
+ namespace: "nq",
762
+ autoScope: "always",
763
+ cleanup: { strategy: "never" },
764
+ redis: redisConfig
765
+ },
766
+ eventStore: {
767
+ adapter: "redis",
768
+ redis: redisConfig
769
+ }
770
+ };
771
+ }
772
+ if (storeAdapter === "postgres") {
773
+ const postgresConfig = store.postgres || {
774
+ connectionString: process.env.DATABASE_URL || "postgresql://localhost:5432/nuxt_queue"
775
+ };
776
+ return {
777
+ queue: {
778
+ adapter: "postgres",
779
+ postgres: postgresConfig,
780
+ defaultConfig: {}
781
+ },
782
+ state: {
783
+ adapter: "postgres",
784
+ postgres: postgresConfig
785
+ },
786
+ eventStore: {
787
+ adapter: "postgres",
788
+ postgres: postgresConfig
789
+ }
790
+ };
791
+ }
792
+ return {};
793
+ }
794
+ function toRuntimeConfig(normalizedOptions) {
795
+ return {
796
+ debug: normalizedOptions.debug,
797
+ workers: [],
798
+ queue: normalizedOptions.queue,
799
+ state: normalizedOptions.state,
800
+ eventStore: normalizedOptions.eventStore
801
+ };
802
+ }
803
+ function getRedisStorageConfig(normalizedOptions) {
804
+ const redisConfig = normalizedOptions.queue.redis || normalizedOptions.state.redis;
805
+ if (!redisConfig) {
806
+ return {
807
+ host: "127.0.0.1",
808
+ port: 6379
809
+ };
810
+ }
811
+ return {
812
+ host: redisConfig.host,
813
+ port: redisConfig.port,
814
+ username: redisConfig.username,
815
+ password: redisConfig.password,
816
+ db: redisConfig.db
817
+ };
818
+ }
819
+
820
+ const meta = {
821
+ name: "queue",
822
+ version: "0.1",
823
+ configKey: "queue"
824
+ };
825
+ const module = defineNuxtModule({
826
+ meta,
827
+ defaults: {},
828
+ moduleDependencies: {
829
+ "json-editor-vue/nuxt": {
830
+ version: "0.18.1"
831
+ }
832
+ },
833
+ async setup(options, nuxt) {
834
+ const { resolve } = createResolver(import.meta.url);
835
+ const config = normalizeModuleOptions(options);
836
+ addServerScanDir(resolve("./runtime/server"));
837
+ addImportsDir(resolve("./runtime/shared/utils"));
838
+ addImportsDir(resolve("./runtime/app/composables"));
839
+ if (config.ui) {
840
+ addPlugin({
841
+ src: resolve("./runtime/app/plugins/vueflow.client.ts"),
842
+ mode: "client"
843
+ });
844
+ addComponentsDir({
845
+ path: resolve("./runtime/app/components"),
846
+ prefix: "Queue"
847
+ });
848
+ addComponent({
849
+ name: "QueueApp",
850
+ filePath: resolve("./runtime/app/pages/index.vue"),
851
+ global: true
852
+ });
853
+ }
854
+ nuxt.options.vite.optimizeDeps = defu(nuxt.options.vite.optimizeDeps, {
855
+ include: ["vanilla-jsoneditor"]
856
+ });
857
+ nuxt.hook("nitro:config", (nitro) => {
858
+ const redisConfig = getRedisStorageConfig(config);
859
+ nitro.storage = defu(nitro.storage || {}, {
860
+ redis: {
861
+ driver: "redis",
862
+ ...redisConfig
863
+ // base namespace handled in provider; keep storage base default
864
+ }
865
+ });
866
+ nitro.experimental = defu(nitro.experimental || {}, {
867
+ websocket: true
868
+ });
869
+ });
870
+ const runtimeConfig = nuxt.options.runtimeConfig;
871
+ runtimeConfig.queue = defu(runtimeConfig.queue || {}, toRuntimeConfig(config));
872
+ if (!runtimeConfig.queue) runtimeConfig.queue = {};
873
+ runtimeConfig.queue.rootDir = nuxt.options.rootDir;
874
+ const layerInfos = nuxt.options._layers.map((l) => ({
875
+ rootDir: l.config.rootDir,
876
+ serverDir: l.config?.serverDir || join(l.config.rootDir, "server")
877
+ }));
878
+ const { worker: _worker, ...queueOptions } = config.queue.defaultConfig || {};
879
+ const defaultConfigs = {
880
+ queue: queueOptions,
881
+ worker: config.queue.defaultConfig?.worker
882
+ };
883
+ const compiledRegistry = await compileRegistryFromServerWorkers(layerInfos, config.dir || "queues", defaultConfigs);
884
+ const compiledWithMeta = defu(compiledRegistry, {
885
+ version: 1,
886
+ compiledAt: (/* @__PURE__ */ new Date()).toISOString(),
887
+ provider: { name: config.queue.adapter === "postgres" ? "pgboss" : "bullmq" },
888
+ logger: { name: "console", level: "info" },
889
+ state: config.state,
890
+ eventStore: config.eventStore,
891
+ runner: { ts: { isolate: "inprocess" }, py: { enabled: false, cmd: "python3", importMode: "file" } },
892
+ workers: [],
893
+ flows: {},
894
+ eventIndex: {}
895
+ });
896
+ const compiledSnapshot = JSON.parse(JSON.stringify(compiledWithMeta));
897
+ let lastCompiledRegistry = compiledSnapshot;
898
+ const REGISTRY_TEMPLATE = "queue-registry.mjs";
899
+ const HANDLERS_TEMPLATE = "worker-handlers.mjs";
900
+ const ANALYZED_FLOWS_TEMPLATE = "analyzed-flows.mjs";
901
+ for (const templateName of [REGISTRY_TEMPLATE, HANDLERS_TEMPLATE, ANALYZED_FLOWS_TEMPLATE]) {
902
+ const templatePath = resolve(nuxt.options.buildDir, templateName);
903
+ nuxt.options.build.transpile.push(templatePath);
904
+ }
905
+ addTemplate({
906
+ filename: REGISTRY_TEMPLATE,
907
+ write: true,
908
+ getContents: () => generateRegistryTemplate(lastCompiledRegistry)
909
+ });
910
+ addTemplate({
911
+ filename: HANDLERS_TEMPLATE,
912
+ write: true,
913
+ getContents: () => generateHandlersTemplate(lastCompiledRegistry)
914
+ });
915
+ addTemplate({
916
+ filename: ANALYZED_FLOWS_TEMPLATE,
917
+ write: true,
918
+ getContents: () => generateAnalyzedFlowsTemplate(lastCompiledRegistry)
919
+ });
920
+ addServerImports([{
921
+ name: "useQueueRegistry",
922
+ as: "$useQueueRegistry",
923
+ from: resolve(nuxt.options.buildDir, "queue-registry")
924
+ }, {
925
+ name: "useWorkerHandlers",
926
+ as: "$useWorkerHandlers",
927
+ from: resolve(nuxt.options.buildDir, "worker-handlers")
928
+ }, {
929
+ name: "useAnalyzedFlows",
930
+ as: "$useAnalyzedFlows",
931
+ from: resolve(nuxt.options.buildDir, "analyzed-flows")
932
+ }]);
933
+ const refreshRegistry = async (reason, changedPath) => {
934
+ const queuesRel = config.dir || "queues";
935
+ const updatedRegistry = await compileRegistryFromServerWorkers(layerInfos, queuesRel, defaultConfigs);
936
+ lastCompiledRegistry = JSON.parse(JSON.stringify(defu(updatedRegistry, {
937
+ version: 1,
938
+ compiledAt: (/* @__PURE__ */ new Date()).toISOString(),
939
+ provider: { name: config.queue.adapter === "postgres" ? "pgboss" : "bullmq" },
940
+ logger: { name: "console", level: "info" },
941
+ state: config.state,
942
+ eventStore: config.eventStore,
943
+ runner: { ts: { isolate: "inprocess" }, py: { enabled: false, cmd: "python3", importMode: "file" } },
944
+ workers: [],
945
+ flows: {},
946
+ eventIndex: {}
947
+ })));
948
+ console.log(`[nuxt-queue] registry refreshed (${reason})`, changedPath || "");
949
+ console.log(`[nuxt-queue] new registry has ${lastCompiledRegistry.workers?.length || 0} workers`);
950
+ console.log(`[nuxt-queue] new registry compiled at: ${lastCompiledRegistry.compiledAt}`);
951
+ await updateTemplates({
952
+ filter: (template) => {
953
+ const match = template.filename === REGISTRY_TEMPLATE || template.filename === HANDLERS_TEMPLATE || template.filename === ANALYZED_FLOWS_TEMPLATE;
954
+ if (match) {
955
+ console.log(`[nuxt-queue] updating template: ${template.filename}`);
956
+ }
957
+ return match;
958
+ }
959
+ });
960
+ console.log(`[nuxt-queue] templates updated`);
961
+ };
962
+ if (nuxt.options.dev) {
963
+ const queuesRel = config.dir || "queues";
964
+ watchQueueFiles({
965
+ nuxt,
966
+ layerInfos,
967
+ queuesDir: queuesRel,
968
+ onRefresh: refreshRegistry
969
+ });
970
+ }
971
+ }
972
+ });
973
+
974
+ export { module as default };