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,19 @@
|
|
|
1
|
+
import { getStreamNames } from './streamNames.js';
|
|
2
|
+
import type { EventStoreAdapter } from './types.js';
|
|
3
|
+
export interface EventStoreInstance {
|
|
4
|
+
name: string;
|
|
5
|
+
append: EventStoreAdapter['append'];
|
|
6
|
+
read: EventStoreAdapter['read'];
|
|
7
|
+
subscribe: EventStoreAdapter['subscribe'];
|
|
8
|
+
}
|
|
9
|
+
export interface EventStoreFactory {
|
|
10
|
+
adapter: EventStoreAdapter;
|
|
11
|
+
names: ReturnType<typeof getStreamNames>;
|
|
12
|
+
stream(name: string): EventStoreInstance;
|
|
13
|
+
/** Idempotently start stream store wiring that persists ingress events and projections */
|
|
14
|
+
start(): void;
|
|
15
|
+
/** Stop wiring and release listeners */
|
|
16
|
+
stop(): void;
|
|
17
|
+
}
|
|
18
|
+
export declare function getEventStoreFactory(): EventStoreFactory;
|
|
19
|
+
export declare function setEventStoreFactory(f: EventStoreFactory): void;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useRuntimeConfig, useServerLogger } from "#imports";
|
|
2
|
+
import { getStreamNames } from "./streamNames.js";
|
|
3
|
+
import { createRedisAdapter } from "./adapters/redis/redisAdapter.js";
|
|
4
|
+
import { createMemoryAdapter } from "./adapters/memoryAdapter.js";
|
|
5
|
+
import { createFileAdapter } from "./adapters/fileAdapter.js";
|
|
6
|
+
import { createWiringRegistry } from "./wiring/registry.js";
|
|
7
|
+
const logger = useServerLogger("event-store-factory");
|
|
8
|
+
let cachedFactory = null;
|
|
9
|
+
export function getEventStoreFactory() {
|
|
10
|
+
if (cachedFactory) return cachedFactory;
|
|
11
|
+
const rc = useRuntimeConfig();
|
|
12
|
+
const adapter = rc?.queue?.eventStore?.adapter || "memory";
|
|
13
|
+
let adapterInstance;
|
|
14
|
+
if (adapter === "memory") adapterInstance = createMemoryAdapter();
|
|
15
|
+
else if (adapter === "file") adapterInstance = createFileAdapter();
|
|
16
|
+
else if (adapter === "redis") adapterInstance = createRedisAdapter();
|
|
17
|
+
else adapterInstance = createMemoryAdapter();
|
|
18
|
+
logger.debug("Event store initialized", { adapter, adapterType: adapter });
|
|
19
|
+
const names = getStreamNames();
|
|
20
|
+
const wiring = createWiringRegistry({ adapter: adapterInstance, names });
|
|
21
|
+
const factory = {
|
|
22
|
+
adapter: adapterInstance,
|
|
23
|
+
names,
|
|
24
|
+
stream(name) {
|
|
25
|
+
return {
|
|
26
|
+
name,
|
|
27
|
+
append: (s, e) => adapterInstance.append(s, e),
|
|
28
|
+
read: (s, o) => adapterInstance.read(s, o),
|
|
29
|
+
subscribe: (s, cb) => adapterInstance.subscribe(s, cb)
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
start() {
|
|
33
|
+
wiring.start();
|
|
34
|
+
},
|
|
35
|
+
stop() {
|
|
36
|
+
wiring.stop();
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
cachedFactory = factory;
|
|
40
|
+
return factory;
|
|
41
|
+
}
|
|
42
|
+
export function setEventStoreFactory(f) {
|
|
43
|
+
cachedFactory = f;
|
|
44
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream naming utilities
|
|
3
|
+
*
|
|
4
|
+
* Core streams:
|
|
5
|
+
* - nq:flow:{runId} - Flow run event stream
|
|
6
|
+
* - nq:flows:{flowName} - Sorted set index of flow runs by flow name
|
|
7
|
+
*/
|
|
8
|
+
export interface StreamNamesConfig {
|
|
9
|
+
flow?: string | ((runId: string) => string);
|
|
10
|
+
flowIndex?: string | ((flowName: string) => string);
|
|
11
|
+
}
|
|
12
|
+
export interface StreamNames {
|
|
13
|
+
flow: (runId: string) => string;
|
|
14
|
+
flowIndex: (flowName: string) => string;
|
|
15
|
+
}
|
|
16
|
+
export declare function getStreamNames(): StreamNames;
|
|
17
|
+
export default getStreamNames;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useRuntimeConfig } from "#imports";
|
|
2
|
+
function defaults() {
|
|
3
|
+
return {
|
|
4
|
+
flow: (runId) => `nq:flow:${runId}`,
|
|
5
|
+
flowIndex: (flowName) => `nq:flows:${flowName}`
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export function getStreamNames() {
|
|
9
|
+
const rc = useRuntimeConfig();
|
|
10
|
+
const cfg = rc?.queue?.eventStore?.streams || {};
|
|
11
|
+
const d = defaults();
|
|
12
|
+
return {
|
|
13
|
+
flow: typeof cfg.flow === "string" ? (runId) => `${cfg.flow}${runId}` : cfg.flow || d.flow,
|
|
14
|
+
flowIndex: typeof cfg.flowIndex === "string" ? (flowName) => `${cfg.flowIndex}${flowName}` : cfg.flowIndex || d.flowIndex
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export default getStreamNames;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { EventRecord } from '../../types.js';
|
|
2
|
+
export interface PublishContext {
|
|
3
|
+
queue?: string;
|
|
4
|
+
jobId?: string;
|
|
5
|
+
/** Flow run ID for flow events */
|
|
6
|
+
flowId?: string;
|
|
7
|
+
/** Trigger ID for trigger events */
|
|
8
|
+
triggerId?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface PublishPayload<T = any> {
|
|
11
|
+
type: string;
|
|
12
|
+
runId: string;
|
|
13
|
+
flowName: string;
|
|
14
|
+
stepName?: string;
|
|
15
|
+
stepId?: string;
|
|
16
|
+
attempt?: number;
|
|
17
|
+
data?: T;
|
|
18
|
+
}
|
|
19
|
+
export interface EventReadOptions {
|
|
20
|
+
fromId?: string;
|
|
21
|
+
limit?: number;
|
|
22
|
+
direction?: 'forward' | 'backward';
|
|
23
|
+
}
|
|
24
|
+
export interface EventSubscription {
|
|
25
|
+
unsubscribe(): void;
|
|
26
|
+
}
|
|
27
|
+
export interface IndexEntry {
|
|
28
|
+
id: string;
|
|
29
|
+
score: number;
|
|
30
|
+
metadata?: {
|
|
31
|
+
status?: 'running' | 'completed' | 'failed';
|
|
32
|
+
startedAt?: number;
|
|
33
|
+
completedAt?: number;
|
|
34
|
+
stepCount?: number;
|
|
35
|
+
completedSteps?: number;
|
|
36
|
+
emittedEvents?: string[];
|
|
37
|
+
version?: number;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export interface IndexReadOptions {
|
|
41
|
+
offset?: number;
|
|
42
|
+
limit?: number;
|
|
43
|
+
}
|
|
44
|
+
export interface EventStoreAdapter {
|
|
45
|
+
append(subject: string, e: Omit<EventRecord, 'id' | 'ts'>): Promise<EventRecord>;
|
|
46
|
+
read(subject: string, opts?: EventReadOptions): Promise<EventRecord[]>;
|
|
47
|
+
subscribe(subject: string, onEvent: (e: EventRecord) => void): Promise<EventSubscription>;
|
|
48
|
+
indexAdd?(key: string, id: string, score: number, metadata?: Record<string, any>): Promise<void>;
|
|
49
|
+
indexGet?(key: string, id: string): Promise<IndexEntry | null>;
|
|
50
|
+
indexUpdate?(key: string, id: string, metadata: Record<string, any>): Promise<boolean>;
|
|
51
|
+
indexUpdateWithRetry?(key: string, id: string, metadata: Record<string, any>, maxRetries?: number): Promise<void>;
|
|
52
|
+
indexIncrement?(key: string, id: string, field: string, increment?: number): Promise<number>;
|
|
53
|
+
indexRead?(key: string, opts?: IndexReadOptions): Promise<IndexEntry[]>;
|
|
54
|
+
setMetadataTTL?(flowName: string, runId: string, ttlSeconds: number): Promise<void>;
|
|
55
|
+
cleanupCompletedFlows?(key: string, retentionSeconds: number): Promise<number>;
|
|
56
|
+
/** Delete a specific stream/subject */
|
|
57
|
+
deleteStream?(subject: string): Promise<void>;
|
|
58
|
+
/** Delete all streams matching a pattern (e.g., 'flow:*' or 'trigger:webhook-*') */
|
|
59
|
+
deleteByPattern?(pattern: string): Promise<number>;
|
|
60
|
+
/** Delete an index key */
|
|
61
|
+
deleteIndex?(key: string): Promise<void>;
|
|
62
|
+
close(): Promise<void>;
|
|
63
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { EventStoreAdapter } from '../types.js';
|
|
2
|
+
import type { EventRecord } from '../../../types.js';
|
|
3
|
+
export interface FlowWiringDeps {
|
|
4
|
+
adapter: EventStoreAdapter;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Check if all dependencies for a step are met
|
|
8
|
+
* Returns true if all subscriptions have been emitted or completed
|
|
9
|
+
*/
|
|
10
|
+
export declare function checkPendingStepTriggers(step: any, emittedEvents: Set<string>, completedSteps: Set<string>): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Analyze flow completion status from events
|
|
13
|
+
* Returns status, step counts, and timestamps
|
|
14
|
+
*/
|
|
15
|
+
export declare function analyzeFlowCompletion(flowSteps: Record<string, any>, entryStep: string | undefined, events: EventRecord[]): {
|
|
16
|
+
status: 'running' | 'completed' | 'failed';
|
|
17
|
+
totalSteps: number;
|
|
18
|
+
completedSteps: number;
|
|
19
|
+
startedAt: number;
|
|
20
|
+
completedAt: number;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* v0.4 Lean Flow Wiring
|
|
24
|
+
*
|
|
25
|
+
* 1. Persists flow events to streams using runId
|
|
26
|
+
* 2. Maintains a sorted set index using projection names for listing runs
|
|
27
|
+
*
|
|
28
|
+
* Events arrive as "ingress" (no id/ts) and are persisted to `nq:flow:{runId}` streams.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createFlowWiring(deps: FlowWiringDeps): {
|
|
31
|
+
start: () => void;
|
|
32
|
+
stop: () => void;
|
|
33
|
+
};
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import { getEventBus } from "../eventBus.js";
|
|
2
|
+
import { useServerLogger, useEventStore, $useAnalyzedFlows, $useQueueRegistry, useQueue } from "#imports";
|
|
3
|
+
const logger = useServerLogger("flow-wiring");
|
|
4
|
+
export function checkPendingStepTriggers(step, emittedEvents, completedSteps) {
|
|
5
|
+
if (!step.subscribes || step.subscribes.length === 0) {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
return step.subscribes.every((sub) => {
|
|
9
|
+
if (emittedEvents.has(sub)) return true;
|
|
10
|
+
const [prefix, value] = sub.split(":");
|
|
11
|
+
if (prefix === "step" && value) {
|
|
12
|
+
return completedSteps.has(value);
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
async function checkAndTriggerPendingSteps(flowName, runId, store) {
|
|
18
|
+
try {
|
|
19
|
+
const analyzedFlows = $useAnalyzedFlows();
|
|
20
|
+
const registry = $useQueueRegistry();
|
|
21
|
+
const { enqueue } = useQueue();
|
|
22
|
+
const flowDef = analyzedFlows.find((f) => f.id === flowName);
|
|
23
|
+
if (!flowDef?.steps) return;
|
|
24
|
+
const indexKey = store.names().flowIndex(flowName);
|
|
25
|
+
const flowEntry = await store.indexGet(indexKey, runId);
|
|
26
|
+
if (!flowEntry?.metadata) return;
|
|
27
|
+
const emittedEvents = new Set(flowEntry.metadata.emittedEvents || []);
|
|
28
|
+
const streamName = store.names().flow(runId);
|
|
29
|
+
const allEvents = await store.read(streamName);
|
|
30
|
+
const completedSteps = /* @__PURE__ */ new Set();
|
|
31
|
+
for (const event of allEvents) {
|
|
32
|
+
if (event.type === "step.completed" && "stepName" in event) {
|
|
33
|
+
completedSteps.add(event.stepName);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
for (const [stepName, stepDef] of Object.entries(flowDef.steps)) {
|
|
37
|
+
const step = stepDef;
|
|
38
|
+
if (!step.subscribes || completedSteps.has(stepName)) continue;
|
|
39
|
+
const canTrigger = checkPendingStepTriggers(step, emittedEvents, completedSteps);
|
|
40
|
+
if (canTrigger) {
|
|
41
|
+
const flowRegistry = (registry?.flows || {})[flowName];
|
|
42
|
+
const stepMeta = flowRegistry?.steps?.[stepName];
|
|
43
|
+
if (stepMeta?.queue) {
|
|
44
|
+
const emitData = {};
|
|
45
|
+
const subscribes = step.subscribes || [];
|
|
46
|
+
for (const sub of subscribes) {
|
|
47
|
+
const emitEvent = allEvents.find(
|
|
48
|
+
(evt) => evt.type === "emit" && evt.data?.name === sub
|
|
49
|
+
);
|
|
50
|
+
if (emitEvent && emitEvent.data?.payload !== void 0) {
|
|
51
|
+
emitData[sub] = emitEvent.data.payload;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const payload = {
|
|
55
|
+
flowId: runId,
|
|
56
|
+
flowName,
|
|
57
|
+
input: emitData
|
|
58
|
+
// Keyed by event name
|
|
59
|
+
};
|
|
60
|
+
const jobId = `${runId}__${stepName}`;
|
|
61
|
+
try {
|
|
62
|
+
await enqueue(stepMeta.queue, { name: stepName, data: payload, opts: { jobId } });
|
|
63
|
+
logger.debug("Triggered pending step", {
|
|
64
|
+
flowName,
|
|
65
|
+
runId,
|
|
66
|
+
step: stepName,
|
|
67
|
+
subscribes: step.subscribes
|
|
68
|
+
});
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
} catch (err) {
|
|
75
|
+
logger.warn("Failed to check pending steps", {
|
|
76
|
+
flowName,
|
|
77
|
+
runId,
|
|
78
|
+
error: err?.message
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export function analyzeFlowCompletion(flowSteps, entryStep, events) {
|
|
83
|
+
const allSteps = entryStep ? [entryStep, ...Object.keys(flowSteps)] : Object.keys(flowSteps);
|
|
84
|
+
const completedSteps = /* @__PURE__ */ new Set();
|
|
85
|
+
const failedSteps = /* @__PURE__ */ new Set();
|
|
86
|
+
const retriedSteps = /* @__PURE__ */ new Map();
|
|
87
|
+
let startedAt = 0;
|
|
88
|
+
let completedAt = 0;
|
|
89
|
+
for (const event of events) {
|
|
90
|
+
if (event.type === "flow.start") {
|
|
91
|
+
startedAt = typeof event.ts === "string" ? new Date(event.ts).getTime() : 0;
|
|
92
|
+
}
|
|
93
|
+
if (event.type === "step.completed" && "stepName" in event) {
|
|
94
|
+
completedSteps.add(event.stepName);
|
|
95
|
+
}
|
|
96
|
+
if (event.type === "step.retry" && "stepName" in event) {
|
|
97
|
+
const currentAttempts = retriedSteps.get(event.stepName) || 0;
|
|
98
|
+
retriedSteps.set(event.stepName, currentAttempts + 1);
|
|
99
|
+
}
|
|
100
|
+
if (event.type === "step.failed" && "stepName" in event) {
|
|
101
|
+
failedSteps.add(event.stepName);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const finalFailedSteps = /* @__PURE__ */ new Set();
|
|
105
|
+
for (const stepName of failedSteps) {
|
|
106
|
+
let lastRetryIndex = -1;
|
|
107
|
+
let lastFailedIndex = -1;
|
|
108
|
+
for (let i = 0; i < events.length; i++) {
|
|
109
|
+
const event = events[i];
|
|
110
|
+
if ("stepName" in event && event.stepName === stepName) {
|
|
111
|
+
if (event.type === "step.retry") {
|
|
112
|
+
lastRetryIndex = i;
|
|
113
|
+
}
|
|
114
|
+
if (event.type === "step.failed") {
|
|
115
|
+
lastFailedIndex = i;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (lastFailedIndex > lastRetryIndex) {
|
|
120
|
+
finalFailedSteps.add(stepName);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const totalSteps = allSteps.length;
|
|
124
|
+
const hasFinalFailures = finalFailedSteps.size > 0;
|
|
125
|
+
let hasBlockingFailure = false;
|
|
126
|
+
if (hasFinalFailures) {
|
|
127
|
+
for (const failedStepName of finalFailedSteps) {
|
|
128
|
+
const failedStepDef = flowSteps[failedStepName];
|
|
129
|
+
if (failedStepDef?.emits && failedStepDef.emits.length > 0) {
|
|
130
|
+
for (const [stepName, stepDef] of Object.entries(flowSteps)) {
|
|
131
|
+
const step = stepDef;
|
|
132
|
+
if (stepName === failedStepName) continue;
|
|
133
|
+
if (step.subscribes && step.subscribes.length > 0) {
|
|
134
|
+
const dependsOnFailedStep = step.subscribes.some((sub) => {
|
|
135
|
+
return failedStepDef.emits.some(
|
|
136
|
+
(emit) => sub === `${failedStepName}.${emit}` || sub === emit
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
if (dependsOnFailedStep && !completedSteps.has(stepName)) {
|
|
140
|
+
hasBlockingFailure = true;
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (hasBlockingFailure) break;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (hasBlockingFailure) {
|
|
150
|
+
return {
|
|
151
|
+
status: "failed",
|
|
152
|
+
totalSteps,
|
|
153
|
+
completedSteps: completedSteps.size,
|
|
154
|
+
startedAt,
|
|
155
|
+
completedAt: Date.now()
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
const allCompleted = allSteps.every(
|
|
159
|
+
(step) => completedSteps.has(step) || finalFailedSteps.has(step)
|
|
160
|
+
);
|
|
161
|
+
let status = "running";
|
|
162
|
+
if (allCompleted) {
|
|
163
|
+
status = "completed";
|
|
164
|
+
completedAt = Date.now();
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
status,
|
|
168
|
+
totalSteps,
|
|
169
|
+
completedSteps: completedSteps.size,
|
|
170
|
+
startedAt,
|
|
171
|
+
completedAt
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
export function createFlowWiring(deps) {
|
|
175
|
+
const { adapter } = deps;
|
|
176
|
+
const bus = getEventBus();
|
|
177
|
+
const unsubs = [];
|
|
178
|
+
let wired = false;
|
|
179
|
+
const indexFlowRun = async (flowName, flowId, timestamp, metadata) => {
|
|
180
|
+
try {
|
|
181
|
+
const store = useEventStore();
|
|
182
|
+
const names = store.names();
|
|
183
|
+
const indexKey = names.flowIndex(flowName);
|
|
184
|
+
await store.indexAdd(indexKey, flowId, timestamp, metadata);
|
|
185
|
+
logger.debug("Indexed run", { flowName, flowId, indexKey, timestamp, metadata });
|
|
186
|
+
} catch (err) {
|
|
187
|
+
logger.error("Failed to index run", { error: err });
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
function start() {
|
|
191
|
+
if (wired) return;
|
|
192
|
+
wired = true;
|
|
193
|
+
const store = useEventStore();
|
|
194
|
+
const names = store.names();
|
|
195
|
+
const handlePersistence = async (e) => {
|
|
196
|
+
try {
|
|
197
|
+
if (e.id && e.ts) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const runId = e.runId;
|
|
201
|
+
if (!runId) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const flowName = e.flowName;
|
|
205
|
+
if (!flowName) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const streamName = names.flow(runId);
|
|
209
|
+
const eventData = {
|
|
210
|
+
type: e.type,
|
|
211
|
+
runId: e.runId,
|
|
212
|
+
flowName: e.flowName,
|
|
213
|
+
data: e.data
|
|
214
|
+
};
|
|
215
|
+
if ("stepName" in e && e.stepName) eventData.stepName = e.stepName;
|
|
216
|
+
if ("stepId" in e && e.stepId) eventData.stepId = e.stepId;
|
|
217
|
+
if ("attempt" in e && e.attempt) eventData.attempt = e.attempt;
|
|
218
|
+
await adapter.append(streamName, eventData);
|
|
219
|
+
if (e.type === "flow.completed" || e.type === "flow.failed") {
|
|
220
|
+
logger.info("Stored terminal event to stream", {
|
|
221
|
+
type: e.type,
|
|
222
|
+
flowName,
|
|
223
|
+
runId
|
|
224
|
+
});
|
|
225
|
+
} else {
|
|
226
|
+
logger.debug("Stored event to stream", {
|
|
227
|
+
type: e.type,
|
|
228
|
+
flowName,
|
|
229
|
+
runId,
|
|
230
|
+
stepName: "stepName" in e ? e.stepName : void 0
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
} catch (err) {
|
|
234
|
+
logger.error("ERROR persisting event", {
|
|
235
|
+
type: e.type,
|
|
236
|
+
runId: e.runId,
|
|
237
|
+
flowName: e.flowName,
|
|
238
|
+
error: err?.message
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
const handleOrchestration = async (e) => {
|
|
243
|
+
try {
|
|
244
|
+
if (e.id && e.ts) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (e.type === "flow.completed" || e.type === "flow.failed") {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const runId = e.runId;
|
|
251
|
+
if (!runId) return;
|
|
252
|
+
const flowName = e.flowName;
|
|
253
|
+
if (!flowName) return;
|
|
254
|
+
const streamName = names.flow(runId);
|
|
255
|
+
const indexKey = names.flowIndex(flowName);
|
|
256
|
+
if (e.type === "flow.start") {
|
|
257
|
+
const timestamp = Date.now();
|
|
258
|
+
await indexFlowRun(flowName, runId, timestamp, {
|
|
259
|
+
status: "running",
|
|
260
|
+
startedAt: timestamp,
|
|
261
|
+
stepCount: 0,
|
|
262
|
+
completedSteps: 0,
|
|
263
|
+
emittedEvents: []
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
if (e.type === "step.completed") {
|
|
267
|
+
try {
|
|
268
|
+
const newCount = await store.indexIncrement(indexKey, runId, "completedSteps", 1);
|
|
269
|
+
logger.debug("Incremented completedSteps", {
|
|
270
|
+
flowName,
|
|
271
|
+
runId,
|
|
272
|
+
stepName: "stepName" in e ? e.stepName : "unknown",
|
|
273
|
+
newCount
|
|
274
|
+
});
|
|
275
|
+
} catch (err) {
|
|
276
|
+
logger.warn("Failed to update completedSteps", {
|
|
277
|
+
flowName,
|
|
278
|
+
runId,
|
|
279
|
+
error: err?.message
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (e.type === "emit") {
|
|
284
|
+
const emitEvent = e;
|
|
285
|
+
const eventName = emitEvent.data?.name || emitEvent.data?.topic;
|
|
286
|
+
if (!eventName) {
|
|
287
|
+
logger.warn("Emit event missing name/topic", { flowName, runId, data: emitEvent.data });
|
|
288
|
+
} else {
|
|
289
|
+
try {
|
|
290
|
+
const currentEntry = await store.indexGet(indexKey, runId);
|
|
291
|
+
const emittedEvents = (currentEntry?.metadata?.emittedEvents || []).filter((item) => item != null && typeof item === "string");
|
|
292
|
+
if (!emittedEvents.includes(eventName)) {
|
|
293
|
+
await store.indexUpdateWithRetry(indexKey, runId, {
|
|
294
|
+
emittedEvents: [...emittedEvents, eventName]
|
|
295
|
+
});
|
|
296
|
+
logger.debug("Tracked emit event", {
|
|
297
|
+
flowName,
|
|
298
|
+
runId,
|
|
299
|
+
name: eventName,
|
|
300
|
+
allEmitted: [...emittedEvents, eventName]
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
} catch (err) {
|
|
304
|
+
logger.warn("Failed to track emitted event", {
|
|
305
|
+
flowName,
|
|
306
|
+
runId,
|
|
307
|
+
event: eventName,
|
|
308
|
+
error: err?.message
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
await checkAndTriggerPendingSteps(flowName, runId, store);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
if (e.type === "step.completed" || e.type === "step.failed") {
|
|
315
|
+
await checkAndTriggerPendingSteps(flowName, runId, store);
|
|
316
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
317
|
+
try {
|
|
318
|
+
const allEvents = await store.read(streamName);
|
|
319
|
+
const analyzedFlows = $useAnalyzedFlows();
|
|
320
|
+
const flowDef = analyzedFlows.find((f) => f.id === flowName);
|
|
321
|
+
if (flowDef?.steps) {
|
|
322
|
+
const entryStepName = flowDef.entry?.step;
|
|
323
|
+
const analysis = analyzeFlowCompletion(flowDef.steps, entryStepName, allEvents);
|
|
324
|
+
const updateMetadata = {
|
|
325
|
+
status: analysis.status,
|
|
326
|
+
stepCount: analysis.totalSteps
|
|
327
|
+
};
|
|
328
|
+
if (analysis.status !== "running" && analysis.completedAt) {
|
|
329
|
+
updateMetadata.completedAt = analysis.completedAt;
|
|
330
|
+
}
|
|
331
|
+
await store.indexUpdateWithRetry(indexKey, runId, updateMetadata);
|
|
332
|
+
if (analysis.status === "completed" || analysis.status === "failed") {
|
|
333
|
+
const eventType = analysis.status === "completed" ? "flow.completed" : "flow.failed";
|
|
334
|
+
const terminalEventExists = allEvents.some(
|
|
335
|
+
(evt) => evt.type === "flow.completed" || evt.type === "flow.failed"
|
|
336
|
+
);
|
|
337
|
+
if (terminalEventExists) {
|
|
338
|
+
logger.debug("Terminal event already exists, skipping publish", {
|
|
339
|
+
flowName,
|
|
340
|
+
runId,
|
|
341
|
+
eventType
|
|
342
|
+
});
|
|
343
|
+
} else {
|
|
344
|
+
logger.info("Publishing terminal event to bus", {
|
|
345
|
+
flowName,
|
|
346
|
+
runId,
|
|
347
|
+
eventType
|
|
348
|
+
});
|
|
349
|
+
await bus.publish({
|
|
350
|
+
type: eventType,
|
|
351
|
+
runId,
|
|
352
|
+
flowName,
|
|
353
|
+
data: {}
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
} catch (err) {
|
|
359
|
+
logger.warn("Failed to analyze flow completion", {
|
|
360
|
+
flowName,
|
|
361
|
+
runId,
|
|
362
|
+
error: err?.message
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
} catch (err) {
|
|
367
|
+
logger.error("ERROR handling event", {
|
|
368
|
+
type: e.type,
|
|
369
|
+
runId: e.runId,
|
|
370
|
+
flowName: e.flowName,
|
|
371
|
+
error: err?.message,
|
|
372
|
+
stack: err?.stack
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
const eventTypes = [
|
|
377
|
+
"flow.start",
|
|
378
|
+
"flow.completed",
|
|
379
|
+
"flow.failed",
|
|
380
|
+
"step.started",
|
|
381
|
+
"step.completed",
|
|
382
|
+
"step.failed",
|
|
383
|
+
"step.retry",
|
|
384
|
+
"log",
|
|
385
|
+
"emit",
|
|
386
|
+
"state"
|
|
387
|
+
];
|
|
388
|
+
for (const type of eventTypes) {
|
|
389
|
+
unsubs.push(bus.onType(type, handlePersistence));
|
|
390
|
+
}
|
|
391
|
+
for (const type of eventTypes) {
|
|
392
|
+
unsubs.push(bus.onType(type, handleOrchestration));
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
function stop() {
|
|
396
|
+
for (const u of unsubs.splice(0)) {
|
|
397
|
+
try {
|
|
398
|
+
u();
|
|
399
|
+
} catch {
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
wired = false;
|
|
403
|
+
logger.debug("Flow wiring stopped");
|
|
404
|
+
}
|
|
405
|
+
return { start, stop };
|
|
406
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { StreamAdapter } from '../types.js';
|
|
2
|
+
export interface WiringDeps {
|
|
3
|
+
adapter: StreamAdapter;
|
|
4
|
+
names?: any;
|
|
5
|
+
}
|
|
6
|
+
export interface Wiring {
|
|
7
|
+
start(): void;
|
|
8
|
+
stop(): void;
|
|
9
|
+
}
|
|
10
|
+
export declare function createWiringRegistry(deps: WiringDeps): Wiring;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createFlowWiring } from "./flowWiring.js";
|
|
2
|
+
export function createWiringRegistry(deps) {
|
|
3
|
+
const wirings = [
|
|
4
|
+
createFlowWiring({ adapter: deps.adapter })
|
|
5
|
+
// add future wirings here (triggers, webhooks, etc.)
|
|
6
|
+
];
|
|
7
|
+
let started = false;
|
|
8
|
+
return {
|
|
9
|
+
start() {
|
|
10
|
+
if (started) return;
|
|
11
|
+
started = true;
|
|
12
|
+
for (const w of wirings) w.start();
|
|
13
|
+
},
|
|
14
|
+
stop() {
|
|
15
|
+
for (const w of wirings) {
|
|
16
|
+
try {
|
|
17
|
+
w.stop();
|
|
18
|
+
} catch {
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
started = false;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Flow Run Snapshots (stream-based)
|
|
3
|
+
*
|
|
4
|
+
* Writes append-only snapshot events to nq:proj:flow:<flowName>:<runId>
|
|
5
|
+
* for key lifecycle kinds:
|
|
6
|
+
* - flow.start -> status=running
|
|
7
|
+
* - flow.complete -> status=completed
|
|
8
|
+
* - runner.log (with correlationId) -> logsCount++ (as a patch)
|
|
9
|
+
*
|
|
10
|
+
* Consumers reduce the small snapshot stream to a final object.
|
|
11
|
+
*/
|
|
12
|
+
declare const _default: any;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineNitroPlugin } from "#imports";
|
|
2
|
+
import { getEventStoreFactory } from "../events/eventStoreFactory.js";
|
|
3
|
+
export default defineNitroPlugin(() => {
|
|
4
|
+
const factory = getEventStoreFactory();
|
|
5
|
+
factory.start();
|
|
6
|
+
return {
|
|
7
|
+
hooks: {
|
|
8
|
+
close: async () => {
|
|
9
|
+
try {
|
|
10
|
+
factory.stop();
|
|
11
|
+
} catch {
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
});
|