effect-machine 0.12.0 → 0.14.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.
Files changed (53) hide show
  1. package/README.md +133 -324
  2. package/dist/actor.d.ts +46 -28
  3. package/dist/actor.js +276 -315
  4. package/dist/cluster/entity-machine.d.ts +1 -1
  5. package/dist/cluster/entity-machine.js +20 -9
  6. package/dist/cluster/to-entity.d.ts +3 -3
  7. package/dist/errors.d.ts +24 -20
  8. package/dist/errors.js +10 -6
  9. package/dist/index.d.ts +5 -4
  10. package/dist/index.js +3 -2
  11. package/dist/internal/runtime.d.ts +82 -7
  12. package/dist/internal/runtime.js +162 -58
  13. package/dist/internal/transition.d.ts +12 -11
  14. package/dist/internal/transition.js +12 -14
  15. package/dist/machine.d.ts +148 -140
  16. package/dist/machine.js +141 -155
  17. package/dist/schema.d.ts +14 -0
  18. package/dist/schema.js +10 -1
  19. package/dist/slot.d.ts +112 -86
  20. package/dist/slot.js +92 -59
  21. package/dist/supervision.d.ts +97 -0
  22. package/dist/supervision.js +42 -0
  23. package/dist/testing.d.ts +21 -12
  24. package/dist/testing.js +23 -26
  25. package/package.json +7 -7
  26. package/v3/dist/actor.d.ts +53 -30
  27. package/v3/dist/actor.js +286 -311
  28. package/v3/dist/cluster/entity-machine.d.ts +1 -1
  29. package/v3/dist/cluster/entity-machine.js +5 -5
  30. package/v3/dist/cluster/to-entity.d.ts +1 -1
  31. package/v3/dist/errors.d.ts +14 -10
  32. package/v3/dist/errors.js +11 -7
  33. package/v3/dist/index.d.ts +6 -5
  34. package/v3/dist/index.js +3 -2
  35. package/v3/dist/inspection.d.ts +3 -22
  36. package/v3/dist/inspection.js +1 -15
  37. package/v3/dist/internal/brands.d.ts +4 -8
  38. package/v3/dist/internal/inspection.js +1 -1
  39. package/v3/dist/internal/runtime.d.ts +87 -10
  40. package/v3/dist/internal/runtime.js +177 -61
  41. package/v3/dist/internal/transition.d.ts +13 -12
  42. package/v3/dist/internal/transition.js +14 -16
  43. package/v3/dist/internal/utils.js +5 -1
  44. package/v3/dist/machine.d.ts +158 -143
  45. package/v3/dist/machine.js +148 -155
  46. package/v3/dist/schema.d.ts +25 -11
  47. package/v3/dist/schema.js +18 -5
  48. package/v3/dist/slot.d.ts +112 -86
  49. package/v3/dist/slot.js +92 -59
  50. package/v3/dist/supervision.d.ts +97 -0
  51. package/v3/dist/supervision.js +42 -0
  52. package/v3/dist/testing.d.ts +21 -12
  53. package/v3/dist/testing.js +23 -24
package/dist/machine.d.ts CHANGED
@@ -1,15 +1,16 @@
1
- import { EffectHandlers, EffectSlots, EffectsDef, EffectsSchema, GuardHandlers, GuardSlots, GuardsDef, GuardsSchema, MachineContext } from "./slot.js";
2
1
  import { DeferReplyResult, ReplyResult, TransitionResult } from "./internal/utils.js";
3
2
  import { BrandedEvent, BrandedState, ExtractReply, TaggedOrConstructor } from "./internal/brands.js";
4
3
  import { MachineEventSchema, MachineStateSchema, VariantsUnion } from "./schema.js";
5
4
  import { DuplicateActorError } from "./errors.js";
5
+ import { MachineContext, ProvideSlots, SlotCalls, SlotsDef, SlotsSchema } from "./slot.js";
6
+ import { Supervision } from "./supervision.js";
6
7
  import { findTransitions } from "./internal/transition.js";
7
8
  import { ActorRef, ActorSystem } from "./actor.js";
8
- import { Cause, Duration, Effect, Schema, Scope, ServiceMap } from "effect";
9
+ import { Cause, Duration, Effect, Option, Schema, Scope, ServiceMap } from "effect";
9
10
 
10
11
  //#region src/machine.d.ts
11
12
  declare namespace machine_d_exports {
12
- export { BackgroundEffect, BuiltMachine, DeferReplyResult, HandlerContext, Machine, MachineRef, MakeConfig, ProvideHandlers, ReplyResult, SlotContext, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, TransitionHandler, deferReply, findTransitions, make, replay, reply, spawn };
13
+ export { BackgroundEffect, DeferReplyResult, HandlerContext, Machine, MachineRef, MakeConfig, PersistConfig, ReplyResult, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, TransitionHandler, deferReply, 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: BuiltMachine<S2, E2, R2>) => Effect.Effect<ActorRef<S2, E2>, DuplicateActorError, R2>;
26
+ }, R2>(id: string, machine: Machine<S2, E2, R2, any, any, any>) => Effect.Effect<ActorRef<S2, E2>, DuplicateActorError, R2>;
26
27
  /**
27
28
  * Settle a deferred reply from a spawn handler.
28
29
  * Only usable when the transition handler returned `Machine.deferReply(state)`.
@@ -33,21 +34,20 @@ interface MachineRef<Event> {
33
34
  /**
34
35
  * Handler context passed to transition handlers
35
36
  */
36
- interface HandlerContext<State, Event, GD extends GuardsDef, ED extends EffectsDef> {
37
+ interface HandlerContext<State, Event, SD extends SlotsDef = Record<string, never>> {
37
38
  readonly state: State;
38
39
  readonly event: Event;
39
- readonly guards: GuardSlots<GD>;
40
- readonly effects: EffectSlots<ED>;
40
+ readonly slots: SlotCalls<SD>;
41
41
  }
42
42
  /**
43
43
  * Handler context passed to state effect handlers (onEnter, spawn, background)
44
44
  */
45
- interface StateHandlerContext<State, Event, ED extends EffectsDef> {
45
+ interface StateHandlerContext<State, Event, SD extends SlotsDef = Record<string, never>> {
46
46
  readonly actorId: string;
47
47
  readonly state: State;
48
48
  readonly event: Event;
49
49
  readonly self: MachineRef<Event>;
50
- readonly effects: EffectSlots<ED>;
50
+ readonly slots: SlotCalls<SD>;
51
51
  readonly system: ActorSystem;
52
52
  }
53
53
  /**
@@ -55,38 +55,66 @@ interface StateHandlerContext<State, Event, ED extends EffectsDef> {
55
55
  * When Reply is concrete (event has a reply schema), handler must return Machine.reply().
56
56
  * When Reply is never, handler returns plain state.
57
57
  */
58
- type TransitionHandler<S, E, NewState, GD extends GuardsDef, ED extends EffectsDef, R, Reply = never> = (ctx: HandlerContext<S, E, GD, ED>) => TransitionResult<NewState, R, Reply>;
58
+ type TransitionHandler<S, E, NewState, SD extends SlotsDef, R, Reply = never> = (ctx: HandlerContext<S, E, SD>) => TransitionResult<NewState, R, Reply>;
59
59
  /**
60
60
  * State effect handler function
61
61
  */
62
- type StateEffectHandler<S, E, ED extends EffectsDef, R> = (ctx: StateHandlerContext<S, E, ED>) => Effect.Effect<void, never, R>;
62
+ type StateEffectHandler<S, E, SD extends SlotsDef, R> = (ctx: StateHandlerContext<S, E, SD>) => Effect.Effect<void, never, R>;
63
63
  /**
64
64
  * Transition definition
65
65
  */
66
- interface Transition<State, Event, GD extends GuardsDef, ED extends EffectsDef, R> {
66
+ interface Transition<State, Event, SD extends SlotsDef, R> {
67
67
  readonly stateTag: string;
68
68
  readonly eventTag: string;
69
- readonly handler: TransitionHandler<State, Event, State, GD, ED, R>;
69
+ readonly handler: TransitionHandler<State, Event, State, SD, R>;
70
70
  readonly reenter?: boolean;
71
71
  }
72
72
  /**
73
73
  * Spawn effect - state-scoped forked effect
74
74
  */
75
- interface SpawnEffect<State, Event, ED extends EffectsDef, R> {
75
+ interface SpawnEffect<State, Event, SD extends SlotsDef, R> {
76
76
  readonly stateTag: string;
77
- readonly handler: StateEffectHandler<State, Event, ED, R>;
77
+ readonly handler: StateEffectHandler<State, Event, SD, R>;
78
78
  }
79
79
  /**
80
80
  * Background effect - runs for entire machine lifetime
81
81
  */
82
- interface BackgroundEffect<State, Event, ED extends EffectsDef, R> {
83
- readonly handler: StateEffectHandler<State, Event, ED, R>;
82
+ interface BackgroundEffect<State, Event, SD extends SlotsDef, R> {
83
+ readonly handler: StateEffectHandler<State, Event, SD, R>;
84
84
  }
85
- interface TaskOptions<State, Event, ED extends EffectsDef, A, E1, ES, EF> {
86
- readonly onSuccess: (value: A, ctx: StateHandlerContext<State, Event, ED>) => ES;
87
- readonly onFailure?: (cause: Cause.Cause<E1>, ctx: StateHandlerContext<State, Event, ED>) => EF;
85
+ interface TaskOptions<State, Event, SD extends SlotsDef, A, E1, ES, EF> {
86
+ readonly onSuccess?: (value: A, ctx: StateHandlerContext<State, Event, SD>) => ES;
87
+ readonly onFailure?: (cause: Cause.Cause<E1>, ctx: StateHandlerContext<State, Event, SD>) => EF;
88
88
  readonly name?: string;
89
89
  }
90
+ /**
91
+ * Local persistence configuration for Machine.spawn.
92
+ *
93
+ * Fully-resolved callbacks — no service dependency.
94
+ * Separate from cluster EntityPersistence which uses a service-based adapter.
95
+ */
96
+ interface PersistConfig<S> {
97
+ /** Load saved state on actor start (and restart). Returns None for cold start. */
98
+ readonly load: () => Effect.Effect<Option.Option<S>>;
99
+ /** Save state after each transition. Runs inline (blocks next event). */
100
+ readonly save: (state: S) => Effect.Effect<void>;
101
+ /** Optional filter — return false to skip saving for this transition. */
102
+ readonly shouldSave?: (state: S, previousState: S) => boolean;
103
+ /**
104
+ * Called after load() returns Some(state). Inspect the restored state
105
+ * and decide how to proceed before the machine starts.
106
+ *
107
+ * Return Some(state) to use that state, or None to discard and start fresh.
108
+ * Called on both initial spawn and supervision restart.
109
+ * Receives `initial` (machine.initial) for comparison.
110
+ *
111
+ * Use cases: validate persisted state against external systems,
112
+ * migrate schema changes, downgrade to a safe state on partial corruption.
113
+ */
114
+ readonly onRestore?: (state: S, context: {
115
+ readonly initial: S;
116
+ }) => Effect.Effect<Option.Option<S>>;
117
+ }
90
118
  /**
91
119
  * Configuration for `.timeout()` — gen_statem-style state timeouts.
92
120
  *
@@ -99,44 +127,26 @@ interface TimeoutConfig<State, Event> {
99
127
  /** Event to send when the timer fires. Static or derived from current state. */
100
128
  readonly event: Event | ((state: State) => Event);
101
129
  }
102
- type IsAny<T> = 0 extends 1 & T ? true : false;
103
- type IsUnknown<T> = unknown extends T ? ([T] extends [unknown] ? true : false) : false;
104
- type NormalizeR<T> = IsAny<T> extends true ? T : IsUnknown<T> extends true ? never : T;
105
- 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> {
130
+ interface MakeConfig<SD extends Record<string, Schema.Struct.Fields>, ED extends Record<string, Schema.Struct.Fields>, S extends BrandedState, E extends BrandedEvent, SLD extends SlotsDef = Record<string, never>> {
106
131
  readonly state: MachineStateSchema<SD> & {
107
132
  Type: S;
108
133
  };
109
134
  readonly event: MachineEventSchema<ED> & {
110
135
  Type: E;
111
136
  };
112
- readonly guards?: GuardsSchema<GD>;
113
- readonly effects?: EffectsSchema<EFD>;
137
+ readonly slots?: SlotsSchema<SLD>;
114
138
  readonly initial: S;
139
+ /** Validate slot inputs/outputs at runtime. Default: true. Set to false for hot paths. */
140
+ readonly slotValidation?: boolean;
115
141
  }
116
- /** Check if a GuardsDef has any actual keys */
117
- type HasGuardKeys<GD extends GuardsDef> = [keyof GD] extends [never] ? false : GD extends Record<string, never> ? false : true;
118
- /** Check if an EffectsDef has any actual keys */
119
- type HasEffectKeys<EFD extends EffectsDef> = [keyof EFD] extends [never] ? false : EFD extends Record<string, never> ? false : true;
120
- /** Context type passed to guard/effect handlers */
121
- type SlotContext<State, Event> = MachineContext<State, Event, MachineRef<Event>>;
122
- /** Combined handlers for build() - guards and effects only */
123
- 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);
124
- /** Whether the machine has any guard or effect slots */
125
- type HasSlots<GD extends GuardsDef, EFD extends EffectsDef> = HasGuardKeys<GD> extends true ? true : HasEffectKeys<EFD>;
126
142
  /**
127
- * A finalized machine ready for spawning.
143
+ * Bind slot handlers to a machine, returning a fresh copy with handlers installed.
144
+ * If no handlers provided and machine has no slots, returns the machine as-is.
145
+ * Validates that all required slots are provided and no extra slots are given.
128
146
  *
129
- * Created by calling `.build()` on a `Machine`. This is the only type
130
- * accepted by `Machine.spawn` and `ActorSystem.spawn` (regular overload).
131
- * Testing utilities (`simulate`, `createTestHarness`, etc.) still accept `Machine`.
147
+ * @internal used by spawn, replay, simulate, test harness, entity-machine
132
148
  */
133
- declare class BuiltMachine<State, Event, R = never> {
134
- /** @internal */
135
- readonly _inner: Machine<State, Event, R, any, any, any, any>;
136
- /** @internal */
137
- constructor(machine: Machine<State, Event, R, any, any, any, any>);
138
- get initial(): State;
139
- }
149
+ declare const materializeMachine: <S, E, R, SD extends SlotsDef>(machine: Machine<S, E, R, any, any, SD>, handlers?: Record<string, any>) => Machine<S, E, never, any, any, SD>;
140
150
  /**
141
151
  * Machine definition with fluent builder API.
142
152
  *
@@ -146,17 +156,16 @@ declare class BuiltMachine<State, Event, R = never> {
146
156
  * - `R`: Effect requirements
147
157
  * - `_SD`: State schema definition (for compile-time validation)
148
158
  * - `_ED`: Event schema definition (for compile-time validation)
149
- * - `GD`: Guard definitions
150
- * - `EFD`: Effect definitions
159
+ * - `SD`: Slot definitions
151
160
  */
152
- declare class Machine<State, Event, R = never, _SD extends Record<string, Schema.Struct.Fields> = Record<string, Schema.Struct.Fields>, _ED extends Record<string, Schema.Struct.Fields> = Record<string, Schema.Struct.Fields>, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>> {
161
+ declare class Machine<State, Event, R = never, _SD extends Record<string, Schema.Struct.Fields> = Record<string, Schema.Struct.Fields>, _ED extends Record<string, Schema.Struct.Fields> = Record<string, Schema.Struct.Fields>, SD extends SlotsDef = Record<string, never>> {
153
162
  readonly initial: State;
154
163
  /** @internal */
155
- readonly _transitions: Array<Transition<State, Event, GD, EFD, R>>;
164
+ readonly _transitions: Array<Transition<State, Event, SD, R>>;
156
165
  /** @internal */
157
- readonly _spawnEffects: Array<SpawnEffect<State, Event, EFD, R>>;
166
+ readonly _spawnEffects: Array<SpawnEffect<State, Event, SD, R>>;
158
167
  /** @internal */
159
- readonly _backgroundEffects: Array<BackgroundEffect<State, Event, EFD, R>>;
168
+ readonly _backgroundEffects: Array<BackgroundEffect<State, Event, SD, R>>;
160
169
  /** @internal */
161
170
  readonly _finalStates: Set<string>;
162
171
  /** @internal */
@@ -165,18 +174,13 @@ declare class Machine<State, Event, R = never, _SD extends Record<string, Schema
165
174
  readonly eventTag: string;
166
175
  }>;
167
176
  /** @internal */
168
- readonly _guardsSchema?: GuardsSchema<GD>;
169
- /** @internal */
170
- readonly _effectsSchema?: EffectsSchema<EFD>;
177
+ readonly _slotsSchema?: SlotsSchema<SD>;
171
178
  /** @internal */
172
- readonly _guardHandlers: Map<string, (params: unknown, ctx: SlotContext<State, Event>) => boolean | Effect.Effect<boolean, never, R>>;
179
+ readonly _slotHandlers: Map<string, (params: unknown) => unknown | Effect.Effect<unknown, never, R>>;
173
180
  /** @internal */
174
- readonly _effectHandlers: Map<string, (params: unknown, ctx: SlotContext<State, Event>) => Effect.Effect<void, never, R>>;
181
+ readonly _slots: SlotCalls<SD>;
175
182
  /** @internal */
176
- readonly _slots: {
177
- guards: GuardSlots<GD>;
178
- effects: EffectSlots<EFD>;
179
- };
183
+ readonly _slotValidation: boolean;
180
184
  readonly stateSchema?: Schema.Schema<State>;
181
185
  readonly eventSchema?: Schema.Schema<Event>;
182
186
  /** @internal */
@@ -186,70 +190,72 @@ declare class Machine<State, Event, R = never, _SD extends Record<string, Schema
186
190
  * Uses shared module-level tag for all machines.
187
191
  */
188
192
  readonly Context: ServiceMap.Service<MachineContext<State, Event, MachineRef<Event>>, MachineContext<State, Event, MachineRef<Event>>>;
189
- get transitions(): ReadonlyArray<Transition<State, Event, GD, EFD, R>>;
190
- get spawnEffects(): ReadonlyArray<SpawnEffect<State, Event, EFD, R>>;
191
- get backgroundEffects(): ReadonlyArray<BackgroundEffect<State, Event, EFD, R>>;
193
+ get transitions(): ReadonlyArray<Transition<State, Event, SD, R>>;
194
+ get spawnEffects(): ReadonlyArray<SpawnEffect<State, Event, SD, R>>;
195
+ get backgroundEffects(): ReadonlyArray<BackgroundEffect<State, Event, SD, R>>;
192
196
  get finalStates(): ReadonlySet<string>;
193
197
  get postponeRules(): ReadonlyArray<{
194
198
  readonly stateTag: string;
195
199
  readonly eventTag: string;
196
200
  }>;
197
- get guardsSchema(): GuardsSchema<GD> | undefined;
198
- get effectsSchema(): EffectsSchema<EFD> | undefined;
201
+ get slotsSchema(): SlotsSchema<SD> | undefined;
199
202
  get replySchemas(): ReadonlyMap<string, Schema.Decoder<unknown>>;
200
203
  /** @internal */
201
- constructor(initial: State, stateSchema?: Schema.Schema<State>, eventSchema?: Schema.Schema<Event>, guardsSchema?: GuardsSchema<GD>, effectsSchema?: EffectsSchema<EFD>);
202
- 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>;
203
- 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>;
204
+ constructor(initial: State, stateSchema?: Schema.Schema<State>, eventSchema?: Schema.Schema<Event>, slotsSchema?: SlotsSchema<SD>, slotValidation?: boolean);
205
+ from<NS extends VariantsUnion<_SD> & BrandedState, R1>(state: TaggedOrConstructor<NS>, build: (scope: TransitionScope<State, Event, R, _SD, _ED, SD, NS>) => R1): Machine<State, Event, R, _SD, _ED, SD>;
206
+ from<NS extends ReadonlyArray<TaggedOrConstructor<VariantsUnion<_SD> & BrandedState>>, R1>(states: NS, build: (scope: TransitionScope<State, Event, R, _SD, _ED, SD, NS[number] extends TaggedOrConstructor<infer S extends VariantsUnion<_SD> & BrandedState> ? S : never>) => R1): Machine<State, Event, R, _SD, _ED, SD>;
204
207
  /** @internal */
205
- 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>;
208
+ 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, SD, never, ExtractReply<NE>>, reenter: boolean): Machine<State, Event, R, _SD, _ED, SD>;
206
209
  /** Register transition for a single state */
207
- 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>;
210
+ 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, SD, never, ExtractReply<NE>>): Machine<State, Event, R, _SD, _ED, SD>;
208
211
  /** Register transition for multiple states (handler receives union of state types) */
209
- 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>;
212
+ 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, SD, never, ExtractReply<NE>>): Machine<State, Event, R, _SD, _ED, SD>;
210
213
  /**
211
214
  * Like `on()`, but forces onEnter/spawn to run even when transitioning to the same state tag.
212
215
  * Use this to restart timers, re-run spawned effects, or reset state-scoped effects.
213
216
  */
214
217
  /** Single state */
215
- 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>;
218
+ 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, SD, never, ExtractReply<NE>>): Machine<State, Event, R, _SD, _ED, SD>;
216
219
  /** Multiple states */
217
- 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>;
220
+ 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, SD, never, ExtractReply<NE>>): Machine<State, Event, R, _SD, _ED, SD>;
218
221
  /**
219
222
  * Register a wildcard transition that fires from any state when no specific transition matches.
220
223
  * Specific `.on()` transitions always take priority over `.onAny()`.
221
224
  */
222
- onAny<NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(event: TaggedOrConstructor<NE>, handler: TransitionHandler<VariantsUnion<_SD> & BrandedState, NE, RS, GD, EFD, never>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
225
+ onAny<NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(event: TaggedOrConstructor<NE>, handler: TransitionHandler<VariantsUnion<_SD> & BrandedState, NE, RS, SD, never>): Machine<State, Event, R, _SD, _ED, SD>;
223
226
  /** @internal */
224
227
  private addTransition;
225
228
  /**
226
229
  * State-scoped effect that is forked on state entry and automatically cancelled on state exit.
227
- * Use effect slots defined via `Slot.Effects` for the actual work.
228
230
  *
229
231
  * @example
230
232
  * ```ts
231
- * const MyEffects = Slot.Effects({
232
- * fetchData: { url: Schema.String },
233
- * });
234
- *
235
- * machine
236
- * .spawn(State.Loading, ({ effects, state }) => effects.fetchData({ url: state.url }))
237
- * .build({
238
- * fetchData: ({ url }, { self }) =>
239
- * Effect.gen(function* () {
240
- * yield* Effect.addFinalizer(() => Effect.log("Leaving Loading"));
241
- * const data = yield* Http.get(url);
242
- * yield* self.send(Event.Loaded({ data }));
243
- * }),
244
- * });
233
+ * machine.spawn(State.Loading, ({ self, state }) =>
234
+ * Effect.gen(function* () {
235
+ * yield* Effect.addFinalizer(() => Effect.log("Leaving Loading"));
236
+ * const data = yield* Http.get(state.url);
237
+ * yield* self.send(Event.Loaded({ data }));
238
+ * }),
239
+ * );
245
240
  * ```
246
241
  */
247
- spawn<NS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>, handler: StateEffectHandler<NS, VariantsUnion<_ED> & BrandedEvent, EFD, Scope.Scope>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
242
+ /** Single state */
243
+ spawn<NS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>, handler: StateEffectHandler<NS, VariantsUnion<_ED> & BrandedEvent, SD, Scope.Scope>): Machine<State, Event, R, _SD, _ED, SD>;
244
+ /** Multiple states */
245
+ spawn<NS extends ReadonlyArray<TaggedOrConstructor<VariantsUnion<_SD> & BrandedState>>>(states: NS, handler: StateEffectHandler<NS[number] extends TaggedOrConstructor<infer S> ? S : never, VariantsUnion<_ED> & BrandedEvent, SD, Scope.Scope>): Machine<State, Event, R, _SD, _ED, SD>;
248
246
  /**
249
247
  * State-scoped task that runs on entry and sends success/failure events.
250
248
  * Interrupts do not emit failure events.
249
+ *
250
+ * Supports multi-state and shorthand overloads:
251
+ * - `.task(State.X, run, { onSuccess, onFailure })` — explicit mapping
252
+ * - `.task(State.X, run, { onFailure })` — shorthand when run returns Event directly
253
+ * - `.task([State.X, State.Y], run, opts)` — multi-state
251
254
  */
252
- task<NS extends VariantsUnion<_SD> & BrandedState, A, E1, ES extends VariantsUnion<_ED> & BrandedEvent, EF extends VariantsUnion<_ED> & BrandedEvent>(state: TaggedOrConstructor<NS>, run: (ctx: StateHandlerContext<NS, VariantsUnion<_ED> & BrandedEvent, EFD>) => Effect.Effect<A, E1, Scope.Scope>, options: TaskOptions<NS, VariantsUnion<_ED> & BrandedEvent, EFD, A, E1, ES, EF>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
255
+ /** Single state onSuccess optional (defaults to identity when task returns Event) */
256
+ task<NS extends VariantsUnion<_SD> & BrandedState, A, E1, ES extends VariantsUnion<_ED> & BrandedEvent, EF extends VariantsUnion<_ED> & BrandedEvent>(state: TaggedOrConstructor<NS>, run: (ctx: StateHandlerContext<NS, VariantsUnion<_ED> & BrandedEvent, SD>) => Effect.Effect<A, E1, Scope.Scope>, options: TaskOptions<NS, VariantsUnion<_ED> & BrandedEvent, SD, A, E1, ES, EF>): Machine<State, Event, R, _SD, _ED, SD>;
257
+ /** Multiple states, explicit onSuccess */
258
+ task<NS extends ReadonlyArray<TaggedOrConstructor<VariantsUnion<_SD> & BrandedState>>, A, E1, ES extends VariantsUnion<_ED> & BrandedEvent, EF extends VariantsUnion<_ED> & BrandedEvent>(states: NS, run: (ctx: StateHandlerContext<NS[number] extends TaggedOrConstructor<infer S> ? S : never, VariantsUnion<_ED> & BrandedEvent, SD>) => Effect.Effect<A, E1, Scope.Scope>, options: TaskOptions<NS[number] extends TaggedOrConstructor<infer S> ? S : never, VariantsUnion<_ED> & BrandedEvent, SD, A, E1, ES, EF>): Machine<State, Event, R, _SD, _ED, SD>;
253
259
  /**
254
260
  * State timeout — gen_statem's `state_timeout`.
255
261
  *
@@ -271,28 +277,20 @@ declare class Machine<State, Event, R = never, _SD extends Record<string, Schema
271
277
  * })
272
278
  * ```
273
279
  */
274
- timeout<NS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>, config: TimeoutConfig<NS, VariantsUnion<_ED> & BrandedEvent>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
280
+ timeout<NS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>, config: TimeoutConfig<NS, VariantsUnion<_ED> & BrandedEvent>): Machine<State, Event, R, _SD, _ED, SD>;
275
281
  /**
276
282
  * Machine-lifetime effect that is forked on actor spawn and runs until the actor stops.
277
- * Use effect slots defined via `Slot.Effects` for the actual work.
278
283
  *
279
284
  * @example
280
285
  * ```ts
281
- * const MyEffects = Slot.Effects({
282
- * heartbeat: {},
283
- * });
284
- *
285
- * machine
286
- * .background(({ effects }) => effects.heartbeat())
287
- * .build({
288
- * heartbeat: (_, { self }) =>
289
- * Effect.forever(
290
- * Effect.sleep("30 seconds").pipe(Effect.andThen(self.send(Event.Ping)))
291
- * ),
292
- * });
286
+ * machine.background(({ self }) =>
287
+ * Effect.forever(
288
+ * Effect.sleep("30 seconds").pipe(Effect.andThen(self.send(Event.Ping))),
289
+ * ),
290
+ * );
293
291
  * ```
294
292
  */
295
- background(handler: StateEffectHandler<State, Event, EFD, Scope.Scope>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
293
+ background(handler: StateEffectHandler<State, Event, SD, Scope.Scope>): Machine<State, Event, R, _SD, _ED, SD>;
296
294
  /**
297
295
  * Postpone events — gen_statem's event postpone.
298
296
  *
@@ -310,54 +308,64 @@ declare class Machine<State, Event, R = never, _SD extends Record<string, Schema
310
308
  * .postpone(State.Connecting, [Event.Data, Event.Cmd]) // multiple events
311
309
  * ```
312
310
  */
313
- 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>;
314
- final<NS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
315
- /**
316
- * Finalize the machine. Returns a `BuiltMachine` — the only type accepted by `Machine.spawn`.
317
- *
318
- * - Machines with slots: pass implementations as the first argument.
319
- * - Machines without slots: call with no arguments.
320
- */
321
- 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>>;
322
- 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>;
311
+ 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, SD>;
312
+ final<NS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>): Machine<State, Event, R, _SD, _ED, SD>;
313
+ static make<SD extends Record<string, Schema.Struct.Fields>, ED extends Record<string, Schema.Struct.Fields>, S extends BrandedState, E extends BrandedEvent, SLD extends SlotsDef = Record<string, never>>(config: MakeConfig<SD, ED, S, E, SLD>): Machine<S, E, never, SD, ED, SLD>;
323
314
  }
324
- 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> {
315
+ declare class TransitionScope<State, Event, R, _SD extends Record<string, Schema.Struct.Fields>, _ED extends Record<string, Schema.Struct.Fields>, SD extends SlotsDef, SelectedState extends VariantsUnion<_SD> & BrandedState> {
325
316
  private readonly machine;
326
317
  private readonly states;
327
- constructor(machine: Machine<State, Event, R, _SD, _ED, GD, EFD>, states: ReadonlyArray<TaggedOrConstructor<SelectedState>>);
328
- 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>;
329
- 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>;
318
+ constructor(machine: Machine<State, Event, R, _SD, _ED, SD>, states: ReadonlyArray<TaggedOrConstructor<SelectedState>>);
319
+ on<NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(event: TaggedOrConstructor<NE>, handler: TransitionHandler<SelectedState, NE, RS, SD, never, ExtractReply<NE>>): TransitionScope<State, Event, R, _SD, _ED, SD, SelectedState>;
320
+ reenter<NE extends VariantsUnion<_ED> & BrandedEvent, RS extends VariantsUnion<_SD> & BrandedState>(event: TaggedOrConstructor<NE>, handler: TransitionHandler<SelectedState, NE, RS, SD, never, ExtractReply<NE>>): TransitionScope<State, Event, R, _SD, _ED, SD, SelectedState>;
330
321
  }
331
322
  declare const make: typeof Machine.make;
332
323
  /**
333
- * Spawn an actor from a built machine.
324
+ * Spawn an actor from a machine.
334
325
  *
335
- * Options:
336
- * - `id` — custom actor ID (default: random)
337
- * - `hydrate` — restore from a previously-saved state snapshot.
338
- * The actor starts in the hydrated state and re-runs spawn effects
339
- * for that state (timers, scoped resources, etc.). Transition history
340
- * is not replayed — only the current state's entry effects run.
326
+ * For machines with slots, pass implementations via `{ slots: { ... } }`.
341
327
  *
342
- * Persistence is composed in userland by observing `actor.changes`
343
- * and saving snapshots to your own storage.
328
+ * @example
329
+ * ```ts
330
+ * // No slots
331
+ * const actor = yield* Machine.spawn(machine);
332
+ *
333
+ * // With slots
334
+ * const actor = yield* Machine.spawn(machine, {
335
+ * slots: { canRetry: ({ max }) => attempts < max },
336
+ * });
337
+ *
338
+ * // With persistence
339
+ * const actor = yield* Machine.spawn(machine, {
340
+ * persist: {
341
+ * load: () => storage.get("actor-state"),
342
+ * save: (state) => storage.set("actor-state", state),
343
+ * },
344
+ * });
345
+ * ```
344
346
  */
345
347
  declare const spawn: <S extends {
346
348
  readonly _tag: string;
347
349
  }, E extends {
348
350
  readonly _tag: string;
349
- }, R>(machine: BuiltMachine<S, E, R>, idOrOptions?: string | {
351
+ }, R, SD extends SlotsDef = Record<string, never>>(machine: Machine<S, E, R, any, any, SD>, options?: string | {
350
352
  id?: string;
351
353
  hydrate?: S;
354
+ slots?: ProvideSlots<SD, any>;
355
+ supervision?: Supervision.Policy;
356
+ persist?: PersistConfig<S>;
352
357
  }) => Effect.Effect<ActorRef<S, E>, never, R>;
353
- declare const replay: <S extends {
354
- readonly _tag: string;
355
- }, E extends {
356
- readonly _tag: string;
357
- }, R>(machine: BuiltMachine<S, E, R>, events: ReadonlyArray<E>, options?: {
358
- from?: S;
359
- }) => Effect.Effect<S, never, R>;
358
+ declare const replay: {
359
+ <S extends {
360
+ readonly _tag: string;
361
+ }, E extends {
362
+ readonly _tag: string;
363
+ }, R, SD extends SlotsDef = Record<string, never>>(machine: Machine<S, E, R, any, any, SD>, events: ReadonlyArray<E>, options?: {
364
+ from?: S;
365
+ slots?: ProvideSlots<SD, any>;
366
+ }): Effect.Effect<S, never, R>;
367
+ };
360
368
  declare const reply: <State, Reply>(state: State, reply: Reply) => ReplyResult<State, Reply>;
361
369
  declare const deferReply: <State>(state: State) => DeferReplyResult<State>;
362
370
  //#endregion
363
- export { BackgroundEffect, BuiltMachine, type DeferReplyResult, HandlerContext, Machine, MachineRef, MakeConfig, ProvideHandlers, type ReplyResult, SlotContext, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, TransitionHandler, deferReply, findTransitions, machine_d_exports, make, replay, reply, spawn };
371
+ export { BackgroundEffect, type DeferReplyResult, HandlerContext, Machine, MachineRef, MakeConfig, PersistConfig, type ReplyResult, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, TransitionHandler, deferReply, findTransitions, machine_d_exports, make, materializeMachine, replay, reply, spawn };