@arki/event-sourcing 0.1.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 +124 -0
- package/dist/builders/command-handler.d.ts +48 -0
- package/dist/builders/command-handler.d.ts.map +1 -0
- package/dist/builders/command-handler.js +40 -0
- package/dist/builders/command-handler.js.map +1 -0
- package/dist/builders/command.d.ts +39 -0
- package/dist/builders/command.d.ts.map +1 -0
- package/dist/builders/command.js +44 -0
- package/dist/builders/command.js.map +1 -0
- package/dist/builders/decider.d.ts +188 -0
- package/dist/builders/decider.d.ts.map +1 -0
- package/dist/builders/decider.js +252 -0
- package/dist/builders/decider.js.map +1 -0
- package/dist/builders/event.d.ts +39 -0
- package/dist/builders/event.d.ts.map +1 -0
- package/dist/builders/event.js +42 -0
- package/dist/builders/event.js.map +1 -0
- package/dist/builders/index.d.ts +40 -0
- package/dist/builders/index.d.ts.map +1 -0
- package/dist/builders/index.js +40 -0
- package/dist/builders/index.js.map +1 -0
- package/dist/builders/process-manager.d.ts +94 -0
- package/dist/builders/process-manager.d.ts.map +1 -0
- package/dist/builders/process-manager.js +131 -0
- package/dist/builders/process-manager.js.map +1 -0
- package/dist/builders/projection.d.ts +92 -0
- package/dist/builders/projection.d.ts.map +1 -0
- package/dist/builders/projection.js +129 -0
- package/dist/builders/projection.js.map +1 -0
- package/dist/builders/stateful-process-manager.d.ts +181 -0
- package/dist/builders/stateful-process-manager.d.ts.map +1 -0
- package/dist/builders/stateful-process-manager.js +280 -0
- package/dist/builders/stateful-process-manager.js.map +1 -0
- package/dist/bus.d.ts +3 -0
- package/dist/bus.d.ts.map +1 -0
- package/dist/bus.js +2 -0
- package/dist/bus.js.map +1 -0
- package/dist/command-flow.d.ts +87 -0
- package/dist/command-flow.d.ts.map +1 -0
- package/dist/command-flow.js +233 -0
- package/dist/command-flow.js.map +1 -0
- package/dist/command.d.ts +38 -0
- package/dist/command.d.ts.map +1 -0
- package/dist/command.js +2 -0
- package/dist/command.js.map +1 -0
- package/dist/debug.d.ts +31 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/debug.js +31 -0
- package/dist/debug.js.map +1 -0
- package/dist/decide.d.ts +11 -0
- package/dist/decide.d.ts.map +1 -0
- package/dist/decide.js +2 -0
- package/dist/decide.js.map +1 -0
- package/dist/dot.d.ts +90 -0
- package/dist/dot.d.ts.map +1 -0
- package/dist/dot.js +91 -0
- package/dist/dot.js.map +1 -0
- package/dist/error.d.ts +2 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +2 -0
- package/dist/error.js.map +1 -0
- package/dist/event-sourcing-features.d.ts +81 -0
- package/dist/event-sourcing-features.d.ts.map +1 -0
- package/dist/event-sourcing-features.js +139 -0
- package/dist/event-sourcing-features.js.map +1 -0
- package/dist/event.d.ts +25 -0
- package/dist/event.d.ts.map +1 -0
- package/dist/event.js +2 -0
- package/dist/event.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/package.json +5 -0
- package/dist/process-manager.d.ts +113 -0
- package/dist/process-manager.d.ts.map +1 -0
- package/dist/process-manager.js +155 -0
- package/dist/process-manager.js.map +1 -0
- package/dist/simple-process-manager.d.ts +37 -0
- package/dist/simple-process-manager.d.ts.map +1 -0
- package/dist/simple-process-manager.js +55 -0
- package/dist/simple-process-manager.js.map +1 -0
- package/dist/src/builders/command-handler.d.ts +48 -0
- package/dist/src/builders/command-handler.d.ts.map +1 -0
- package/dist/src/builders/command.d.ts +39 -0
- package/dist/src/builders/command.d.ts.map +1 -0
- package/dist/src/builders/decider.d.ts +188 -0
- package/dist/src/builders/decider.d.ts.map +1 -0
- package/dist/src/builders/event.d.ts +39 -0
- package/dist/src/builders/event.d.ts.map +1 -0
- package/dist/src/builders/index.d.ts +40 -0
- package/dist/src/builders/index.d.ts.map +1 -0
- package/dist/src/builders/process-manager.d.ts +94 -0
- package/dist/src/builders/process-manager.d.ts.map +1 -0
- package/dist/src/builders/projection.d.ts +92 -0
- package/dist/src/builders/projection.d.ts.map +1 -0
- package/dist/src/builders/stateful-process-manager.d.ts +181 -0
- package/dist/src/builders/stateful-process-manager.d.ts.map +1 -0
- package/dist/src/bus.d.ts +3 -0
- package/dist/src/bus.d.ts.map +1 -0
- package/dist/src/command-flow.d.ts +87 -0
- package/dist/src/command-flow.d.ts.map +1 -0
- package/dist/src/command.d.ts +16 -0
- package/dist/src/command.d.ts.map +1 -0
- package/dist/src/debug.d.ts +31 -0
- package/dist/src/debug.d.ts.map +1 -0
- package/dist/src/decide.d.ts +11 -0
- package/dist/src/decide.d.ts.map +1 -0
- package/dist/src/error.d.ts +2 -0
- package/dist/src/error.d.ts.map +1 -0
- package/dist/src/event.d.ts +25 -0
- package/dist/src/event.d.ts.map +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/process-manager.d.ts +113 -0
- package/dist/src/process-manager.d.ts.map +1 -0
- package/dist/src/store.d.ts +44 -0
- package/dist/src/store.d.ts.map +1 -0
- package/dist/src/types.d.ts +10 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/store.d.ts +44 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +94 -0
- package/dist/store.js.map +1 -0
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +100 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export * from './command.js';
|
|
2
|
+
export * from './decide.js';
|
|
3
|
+
export * from './event.js';
|
|
4
|
+
export { createSimpleProcessManager } from './simple-process-manager.js';
|
|
5
|
+
export { EVENT_STORE_URL_VARIANTS, eventSourcingFeatures, } from './event-sourcing-features.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AACzE,OAAO,EACL,wBAAwB,EACxB,qBAAqB,GAEtB,MAAM,8BAA8B,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { AnyEvent, DefaultRecord, Event, EventTypeOf, GlobalPositionTypeOfRecordedMessageMetadata, MessageBus, MessageProcessorStartFrom, ReadEventMetadataWithGlobalPosition } from '@event-driven-io/emmett';
|
|
2
|
+
/**
|
|
3
|
+
* Process Manager (Saga) handler context
|
|
4
|
+
* This context is passed to the process manager handler function
|
|
5
|
+
*/
|
|
6
|
+
export type ProcessManagerContext = DefaultRecord & {
|
|
7
|
+
/** Message bus for sending commands in response to events */
|
|
8
|
+
messageBus: MessageBus;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Process Manager handler function
|
|
12
|
+
*/
|
|
13
|
+
export type ProcessManagerHandler<EventType extends Event = AnyEvent, Context extends ProcessManagerContext = ProcessManagerContext> = (events: EventType[], context: Context) => Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Process Manager configuration options
|
|
16
|
+
*/
|
|
17
|
+
export type ProcessManagerOptions<EventType extends Event = AnyEvent, Context extends ProcessManagerContext = ProcessManagerContext, CheckpointType = GlobalPositionTypeOfRecordedMessageMetadata<ReadEventMetadataWithGlobalPosition>> = {
|
|
18
|
+
/** Unique identifier for the process manager */
|
|
19
|
+
name: string;
|
|
20
|
+
/** Event types the process manager will handle */
|
|
21
|
+
eventTypes: EventTypeOf<EventType>[];
|
|
22
|
+
/** Handler function that processes events */
|
|
23
|
+
handler: ProcessManagerHandler<EventType, Context>;
|
|
24
|
+
/**
|
|
25
|
+
* Optional hooks for process manager lifecycle
|
|
26
|
+
*/
|
|
27
|
+
hooks?: {
|
|
28
|
+
/** Called when the process manager starts */
|
|
29
|
+
onStart?: (context: Context) => Promise<void>;
|
|
30
|
+
/** Called when the process manager closes */
|
|
31
|
+
onClose?: () => Promise<void>;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Optional configuration for resuming from specific checkpoint
|
|
35
|
+
* Useful for long-running process managers
|
|
36
|
+
*/
|
|
37
|
+
startFrom?: MessageProcessorStartFrom<CheckpointType>;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Creates a process manager (saga) that subscribes to events and orchestrates responses
|
|
41
|
+
* This is built on top of Emmett's reactor functionality
|
|
42
|
+
*/
|
|
43
|
+
export declare function createProcessManager<EventType extends Event = AnyEvent, Context extends ProcessManagerContext = ProcessManagerContext, CheckpointType = GlobalPositionTypeOfRecordedMessageMetadata<ReadEventMetadataWithGlobalPosition>>(options: ProcessManagerOptions<EventType, Context, CheckpointType>): import("@event-driven-io/emmett").MessageProcessor<EventType, ReadEventMetadataWithGlobalPosition, Context, CheckpointType>;
|
|
44
|
+
/**
|
|
45
|
+
* State that can be maintained by a stateful process manager
|
|
46
|
+
*/
|
|
47
|
+
export type ProcessManagerState = DefaultRecord;
|
|
48
|
+
/**
|
|
49
|
+
* Handler function for a stateful process manager
|
|
50
|
+
*/
|
|
51
|
+
export type StatefulProcessManagerHandler<EventType extends Event = AnyEvent, StateType extends ProcessManagerState = ProcessManagerState, Context extends ProcessManagerContext = ProcessManagerContext> = (events: EventType[], state: StateType, context: Context) => Promise<StateType>;
|
|
52
|
+
/**
|
|
53
|
+
* Options for creating a stateful process manager
|
|
54
|
+
*/
|
|
55
|
+
export type StatefulProcessManagerOptions<EventType extends Event = AnyEvent, StateType extends ProcessManagerState = ProcessManagerState, Context extends ProcessManagerContext = ProcessManagerContext, CheckpointType = GlobalPositionTypeOfRecordedMessageMetadata<ReadEventMetadataWithGlobalPosition>> = Omit<ProcessManagerOptions<EventType, Context, CheckpointType>, 'handler'> & {
|
|
56
|
+
/** Initial state for the process manager */
|
|
57
|
+
initialState: StateType;
|
|
58
|
+
/** Handler function that processes events and updates state */
|
|
59
|
+
handler: StatefulProcessManagerHandler<EventType, StateType, Context>;
|
|
60
|
+
/**
|
|
61
|
+
* Store function that persists process manager state
|
|
62
|
+
* Called after each successful event processing
|
|
63
|
+
*/
|
|
64
|
+
storeState?: (state: StateType, processorId: string) => Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Load function that retrieves process manager state
|
|
67
|
+
* Called during initialization
|
|
68
|
+
*/
|
|
69
|
+
loadState?: (processorId: string) => Promise<StateType | null>;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Creates a stateful process manager that maintains its own state
|
|
73
|
+
* This is useful for tracking saga state across event processing
|
|
74
|
+
*/
|
|
75
|
+
export declare function createStatefulProcessManager<EventType extends Event = AnyEvent, StateType extends ProcessManagerState = ProcessManagerState, Context extends ProcessManagerContext = ProcessManagerContext, CheckpointType = GlobalPositionTypeOfRecordedMessageMetadata<ReadEventMetadataWithGlobalPosition>>(options: StatefulProcessManagerOptions<EventType, StateType, Context, CheckpointType>): import("@event-driven-io/emmett").MessageProcessor<EventType, ReadEventMetadataWithGlobalPosition, Context, CheckpointType>;
|
|
76
|
+
/**
|
|
77
|
+
* Function to generate a unique idempotency key for an event
|
|
78
|
+
* Used to ensure that a process manager only processes an event once
|
|
79
|
+
*
|
|
80
|
+
* @param event The event to generate an idempotency key for
|
|
81
|
+
* @param processManagerId Optional identifier for the process manager
|
|
82
|
+
* @returns A string that can be used as an idempotency key
|
|
83
|
+
*/
|
|
84
|
+
export declare function generateIdempotencyKey(event: Event<any, any, ReadEventMetadataWithGlobalPosition>, processManagerId?: string): string;
|
|
85
|
+
/**
|
|
86
|
+
* Interface for a function to check if an event has already been processed
|
|
87
|
+
*/
|
|
88
|
+
export type IdempotencyCheck = (key: string) => Promise<boolean>;
|
|
89
|
+
/**
|
|
90
|
+
* Interface for a function to mark an event as processed
|
|
91
|
+
*/
|
|
92
|
+
export type MarkProcessed = (key: string) => Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Options for idempotent event processing
|
|
95
|
+
*/
|
|
96
|
+
export type IdempotentProcessingOptions = {
|
|
97
|
+
/** Function to check if an event has already been processed */
|
|
98
|
+
checkProcessed: IdempotencyCheck;
|
|
99
|
+
/** Function to mark an event as processed */
|
|
100
|
+
markProcessed: MarkProcessed;
|
|
101
|
+
/** Optional process manager ID to include in the idempotency key */
|
|
102
|
+
processManagerId?: string;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Higher-order function that wraps a process manager handler to provide idempotent processing
|
|
106
|
+
* This ensures that each event is only processed once, even if it's received multiple times
|
|
107
|
+
*
|
|
108
|
+
* @param handler The original process manager handler
|
|
109
|
+
* @param options Options for idempotent processing
|
|
110
|
+
* @returns A wrapped handler that implements idempotent processing
|
|
111
|
+
*/
|
|
112
|
+
export declare function withIdempotentProcessing<EventType extends Event<any, any, ReadEventMetadataWithGlobalPosition> = Event<any, any, ReadEventMetadataWithGlobalPosition>, Context extends ProcessManagerContext = ProcessManagerContext>(handler: ProcessManagerHandler<EventType, Context>, options: IdempotentProcessingOptions): ProcessManagerHandler<EventType, Context>;
|
|
113
|
+
//# sourceMappingURL=process-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-manager.d.ts","sourceRoot":"","sources":["../src/process-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { reactor } from '@event-driven-io/emmett';
|
|
2
|
+
import { debugProcess } from './debug.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a process manager (saga) that subscribes to events and orchestrates responses
|
|
5
|
+
* This is built on top of Emmett's reactor functionality
|
|
6
|
+
*/
|
|
7
|
+
export function createProcessManager(options) {
|
|
8
|
+
const { name, eventTypes, handler, hooks, startFrom } = options;
|
|
9
|
+
debugProcess('[%s] Creating process manager for event types: %o', name, eventTypes);
|
|
10
|
+
return reactor({
|
|
11
|
+
processorId: name,
|
|
12
|
+
canHandle: eventTypes,
|
|
13
|
+
startFrom,
|
|
14
|
+
// Process events in batch mode
|
|
15
|
+
eachBatch: async (events, context) => {
|
|
16
|
+
debugProcess('[%s] Processing batch of %d events', name, events.length);
|
|
17
|
+
await handler(events, context);
|
|
18
|
+
debugProcess('[%s] Batch processed successfully', name);
|
|
19
|
+
},
|
|
20
|
+
// Pass through lifecycle hooks
|
|
21
|
+
hooks: {
|
|
22
|
+
onStart: async (context) => {
|
|
23
|
+
debugProcess('[%s] Process manager starting', name);
|
|
24
|
+
if (hooks?.onStart) {
|
|
25
|
+
await hooks.onStart(context);
|
|
26
|
+
}
|
|
27
|
+
debugProcess('[%s] Process manager started', name);
|
|
28
|
+
},
|
|
29
|
+
onClose: async () => {
|
|
30
|
+
debugProcess('[%s] Process manager closing', name);
|
|
31
|
+
if (hooks?.onClose) {
|
|
32
|
+
await hooks.onClose();
|
|
33
|
+
}
|
|
34
|
+
debugProcess('[%s] Process manager closed', name);
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Creates a stateful process manager that maintains its own state
|
|
41
|
+
* This is useful for tracking saga state across event processing
|
|
42
|
+
*/
|
|
43
|
+
export function createStatefulProcessManager(options) {
|
|
44
|
+
const { name, eventTypes, initialState, handler, hooks, startFrom, storeState, loadState } = options;
|
|
45
|
+
debugProcess('[%s] Creating stateful process manager for event types: %o', name, eventTypes);
|
|
46
|
+
// Initialize state (will be updated during processing)
|
|
47
|
+
let state = initialState;
|
|
48
|
+
return reactor({
|
|
49
|
+
processorId: name,
|
|
50
|
+
canHandle: eventTypes,
|
|
51
|
+
startFrom,
|
|
52
|
+
hooks: {
|
|
53
|
+
// Load state during startup
|
|
54
|
+
onStart: async (context) => {
|
|
55
|
+
debugProcess('[%s] Stateful process manager starting', name);
|
|
56
|
+
if (loadState) {
|
|
57
|
+
debugProcess('[%s] Loading state from storage', name);
|
|
58
|
+
const loadedState = await loadState(name);
|
|
59
|
+
if (loadedState) {
|
|
60
|
+
state = loadedState;
|
|
61
|
+
debugProcess('[%s] State loaded successfully', name);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
debugProcess('[%s] No stored state found, using initial state', name);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Call user-provided onStart hook if specified
|
|
68
|
+
if (hooks?.onStart) {
|
|
69
|
+
await hooks.onStart(context);
|
|
70
|
+
}
|
|
71
|
+
debugProcess('[%s] Stateful process manager started', name);
|
|
72
|
+
},
|
|
73
|
+
// Call user-provided onClose hook if specified
|
|
74
|
+
onClose: async () => {
|
|
75
|
+
debugProcess('[%s] Stateful process manager closing', name);
|
|
76
|
+
if (hooks?.onClose) {
|
|
77
|
+
await hooks.onClose();
|
|
78
|
+
}
|
|
79
|
+
debugProcess('[%s] Stateful process manager closed', name);
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
// Process events and update state
|
|
83
|
+
eachBatch: async (events, context) => {
|
|
84
|
+
debugProcess('[%s] Processing batch of %d events (stateful)', name, events.length);
|
|
85
|
+
// Update state based on events
|
|
86
|
+
state = await handler(events, state, context);
|
|
87
|
+
debugProcess('[%s] State updated after processing events', name);
|
|
88
|
+
// Persist updated state if storage function provided
|
|
89
|
+
if (storeState) {
|
|
90
|
+
debugProcess('[%s] Storing updated state', name);
|
|
91
|
+
await storeState(state, name);
|
|
92
|
+
debugProcess('[%s] State stored successfully', name);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Function to generate a unique idempotency key for an event
|
|
99
|
+
* Used to ensure that a process manager only processes an event once
|
|
100
|
+
*
|
|
101
|
+
* @param event The event to generate an idempotency key for
|
|
102
|
+
* @param processManagerId Optional identifier for the process manager
|
|
103
|
+
* @returns A string that can be used as an idempotency key
|
|
104
|
+
*/
|
|
105
|
+
export function generateIdempotencyKey(event, processManagerId) {
|
|
106
|
+
// Get the event metadata
|
|
107
|
+
const metadata = event.metadata;
|
|
108
|
+
// Create an idempotency key using stream name, position, and optionally process manager ID
|
|
109
|
+
const baseKey = `${metadata.streamName}:${metadata.streamPosition}:${event.type}`;
|
|
110
|
+
// Add process manager ID if provided
|
|
111
|
+
return processManagerId ? `${processManagerId}:${baseKey}` : baseKey;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Higher-order function that wraps a process manager handler to provide idempotent processing
|
|
115
|
+
* This ensures that each event is only processed once, even if it's received multiple times
|
|
116
|
+
*
|
|
117
|
+
* @param handler The original process manager handler
|
|
118
|
+
* @param options Options for idempotent processing
|
|
119
|
+
* @returns A wrapped handler that implements idempotent processing
|
|
120
|
+
*/
|
|
121
|
+
export function withIdempotentProcessing(handler, options) {
|
|
122
|
+
const { checkProcessed, markProcessed, processManagerId } = options;
|
|
123
|
+
debugProcess('[%s] Wrapping handler with idempotent processing', processManagerId ?? 'unknown');
|
|
124
|
+
return async (events, context) => {
|
|
125
|
+
debugProcess('[%s] Checking idempotency for %d events', processManagerId ?? 'unknown', events.length);
|
|
126
|
+
// Filter out events that have already been processed
|
|
127
|
+
const unprocessedEvents = [];
|
|
128
|
+
const processedKeys = [];
|
|
129
|
+
// Check each event
|
|
130
|
+
for (const event of events) {
|
|
131
|
+
const idempotencyKey = generateIdempotencyKey(event, processManagerId);
|
|
132
|
+
const alreadyProcessed = await checkProcessed(idempotencyKey);
|
|
133
|
+
if (alreadyProcessed) {
|
|
134
|
+
debugProcess('[%s] Event already processed, skipping: %s', processManagerId ?? 'unknown', idempotencyKey);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
unprocessedEvents.push(event);
|
|
138
|
+
processedKeys.push(idempotencyKey);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// If no events need processing, return early
|
|
142
|
+
if (unprocessedEvents.length === 0) {
|
|
143
|
+
debugProcess('[%s] All events already processed, skipping batch', processManagerId ?? 'unknown');
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
debugProcess('[%s] Processing %d unprocessed events', processManagerId ?? 'unknown', unprocessedEvents.length);
|
|
147
|
+
// Process the unprocessed events
|
|
148
|
+
await handler(unprocessedEvents, context);
|
|
149
|
+
// Mark all events as processed
|
|
150
|
+
debugProcess('[%s] Marking %d events as processed', processManagerId ?? 'unknown', processedKeys.length);
|
|
151
|
+
await Promise.all(processedKeys.map(key => markProcessed(key)));
|
|
152
|
+
debugProcess('[%s] Idempotent processing completed', processManagerId ?? 'unknown');
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=process-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-manager.js","sourceRoot":"","sources":["../src/process-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Event } from '@event-driven-io/emmett';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a simple process manager that reacts to events one at a time,
|
|
4
|
+
* with a pre-bound context closed over at construction time.
|
|
5
|
+
*
|
|
6
|
+
* This is a thin wrapper around Emmett's `reactor` that exposes a positional
|
|
7
|
+
* API with per-message processing semantics. It is intended for the most
|
|
8
|
+
* common process manager use case where:
|
|
9
|
+
*
|
|
10
|
+
* - The context (repositories, KV, message bus, etc.) is fixed at construction time.
|
|
11
|
+
* - The handler operates on one event at a time rather than a batch.
|
|
12
|
+
* - Errors propagate to the consumer so the underlying subscription can
|
|
13
|
+
* apply retry/back-off policies.
|
|
14
|
+
*
|
|
15
|
+
* For richer use cases (per-batch processing, lifecycle hooks, stateful
|
|
16
|
+
* sagas, idempotency) prefer {@link createProcessManager} or
|
|
17
|
+
* {@link createStatefulProcessManager} from this package.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const trackingNotifications = createSimpleProcessManager(
|
|
22
|
+
* { repo, kv },
|
|
23
|
+
* 'tracking-notifications',
|
|
24
|
+
* ['MovieWatchLogged', 'TvShowRated'],
|
|
25
|
+
* async (event, context) => {
|
|
26
|
+
* // ... handle one event using context
|
|
27
|
+
* },
|
|
28
|
+
* );
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* @param context Fixed context closed over by the process manager handler.
|
|
32
|
+
* @param name Unique identifier for the process manager (used as processor id).
|
|
33
|
+
* @param eventTypes Event types this process manager reacts to.
|
|
34
|
+
* @param handlerFn Async function invoked once per matching event.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createSimpleProcessManager<TEvent extends Event, TContext extends object>(context: TContext, name: string, eventTypes: TEvent['type'][], handlerFn: (event: TEvent, context: TContext) => Promise<void>): import("@event-driven-io/emmett").MessageProcessor<TEvent, import("@event-driven-io/emmett").AnyRecordedMessageMetadata, import("@event-driven-io/emmett").DefaultRecord, any>;
|
|
37
|
+
//# sourceMappingURL=simple-process-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simple-process-manager.d.ts","sourceRoot":"","sources":["../src/simple-process-manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAKrD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,SAAS,KAAK,EAAE,QAAQ,SAAS,MAAM,EACtF,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,EAC5B,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,kLA0B/D"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { reactor } from '@event-driven-io/emmett';
|
|
2
|
+
import { debugProcess } from './debug.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a simple process manager that reacts to events one at a time,
|
|
5
|
+
* with a pre-bound context closed over at construction time.
|
|
6
|
+
*
|
|
7
|
+
* This is a thin wrapper around Emmett's `reactor` that exposes a positional
|
|
8
|
+
* API with per-message processing semantics. It is intended for the most
|
|
9
|
+
* common process manager use case where:
|
|
10
|
+
*
|
|
11
|
+
* - The context (repositories, KV, message bus, etc.) is fixed at construction time.
|
|
12
|
+
* - The handler operates on one event at a time rather than a batch.
|
|
13
|
+
* - Errors propagate to the consumer so the underlying subscription can
|
|
14
|
+
* apply retry/back-off policies.
|
|
15
|
+
*
|
|
16
|
+
* For richer use cases (per-batch processing, lifecycle hooks, stateful
|
|
17
|
+
* sagas, idempotency) prefer {@link createProcessManager} or
|
|
18
|
+
* {@link createStatefulProcessManager} from this package.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const trackingNotifications = createSimpleProcessManager(
|
|
23
|
+
* { repo, kv },
|
|
24
|
+
* 'tracking-notifications',
|
|
25
|
+
* ['MovieWatchLogged', 'TvShowRated'],
|
|
26
|
+
* async (event, context) => {
|
|
27
|
+
* // ... handle one event using context
|
|
28
|
+
* },
|
|
29
|
+
* );
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @param context Fixed context closed over by the process manager handler.
|
|
33
|
+
* @param name Unique identifier for the process manager (used as processor id).
|
|
34
|
+
* @param eventTypes Event types this process manager reacts to.
|
|
35
|
+
* @param handlerFn Async function invoked once per matching event.
|
|
36
|
+
*/
|
|
37
|
+
export function createSimpleProcessManager(context, name, eventTypes, handlerFn) {
|
|
38
|
+
debugProcess('[createSimpleProcessManager] Creating process manager: %s for event types: %s', name, eventTypes.join(', '));
|
|
39
|
+
return reactor({
|
|
40
|
+
canHandle: [...eventTypes],
|
|
41
|
+
eachMessage: async (message) => {
|
|
42
|
+
debugProcess('[createSimpleProcessManager:%s] Processing event: %s', name, message.type);
|
|
43
|
+
try {
|
|
44
|
+
await handlerFn(message, context);
|
|
45
|
+
debugProcess('[createSimpleProcessManager:%s] Successfully processed event: %s', name, message.type);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
debugProcess('[createSimpleProcessManager:%s] Error processing event %s: %s', name, message.type, error instanceof Error ? error.message : String(error));
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
processorId: `process-manager-${name}`,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=simple-process-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simple-process-manager.js","sourceRoot":"","sources":["../src/simple-process-manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAElD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAAiB,EACjB,IAAY,EACZ,UAA4B,EAC5B,SAA8D;IAE9D,YAAY,CACV,+EAA+E,EAC/E,IAAI,EACJ,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CACtB,CAAC;IACF,OAAO,OAAO,CAAS;QACrB,SAAS,EAAE,CAAC,GAAG,UAAU,CAAC;QAC1B,WAAW,EAAE,KAAK,EAAC,OAAO,EAAC,EAAE;YAC3B,YAAY,CAAC,sDAAsD,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;YACzF,IAAI,CAAC;gBACH,MAAM,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBAClC,YAAY,CAAC,kEAAkE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;YACvG,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,YAAY,CACV,+DAA+D,EAC/D,IAAI,EACJ,OAAO,CAAC,IAAI,EACZ,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CACvD,CAAC;gBACF,MAAM,KAAK,CAAC;YACd,CAAC;QACH,CAAC;QACD,WAAW,EAAE,mBAAmB,IAAI,EAAE;KACvC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { CommandHandlerResult, Event, EventStore, HandleOptions } from '@event-driven-io/emmett';
|
|
2
|
+
type DeciderConfig<State, CommandType, StreamEvent> = {
|
|
3
|
+
initialState: () => State;
|
|
4
|
+
evolve: (state: State, event: StreamEvent) => State;
|
|
5
|
+
decide: (command: CommandType, state: State) => StreamEvent | StreamEvent[];
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Store-connected command handler function type.
|
|
9
|
+
*
|
|
10
|
+
* Given an event store, stream id, and one or more commands, it loads the
|
|
11
|
+
* current aggregate state from the stream, applies the decider's `decide`
|
|
12
|
+
* function, and appends the resulting events.
|
|
13
|
+
*/
|
|
14
|
+
export type CommandHandler<State, CommandType, StreamEvent extends Event> = <Store extends EventStore>(eventStore: Store, id: string, commands: CommandType | CommandType[], handleOptions?: HandleOptions<Store>) => Promise<CommandHandlerResult<State, StreamEvent, Store>>;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a store-connected command handler from a decider configuration.
|
|
17
|
+
*
|
|
18
|
+
* This is the recommended way to create command handlers. It wraps Emmett's
|
|
19
|
+
* `DeciderCommandHandler` while lifting the `CommandType extends Command`
|
|
20
|
+
* constraint that prevents commands with custom metadata from type-checking.
|
|
21
|
+
*
|
|
22
|
+
* Emmett's `Command` type uses a conditional type for metadata:
|
|
23
|
+
* - When metadata is `undefined`, the `metadata` property is optional.
|
|
24
|
+
* - When metadata is defined, it becomes required.
|
|
25
|
+
*
|
|
26
|
+
* TypeScript cannot prove that a concrete command (with custom metadata)
|
|
27
|
+
* satisfies `extends Command` across these conditional branches. This wrapper
|
|
28
|
+
* bridges that gap with a single, localised type assertion — keeping all
|
|
29
|
+
* call sites fully type-safe.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const handler = defineCommandHandler({
|
|
34
|
+
* initialState,
|
|
35
|
+
* evolve,
|
|
36
|
+
* decide,
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* export const bookCommandHandlers = BookCommands.map(commandType => ({
|
|
40
|
+
* commandType,
|
|
41
|
+
* handler,
|
|
42
|
+
* getStreamName,
|
|
43
|
+
* }));
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function defineCommandHandler<State, CommandType, StreamEvent extends Event>(config: DeciderConfig<State, CommandType, StreamEvent>): CommandHandler<State, CommandType, StreamEvent>;
|
|
47
|
+
export {};
|
|
48
|
+
//# sourceMappingURL=command-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-handler.d.ts","sourceRoot":"","sources":["../../../src/builders/command-handler.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAU,oBAAoB,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAC,MAAM,yBAAyB,CAAC;AAI7G,KAAK,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,IAAI;IACpD,YAAY,EAAE,MAAM,KAAK,CAAC;IAC1B,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,KAAK,KAAK,CAAC;IACpD,MAAM,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,KAAK,WAAW,GAAG,WAAW,EAAE,CAAC;CAC7E,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,SAAS,KAAK,IAAI,CAAC,KAAK,SAAS,UAAU,EACnG,UAAU,EAAE,KAAK,EACjB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,WAAW,GAAG,WAAW,EAAE,EACrC,aAAa,CAAC,EAAE,aAAa,CAAC,KAAK,CAAC,KACjC,OAAO,CAAC,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;AAE9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,SAAS,KAAK,EAChF,MAAM,EAAE,aAAa,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,CAAC,GACrD,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,WAAW,CAAC,CAWjD"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { z } from '@arki/contracts';
|
|
2
|
+
import type { Command, DefaultCommandMetadata } from '../command';
|
|
3
|
+
import type { DefaultRecord } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* Configuration for defining a domain command factory.
|
|
6
|
+
*/
|
|
7
|
+
export type CommandConfig<TType extends string, TInput extends DefaultRecord, TMetadata extends DefaultCommandMetadata | undefined = undefined> = {
|
|
8
|
+
/** The command type string (e.g., 'CreateUser') */
|
|
9
|
+
type: TType;
|
|
10
|
+
/** Zod schema for validating command input */
|
|
11
|
+
inputSchema: z.ZodType<TInput>;
|
|
12
|
+
/** Optional Zod schema for validating command metadata */
|
|
13
|
+
metadataSchema?: z.ZodType<TMetadata>;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Creates a strongly-typed command factory function.
|
|
17
|
+
*
|
|
18
|
+
* This factory validates input and metadata using Zod schemas before
|
|
19
|
+
* creating commands that can be dispatched through a command flow or aggregate.
|
|
20
|
+
*
|
|
21
|
+
* @param config - Configuration object containing type, input schema, and optional metadata schema
|
|
22
|
+
* @returns A factory function that validates and creates commands
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const createUserCommand = defineCommand({
|
|
27
|
+
* type: 'CreateUser',
|
|
28
|
+
* inputSchema: z.object({ name: z.string(), email: z.email() }),
|
|
29
|
+
* metadataSchema: z.object({ now: z.date(), issuedBy: z.string().uuid() }),
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* const command = createUserCommand(
|
|
33
|
+
* { name: 'Ada', email: 'ada@example.org' },
|
|
34
|
+
* { now: new Date(), issuedBy: 'usr_123' },
|
|
35
|
+
* );
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function defineCommand<TType extends string, TInput extends DefaultRecord, TMetadata extends DefaultCommandMetadata | undefined = undefined>(config: CommandConfig<TType, TInput, TMetadata>): (input: TInput, metadata?: TMetadata) => Command<TType, TInput, TMetadata>;
|
|
39
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../../src/builders/command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,KAAK,EAAE,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;GAEG;AACH,MAAM,MAAM,aAAa,CACvB,KAAK,SAAS,MAAM,EACpB,MAAM,SAAS,aAAa,EAC5B,SAAS,SAAS,sBAAsB,GAAG,SAAS,GAAG,SAAS,IAC9D;IACF,mDAAmD;IACnD,IAAI,EAAE,KAAK,CAAC;IACZ,8CAA8C;IAC9C,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/B,0DAA0D;IAC1D,cAAc,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;CACvC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,CAC3B,KAAK,SAAS,MAAM,EACpB,MAAM,SAAS,aAAa,EAC5B,SAAS,SAAS,sBAAsB,GAAG,SAAS,GAAG,SAAS,EAEhE,MAAM,EAAE,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,GAC9C,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAqB5E"}
|