@nvent-addon/app 0.5.15 → 1.0.0-alpha.10
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/dist/module.json +1 -1
- package/dist/module.mjs +3 -2
- package/dist/runtime/app/components/DashboardCard.d.vue.ts +1 -1
- package/dist/runtime/app/components/DashboardCard.vue.d.ts +1 -1
- package/dist/runtime/app/composables/useWorkers.d.ts +57 -0
- package/dist/runtime/app/composables/useWorkers.js +42 -0
- package/dist/runtime/app/pages/dashboard.vue +1 -654
- package/dist/runtime/app/pages/index.vue +25 -41
- package/dist/runtime/app/pages/workers.vue +458 -0
- package/dist/runtime/server/api/_workers/index.get.d.ts +8 -0
- package/dist/runtime/server/api/_workers/index.get.js +14 -0
- package/package.json +13 -12
- package/dist/runtime/app/components/ComponentRouter.d.vue.ts +0 -46
- package/dist/runtime/app/components/ComponentRouter.vue +0 -26
- package/dist/runtime/app/components/ComponentRouter.vue.d.ts +0 -46
- package/dist/runtime/app/components/ComponentShell.d.vue.ts +0 -23
- package/dist/runtime/app/components/ComponentShell.vue +0 -97
- package/dist/runtime/app/components/ComponentShell.vue.d.ts +0 -23
- package/dist/runtime/app/components/ConfirmDialog.d.vue.ts +0 -33
- package/dist/runtime/app/components/ConfirmDialog.vue +0 -120
- package/dist/runtime/app/components/ConfirmDialog.vue.d.ts +0 -33
- package/dist/runtime/app/composables/useComponentRouter.d.ts +0 -46
- package/dist/runtime/app/composables/useComponentRouter.js +0 -248
- package/dist/runtime/app/pages/flows/[name].vue +0 -750
- package/dist/runtime/app/pages/flows/index.d.vue.ts +0 -3
- package/dist/runtime/app/pages/flows/index.vue +0 -381
- package/dist/runtime/app/pages/flows/index.vue.d.ts +0 -3
- package/dist/runtime/app/pages/queues/index.d.vue.ts +0 -3
- package/dist/runtime/app/pages/queues/index.vue +0 -236
- package/dist/runtime/app/pages/queues/index.vue.d.ts +0 -3
- package/dist/runtime/app/pages/queues/job.d.vue.ts +0 -3
- package/dist/runtime/app/pages/queues/job.vue +0 -261
- package/dist/runtime/app/pages/queues/job.vue.d.ts +0 -3
- package/dist/runtime/app/pages/queues/jobs.d.vue.ts +0 -3
- package/dist/runtime/app/pages/queues/jobs.vue +0 -595
- package/dist/runtime/app/pages/queues/jobs.vue.d.ts +0 -3
- package/dist/runtime/app/pages/settings/scheduler.d.vue.ts +0 -3
- package/dist/runtime/app/pages/settings/scheduler.vue +0 -310
- package/dist/runtime/app/pages/settings/scheduler.vue.d.ts +0 -3
- package/dist/runtime/app/pages/triggers/[name]/edit.d.vue.ts +0 -3
- package/dist/runtime/app/pages/triggers/[name]/edit.vue +0 -429
- package/dist/runtime/app/pages/triggers/[name]/edit.vue.d.ts +0 -3
- package/dist/runtime/app/pages/triggers/[name].d.vue.ts +0 -3
- package/dist/runtime/app/pages/triggers/[name].vue +0 -870
- package/dist/runtime/app/pages/triggers/[name].vue.d.ts +0 -3
- package/dist/runtime/app/pages/triggers/index.d.vue.ts +0 -3
- package/dist/runtime/app/pages/triggers/index.vue +0 -525
- package/dist/runtime/app/pages/triggers/index.vue.d.ts +0 -3
- package/dist/runtime/app/pages/triggers/new.d.vue.ts +0 -3
- package/dist/runtime/app/pages/triggers/new.vue +0 -610
- package/dist/runtime/app/pages/triggers/new.vue.d.ts +0 -3
- package/dist/runtime/server/api/_flows/[name]/clear-history.delete.d.ts +0 -10
- package/dist/runtime/server/api/_flows/[name]/clear-history.delete.js +0 -49
- package/dist/runtime/server/api/_flows/[name]/runs/[runId]/cancel.post.d.ts +0 -2
- package/dist/runtime/server/api/_flows/[name]/runs/[runId]/cancel.post.js +0 -21
- package/dist/runtime/server/api/_flows/[name]/runs/[runId]/restart.post.d.ts +0 -2
- package/dist/runtime/server/api/_flows/[name]/runs/[runId]/restart.post.js +0 -21
- package/dist/runtime/server/api/_flows/[name]/runs.get.d.ts +0 -17
- package/dist/runtime/server/api/_flows/[name]/runs.get.js +0 -64
- package/dist/runtime/server/api/_flows/[name]/start.post.d.ts +0 -2
- package/dist/runtime/server/api/_flows/[name]/start.post.js +0 -9
- package/dist/runtime/server/api/_flows/index.get.d.ts +0 -7
- package/dist/runtime/server/api/_flows/index.get.js +0 -5
- package/dist/runtime/server/api/_flows/recent-runs.get.d.ts +0 -15
- package/dist/runtime/server/api/_flows/recent-runs.get.js +0 -67
- package/dist/runtime/server/api/_flows/ws.d.ts +0 -80
- package/dist/runtime/server/api/_flows/ws.js +0 -309
- package/dist/runtime/server/api/_queues/[name]/job/[id].get.d.ts +0 -2
- package/dist/runtime/server/api/_queues/[name]/job/[id].get.js +0 -14
- package/dist/runtime/server/api/_queues/[name]/job/index.get.d.ts +0 -2
- package/dist/runtime/server/api/_queues/[name]/job/index.get.js +0 -39
- package/dist/runtime/server/api/_queues/index.get.d.ts +0 -2
- package/dist/runtime/server/api/_queues/index.get.js +0 -106
- package/dist/runtime/server/api/_queues/ws.d.ts +0 -48
- package/dist/runtime/server/api/_queues/ws.js +0 -215
- package/dist/runtime/server/api/_scheduler/jobs.get.d.ts +0 -19
- package/dist/runtime/server/api/_scheduler/jobs.get.js +0 -36
- package/dist/runtime/server/api/_triggers/[name]/events.get.d.ts +0 -6
- package/dist/runtime/server/api/_triggers/[name]/events.get.js +0 -43
- package/dist/runtime/server/api/_triggers/[name]/index.get.d.ts +0 -6
- package/dist/runtime/server/api/_triggers/[name]/index.get.js +0 -76
- package/dist/runtime/server/api/_triggers/[name].delete.d.ts +0 -7
- package/dist/runtime/server/api/_triggers/[name].delete.js +0 -37
- package/dist/runtime/server/api/_triggers/[name].patch.d.ts +0 -7
- package/dist/runtime/server/api/_triggers/[name].patch.js +0 -117
- package/dist/runtime/server/api/_triggers/index.get.d.ts +0 -6
- package/dist/runtime/server/api/_triggers/index.get.js +0 -44
- package/dist/runtime/server/api/_triggers/index.post.d.ts +0 -7
- package/dist/runtime/server/api/_triggers/index.post.js +0 -124
- package/dist/runtime/server/api/_triggers/stats.get.d.ts +0 -6
- package/dist/runtime/server/api/_triggers/stats.get.js +0 -41
- package/dist/runtime/server/api/_triggers/ws.d.ts +0 -74
- package/dist/runtime/server/api/_triggers/ws.js +0 -315
- /package/dist/runtime/app/pages/{flows/[name].d.vue.ts → workers.d.vue.ts} +0 -0
- /package/dist/runtime/app/pages/{flows/[name].vue.d.ts → workers.vue.d.ts} +0 -0
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { defineEventHandler, getRouterParam, createError, useFlow } from "#imports";
|
|
2
|
-
export default defineEventHandler(async (event) => {
|
|
3
|
-
const flowName = getRouterParam(event, "name");
|
|
4
|
-
const runId = getRouterParam(event, "runId");
|
|
5
|
-
if (!flowName || !runId) {
|
|
6
|
-
throw createError({
|
|
7
|
-
statusCode: 400,
|
|
8
|
-
statusMessage: "Flow name and run ID are required"
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
const flowEngine = useFlow();
|
|
12
|
-
try {
|
|
13
|
-
const result = await flowEngine.cancelFlow(flowName, runId);
|
|
14
|
-
return result;
|
|
15
|
-
} catch (error) {
|
|
16
|
-
throw createError({
|
|
17
|
-
statusCode: 500,
|
|
18
|
-
statusMessage: `Failed to cancel flow: ${error.message}`
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { defineEventHandler, getRouterParam, createError, useFlow } from "#imports";
|
|
2
|
-
export default defineEventHandler(async (event) => {
|
|
3
|
-
const flowName = getRouterParam(event, "name");
|
|
4
|
-
const runId = getRouterParam(event, "runId");
|
|
5
|
-
if (!flowName || !runId) {
|
|
6
|
-
throw createError({
|
|
7
|
-
statusCode: 400,
|
|
8
|
-
statusMessage: "Flow name and run ID are required"
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
const flowEngine = useFlow();
|
|
12
|
-
try {
|
|
13
|
-
const result = await flowEngine.restartFlow(flowName, runId);
|
|
14
|
-
return result;
|
|
15
|
-
} catch (error) {
|
|
16
|
-
throw createError({
|
|
17
|
-
statusCode: 500,
|
|
18
|
-
statusMessage: `Failed to restart flow: ${error.message}`
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GET /api/_flows/:flowName/runs
|
|
3
|
-
*
|
|
4
|
-
* Returns a list of flow runs with their metadata from the sorted set index.
|
|
5
|
-
* Supports pagination via offset/limit query params.
|
|
6
|
-
*
|
|
7
|
-
* Query params:
|
|
8
|
-
* - limit: number (default: 50)
|
|
9
|
-
* - offset: number (default: 0)
|
|
10
|
-
*
|
|
11
|
-
* Returns:
|
|
12
|
-
* {
|
|
13
|
-
* runs: Array<{ id, score, metadata }>
|
|
14
|
-
* }
|
|
15
|
-
*/
|
|
16
|
-
declare const _default: any;
|
|
17
|
-
export default _default;
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { defineEventHandler, getRouterParam, getQuery, useStoreAdapter, useNventLogger, useStreamTopics } from "#imports";
|
|
2
|
-
export default defineEventHandler(async (event) => {
|
|
3
|
-
const logger = useNventLogger("api-flows-runs");
|
|
4
|
-
const flowName = getRouterParam(event, "name");
|
|
5
|
-
const query = getQuery(event);
|
|
6
|
-
const limit = Math.min(Number.parseInt(query.limit) || 50, 100);
|
|
7
|
-
const offset = Math.max(Number.parseInt(query.offset) || 0, 0);
|
|
8
|
-
const status = query.status;
|
|
9
|
-
event.node.res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
|
10
|
-
event.node.res.setHeader("Pragma", "no-cache");
|
|
11
|
-
if (!flowName) {
|
|
12
|
-
return { error: "Missing flow name" };
|
|
13
|
-
}
|
|
14
|
-
let store;
|
|
15
|
-
let StoreSubjects;
|
|
16
|
-
try {
|
|
17
|
-
store = useStoreAdapter();
|
|
18
|
-
const topics = useStreamTopics();
|
|
19
|
-
StoreSubjects = topics.StoreSubjects;
|
|
20
|
-
} catch (err) {
|
|
21
|
-
logger.error("[flows/runs] Adapters not initialized yet:", { error: err });
|
|
22
|
-
return {
|
|
23
|
-
error: "Server initializing",
|
|
24
|
-
message: "Please retry in a moment"
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
try {
|
|
28
|
-
const runIndexKey = StoreSubjects.flowRunIndex(flowName);
|
|
29
|
-
let totalCount = 0;
|
|
30
|
-
try {
|
|
31
|
-
const allEntries = await store.index.read(runIndexKey, { limit: 1e4 });
|
|
32
|
-
totalCount = allEntries.length;
|
|
33
|
-
} catch {
|
|
34
|
-
totalCount = 0;
|
|
35
|
-
}
|
|
36
|
-
const entries = await store.index.read(runIndexKey, { offset, limit });
|
|
37
|
-
const filteredEntries = status ? entries.filter((e) => e.metadata?.status === status) : entries;
|
|
38
|
-
const items = filteredEntries.map((entry) => ({
|
|
39
|
-
id: entry.id,
|
|
40
|
-
flowName,
|
|
41
|
-
status: entry.metadata?.status || "unknown",
|
|
42
|
-
createdAt: new Date(entry.score).toISOString(),
|
|
43
|
-
startedAt: entry.metadata?.startedAt ? new Date(entry.metadata.startedAt).toISOString() : void 0,
|
|
44
|
-
completedAt: entry.metadata?.completedAt ? new Date(entry.metadata.completedAt).toISOString() : void 0,
|
|
45
|
-
stepCount: entry.metadata?.stepCount || 0,
|
|
46
|
-
completedSteps: entry.metadata?.completedSteps || 0
|
|
47
|
-
}));
|
|
48
|
-
return {
|
|
49
|
-
flowName,
|
|
50
|
-
count: items.length,
|
|
51
|
-
total: totalCount,
|
|
52
|
-
offset,
|
|
53
|
-
limit,
|
|
54
|
-
hasMore: offset + items.length < totalCount,
|
|
55
|
-
items
|
|
56
|
-
};
|
|
57
|
-
} catch (err) {
|
|
58
|
-
logger.error("[flows/runs] error:", { error: err });
|
|
59
|
-
return {
|
|
60
|
-
error: "Failed to list runs",
|
|
61
|
-
message: err instanceof Error ? err.message : String(err)
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
});
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { defineEventHandler, getRouterParam, createError, readBody, useFlow } 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 } = useFlow();
|
|
6
|
-
const body = await readBody(event);
|
|
7
|
-
const result = await startFlow(flowName, body || {});
|
|
8
|
-
return result;
|
|
9
|
-
});
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* GET /api/_flows/recent-runs
|
|
3
|
-
*
|
|
4
|
-
* Returns a list of recent flow runs across all flows.
|
|
5
|
-
*
|
|
6
|
-
* Query params:
|
|
7
|
-
* - limit: number (default: 10)
|
|
8
|
-
*
|
|
9
|
-
* Returns:
|
|
10
|
-
* {
|
|
11
|
-
* runs: Array<{ id, flowName, status, createdAt, ... }>
|
|
12
|
-
* }
|
|
13
|
-
*/
|
|
14
|
-
declare const _default: any;
|
|
15
|
-
export default _default;
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { defineEventHandler, getQuery, useStoreAdapter, useNventLogger, useStreamTopics, $useAnalyzedFlows } from "#imports";
|
|
2
|
-
export default defineEventHandler(async (event) => {
|
|
3
|
-
const logger = useNventLogger("api-flows-recent-runs");
|
|
4
|
-
const query = getQuery(event);
|
|
5
|
-
const limit = Math.min(Number.parseInt(query.limit) || 10, 50);
|
|
6
|
-
event.node.res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
|
7
|
-
event.node.res.setHeader("Pragma", "no-cache");
|
|
8
|
-
let store;
|
|
9
|
-
let StoreSubjects;
|
|
10
|
-
let flows;
|
|
11
|
-
try {
|
|
12
|
-
store = useStoreAdapter();
|
|
13
|
-
const topics = useStreamTopics();
|
|
14
|
-
StoreSubjects = topics.StoreSubjects;
|
|
15
|
-
flows = $useAnalyzedFlows();
|
|
16
|
-
} catch (err) {
|
|
17
|
-
logger.error("[flows/recent-runs] Adapters not initialized yet:", { error: err });
|
|
18
|
-
return {
|
|
19
|
-
error: "Server initializing",
|
|
20
|
-
message: "Please retry in a moment"
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
try {
|
|
24
|
-
const flowsList = flows || [];
|
|
25
|
-
const allRuns = [];
|
|
26
|
-
for (const flow of flowsList) {
|
|
27
|
-
try {
|
|
28
|
-
const flowName = flow.id || flow.name;
|
|
29
|
-
const runIndexKey = StoreSubjects.flowRunIndex(flowName);
|
|
30
|
-
const entries = await store.index.read(runIndexKey, { offset: 0, limit: 5 });
|
|
31
|
-
const flowRuns = entries.map((entry) => ({
|
|
32
|
-
id: entry.id,
|
|
33
|
-
flowName,
|
|
34
|
-
flowDisplayName: flow.displayName || flowName,
|
|
35
|
-
status: entry.metadata?.status || "unknown",
|
|
36
|
-
createdAt: entry.score,
|
|
37
|
-
// timestamp
|
|
38
|
-
startedAt: entry.metadata?.startedAt,
|
|
39
|
-
completedAt: entry.metadata?.completedAt,
|
|
40
|
-
stepCount: entry.metadata?.stepCount || 0,
|
|
41
|
-
completedSteps: entry.metadata?.completedSteps || 0
|
|
42
|
-
}));
|
|
43
|
-
allRuns.push(...flowRuns);
|
|
44
|
-
} catch (err) {
|
|
45
|
-
const flowName = flow.id || flow.name;
|
|
46
|
-
logger.debug(`No runs found for flow ${flowName}`, { error: err });
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
allRuns.sort((a, b) => b.createdAt - a.createdAt);
|
|
50
|
-
const recentRuns = allRuns.slice(0, limit);
|
|
51
|
-
return {
|
|
52
|
-
count: recentRuns.length,
|
|
53
|
-
items: recentRuns.map((run) => ({
|
|
54
|
-
...run,
|
|
55
|
-
createdAt: new Date(run.createdAt).toISOString(),
|
|
56
|
-
startedAt: run.startedAt ? new Date(run.startedAt).toISOString() : void 0,
|
|
57
|
-
completedAt: run.completedAt ? new Date(run.completedAt).toISOString() : void 0
|
|
58
|
-
}))
|
|
59
|
-
};
|
|
60
|
-
} catch (err) {
|
|
61
|
-
logger.error("[flows/recent-runs] error:", { error: err });
|
|
62
|
-
return {
|
|
63
|
-
error: "Failed to list recent runs",
|
|
64
|
-
message: err instanceof Error ? err.message : String(err)
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
});
|
|
@@ -1,80 +0,0 @@
|
|
|
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": "subscribe.stats"
|
|
20
|
-
* }
|
|
21
|
-
*
|
|
22
|
-
* {
|
|
23
|
-
* "type": "unsubscribe.stats"
|
|
24
|
-
* }
|
|
25
|
-
*
|
|
26
|
-
* {
|
|
27
|
-
* "type": "ping"
|
|
28
|
-
* }
|
|
29
|
-
*
|
|
30
|
-
* Message format (server -> client):
|
|
31
|
-
* {
|
|
32
|
-
* "type": "event",
|
|
33
|
-
* "flowName": "example",
|
|
34
|
-
* "runId": "abc123",
|
|
35
|
-
* "event": { v: 1, eventType: "...", record: {...} }
|
|
36
|
-
* }
|
|
37
|
-
*
|
|
38
|
-
* {
|
|
39
|
-
* "type": "history",
|
|
40
|
-
* "flowName": "example",
|
|
41
|
-
* "runId": "abc123",
|
|
42
|
-
* "events": [ ...historicalEvents ]
|
|
43
|
-
* }
|
|
44
|
-
*
|
|
45
|
-
* {
|
|
46
|
-
* "type": "subscribed",
|
|
47
|
-
* "flowName": "example",
|
|
48
|
-
* "runId": "abc123"
|
|
49
|
-
* }
|
|
50
|
-
*
|
|
51
|
-
* {
|
|
52
|
-
* "type": "unsubscribed",
|
|
53
|
-
* "flowName": "example",
|
|
54
|
-
* "runId": "abc123"
|
|
55
|
-
* }
|
|
56
|
-
*
|
|
57
|
-
* {
|
|
58
|
-
* "type": "pong",
|
|
59
|
-
* "timestamp": 1234567890
|
|
60
|
-
* }
|
|
61
|
-
*
|
|
62
|
-
* {
|
|
63
|
-
* "type": "flow.stats.initial",
|
|
64
|
-
* "data": { id: "flowName", metadata: {...} },
|
|
65
|
-
* "timestamp": 1234567890
|
|
66
|
-
* }
|
|
67
|
-
*
|
|
68
|
-
* {
|
|
69
|
-
* "type": "flow.stats.update",
|
|
70
|
-
* "data": { id: "flowName", metadata: {...} },
|
|
71
|
-
* "timestamp": 1234567890
|
|
72
|
-
* }
|
|
73
|
-
*
|
|
74
|
-
* {
|
|
75
|
-
* "type": "error",
|
|
76
|
-
* "message": "error description"
|
|
77
|
-
* }
|
|
78
|
-
*/
|
|
79
|
-
declare const _default: any;
|
|
80
|
-
export default _default;
|
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
defineWebSocketHandler,
|
|
3
|
-
usePeerManager,
|
|
4
|
-
useNventLogger,
|
|
5
|
-
useStreamAdapter,
|
|
6
|
-
useStoreAdapter,
|
|
7
|
-
useStreamTopics,
|
|
8
|
-
useFlow
|
|
9
|
-
} from "#imports";
|
|
10
|
-
const peerContexts = /* @__PURE__ */ new WeakMap();
|
|
11
|
-
function safeSend(peer, data) {
|
|
12
|
-
try {
|
|
13
|
-
peer.send(JSON.stringify(data));
|
|
14
|
-
return true;
|
|
15
|
-
} catch {
|
|
16
|
-
return false;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
export default defineWebSocketHandler({
|
|
20
|
-
async open(peer) {
|
|
21
|
-
const logger = useNventLogger("api-flows-ws");
|
|
22
|
-
logger.info("[ws] client connected:", { peerId: peer.id });
|
|
23
|
-
const { registerWsPeer } = usePeerManager();
|
|
24
|
-
registerWsPeer(peer);
|
|
25
|
-
peerContexts.set(peer, {
|
|
26
|
-
subscriptions: /* @__PURE__ */ new Map()
|
|
27
|
-
});
|
|
28
|
-
safeSend(peer, {
|
|
29
|
-
type: "connected",
|
|
30
|
-
timestamp: Date.now()
|
|
31
|
-
});
|
|
32
|
-
},
|
|
33
|
-
async message(peer, message) {
|
|
34
|
-
const logger = useNventLogger("api-flows-ws");
|
|
35
|
-
const context = peerContexts.get(peer);
|
|
36
|
-
if (!context) {
|
|
37
|
-
logger.error("[ws] no context for peer:", { peerId: peer.id });
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
let data;
|
|
41
|
-
try {
|
|
42
|
-
data = JSON.parse(message.text());
|
|
43
|
-
} catch {
|
|
44
|
-
safeSend(peer, {
|
|
45
|
-
type: "error",
|
|
46
|
-
message: "Invalid JSON"
|
|
47
|
-
});
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
const { type, flowName, runId } = data;
|
|
51
|
-
if (type === "subscribe") {
|
|
52
|
-
if (!flowName || !runId) {
|
|
53
|
-
safeSend(peer, {
|
|
54
|
-
type: "error",
|
|
55
|
-
message: "Missing flowName or runId"
|
|
56
|
-
});
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
let stream;
|
|
60
|
-
let store;
|
|
61
|
-
try {
|
|
62
|
-
stream = useStreamAdapter();
|
|
63
|
-
store = useStoreAdapter();
|
|
64
|
-
} catch (err) {
|
|
65
|
-
logger.error("[ws] Adapters not initialized yet:", { error: err });
|
|
66
|
-
safeSend(peer, {
|
|
67
|
-
type: "error",
|
|
68
|
-
message: "Server initializing, please retry"
|
|
69
|
-
});
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
const subscriptionKey = `flow:${flowName}:${runId}`;
|
|
73
|
-
const existingUnsub = context.subscriptions.get(subscriptionKey);
|
|
74
|
-
if (existingUnsub) {
|
|
75
|
-
try {
|
|
76
|
-
existingUnsub();
|
|
77
|
-
} catch (err) {
|
|
78
|
-
logger.error("[ws] error unsubscribing:", { error: err });
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
const { StoreSubjects, StreamTopics } = useStreamTopics();
|
|
82
|
-
const subject = StoreSubjects.flowRun(runId);
|
|
83
|
-
const topic = StreamTopics.flowEvents(runId);
|
|
84
|
-
const handle = await stream.subscribe(topic, async (message2) => {
|
|
85
|
-
const event = message2.data?.event;
|
|
86
|
-
if (!event) {
|
|
87
|
-
logger.warn("[ws] Received message without event data:", message2);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
safeSend(peer, {
|
|
91
|
-
type: "event",
|
|
92
|
-
flowName,
|
|
93
|
-
runId,
|
|
94
|
-
event: {
|
|
95
|
-
v: 1,
|
|
96
|
-
eventType: event.type,
|
|
97
|
-
record: event
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
const unsub = async () => {
|
|
102
|
-
try {
|
|
103
|
-
await handle.unsubscribe();
|
|
104
|
-
} catch (err) {
|
|
105
|
-
logger.error("[ws] error in unsub:", { error: err });
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
context.subscriptions.set(subscriptionKey, unsub);
|
|
109
|
-
try {
|
|
110
|
-
const historicalEvents = await store.stream.read(subject, {
|
|
111
|
-
limit: 100,
|
|
112
|
-
order: "asc"
|
|
113
|
-
// forward order
|
|
114
|
-
});
|
|
115
|
-
safeSend(peer, {
|
|
116
|
-
type: "history",
|
|
117
|
-
flowName,
|
|
118
|
-
runId,
|
|
119
|
-
events: historicalEvents.map((e) => ({
|
|
120
|
-
v: 1,
|
|
121
|
-
eventType: e.kind || e.type,
|
|
122
|
-
record: e
|
|
123
|
-
}))
|
|
124
|
-
});
|
|
125
|
-
} catch (err) {
|
|
126
|
-
logger.error("[ws] error sending history:", { error: err });
|
|
127
|
-
safeSend(peer, {
|
|
128
|
-
type: "error",
|
|
129
|
-
message: "Failed to load history"
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
safeSend(peer, {
|
|
133
|
-
type: "subscribed",
|
|
134
|
-
flowName,
|
|
135
|
-
runId
|
|
136
|
-
});
|
|
137
|
-
} else if (type === "unsubscribe") {
|
|
138
|
-
if (!flowName || !runId) {
|
|
139
|
-
safeSend(peer, {
|
|
140
|
-
type: "error",
|
|
141
|
-
message: "Missing flowName or runId"
|
|
142
|
-
});
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
const subscriptionKey = `flow:${flowName}:${runId}`;
|
|
146
|
-
const unsub = context.subscriptions.get(subscriptionKey);
|
|
147
|
-
if (unsub) {
|
|
148
|
-
try {
|
|
149
|
-
await unsub();
|
|
150
|
-
context.subscriptions.delete(subscriptionKey);
|
|
151
|
-
safeSend(peer, {
|
|
152
|
-
type: "unsubscribed",
|
|
153
|
-
flowName,
|
|
154
|
-
runId
|
|
155
|
-
});
|
|
156
|
-
} catch (err) {
|
|
157
|
-
logger.error("[ws] error unsubscribing:", { error: err });
|
|
158
|
-
safeSend(peer, {
|
|
159
|
-
type: "error",
|
|
160
|
-
message: "Failed to unsubscribe"
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
} else if (type === "subscribe.stats") {
|
|
165
|
-
const statsKey = "stats";
|
|
166
|
-
const existingUnsub = context.subscriptions.get(statsKey);
|
|
167
|
-
if (existingUnsub) {
|
|
168
|
-
safeSend(peer, {
|
|
169
|
-
type: "error",
|
|
170
|
-
message: "Already subscribed to stats"
|
|
171
|
-
});
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
try {
|
|
175
|
-
const stream = useStreamAdapter();
|
|
176
|
-
const { StreamTopics } = useStreamTopics();
|
|
177
|
-
const topic = StreamTopics.flowStats();
|
|
178
|
-
const handle = await stream.subscribe(topic, (message2) => {
|
|
179
|
-
safeSend(peer, {
|
|
180
|
-
type: "flow.stats.update",
|
|
181
|
-
data: message2,
|
|
182
|
-
timestamp: Date.now()
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
const unsub = async () => {
|
|
186
|
-
try {
|
|
187
|
-
await handle.unsubscribe();
|
|
188
|
-
} catch (err) {
|
|
189
|
-
logger.error("[ws] error in stats unsub:", { error: err });
|
|
190
|
-
}
|
|
191
|
-
};
|
|
192
|
-
context.subscriptions.set(statsKey, unsub);
|
|
193
|
-
try {
|
|
194
|
-
const flow = useFlow();
|
|
195
|
-
const allFlowStats = await flow.getAllFlowStats();
|
|
196
|
-
if (allFlowStats && allFlowStats.length > 0) {
|
|
197
|
-
for (const flowStat of allFlowStats) {
|
|
198
|
-
safeSend(peer, {
|
|
199
|
-
type: "flow.stats.initial",
|
|
200
|
-
data: {
|
|
201
|
-
id: flowStat.name,
|
|
202
|
-
metadata: {
|
|
203
|
-
name: flowStat.name,
|
|
204
|
-
displayName: flowStat.displayName,
|
|
205
|
-
registeredAt: flowStat.registeredAt,
|
|
206
|
-
lastRunAt: flowStat.lastRunAt,
|
|
207
|
-
lastCompletedAt: flowStat.lastCompletedAt,
|
|
208
|
-
stats: {
|
|
209
|
-
total: flowStat.stats.total,
|
|
210
|
-
success: flowStat.stats.success,
|
|
211
|
-
failure: flowStat.stats.failure,
|
|
212
|
-
cancel: flowStat.stats.cancel,
|
|
213
|
-
running: flowStat.stats.running,
|
|
214
|
-
awaiting: flowStat.stats.awaiting
|
|
215
|
-
},
|
|
216
|
-
version: flowStat.version
|
|
217
|
-
}
|
|
218
|
-
},
|
|
219
|
-
timestamp: Date.now()
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
} catch (err) {
|
|
224
|
-
logger.error("[ws] error fetching initial stats:", { error: err });
|
|
225
|
-
}
|
|
226
|
-
safeSend(peer, {
|
|
227
|
-
type: "stats.subscribed",
|
|
228
|
-
timestamp: Date.now()
|
|
229
|
-
});
|
|
230
|
-
} catch (err) {
|
|
231
|
-
logger.error("[ws] error subscribing to stats:", { error: err });
|
|
232
|
-
safeSend(peer, {
|
|
233
|
-
type: "error",
|
|
234
|
-
message: "Failed to subscribe to stats"
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
} else if (type === "unsubscribe.stats") {
|
|
238
|
-
const statsKey = "stats";
|
|
239
|
-
const unsub = context.subscriptions.get(statsKey);
|
|
240
|
-
if (unsub) {
|
|
241
|
-
try {
|
|
242
|
-
await unsub();
|
|
243
|
-
context.subscriptions.delete(statsKey);
|
|
244
|
-
safeSend(peer, {
|
|
245
|
-
type: "stats.unsubscribed",
|
|
246
|
-
timestamp: Date.now()
|
|
247
|
-
});
|
|
248
|
-
} catch (err) {
|
|
249
|
-
logger.error("[ws] error unsubscribing from stats:", { error: err });
|
|
250
|
-
safeSend(peer, {
|
|
251
|
-
type: "error",
|
|
252
|
-
message: "Failed to unsubscribe from stats"
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
} else if (type === "ping") {
|
|
257
|
-
safeSend(peer, {
|
|
258
|
-
type: "pong",
|
|
259
|
-
timestamp: Date.now()
|
|
260
|
-
});
|
|
261
|
-
} else {
|
|
262
|
-
safeSend(peer, {
|
|
263
|
-
type: "error",
|
|
264
|
-
message: `Unknown message type: ${type}`
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
},
|
|
268
|
-
async close(peer, event) {
|
|
269
|
-
const logger = useNventLogger("api-flows-ws");
|
|
270
|
-
const isNormalClosure = event?.code === 1e3 || event?.code === 1001;
|
|
271
|
-
if (!isNormalClosure) {
|
|
272
|
-
logger.info("[ws] client disconnected:", { peerId: peer.id, code: event?.code, reason: event?.reason });
|
|
273
|
-
}
|
|
274
|
-
const { unregisterWsPeer } = usePeerManager();
|
|
275
|
-
unregisterWsPeer(peer);
|
|
276
|
-
const context = peerContexts.get(peer);
|
|
277
|
-
if (context) {
|
|
278
|
-
for (const unsub of Array.from(context.subscriptions.values())) {
|
|
279
|
-
try {
|
|
280
|
-
await unsub();
|
|
281
|
-
} catch (err) {
|
|
282
|
-
if (!isNormalClosure) {
|
|
283
|
-
logger.error("[ws] error unsubscribing on close:", { error: err });
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
context.subscriptions.clear();
|
|
288
|
-
peerContexts.delete(peer);
|
|
289
|
-
}
|
|
290
|
-
},
|
|
291
|
-
async error(peer, error) {
|
|
292
|
-
const logger = useNventLogger("api-flows-ws");
|
|
293
|
-
logger.error("[ws] error for peer:", { peerId: peer.id, error });
|
|
294
|
-
const { unregisterWsPeer } = usePeerManager();
|
|
295
|
-
unregisterWsPeer(peer);
|
|
296
|
-
const context = peerContexts.get(peer);
|
|
297
|
-
if (context) {
|
|
298
|
-
for (const unsub of Array.from(context.subscriptions.values())) {
|
|
299
|
-
try {
|
|
300
|
-
await unsub();
|
|
301
|
-
} catch (err) {
|
|
302
|
-
logger.error("[ws] error unsubscribing on error:", { error: err });
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
context.subscriptions.clear();
|
|
306
|
-
peerContexts.delete(peer);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { defineEventHandler, getRouterParam, useQueueAdapter } from "#imports";
|
|
2
|
-
export default defineEventHandler(async (event) => {
|
|
3
|
-
const name = getRouterParam(event, "name") || "";
|
|
4
|
-
const id = getRouterParam(event, "id") || "";
|
|
5
|
-
let queue;
|
|
6
|
-
try {
|
|
7
|
-
queue = useQueueAdapter();
|
|
8
|
-
} catch {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
const job = await queue.getJob(name, id);
|
|
12
|
-
if (!job) return null;
|
|
13
|
-
return { ...job, queue: name };
|
|
14
|
-
});
|