effect-machine 0.14.0 → 0.15.1

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.
@@ -10,7 +10,7 @@ import { Cause, Context, Duration, Effect, Option, Schema, Scope } from "effect"
10
10
 
11
11
  //#region src/machine.d.ts
12
12
  declare namespace machine_d_exports {
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
+ export { BackgroundEffect, DeferReplyResult, Durability, DurabilityCommit, HandlerContext, Lifecycle, Machine, MachineRef, MakeConfig, Recovery, RecoveryContext, ReplyResult, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, TransitionHandler, deferReply, findTransitions, make, materializeMachine, replay, reply, spawn };
14
14
  }
15
15
  /**
16
16
  * Self reference for sending events back to the machine
@@ -88,32 +88,39 @@ interface TaskOptions<State, Event, SD extends SlotsDef, A, E1, ES, EF> {
88
88
  readonly name?: string;
89
89
  }
90
90
  /**
91
- * Local persistence configuration for Machine.spawn.
91
+ * Recovery resolves the initial state for a generation. Runs during actor.start.
92
92
  *
93
- * Fully-resolved callbacks no service dependency.
94
- * Separate from cluster EntityPersistence which uses a service-based adapter.
93
+ * For initial start (generation 0): loads persisted state.
94
+ * For supervision restart (generation 1+): reloads state after crash.
95
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. */
96
+ interface Recovery<S> {
97
+ readonly resolve: (ctx: RecoveryContext<S>) => Effect.Effect<Option.Option<S>>;
98
+ }
99
+ interface RecoveryContext<S> {
100
+ readonly actorId: string;
101
+ readonly generation: number;
102
+ readonly machineInitial: S;
103
+ }
104
+ /**
105
+ * Durability saves state after committed transitions. Runs during runtime.
106
+ */
107
+ interface Durability<S, E> {
108
+ readonly save: (commit: DurabilityCommit<S, E>) => Effect.Effect<void>;
102
109
  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>>;
110
+ }
111
+ interface DurabilityCommit<S, E> {
112
+ readonly actorId: string;
113
+ readonly generation: number;
114
+ readonly previousState: S;
115
+ readonly nextState: S;
116
+ readonly event: E;
117
+ }
118
+ /**
119
+ * Actor lifecycle configuration.
120
+ */
121
+ interface Lifecycle<S, E> {
122
+ readonly recovery?: Recovery<S>;
123
+ readonly durability?: Durability<S, E>;
117
124
  }
118
125
  /**
119
126
  * Configuration for `.timeout()` — gen_statem-style state timeouts.
@@ -335,11 +342,11 @@ declare const make: typeof Machine.make;
335
342
  * slots: { canRetry: ({ max }) => attempts < max },
336
343
  * });
337
344
  *
338
- * // With persistence
345
+ * // With lifecycle (recovery + durability)
339
346
  * const actor = yield* Machine.spawn(machine, {
340
- * persist: {
341
- * load: () => storage.get("actor-state"),
342
- * save: (state) => storage.set("actor-state", state),
347
+ * lifecycle: {
348
+ * recovery: { resolve: ({ machineInitial }) => storage.get("actor-state") },
349
+ * durability: { save: ({ nextState }) => storage.set("actor-state", nextState) },
343
350
  * },
344
351
  * });
345
352
  * ```
@@ -353,7 +360,7 @@ declare const spawn: <S extends {
353
360
  hydrate?: S;
354
361
  slots?: ProvideSlots<SD, any>;
355
362
  supervision?: Supervision.Policy;
356
- persist?: PersistConfig<S>;
363
+ lifecycle?: Lifecycle<S, E>;
357
364
  }) => Effect.Effect<ActorRef<S, E>, never, R>;
358
365
  declare const replay: {
359
366
  <S extends {
@@ -368,4 +375,4 @@ declare const replay: {
368
375
  declare const reply: <State, Reply>(state: State, reply: Reply) => ReplyResult<State, Reply>;
369
376
  declare const deferReply: <State>(state: State) => DeferReplyResult<State>;
370
377
  //#endregion
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 };
378
+ export { BackgroundEffect, type DeferReplyResult, Durability, DurabilityCommit, HandlerContext, Lifecycle, Machine, MachineRef, MakeConfig, Recovery, RecoveryContext, type ReplyResult, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, TransitionHandler, deferReply, findTransitions, machine_d_exports, make, materializeMachine, replay, reply, spawn };
@@ -395,11 +395,11 @@ const make = Machine.make;
395
395
  * slots: { canRetry: ({ max }) => attempts < max },
396
396
  * });
397
397
  *
398
- * // With persistence
398
+ * // With lifecycle (recovery + durability)
399
399
  * const actor = yield* Machine.spawn(machine, {
400
- * persist: {
401
- * load: () => storage.get("actor-state"),
402
- * save: (state) => storage.set("actor-state", state),
400
+ * lifecycle: {
401
+ * recovery: { resolve: ({ machineInitial }) => storage.get("actor-state") },
402
+ * durability: { save: ({ nextState }) => storage.set("actor-state", nextState) },
403
403
  * },
404
404
  * });
405
405
  * ```
@@ -409,7 +409,7 @@ const spawn = Effect.fn("effect-machine.spawn")(function* (machine, idOrOptions)
409
409
  const actor = yield* createActor(opts?.id ?? `actor-${(yield* Random.next).toString(36).slice(2)}`, materializeMachine(machine, opts?.slots), {
410
410
  initialState: opts?.hydrate,
411
411
  supervision: opts?.supervision,
412
- persist: opts?.persist
412
+ lifecycle: opts?.lifecycle
413
413
  });
414
414
  const maybeScope = yield* Effect.serviceOption(Scope.Scope);
415
415
  if (Option.isSome(maybeScope)) yield* Scope.addFinalizer(maybeScope.value, actor.stop);