effect-machine 0.11.0 → 0.13.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 +128 -324
- package/dist/actor.d.ts +52 -31
- package/dist/actor.js +218 -283
- package/dist/cluster/adapters/in-memory.d.ts +28 -0
- package/dist/cluster/adapters/in-memory.js +79 -0
- package/dist/cluster/entity-actor-ref.d.ts +56 -0
- package/dist/cluster/entity-actor-ref.js +33 -0
- package/dist/cluster/entity-machine.d.ts +31 -49
- package/dist/cluster/entity-machine.js +178 -52
- package/dist/cluster/index.d.ts +5 -2
- package/dist/cluster/index.js +4 -1
- package/dist/cluster/persistence.d.ts +49 -0
- package/dist/cluster/persistence.js +18 -0
- package/dist/cluster/to-entity.d.ts +9 -3
- package/dist/cluster/to-entity.js +16 -4
- package/dist/errors.d.ts +25 -17
- package/dist/errors.js +10 -5
- package/dist/index.d.ts +6 -4
- package/dist/index.js +4 -3
- package/dist/internal/brands.d.ts +14 -1
- package/dist/internal/runtime.d.ts +142 -0
- package/dist/internal/runtime.js +357 -0
- package/dist/internal/transition.d.ts +10 -4
- package/dist/internal/transition.js +24 -12
- package/dist/internal/utils.d.ts +42 -6
- package/dist/internal/utils.js +27 -1
- package/dist/machine.d.ts +89 -55
- package/dist/machine.js +80 -68
- package/dist/schema.d.ts +35 -34
- package/dist/schema.js +33 -4
- package/dist/supervision.d.ts +97 -0
- package/dist/supervision.js +42 -0
- package/dist/testing.d.ts +17 -8
- package/dist/testing.js +22 -23
- package/package.json +7 -7
- package/v3/dist/actor.d.ts +54 -37
- package/v3/dist/actor.js +209 -277
- package/v3/dist/cluster/adapters/in-memory.d.ts +15 -0
- package/v3/dist/cluster/adapters/in-memory.js +62 -0
- package/v3/dist/cluster/entity-actor-ref.d.ts +49 -0
- package/v3/dist/cluster/entity-actor-ref.js +19 -0
- package/v3/dist/cluster/entity-machine.d.ts +34 -49
- package/v3/dist/cluster/entity-machine.js +134 -50
- package/v3/dist/cluster/index.d.ts +5 -2
- package/v3/dist/cluster/index.js +4 -1
- package/v3/dist/cluster/persistence.d.ts +48 -0
- package/v3/dist/cluster/persistence.js +14 -0
- package/v3/dist/cluster/to-entity.d.ts +5 -2
- package/v3/dist/cluster/to-entity.js +12 -4
- package/v3/dist/errors.d.ts +18 -8
- package/v3/dist/errors.js +9 -4
- package/v3/dist/index.d.ts +6 -4
- package/v3/dist/index.js +3 -2
- package/v3/dist/internal/brands.d.ts +15 -1
- package/v3/dist/internal/runtime.d.ts +142 -0
- package/v3/dist/internal/runtime.js +335 -0
- package/v3/dist/internal/transition.d.ts +10 -4
- package/v3/dist/internal/transition.js +23 -11
- package/v3/dist/internal/utils.d.ts +42 -6
- package/v3/dist/internal/utils.js +27 -1
- package/v3/dist/machine.d.ts +35 -47
- package/v3/dist/machine.js +62 -64
- package/v3/dist/schema.d.ts +35 -34
- package/v3/dist/schema.js +29 -3
- package/v3/dist/supervision.d.ts +97 -0
- package/v3/dist/supervision.js +42 -0
- package/v3/dist/testing.d.ts +18 -9
- package/v3/dist/testing.js +21 -22
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { INTERNAL_ENTER_EVENT, isEffect } from "./utils.js";
|
|
2
|
-
import { BuiltMachine } from "../machine.js";
|
|
1
|
+
import { INTERNAL_ENTER_EVENT, isDeferReplyResult, isEffect, isReplyResult } from "./utils.js";
|
|
3
2
|
import { Cause, Effect, Exit, Scope } from "effect";
|
|
4
3
|
//#region src/internal/transition.ts
|
|
5
4
|
/**
|
|
@@ -39,14 +38,22 @@ const runTransitionHandler = Effect.fn("effect-machine.runTransitionHandler")(fu
|
|
|
39
38
|
};
|
|
40
39
|
const raw = transition.handler(handlerCtx);
|
|
41
40
|
const resolved = isEffect(raw) ? yield* raw.pipe(Effect.provideService(machine.Context, ctx)) : raw;
|
|
42
|
-
if (
|
|
41
|
+
if (isReplyResult(resolved)) return {
|
|
43
42
|
newState: resolved.state,
|
|
44
43
|
hasReply: true,
|
|
44
|
+
deferReply: false,
|
|
45
45
|
reply: resolved.reply
|
|
46
46
|
};
|
|
47
|
+
if (isDeferReplyResult(resolved)) return {
|
|
48
|
+
newState: resolved.state,
|
|
49
|
+
hasReply: false,
|
|
50
|
+
deferReply: true,
|
|
51
|
+
reply: void 0
|
|
52
|
+
};
|
|
47
53
|
return {
|
|
48
54
|
newState: resolved,
|
|
49
55
|
hasReply: false,
|
|
56
|
+
deferReply: false,
|
|
50
57
|
reply: void 0
|
|
51
58
|
};
|
|
52
59
|
});
|
|
@@ -68,14 +75,16 @@ const executeTransition = Effect.fn("effect-machine.executeTransition")(function
|
|
|
68
75
|
transitioned: false,
|
|
69
76
|
reenter: false,
|
|
70
77
|
hasReply: false,
|
|
78
|
+
deferReply: false,
|
|
71
79
|
reply: void 0
|
|
72
80
|
};
|
|
73
|
-
const { newState, hasReply, reply } = yield* runTransitionHandler(machine, transition, currentState, event, self, system, actorId);
|
|
81
|
+
const { newState, hasReply, deferReply, reply } = yield* runTransitionHandler(machine, transition, currentState, event, self, system, actorId);
|
|
74
82
|
return {
|
|
75
83
|
newState,
|
|
76
84
|
transitioned: true,
|
|
77
85
|
reenter: transition.reenter === true,
|
|
78
86
|
hasReply,
|
|
87
|
+
deferReply,
|
|
79
88
|
reply
|
|
80
89
|
};
|
|
81
90
|
});
|
|
@@ -118,6 +127,7 @@ const processEventCore = Effect.fn("effect-machine.processEventCore")(function*
|
|
|
118
127
|
lifecycleRan: false,
|
|
119
128
|
isFinal: false,
|
|
120
129
|
hasReply: false,
|
|
130
|
+
deferReply: false,
|
|
121
131
|
reply: void 0,
|
|
122
132
|
postponed: false
|
|
123
133
|
};
|
|
@@ -128,7 +138,7 @@ const processEventCore = Effect.fn("effect-machine.processEventCore")(function*
|
|
|
128
138
|
stateScopeRef.current = yield* Scope.make();
|
|
129
139
|
if (hooks?.onTransition !== void 0) yield* hooks.onTransition(currentState, newState, event);
|
|
130
140
|
if (hooks?.onSpawnEffect !== void 0) yield* hooks.onSpawnEffect(newState);
|
|
131
|
-
yield* runSpawnEffects(machine, newState, { _tag: INTERNAL_ENTER_EVENT }, self, stateScopeRef.current, system, actorId, hooks?.onError);
|
|
141
|
+
yield* runSpawnEffects(machine, newState, { _tag: INTERNAL_ENTER_EVENT }, self, stateScopeRef.current, system, actorId, hooks?.onError, hooks?.onSpawnDefect);
|
|
132
142
|
}
|
|
133
143
|
return {
|
|
134
144
|
newState,
|
|
@@ -137,6 +147,7 @@ const processEventCore = Effect.fn("effect-machine.processEventCore")(function*
|
|
|
137
147
|
lifecycleRan: runLifecycle,
|
|
138
148
|
isFinal: machine.finalStates.has(newState._tag),
|
|
139
149
|
hasReply: result.hasReply,
|
|
150
|
+
deferReply: result.deferReply,
|
|
140
151
|
reply: result.reply,
|
|
141
152
|
postponed: false
|
|
142
153
|
};
|
|
@@ -146,7 +157,7 @@ const processEventCore = Effect.fn("effect-machine.processEventCore")(function*
|
|
|
146
157
|
*
|
|
147
158
|
* @internal
|
|
148
159
|
*/
|
|
149
|
-
const runSpawnEffects = Effect.fn("effect-machine.runSpawnEffects")(function* (machine, state, event, self, stateScope, system, actorId, onError) {
|
|
160
|
+
const runSpawnEffects = Effect.fn("effect-machine.runSpawnEffects")(function* (machine, state, event, self, stateScope, system, actorId, onError, onSpawnDefect) {
|
|
150
161
|
const spawnEffects = findSpawnEffects(machine, state._tag);
|
|
151
162
|
const ctx = {
|
|
152
163
|
actorId,
|
|
@@ -157,6 +168,7 @@ const runSpawnEffects = Effect.fn("effect-machine.runSpawnEffects")(function* (m
|
|
|
157
168
|
};
|
|
158
169
|
const { effects: effectSlots } = machine._slots;
|
|
159
170
|
const reportError = onError;
|
|
171
|
+
const defectSignal = onSpawnDefect;
|
|
160
172
|
for (const spawnEffect of spawnEffects) {
|
|
161
173
|
const effect = spawnEffect.handler({
|
|
162
174
|
actorId,
|
|
@@ -167,13 +179,14 @@ const runSpawnEffects = Effect.fn("effect-machine.runSpawnEffects")(function* (m
|
|
|
167
179
|
system
|
|
168
180
|
}).pipe(Effect.provideService(machine.Context, ctx), Effect.catchAllCause((cause) => {
|
|
169
181
|
if (Cause.isInterruptedOnly(cause)) return Effect.interrupt;
|
|
170
|
-
|
|
171
|
-
return reportError({
|
|
182
|
+
const report = reportError !== void 0 ? reportError({
|
|
172
183
|
phase: "spawn",
|
|
173
184
|
state,
|
|
174
185
|
event,
|
|
175
186
|
cause
|
|
176
|
-
})
|
|
187
|
+
}) : Effect.void;
|
|
188
|
+
const signal = defectSignal !== void 0 ? defectSignal(cause) : Effect.void;
|
|
189
|
+
return report.pipe(Effect.zipRight(signal), Effect.zipRight(Effect.failCause(cause).pipe(Effect.orDie)));
|
|
177
190
|
}));
|
|
178
191
|
yield* Effect.forkScoped(effect).pipe(Effect.provideService(Scope.Scope, stateScope));
|
|
179
192
|
}
|
|
@@ -246,11 +259,10 @@ const getIndex = (machine) => {
|
|
|
246
259
|
* Find all transitions matching a state/event pair.
|
|
247
260
|
* Returns empty array if no matches.
|
|
248
261
|
*
|
|
249
|
-
* Accepts both `Machine` and `BuiltMachine`.
|
|
250
262
|
* O(1) lookup after first access (index is lazily built).
|
|
251
263
|
*/
|
|
252
264
|
const findTransitions = (input, stateTag, eventTag) => {
|
|
253
|
-
const index = getIndex(input
|
|
265
|
+
const index = getIndex(input);
|
|
254
266
|
const specific = index.transitions.get(stateTag)?.get(eventTag) ?? [];
|
|
255
267
|
if (specific.length > 0) return specific;
|
|
256
268
|
return index.transitions.get("*")?.get(eventTag) ?? [];
|
|
@@ -23,15 +23,51 @@ type InstanceOf<C> = C extends ((...args: unknown[]) => infer R) ? R : never;
|
|
|
23
23
|
type TaggedConstructor<T extends {
|
|
24
24
|
readonly _tag: string;
|
|
25
25
|
}> = (args: Omit<T, "_tag">) => T;
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
declare const ReplyResultSymbol: unique symbol;
|
|
27
|
+
type ReplyResultSymbol = typeof ReplyResultSymbol;
|
|
28
|
+
/**
|
|
29
|
+
* Branded reply result from a transition handler.
|
|
30
|
+
* Created via `Machine.reply(state, value)`.
|
|
31
|
+
*/
|
|
32
|
+
interface ReplyResult<State, Reply> {
|
|
33
|
+
readonly state: State;
|
|
34
|
+
readonly reply: Reply;
|
|
35
|
+
readonly [ReplyResultSymbol]: true;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a reply result for ask-bearing event handlers.
|
|
39
|
+
*/
|
|
40
|
+
declare const makeReply: <State, Reply>(state: State, reply: Reply) => ReplyResult<State, Reply>;
|
|
41
|
+
/**
|
|
42
|
+
* Type guard for ReplyResult (symbol-based, replaces duck-typing).
|
|
43
|
+
*/
|
|
44
|
+
declare const isReplyResult: (value: unknown) => value is ReplyResult<unknown, unknown>;
|
|
45
|
+
declare const DeferReplySymbol: unique symbol;
|
|
46
|
+
type DeferReplySymbol = typeof DeferReplySymbol;
|
|
47
|
+
/**
|
|
48
|
+
* Branded deferred reply result from a transition handler.
|
|
49
|
+
* Signals that the reply will be settled later by `self.reply()` in a spawn handler.
|
|
50
|
+
* Created via `Machine.deferReply(state)`.
|
|
51
|
+
*/
|
|
52
|
+
interface DeferReplyResult<State> {
|
|
28
53
|
readonly state: State;
|
|
29
|
-
readonly
|
|
54
|
+
readonly [DeferReplySymbol]: true;
|
|
30
55
|
}
|
|
31
56
|
/**
|
|
32
|
-
*
|
|
57
|
+
* Create a deferred reply result. Handler returns this to signal
|
|
58
|
+
* "spawn handler will call self.reply(value) later".
|
|
59
|
+
*/
|
|
60
|
+
declare const makeDeferReply: <State>(state: State) => DeferReplyResult<State>;
|
|
61
|
+
/**
|
|
62
|
+
* Type guard for DeferReplyResult.
|
|
63
|
+
*/
|
|
64
|
+
declare const isDeferReplyResult: (value: unknown) => value is DeferReplyResult<unknown>;
|
|
65
|
+
/**
|
|
66
|
+
* Transition handler result.
|
|
67
|
+
* - When Reply is `never`: handler returns plain State (no reply allowed)
|
|
68
|
+
* - When Reply is concrete: handler must return ReplyResult via Machine.reply()
|
|
33
69
|
*/
|
|
34
|
-
type TransitionResult<State, R> = State |
|
|
70
|
+
type TransitionResult<State, R, Reply = never> = [Reply] extends [never] ? State | Effect.Effect<State, never, R> : ReplyResult<State, Reply> | DeferReplyResult<State> | Effect.Effect<ReplyResult<State, Reply> | DeferReplyResult<State>, never, R>;
|
|
35
71
|
/**
|
|
36
72
|
* Internal event tags used for lifecycle effect contexts.
|
|
37
73
|
* Prefixed with $ to distinguish from user events.
|
|
@@ -62,4 +98,4 @@ declare const isEffect: (value: unknown) => value is Effect.Effect<unknown, unkn
|
|
|
62
98
|
*/
|
|
63
99
|
declare const stubSystem: ActorSystem;
|
|
64
100
|
//#endregion
|
|
65
|
-
export { ArgsOf, INTERNAL_ENTER_EVENT, INTERNAL_INIT_EVENT, InstanceOf, TagOf, TaggedConstructor,
|
|
101
|
+
export { ArgsOf, DeferReplyResult, DeferReplySymbol, INTERNAL_ENTER_EVENT, INTERNAL_INIT_EVENT, InstanceOf, ReplyResult, ReplyResultSymbol, TagOf, TaggedConstructor, TransitionResult, getTag, isDeferReplyResult, isEffect, isReplyResult, makeDeferReply, makeReply, stubSystem };
|
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
import { Effect, Stream } from "effect";
|
|
2
2
|
//#region src/internal/utils.ts
|
|
3
|
+
const ReplyResultSymbol = Symbol.for("effect-machine/ReplyResult");
|
|
4
|
+
/**
|
|
5
|
+
* Create a reply result for ask-bearing event handlers.
|
|
6
|
+
*/
|
|
7
|
+
const makeReply = (state, reply) => ({
|
|
8
|
+
state,
|
|
9
|
+
reply,
|
|
10
|
+
[ReplyResultSymbol]: true
|
|
11
|
+
});
|
|
12
|
+
/**
|
|
13
|
+
* Type guard for ReplyResult (symbol-based, replaces duck-typing).
|
|
14
|
+
*/
|
|
15
|
+
const isReplyResult = (value) => value !== null && typeof value === "object" && ReplyResultSymbol in value;
|
|
16
|
+
const DeferReplySymbol = Symbol.for("effect-machine/DeferReply");
|
|
17
|
+
/**
|
|
18
|
+
* Create a deferred reply result. Handler returns this to signal
|
|
19
|
+
* "spawn handler will call self.reply(value) later".
|
|
20
|
+
*/
|
|
21
|
+
const makeDeferReply = (state) => ({
|
|
22
|
+
state,
|
|
23
|
+
[DeferReplySymbol]: true
|
|
24
|
+
});
|
|
25
|
+
/**
|
|
26
|
+
* Type guard for DeferReplyResult.
|
|
27
|
+
*/
|
|
28
|
+
const isDeferReplyResult = (value) => value !== null && typeof value === "object" && DeferReplySymbol in value;
|
|
3
29
|
/**
|
|
4
30
|
* Internal event tags used for lifecycle effect contexts.
|
|
5
31
|
* Prefixed with $ to distinguish from user events.
|
|
@@ -42,4 +68,4 @@ const stubSystem = {
|
|
|
42
68
|
subscribe: () => () => {}
|
|
43
69
|
};
|
|
44
70
|
//#endregion
|
|
45
|
-
export { INTERNAL_ENTER_EVENT, INTERNAL_INIT_EVENT, getTag, isEffect, stubSystem };
|
|
71
|
+
export { INTERNAL_ENTER_EVENT, INTERNAL_INIT_EVENT, getTag, isDeferReplyResult, isEffect, isReplyResult, makeDeferReply, makeReply, stubSystem };
|
package/v3/dist/machine.d.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { TransitionResult } from "./internal/utils.js";
|
|
3
|
-
import { BrandedEvent, BrandedState, TaggedOrConstructor } from "./internal/brands.js";
|
|
1
|
+
import { Supervision } from "./supervision.js";
|
|
2
|
+
import { ReplyResult, TransitionResult } from "./internal/utils.js";
|
|
3
|
+
import { BrandedEvent, BrandedState, ExtractReply, TaggedOrConstructor } from "./internal/brands.js";
|
|
4
4
|
import { MachineEventSchema, MachineStateSchema, VariantsUnion } from "./schema.js";
|
|
5
5
|
import { DuplicateActorError } from "./errors.js";
|
|
6
|
+
import { EffectHandlers, EffectSlots, EffectsDef, EffectsSchema, GuardHandlers, GuardSlots, GuardsDef, GuardsSchema, MachineContext } from "./slot.js";
|
|
6
7
|
import { findTransitions } from "./internal/transition.js";
|
|
7
8
|
import { ActorRef, ActorSystem } from "./actor.js";
|
|
8
9
|
import { Cause, Context, Duration, Effect, Schema, Scope } from "effect";
|
|
9
10
|
|
|
10
11
|
//#region src/machine.d.ts
|
|
11
12
|
declare namespace machine_d_exports {
|
|
12
|
-
export { BackgroundEffect,
|
|
13
|
+
export { BackgroundEffect, HandlerContext, Machine, MachineRef, MakeConfig, ProvideHandlers, ReplyResult, SlotContext, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, TransitionHandler, findTransitions, make, materializeMachine, replay, reply, spawn };
|
|
13
14
|
}
|
|
14
15
|
/**
|
|
15
16
|
* Self reference for sending events back to the machine
|
|
@@ -22,7 +23,7 @@ interface MachineRef<Event> {
|
|
|
22
23
|
readonly _tag: string;
|
|
23
24
|
}, E2 extends {
|
|
24
25
|
readonly _tag: string;
|
|
25
|
-
}, R2>(id: string, machine:
|
|
26
|
+
}, R2>(id: string, machine: Machine<S2, E2, R2, any, any, any, any>) => Effect.Effect<ActorRef<S2, E2>, DuplicateActorError, R2>;
|
|
26
27
|
}
|
|
27
28
|
/**
|
|
28
29
|
* Handler context passed to transition handlers
|
|
@@ -45,9 +46,11 @@ interface StateHandlerContext<State, Event, ED extends EffectsDef> {
|
|
|
45
46
|
readonly system: ActorSystem;
|
|
46
47
|
}
|
|
47
48
|
/**
|
|
48
|
-
* Transition handler function
|
|
49
|
+
* Transition handler function.
|
|
50
|
+
* When Reply is concrete (event has a reply schema), handler must return Machine.reply().
|
|
51
|
+
* When Reply is never, handler returns plain state.
|
|
49
52
|
*/
|
|
50
|
-
type TransitionHandler<S, E, NewState, GD extends GuardsDef, ED extends EffectsDef, R> = (ctx: HandlerContext<S, E, GD, ED>) => TransitionResult<NewState, R>;
|
|
53
|
+
type TransitionHandler<S, E, NewState, GD extends GuardsDef, ED extends EffectsDef, R, Reply = never> = (ctx: HandlerContext<S, E, GD, ED>) => TransitionResult<NewState, R, Reply>;
|
|
51
54
|
/**
|
|
52
55
|
* State effect handler function
|
|
53
56
|
*/
|
|
@@ -91,9 +94,6 @@ interface TimeoutConfig<State, Event> {
|
|
|
91
94
|
/** Event to send when the timer fires. Static or derived from current state. */
|
|
92
95
|
readonly event: Event | ((state: State) => Event);
|
|
93
96
|
}
|
|
94
|
-
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
95
|
-
type IsUnknown<T> = unknown extends T ? ([T] extends [unknown] ? true : false) : false;
|
|
96
|
-
type NormalizeR<T> = IsAny<T> extends true ? T : IsUnknown<T> extends true ? never : T;
|
|
97
97
|
interface MakeConfig<SD extends Record<string, Schema.Struct.Fields>, ED extends Record<string, Schema.Struct.Fields>, S extends BrandedState, E extends BrandedEvent, GD extends GuardsDef, EFD extends EffectsDef> {
|
|
98
98
|
readonly state: MachineStateSchema<SD> & {
|
|
99
99
|
Type: S;
|
|
@@ -113,22 +113,14 @@ type HasEffectKeys<EFD extends EffectsDef> = [keyof EFD] extends [never] ? false
|
|
|
113
113
|
type SlotContext<State, Event> = MachineContext<State, Event, MachineRef<Event>>;
|
|
114
114
|
/** Combined handlers for build() - guards and effects only */
|
|
115
115
|
type ProvideHandlers<State, Event, GD extends GuardsDef, EFD extends EffectsDef, R> = (HasGuardKeys<GD> extends true ? GuardHandlers<GD, SlotContext<State, Event>, R> : object) & (HasEffectKeys<EFD> extends true ? EffectHandlers<EFD, SlotContext<State, Event>, R> : object);
|
|
116
|
-
/** Whether the machine has any guard or effect slots */
|
|
117
|
-
type HasSlots<GD extends GuardsDef, EFD extends EffectsDef> = HasGuardKeys<GD> extends true ? true : HasEffectKeys<EFD>;
|
|
118
116
|
/**
|
|
119
|
-
*
|
|
117
|
+
* Bind slot handlers to a machine, returning a fresh copy with handlers installed.
|
|
118
|
+
* If no handlers provided and machine has no slots, returns the machine as-is.
|
|
119
|
+
* Validates that all required slots are provided and no extra slots are given.
|
|
120
120
|
*
|
|
121
|
-
*
|
|
122
|
-
* accepted by `Machine.spawn` and `ActorSystem.spawn` (regular overload).
|
|
123
|
-
* Testing utilities (`simulate`, `createTestHarness`, etc.) still accept `Machine`.
|
|
121
|
+
* @internal — used by spawn, replay, simulate, test harness, entity-machine
|
|
124
122
|
*/
|
|
125
|
-
declare
|
|
126
|
-
/** @internal */
|
|
127
|
-
readonly _inner: Machine<State, Event, R, any, any, any, any>;
|
|
128
|
-
/** @internal */
|
|
129
|
-
constructor(machine: Machine<State, Event, R, any, any, any, any>);
|
|
130
|
-
get initial(): State;
|
|
131
|
-
}
|
|
123
|
+
declare const materializeMachine: <S, E, R, GD extends GuardsDef, EFD extends EffectsDef>(machine: Machine<S, E, R, any, any, GD, EFD>, handlers?: Record<string, any>) => Machine<S, E, never, any, any, GD, EFD>;
|
|
132
124
|
/**
|
|
133
125
|
* Machine definition with fluent builder API.
|
|
134
126
|
*
|
|
@@ -171,6 +163,8 @@ declare class Machine<State, Event, R = never, _SD extends Record<string, Schema
|
|
|
171
163
|
};
|
|
172
164
|
readonly stateSchema?: Schema.Schema<State, unknown, never>;
|
|
173
165
|
readonly eventSchema?: Schema.Schema<Event, unknown, never>;
|
|
166
|
+
/** @internal */
|
|
167
|
+
readonly _replySchemas: ReadonlyMap<string, Schema.Schema.Any>;
|
|
174
168
|
/**
|
|
175
169
|
* Context tag for accessing machine state/event/self in slot handlers.
|
|
176
170
|
* Uses shared module-level tag for all machines.
|
|
@@ -186,24 +180,25 @@ declare class Machine<State, Event, R = never, _SD extends Record<string, Schema
|
|
|
186
180
|
}>;
|
|
187
181
|
get guardsSchema(): GuardsSchema<GD> | undefined;
|
|
188
182
|
get effectsSchema(): EffectsSchema<EFD> | undefined;
|
|
183
|
+
get replySchemas(): ReadonlyMap<string, Schema.Schema.Any>;
|
|
189
184
|
/** @internal */
|
|
190
185
|
constructor(initial: State, stateSchema?: Schema.Schema<State, unknown, never>, eventSchema?: Schema.Schema<Event, unknown, never>, guardsSchema?: GuardsSchema<GD>, effectsSchema?: EffectsSchema<EFD>);
|
|
191
186
|
from<NS extends VariantsUnion<_SD> & BrandedState, R1>(state: TaggedOrConstructor<NS>, build: (scope: TransitionScope<State, Event, R, _SD, _ED, GD, EFD, NS>) => R1): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
192
187
|
from<NS extends ReadonlyArray<TaggedOrConstructor<VariantsUnion<_SD> & BrandedState>>, R1>(states: NS, build: (scope: TransitionScope<State, Event, R, _SD, _ED, GD, EFD, NS[number] extends TaggedOrConstructor<infer S extends VariantsUnion<_SD> & BrandedState> ? S : never>) => R1): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
193
188
|
/** @internal */
|
|
194
|
-
scopeTransition<NS extends VariantsUnion<_SD> & BrandedState, NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(states: ReadonlyArray<TaggedOrConstructor<NS>>, event: TaggedOrConstructor<NE>, handler: TransitionHandler<NS, NE, RS, GD, EFD, never
|
|
189
|
+
scopeTransition<NS extends VariantsUnion<_SD> & BrandedState, NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(states: ReadonlyArray<TaggedOrConstructor<NS>>, event: TaggedOrConstructor<NE>, handler: TransitionHandler<NS, NE, RS, GD, EFD, never, ExtractReply<NE>>, reenter: boolean): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
195
190
|
/** Register transition for a single state */
|
|
196
|
-
on<NS extends VariantsUnion<_SD> & BrandedState, NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>, event: TaggedOrConstructor<NE>, handler: TransitionHandler<NS, NE, RS, GD, EFD, never
|
|
191
|
+
on<NS extends VariantsUnion<_SD> & BrandedState, NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>, event: TaggedOrConstructor<NE>, handler: TransitionHandler<NS, NE, RS, GD, EFD, never, ExtractReply<NE>>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
197
192
|
/** Register transition for multiple states (handler receives union of state types) */
|
|
198
|
-
on<NS extends ReadonlyArray<TaggedOrConstructor<VariantsUnion<_SD> & BrandedState>>, NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(states: NS, event: TaggedOrConstructor<NE>, handler: TransitionHandler<NS[number] extends TaggedOrConstructor<infer S> ? S : never, NE, RS, GD, EFD, never
|
|
193
|
+
on<NS extends ReadonlyArray<TaggedOrConstructor<VariantsUnion<_SD> & BrandedState>>, NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(states: NS, event: TaggedOrConstructor<NE>, handler: TransitionHandler<NS[number] extends TaggedOrConstructor<infer S> ? S : never, NE, RS, GD, EFD, never, ExtractReply<NE>>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
199
194
|
/**
|
|
200
195
|
* Like `on()`, but forces onEnter/spawn to run even when transitioning to the same state tag.
|
|
201
196
|
* Use this to restart timers, re-run spawned effects, or reset state-scoped effects.
|
|
202
197
|
*/
|
|
203
198
|
/** Single state */
|
|
204
|
-
reenter<NS extends VariantsUnion<_SD> & BrandedState, NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>, event: TaggedOrConstructor<NE>, handler: TransitionHandler<NS, NE, RS, GD, EFD, never
|
|
199
|
+
reenter<NS extends VariantsUnion<_SD> & BrandedState, NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>, event: TaggedOrConstructor<NE>, handler: TransitionHandler<NS, NE, RS, GD, EFD, never, ExtractReply<NE>>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
205
200
|
/** Multiple states */
|
|
206
|
-
reenter<NS extends ReadonlyArray<TaggedOrConstructor<VariantsUnion<_SD> & BrandedState>>, NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(states: NS, event: TaggedOrConstructor<NE>, handler: TransitionHandler<NS[number] extends TaggedOrConstructor<infer S> ? S : never, NE, RS, GD, EFD, never
|
|
201
|
+
reenter<NS extends ReadonlyArray<TaggedOrConstructor<VariantsUnion<_SD> & BrandedState>>, NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(states: NS, event: TaggedOrConstructor<NE>, handler: TransitionHandler<NS[number] extends TaggedOrConstructor<infer S> ? S : never, NE, RS, GD, EFD, never, ExtractReply<NE>>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
207
202
|
/**
|
|
208
203
|
* Register a wildcard transition that fires from any state when no specific transition matches.
|
|
209
204
|
* Specific `.on()` transitions always take priority over `.onAny()`.
|
|
@@ -301,50 +296,43 @@ declare class Machine<State, Event, R = never, _SD extends Record<string, Schema
|
|
|
301
296
|
*/
|
|
302
297
|
postpone<NS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>, events: TaggedOrConstructor<VariantsUnion<_ED> & BrandedEvent> | ReadonlyArray<TaggedOrConstructor<VariantsUnion<_ED> & BrandedEvent>>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
303
298
|
final<NS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
304
|
-
/**
|
|
305
|
-
* Finalize the machine. Returns a `BuiltMachine` — the only type accepted by `Machine.spawn`.
|
|
306
|
-
*
|
|
307
|
-
* - Machines with slots: pass implementations as the first argument.
|
|
308
|
-
* - Machines without slots: call with no arguments.
|
|
309
|
-
*/
|
|
310
|
-
build<R2 = never>(...args: HasSlots<GD, EFD> extends true ? [handlers: ProvideHandlers<State, Event, GD, EFD, R2>] : [handlers?: ProvideHandlers<State, Event, GD, EFD, R2>]): BuiltMachine<State, Event, R | NormalizeR<R2>>;
|
|
311
299
|
static make<SD extends Record<string, Schema.Struct.Fields>, ED extends Record<string, Schema.Struct.Fields>, S extends BrandedState, E extends BrandedEvent, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>>(config: MakeConfig<SD, ED, S, E, GD, EFD>): Machine<S, E, never, SD, ED, GD, EFD>;
|
|
312
300
|
}
|
|
313
301
|
declare class TransitionScope<State, Event, R, _SD extends Record<string, Schema.Struct.Fields>, _ED extends Record<string, Schema.Struct.Fields>, GD extends GuardsDef, EFD extends EffectsDef, SelectedState extends VariantsUnion<_SD> & BrandedState> {
|
|
314
302
|
private readonly machine;
|
|
315
303
|
private readonly states;
|
|
316
304
|
constructor(machine: Machine<State, Event, R, _SD, _ED, GD, EFD>, states: ReadonlyArray<TaggedOrConstructor<SelectedState>>);
|
|
317
|
-
on<NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(event: TaggedOrConstructor<NE>, handler: TransitionHandler<SelectedState, NE, RS, GD, EFD, never
|
|
318
|
-
reenter<NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(event: TaggedOrConstructor<NE>, handler: TransitionHandler<SelectedState, NE, RS, GD, EFD, never
|
|
305
|
+
on<NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(event: TaggedOrConstructor<NE>, handler: TransitionHandler<SelectedState, NE, RS, GD, EFD, never, ExtractReply<NE>>): TransitionScope<State, Event, R, _SD, _ED, GD, EFD, SelectedState>;
|
|
306
|
+
reenter<NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(event: TaggedOrConstructor<NE>, handler: TransitionHandler<SelectedState, NE, RS, GD, EFD, never, ExtractReply<NE>>): TransitionScope<State, Event, R, _SD, _ED, GD, EFD, SelectedState>;
|
|
319
307
|
}
|
|
320
308
|
declare const make: typeof Machine.make;
|
|
309
|
+
type AnyMachine<S, E, R> = Machine<S, E, R, any, any, any, any>;
|
|
321
310
|
/**
|
|
322
|
-
* Spawn an actor from a
|
|
311
|
+
* Spawn an actor from a machine.
|
|
323
312
|
*
|
|
324
313
|
* Options:
|
|
325
314
|
* - `id` — custom actor ID (default: random)
|
|
326
315
|
* - `hydrate` — restore from a previously-saved state snapshot.
|
|
327
|
-
*
|
|
328
|
-
* for that state (timers, scoped resources, etc.). Transition history
|
|
329
|
-
* is not replayed — only the current state's entry effects run.
|
|
330
|
-
*
|
|
331
|
-
* Persistence is composed in userland by observing `actor.changes`
|
|
332
|
-
* and saving snapshots to your own storage.
|
|
316
|
+
* - `slots` — slot handler implementations for slotful machines.
|
|
333
317
|
*/
|
|
334
318
|
declare const spawn: <S extends {
|
|
335
319
|
readonly _tag: string;
|
|
336
320
|
}, E extends {
|
|
337
321
|
readonly _tag: string;
|
|
338
|
-
}, R>(machine:
|
|
322
|
+
}, R>(machine: AnyMachine<S, E, R>, options?: string | {
|
|
339
323
|
id?: string;
|
|
340
324
|
hydrate?: S;
|
|
325
|
+
slots?: Record<string, any>;
|
|
326
|
+
supervision?: Supervision.Policy;
|
|
341
327
|
}) => Effect.Effect<ActorRef<S, E>, never, R>;
|
|
342
328
|
declare const replay: <S extends {
|
|
343
329
|
readonly _tag: string;
|
|
344
330
|
}, E extends {
|
|
345
331
|
readonly _tag: string;
|
|
346
|
-
}, R>(machine:
|
|
332
|
+
}, R>(machine: AnyMachine<S, E, R>, events: ReadonlyArray<E>, options?: {
|
|
347
333
|
from?: S;
|
|
334
|
+
slots?: Record<string, any>;
|
|
348
335
|
}) => Effect.Effect<S, never, R>;
|
|
336
|
+
declare const reply: <State, Reply>(state: State, reply: Reply) => ReplyResult<State, Reply>;
|
|
349
337
|
//#endregion
|
|
350
|
-
export { BackgroundEffect,
|
|
338
|
+
export { BackgroundEffect, HandlerContext, Machine, MachineRef, MakeConfig, ProvideHandlers, type ReplyResult, SlotContext, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, TransitionHandler, findTransitions, machine_d_exports, make, materializeMachine, replay, reply, spawn };
|
package/v3/dist/machine.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
|
-
import {
|
|
3
|
-
import { getTag, stubSystem } from "./internal/utils.js";
|
|
2
|
+
import { getTag, makeReply, stubSystem } from "./internal/utils.js";
|
|
4
3
|
import { ProvisionValidationError, SlotProvisionError } from "./errors.js";
|
|
4
|
+
import { findTransitions, invalidateIndex, resolveTransition, runTransitionHandler, shouldPostpone } from "./internal/transition.js";
|
|
5
5
|
import { emitWithTimestamp } from "./internal/inspection.js";
|
|
6
|
+
import { Inspector } from "./inspection.js";
|
|
6
7
|
import { MachineContextTag } from "./slot.js";
|
|
7
|
-
import { findTransitions, invalidateIndex, resolveTransition, runTransitionHandler, shouldPostpone } from "./internal/transition.js";
|
|
8
8
|
import { createActor } from "./actor.js";
|
|
9
9
|
import { Cause, Effect, Exit, Option, Scope } from "effect";
|
|
10
10
|
//#region src/machine.ts
|
|
11
11
|
var machine_exports = /* @__PURE__ */ __exportAll({
|
|
12
|
-
BuiltMachine: () => BuiltMachine,
|
|
13
12
|
Machine: () => Machine,
|
|
14
13
|
findTransitions: () => findTransitions,
|
|
15
14
|
make: () => make,
|
|
15
|
+
materializeMachine: () => materializeMachine,
|
|
16
16
|
replay: () => replay,
|
|
17
|
+
reply: () => reply,
|
|
17
18
|
spawn: () => spawn
|
|
18
19
|
});
|
|
19
20
|
const emitTaskInspection = (input) => Effect.flatMap(Effect.serviceOptional(Inspector).pipe(Effect.option), (inspector) => Option.isNone(inspector) ? Effect.void : emitWithTimestamp(inspector.value, (timestamp) => ({
|
|
@@ -26,22 +27,49 @@ const emitTaskInspection = (input) => Effect.flatMap(Effect.serviceOptional(Insp
|
|
|
26
27
|
timestamp
|
|
27
28
|
})));
|
|
28
29
|
/**
|
|
29
|
-
*
|
|
30
|
+
* Bind slot handlers to a machine, returning a fresh copy with handlers installed.
|
|
31
|
+
* If no handlers provided and machine has no slots, returns the machine as-is.
|
|
32
|
+
* Validates that all required slots are provided and no extra slots are given.
|
|
30
33
|
*
|
|
31
|
-
*
|
|
32
|
-
* accepted by `Machine.spawn` and `ActorSystem.spawn` (regular overload).
|
|
33
|
-
* Testing utilities (`simulate`, `createTestHarness`, etc.) still accept `Machine`.
|
|
34
|
+
* @internal — used by spawn, replay, simulate, test harness, entity-machine
|
|
34
35
|
*/
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
const materializeMachine = (machine, handlers) => {
|
|
37
|
+
if (handlers === void 0) {
|
|
38
|
+
const hasGuards = machine._guardsSchema !== void 0 && Object.keys(machine._guardsSchema.definitions).length > 0;
|
|
39
|
+
const hasEffects = machine._effectsSchema !== void 0 && Object.keys(machine._effectsSchema.definitions).length > 0;
|
|
40
|
+
if (hasGuards || hasEffects) {
|
|
41
|
+
const missing = [];
|
|
42
|
+
if (machine._guardsSchema !== void 0) missing.push(...Object.keys(machine._guardsSchema.definitions));
|
|
43
|
+
if (machine._effectsSchema !== void 0) missing.push(...Object.keys(machine._effectsSchema.definitions));
|
|
44
|
+
throw new ProvisionValidationError({
|
|
45
|
+
missing,
|
|
46
|
+
extra: []
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return machine;
|
|
44
50
|
}
|
|
51
|
+
const requiredSlots = /* @__PURE__ */ new Set();
|
|
52
|
+
if (machine._guardsSchema !== void 0) for (const name of Object.keys(machine._guardsSchema.definitions)) requiredSlots.add(name);
|
|
53
|
+
if (machine._effectsSchema !== void 0) for (const name of Object.keys(machine._effectsSchema.definitions)) requiredSlots.add(name);
|
|
54
|
+
const providedSlots = new Set(Object.keys(handlers));
|
|
55
|
+
const missing = [];
|
|
56
|
+
const extra = [];
|
|
57
|
+
for (const name of requiredSlots) if (!providedSlots.has(name)) missing.push(name);
|
|
58
|
+
for (const name of providedSlots) if (!requiredSlots.has(name)) extra.push(name);
|
|
59
|
+
if (missing.length > 0 || extra.length > 0) throw new ProvisionValidationError({
|
|
60
|
+
missing,
|
|
61
|
+
extra
|
|
62
|
+
});
|
|
63
|
+
const result = new Machine(machine.initial, machine.stateSchema, machine.eventSchema, machine._guardsSchema, machine._effectsSchema);
|
|
64
|
+
result._transitions = [...machine._transitions];
|
|
65
|
+
result._finalStates = new Set(machine._finalStates);
|
|
66
|
+
result._spawnEffects = [...machine._spawnEffects];
|
|
67
|
+
result._backgroundEffects = [...machine._backgroundEffects];
|
|
68
|
+
result._postponeRules = [...machine._postponeRules];
|
|
69
|
+
result._replySchemas = machine._replySchemas;
|
|
70
|
+
if (machine._guardsSchema !== void 0) for (const name of Object.keys(machine._guardsSchema.definitions)) result._guardHandlers.set(name, handlers[name]);
|
|
71
|
+
if (machine._effectsSchema !== void 0) for (const name of Object.keys(machine._effectsSchema.definitions)) result._effectHandlers.set(name, handlers[name]);
|
|
72
|
+
return result;
|
|
45
73
|
};
|
|
46
74
|
/**
|
|
47
75
|
* Machine definition with fluent builder API.
|
|
@@ -69,6 +97,7 @@ var Machine = class Machine {
|
|
|
69
97
|
/** @internal */ _slots;
|
|
70
98
|
stateSchema;
|
|
71
99
|
eventSchema;
|
|
100
|
+
/** @internal */ _replySchemas;
|
|
72
101
|
/**
|
|
73
102
|
* Context tag for accessing machine state/event/self in slot handlers.
|
|
74
103
|
* Uses shared module-level tag for all machines.
|
|
@@ -95,6 +124,9 @@ var Machine = class Machine {
|
|
|
95
124
|
get effectsSchema() {
|
|
96
125
|
return this._effectsSchema;
|
|
97
126
|
}
|
|
127
|
+
get replySchemas() {
|
|
128
|
+
return this._replySchemas;
|
|
129
|
+
}
|
|
98
130
|
/** @internal */
|
|
99
131
|
constructor(initial, stateSchema, eventSchema, guardsSchema, effectsSchema) {
|
|
100
132
|
this.initial = initial;
|
|
@@ -109,6 +141,7 @@ var Machine = class Machine {
|
|
|
109
141
|
this._effectHandlers = /* @__PURE__ */ new Map();
|
|
110
142
|
this.stateSchema = stateSchema;
|
|
111
143
|
this.eventSchema = eventSchema;
|
|
144
|
+
this._replySchemas = eventSchema?._replySchemas ?? /* @__PURE__ */ new Map();
|
|
112
145
|
this._slots = {
|
|
113
146
|
guards: this._guardsSchema !== void 0 ? this._guardsSchema._createSlots((name, params) => Effect.flatMap(Effect.serviceOptional(this.Context).pipe(Effect.orDie), (ctx) => {
|
|
114
147
|
const handler = this._guardHandlers.get(name);
|
|
@@ -344,40 +377,6 @@ var Machine = class Machine {
|
|
|
344
377
|
this._finalStates.add(stateTag);
|
|
345
378
|
return this;
|
|
346
379
|
}
|
|
347
|
-
/**
|
|
348
|
-
* Finalize the machine. Returns a `BuiltMachine` — the only type accepted by `Machine.spawn`.
|
|
349
|
-
*
|
|
350
|
-
* - Machines with slots: pass implementations as the first argument.
|
|
351
|
-
* - Machines without slots: call with no arguments.
|
|
352
|
-
*/
|
|
353
|
-
build(...args) {
|
|
354
|
-
const handlers = args[0];
|
|
355
|
-
if (handlers !== void 0) {
|
|
356
|
-
const requiredSlots = /* @__PURE__ */ new Set();
|
|
357
|
-
if (this._guardsSchema !== void 0) for (const name of Object.keys(this._guardsSchema.definitions)) requiredSlots.add(name);
|
|
358
|
-
if (this._effectsSchema !== void 0) for (const name of Object.keys(this._effectsSchema.definitions)) requiredSlots.add(name);
|
|
359
|
-
const providedSlots = new Set(Object.keys(handlers));
|
|
360
|
-
const missing = [];
|
|
361
|
-
const extra = [];
|
|
362
|
-
for (const name of requiredSlots) if (!providedSlots.has(name)) missing.push(name);
|
|
363
|
-
for (const name of providedSlots) if (!requiredSlots.has(name)) extra.push(name);
|
|
364
|
-
if (missing.length > 0 || extra.length > 0) throw new ProvisionValidationError({
|
|
365
|
-
missing,
|
|
366
|
-
extra
|
|
367
|
-
});
|
|
368
|
-
const result = new Machine(this.initial, this.stateSchema, this.eventSchema, this._guardsSchema, this._effectsSchema);
|
|
369
|
-
result._transitions = [...this._transitions];
|
|
370
|
-
result._finalStates = new Set(this._finalStates);
|
|
371
|
-
result._spawnEffects = [...this._spawnEffects];
|
|
372
|
-
result._backgroundEffects = [...this._backgroundEffects];
|
|
373
|
-
result._postponeRules = [...this._postponeRules];
|
|
374
|
-
const anyHandlers = handlers;
|
|
375
|
-
if (this._guardsSchema !== void 0) for (const name of Object.keys(this._guardsSchema.definitions)) result._guardHandlers.set(name, anyHandlers[name]);
|
|
376
|
-
if (this._effectsSchema !== void 0) for (const name of Object.keys(this._effectsSchema.definitions)) result._effectHandlers.set(name, anyHandlers[name]);
|
|
377
|
-
return new BuiltMachine(result);
|
|
378
|
-
}
|
|
379
|
-
return new BuiltMachine(this);
|
|
380
|
-
}
|
|
381
380
|
static make(config) {
|
|
382
381
|
return new Machine(config.initial, config.state, config.event, config.guards, config.effects);
|
|
383
382
|
}
|
|
@@ -398,27 +397,25 @@ var TransitionScope = class {
|
|
|
398
397
|
};
|
|
399
398
|
const make = Machine.make;
|
|
400
399
|
/**
|
|
401
|
-
* Spawn an actor from a
|
|
400
|
+
* Spawn an actor from a machine.
|
|
402
401
|
*
|
|
403
402
|
* Options:
|
|
404
403
|
* - `id` — custom actor ID (default: random)
|
|
405
404
|
* - `hydrate` — restore from a previously-saved state snapshot.
|
|
406
|
-
*
|
|
407
|
-
* for that state (timers, scoped resources, etc.). Transition history
|
|
408
|
-
* is not replayed — only the current state's entry effects run.
|
|
409
|
-
*
|
|
410
|
-
* Persistence is composed in userland by observing `actor.changes`
|
|
411
|
-
* and saving snapshots to your own storage.
|
|
405
|
+
* - `slots` — slot handler implementations for slotful machines.
|
|
412
406
|
*/
|
|
413
|
-
const spawn = Effect.fn("effect-machine.spawn")(function* (
|
|
414
|
-
const opts = typeof
|
|
415
|
-
const actor = yield* createActor(opts?.id ?? `actor-${Math.random().toString(36).slice(2)}`,
|
|
407
|
+
const spawn = Effect.fn("effect-machine.spawn")(function* (machine, options) {
|
|
408
|
+
const opts = typeof options === "string" ? { id: options } : options;
|
|
409
|
+
const actor = yield* createActor(opts?.id ?? `actor-${Math.random().toString(36).slice(2)}`, materializeMachine(machine, opts?.slots), {
|
|
410
|
+
initialState: opts?.hydrate,
|
|
411
|
+
supervision: opts?.supervision
|
|
412
|
+
});
|
|
416
413
|
const maybeScope = yield* Effect.serviceOption(Scope.Scope);
|
|
417
414
|
if (Option.isSome(maybeScope)) yield* Scope.addFinalizer(maybeScope.value, actor.stop);
|
|
418
415
|
return actor;
|
|
419
416
|
});
|
|
420
|
-
const replay = Effect.fn("effect-machine.replay")(function* (
|
|
421
|
-
const machine =
|
|
417
|
+
const replay = Effect.fn("effect-machine.replay")(function* (input, events, options) {
|
|
418
|
+
const machine = materializeMachine(input, options?.slots);
|
|
422
419
|
let state = options?.from ?? machine.initial;
|
|
423
420
|
const hasPostponeRules = machine.postponeRules.length > 0;
|
|
424
421
|
const postponed = [];
|
|
@@ -460,5 +457,6 @@ const replay = Effect.fn("effect-machine.replay")(function* (built, events, opti
|
|
|
460
457
|
}
|
|
461
458
|
return state;
|
|
462
459
|
});
|
|
460
|
+
const reply = makeReply;
|
|
463
461
|
//#endregion
|
|
464
|
-
export {
|
|
462
|
+
export { Machine, findTransitions, machine_exports, make, materializeMachine, replay, reply, spawn };
|