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.
- package/LICENSE +21 -0
- package/README.md +389 -0
- package/dist/module.d.mts +193 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +974 -0
- package/dist/runtime/app/components/ConfirmDialog.d.vue.ts +33 -0
- package/dist/runtime/app/components/ConfirmDialog.vue +121 -0
- package/dist/runtime/app/components/ConfirmDialog.vue.d.ts +33 -0
- package/dist/runtime/app/components/FlowDiagram.d.vue.ts +64 -0
- package/dist/runtime/app/components/FlowDiagram.vue +338 -0
- package/dist/runtime/app/components/FlowDiagram.vue.d.ts +64 -0
- package/dist/runtime/app/components/FlowNodeCard.d.vue.ts +29 -0
- package/dist/runtime/app/components/FlowNodeCard.vue +156 -0
- package/dist/runtime/app/components/FlowNodeCard.vue.d.ts +29 -0
- package/dist/runtime/app/components/FlowRunOverview.d.vue.ts +9 -0
- package/dist/runtime/app/components/FlowRunOverview.vue +291 -0
- package/dist/runtime/app/components/FlowRunOverview.vue.d.ts +9 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.d.vue.ts +14 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.vue +60 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.vue.d.ts +14 -0
- package/dist/runtime/app/components/FlowRunTimeline.d.vue.ts +12 -0
- package/dist/runtime/app/components/FlowRunTimeline.vue +127 -0
- package/dist/runtime/app/components/FlowRunTimeline.vue.d.ts +12 -0
- package/dist/runtime/app/components/FlowScheduleDialog.d.vue.ts +16 -0
- package/dist/runtime/app/components/FlowScheduleDialog.vue +226 -0
- package/dist/runtime/app/components/FlowScheduleDialog.vue.d.ts +16 -0
- package/dist/runtime/app/components/FlowSchedulesList.d.vue.ts +12 -0
- package/dist/runtime/app/components/FlowSchedulesList.vue +99 -0
- package/dist/runtime/app/components/FlowSchedulesList.vue.d.ts +12 -0
- package/dist/runtime/app/components/JobScheduling.d.vue.ts +6 -0
- package/dist/runtime/app/components/JobScheduling.vue +203 -0
- package/dist/runtime/app/components/JobScheduling.vue.d.ts +6 -0
- package/dist/runtime/app/components/ListItem.d.vue.ts +23 -0
- package/dist/runtime/app/components/ListItem.vue +70 -0
- package/dist/runtime/app/components/ListItem.vue.d.ts +23 -0
- package/dist/runtime/app/components/QueueConfigDetails.d.vue.ts +45 -0
- package/dist/runtime/app/components/QueueConfigDetails.vue +412 -0
- package/dist/runtime/app/components/QueueConfigDetails.vue.d.ts +45 -0
- package/dist/runtime/app/components/StatCounter.d.vue.ts +9 -0
- package/dist/runtime/app/components/StatCounter.vue +25 -0
- package/dist/runtime/app/components/StatCounter.vue.d.ts +9 -0
- package/dist/runtime/app/components/TimelineList.d.vue.ts +7 -0
- package/dist/runtime/app/components/TimelineList.vue +210 -0
- package/dist/runtime/app/components/TimelineList.vue.d.ts +7 -0
- package/dist/runtime/app/components/nhealth/component-router.d.vue.ts +46 -0
- package/dist/runtime/app/components/nhealth/component-router.vue +26 -0
- package/dist/runtime/app/components/nhealth/component-router.vue.d.ts +46 -0
- package/dist/runtime/app/components/nhealth/component-shell.d.vue.ts +24 -0
- package/dist/runtime/app/components/nhealth/component-shell.vue +89 -0
- package/dist/runtime/app/components/nhealth/component-shell.vue.d.ts +24 -0
- package/dist/runtime/app/composables/useAnalyzedFlows.d.ts +14 -0
- package/dist/runtime/app/composables/useAnalyzedFlows.js +7 -0
- package/dist/runtime/app/composables/useComponentRouter.d.ts +38 -0
- package/dist/runtime/app/composables/useComponentRouter.js +240 -0
- package/dist/runtime/app/composables/useFlowRunTimeline.d.ts +15 -0
- package/dist/runtime/app/composables/useFlowRunTimeline.js +66 -0
- package/dist/runtime/app/composables/useFlowRuns.d.ts +11 -0
- package/dist/runtime/app/composables/useFlowRuns.js +31 -0
- package/dist/runtime/app/composables/useFlowRunsInfinite.d.ts +24 -0
- package/dist/runtime/app/composables/useFlowRunsInfinite.js +123 -0
- package/dist/runtime/app/composables/useFlowRunsPolling.d.ts +8 -0
- package/dist/runtime/app/composables/useFlowRunsPolling.js +26 -0
- package/dist/runtime/app/composables/useFlowState.d.ts +125 -0
- package/dist/runtime/app/composables/useFlowState.js +211 -0
- package/dist/runtime/app/composables/useFlowWebSocket.d.ts +27 -0
- package/dist/runtime/app/composables/useFlowWebSocket.js +205 -0
- package/dist/runtime/app/composables/useFlowsNavigation.d.ts +10 -0
- package/dist/runtime/app/composables/useFlowsNavigation.js +57 -0
- package/dist/runtime/app/composables/useQueueJobs.d.ts +20 -0
- package/dist/runtime/app/composables/useQueueJobs.js +20 -0
- package/dist/runtime/app/composables/useQueueUpdates.d.ts +26 -0
- package/dist/runtime/app/composables/useQueueUpdates.js +122 -0
- package/dist/runtime/app/composables/useQueues.d.ts +43 -0
- package/dist/runtime/app/composables/useQueues.js +26 -0
- package/dist/runtime/app/composables/useQueuesLive.d.ts +19 -0
- package/dist/runtime/app/composables/useQueuesLive.js +143 -0
- package/dist/runtime/app/pages/flows/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/flows/index.vue +645 -0
- package/dist/runtime/app/pages/flows/index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/index.vue +34 -0
- package/dist/runtime/app/pages/index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/queues/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/queues/index.vue +229 -0
- package/dist/runtime/app/pages/queues/index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/queues/job.d.vue.ts +3 -0
- package/dist/runtime/app/pages/queues/job.vue +262 -0
- package/dist/runtime/app/pages/queues/job.vue.d.ts +3 -0
- package/dist/runtime/app/pages/queues/jobs.d.vue.ts +3 -0
- package/dist/runtime/app/pages/queues/jobs.vue +291 -0
- package/dist/runtime/app/pages/queues/jobs.vue.d.ts +3 -0
- package/dist/runtime/app/plugins/vueflow.client.d.ts +6 -0
- package/dist/runtime/app/plugins/vueflow.client.js +15 -0
- package/dist/runtime/constants.d.ts +11 -0
- package/dist/runtime/constants.js +11 -0
- package/dist/runtime/python/get_config.py +64 -0
- package/dist/runtime/schema.d.ts +37 -0
- package/dist/runtime/schema.js +20 -0
- package/dist/runtime/server/api/_flows/[name]/clear-history.delete.d.ts +10 -0
- package/dist/runtime/server/api/_flows/[name]/clear-history.delete.js +44 -0
- package/dist/runtime/server/api/_flows/[name]/runs.get.d.ts +7 -0
- package/dist/runtime/server/api/_flows/[name]/runs.get.js +53 -0
- package/dist/runtime/server/api/_flows/[name]/schedule.post.d.ts +2 -0
- package/dist/runtime/server/api/_flows/[name]/schedule.post.js +57 -0
- package/dist/runtime/server/api/_flows/[name]/schedules/[id].delete.d.ts +2 -0
- package/dist/runtime/server/api/_flows/[name]/schedules/[id].delete.js +42 -0
- package/dist/runtime/server/api/_flows/[name]/schedules.get.d.ts +2 -0
- package/dist/runtime/server/api/_flows/[name]/schedules.get.js +48 -0
- package/dist/runtime/server/api/_flows/[name]/start.post.d.ts +2 -0
- package/dist/runtime/server/api/_flows/[name]/start.post.js +9 -0
- package/dist/runtime/server/api/_flows/index.get.d.ts +6 -0
- package/dist/runtime/server/api/_flows/index.get.js +5 -0
- package/dist/runtime/server/api/_flows/ws.d.ts +60 -0
- package/dist/runtime/server/api/_flows/ws.js +183 -0
- package/dist/runtime/server/api/_queues/[name]/job/[id].get.d.ts +2 -0
- package/dist/runtime/server/api/_queues/[name]/job/[id].get.js +9 -0
- package/dist/runtime/server/api/_queues/[name]/job/index.get.d.ts +2 -0
- package/dist/runtime/server/api/_queues/[name]/job/index.get.js +18 -0
- package/dist/runtime/server/api/_queues/index.get.d.ts +2 -0
- package/dist/runtime/server/api/_queues/index.get.js +63 -0
- package/dist/runtime/server/api/_queues/ws.d.ts +48 -0
- package/dist/runtime/server/api/_queues/ws.js +200 -0
- package/dist/runtime/server/events/adapters/fileAdapter.d.ts +2 -0
- package/dist/runtime/server/events/adapters/fileAdapter.js +382 -0
- package/dist/runtime/server/events/adapters/memoryAdapter.d.ts +2 -0
- package/dist/runtime/server/events/adapters/memoryAdapter.js +171 -0
- package/dist/runtime/server/events/adapters/redis/redisAdapter.d.ts +2 -0
- package/dist/runtime/server/events/adapters/redis/redisAdapter.js +348 -0
- package/dist/runtime/server/events/adapters/redis/redisPubSubGateway.d.ts +29 -0
- package/dist/runtime/server/events/adapters/redis/redisPubSubGateway.js +82 -0
- package/dist/runtime/server/events/eventBus.d.ts +20 -0
- package/dist/runtime/server/events/eventBus.js +35 -0
- package/dist/runtime/server/events/eventStoreFactory.d.ts +19 -0
- package/dist/runtime/server/events/eventStoreFactory.js +44 -0
- package/dist/runtime/server/events/streamNames.d.ts +17 -0
- package/dist/runtime/server/events/streamNames.js +17 -0
- package/dist/runtime/server/events/types.d.ts +63 -0
- package/dist/runtime/server/events/types.js +0 -0
- package/dist/runtime/server/events/wiring/flowWiring.d.ts +33 -0
- package/dist/runtime/server/events/wiring/flowWiring.js +406 -0
- package/dist/runtime/server/events/wiring/registry.d.ts +10 -0
- package/dist/runtime/server/events/wiring/registry.js +24 -0
- package/dist/runtime/server/plugins/00.event-store.d.ts +13 -0
- package/dist/runtime/server/plugins/00.event-store.js +16 -0
- package/dist/runtime/server/plugins/00.ws-lifecycle.d.ts +5 -0
- package/dist/runtime/server/plugins/00.ws-lifecycle.js +66 -0
- package/dist/runtime/server/plugins/flow-management.d.ts +13 -0
- package/dist/runtime/server/plugins/flow-management.js +65 -0
- package/dist/runtime/server/plugins/queue-management.d.ts +2 -0
- package/dist/runtime/server/plugins/queue-management.js +27 -0
- package/dist/runtime/server/plugins/state-cleanup.d.ts +11 -0
- package/dist/runtime/server/plugins/state-cleanup.js +93 -0
- package/dist/runtime/server/plugins/worker-management.d.ts +2 -0
- package/dist/runtime/server/plugins/worker-management.js +33 -0
- package/dist/runtime/server/queue/adapters/bullmq.d.ts +17 -0
- package/dist/runtime/server/queue/adapters/bullmq.js +164 -0
- package/dist/runtime/server/queue/queueFactory.d.ts +3 -0
- package/dist/runtime/server/queue/queueFactory.js +10 -0
- package/dist/runtime/server/queue/types.d.ts +47 -0
- package/dist/runtime/server/queue/types.js +0 -0
- package/dist/runtime/server/state/adapters/redis.d.ts +2 -0
- package/dist/runtime/server/state/adapters/redis.js +42 -0
- package/dist/runtime/server/state/stateFactory.d.ts +3 -0
- package/dist/runtime/server/state/stateFactory.js +17 -0
- package/dist/runtime/server/state/types.d.ts +23 -0
- package/dist/runtime/server/state/types.js +0 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/server/utils/defineQueueConfig.d.ts +154 -0
- package/dist/runtime/server/utils/defineQueueConfig.js +2 -0
- package/dist/runtime/server/utils/defineQueueWorker.d.ts +10 -0
- package/dist/runtime/server/utils/defineQueueWorker.js +17 -0
- package/dist/runtime/server/utils/useEventManager.d.ts +15 -0
- package/dist/runtime/server/utils/useEventManager.js +26 -0
- package/dist/runtime/server/utils/useEventStore.d.ts +20 -0
- package/dist/runtime/server/utils/useEventStore.js +119 -0
- package/dist/runtime/server/utils/useFlowEngine.d.ts +9 -0
- package/dist/runtime/server/utils/useFlowEngine.js +44 -0
- package/dist/runtime/server/utils/useLogs.d.ts +41 -0
- package/dist/runtime/server/utils/useLogs.js +74 -0
- package/dist/runtime/server/utils/useQueue.d.ts +31 -0
- package/dist/runtime/server/utils/useQueue.js +24 -0
- package/dist/runtime/server/utils/useServerLogger.d.ts +42 -0
- package/dist/runtime/server/utils/useServerLogger.js +54 -0
- package/dist/runtime/server/utils/wsPeerManager.d.ts +34 -0
- package/dist/runtime/server/utils/wsPeerManager.js +23 -0
- package/dist/runtime/server/worker/adapter.d.ts +4 -0
- package/dist/runtime/server/worker/adapter.js +65 -0
- package/dist/runtime/server/worker/runner/node.d.ts +27 -0
- package/dist/runtime/server/worker/runner/node.js +196 -0
- package/dist/runtime/types.d.ts +132 -0
- package/dist/types.d.mts +3 -0
- package/package.json +75 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { defineEventHandler, getRouterParam, createError, useRuntimeConfig, $useQueueRegistry } from "#imports";
|
|
2
|
+
import { Queue } from "bullmq";
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const flowName = getRouterParam(event, "name");
|
|
5
|
+
const scheduleId = getRouterParam(event, "id");
|
|
6
|
+
if (!flowName || !scheduleId) {
|
|
7
|
+
throw createError({ statusCode: 400, statusMessage: "Flow name and schedule ID are required" });
|
|
8
|
+
}
|
|
9
|
+
const registry = $useQueueRegistry();
|
|
10
|
+
const flow = registry?.flows?.[flowName];
|
|
11
|
+
if (!flow || !flow.entry) {
|
|
12
|
+
throw createError({ statusCode: 404, statusMessage: `Flow '${flowName}' not found` });
|
|
13
|
+
}
|
|
14
|
+
const queueName = typeof flow.entry.queue === "string" ? flow.entry.queue : flow.entry.queue?.name || flow.entry.queue;
|
|
15
|
+
const rc = useRuntimeConfig();
|
|
16
|
+
const connection = rc.queue?.redis;
|
|
17
|
+
let prefix;
|
|
18
|
+
try {
|
|
19
|
+
if (registry && Array.isArray(registry.workers)) {
|
|
20
|
+
const worker = registry.workers.find((w) => w?.queue?.name === queueName);
|
|
21
|
+
if (worker?.queue?.prefix) {
|
|
22
|
+
prefix = worker.queue.prefix;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
} catch {
|
|
26
|
+
}
|
|
27
|
+
const queue = new Queue(queueName, { connection, prefix });
|
|
28
|
+
try {
|
|
29
|
+
await queue.removeRepeatableByKey(scheduleId);
|
|
30
|
+
await queue.close();
|
|
31
|
+
return {
|
|
32
|
+
success: true,
|
|
33
|
+
message: "Schedule deleted successfully"
|
|
34
|
+
};
|
|
35
|
+
} catch (error) {
|
|
36
|
+
await queue.close();
|
|
37
|
+
throw createError({
|
|
38
|
+
statusCode: 500,
|
|
39
|
+
statusMessage: `Failed to delete schedule: ${error.message}`
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { defineEventHandler, getRouterParam, createError, useRuntimeConfig, $useQueueRegistry } from "#imports";
|
|
2
|
+
import { Queue } from "bullmq";
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const flowName = getRouterParam(event, "name");
|
|
5
|
+
if (!flowName) {
|
|
6
|
+
throw createError({ statusCode: 400, statusMessage: "Flow name is required" });
|
|
7
|
+
}
|
|
8
|
+
const registry = $useQueueRegistry();
|
|
9
|
+
const flow = registry?.flows?.[flowName];
|
|
10
|
+
if (!flow || !flow.entry) {
|
|
11
|
+
throw createError({ statusCode: 404, statusMessage: `Flow '${flowName}' not found` });
|
|
12
|
+
}
|
|
13
|
+
const rc = useRuntimeConfig();
|
|
14
|
+
const connection = rc.queue?.redis;
|
|
15
|
+
const queueName = typeof flow.entry.queue === "string" ? flow.entry.queue : flow.entry.queue?.name || flow.entry.queue;
|
|
16
|
+
let prefix;
|
|
17
|
+
try {
|
|
18
|
+
if (registry && Array.isArray(registry.workers)) {
|
|
19
|
+
const worker = registry.workers.find((w) => w?.queue?.name === queueName);
|
|
20
|
+
if (worker?.queue?.prefix) {
|
|
21
|
+
prefix = worker.queue.prefix;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
const queue = new Queue(queueName, { connection, prefix });
|
|
27
|
+
try {
|
|
28
|
+
const repeatableJobs = await queue.getRepeatableJobs();
|
|
29
|
+
const schedules = repeatableJobs.filter((job) => job.name === flow.entry.step).map((job) => ({
|
|
30
|
+
id: job.key,
|
|
31
|
+
flowName,
|
|
32
|
+
queue: queueName,
|
|
33
|
+
step: flow.entry.step,
|
|
34
|
+
schedule: {
|
|
35
|
+
cron: job.pattern
|
|
36
|
+
},
|
|
37
|
+
nextRun: job.next ? new Date(job.next).toISOString() : void 0
|
|
38
|
+
}));
|
|
39
|
+
await queue.close();
|
|
40
|
+
return schedules;
|
|
41
|
+
} catch (error) {
|
|
42
|
+
await queue.close();
|
|
43
|
+
throw createError({
|
|
44
|
+
statusCode: 500,
|
|
45
|
+
statusMessage: `Failed to list schedules: ${error.message}`
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { defineEventHandler, getRouterParam, createError, readBody, useFlowEngine } from "#imports";
|
|
2
|
+
export default defineEventHandler(async (event) => {
|
|
3
|
+
const flowName = getRouterParam(event, "name");
|
|
4
|
+
if (!flowName) throw createError({ statusCode: 400, statusMessage: "Flow name is required" });
|
|
5
|
+
const { startFlow } = useFlowEngine();
|
|
6
|
+
const body = await readBody(event);
|
|
7
|
+
const result = await startFlow(flowName, body || {});
|
|
8
|
+
return result;
|
|
9
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket endpoint for flow run events
|
|
3
|
+
* Supports subscribing to specific flow runs and receiving real-time updates
|
|
4
|
+
*
|
|
5
|
+
* Message format (client -> server):
|
|
6
|
+
* {
|
|
7
|
+
* "type": "subscribe",
|
|
8
|
+
* "flowName": "example",
|
|
9
|
+
* "runId": "abc123"
|
|
10
|
+
* }
|
|
11
|
+
*
|
|
12
|
+
* {
|
|
13
|
+
* "type": "unsubscribe",
|
|
14
|
+
* "flowName": "example",
|
|
15
|
+
* "runId": "abc123"
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* {
|
|
19
|
+
* "type": "ping"
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* Message format (server -> client):
|
|
23
|
+
* {
|
|
24
|
+
* "type": "event",
|
|
25
|
+
* "flowName": "example",
|
|
26
|
+
* "runId": "abc123",
|
|
27
|
+
* "event": { v: 1, eventType: "...", record: {...} }
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* {
|
|
31
|
+
* "type": "history",
|
|
32
|
+
* "flowName": "example",
|
|
33
|
+
* "runId": "abc123",
|
|
34
|
+
* "events": [ ...historicalEvents ]
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* {
|
|
38
|
+
* "type": "subscribed",
|
|
39
|
+
* "flowName": "example",
|
|
40
|
+
* "runId": "abc123"
|
|
41
|
+
* }
|
|
42
|
+
*
|
|
43
|
+
* {
|
|
44
|
+
* "type": "unsubscribed",
|
|
45
|
+
* "flowName": "example",
|
|
46
|
+
* "runId": "abc123"
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* {
|
|
50
|
+
* "type": "pong",
|
|
51
|
+
* "timestamp": 1234567890
|
|
52
|
+
* }
|
|
53
|
+
*
|
|
54
|
+
* {
|
|
55
|
+
* "type": "error",
|
|
56
|
+
* "message": "error description"
|
|
57
|
+
* }
|
|
58
|
+
*/
|
|
59
|
+
declare const _default: any;
|
|
60
|
+
export default _default;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineWebSocketHandler,
|
|
3
|
+
useEventStore,
|
|
4
|
+
registerWsPeer,
|
|
5
|
+
unregisterWsPeer,
|
|
6
|
+
useServerLogger
|
|
7
|
+
} from "#imports";
|
|
8
|
+
const logger = useServerLogger("api-flows-ws");
|
|
9
|
+
const peerContexts = /* @__PURE__ */ new WeakMap();
|
|
10
|
+
function safeSend(peer, data) {
|
|
11
|
+
try {
|
|
12
|
+
peer.send(JSON.stringify(data));
|
|
13
|
+
return true;
|
|
14
|
+
} catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export default defineWebSocketHandler({
|
|
19
|
+
open(peer) {
|
|
20
|
+
logger.info("[ws] client connected:", { peerId: peer.id });
|
|
21
|
+
registerWsPeer(peer);
|
|
22
|
+
peerContexts.set(peer, {
|
|
23
|
+
subscriptions: /* @__PURE__ */ new Map()
|
|
24
|
+
});
|
|
25
|
+
safeSend(peer, {
|
|
26
|
+
type: "connected",
|
|
27
|
+
timestamp: Date.now()
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
async message(peer, message) {
|
|
31
|
+
const context = peerContexts.get(peer);
|
|
32
|
+
if (!context) {
|
|
33
|
+
logger.error("[ws] no context for peer:", { peerId: peer.id });
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
let data;
|
|
37
|
+
try {
|
|
38
|
+
data = JSON.parse(message.text());
|
|
39
|
+
} catch {
|
|
40
|
+
safeSend(peer, {
|
|
41
|
+
type: "error",
|
|
42
|
+
message: "Invalid JSON"
|
|
43
|
+
});
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const { type, flowName, runId } = data;
|
|
47
|
+
if (type === "subscribe") {
|
|
48
|
+
if (!flowName || !runId) {
|
|
49
|
+
safeSend(peer, {
|
|
50
|
+
type: "error",
|
|
51
|
+
message: "Missing flowName or runId"
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const store = useEventStore();
|
|
56
|
+
const names = store.names();
|
|
57
|
+
const flowStream = names.flow(runId);
|
|
58
|
+
const subscriptionKey = `${flowName}:${runId}`;
|
|
59
|
+
const existingUnsub = context.subscriptions.get(subscriptionKey);
|
|
60
|
+
if (existingUnsub) {
|
|
61
|
+
try {
|
|
62
|
+
existingUnsub();
|
|
63
|
+
} catch (err) {
|
|
64
|
+
logger.error("[ws] error unsubscribing:", { error: err });
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const unsub = store.subscribe(flowStream, async (event) => {
|
|
68
|
+
safeSend(peer, {
|
|
69
|
+
type: "event",
|
|
70
|
+
flowName,
|
|
71
|
+
runId,
|
|
72
|
+
event: {
|
|
73
|
+
v: 1,
|
|
74
|
+
eventType: event.type,
|
|
75
|
+
record: event
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
context.subscriptions.set(subscriptionKey, unsub);
|
|
80
|
+
try {
|
|
81
|
+
const historicalEvents = await store.read(flowStream, {
|
|
82
|
+
limit: 100,
|
|
83
|
+
direction: "forward"
|
|
84
|
+
});
|
|
85
|
+
safeSend(peer, {
|
|
86
|
+
type: "history",
|
|
87
|
+
flowName,
|
|
88
|
+
runId,
|
|
89
|
+
events: historicalEvents.map((e) => ({
|
|
90
|
+
v: 1,
|
|
91
|
+
eventType: e.kind || e.type,
|
|
92
|
+
record: e
|
|
93
|
+
}))
|
|
94
|
+
});
|
|
95
|
+
} catch (err) {
|
|
96
|
+
logger.error("[ws] error sending history:", { error: err });
|
|
97
|
+
safeSend(peer, {
|
|
98
|
+
type: "error",
|
|
99
|
+
message: "Failed to load history"
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
safeSend(peer, {
|
|
103
|
+
type: "subscribed",
|
|
104
|
+
flowName,
|
|
105
|
+
runId
|
|
106
|
+
});
|
|
107
|
+
} else if (type === "unsubscribe") {
|
|
108
|
+
if (!flowName || !runId) {
|
|
109
|
+
safeSend(peer, {
|
|
110
|
+
type: "error",
|
|
111
|
+
message: "Missing flowName or runId"
|
|
112
|
+
});
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const subscriptionKey = `${flowName}:${runId}`;
|
|
116
|
+
const unsub = context.subscriptions.get(subscriptionKey);
|
|
117
|
+
if (unsub) {
|
|
118
|
+
try {
|
|
119
|
+
unsub();
|
|
120
|
+
context.subscriptions.delete(subscriptionKey);
|
|
121
|
+
safeSend(peer, {
|
|
122
|
+
type: "unsubscribed",
|
|
123
|
+
flowName,
|
|
124
|
+
runId
|
|
125
|
+
});
|
|
126
|
+
} catch (err) {
|
|
127
|
+
logger.error("[ws] error unsubscribing:", { error: err });
|
|
128
|
+
safeSend(peer, {
|
|
129
|
+
type: "error",
|
|
130
|
+
message: "Failed to unsubscribe"
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
} else if (type === "ping") {
|
|
135
|
+
safeSend(peer, {
|
|
136
|
+
type: "pong",
|
|
137
|
+
timestamp: Date.now()
|
|
138
|
+
});
|
|
139
|
+
} else {
|
|
140
|
+
safeSend(peer, {
|
|
141
|
+
type: "error",
|
|
142
|
+
message: `Unknown message type: ${type}`
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
close(peer, event) {
|
|
147
|
+
const isNormalClosure = event?.code === 1e3 || event?.code === 1001;
|
|
148
|
+
if (!isNormalClosure) {
|
|
149
|
+
logger.info("[ws] client disconnected:", { peerId: peer.id, code: event?.code, reason: event?.reason });
|
|
150
|
+
}
|
|
151
|
+
unregisterWsPeer(peer);
|
|
152
|
+
const context = peerContexts.get(peer);
|
|
153
|
+
if (context) {
|
|
154
|
+
for (const unsub of context.subscriptions.values()) {
|
|
155
|
+
try {
|
|
156
|
+
unsub();
|
|
157
|
+
} catch (err) {
|
|
158
|
+
if (!isNormalClosure) {
|
|
159
|
+
logger.error("[ws] error unsubscribing on close:", { error: err });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
context.subscriptions.clear();
|
|
164
|
+
peerContexts.delete(peer);
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
error(peer, error) {
|
|
168
|
+
logger.error("[ws] error for peer:", { peerId: peer.id, error });
|
|
169
|
+
unregisterWsPeer(peer);
|
|
170
|
+
const context = peerContexts.get(peer);
|
|
171
|
+
if (context) {
|
|
172
|
+
for (const unsub of context.subscriptions.values()) {
|
|
173
|
+
try {
|
|
174
|
+
unsub();
|
|
175
|
+
} catch (err) {
|
|
176
|
+
logger.error("[ws] error unsubscribing on error:", { error: err });
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
context.subscriptions.clear();
|
|
180
|
+
peerContexts.delete(peer);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { defineEventHandler, getRouterParam, useQueue } from "#imports";
|
|
2
|
+
export default defineEventHandler(async (event) => {
|
|
3
|
+
const name = getRouterParam(event, "name") || "";
|
|
4
|
+
const id = getRouterParam(event, "id") || "";
|
|
5
|
+
const { getJob } = useQueue();
|
|
6
|
+
const job = await getJob(name, id);
|
|
7
|
+
if (!job) return null;
|
|
8
|
+
return { ...job, queue: name };
|
|
9
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineEventHandler, getRouterParam, getQuery, useQueue, createError } from "#imports";
|
|
2
|
+
export default defineEventHandler(async (event) => {
|
|
3
|
+
const name = getRouterParam(event, "name");
|
|
4
|
+
if (!name) {
|
|
5
|
+
throw createError({ statusCode: 400, statusMessage: "Missing queue name" });
|
|
6
|
+
}
|
|
7
|
+
const query = getQuery(event);
|
|
8
|
+
const state = query.state;
|
|
9
|
+
const { getJobs } = useQueue();
|
|
10
|
+
const jobs = await getJobs(name, {
|
|
11
|
+
state: state ? [state] : void 0,
|
|
12
|
+
limit: 1e3
|
|
13
|
+
// Fetch all jobs, pagination happens client-side
|
|
14
|
+
});
|
|
15
|
+
return {
|
|
16
|
+
jobs
|
|
17
|
+
};
|
|
18
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { defineEventHandler, useRuntimeConfig, $useQueueRegistry, useQueue, useServerLogger } from "#imports";
|
|
2
|
+
const logger = useServerLogger("api-queues-index");
|
|
3
|
+
export default defineEventHandler(async () => {
|
|
4
|
+
const rc = useRuntimeConfig();
|
|
5
|
+
const cfgQueues = rc?.queue?.queues || {};
|
|
6
|
+
const registry = $useQueueRegistry();
|
|
7
|
+
const queue = useQueue();
|
|
8
|
+
const names = /* @__PURE__ */ new Set();
|
|
9
|
+
for (const q in cfgQueues) names.add(q);
|
|
10
|
+
if (registry?.workers?.length) {
|
|
11
|
+
for (const w of registry.workers) names.add(w.queue.name);
|
|
12
|
+
}
|
|
13
|
+
const queuesWithCounts = await Promise.all(
|
|
14
|
+
Array.from(names).map(async (name) => {
|
|
15
|
+
try {
|
|
16
|
+
const counts = await queue.getJobCounts(name);
|
|
17
|
+
const isPaused = await queue.isPaused(name);
|
|
18
|
+
const worker = registry?.workers?.find((w) => w.queue.name === name);
|
|
19
|
+
const queueConfig = worker?.queue || {};
|
|
20
|
+
const workerConfig = worker?.worker || {};
|
|
21
|
+
return {
|
|
22
|
+
name,
|
|
23
|
+
counts,
|
|
24
|
+
isPaused,
|
|
25
|
+
config: {
|
|
26
|
+
queue: {
|
|
27
|
+
prefix: queueConfig.prefix,
|
|
28
|
+
defaultJobOptions: queueConfig.defaultJobOptions,
|
|
29
|
+
limiter: queueConfig.limiter
|
|
30
|
+
},
|
|
31
|
+
worker: {
|
|
32
|
+
concurrency: workerConfig.concurrency,
|
|
33
|
+
lockDurationMs: workerConfig.lockDurationMs,
|
|
34
|
+
maxStalledCount: workerConfig.maxStalledCount,
|
|
35
|
+
drainDelayMs: workerConfig.drainDelayMs,
|
|
36
|
+
autorun: workerConfig.autorun,
|
|
37
|
+
pollingIntervalMs: workerConfig.pollingIntervalMs
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
} catch (err) {
|
|
42
|
+
logger.error(`Failed to get counts for queue ${name}:`, { error: err });
|
|
43
|
+
return {
|
|
44
|
+
name,
|
|
45
|
+
counts: {
|
|
46
|
+
active: 0,
|
|
47
|
+
completed: 0,
|
|
48
|
+
failed: 0,
|
|
49
|
+
delayed: 0,
|
|
50
|
+
waiting: 0,
|
|
51
|
+
paused: 0
|
|
52
|
+
},
|
|
53
|
+
isPaused: false,
|
|
54
|
+
config: {
|
|
55
|
+
queue: {},
|
|
56
|
+
worker: {}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
return queuesWithCounts;
|
|
63
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket endpoint for queue events
|
|
3
|
+
* Supports subscribing to specific queues and receiving real-time job updates
|
|
4
|
+
*
|
|
5
|
+
* Message format (client -> server):
|
|
6
|
+
* {
|
|
7
|
+
* "type": "subscribe",
|
|
8
|
+
* "queueName": "test"
|
|
9
|
+
* }
|
|
10
|
+
*
|
|
11
|
+
* {
|
|
12
|
+
* "type": "unsubscribe",
|
|
13
|
+
* "queueName": "test"
|
|
14
|
+
* }
|
|
15
|
+
*
|
|
16
|
+
* {
|
|
17
|
+
* "type": "ping"
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* Message format (server -> client):
|
|
21
|
+
* {
|
|
22
|
+
* "type": "event",
|
|
23
|
+
* "queueName": "test",
|
|
24
|
+
* "event": { eventType: "waiting|active|completed|failed", jobId: "...", ... }
|
|
25
|
+
* }
|
|
26
|
+
*
|
|
27
|
+
* {
|
|
28
|
+
* "type": "subscribed",
|
|
29
|
+
* "queueName": "test"
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* {
|
|
33
|
+
* "type": "unsubscribed",
|
|
34
|
+
* "queueName": "test"
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* {
|
|
38
|
+
* "type": "pong",
|
|
39
|
+
* "timestamp": 1234567890
|
|
40
|
+
* }
|
|
41
|
+
*
|
|
42
|
+
* {
|
|
43
|
+
* "type": "error",
|
|
44
|
+
* "message": "error description"
|
|
45
|
+
* }
|
|
46
|
+
*/
|
|
47
|
+
declare const _default: any;
|
|
48
|
+
export default _default;
|