effect-machine 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.
Files changed (49) hide show
  1. package/README.md +19 -11
  2. package/dist/actor.d.ts +18 -6
  3. package/dist/actor.js +151 -61
  4. package/dist/cluster/entity-machine.d.ts +1 -1
  5. package/dist/cluster/entity-machine.js +2 -1
  6. package/dist/cluster/to-entity.d.ts +1 -1
  7. package/dist/errors.d.ts +9 -2
  8. package/dist/errors.js +8 -2
  9. package/dist/index.d.ts +4 -4
  10. package/dist/index.js +4 -4
  11. package/dist/internal/runtime.d.ts +21 -2
  12. package/dist/internal/runtime.js +64 -56
  13. package/dist/internal/transition.d.ts +9 -9
  14. package/dist/internal/transition.js +3 -5
  15. package/dist/machine.d.ts +129 -135
  16. package/dist/machine.js +97 -112
  17. package/dist/schema.d.ts +17 -1
  18. package/dist/schema.js +10 -0
  19. package/dist/slot.d.ts +112 -86
  20. package/dist/slot.js +92 -59
  21. package/dist/testing.d.ts +16 -16
  22. package/dist/testing.js +3 -3
  23. package/package.json +3 -3
  24. package/v3/dist/actor.d.ts +25 -12
  25. package/v3/dist/actor.js +174 -89
  26. package/v3/dist/cluster/entity-machine.d.ts +1 -1
  27. package/v3/dist/cluster/entity-machine.js +1 -0
  28. package/v3/dist/cluster/to-entity.d.ts +1 -1
  29. package/v3/dist/errors.d.ts +12 -3
  30. package/v3/dist/errors.js +10 -4
  31. package/v3/dist/index.d.ts +6 -6
  32. package/v3/dist/index.js +2 -2
  33. package/v3/dist/inspection.d.ts +3 -22
  34. package/v3/dist/inspection.js +1 -15
  35. package/v3/dist/internal/brands.d.ts +4 -8
  36. package/v3/dist/internal/inspection.js +1 -1
  37. package/v3/dist/internal/runtime.d.ts +27 -8
  38. package/v3/dist/internal/runtime.js +91 -61
  39. package/v3/dist/internal/transition.d.ts +10 -10
  40. package/v3/dist/internal/transition.js +8 -10
  41. package/v3/dist/internal/utils.js +5 -1
  42. package/v3/dist/machine.d.ts +160 -120
  43. package/v3/dist/machine.js +118 -115
  44. package/v3/dist/schema.d.ts +25 -11
  45. package/v3/dist/schema.js +18 -5
  46. package/v3/dist/slot.d.ts +112 -86
  47. package/v3/dist/slot.js +92 -59
  48. package/v3/dist/testing.d.ts +16 -16
  49. package/v3/dist/testing.js +7 -7
package/v3/dist/actor.js CHANGED
@@ -12,7 +12,7 @@ import { Cause, Context, Deferred, Effect, Exit, Fiber, Layer, MutableHashMap, O
12
12
  * Combines:
13
13
  * - ActorRef interface (running actor handle)
14
14
  * - ActorSystem service (spawn/stop/get actors)
15
- * - Actor creation (delegates to runtime kernel)
15
+ * - Actor creation and event loop
16
16
  */
17
17
  /**
18
18
  * ActorSystem service tag
@@ -29,7 +29,7 @@ const notifyListeners = (listeners, state) => {
29
29
  /**
30
30
  * Build core ActorRef methods.
31
31
  */
32
- const buildActorRefCore = (id, machine, stateRef, eventQueueRef, stoppedRef, listeners, stop, system, childrenMap, pendingReplies, transitionsPubSub, exitDeferred) => {
32
+ const buildActorRefCore = (id, machine, stateRef, eventQueueRef, stoppedRef, listeners, stop, start, system, childrenMap, pendingReplies, transitionsPubSub, exitDeferred) => {
33
33
  const send = Effect.fn("effect-machine.actor.send")(function* (event) {
34
34
  if (yield* Ref.get(stoppedRef)) return;
35
35
  const q = yield* Ref.get(eventQueueRef);
@@ -116,6 +116,7 @@ const buildActorRefCore = (id, machine, stateRef, eventQueueRef, stoppedRef, lis
116
116
  ask,
117
117
  state: stateRef,
118
118
  stop,
119
+ start,
119
120
  snapshot,
120
121
  matches,
121
122
  can,
@@ -163,60 +164,116 @@ const buildActorRefCore = (id, machine, stateRef, eventQueueRef, stoppedRef, lis
163
164
  children: childrenMap
164
165
  };
165
166
  };
167
+ /** Build ProcessEventHooks from an inspector */
168
+ const buildInspectionHooks = (actorId, inspector) => ({
169
+ onSpawnEffect: (state) => emitWithTimestamp(inspector, (timestamp) => ({
170
+ type: "@machine.effect",
171
+ actorId,
172
+ effectType: "spawn",
173
+ state,
174
+ timestamp
175
+ })),
176
+ onTransition: (from, to, ev) => emitWithTimestamp(inspector, (timestamp) => ({
177
+ type: "@machine.transition",
178
+ actorId,
179
+ fromState: from,
180
+ toState: to,
181
+ event: ev,
182
+ timestamp
183
+ })),
184
+ onError: (info) => emitWithTimestamp(inspector, (timestamp) => ({
185
+ type: "@machine.error",
186
+ actorId,
187
+ phase: info.phase,
188
+ state: info.state,
189
+ event: info.event,
190
+ error: Cause.pretty(info.cause),
191
+ timestamp
192
+ }))
193
+ });
194
+ /**
195
+ * Resolve actor system from context, creating an implicit one if none exists.
196
+ * @internal
197
+ */
198
+ const resolveActorSystem = Effect.fn("effect-machine.resolveActorSystem")(function* () {
199
+ const existingSystem = yield* Effect.serviceOption(ActorSystem);
200
+ if (Option.isSome(existingSystem)) return {
201
+ system: existingSystem.value,
202
+ implicitSystemScope: void 0
203
+ };
204
+ const scope = yield* Scope.make();
205
+ return {
206
+ system: yield* make().pipe(Effect.provideService(Scope.Scope, scope)),
207
+ implicitSystemScope: scope
208
+ };
209
+ });
210
+ /**
211
+ * Run the supervision loop for a supervised actor.
212
+ * Observes exit deferred, applies restart policy, resets cell resources on restart.
213
+ * @internal
214
+ */
215
+ const runSupervisionLoop = (params) => Effect.gen(function* () {
216
+ const driver = yield* Schedule.driver(params.supervision.schedule);
217
+ let generation = 0;
218
+ while (true) {
219
+ const currentRuntime = params.runtimeRef.current;
220
+ if (currentRuntime === void 0) return;
221
+ const generationExit = yield* Deferred.await(currentRuntime.exitDeferred);
222
+ if (generationExit._tag !== "Defect") {
223
+ yield* Deferred.succeed(params.terminalExitDeferred, generationExit);
224
+ return;
225
+ }
226
+ if (params.supervision.shouldRestart !== void 0 && !params.supervision.shouldRestart(generationExit)) {
227
+ yield* Deferred.succeed(params.terminalExitDeferred, generationExit);
228
+ return;
229
+ }
230
+ if ((yield* driver.next(generationExit).pipe(Effect.exit))._tag === "Failure") {
231
+ yield* Deferred.succeed(params.terminalExitDeferred, generationExit);
232
+ return;
233
+ }
234
+ let restartState = params.machine.initial;
235
+ if (params.lifecycle?.recovery !== void 0) {
236
+ const resolved = yield* params.lifecycle.recovery.resolve({
237
+ actorId: params.id,
238
+ generation: generation + 1,
239
+ machineInitial: params.machine.initial
240
+ });
241
+ if (Option.isSome(resolved)) restartState = resolved.value;
242
+ }
243
+ yield* settlePendingReplies(params.pendingReplies, params.id);
244
+ const freshQueue = yield* Queue.unbounded();
245
+ yield* Ref.set(params.eventQueueRef, freshQueue);
246
+ yield* SubscriptionRef.set(params.stateRef, restartState);
247
+ yield* Ref.set(params.stoppedRef, false);
248
+ params.childrenMap.clear();
249
+ const machineForRestart = restartState !== params.machine.initial ? Object.create(params.machine, { initial: {
250
+ value: restartState,
251
+ enumerable: true
252
+ } }) : params.machine;
253
+ const newRuntime = yield* params.spawnGeneration(machineForRestart);
254
+ params.runtimeRef.current = newRuntime;
255
+ yield* newRuntime.start;
256
+ generation++;
257
+ if (params.onRestart !== void 0) yield* params.onRestart(generation, generationExit);
258
+ notifyListeners(params.listeners, restartState);
259
+ }
260
+ });
166
261
  /**
167
262
  * Create and start an actor for a machine.
168
- * Uses the shared runtime kernel with lifecycle hooks for actor-specific concerns.
263
+ * Delegates to the shared runtime kernel with actor-specific lifecycle hooks.
169
264
  */
170
265
  const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machine, options) {
266
+ const lifecycle = options?.lifecycle;
171
267
  const initial = options?.initialState ?? machine.initial;
172
268
  yield* Effect.annotateCurrentSpan("effect_machine.actor.id", id);
173
269
  yield* Effect.annotateCurrentSpan("effect_machine.actor.initial_state", initial._tag);
174
- const existingSystem = yield* Effect.serviceOption(ActorSystem);
175
- let system;
176
- let implicitSystemScope;
177
- if (Option.isSome(existingSystem)) system = existingSystem.value;
178
- else {
179
- const scope = yield* Scope.make();
180
- system = yield* make().pipe(Effect.provideService(Scope.Scope, scope));
181
- implicitSystemScope = scope;
182
- }
270
+ const { system, implicitSystemScope } = yield* resolveActorSystem();
183
271
  const inspectorValue = Option.getOrUndefined(yield* Effect.serviceOption(Inspector));
184
272
  const childrenMap = /* @__PURE__ */ new Map();
185
273
  const pendingReplies = /* @__PURE__ */ new Set();
186
274
  const listeners = /* @__PURE__ */ new Set();
187
275
  const transitionsPubSub = yield* PubSub.unbounded();
188
- yield* emitWithTimestamp(inspectorValue, (timestamp) => ({
189
- type: "@machine.spawn",
190
- actorId: id,
191
- initialState: initial,
192
- timestamp
193
- }));
194
- const hooks = inspectorValue === void 0 ? void 0 : {
195
- onSpawnEffect: (state) => emitWithTimestamp(inspectorValue, (timestamp) => ({
196
- type: "@machine.effect",
197
- actorId: id,
198
- effectType: "spawn",
199
- state,
200
- timestamp
201
- })),
202
- onTransition: (from, to, ev) => emitWithTimestamp(inspectorValue, (timestamp) => ({
203
- type: "@machine.transition",
204
- actorId: id,
205
- fromState: from,
206
- toState: to,
207
- event: ev,
208
- timestamp
209
- })),
210
- onError: (info) => emitWithTimestamp(inspectorValue, (timestamp) => ({
211
- type: "@machine.error",
212
- actorId: id,
213
- phase: info.phase,
214
- state: info.state,
215
- event: info.event,
216
- error: Cause.pretty(info.cause),
217
- timestamp
218
- }))
219
- };
276
+ const hooks = inspectorValue !== void 0 ? buildInspectionHooks(id, inspectorValue) : void 0;
220
277
  const machineWithState = initial !== machine.initial ? Object.create(machine, { initial: {
221
278
  value: initial,
222
279
  enumerable: true
@@ -227,6 +284,7 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
227
284
  const eventQueueRef = yield* Ref.make(initialQueue);
228
285
  const terminalExitDeferred = yield* Deferred.make();
229
286
  let stopEmitted = false;
287
+ let generation = 0;
230
288
  const runtimeRef = { current: void 0 };
231
289
  /** Build lifecycle hooks for a generation */
232
290
  const buildLifecycle = () => {
@@ -239,8 +297,18 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
239
297
  event,
240
298
  timestamp
241
299
  })) : void 0,
242
- onStateChange: (result, _event) => Effect.gen(function* () {
300
+ onStateChange: (result, event) => Effect.gen(function* () {
243
301
  notifyListeners(listeners, result.newState);
302
+ if (lifecycle?.durability !== void 0 && result.transitioned) {
303
+ const durability = lifecycle.durability;
304
+ if (durability.shouldSave === void 0 || durability.shouldSave(result.newState, result.previousState)) yield* durability.save({
305
+ actorId: id,
306
+ generation,
307
+ previousState: result.previousState,
308
+ nextState: result.newState,
309
+ event
310
+ });
311
+ }
244
312
  yield* Effect.annotateCurrentSpan("effect_machine.transition.matched", true);
245
313
  if (result.lifecycleRan) {
246
314
  yield* Effect.annotateCurrentSpan("effect_machine.state.from", result.previousState._tag);
@@ -282,7 +350,7 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
282
350
  })) : void 0
283
351
  };
284
352
  };
285
- /** Create a single runtime generation */
353
+ /** Create a single runtime generation. machineForGen is machineWithState for initial, machine for restarts. */
286
354
  const spawnGeneration = (machineForGen) => Ref.get(eventQueueRef).pipe(Effect.flatMap((currentQueue) => createRuntime(machineForGen, system, {
287
355
  actorId: id,
288
356
  hooks,
@@ -306,49 +374,62 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
306
374
  }));
307
375
  })
308
376
  })));
377
+ runtimeRef.current = yield* spawnGeneration(machineWithState);
309
378
  const supervision = options?.supervision;
310
- const runtime = yield* spawnGeneration(machineWithState);
311
- runtimeRef.current = runtime;
312
- let supervisorFiber;
313
- if (supervision !== void 0) supervisorFiber = yield* Effect.forkDaemon(Effect.gen(function* () {
314
- const driver = yield* Schedule.driver(supervision.schedule);
315
- let generation = 0;
316
- while (true) {
317
- const currentRuntime = runtimeRef.current;
318
- if (currentRuntime === void 0) return;
319
- const generationExit = yield* Deferred.await(currentRuntime.exitDeferred);
320
- if (generationExit._tag !== "Defect") {
321
- yield* Deferred.succeed(terminalExitDeferred, generationExit);
322
- return;
323
- }
324
- if (supervision.shouldRestart !== void 0 && !supervision.shouldRestart(generationExit)) {
325
- yield* Deferred.succeed(terminalExitDeferred, generationExit);
326
- return;
327
- }
328
- if ((yield* driver.next(generationExit).pipe(Effect.exit))._tag === "Failure") {
329
- yield* Deferred.succeed(terminalExitDeferred, generationExit);
330
- return;
331
- }
332
- yield* settlePendingReplies(pendingReplies, id);
333
- const freshQueue = yield* Queue.unbounded();
334
- yield* Ref.set(eventQueueRef, freshQueue);
335
- yield* SubscriptionRef.set(stateRef, machine.initial);
336
- yield* Ref.set(stoppedRef, false);
337
- childrenMap.clear();
338
- runtimeRef.current = yield* spawnGeneration(machine);
339
- generation++;
340
- if (options?.onRestart !== void 0) yield* options.onRestart(generation, generationExit);
341
- notifyListeners(listeners, machine.initial);
342
- }
343
- }));
344
- else yield* Deferred.await(runtime.exitDeferred).pipe(Effect.tap((exit) => Deferred.succeed(terminalExitDeferred, exit)), Effect.catchAllCause(() => Effect.void), Effect.fork);
345
- return buildActorRefCore(id, machine, stateRef, eventQueueRef, stoppedRef, listeners, Effect.gen(function* () {
346
- if (supervisorFiber !== void 0) yield* Fiber.interrupt(supervisorFiber);
379
+ const supervisorFiberRef = { current: void 0 };
380
+ const stop = Effect.gen(function* () {
381
+ if (supervisorFiberRef.current !== void 0) yield* Fiber.interrupt(supervisorFiberRef.current);
347
382
  const currentRuntime = runtimeRef.current;
348
383
  if (currentRuntime !== void 0) yield* currentRuntime.stop;
349
384
  yield* Deferred.succeed(terminalExitDeferred, { _tag: "Stopped" });
350
385
  if (implicitSystemScope !== void 0) yield* Scope.close(implicitSystemScope, Exit.void);
351
- }).pipe(Effect.withSpan("effect-machine.actor.stop"), Effect.asVoid), system, childrenMap, pendingReplies, transitionsPubSub, terminalExitDeferred);
386
+ }).pipe(Effect.withSpan("effect-machine.actor.stop"), Effect.asVoid);
387
+ const isHydrated = options?.initialState !== void 0;
388
+ return buildActorRefCore(id, machine, stateRef, eventQueueRef, stoppedRef, listeners, stop, Effect.gen(function* () {
389
+ if (lifecycle?.recovery !== void 0 && !isHydrated) {
390
+ const resolved = yield* lifecycle.recovery.resolve({
391
+ actorId: id,
392
+ generation,
393
+ machineInitial: machine.initial
394
+ });
395
+ if (Option.isSome(resolved)) {
396
+ yield* SubscriptionRef.set(stateRef, resolved.value);
397
+ runtimeRef.current = yield* spawnGeneration(Object.create(machine, { initial: {
398
+ value: resolved.value,
399
+ enumerable: true
400
+ } }));
401
+ }
402
+ }
403
+ const currentState = yield* SubscriptionRef.get(stateRef);
404
+ yield* emitWithTimestamp(inspectorValue, (timestamp) => ({
405
+ type: "@machine.spawn",
406
+ actorId: id,
407
+ initialState: currentState,
408
+ timestamp
409
+ }));
410
+ if (supervision !== void 0) supervisorFiberRef.current = yield* Effect.forkDaemon(runSupervisionLoop({
411
+ supervision,
412
+ machine,
413
+ id,
414
+ runtimeRef,
415
+ terminalExitDeferred,
416
+ pendingReplies,
417
+ eventQueueRef,
418
+ stateRef,
419
+ stoppedRef,
420
+ childrenMap,
421
+ listeners,
422
+ spawnGeneration,
423
+ lifecycle,
424
+ onRestart: options?.onRestart
425
+ }));
426
+ else {
427
+ const currentRuntime = runtimeRef.current;
428
+ if (currentRuntime !== void 0) yield* Effect.forkDaemon(Deferred.await(currentRuntime.exitDeferred).pipe(Effect.tap((exit) => Deferred.succeed(terminalExitDeferred, exit))));
429
+ }
430
+ const currentRuntime = runtimeRef.current;
431
+ if (currentRuntime !== void 0) yield* currentRuntime.start;
432
+ }).pipe(Effect.withSpan("effect-machine.actor.start"), Effect.asVoid), system, childrenMap, pendingReplies, transitionsPubSub, terminalExitDeferred);
352
433
  });
353
434
  /** Fail all pending call/ask Deferreds with ActorStoppedError. Safe to call multiple times. */
354
435
  const settlePendingReplies = (pendingReplies, actorId) => Effect.sync(() => {
@@ -367,14 +448,15 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
367
448
  const withSpawnGate = (yield* Effect.makeSemaphore(1)).withPermits(1);
368
449
  const eventPubSub = yield* PubSub.unbounded();
369
450
  const eventListeners = /* @__PURE__ */ new Set();
370
- const emitSystemEvent = (event) => Effect.sync(() => notifySystemListeners(eventListeners, event)).pipe(Effect.zipRight(PubSub.publish(eventPubSub, event)), Effect.catchAllCause(() => Effect.void), Effect.asVoid);
451
+ const emitSystemEvent = (event) => Effect.sync(() => notifySystemListeners(eventListeners, event)).pipe(Effect.andThen(PubSub.publish(eventPubSub, event)), Effect.catchAllCause(() => Effect.void), Effect.asVoid);
371
452
  yield* Effect.addFinalizer(() => {
372
453
  const stops = [];
373
454
  MutableHashMap.forEach(actorsMap, (actor) => {
374
455
  stops.push(actor.stop);
375
456
  });
376
- return Effect.all(stops, { concurrency: "unbounded" }).pipe(Effect.zipRight(PubSub.shutdown(eventPubSub)), Effect.asVoid);
457
+ return Effect.all(stops, { concurrency: "unbounded" }).pipe(Effect.andThen(PubSub.shutdown(eventPubSub)), Effect.asVoid);
377
458
  });
459
+ /** Check for duplicate ID, register actor, attach scope cleanup if available */
378
460
  const registerActor = Effect.fn("effect-machine.actorSystem.register")(function* (id, actor) {
379
461
  if (MutableHashMap.has(actorsMap, id)) {
380
462
  yield* actor.stop;
@@ -404,10 +486,11 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
404
486
  });
405
487
  const spawnRegular = Effect.fn("effect-machine.actorSystem.spawnRegular")(function* (id, machine, spawnOptions) {
406
488
  if (MutableHashMap.has(actorsMap, id)) return yield* new DuplicateActorError({ actorId: id });
407
- const materialized = materializeMachine(machine, spawnOptions?.slots);
489
+ const materialized = spawnOptions?.slots !== void 0 ? materializeMachine(machine, spawnOptions.slots) : machine;
408
490
  let actorRef;
409
491
  const actor = yield* createActor(id, materialized, {
410
492
  supervision: spawnOptions?.supervision,
493
+ lifecycle: spawnOptions?.lifecycle,
411
494
  onRestart: spawnOptions?.supervision !== void 0 ? (generation, exit) => actorRef !== void 0 ? emitSystemEvent({
412
495
  _tag: "ActorRestarted",
413
496
  id,
@@ -417,7 +500,9 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
417
500
  }) : Effect.void : void 0
418
501
  });
419
502
  actorRef = actor;
420
- return yield* registerActor(id, actor);
503
+ yield* registerActor(id, actor);
504
+ yield* actor.start.pipe(Effect.catchAllCause((cause) => actor.stop.pipe(Effect.andThen(Effect.failCause(cause)))));
505
+ return actor;
421
506
  });
422
507
  const spawn = (id, machine, options) => withSpawnGate(spawnRegular(id, machine, options));
423
508
  const get = Effect.fn("effect-machine.actorSystem.get")(function* (id) {
@@ -465,6 +550,6 @@ const makeSystem = make;
465
550
  /**
466
551
  * Default ActorSystem layer
467
552
  */
468
- const Default = Layer.effect(ActorSystem, make());
553
+ const Default = Layer.scoped(ActorSystem, make());
469
554
  //#endregion
470
555
  export { ActorSystem, Default, buildActorRefCore, createActor, makeSystem, notifyListeners, processEventCore, resolveTransition, runSpawnEffects, settlePendingReplies };
@@ -68,7 +68,7 @@ declare const EntityMachine: {
68
68
  readonly _tag: string;
69
69
  }, E extends {
70
70
  readonly _tag: string;
71
- }, R, EntityType extends string, Rpcs extends Rpc.Any>(entity: Entity.Entity<EntityType, Rpcs>, machine: Machine<S, E, R, any, any, any, any>, options?: EntityMachineOptions<S, E>) => Layer.Layer<never, never, R>;
71
+ }, R, EntityType extends string, Rpcs extends Rpc.Any>(entity: Entity.Entity<EntityType, Rpcs>, machine: Machine<S, E, R, any, any, any>, options?: EntityMachineOptions<S, E>) => Layer.Layer<never, never, R>;
72
72
  };
73
73
  //#endregion
74
74
  export { EntityMachine, EntityMachineOptions };
@@ -50,6 +50,7 @@ const EntityMachine = { layer: (entity, machine, options) => {
50
50
  hooks: options?.hooks,
51
51
  childIdPrefix: `${entityId}/`
52
52
  });
53
+ yield* runtime.start;
53
54
  if (persistCtx.adapter !== void 0) {
54
55
  const { adapter: pAdapter, key } = persistCtx;
55
56
  yield* Effect.addFinalizer(() => Effect.gen(function* () {
@@ -59,6 +59,6 @@ declare const toEntity: <S extends {
59
59
  readonly _tag: string;
60
60
  }, E extends {
61
61
  readonly _tag: string;
62
- }, R>(machine: Machine<S, E, R, any, any, any, any>, options: ToEntityOptions) => any;
62
+ }, R>(machine: Machine<S, E, R, any, any, any>, options: ToEntityOptions) => any;
63
63
  //#endregion
64
64
  export { EntityRpcs, ToEntityOptions, toEntity };
@@ -33,7 +33,7 @@ declare const SlotProvisionError_base: Schema.TaggedErrorClass<SlotProvisionErro
33
33
  readonly _tag: Schema.tag<"SlotProvisionError">;
34
34
  } & {
35
35
  slotName: typeof Schema.String;
36
- slotType: Schema.Literal<["guard", "effect"]>;
36
+ slotType: Schema.Literal<["slot"]>;
37
37
  }>;
38
38
  /** Slot handler not found at runtime (internal error) */
39
39
  declare class SlotProvisionError extends SlotProvisionError_base {}
@@ -43,7 +43,7 @@ declare const ProvisionValidationError_base: Schema.TaggedErrorClass<ProvisionVa
43
43
  missing: Schema.Array$<typeof Schema.String>;
44
44
  extra: Schema.Array$<typeof Schema.String>;
45
45
  }>;
46
- /** Machine.build() validation failed - missing or extra handlers */
46
+ /** Slot provision validation failed missing or extra handlers */
47
47
  declare class ProvisionValidationError extends ProvisionValidationError_base {}
48
48
  declare const AssertionError_base: Schema.TaggedErrorClass<AssertionError, "AssertionError", {
49
49
  readonly _tag: Schema.tag<"AssertionError">;
@@ -74,6 +74,15 @@ declare const PersistenceError_base: Schema.TaggedErrorClass<PersistenceError, "
74
74
  }>;
75
75
  /** Persistence adapter operation failed */
76
76
  declare class PersistenceError extends PersistenceError_base {}
77
+ declare const SlotCodecError_base: Schema.TaggedErrorClass<SlotCodecError, "SlotCodecError", {
78
+ readonly _tag: Schema.tag<"SlotCodecError">;
79
+ } & {
80
+ slotName: typeof Schema.String;
81
+ phase: Schema.Literal<["input", "output"]>;
82
+ message: typeof Schema.String;
83
+ }>;
84
+ /** Slot input/output schema validation failed */
85
+ declare class SlotCodecError extends SlotCodecError_base {}
77
86
  declare const VersionConflictError_base: Schema.TaggedErrorClass<VersionConflictError, "VersionConflictError", {
78
87
  readonly _tag: Schema.tag<"VersionConflictError">;
79
88
  } & {
@@ -83,4 +92,4 @@ declare const VersionConflictError_base: Schema.TaggedErrorClass<VersionConflict
83
92
  /** Optimistic locking failure — stored version doesn't match expected */
84
93
  declare class VersionConflictError extends VersionConflictError_base {}
85
94
  //#endregion
86
- export { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceError, ProvisionValidationError, SlotProvisionError, VersionConflictError };
95
+ export { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceError, ProvisionValidationError, SlotCodecError, SlotProvisionError, VersionConflictError };
package/v3/dist/errors.js CHANGED
@@ -3,7 +3,7 @@ import { Schema } from "effect";
3
3
  /**
4
4
  * Typed error classes for effect-machine.
5
5
  *
6
- * All errors extend Schema.TaggedError for:
6
+ * All errors extend Schema.TaggedErrorClass for:
7
7
  * - Type-safe catching via Effect.catchTag
8
8
  * - Serialization support
9
9
  * - Composable error handling
@@ -21,9 +21,9 @@ var MissingMatchHandlerError = class extends Schema.TaggedError()("MissingMatchH
21
21
  /** Slot handler not found at runtime (internal error) */
22
22
  var SlotProvisionError = class extends Schema.TaggedError()("SlotProvisionError", {
23
23
  slotName: Schema.String,
24
- slotType: Schema.Literal("guard", "effect")
24
+ slotType: Schema.Literal("slot")
25
25
  }) {};
26
- /** Machine.build() validation failed - missing or extra handlers */
26
+ /** Slot provision validation failed missing or extra handlers */
27
27
  var ProvisionValidationError = class extends Schema.TaggedError()("ProvisionValidationError", {
28
28
  missing: Schema.Array(Schema.String),
29
29
  extra: Schema.Array(Schema.String)
@@ -39,10 +39,16 @@ var NoReplyError = class extends Schema.TaggedError()("NoReplyError", {
39
39
  }) {};
40
40
  /** Persistence adapter operation failed */
41
41
  var PersistenceError = class extends Schema.TaggedError()("PersistenceError", { message: Schema.String }) {};
42
+ /** Slot input/output schema validation failed */
43
+ var SlotCodecError = class extends Schema.TaggedError()("SlotCodecError", {
44
+ slotName: Schema.String,
45
+ phase: Schema.Literal("input", "output"),
46
+ message: Schema.String
47
+ }) {};
42
48
  /** Optimistic locking failure — stored version doesn't match expected */
43
49
  var VersionConflictError = class extends Schema.TaggedError()("VersionConflictError", {
44
50
  expected: Schema.Number,
45
51
  actual: Schema.Number
46
52
  }) {};
47
53
  //#endregion
48
- export { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceError, ProvisionValidationError, SlotProvisionError, VersionConflictError };
54
+ export { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceError, ProvisionValidationError, SlotCodecError, SlotProvisionError, VersionConflictError };
@@ -1,11 +1,11 @@
1
- import { ActorExit, CellPhase, DefectPhase, Supervision } from "./supervision.js";
2
- import { ReplyResult } from "./internal/utils.js";
1
+ import { DeferReplyResult, ReplyResult } from "./internal/utils.js";
3
2
  import { Event, MachineEventSchema, MachineStateSchema, ReplyFields, State } from "./schema.js";
4
- import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceError, ProvisionValidationError, SlotProvisionError, VersionConflictError } from "./errors.js";
5
- import { EffectHandlers, EffectSlot, EffectSlots, EffectsDef, EffectsSchema, GuardHandlers, GuardSlot, GuardSlots, GuardsDef, GuardsSchema, MachineContext, Slot } from "./slot.js";
3
+ import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceError, ProvisionValidationError, SlotCodecError, SlotProvisionError, VersionConflictError } from "./errors.js";
4
+ import { HasSlotKeys, MachineContext, ProvideSlots, Slot, SlotCall, SlotCalls, SlotFnDef, SlotHandler, SlotInvocation, SlotRequest, SlotResult, SlotsDef, SlotsSchema } from "./slot.js";
5
+ import { ActorExit, CellPhase, DefectPhase, Supervision } from "./supervision.js";
6
6
  import { ProcessEventResult } from "./internal/transition.js";
7
- import { BackgroundEffect, HandlerContext, Machine, MachineRef, MakeConfig, ProvideHandlers, SlotContext, SpawnEffect, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, machine_d_exports } from "./machine.js";
7
+ import { BackgroundEffect, Durability, DurabilityCommit, HandlerContext, Lifecycle, Machine, MachineRef, MakeConfig, Recovery, RecoveryContext, SpawnEffect, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, machine_d_exports } from "./machine.js";
8
8
  import { ActorRef, ActorRefSync, ActorSystem, Default, SystemEvent, SystemEventListener, TransitionInfo } from "./actor.js";
9
9
  import { SimulationResult, TestHarness, TestHarnessOptions, assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
10
10
  import { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, InspectionEvent, Inspector, InspectorHandler, SpawnEvent, StopEvent, TaskEvent, TracingInspectorOptions, TransitionEvent, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector } from "./inspection.js";
11
- export { ActorExit, type ActorRef, type ActorRefSync, ActorStoppedError, type ActorSystem, Default as ActorSystemDefault, ActorSystem as ActorSystemService, type AnyInspectionEvent, AssertionError, type BackgroundEffect, type CellPhase, type DefectPhase, DuplicateActorError, type EffectEvent, type EffectSlots, type EffectsDef, type EffectsSchema, type ErrorEvent, Event, type EventReceivedEvent, type GuardHandlers, type GuardSlot, type GuardSlots, type GuardsDef, type GuardsSchema, type HandlerContext, type InspectionEvent, type Inspector, type InspectorHandler, Inspector as InspectorService, InvalidSchemaError, machine_d_exports as Machine, type MachineContext, type MachineEventSchema, type MachineRef, type MachineStateSchema, type Machine as MachineType, type MakeConfig, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceError, type ProcessEventResult, type ProvideHandlers, ProvisionValidationError, type ReplyFields, type ReplyResult, type SimulationResult, Slot, type SlotContext, type EffectHandlers as SlotEffectHandlers, type EffectSlot as SlotEffectSlot, SlotProvisionError, type SpawnEffect, type SpawnEvent, State, type StateHandlerContext, type StopEvent, Supervision, type SystemEvent, type SystemEventListener, type TaskEvent, type TaskOptions, type TestHarness, type TestHarnessOptions, type TimeoutConfig, type TracingInspectorOptions, type Transition, type TransitionEvent, type TransitionInfo, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createTestHarness, makeInspector, makeInspectorEffect, simulate, tracingInspector };
11
+ export { ActorExit, type ActorRef, type ActorRefSync, ActorStoppedError, type ActorSystem, Default as ActorSystemDefault, ActorSystem as ActorSystemService, type AnyInspectionEvent, AssertionError, type BackgroundEffect, type CellPhase, type DefectPhase, type DeferReplyResult, DuplicateActorError, type Durability, type DurabilityCommit, type EffectEvent, type ErrorEvent, Event, type EventReceivedEvent, type HandlerContext, type HasSlotKeys, type InspectionEvent, type Inspector, type InspectorHandler, Inspector as InspectorService, InvalidSchemaError, type Lifecycle, machine_d_exports as Machine, type MachineContext, type MachineEventSchema, type MachineRef, type MachineStateSchema, type Machine as MachineType, type MakeConfig, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceError, type ProcessEventResult, type ProvideSlots, ProvisionValidationError, type Recovery, type RecoveryContext, type ReplyFields, type ReplyResult, type SimulationResult, Slot, type SlotCall, type SlotCalls, SlotCodecError, type SlotFnDef, type SlotHandler, type SlotInvocation, SlotProvisionError, type SlotRequest, type SlotResult, type SlotsDef, type SlotsSchema, type SpawnEffect, type SpawnEvent, State, type StateHandlerContext, type StopEvent, Supervision, type SystemEvent, type SystemEventListener, type TaskEvent, type TaskOptions, type TestHarness, type TestHarnessOptions, type TimeoutConfig, type TracingInspectorOptions, type Transition, type TransitionEvent, type TransitionInfo, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createTestHarness, makeInspector, makeInspectorEffect, simulate, tracingInspector };
package/v3/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceError, ProvisionValidationError, SlotProvisionError, VersionConflictError } from "./errors.js";
1
+ import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceError, ProvisionValidationError, SlotCodecError, SlotProvisionError, VersionConflictError } from "./errors.js";
2
2
  import { Inspector, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector } from "./inspection.js";
3
3
  import { Slot } from "./slot.js";
4
4
  import { machine_exports } from "./machine.js";
@@ -6,4 +6,4 @@ import { ActorExit, Supervision } from "./supervision.js";
6
6
  import { ActorSystem, Default } from "./actor.js";
7
7
  import { Event, State } from "./schema.js";
8
8
  import { assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
9
- export { ActorExit, ActorStoppedError, Default as ActorSystemDefault, ActorSystem as ActorSystemService, AssertionError, DuplicateActorError, Event, Inspector as InspectorService, InvalidSchemaError, machine_exports as Machine, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceError, ProvisionValidationError, Slot, SlotProvisionError, State, Supervision, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createTestHarness, makeInspector, makeInspectorEffect, simulate, tracingInspector };
9
+ export { ActorExit, ActorStoppedError, Default as ActorSystemDefault, ActorSystem as ActorSystemService, AssertionError, DuplicateActorError, Event, Inspector as InspectorService, InvalidSchemaError, machine_exports as Machine, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceError, ProvisionValidationError, Slot, SlotCodecError, SlotProvisionError, State, Supervision, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createTestHarness, makeInspector, makeInspectorEffect, simulate, tracingInspector };
@@ -4,7 +4,7 @@ import { Context, Effect, Schema } from "effect";
4
4
  /**
5
5
  * Resolve a type param: if it's a Schema, extract `.Type`; otherwise use as-is.
6
6
  */
7
- type ResolveType<T> = T extends Schema.Schema<infer A, infer _I, infer _R> ? A : T;
7
+ type ResolveType<T> = T extends Schema.Schema<infer A> ? A : T;
8
8
  /**
9
9
  * Event emitted when an actor is spawned
10
10
  */
@@ -45,9 +45,6 @@ interface EffectEvent<S> {
45
45
  readonly state: S;
46
46
  readonly timestamp: number;
47
47
  }
48
- /**
49
- * Event emitted when a task lifecycle phase occurs
50
- */
51
48
  interface TaskEvent<S> {
52
49
  readonly type: "@machine.task";
53
50
  readonly actorId: string;
@@ -93,13 +90,10 @@ type AnyInspectionEvent = InspectionEvent<{
93
90
  }, {
94
91
  readonly _tag: string;
95
92
  }>;
96
- /**
97
- * Inspector handler — sync callback or Effect-returning callback.
98
- */
99
- type InspectorHandler<S, E> = (event: InspectionEvent<S, E>) => void | Effect.Effect<void, never, never>;
100
93
  /**
101
94
  * Inspector interface for observing machine behavior
102
95
  */
96
+ type InspectorHandler<S, E> = (event: InspectionEvent<S, E>) => void | Effect.Effect<void, never, never>;
103
97
  interface Inspector<S, E> {
104
98
  readonly onInspect: InspectorHandler<S, E>;
105
99
  }
@@ -109,7 +103,7 @@ interface Inspector<S, E> {
109
103
  */
110
104
  declare const Inspector: Context.Tag<Inspector<any, any>, Inspector<any, any>>;
111
105
  /**
112
- * Create an inspector from a sync callback function.
106
+ * Create an inspector from a callback function.
113
107
  *
114
108
  * Type params accept either raw tagged types or Schema constructors:
115
109
  * - `makeInspector(cb)` — defaults to `AnyInspectionEvent`
@@ -121,30 +115,17 @@ declare const makeInspector: <S = {
121
115
  }, E = {
122
116
  readonly _tag: string;
123
117
  }>(onInspect: InspectorHandler<ResolveType<S>, ResolveType<E>>) => Inspector<ResolveType<S>, ResolveType<E>>;
124
- /**
125
- * Create an inspector from an Effect-returning callback function.
126
- */
127
118
  declare const makeInspectorEffect: <S = {
128
119
  readonly _tag: string;
129
120
  }, E = {
130
121
  readonly _tag: string;
131
122
  }>(onInspect: (event: InspectionEvent<ResolveType<S>, ResolveType<E>>) => Effect.Effect<void, never, never>) => Inspector<ResolveType<S>, ResolveType<E>>;
132
- /**
133
- * Combine multiple inspectors into one. All run concurrently per event.
134
- * Individual inspector failures are swallowed.
135
- */
136
123
  declare const combineInspectors: <S, E>(...inspectors: ReadonlyArray<Inspector<S, E>>) => Inspector<S, E>;
137
- /**
138
- * Options for the tracing inspector.
139
- */
140
124
  interface TracingInspectorOptions<S, E> {
141
125
  readonly spanName?: string | ((event: InspectionEvent<S, E>) => string);
142
126
  readonly attributes?: (event: InspectionEvent<S, E>) => Readonly<Record<string, string | number | boolean>>;
143
127
  readonly eventName?: (event: InspectionEvent<S, E>) => string;
144
128
  }
145
- /**
146
- * Inspector that emits OpenTelemetry spans and events for each inspection event.
147
- */
148
129
  declare const tracingInspector: <S extends {
149
130
  readonly _tag: string;
150
131
  }, E extends {
@@ -6,7 +6,7 @@ import { Context, Effect, Option } from "effect";
6
6
  */
7
7
  const Inspector = Context.GenericTag("@effect/machine/Inspector");
8
8
  /**
9
- * Create an inspector from a sync callback function.
9
+ * Create an inspector from a callback function.
10
10
  *
11
11
  * Type params accept either raw tagged types or Schema constructors:
12
12
  * - `makeInspector(cb)` — defaults to `AnyInspectionEvent`
@@ -14,22 +14,11 @@ const Inspector = Context.GenericTag("@effect/machine/Inspector");
14
14
  * - `makeInspector<typeof MyState, typeof MyEvent>(cb)` — schema constructors (auto-extracts `.Type`)
15
15
  */
16
16
  const makeInspector = (onInspect) => ({ onInspect });
17
- /**
18
- * Create an inspector from an Effect-returning callback function.
19
- */
20
17
  const makeInspectorEffect = (onInspect) => ({ onInspect });
21
- /**
22
- * Run an inspector handler, handling both sync and Effect returns.
23
- * @internal
24
- */
25
18
  const inspectionEffect = (inspector, event) => {
26
19
  const result = inspector.onInspect(event);
27
20
  return Effect.isEffect(result) ? result : Effect.void;
28
21
  };
29
- /**
30
- * Combine multiple inspectors into one. All run concurrently per event.
31
- * Individual inspector failures are swallowed.
32
- */
33
22
  const combineInspectors = (...inspectors) => ({ onInspect: (event) => Effect.forEach(inspectors, (inspector) => inspectionEffect(inspector, event).pipe(Effect.catchAllCause(() => Effect.void)), {
34
23
  concurrency: "unbounded",
35
24
  discard: true
@@ -99,9 +88,6 @@ const inspectionAttributes = (event) => {
99
88
  };
100
89
  }
101
90
  };
102
- /**
103
- * Inspector that emits OpenTelemetry spans and events for each inspection event.
104
- */
105
91
  const tracingInspector = (options) => ({ onInspect: (event) => {
106
92
  const spanName = typeof options?.spanName === "function" ? options.spanName(event) : options?.spanName;
107
93
  const traceName = options?.eventName?.(event) ?? inspectionTraceName(event);