@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-manager.js","sourceRoot":"","sources":["../../src/builders/process-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { z } from '@arki/contracts';
|
|
2
|
+
import type { AnyEvent } from '../event.js';
|
|
3
|
+
/**
|
|
4
|
+
* Type definition for CanHandle predicate
|
|
5
|
+
* Used to filter events that a projection can handle
|
|
6
|
+
*/
|
|
7
|
+
type CanHandle<EventType extends AnyEvent> = EventType['type'][];
|
|
8
|
+
/**
|
|
9
|
+
* Fluent builder for read-model projections.
|
|
10
|
+
*
|
|
11
|
+
* Projections consume event streams and populate query-side views. This builder captures
|
|
12
|
+
* the essentials—projection name, handled event types, validated context—and terminates
|
|
13
|
+
* in a `.handler(...)` call that returns the shape required by Emmett’s projection
|
|
14
|
+
* registration utilities.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const userProjection = defineProjection<UserEvent>()
|
|
19
|
+
* .name('user-projection')
|
|
20
|
+
* .eventTypes(['UserCreated', 'UserUpdated'])
|
|
21
|
+
* .contextSchema(z.object({ repo: z.any() }))
|
|
22
|
+
* .handler(async (events, context) => {
|
|
23
|
+
* for (const event of events) {
|
|
24
|
+
* if (event.type === 'UserCreated') {
|
|
25
|
+
* await context.repo.users.create(event.data);
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
declare class ProjectionBuilder<EventType extends AnyEvent = never, Context = never> {
|
|
32
|
+
private _name?;
|
|
33
|
+
private _eventTypes?;
|
|
34
|
+
private _contextSchema?;
|
|
35
|
+
private _handlerFn?;
|
|
36
|
+
/**
|
|
37
|
+
* Creates a deep copy of the builder to ensure immutability
|
|
38
|
+
* @private
|
|
39
|
+
*/
|
|
40
|
+
private clone;
|
|
41
|
+
/**
|
|
42
|
+
* Sets the projection name
|
|
43
|
+
* @param name - Unique identifier for the projection
|
|
44
|
+
* @returns A new ProjectionBuilder instance with the name set
|
|
45
|
+
*/
|
|
46
|
+
name(name: string): ProjectionBuilder<EventType, Context>;
|
|
47
|
+
/**
|
|
48
|
+
* Sets the event types this projection can handle
|
|
49
|
+
* @param types - Array of event type strings
|
|
50
|
+
* @returns A new ProjectionBuilder instance with the event types set
|
|
51
|
+
*/
|
|
52
|
+
eventTypes(types: EventType['type'][]): ProjectionBuilder<EventType, Context>;
|
|
53
|
+
/**
|
|
54
|
+
* Sets the context schema for validation
|
|
55
|
+
* @param schema - Zod schema for validating the context
|
|
56
|
+
* @returns A new ProjectionBuilder instance with the context schema set
|
|
57
|
+
*/
|
|
58
|
+
contextSchema<TNewContext>(schema: z.ZodType<TNewContext>): ProjectionBuilder<EventType, TNewContext>;
|
|
59
|
+
/**
|
|
60
|
+
* Terminal method that creates the projection
|
|
61
|
+
*
|
|
62
|
+
* Validates that all required properties are set and returns an object
|
|
63
|
+
* with three properties:
|
|
64
|
+
* - name: The projection name
|
|
65
|
+
* - canHandle: Array of event types to filter events
|
|
66
|
+
* - handle: Function that validates context and processes events
|
|
67
|
+
*
|
|
68
|
+
* @param fn - Function that processes events and updates read models
|
|
69
|
+
* @returns An object containing the projection configuration
|
|
70
|
+
* @throws Error if name, eventTypes, or contextSchema are not defined
|
|
71
|
+
*/
|
|
72
|
+
handler(fn: (events: EventType[], context: Context) => Promise<void>): {
|
|
73
|
+
name: string;
|
|
74
|
+
canHandle: CanHandle<EventType>;
|
|
75
|
+
handle: (events: EventType[], context: unknown) => Promise<void>;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Factory function to create a new ProjectionBuilder
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```typescript
|
|
83
|
+
* const builder = defineProjection<MyEvent>()
|
|
84
|
+
* .name('my-projection')
|
|
85
|
+
* .eventTypes(['EventTypeA', 'EventTypeB'])
|
|
86
|
+
* .contextSchema(myContextSchema)
|
|
87
|
+
* .handler(async (events, context) => { ... });
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export declare function defineProjection<EventType extends AnyEvent = never>(): ProjectionBuilder<EventType, never>;
|
|
91
|
+
export {};
|
|
92
|
+
//# sourceMappingURL=projection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../../src/builders/projection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C;;;GAGG;AACH,KAAK,SAAS,CAAC,SAAS,SAAS,QAAQ,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,cAAM,iBAAiB,CAAC,SAAS,SAAS,QAAQ,GAAG,KAAK,EAAE,OAAO,GAAG,KAAK;IACzE,OAAO,CAAC,KAAK,CAAC,CAAS;IACvB,OAAO,CAAC,WAAW,CAAC,CAAsB;IAC1C,OAAO,CAAC,cAAc,CAAC,CAAqB;IAC5C,OAAO,CAAC,UAAU,CAAC,CAA2D;IAE9E;;;OAGG;IACH,OAAO,CAAC,KAAK;IASb;;;;OAIG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC;IAOzD;;;;OAIG;IACH,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,iBAAiB,CAAC,SAAS,EAAE,OAAO,CAAC;IAO7E;;;;OAIG;IACH,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,iBAAiB,CAAC,SAAS,EAAE,WAAW,CAAC;IAUrG;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,EAAE,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG;QACrE,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;QAChC,MAAM,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KAClE;CAwBF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,SAAS,QAAQ,GAAG,KAAK,KAAK,iBAAiB,CAAC,SAAS,EAAE,KAAK,CAAC,CAG1G"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { debugBuilder } from '../debug.js';
|
|
2
|
+
/**
|
|
3
|
+
* Fluent builder for read-model projections.
|
|
4
|
+
*
|
|
5
|
+
* Projections consume event streams and populate query-side views. This builder captures
|
|
6
|
+
* the essentials—projection name, handled event types, validated context—and terminates
|
|
7
|
+
* in a `.handler(...)` call that returns the shape required by Emmett’s projection
|
|
8
|
+
* registration utilities.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const userProjection = defineProjection<UserEvent>()
|
|
13
|
+
* .name('user-projection')
|
|
14
|
+
* .eventTypes(['UserCreated', 'UserUpdated'])
|
|
15
|
+
* .contextSchema(z.object({ repo: z.any() }))
|
|
16
|
+
* .handler(async (events, context) => {
|
|
17
|
+
* for (const event of events) {
|
|
18
|
+
* if (event.type === 'UserCreated') {
|
|
19
|
+
* await context.repo.users.create(event.data);
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
class ProjectionBuilder {
|
|
26
|
+
_name;
|
|
27
|
+
_eventTypes;
|
|
28
|
+
_contextSchema;
|
|
29
|
+
_handlerFn;
|
|
30
|
+
/**
|
|
31
|
+
* Creates a deep copy of the builder to ensure immutability
|
|
32
|
+
* @private
|
|
33
|
+
*/
|
|
34
|
+
clone() {
|
|
35
|
+
const builder = new ProjectionBuilder();
|
|
36
|
+
builder._name = this._name;
|
|
37
|
+
builder._eventTypes = this._eventTypes;
|
|
38
|
+
builder._contextSchema = this._contextSchema;
|
|
39
|
+
builder._handlerFn = this._handlerFn;
|
|
40
|
+
return builder;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Sets the projection name
|
|
44
|
+
* @param name - Unique identifier for the projection
|
|
45
|
+
* @returns A new ProjectionBuilder instance with the name set
|
|
46
|
+
*/
|
|
47
|
+
name(name) {
|
|
48
|
+
const builder = this.clone();
|
|
49
|
+
builder._name = name;
|
|
50
|
+
debugBuilder('[projection] Set name: %s', name);
|
|
51
|
+
return builder;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Sets the event types this projection can handle
|
|
55
|
+
* @param types - Array of event type strings
|
|
56
|
+
* @returns A new ProjectionBuilder instance with the event types set
|
|
57
|
+
*/
|
|
58
|
+
eventTypes(types) {
|
|
59
|
+
const builder = this.clone();
|
|
60
|
+
builder._eventTypes = types;
|
|
61
|
+
debugBuilder('[projection:%s] Set event types: %o', this._name ?? 'unnamed', types);
|
|
62
|
+
return builder;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Sets the context schema for validation
|
|
66
|
+
* @param schema - Zod schema for validating the context
|
|
67
|
+
* @returns A new ProjectionBuilder instance with the context schema set
|
|
68
|
+
*/
|
|
69
|
+
contextSchema(schema) {
|
|
70
|
+
const builder = new ProjectionBuilder();
|
|
71
|
+
builder._name = this._name;
|
|
72
|
+
builder._eventTypes = this._eventTypes;
|
|
73
|
+
builder._contextSchema = schema;
|
|
74
|
+
builder._handlerFn = this._handlerFn;
|
|
75
|
+
debugBuilder('[projection:%s] Set context schema', this._name ?? 'unnamed');
|
|
76
|
+
return builder;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Terminal method that creates the projection
|
|
80
|
+
*
|
|
81
|
+
* Validates that all required properties are set and returns an object
|
|
82
|
+
* with three properties:
|
|
83
|
+
* - name: The projection name
|
|
84
|
+
* - canHandle: Array of event types to filter events
|
|
85
|
+
* - handle: Function that validates context and processes events
|
|
86
|
+
*
|
|
87
|
+
* @param fn - Function that processes events and updates read models
|
|
88
|
+
* @returns An object containing the projection configuration
|
|
89
|
+
* @throws Error if name, eventTypes, or contextSchema are not defined
|
|
90
|
+
*/
|
|
91
|
+
handler(fn) {
|
|
92
|
+
if (!this._name || !this._eventTypes || !this._contextSchema) {
|
|
93
|
+
debugBuilder('[projection] ERROR: Missing required properties');
|
|
94
|
+
throw new Error('Projection must have name, eventTypes, and contextSchema defined');
|
|
95
|
+
}
|
|
96
|
+
const name = this._name;
|
|
97
|
+
const eventTypes = this._eventTypes;
|
|
98
|
+
const contextSchema = this._contextSchema;
|
|
99
|
+
debugBuilder('[projection:%s] Building handler for event types: %o', name, eventTypes);
|
|
100
|
+
return {
|
|
101
|
+
name,
|
|
102
|
+
canHandle: eventTypes,
|
|
103
|
+
handle: async (events, context) => {
|
|
104
|
+
debugBuilder('[projection:%s] Validating context', name);
|
|
105
|
+
const validatedContext = contextSchema.parse(context);
|
|
106
|
+
debugBuilder('[projection:%s] Processing %d events', name, events.length);
|
|
107
|
+
await fn(events, validatedContext);
|
|
108
|
+
debugBuilder('[projection:%s] Events processed successfully', name);
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Factory function to create a new ProjectionBuilder
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const builder = defineProjection<MyEvent>()
|
|
119
|
+
* .name('my-projection')
|
|
120
|
+
* .eventTypes(['EventTypeA', 'EventTypeB'])
|
|
121
|
+
* .contextSchema(myContextSchema)
|
|
122
|
+
* .handler(async (events, context) => { ... });
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
export function defineProjection() {
|
|
126
|
+
debugBuilder('[projection] Creating new projection builder');
|
|
127
|
+
return new ProjectionBuilder();
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=projection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projection.js","sourceRoot":"","sources":["../../src/builders/projection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import type { z } from '@arki/contracts';
|
|
2
|
+
import type { Event } from '../event.js';
|
|
3
|
+
/**
|
|
4
|
+
* Type definition for CanHandle predicate
|
|
5
|
+
* Used to filter events that a stateful process manager can handle
|
|
6
|
+
*/
|
|
7
|
+
type CanHandle<EventType extends Event> = EventType['type'][];
|
|
8
|
+
/**
|
|
9
|
+
* StatefulProcessManagerBuilder - Fluent API for building type-safe stateful process managers (sagas)
|
|
10
|
+
*
|
|
11
|
+
* Provides an immutable builder pattern for creating stateful process managers with:
|
|
12
|
+
* - Type safety through TypeScript generics
|
|
13
|
+
* - Runtime validation through Zod schemas
|
|
14
|
+
* - ORPC-style API with .handler() as terminal method
|
|
15
|
+
* - Persistent state management with load/save operations
|
|
16
|
+
*
|
|
17
|
+
* A Stateful Process Manager (Saga) maintains state across events to coordinate complex,
|
|
18
|
+
* long-running business processes by:
|
|
19
|
+
* - name: Unique identifier for the stateful process manager
|
|
20
|
+
* - eventTypes: Array of event types this process manager handles
|
|
21
|
+
* - stateSchema: Schema for validating process manager state
|
|
22
|
+
* - contextSchema: Schema for validating execution context
|
|
23
|
+
* - getStateId: Function to extract state identifier from events
|
|
24
|
+
* - loadState: Function to load existing state from storage
|
|
25
|
+
* - saveState: Function to persist state to storage
|
|
26
|
+
* - handler: Function that processes individual events and returns updated state
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* type OrderState = {
|
|
31
|
+
* orderId: string;
|
|
32
|
+
* status: 'pending' | 'paid' | 'shipped' | 'completed';
|
|
33
|
+
* paymentId?: string;
|
|
34
|
+
* trackingId?: string;
|
|
35
|
+
* };
|
|
36
|
+
*
|
|
37
|
+
* const orderProcessManager = defineStatefulProcessManager<OrderEvent, OrderState>()
|
|
38
|
+
* .name('order-fulfillment')
|
|
39
|
+
* .eventTypes(['OrderPlaced', 'PaymentProcessed', 'OrderShipped'])
|
|
40
|
+
* .stateSchema(z.object({
|
|
41
|
+
* orderId: z.string(),
|
|
42
|
+
* status: z.enum(['pending', 'paid', 'shipped', 'completed']),
|
|
43
|
+
* paymentId: z.string().optional(),
|
|
44
|
+
* trackingId: z.string().optional(),
|
|
45
|
+
* }))
|
|
46
|
+
* .contextSchema(z.object({ messageBus: z.any(), repo: z.any() }))
|
|
47
|
+
* .getStateId(event => `order-${event.data.orderId}`)
|
|
48
|
+
* .loadState(async (stateId, context) => {
|
|
49
|
+
* return await context.repo.orderSagas.findById(stateId);
|
|
50
|
+
* })
|
|
51
|
+
* .saveState(async (stateId, state, context) => {
|
|
52
|
+
* await context.repo.orderSagas.upsert({ id: stateId, ...state });
|
|
53
|
+
* })
|
|
54
|
+
* .handler(async (event, state, context) => {
|
|
55
|
+
* if (event.type === 'OrderPlaced') {
|
|
56
|
+
* // Initialize state for new order
|
|
57
|
+
* return {
|
|
58
|
+
* orderId: event.data.orderId,
|
|
59
|
+
* status: 'pending',
|
|
60
|
+
* };
|
|
61
|
+
* } else if (event.type === 'PaymentProcessed') {
|
|
62
|
+
* // Update state after payment
|
|
63
|
+
* return {
|
|
64
|
+
* ...state!,
|
|
65
|
+
* status: 'paid',
|
|
66
|
+
* paymentId: event.data.paymentId,
|
|
67
|
+
* };
|
|
68
|
+
* } else if (event.type === 'OrderShipped') {
|
|
69
|
+
* // Update state after shipping
|
|
70
|
+
* return {
|
|
71
|
+
* ...state!,
|
|
72
|
+
* status: 'shipped',
|
|
73
|
+
* trackingId: event.data.trackingId,
|
|
74
|
+
* };
|
|
75
|
+
* }
|
|
76
|
+
* return state!;
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare class StatefulProcessManagerBuilder<EventType extends Event = never, State = never, Context = never> {
|
|
81
|
+
private _name?;
|
|
82
|
+
private _eventTypes?;
|
|
83
|
+
private _stateSchema?;
|
|
84
|
+
private _contextSchema?;
|
|
85
|
+
private _getStateIdFn?;
|
|
86
|
+
private _loadStateFn?;
|
|
87
|
+
private _saveStateFn?;
|
|
88
|
+
private _handlerFn?;
|
|
89
|
+
/**
|
|
90
|
+
* Creates a deep copy of the builder to ensure immutability
|
|
91
|
+
* @private
|
|
92
|
+
*/
|
|
93
|
+
private clone;
|
|
94
|
+
/**
|
|
95
|
+
* Sets the stateful process manager name
|
|
96
|
+
* @param name - Unique identifier for the stateful process manager
|
|
97
|
+
* @returns A new StatefulProcessManagerBuilder instance with the name set
|
|
98
|
+
*/
|
|
99
|
+
name(name: string): StatefulProcessManagerBuilder<EventType, State, Context>;
|
|
100
|
+
/**
|
|
101
|
+
* Sets the event types this stateful process manager can handle
|
|
102
|
+
* @param types - Array of event type strings
|
|
103
|
+
* @returns A new StatefulProcessManagerBuilder instance with the event types set
|
|
104
|
+
*/
|
|
105
|
+
eventTypes(types: EventType['type'][]): StatefulProcessManagerBuilder<EventType, State, Context>;
|
|
106
|
+
/**
|
|
107
|
+
* Sets the state schema for validation
|
|
108
|
+
* @param schema - Zod schema for validating the stateful process manager state
|
|
109
|
+
* @returns A new StatefulProcessManagerBuilder instance with the state schema set
|
|
110
|
+
*/
|
|
111
|
+
stateSchema<TNewState>(schema: z.ZodType<TNewState>): StatefulProcessManagerBuilder<EventType, TNewState, Context>;
|
|
112
|
+
/**
|
|
113
|
+
* Sets the context schema for validation
|
|
114
|
+
* @param schema - Zod schema for validating the execution context
|
|
115
|
+
* @returns A new StatefulProcessManagerBuilder instance with the context schema set
|
|
116
|
+
*/
|
|
117
|
+
contextSchema<TNewContext>(schema: z.ZodType<TNewContext>): StatefulProcessManagerBuilder<EventType, State, TNewContext>;
|
|
118
|
+
/**
|
|
119
|
+
* Sets the function to extract state identifier from events
|
|
120
|
+
* @param fn - Function that extracts a unique state identifier from an event
|
|
121
|
+
* @returns A new StatefulProcessManagerBuilder instance with the getStateId function set
|
|
122
|
+
*/
|
|
123
|
+
getStateId(fn: (event: EventType) => string): StatefulProcessManagerBuilder<EventType, State, Context>;
|
|
124
|
+
/**
|
|
125
|
+
* Sets the function to load existing state from storage
|
|
126
|
+
* @param fn - Function that loads state by identifier, returns null if state doesn't exist
|
|
127
|
+
* @returns A new StatefulProcessManagerBuilder instance with the loadState function set
|
|
128
|
+
*/
|
|
129
|
+
loadState(fn: (stateId: string, context: Context) => Promise<State | null>): StatefulProcessManagerBuilder<EventType, State, Context>;
|
|
130
|
+
/**
|
|
131
|
+
* Sets the function to persist state to storage
|
|
132
|
+
* @param fn - Function that saves state by identifier
|
|
133
|
+
* @returns A new StatefulProcessManagerBuilder instance with the saveState function set
|
|
134
|
+
*/
|
|
135
|
+
saveState(fn: (stateId: string, state: State, context: Context) => Promise<void>): StatefulProcessManagerBuilder<EventType, State, Context>;
|
|
136
|
+
/**
|
|
137
|
+
* Terminal method that creates the stateful process manager
|
|
138
|
+
*
|
|
139
|
+
* Validates that all required configuration is set and returns an object
|
|
140
|
+
* with three properties:
|
|
141
|
+
* - processorId: The stateful process manager identifier
|
|
142
|
+
* - canHandle: Array of event types to filter events
|
|
143
|
+
* - eachBatch: Function that validates context, loads state for each event,
|
|
144
|
+
* processes it through the handler, and saves the updated state
|
|
145
|
+
*
|
|
146
|
+
* @param fn - Function that processes individual events with their state and returns updated state
|
|
147
|
+
* @returns An object containing the stateful process manager configuration
|
|
148
|
+
* @throws Error if name, eventTypes, stateSchema, contextSchema, getStateId, loadState, or saveState are not defined
|
|
149
|
+
*/
|
|
150
|
+
handler(fn: (event: EventType, state: State | null, context: Context) => Promise<State>): {
|
|
151
|
+
processorId: string;
|
|
152
|
+
canHandle: CanHandle<EventType>;
|
|
153
|
+
eachBatch: (events: EventType[], context: unknown) => Promise<void>;
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Factory function to create a new StatefulProcessManagerBuilder
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```typescript
|
|
161
|
+
* const builder = defineStatefulProcessManager<MyEvent, MyState>()
|
|
162
|
+
* .name('my-stateful-process-manager')
|
|
163
|
+
* .eventTypes(['EventTypeA', 'EventTypeB'])
|
|
164
|
+
* .stateSchema(myStateSchema)
|
|
165
|
+
* .contextSchema(myContextSchema)
|
|
166
|
+
* .getStateId(event => `state-${event.data.id}`)
|
|
167
|
+
* .loadState(async (stateId, context) => {
|
|
168
|
+
* return await context.repo.findById(stateId);
|
|
169
|
+
* })
|
|
170
|
+
* .saveState(async (stateId, state, context) => {
|
|
171
|
+
* await context.repo.upsert({ id: stateId, ...state });
|
|
172
|
+
* })
|
|
173
|
+
* .handler(async (event, state, context) => {
|
|
174
|
+
* // Process event and return updated state
|
|
175
|
+
* return { ...state, updated: true };
|
|
176
|
+
* });
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
export declare function defineStatefulProcessManager<EventType extends Event = never, State = never>(): StatefulProcessManagerBuilder<EventType, State, never>;
|
|
180
|
+
export {};
|
|
181
|
+
//# sourceMappingURL=stateful-process-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stateful-process-manager.d.ts","sourceRoot":"","sources":["../../src/builders/stateful-process-manager.ts"],"names":[],"mappings":"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"}
|