@rotorsoft/act 0.13.0 → 0.15.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/README.md +2 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/act-builder.d.ts +60 -20
- package/dist/@types/act-builder.d.ts.map +1 -1
- package/dist/@types/act.d.ts +24 -22
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/event-sourcing.d.ts +12 -12
- package/dist/@types/event-sourcing.d.ts.map +1 -1
- package/dist/@types/merge.d.ts +1 -1
- package/dist/@types/merge.d.ts.map +1 -1
- package/dist/@types/projection-builder.d.ts +22 -22
- package/dist/@types/projection-builder.d.ts.map +1 -1
- package/dist/@types/slice-builder.d.ts +31 -27
- package/dist/@types/slice-builder.d.ts.map +1 -1
- package/dist/@types/state-builder.d.ts +94 -77
- package/dist/@types/state-builder.d.ts.map +1 -1
- package/dist/@types/types/action.d.ts +75 -66
- package/dist/@types/types/action.d.ts.map +1 -1
- package/dist/@types/types/errors.d.ts +15 -14
- package/dist/@types/types/errors.d.ts.map +1 -1
- package/dist/@types/types/reaction.d.ts +25 -22
- package/dist/@types/types/reaction.d.ts.map +1 -1
- package/dist/@types/types/registry.d.ts +15 -15
- package/dist/@types/types/registry.d.ts.map +1 -1
- package/dist/@types/types/schemas.d.ts +7 -7
- package/dist/@types/types/schemas.d.ts.map +1 -1
- package/dist/index.cjs +58 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +58 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
import type { Projection } from "./projection-builder.js";
|
|
2
|
-
import type { Committed, Dispatcher, EventRegister, ReactionOptions, ReactionResolver, Schema, SchemaRegister, Schemas, Snapshot, State } from "./types/index.js";
|
|
2
|
+
import type { Actor, Committed, Dispatcher, EventRegister, ReactionOptions, ReactionResolver, Schema, SchemaRegister, Schemas, Snapshot, State } from "./types/index.js";
|
|
3
3
|
/**
|
|
4
4
|
* A self-contained functional slice grouping partial states with their
|
|
5
5
|
* scoped reactions. Slices are composed into an Act orchestrator via
|
|
6
6
|
* `act().withSlice(slice)`.
|
|
7
7
|
*
|
|
8
|
-
* @template
|
|
9
|
-
* @template
|
|
10
|
-
* @template
|
|
11
|
-
* @template
|
|
8
|
+
* @template TSchemaReg - Schema register for states
|
|
9
|
+
* @template TEvents - Event schemas from this slice's states
|
|
10
|
+
* @template TActions - Action schemas from this slice's states
|
|
11
|
+
* @template TStateMap - Map of state names to state schemas
|
|
12
|
+
* @template TActor - Actor type extending base Actor
|
|
12
13
|
*/
|
|
13
|
-
export type Slice<
|
|
14
|
+
export type Slice<TSchemaReg extends SchemaRegister<TActions>, TEvents extends Schemas, TActions extends Schemas, TStateMap extends Record<string, Schema> = {}, TActor extends Actor = Actor> = {
|
|
14
15
|
readonly _tag: "Slice";
|
|
15
16
|
readonly states: Map<string, State<any, any, any>>;
|
|
16
|
-
readonly events: EventRegister<
|
|
17
|
+
readonly events: EventRegister<TEvents>;
|
|
17
18
|
readonly projections: ReadonlyArray<Projection<any>>;
|
|
18
19
|
/** @internal phantom field for type-level state schema tracking */
|
|
19
|
-
readonly _S?:
|
|
20
|
+
readonly _S?: TSchemaReg;
|
|
20
21
|
/** @internal phantom field for type-level state name tracking */
|
|
21
|
-
readonly _M?:
|
|
22
|
+
readonly _M?: TStateMap;
|
|
23
|
+
/** @internal phantom field for type-level actor tracking */
|
|
24
|
+
readonly _TActor?: TActor;
|
|
22
25
|
};
|
|
23
26
|
/**
|
|
24
27
|
* Fluent builder interface for composing functional slices.
|
|
@@ -26,12 +29,13 @@ export type Slice<S extends SchemaRegister<A>, E extends Schemas, A extends Sche
|
|
|
26
29
|
* Provides a chainable API for registering states and projections,
|
|
27
30
|
* and defining reactions scoped to the slice's own events.
|
|
28
31
|
*
|
|
29
|
-
* @template
|
|
30
|
-
* @template
|
|
31
|
-
* @template
|
|
32
|
-
* @template
|
|
32
|
+
* @template TSchemaReg - Schema register for states
|
|
33
|
+
* @template TEvents - Event schemas
|
|
34
|
+
* @template TActions - Action schemas
|
|
35
|
+
* @template TStateMap - Map of state names to state schemas
|
|
36
|
+
* @template TActor - Actor type extending base Actor
|
|
33
37
|
*/
|
|
34
|
-
export type SliceBuilder<
|
|
38
|
+
export type SliceBuilder<TSchemaReg extends SchemaRegister<TActions>, TEvents extends Schemas, TActions extends Schemas, TStateMap extends Record<string, Schema> = {}, TActor extends Actor = Actor> = {
|
|
35
39
|
/**
|
|
36
40
|
* Registers a state definition with the slice.
|
|
37
41
|
*
|
|
@@ -39,35 +43,35 @@ export type SliceBuilder<S extends SchemaRegister<A>, E extends Schemas, A exten
|
|
|
39
43
|
* dispatch. Duplicate registrations (same state in multiple slices)
|
|
40
44
|
* are handled automatically at composition time.
|
|
41
45
|
*/
|
|
42
|
-
withState: <
|
|
43
|
-
[K in keyof
|
|
44
|
-
},
|
|
45
|
-
[K in
|
|
46
|
-
}>;
|
|
46
|
+
withState: <TNewState extends Schema, TNewEvents extends Schemas, TNewActions extends Schemas, TNewName extends string = string>(state: State<TNewState, TNewEvents, TNewActions, TNewName>) => SliceBuilder<TSchemaReg & {
|
|
47
|
+
[K in keyof TNewActions]: TNewState;
|
|
48
|
+
}, TEvents & TNewEvents, TActions & TNewActions, TStateMap & {
|
|
49
|
+
[K in TNewName]: TNewState;
|
|
50
|
+
}, TActor>;
|
|
47
51
|
/**
|
|
48
52
|
* Embeds a built Projection within this slice. The projection's events
|
|
49
53
|
* must be a subset of events from states already registered via
|
|
50
54
|
* `.withState()`. Projection handlers preserve their `(event, stream)`
|
|
51
55
|
* signature and do not receive a Dispatcher.
|
|
52
56
|
*/
|
|
53
|
-
withProjection: <
|
|
57
|
+
withProjection: <TNewEvents extends Schemas>(projection: [Exclude<keyof TNewEvents, keyof TEvents>] extends [never] ? Projection<TNewEvents> : never) => SliceBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor>;
|
|
54
58
|
/**
|
|
55
59
|
* Begins defining a reaction scoped to this slice's events.
|
|
56
60
|
*/
|
|
57
|
-
on: <
|
|
58
|
-
do: (handler: (event: Committed<
|
|
59
|
-
to: (resolver: ReactionResolver<
|
|
60
|
-
void: () => SliceBuilder<
|
|
61
|
+
on: <TKey extends keyof TEvents>(event: TKey) => {
|
|
62
|
+
do: (handler: (event: Committed<TEvents, TKey>, stream: string, app: Dispatcher<TActions, TActor>) => Promise<Snapshot<Schema, TEvents> | void>, options?: Partial<ReactionOptions>) => SliceBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor> & {
|
|
63
|
+
to: (resolver: ReactionResolver<TEvents, TKey> | string) => SliceBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor>;
|
|
64
|
+
void: () => SliceBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor>;
|
|
61
65
|
};
|
|
62
66
|
};
|
|
63
67
|
/**
|
|
64
68
|
* Builds and returns the Slice data structure.
|
|
65
69
|
*/
|
|
66
|
-
build: () => Slice<
|
|
70
|
+
build: () => Slice<TSchemaReg, TEvents, TActions, TStateMap, TActor>;
|
|
67
71
|
/**
|
|
68
72
|
* The registered event schemas and their reaction maps.
|
|
69
73
|
*/
|
|
70
|
-
readonly events: EventRegister<
|
|
74
|
+
readonly events: EventRegister<TEvents>;
|
|
71
75
|
};
|
|
72
76
|
/**
|
|
73
77
|
* Creates a new slice builder for composing partial states with scoped reactions.
|
|
@@ -102,5 +106,5 @@ export type SliceBuilder<S extends SchemaRegister<A>, E extends Schemas, A exten
|
|
|
102
106
|
* @see {@link SliceBuilder} for builder methods
|
|
103
107
|
* @see {@link Slice} for the output type
|
|
104
108
|
*/
|
|
105
|
-
export declare function slice<
|
|
109
|
+
export declare function slice<TSchemaReg extends SchemaRegister<TActions> = {}, TEvents extends Schemas = {}, TActions extends Schemas = {}, TStateMap extends Record<string, Schema> = {}, TActor extends Actor = Actor>(states?: Map<string, State<any, any, any>>, actions?: Record<string, any>, events?: EventRegister<TEvents>, projections?: Projection<any>[]): SliceBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor>;
|
|
106
110
|
//# sourceMappingURL=slice-builder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slice-builder.d.ts","sourceRoot":"","sources":["../../src/slice-builder.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EACV,aAAa,EAGb,eAAe,EACf,gBAAgB,EAChB,MAAM,EACN,cAAc,EACd,OAAO,EACP,QAAQ,EACR,KAAK,EACN,MAAM,kBAAkB,CAAC;AAE1B
|
|
1
|
+
{"version":3,"file":"slice-builder.d.ts","sourceRoot":"","sources":["../../src/slice-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,12 +12,13 @@ import { ActionHandler, Invariant, PatchHandlers, Schema, Schemas, Snapshot, Sta
|
|
|
12
12
|
* Provides a fluent API to configure the initial state, event types,
|
|
13
13
|
* and event handlers (reducers) before moving to action configuration.
|
|
14
14
|
*
|
|
15
|
-
* @template
|
|
15
|
+
* @template TState - State schema type
|
|
16
|
+
* @template TName - State name literal type
|
|
16
17
|
*
|
|
17
18
|
* @see {@link state} for usage examples
|
|
18
19
|
* @see {@link ActionBuilder} for action configuration
|
|
19
20
|
*/
|
|
20
|
-
export type StateBuilder<
|
|
21
|
+
export type StateBuilder<TState extends Schema, TName extends string = string> = {
|
|
21
22
|
/**
|
|
22
23
|
* Defines the initial state for new state instances.
|
|
23
24
|
*
|
|
@@ -37,16 +38,16 @@ export type StateBuilder<S extends Schema, N extends string = string> = {
|
|
|
37
38
|
* .init((data) => ({ ...data, createdAt: new Date() }))
|
|
38
39
|
* ```
|
|
39
40
|
*/
|
|
40
|
-
init: (init: () => Readonly<
|
|
41
|
+
init: (init: () => Readonly<TState>) => {
|
|
41
42
|
/**
|
|
42
43
|
* Declares the event types that this state can emit.
|
|
43
44
|
*
|
|
44
45
|
* Events represent facts that have happened - they should be named in past tense.
|
|
45
46
|
* Each event is defined with a Zod schema for type safety and runtime validation.
|
|
46
47
|
*
|
|
47
|
-
* @template
|
|
48
|
+
* @template TEvents - Event schemas type
|
|
48
49
|
* @param events - Object mapping event names to Zod schemas
|
|
49
|
-
* @returns
|
|
50
|
+
* @returns An ActionBuilder (with optional `.patch()` to override specific reducers)
|
|
50
51
|
*
|
|
51
52
|
* @example
|
|
52
53
|
* ```typescript
|
|
@@ -57,37 +58,38 @@ export type StateBuilder<S extends Schema, N extends string = string> = {
|
|
|
57
58
|
* })
|
|
58
59
|
* ```
|
|
59
60
|
*/
|
|
60
|
-
emits: <
|
|
61
|
+
emits: <TEvents extends Schemas>(events: ZodTypes<TEvents>) => ActionBuilder<TState, TEvents, {}, TName> & {
|
|
61
62
|
/**
|
|
62
|
-
*
|
|
63
|
+
* Overrides specific event reducers. Events without a custom patch
|
|
64
|
+
* default to passthrough: `({ data }) => data` (event data merges
|
|
65
|
+
* into state).
|
|
63
66
|
*
|
|
64
|
-
*
|
|
65
|
-
* and return the changes to apply. Return partial state objects; unchanged fields
|
|
66
|
-
* are preserved automatically.
|
|
67
|
-
*
|
|
68
|
-
* @param patch - Object mapping event names to patch handler functions
|
|
67
|
+
* @param patch - Partial map of event names to patch handler functions
|
|
69
68
|
* @returns An ActionBuilder for defining actions
|
|
70
69
|
*
|
|
71
|
-
* @example
|
|
70
|
+
* @example Only override the events that need custom logic
|
|
72
71
|
* ```typescript
|
|
72
|
+
* .emits({ TicketOpened, TicketClosed, TicketResolved })
|
|
73
73
|
* .patch({
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
74
|
+
* TicketOpened: ({ data }) => {
|
|
75
|
+
* const { message, messageId, userId, ...other } = data;
|
|
76
|
+
* return { ...other, userId, messages: { [messageId]: { ... } } };
|
|
77
|
+
* },
|
|
77
78
|
* })
|
|
79
|
+
* // TicketClosed and TicketResolved use passthrough
|
|
78
80
|
* ```
|
|
79
81
|
*/
|
|
80
|
-
patch: (patch: PatchHandlers<
|
|
82
|
+
patch: (patch: Partial<PatchHandlers<TState, TEvents>>) => ActionBuilder<TState, TEvents, {}, TName>;
|
|
81
83
|
};
|
|
82
84
|
};
|
|
83
85
|
};
|
|
84
86
|
/** Helper: a single-key record mapping a state name to its Zod schema. */
|
|
85
|
-
type StateEntry<
|
|
86
|
-
[P in
|
|
87
|
+
type StateEntry<TKey extends string = string, TState extends Schema = Schema> = {
|
|
88
|
+
[P in TKey]: ZodType<TState>;
|
|
87
89
|
};
|
|
88
90
|
/** Helper: a single-key record mapping an action name to its Zod schema. */
|
|
89
|
-
type ActionEntry<
|
|
90
|
-
[P in
|
|
91
|
+
type ActionEntry<TKey extends string = string, TNewActions extends Schema = Schema> = {
|
|
92
|
+
[P in TKey]: ZodType<TNewActions>;
|
|
91
93
|
};
|
|
92
94
|
/**
|
|
93
95
|
* Builder interface for defining actions (commands) on a state.
|
|
@@ -95,13 +97,14 @@ type ActionEntry<K extends string = string, AX extends Schema = Schema> = {
|
|
|
95
97
|
* Actions represent user/system intents to modify state. Each action is validated
|
|
96
98
|
* against a schema, can have business rule invariants, and must emit one or more events.
|
|
97
99
|
*
|
|
98
|
-
* @template
|
|
99
|
-
* @template
|
|
100
|
-
* @template
|
|
100
|
+
* @template TState - State schema type
|
|
101
|
+
* @template TEvents - Event schemas type
|
|
102
|
+
* @template TActions - Action schemas type
|
|
103
|
+
* @template TName - State name literal type
|
|
101
104
|
*
|
|
102
105
|
* @see {@link state} for complete usage examples
|
|
103
106
|
*/
|
|
104
|
-
export type ActionBuilder<
|
|
107
|
+
export type ActionBuilder<TState extends Schema, TEvents extends Schemas, TActions extends Schemas, TName extends string = string> = {
|
|
105
108
|
/**
|
|
106
109
|
* Defines an action (command) that can be executed on this state.
|
|
107
110
|
*
|
|
@@ -113,8 +116,8 @@ export type ActionBuilder<S extends Schema, E extends Schemas, A extends Schemas
|
|
|
113
116
|
* when the variable name matches the action name. The key becomes the
|
|
114
117
|
* action name, the value the Zod schema.
|
|
115
118
|
*
|
|
116
|
-
* @template
|
|
117
|
-
* @template
|
|
119
|
+
* @template TKey - Action name (string literal type)
|
|
120
|
+
* @template TNewActions - Action payload schema type
|
|
118
121
|
* @param entry - Single-key record `{ ActionName: schema }`
|
|
119
122
|
* @returns An object with `.given()` and `.emit()` for further configuration
|
|
120
123
|
*
|
|
@@ -141,7 +144,7 @@ export type ActionBuilder<S extends Schema, E extends Schemas, A extends Schemas
|
|
|
141
144
|
* .emit((action) => ["TicketOpened", { title: action.title }])
|
|
142
145
|
* ```
|
|
143
146
|
*/
|
|
144
|
-
on: <
|
|
147
|
+
on: <TKey extends string, TNewActions extends Schema>(entry: ActionEntry<TKey, TNewActions>) => {
|
|
145
148
|
/**
|
|
146
149
|
* Adds business rule invariants that must hold before the action can execute.
|
|
147
150
|
*
|
|
@@ -160,7 +163,7 @@ export type ActionBuilder<S extends Schema, E extends Schemas, A extends Schemas
|
|
|
160
163
|
* ])
|
|
161
164
|
* ```
|
|
162
165
|
*/
|
|
163
|
-
given: (rules: Invariant<
|
|
166
|
+
given: (rules: Invariant<TState>[]) => {
|
|
164
167
|
/**
|
|
165
168
|
* Defines the action handler that emits events.
|
|
166
169
|
*
|
|
@@ -168,22 +171,30 @@ export type ActionBuilder<S extends Schema, E extends Schemas, A extends Schemas
|
|
|
168
171
|
* and must return one or more events to emit. Events are applied to state
|
|
169
172
|
* via the patch handlers defined earlier.
|
|
170
173
|
*
|
|
171
|
-
*
|
|
174
|
+
* Pass a string event name for passthrough: the action payload becomes
|
|
175
|
+
* the event data directly.
|
|
176
|
+
*
|
|
177
|
+
* @param handler - Function that returns events to emit, or event name string for passthrough
|
|
172
178
|
* @returns The ActionBuilder for chaining more actions
|
|
173
179
|
*
|
|
174
|
-
* @example
|
|
180
|
+
* @example Custom handler
|
|
175
181
|
* ```typescript
|
|
176
182
|
* .emit((action, snapshot) => {
|
|
177
183
|
* const newBalance = snapshot.state.balance + action.amount;
|
|
178
184
|
* return ["Deposited", { amount: action.amount, newBalance }];
|
|
179
185
|
* })
|
|
180
186
|
* ```
|
|
187
|
+
*
|
|
188
|
+
* @example Passthrough (action payload = event data)
|
|
189
|
+
* ```typescript
|
|
190
|
+
* .emit("TicketAssigned")
|
|
191
|
+
* ```
|
|
181
192
|
*/
|
|
182
|
-
emit: (handler: ActionHandler<
|
|
183
|
-
[P in
|
|
184
|
-
},
|
|
185
|
-
[P in
|
|
186
|
-
},
|
|
193
|
+
emit: (handler: ActionHandler<TState, TEvents, {
|
|
194
|
+
[P in TKey]: TNewActions;
|
|
195
|
+
}, TKey> | (keyof TEvents & string)) => ActionBuilder<TState, TEvents, TActions & {
|
|
196
|
+
[P in TKey]: TNewActions;
|
|
197
|
+
}, TName>;
|
|
187
198
|
};
|
|
188
199
|
/**
|
|
189
200
|
* Defines the action handler that emits events.
|
|
@@ -192,9 +203,17 @@ export type ActionBuilder<S extends Schema, E extends Schemas, A extends Schemas
|
|
|
192
203
|
* and must return one or more events to emit. Return a single event as
|
|
193
204
|
* `["EventName", data]` or multiple events as an array of event tuples.
|
|
194
205
|
*
|
|
195
|
-
*
|
|
206
|
+
* Pass a string event name for passthrough: the action payload becomes
|
|
207
|
+
* the event data directly.
|
|
208
|
+
*
|
|
209
|
+
* @param handler - Function that returns events to emit, or event name string for passthrough
|
|
196
210
|
* @returns The ActionBuilder for chaining more actions
|
|
197
211
|
*
|
|
212
|
+
* @example Passthrough (action payload = event data)
|
|
213
|
+
* ```typescript
|
|
214
|
+
* .emit("Incremented")
|
|
215
|
+
* ```
|
|
216
|
+
*
|
|
198
217
|
* @example Single event
|
|
199
218
|
* ```typescript
|
|
200
219
|
* .emit((action) => ["Incremented", { amount: action.by }])
|
|
@@ -207,25 +226,12 @@ export type ActionBuilder<S extends Schema, E extends Schemas, A extends Schemas
|
|
|
207
226
|
* ["LogUpdated", { message: `Incremented by ${action.by}` }]
|
|
208
227
|
* ])
|
|
209
228
|
* ```
|
|
210
|
-
*
|
|
211
|
-
* @example Conditional events
|
|
212
|
-
* ```typescript
|
|
213
|
-
* .emit((action, snapshot) => {
|
|
214
|
-
* if (snapshot.state.count + action.by >= 100) {
|
|
215
|
-
* return [
|
|
216
|
-
* ["Incremented", { amount: action.by }],
|
|
217
|
-
* ["MilestoneReached", { milestone: 100 }]
|
|
218
|
-
* ];
|
|
219
|
-
* }
|
|
220
|
-
* return ["Incremented", { amount: action.by }];
|
|
221
|
-
* })
|
|
222
|
-
* ```
|
|
223
229
|
*/
|
|
224
|
-
emit: (handler: ActionHandler<
|
|
225
|
-
[P in
|
|
226
|
-
},
|
|
227
|
-
[P in
|
|
228
|
-
},
|
|
230
|
+
emit: (handler: ActionHandler<TState, TEvents, {
|
|
231
|
+
[P in TKey]: TNewActions;
|
|
232
|
+
}, TKey> | (keyof TEvents & string)) => ActionBuilder<TState, TEvents, TActions & {
|
|
233
|
+
[P in TKey]: TNewActions;
|
|
234
|
+
}, TName>;
|
|
229
235
|
};
|
|
230
236
|
/**
|
|
231
237
|
* Defines a snapshotting strategy to optimize state reconstruction.
|
|
@@ -258,7 +264,7 @@ export type ActionBuilder<S extends Schema, E extends Schemas, A extends Schemas
|
|
|
258
264
|
* })
|
|
259
265
|
* ```
|
|
260
266
|
*/
|
|
261
|
-
snap: (snap: (snapshot: Snapshot<
|
|
267
|
+
snap: (snap: (snapshot: Snapshot<TState, TEvents>) => boolean) => ActionBuilder<TState, TEvents, TActions, TName>;
|
|
262
268
|
/**
|
|
263
269
|
* Finalizes and builds the state definition.
|
|
264
270
|
*
|
|
@@ -272,13 +278,13 @@ export type ActionBuilder<S extends Schema, E extends Schemas, A extends Schemas
|
|
|
272
278
|
* const Counter = state({ Counter: schema })
|
|
273
279
|
* .init(() => ({ count: 0 }))
|
|
274
280
|
* .emits({ Incremented: z.object({ amount: z.number() }) })
|
|
275
|
-
* .patch({ Incremented: (
|
|
281
|
+
* .patch({ Incremented: ({ data }, state) => ({ count: state.count + data.amount }) })
|
|
276
282
|
* .on({ increment: z.object({ by: z.number() }) })
|
|
277
283
|
* .emit((action) => ["Incremented", { amount: action.by }])
|
|
278
|
-
* .build(); // Returns State<
|
|
284
|
+
* .build(); // Returns State<TState, TEvents, TActions, TName>
|
|
279
285
|
* ```
|
|
280
286
|
*/
|
|
281
|
-
build: () => State<
|
|
287
|
+
build: () => State<TState, TEvents, TActions, TName>;
|
|
282
288
|
};
|
|
283
289
|
/**
|
|
284
290
|
* Creates a new state definition with event sourcing capabilities.
|
|
@@ -290,17 +296,17 @@ export type ActionBuilder<S extends Schema, E extends Schemas, A extends Schemas
|
|
|
290
296
|
*
|
|
291
297
|
* The state builder provides a fluent API for defining:
|
|
292
298
|
* 1. Initial state via `.init()`
|
|
293
|
-
* 2. Event types via `.emits()`
|
|
294
|
-
* 3.
|
|
295
|
-
* 4. Actions (commands) via `.on()` → `.emit()`
|
|
299
|
+
* 2. Event types via `.emits()` — all events default to passthrough (`({ data }) => data`)
|
|
300
|
+
* 3. Custom event reducers via `.patch()` (optional — only for events that need custom logic)
|
|
301
|
+
* 4. Actions (commands) via `.on()` → `.emit()` — pass an event name string for passthrough
|
|
296
302
|
* 5. Business rules (invariants) via `.given()`
|
|
297
303
|
* 6. Snapshotting strategy via `.snap()`
|
|
298
304
|
*
|
|
299
|
-
* @template
|
|
305
|
+
* @template TState - Zod schema type defining the shape of the state
|
|
300
306
|
* @param entry - Single-key record mapping state name to Zod schema (e.g., `{ Counter: z.object({ count: z.number() }) }`)
|
|
301
307
|
* @returns A StateBuilder instance for fluent API configuration
|
|
302
308
|
*
|
|
303
|
-
* @example Basic counter state
|
|
309
|
+
* @example Basic counter state (with custom patch)
|
|
304
310
|
* ```typescript
|
|
305
311
|
* import { state } from "@rotorsoft/act";
|
|
306
312
|
* import { z } from "zod";
|
|
@@ -310,14 +316,25 @@ export type ActionBuilder<S extends Schema, E extends Schemas, A extends Schemas
|
|
|
310
316
|
* .emits({
|
|
311
317
|
* Incremented: z.object({ amount: z.number() })
|
|
312
318
|
* })
|
|
313
|
-
* .patch({
|
|
314
|
-
* Incremented: (
|
|
319
|
+
* .patch({ // optional — only for events needing custom reducers
|
|
320
|
+
* Incremented: ({ data }, state) => ({ count: state.count + data.amount })
|
|
315
321
|
* })
|
|
316
322
|
* .on({ increment: z.object({ by: z.number() }) })
|
|
317
323
|
* .emit((action) => ["Incremented", { amount: action.by }])
|
|
318
324
|
* .build();
|
|
319
325
|
* ```
|
|
320
326
|
*
|
|
327
|
+
* @example Passthrough state (no custom patch or emit needed)
|
|
328
|
+
* ```typescript
|
|
329
|
+
* const DigitBoard = state({ DigitBoard: z.object({ digit: z.string() }) })
|
|
330
|
+
* .init(() => ({ digit: "" }))
|
|
331
|
+
* .emits({ DigitCounted: z.object({ digit: z.string() }) })
|
|
332
|
+
* // no .patch() — passthrough is the default (event data merges into state)
|
|
333
|
+
* .on({ CountDigit: z.object({ digit: z.string() }) })
|
|
334
|
+
* .emit("DigitCounted") // string passthrough — action payload becomes event data
|
|
335
|
+
* .build();
|
|
336
|
+
* ```
|
|
337
|
+
*
|
|
321
338
|
* @example State with multiple events and invariants
|
|
322
339
|
* ```typescript
|
|
323
340
|
* const BankAccount = state({ BankAccount: z.object({
|
|
@@ -331,29 +348,29 @@ export type ActionBuilder<S extends Schema, E extends Schemas, A extends Schemas
|
|
|
331
348
|
* Withdrawn: z.object({ amount: z.number() }),
|
|
332
349
|
* Closed: z.object({})
|
|
333
350
|
* })
|
|
334
|
-
* .patch({
|
|
335
|
-
* Deposited: (
|
|
336
|
-
* Withdrawn: (
|
|
351
|
+
* .patch({ // only override events needing custom logic
|
|
352
|
+
* Deposited: ({ data }, state) => ({ balance: state.balance + data.amount }),
|
|
353
|
+
* Withdrawn: ({ data }, state) => ({ balance: state.balance - data.amount }),
|
|
337
354
|
* Closed: () => ({ status: "closed", balance: 0 })
|
|
338
355
|
* })
|
|
339
356
|
* .on({ deposit: z.object({ amount: z.number() }) })
|
|
340
357
|
* .given([
|
|
341
358
|
* (_, snap) => snap.state.status === "open" || "Account must be open"
|
|
342
359
|
* ])
|
|
343
|
-
* .emit(
|
|
360
|
+
* .emit("Deposited") // passthrough — action payload { amount } becomes event data
|
|
344
361
|
* .on({ withdraw: z.object({ amount: z.number() }) })
|
|
345
362
|
* .given([
|
|
346
363
|
* (_, snap) => snap.state.status === "open" || "Account must be open",
|
|
347
364
|
* (_, snap, action) =>
|
|
348
365
|
* snap.state.balance >= action.amount || "Insufficient funds"
|
|
349
366
|
* ])
|
|
350
|
-
* .emit(
|
|
367
|
+
* .emit("Withdrawn")
|
|
351
368
|
* .on({ close: z.object({}) })
|
|
352
369
|
* .given([
|
|
353
370
|
* (_, snap) => snap.state.status === "open" || "Already closed",
|
|
354
371
|
* (_, snap) => snap.state.balance === 0 || "Balance must be zero"
|
|
355
372
|
* ])
|
|
356
|
-
* .emit(
|
|
373
|
+
* .emit("Closed")
|
|
357
374
|
* .build();
|
|
358
375
|
* ```
|
|
359
376
|
*
|
|
@@ -369,14 +386,14 @@ export type ActionBuilder<S extends Schema, E extends Schemas, A extends Schemas
|
|
|
369
386
|
* UserCreated: z.object({ name: z.string(), email: z.string() }),
|
|
370
387
|
* UserLoggedIn: z.object({})
|
|
371
388
|
* })
|
|
372
|
-
* .patch({
|
|
373
|
-
* UserCreated: (event) => event.data,
|
|
389
|
+
* .patch({ // only override events needing custom logic
|
|
374
390
|
* UserLoggedIn: (_, state) => ({ loginCount: state.loginCount + 1 })
|
|
375
391
|
* })
|
|
392
|
+
* // UserCreated uses passthrough — event data merges into state
|
|
376
393
|
* .on({ createUser: z.object({ name: z.string(), email: z.string() }) })
|
|
377
|
-
* .emit(
|
|
394
|
+
* .emit("UserCreated") // passthrough
|
|
378
395
|
* .on({ login: z.object({}) })
|
|
379
|
-
* .emit(
|
|
396
|
+
* .emit("UserLoggedIn")
|
|
380
397
|
* .snap((snap) => snap.patches >= 10) // Snapshot every 10 events
|
|
381
398
|
* .build();
|
|
382
399
|
* ```
|
|
@@ -386,6 +403,6 @@ export type ActionBuilder<S extends Schema, E extends Schemas, A extends Schemas
|
|
|
386
403
|
* @see {@link https://rotorsoft.github.io/act-root/docs/intro | Getting Started Guide}
|
|
387
404
|
* @see {@link https://rotorsoft.github.io/act-root/docs/examples/calculator | Calculator Example}
|
|
388
405
|
*/
|
|
389
|
-
export declare function state<
|
|
406
|
+
export declare function state<TName extends string, TState extends Schema>(entry: StateEntry<TName, TState>): StateBuilder<TState, TName>;
|
|
390
407
|
export {};
|
|
391
408
|
//# sourceMappingURL=state-builder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-builder.d.ts","sourceRoot":"","sources":["../../src/state-builder.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAC9B,OAAO,EACL,aAAa,EAGb,SAAS,EACT,aAAa,EACb,MAAM,EACN,OAAO,EACP,QAAQ,EACR,KAAK,EACL,QAAQ,EACT,MAAM,kBAAkB,CAAC;AAE1B
|
|
1
|
+
{"version":3,"file":"state-builder.d.ts","sourceRoot":"","sources":["../../src/state-builder.ts"],"names":[],"mappings":"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"}
|