nvent 0.4.5 → 0.5.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/dist/module.d.mts +1 -1
- package/dist/module.mjs +433 -175
- package/dist/runtime/adapters/base/index.d.ts +6 -0
- package/dist/runtime/adapters/base/index.js +1 -0
- package/dist/runtime/adapters/base/store-validator.d.ts +48 -0
- package/dist/runtime/adapters/base/store-validator.js +147 -0
- package/dist/runtime/adapters/builtin/file-queue.d.ts +15 -1
- package/dist/runtime/adapters/builtin/file-queue.js +70 -6
- package/dist/runtime/adapters/builtin/file-store.d.ts +4 -18
- package/dist/runtime/adapters/builtin/file-store.js +90 -109
- package/dist/runtime/adapters/builtin/memory-queue.js +4 -0
- package/dist/runtime/adapters/builtin/memory-store.d.ts +42 -31
- package/dist/runtime/adapters/builtin/memory-store.js +253 -183
- package/dist/runtime/adapters/factory.d.ts +2 -2
- package/dist/runtime/adapters/factory.js +54 -20
- package/dist/runtime/adapters/interfaces/store.d.ts +177 -113
- package/dist/runtime/config/index.d.ts +2 -2
- package/dist/runtime/config/index.js +14 -6
- package/dist/runtime/config/types.d.ts +32 -2
- package/dist/runtime/events/eventBus.d.ts +1 -1
- package/dist/runtime/events/types.d.ts +31 -2
- package/dist/runtime/events/utils/scheduleTrigger.d.ts +8 -0
- package/dist/runtime/events/utils/scheduleTrigger.js +69 -0
- package/dist/runtime/events/utils/stallDetector.d.ts +44 -3
- package/dist/runtime/events/utils/stallDetector.js +288 -89
- package/dist/runtime/events/utils/triggerRuntime.d.ts +58 -0
- package/dist/runtime/events/utils/triggerRuntime.js +212 -0
- package/dist/runtime/events/wiring/flowWiring.d.ts +11 -5
- package/dist/runtime/events/wiring/flowWiring.js +620 -92
- package/dist/runtime/events/wiring/registry.d.ts +2 -2
- package/dist/runtime/events/wiring/registry.js +8 -6
- package/dist/runtime/events/wiring/streamWiring.d.ts +15 -11
- package/dist/runtime/events/wiring/streamWiring.js +88 -11
- package/dist/runtime/events/wiring/triggerWiring.d.ts +21 -0
- package/dist/runtime/events/wiring/triggerWiring.js +412 -0
- package/dist/runtime/{server → nitro}/plugins/00.adapters.js +8 -4
- package/dist/runtime/{server → nitro}/plugins/02.workers.js +21 -3
- package/dist/runtime/nitro/plugins/03.triggers.d.ts +12 -0
- package/dist/runtime/nitro/plugins/03.triggers.js +55 -0
- package/dist/runtime/nitro/routes/webhook.await.d.ts +23 -0
- package/dist/runtime/nitro/routes/webhook.await.js +90 -0
- package/dist/runtime/nitro/routes/webhook.trigger.d.ts +69 -0
- package/dist/runtime/nitro/routes/webhook.trigger.js +64 -0
- package/dist/runtime/{utils → nitro/utils}/adapters.d.ts +6 -6
- package/dist/runtime/nitro/utils/awaitPatterns/event.d.ts +15 -0
- package/dist/runtime/nitro/utils/awaitPatterns/event.js +120 -0
- package/dist/runtime/nitro/utils/awaitPatterns/index.d.ts +28 -0
- package/dist/runtime/nitro/utils/awaitPatterns/index.js +55 -0
- package/dist/runtime/nitro/utils/awaitPatterns/schedule.d.ts +16 -0
- package/dist/runtime/nitro/utils/awaitPatterns/schedule.js +78 -0
- package/dist/runtime/nitro/utils/awaitPatterns/time.d.ts +15 -0
- package/dist/runtime/nitro/utils/awaitPatterns/time.js +67 -0
- package/dist/runtime/nitro/utils/awaitPatterns/webhook.d.ts +15 -0
- package/dist/runtime/nitro/utils/awaitPatterns/webhook.js +120 -0
- package/dist/runtime/{utils → nitro/utils}/defineFunction.d.ts +2 -2
- package/dist/runtime/{utils → nitro/utils}/defineFunction.js +3 -3
- package/dist/runtime/{utils → nitro/utils}/defineFunctionConfig.d.ts +156 -0
- package/dist/runtime/{utils → nitro/utils}/defineFunctionConfig.js +1 -0
- package/dist/runtime/nitro/utils/defineHooks.d.ts +41 -0
- package/dist/runtime/nitro/utils/defineHooks.js +6 -0
- package/dist/runtime/{utils → nitro/utils}/registerAdapter.d.ts +3 -3
- package/dist/runtime/{utils → nitro/utils}/registerAdapter.js +1 -1
- package/dist/runtime/nitro/utils/useAwait.d.ts +71 -0
- package/dist/runtime/nitro/utils/useAwait.js +139 -0
- package/dist/runtime/{utils → nitro/utils}/useEventManager.d.ts +2 -2
- package/dist/runtime/{utils → nitro/utils}/useEventManager.js +1 -1
- package/dist/runtime/nitro/utils/useFlow.d.ts +68 -0
- package/dist/runtime/nitro/utils/useFlow.js +226 -0
- package/dist/runtime/nitro/utils/useHookRegistry.d.ts +34 -0
- package/dist/runtime/nitro/utils/useHookRegistry.js +25 -0
- package/dist/runtime/nitro/utils/useRunContext.d.ts +6 -0
- package/dist/runtime/nitro/utils/useRunContext.js +102 -0
- package/dist/runtime/nitro/utils/useStreamTopics.d.ts +83 -0
- package/dist/runtime/nitro/utils/useStreamTopics.js +94 -0
- package/dist/runtime/nitro/utils/useTrigger.d.ts +150 -0
- package/dist/runtime/nitro/utils/useTrigger.js +320 -0
- package/dist/runtime/scheduler/index.d.ts +33 -0
- package/dist/runtime/scheduler/index.js +38 -0
- package/dist/runtime/scheduler/scheduler.d.ts +113 -0
- package/dist/runtime/scheduler/scheduler.js +623 -0
- package/dist/runtime/scheduler/types.d.ts +116 -0
- package/dist/runtime/scheduler/types.js +0 -0
- package/dist/runtime/worker/node/runner.d.ts +12 -2
- package/dist/runtime/worker/node/runner.js +141 -37
- package/package.json +6 -6
- 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 -55
- 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.get.d.ts +0 -17
- package/dist/runtime/server/api/_flows/[name]/runs.get.js +0 -64
- package/dist/runtime/server/api/_flows/[name]/schedule.post.d.ts +0 -2
- package/dist/runtime/server/api/_flows/[name]/schedule.post.js +0 -66
- package/dist/runtime/server/api/_flows/[name]/schedules/[id].delete.d.ts +0 -2
- package/dist/runtime/server/api/_flows/[name]/schedules/[id].delete.js +0 -47
- package/dist/runtime/server/api/_flows/[name]/schedules.get.d.ts +0 -2
- package/dist/runtime/server/api/_flows/[name]/schedules.get.js +0 -50
- 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 -6
- package/dist/runtime/server/api/_flows/index.get.js +0 -5
- package/dist/runtime/server/api/_flows/ws.d.ts +0 -60
- package/dist/runtime/server/api/_flows/ws.js +0 -209
- 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 -27
- 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/utils/useFlowEngine.d.ts +0 -19
- package/dist/runtime/utils/useFlowEngine.js +0 -108
- package/dist/runtime/utils/useStreamTopics.d.ts +0 -72
- package/dist/runtime/utils/useStreamTopics.js +0 -47
- /package/dist/runtime/{server → nitro}/plugins/00.adapters.d.ts +0 -0
- /package/dist/runtime/{server → nitro}/plugins/01.ws-lifecycle.d.ts +0 -0
- /package/dist/runtime/{server → nitro}/plugins/01.ws-lifecycle.js +0 -0
- /package/dist/runtime/{server → nitro}/plugins/02.workers.d.ts +0 -0
- /package/dist/runtime/{utils → nitro/utils}/adapters.js +0 -0
- /package/dist/runtime/{utils → nitro/utils}/useNventLogger.d.ts +0 -0
- /package/dist/runtime/{utils → nitro/utils}/useNventLogger.js +0 -0
- /package/dist/runtime/{utils → nitro/utils}/wsPeerManager.d.ts +0 -0
- /package/dist/runtime/{utils → nitro/utils}/wsPeerManager.js +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createFlowWiring } from "./flowWiring.js";
|
|
2
2
|
import { createStreamWiring } from "./streamWiring.js";
|
|
3
3
|
import { createStateWiring } from "./stateWiring.js";
|
|
4
|
+
import { createTriggerWiring } from "./triggerWiring.js";
|
|
4
5
|
export function createWiringRegistry(opts) {
|
|
5
6
|
const wirings = [
|
|
6
7
|
// 1. Flow orchestration (persistence, completion tracking, step triggering)
|
|
@@ -10,20 +11,21 @@ export function createWiringRegistry(opts) {
|
|
|
10
11
|
enabled: true
|
|
11
12
|
}),
|
|
12
13
|
// 3. State wiring (automatic state cleanup)
|
|
13
|
-
createStateWiring(opts?.stateWiring)
|
|
14
|
-
//
|
|
14
|
+
createStateWiring(opts?.stateWiring),
|
|
15
|
+
// 4. Trigger wiring (v0.5: trigger.fired, await.registered, await.resolved)
|
|
16
|
+
createTriggerWiring()
|
|
15
17
|
];
|
|
16
18
|
let started = false;
|
|
17
19
|
return {
|
|
18
|
-
start() {
|
|
20
|
+
async start() {
|
|
19
21
|
if (started) return;
|
|
20
22
|
started = true;
|
|
21
|
-
for (const w of wirings) w.start();
|
|
23
|
+
for (const w of wirings) await w.start();
|
|
22
24
|
},
|
|
23
|
-
stop() {
|
|
25
|
+
async stop() {
|
|
24
26
|
for (const w of wirings) {
|
|
25
27
|
try {
|
|
26
|
-
w.stop();
|
|
28
|
+
await w.stop();
|
|
27
29
|
} catch {
|
|
28
30
|
}
|
|
29
31
|
}
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Stream Wiring -
|
|
2
|
+
* Stream Wiring - Bridge event bus to StreamAdapter for real-time UI updates
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* 1. Event Bus - Single source of truth for all events (in-memory)
|
|
6
|
+
* 2. StreamWiring - Bridges persisted events to stream topics (this file)
|
|
7
|
+
* 3. StreamAdapter - Pub/sub for real-time distribution (Redis/Memory)
|
|
8
|
+
* 4. WebSocket handlers - Subscribe to topics and send to clients
|
|
6
9
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* - Publishes to client channel: client:flow:{runId}
|
|
10
|
-
* - UI gets real-time updates
|
|
10
|
+
* Flow:
|
|
11
|
+
* Event Bus → StreamWiring → StreamAdapter → WebSocket → UI
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
* -
|
|
14
|
-
* -
|
|
15
|
-
* -
|
|
13
|
+
* Stream Topics (defined in useStreamTopics):
|
|
14
|
+
* - stream:flow:events:{runId} - Flow events for specific run
|
|
15
|
+
* - stream:flow:stats - Flow statistics updates
|
|
16
|
+
* - stream:trigger:events:{triggerName} - Trigger events
|
|
17
|
+
* - stream:trigger:stats - Trigger statistics updates
|
|
18
|
+
*
|
|
19
|
+
* Only publishes persisted events (with id/ts) to avoid duplicates
|
|
16
20
|
*/
|
|
17
21
|
export interface StreamWiringOptions {
|
|
18
22
|
/**
|
|
@@ -13,14 +13,14 @@ export function createStreamWiring(opts = {}) {
|
|
|
13
13
|
if (!enabled) return;
|
|
14
14
|
const logger = useNventLogger("stream-wiring");
|
|
15
15
|
const stream = useStreamAdapter();
|
|
16
|
-
const {
|
|
16
|
+
const { StreamTopics } = useStreamTopics();
|
|
17
17
|
logger.info("Starting stream wiring for UI clients");
|
|
18
|
-
const
|
|
18
|
+
const handleFlowEvent = async (e) => {
|
|
19
19
|
if (!e.id || !e.ts) return;
|
|
20
20
|
const runId = e.runId;
|
|
21
21
|
if (!runId) return;
|
|
22
22
|
try {
|
|
23
|
-
const topic =
|
|
23
|
+
const topic = StreamTopics.flowEvents(runId);
|
|
24
24
|
await stream.publish(topic, {
|
|
25
25
|
type: "flow.event",
|
|
26
26
|
data: {
|
|
@@ -39,14 +39,46 @@ export function createStreamWiring(opts = {}) {
|
|
|
39
39
|
},
|
|
40
40
|
timestamp: Date.now()
|
|
41
41
|
});
|
|
42
|
-
logger.debug("Published to
|
|
42
|
+
logger.debug("Published flow event to stream", { type: e.type, runId });
|
|
43
43
|
} catch (err) {
|
|
44
|
-
logger.error("Failed to publish to
|
|
44
|
+
logger.error("Failed to publish flow event to stream", {
|
|
45
45
|
error: err?.message
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
|
-
const
|
|
49
|
+
const handleTriggerEvent = async (e) => {
|
|
50
|
+
if (!e.id || !e.ts) return;
|
|
51
|
+
const triggerName = e.triggerName;
|
|
52
|
+
if (!triggerName) return;
|
|
53
|
+
try {
|
|
54
|
+
const topic = StreamTopics.triggerEvents(triggerName);
|
|
55
|
+
await stream.publish(topic, {
|
|
56
|
+
type: "trigger.event",
|
|
57
|
+
data: {
|
|
58
|
+
event: {
|
|
59
|
+
id: e.id,
|
|
60
|
+
ts: e.ts,
|
|
61
|
+
type: e.type,
|
|
62
|
+
triggerName,
|
|
63
|
+
data: e.data
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
timestamp: Date.now()
|
|
67
|
+
});
|
|
68
|
+
logger.debug("Published trigger event to stream", {
|
|
69
|
+
triggerName,
|
|
70
|
+
type: e.type,
|
|
71
|
+
id: e.id
|
|
72
|
+
});
|
|
73
|
+
} catch (err) {
|
|
74
|
+
logger.error("Failed to publish trigger event to stream", {
|
|
75
|
+
triggerName,
|
|
76
|
+
type: e.type,
|
|
77
|
+
error: err?.message
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const flowEventTypes = [
|
|
50
82
|
"flow.start",
|
|
51
83
|
"flow.completed",
|
|
52
84
|
"flow.failed",
|
|
@@ -55,14 +87,59 @@ export function createStreamWiring(opts = {}) {
|
|
|
55
87
|
"step.completed",
|
|
56
88
|
"step.failed",
|
|
57
89
|
"step.retry",
|
|
90
|
+
"await.registered",
|
|
91
|
+
"await.resolved",
|
|
92
|
+
"await.timeout",
|
|
58
93
|
"log",
|
|
59
|
-
"emit"
|
|
60
|
-
"state"
|
|
94
|
+
"emit"
|
|
61
95
|
];
|
|
62
|
-
|
|
63
|
-
|
|
96
|
+
const triggerEventTypes = [
|
|
97
|
+
"trigger.registered",
|
|
98
|
+
"trigger.updated",
|
|
99
|
+
"trigger.deleted",
|
|
100
|
+
"trigger.fired",
|
|
101
|
+
"subscription.added",
|
|
102
|
+
"subscription.removed"
|
|
103
|
+
];
|
|
104
|
+
const handleFlowStatsUpdate = async (e) => {
|
|
105
|
+
try {
|
|
106
|
+
const topic = StreamTopics.flowStats();
|
|
107
|
+
await stream.publish(topic, {
|
|
108
|
+
id: e.flowName,
|
|
109
|
+
metadata: e.metadata
|
|
110
|
+
});
|
|
111
|
+
logger.debug("Published flow stats to stream", { flowName: e.flowName });
|
|
112
|
+
} catch (err) {
|
|
113
|
+
logger.error("Failed to publish flow stats to stream", {
|
|
114
|
+
flowName: e.flowName,
|
|
115
|
+
error: err?.message
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const handleTriggerStatsUpdate = async (e) => {
|
|
120
|
+
try {
|
|
121
|
+
const topic = StreamTopics.triggerStats();
|
|
122
|
+
await stream.publish(topic, {
|
|
123
|
+
id: e.triggerName,
|
|
124
|
+
metadata: e.metadata
|
|
125
|
+
});
|
|
126
|
+
logger.debug("Published trigger stats to stream", { triggerName: e.triggerName });
|
|
127
|
+
} catch (err) {
|
|
128
|
+
logger.error("Failed to publish trigger stats to stream", {
|
|
129
|
+
triggerName: e.triggerName,
|
|
130
|
+
error: err?.message
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
for (const type of flowEventTypes) {
|
|
135
|
+
unsubs.push(bus.onType(type, handleFlowEvent));
|
|
136
|
+
}
|
|
137
|
+
for (const type of triggerEventTypes) {
|
|
138
|
+
unsubs.push(bus.onType(type, handleTriggerEvent));
|
|
64
139
|
}
|
|
65
|
-
|
|
140
|
+
unsubs.push(bus.onType("flow.stats.updated", handleFlowStatsUpdate));
|
|
141
|
+
unsubs.push(bus.onType("trigger.stats.updated", handleTriggerStatsUpdate));
|
|
142
|
+
logger.info("Stream wiring started - listening for persisted flow and trigger events");
|
|
66
143
|
}
|
|
67
144
|
function stop() {
|
|
68
145
|
const logger = useNventLogger("stream-wiring");
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { TriggerFiredEvent } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Create trigger event wiring
|
|
4
|
+
* Listens to trigger.fired events and starts subscribed flows
|
|
5
|
+
* Handles await.registered and await.resolved events
|
|
6
|
+
*/
|
|
7
|
+
export declare function createTriggerWiring(): {
|
|
8
|
+
start: () => Promise<void>;
|
|
9
|
+
stop: () => void;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Handle trigger.fired event
|
|
13
|
+
* Starts all subscribed flows (auto mode) or queues them (manual mode)
|
|
14
|
+
* Returns list of flows that were started for stream metadata
|
|
15
|
+
*/
|
|
16
|
+
export declare function handleTriggerFired(event: TriggerFiredEvent): Promise<string[]>;
|
|
17
|
+
/**
|
|
18
|
+
* Start a flow from a trigger event
|
|
19
|
+
* Enqueues the entry step and publishes flow.start event
|
|
20
|
+
*/
|
|
21
|
+
export declare function startFlowFromTrigger(flowName: string, triggerName: string, triggerData: any): Promise<void>;
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import { getEventBus } from "../eventBus.js";
|
|
2
|
+
import { useTrigger, useNventLogger, useStoreAdapter, useQueueAdapter, $useAnalyzedFlows, $useFunctionRegistry, useStreamTopics } from "#imports";
|
|
3
|
+
import { getTriggerRuntime } from "../utils/triggerRuntime.js";
|
|
4
|
+
import { scheduleTrigger, unscheduleTrigger } from "../utils/scheduleTrigger.js";
|
|
5
|
+
export function createTriggerWiring() {
|
|
6
|
+
const unsubs = [];
|
|
7
|
+
let wired = false;
|
|
8
|
+
async function start() {
|
|
9
|
+
if (wired) return;
|
|
10
|
+
wired = true;
|
|
11
|
+
const logger = useNventLogger("trigger-wiring");
|
|
12
|
+
const eventBus = getEventBus();
|
|
13
|
+
const trigger = useTrigger();
|
|
14
|
+
const store = useStoreAdapter();
|
|
15
|
+
const { StoreSubjects } = useStreamTopics();
|
|
16
|
+
const runtime = getTriggerRuntime(store, logger);
|
|
17
|
+
await trigger.initialize();
|
|
18
|
+
logger.info("Setting up trigger event wiring");
|
|
19
|
+
const handlePersistence = async (e) => {
|
|
20
|
+
try {
|
|
21
|
+
if (e.id && e.ts) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const triggerName = e.triggerName || e.data?.triggerName;
|
|
25
|
+
if (!triggerName) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const streamName = StoreSubjects.triggerStream(triggerName);
|
|
29
|
+
if (!e.type) {
|
|
30
|
+
logger.error("Event missing type field", { event: e });
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const eventData = {
|
|
34
|
+
type: e.type,
|
|
35
|
+
triggerName,
|
|
36
|
+
data: e.data
|
|
37
|
+
};
|
|
38
|
+
const persistedEvent = await store.stream.append(streamName, eventData);
|
|
39
|
+
await eventBus.publish(persistedEvent);
|
|
40
|
+
logger.debug("Stored trigger event", {
|
|
41
|
+
type: e.type,
|
|
42
|
+
triggerName,
|
|
43
|
+
id: persistedEvent.id
|
|
44
|
+
});
|
|
45
|
+
} catch (err) {
|
|
46
|
+
logger.error("ERROR persisting trigger event", {
|
|
47
|
+
type: e.type,
|
|
48
|
+
triggerName: e.triggerName,
|
|
49
|
+
error: err?.message
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const handleOrchestration = async (e) => {
|
|
54
|
+
try {
|
|
55
|
+
if (e.id && e.ts) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const triggerName = e.triggerName || e.data?.triggerName;
|
|
59
|
+
if (!triggerName) {
|
|
60
|
+
logger.debug("Orchestration skipped - no triggerName", { type: e.type });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
logger.debug("Processing trigger orchestration", { type: e.type, triggerName });
|
|
64
|
+
const indexKey = StoreSubjects.triggerIndex();
|
|
65
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
66
|
+
const nowTimestamp = Date.now();
|
|
67
|
+
if (e.type === "trigger.registered") {
|
|
68
|
+
const data = e.data;
|
|
69
|
+
if (store.index.add) {
|
|
70
|
+
await store.index.add(indexKey, triggerName, nowTimestamp, {
|
|
71
|
+
"name": data.name,
|
|
72
|
+
"type": data.type,
|
|
73
|
+
"scope": data.scope,
|
|
74
|
+
"status": "active",
|
|
75
|
+
"displayName": data.displayName,
|
|
76
|
+
"description": data.description,
|
|
77
|
+
"source": data.source || "programmatic",
|
|
78
|
+
"registeredAt": now,
|
|
79
|
+
"registeredBy": "runtime",
|
|
80
|
+
"lastActivityAt": now,
|
|
81
|
+
"stats.totalFires": 0,
|
|
82
|
+
"stats.totalFlowsStarted": 0,
|
|
83
|
+
"stats.activeSubscribers": 0,
|
|
84
|
+
"webhook": data.webhook,
|
|
85
|
+
"schedule": data.schedule,
|
|
86
|
+
"config": data.config,
|
|
87
|
+
"version": 1
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
const entry = {
|
|
91
|
+
name: data.name,
|
|
92
|
+
type: data.type,
|
|
93
|
+
scope: data.scope,
|
|
94
|
+
status: "active",
|
|
95
|
+
displayName: data.displayName,
|
|
96
|
+
description: data.description,
|
|
97
|
+
source: data.source || "programmatic",
|
|
98
|
+
registeredAt: now,
|
|
99
|
+
registeredBy: "runtime",
|
|
100
|
+
lastActivityAt: now,
|
|
101
|
+
subscriptions: {},
|
|
102
|
+
stats: { totalFires: 0, totalFlowsStarted: 0, activeSubscribers: 0 },
|
|
103
|
+
webhook: data.webhook,
|
|
104
|
+
schedule: data.schedule,
|
|
105
|
+
config: data.config,
|
|
106
|
+
version: 1
|
|
107
|
+
};
|
|
108
|
+
runtime.addTrigger(triggerName, entry);
|
|
109
|
+
logger.info("Registered trigger in index", { triggerName });
|
|
110
|
+
if (data.type === "schedule" && data.schedule) {
|
|
111
|
+
await scheduleTrigger(triggerName, data.schedule, data.status || "active");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (e.type === "trigger.updated") {
|
|
115
|
+
const data = e.data;
|
|
116
|
+
if (store.index.updateWithRetry) {
|
|
117
|
+
await store.index.updateWithRetry(indexKey, triggerName, {
|
|
118
|
+
type: data.type,
|
|
119
|
+
scope: data.scope,
|
|
120
|
+
status: data.status,
|
|
121
|
+
displayName: data.displayName,
|
|
122
|
+
description: data.description,
|
|
123
|
+
webhook: data.webhook,
|
|
124
|
+
schedule: data.schedule,
|
|
125
|
+
config: data.config,
|
|
126
|
+
lastActivityAt: now
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
const existing = runtime.getTrigger(triggerName);
|
|
130
|
+
if (existing) {
|
|
131
|
+
const updated = {
|
|
132
|
+
...existing,
|
|
133
|
+
status: data.status !== void 0 ? data.status : existing.status,
|
|
134
|
+
displayName: data.displayName !== void 0 ? data.displayName : existing.displayName,
|
|
135
|
+
description: data.description !== void 0 ? data.description : existing.description,
|
|
136
|
+
webhook: data.webhook !== void 0 ? data.webhook : existing.webhook,
|
|
137
|
+
schedule: data.schedule !== void 0 ? data.schedule : existing.schedule,
|
|
138
|
+
config: data.config !== void 0 ? data.config : existing.config,
|
|
139
|
+
lastActivityAt: now
|
|
140
|
+
};
|
|
141
|
+
runtime.addTrigger(triggerName, updated);
|
|
142
|
+
if (updated.type === "schedule" && updated.schedule) {
|
|
143
|
+
await scheduleTrigger(triggerName, updated.schedule, updated.status);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
logger.info("Updated trigger in index and runtime", { triggerName, status: data.status });
|
|
147
|
+
}
|
|
148
|
+
if (e.type === "subscription.added") {
|
|
149
|
+
const data = e.data;
|
|
150
|
+
const { flow, mode } = data;
|
|
151
|
+
const existingSub = runtime.getSubscription(triggerName, flow);
|
|
152
|
+
if (store.index.updateWithRetry) {
|
|
153
|
+
await store.index.updateWithRetry(indexKey, triggerName, {
|
|
154
|
+
subscriptions: {
|
|
155
|
+
[flow]: {
|
|
156
|
+
mode,
|
|
157
|
+
subscribedAt: existingSub ? existingSub.registeredAt || now : now
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
lastActivityAt: now
|
|
161
|
+
});
|
|
162
|
+
if (!existingSub && store.index.increment) {
|
|
163
|
+
await store.index.increment(indexKey, triggerName, "stats.activeSubscribers", 1);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const subscription = {
|
|
167
|
+
triggerName,
|
|
168
|
+
flowName: flow,
|
|
169
|
+
mode,
|
|
170
|
+
source: "programmatic",
|
|
171
|
+
registeredAt: existingSub?.registeredAt || now
|
|
172
|
+
};
|
|
173
|
+
runtime.addSubscription(triggerName, flow, subscription);
|
|
174
|
+
logger.info(`Subscription ${existingSub ? "updated" : "added"}`, { triggerName, flow, mode });
|
|
175
|
+
}
|
|
176
|
+
if (e.type === "subscription.removed") {
|
|
177
|
+
const data = e.data;
|
|
178
|
+
const { flow } = data;
|
|
179
|
+
if (store.index.updateWithRetry) {
|
|
180
|
+
await store.index.updateWithRetry(indexKey, triggerName, {
|
|
181
|
+
subscriptions: {
|
|
182
|
+
[flow]: null
|
|
183
|
+
// null removes the field
|
|
184
|
+
},
|
|
185
|
+
lastActivityAt: now
|
|
186
|
+
});
|
|
187
|
+
if (store.index.increment) {
|
|
188
|
+
await store.index.increment(indexKey, triggerName, "stats.activeSubscribers", -1);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
runtime.removeSubscription(triggerName, flow);
|
|
192
|
+
logger.info("Subscription removed", { triggerName, flow });
|
|
193
|
+
}
|
|
194
|
+
if (e.type === "trigger.fired") {
|
|
195
|
+
const flowsStarted = await handleTriggerFired(e);
|
|
196
|
+
if (flowsStarted.length > 0 && store.index.increment) {
|
|
197
|
+
await store.index.increment(indexKey, triggerName, "stats.totalFlowsStarted", flowsStarted.length);
|
|
198
|
+
}
|
|
199
|
+
logger.debug("Trigger fired and processed", { triggerName, flowsStarted: flowsStarted.length });
|
|
200
|
+
}
|
|
201
|
+
if (e.type === "trigger.deleted") {
|
|
202
|
+
const triggerEntry = runtime.getTrigger(triggerName);
|
|
203
|
+
const wasScheduleTrigger = triggerEntry?.type === "schedule";
|
|
204
|
+
if (store.index.delete) {
|
|
205
|
+
await store.index.delete(indexKey, triggerName);
|
|
206
|
+
}
|
|
207
|
+
const triggerStreamKey = StoreSubjects.triggerStream(triggerName);
|
|
208
|
+
if (store.stream.delete) {
|
|
209
|
+
await store.stream.delete(triggerStreamKey);
|
|
210
|
+
}
|
|
211
|
+
runtime.removeTrigger(triggerName);
|
|
212
|
+
if (wasScheduleTrigger) {
|
|
213
|
+
await unscheduleTrigger(triggerName);
|
|
214
|
+
}
|
|
215
|
+
logger.info("Trigger deleted completely", { triggerName });
|
|
216
|
+
}
|
|
217
|
+
} catch (err) {
|
|
218
|
+
logger.error("ERROR in trigger orchestration", {
|
|
219
|
+
type: e.type,
|
|
220
|
+
triggerName: e.triggerName,
|
|
221
|
+
error: err?.message,
|
|
222
|
+
stack: err?.stack
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
const handleTriggerStats = async (e) => {
|
|
227
|
+
try {
|
|
228
|
+
if (!e.id || !e.ts) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const triggerName = e.triggerName || e.data?.triggerName;
|
|
232
|
+
if (!triggerName) return;
|
|
233
|
+
const indexKey = StoreSubjects.triggerIndex();
|
|
234
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
235
|
+
if (e.type === "trigger.fired") {
|
|
236
|
+
if (store.index.updateWithRetry) {
|
|
237
|
+
await store.index.updateWithRetry(indexKey, triggerName, {
|
|
238
|
+
stats: {
|
|
239
|
+
lastFiredAt: now
|
|
240
|
+
},
|
|
241
|
+
lastActivityAt: now
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
if (store.index.increment) {
|
|
245
|
+
await store.index.increment(indexKey, triggerName, "stats.totalFires", 1);
|
|
246
|
+
}
|
|
247
|
+
logger.debug("Updated trigger stats for fire", { triggerName });
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
if (store.index.get) {
|
|
251
|
+
const indexEntry = await store.index.get(indexKey, triggerName);
|
|
252
|
+
if (indexEntry) {
|
|
253
|
+
await eventBus.publish({
|
|
254
|
+
type: "trigger.stats.updated",
|
|
255
|
+
triggerName,
|
|
256
|
+
id: indexEntry.id,
|
|
257
|
+
metadata: indexEntry.metadata,
|
|
258
|
+
ts: Date.now()
|
|
259
|
+
});
|
|
260
|
+
logger.debug("Published trigger stats update event to bus", { triggerName });
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
} catch (err) {
|
|
264
|
+
logger.warn("Failed to publish trigger stats update event", {
|
|
265
|
+
triggerName,
|
|
266
|
+
error: err?.message
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
} catch (err) {
|
|
270
|
+
logger.warn("Failed to update trigger stats", {
|
|
271
|
+
type: e.type,
|
|
272
|
+
triggerName: e.triggerName,
|
|
273
|
+
error: err?.message
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
const eventTypes = [
|
|
278
|
+
"trigger.registered",
|
|
279
|
+
"trigger.updated",
|
|
280
|
+
"trigger.deleted",
|
|
281
|
+
"trigger.fired",
|
|
282
|
+
"subscription.added",
|
|
283
|
+
"subscription.removed"
|
|
284
|
+
];
|
|
285
|
+
const triggerStatsEventTypes = ["trigger.fired"];
|
|
286
|
+
for (const type of eventTypes) {
|
|
287
|
+
unsubs.push(eventBus.onType(type, handlePersistence));
|
|
288
|
+
}
|
|
289
|
+
for (const type of eventTypes) {
|
|
290
|
+
unsubs.push(eventBus.onType(type, handleOrchestration));
|
|
291
|
+
}
|
|
292
|
+
for (const type of triggerStatsEventTypes) {
|
|
293
|
+
unsubs.push(eventBus.onType(type, handleTriggerStats));
|
|
294
|
+
}
|
|
295
|
+
logger.info("Trigger event wiring setup complete (persistence + orchestration + stats)");
|
|
296
|
+
}
|
|
297
|
+
function stop() {
|
|
298
|
+
const logger = useNventLogger("trigger-wiring");
|
|
299
|
+
for (const u of unsubs.splice(0)) {
|
|
300
|
+
try {
|
|
301
|
+
u();
|
|
302
|
+
} catch {
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
wired = false;
|
|
306
|
+
logger.debug("Trigger wiring stopped");
|
|
307
|
+
}
|
|
308
|
+
return { start, stop };
|
|
309
|
+
}
|
|
310
|
+
export async function handleTriggerFired(event) {
|
|
311
|
+
const logger = useNventLogger("trigger-wiring");
|
|
312
|
+
const trigger = useTrigger();
|
|
313
|
+
const { triggerName, data } = event;
|
|
314
|
+
logger.debug("Trigger fired", { trigger: triggerName });
|
|
315
|
+
const subscriptions = trigger.getAllSubscriptions().filter((sub) => sub.triggerName === triggerName);
|
|
316
|
+
if (subscriptions.length === 0) {
|
|
317
|
+
logger.warn(`No flows subscribed to trigger: ${triggerName}`);
|
|
318
|
+
return [];
|
|
319
|
+
}
|
|
320
|
+
const flowsStarted = [];
|
|
321
|
+
const store = useStoreAdapter();
|
|
322
|
+
const loggerForRuntime = useNventLogger("trigger-runtime");
|
|
323
|
+
const runtime = getTriggerRuntime(store, loggerForRuntime);
|
|
324
|
+
const resolvedData = await runtime.resolvePayload(data);
|
|
325
|
+
for (const subscription of subscriptions) {
|
|
326
|
+
try {
|
|
327
|
+
if (subscription.mode === "manual") {
|
|
328
|
+
logger.info(
|
|
329
|
+
`Trigger '${triggerName}' fired for flow '${subscription.flowName}' (manual mode - awaiting manual start)`
|
|
330
|
+
);
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
await startFlowFromTrigger(subscription.flowName, triggerName, resolvedData);
|
|
334
|
+
flowsStarted.push(subscription.flowName);
|
|
335
|
+
} catch (error) {
|
|
336
|
+
logger.error("Error starting flow from trigger", {
|
|
337
|
+
flow: subscription.flowName,
|
|
338
|
+
trigger: triggerName,
|
|
339
|
+
error: error instanceof Error ? error.message : String(error)
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return flowsStarted;
|
|
344
|
+
}
|
|
345
|
+
export async function startFlowFromTrigger(flowName, triggerName, triggerData) {
|
|
346
|
+
const logger = useNventLogger("trigger-wiring");
|
|
347
|
+
const eventBus = getEventBus();
|
|
348
|
+
const queue = useQueueAdapter();
|
|
349
|
+
const registry = $useFunctionRegistry();
|
|
350
|
+
const analyzedFlows = $useAnalyzedFlows();
|
|
351
|
+
const store = useStoreAdapter();
|
|
352
|
+
const triggerRuntime = getTriggerRuntime(store, logger);
|
|
353
|
+
const flowDef = analyzedFlows.find((f) => f.id === flowName);
|
|
354
|
+
if (!flowDef || !flowDef.entry) {
|
|
355
|
+
logger.error(`Flow '${flowName}' not found or has no entry point`);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const flowRegistry = (registry?.flows || {})[flowName];
|
|
359
|
+
if (!flowRegistry?.entry) {
|
|
360
|
+
logger.error(`Flow '${flowName}' has no entry in registry`);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
const triggerDef = triggerRuntime.getTrigger(triggerName);
|
|
364
|
+
const triggerType = triggerDef?.type || "manual";
|
|
365
|
+
const runId = `${flowName}-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
366
|
+
logger.info(`Starting flow '${flowName}' from trigger '${triggerName}'`, { runId });
|
|
367
|
+
const queueName = flowRegistry.entry.queue;
|
|
368
|
+
const stepName = flowRegistry.entry.step;
|
|
369
|
+
const payload = {
|
|
370
|
+
flowId: runId,
|
|
371
|
+
flowName,
|
|
372
|
+
trigger: {
|
|
373
|
+
name: triggerName,
|
|
374
|
+
type: triggerType,
|
|
375
|
+
data: triggerData
|
|
376
|
+
},
|
|
377
|
+
...triggerData
|
|
378
|
+
};
|
|
379
|
+
const entryWorker = registry?.workers?.find(
|
|
380
|
+
(w) => w?.flow?.step === stepName && w?.queue?.name === queueName
|
|
381
|
+
);
|
|
382
|
+
const defaultOpts = entryWorker?.queue?.defaultJobOptions || {};
|
|
383
|
+
const jobId = `${runId}__${stepName}`;
|
|
384
|
+
const opts = { ...defaultOpts, jobId };
|
|
385
|
+
try {
|
|
386
|
+
await queue.enqueue(queueName, {
|
|
387
|
+
name: stepName,
|
|
388
|
+
data: payload,
|
|
389
|
+
opts
|
|
390
|
+
});
|
|
391
|
+
logger.info(`Enqueued entry step '${stepName}' to queue '${queueName}'`, { runId });
|
|
392
|
+
await eventBus.publish({
|
|
393
|
+
type: "flow.start",
|
|
394
|
+
flowName,
|
|
395
|
+
runId,
|
|
396
|
+
data: {
|
|
397
|
+
input: triggerData,
|
|
398
|
+
trigger: {
|
|
399
|
+
name: triggerName,
|
|
400
|
+
type: triggerType,
|
|
401
|
+
data: triggerData
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
} catch (error) {
|
|
406
|
+
logger.error("Failed to start flow from trigger", {
|
|
407
|
+
flowName,
|
|
408
|
+
trigger: triggerName,
|
|
409
|
+
error: error instanceof Error ? error.message : String(error)
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defineNitroPlugin, useRuntimeConfig, useNventLogger, setAdapters } from "#imports";
|
|
1
|
+
import { defineNitroPlugin, useRuntimeConfig, useNventLogger, setAdapters, initializeScheduler, shutdownScheduler } from "#imports";
|
|
2
2
|
import { createAdapters, shutdownAdapters } from "../../adapters/factory.js";
|
|
3
3
|
import { useAdapterRegistry } from "../../adapters/registry.js";
|
|
4
4
|
import { createWiringRegistry } from "../../events/wiring/registry.js";
|
|
@@ -34,7 +34,8 @@ export default defineNitroPlugin(async (nitroApp) => {
|
|
|
34
34
|
streamAdapter: config.stream.adapter,
|
|
35
35
|
storeAdapter: config.store.adapter
|
|
36
36
|
});
|
|
37
|
-
await
|
|
37
|
+
await initializeScheduler(adapters.store);
|
|
38
|
+
logger.info("Scheduler initialized");
|
|
38
39
|
const wiring = createWiringRegistry({
|
|
39
40
|
streamWiring: {
|
|
40
41
|
enabled: true
|
|
@@ -45,15 +46,18 @@ export default defineNitroPlugin(async (nitroApp) => {
|
|
|
45
46
|
// Can be overridden here if needed
|
|
46
47
|
}
|
|
47
48
|
});
|
|
48
|
-
wiring.start();
|
|
49
|
+
await wiring.start();
|
|
49
50
|
logger.info("Flow wiring started");
|
|
51
|
+
await nitroApp.hooks.callHook("nvent:adapters:ready");
|
|
50
52
|
return {
|
|
51
53
|
hooks: {
|
|
52
54
|
close: async () => {
|
|
53
55
|
logger.info("Shutting down");
|
|
54
56
|
try {
|
|
55
|
-
wiring.stop();
|
|
57
|
+
await wiring.stop();
|
|
56
58
|
logger.info("Flow wiring stopped");
|
|
59
|
+
await shutdownScheduler();
|
|
60
|
+
logger.info("Scheduler shut down");
|
|
57
61
|
await shutdownAdapters(adapters);
|
|
58
62
|
logger.info("Adapters shut down successfully");
|
|
59
63
|
} catch (error) {
|