effect-machine 0.9.0 → 0.10.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 (62) hide show
  1. package/README.md +76 -16
  2. package/dist/actor.d.ts +55 -89
  3. package/dist/actor.js +135 -30
  4. package/dist/cluster/entity-machine.js +5 -3
  5. package/dist/errors.d.ts +12 -1
  6. package/dist/errors.js +8 -1
  7. package/dist/index.d.ts +3 -3
  8. package/dist/index.js +2 -2
  9. package/dist/internal/transition.d.ts +26 -2
  10. package/dist/internal/transition.js +37 -8
  11. package/dist/internal/utils.d.ts +7 -2
  12. package/dist/machine.d.ts +66 -3
  13. package/dist/machine.js +65 -0
  14. package/dist/persistence/persistent-actor.js +52 -16
  15. package/dist/testing.js +57 -3
  16. package/package.json +9 -8
  17. package/{dist-v3 → v3/dist}/actor.d.ts +65 -78
  18. package/{dist-v3 → v3/dist}/actor.js +173 -35
  19. package/{dist-v3 → v3/dist}/cluster/entity-machine.d.ts +1 -1
  20. package/{dist-v3 → v3/dist}/cluster/entity-machine.js +8 -6
  21. package/{dist-v3 → v3/dist}/cluster/to-entity.d.ts +1 -1
  22. package/{dist-v3 → v3/dist}/cluster/to-entity.js +1 -1
  23. package/v3/dist/errors.d.ts +76 -0
  24. package/{dist-v3 → v3/dist}/errors.js +9 -2
  25. package/v3/dist/index.d.ts +13 -0
  26. package/v3/dist/index.js +13 -0
  27. package/{dist-v3 → v3/dist}/inspection.d.ts +53 -8
  28. package/v3/dist/inspection.js +156 -0
  29. package/{dist-v3 → v3/dist}/internal/brands.d.ts +1 -1
  30. package/{dist-v3 → v3/dist}/internal/inspection.d.ts +1 -1
  31. package/v3/dist/internal/inspection.js +20 -0
  32. package/{dist-v3 → v3/dist}/internal/transition.d.ts +35 -11
  33. package/{dist-v3 → v3/dist}/internal/transition.js +47 -15
  34. package/{dist-v3 → v3/dist}/internal/utils.d.ts +9 -4
  35. package/{dist-v3 → v3/dist}/internal/utils.js +1 -1
  36. package/{dist-v3 → v3/dist}/machine.d.ts +86 -9
  37. package/{dist-v3 → v3/dist}/machine.js +128 -2
  38. package/{dist-v3 → v3/dist}/persistence/adapter.d.ts +18 -5
  39. package/{dist-v3 → v3/dist}/persistence/adapter.js +1 -1
  40. package/{dist-v3 → v3/dist}/persistence/adapters/in-memory.d.ts +1 -1
  41. package/{dist-v3 → v3/dist}/persistence/adapters/in-memory.js +1 -1
  42. package/{dist-v3 → v3/dist}/persistence/persistent-actor.d.ts +7 -6
  43. package/{dist-v3 → v3/dist}/persistence/persistent-actor.js +58 -19
  44. package/{dist-v3 → v3/dist}/persistence/persistent-machine.d.ts +1 -1
  45. package/{dist-v3 → v3/dist}/persistence/persistent-machine.js +1 -1
  46. package/{dist-v3 → v3/dist}/schema.d.ts +1 -1
  47. package/{dist-v3 → v3/dist}/schema.js +5 -2
  48. package/{dist-v3 → v3/dist}/slot.d.ts +4 -3
  49. package/{dist-v3 → v3/dist}/slot.js +1 -1
  50. package/{dist-v3 → v3/dist}/testing.d.ts +14 -8
  51. package/{dist-v3 → v3/dist}/testing.js +60 -6
  52. package/dist-v3/errors.d.ts +0 -27
  53. package/dist-v3/index.d.ts +0 -12
  54. package/dist-v3/index.js +0 -13
  55. package/dist-v3/inspection.js +0 -48
  56. package/dist-v3/internal/inspection.js +0 -13
  57. /package/{dist-v3 → v3/dist}/_virtual/_rolldown/runtime.js +0 -0
  58. /package/{dist-v3 → v3/dist}/cluster/index.d.ts +0 -0
  59. /package/{dist-v3 → v3/dist}/cluster/index.js +0 -0
  60. /package/{dist-v3 → v3/dist}/internal/brands.js +0 -0
  61. /package/{dist-v3 → v3/dist}/persistence/index.d.ts +0 -0
  62. /package/{dist-v3 → v3/dist}/persistence/index.js +0 -0
@@ -1,9 +1,9 @@
1
1
  import { stubSystem } from "./internal/utils.js";
2
2
  import { AssertionError } from "./errors.js";
3
3
  import { BuiltMachine } from "./machine.js";
4
- import { executeTransition } from "./internal/transition.js";
4
+ import { executeTransition, shouldPostpone } from "./internal/transition.js";
5
5
  import { Effect, SubscriptionRef } from "effect";
6
- //#region src-v3/testing.ts
6
+ //#region src/testing.ts
7
7
  /**
8
8
  * Simulate a sequence of events through a machine without running an actor.
9
9
  * Useful for testing state transitions in isolation.
@@ -26,18 +26,44 @@ import { Effect, SubscriptionRef } from "effect";
26
26
  */
27
27
  const simulate = Effect.fn("effect-machine.simulate")(function* (input, events) {
28
28
  const machine = input instanceof BuiltMachine ? input._inner : input;
29
+ const dummySend = Effect.fn("effect-machine.testing.simulate.send")((_event) => Effect.void);
29
30
  const dummySelf = {
30
- send: Effect.fn("effect-machine.testing.simulate.send")((_event) => Effect.void),
31
+ send: dummySend,
32
+ cast: dummySend,
31
33
  spawn: () => Effect.die("spawn not supported in simulation")
32
34
  };
33
35
  let currentState = machine.initial;
34
36
  const states = [currentState];
37
+ const hasPostponeRules = machine.postponeRules.length > 0;
38
+ const postponed = [];
35
39
  for (const event of events) {
36
- const result = yield* executeTransition(machine, currentState, event, dummySelf, stubSystem);
40
+ if (hasPostponeRules && shouldPostpone(machine, currentState._tag, event._tag)) {
41
+ postponed.push(event);
42
+ continue;
43
+ }
44
+ const result = yield* executeTransition(machine, currentState, event, dummySelf, stubSystem, "simulation");
37
45
  if (!result.transitioned) continue;
46
+ const prevTag = currentState._tag;
38
47
  currentState = result.newState;
39
48
  states.push(currentState);
40
49
  if (machine.finalStates.has(currentState._tag)) break;
50
+ let drainTag = prevTag;
51
+ while (currentState._tag !== drainTag && postponed.length > 0) {
52
+ drainTag = currentState._tag;
53
+ const drained = postponed.splice(0);
54
+ for (const postponedEvent of drained) {
55
+ if (shouldPostpone(machine, currentState._tag, postponedEvent._tag)) {
56
+ postponed.push(postponedEvent);
57
+ continue;
58
+ }
59
+ const drainResult = yield* executeTransition(machine, currentState, postponedEvent, dummySelf, stubSystem, "simulation");
60
+ if (drainResult.transitioned) {
61
+ currentState = drainResult.newState;
62
+ states.push(currentState);
63
+ if (machine.finalStates.has(currentState._tag)) break;
64
+ }
65
+ }
66
+ }
41
67
  }
42
68
  return {
43
69
  states,
@@ -113,20 +139,48 @@ const assertNeverReaches = Effect.fn("effect-machine.assertNeverReaches")(functi
113
139
  */
114
140
  const createTestHarness = Effect.fn("effect-machine.createTestHarness")(function* (input, options) {
115
141
  const machine = input instanceof BuiltMachine ? input._inner : input;
142
+ const dummySend = Effect.fn("effect-machine.testing.harness.send")((_event) => Effect.void);
116
143
  const dummySelf = {
117
- send: Effect.fn("effect-machine.testing.harness.send")((_event) => Effect.void),
144
+ send: dummySend,
145
+ cast: dummySend,
118
146
  spawn: () => Effect.die("spawn not supported in test harness")
119
147
  };
120
148
  const stateRef = yield* SubscriptionRef.make(machine.initial);
149
+ const hasPostponeRules = machine.postponeRules.length > 0;
150
+ const postponed = [];
121
151
  return {
122
152
  state: stateRef,
123
153
  send: Effect.fn("effect-machine.testHarness.send")(function* (event) {
124
154
  const currentState = yield* SubscriptionRef.get(stateRef);
125
- const result = yield* executeTransition(machine, currentState, event, dummySelf, stubSystem);
155
+ if (hasPostponeRules && shouldPostpone(machine, currentState._tag, event._tag)) {
156
+ postponed.push(event);
157
+ return currentState;
158
+ }
159
+ const result = yield* executeTransition(machine, currentState, event, dummySelf, stubSystem, "test-harness");
126
160
  if (!result.transitioned) return currentState;
161
+ const prevTag = currentState._tag;
127
162
  const newState = result.newState;
128
163
  yield* SubscriptionRef.set(stateRef, newState);
129
164
  if (options?.onTransition !== void 0) options.onTransition(currentState, event, newState);
165
+ let drainTag = prevTag;
166
+ let currentTag = newState._tag;
167
+ while (currentTag !== drainTag && postponed.length > 0) {
168
+ drainTag = currentTag;
169
+ const drained = postponed.splice(0);
170
+ for (const postponedEvent of drained) {
171
+ const state = yield* SubscriptionRef.get(stateRef);
172
+ if (shouldPostpone(machine, state._tag, postponedEvent._tag)) {
173
+ postponed.push(postponedEvent);
174
+ continue;
175
+ }
176
+ const drainResult = yield* executeTransition(machine, state, postponedEvent, dummySelf, stubSystem, "test-harness");
177
+ if (drainResult.transitioned) {
178
+ yield* SubscriptionRef.set(stateRef, drainResult.newState);
179
+ currentTag = drainResult.newState._tag;
180
+ if (options?.onTransition !== void 0) options.onTransition(state, postponedEvent, drainResult.newState);
181
+ }
182
+ }
183
+ }
130
184
  return newState;
131
185
  }),
132
186
  getState: SubscriptionRef.get(stateRef)
@@ -1,27 +0,0 @@
1
- //#region src-v3/errors.d.ts
2
- declare const DuplicateActorError_base: any;
3
- /** Attempted to spawn/restore actor with ID already in use */
4
- declare class DuplicateActorError extends DuplicateActorError_base {}
5
- declare const UnprovidedSlotsError_base: any;
6
- /** Machine has unprovided effect slots */
7
- declare class UnprovidedSlotsError extends UnprovidedSlotsError_base {}
8
- declare const MissingSchemaError_base: any;
9
- /** Operation requires schemas attached to machine */
10
- declare class MissingSchemaError extends MissingSchemaError_base {}
11
- declare const InvalidSchemaError_base: any;
12
- /** State/Event schema has no variants */
13
- declare class InvalidSchemaError extends InvalidSchemaError_base {}
14
- declare const MissingMatchHandlerError_base: any;
15
- /** $match called with missing handler for tag */
16
- declare class MissingMatchHandlerError extends MissingMatchHandlerError_base {}
17
- declare const SlotProvisionError_base: any;
18
- /** Slot handler not found at runtime (internal error) */
19
- declare class SlotProvisionError extends SlotProvisionError_base {}
20
- declare const ProvisionValidationError_base: any;
21
- /** Machine.build() validation failed - missing or extra handlers */
22
- declare class ProvisionValidationError extends ProvisionValidationError_base {}
23
- declare const AssertionError_base: any;
24
- /** Assertion failed in testing utilities */
25
- declare class AssertionError extends AssertionError_base {}
26
- //#endregion
27
- export { AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError };
@@ -1,12 +0,0 @@
1
- import { Event, MachineEventSchema, MachineStateSchema, State } from "./schema.js";
2
- import { PersistenceConfig, PersistentMachine, isPersistentMachine } from "./persistence/persistent-machine.js";
3
- import { AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError } from "./errors.js";
4
- import { EffectHandlers, EffectSlot, EffectSlots, EffectsDef, EffectsSchema, GuardHandlers, GuardSlot, GuardSlots, GuardsDef, GuardsSchema, MachineContext, Slot } from "./slot.js";
5
- import { PersistentActorRef, createPersistentActor, restorePersistentActor } from "./persistence/persistent-actor.js";
6
- import { ActorMetadata, PersistedEvent, PersistenceAdapter, PersistenceAdapterTag, PersistenceError, RestoreFailure, RestoreResult, Snapshot, VersionConflictError } from "./persistence/adapter.js";
7
- import { InMemoryPersistenceAdapter, makeInMemoryPersistenceAdapter } from "./persistence/adapters/in-memory.js";
8
- import { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig, PersistOptions, ProvideHandlers, SpawnEffect, StateHandlerContext, Transition, machine_d_exports } from "./machine.js";
9
- import { ActorRef, ActorSystem, Default, SystemEvent, SystemEventListener } from "./actor.js";
10
- import { SimulationResult, TestHarness, TestHarnessOptions, assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
11
- import { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, InspectionEvent, Inspector, SpawnEvent, StopEvent, TransitionEvent, collectingInspector, consoleInspector, makeInspector } from "./inspection.js";
12
- export { type ActorMetadata, type ActorRef, type ActorSystem, Default as ActorSystemDefault, ActorSystem as ActorSystemService, type AnyInspectionEvent, AssertionError, type BackgroundEffect, type BuiltMachine, 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, InMemoryPersistenceAdapter, type InspectionEvent, type Inspector, 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, type PersistOptions, type PersistedEvent, type PersistenceAdapter, PersistenceAdapterTag, type PersistenceConfig, PersistenceError, type PersistentActorRef, type PersistentMachine, type ProvideHandlers, ProvisionValidationError, type RestoreFailure, type RestoreResult, type SimulationResult, Slot, type EffectHandlers as SlotEffectHandlers, type EffectSlot as SlotEffectSlot, SlotProvisionError, type Snapshot, type SpawnEffect, type SpawnEvent, State, type StateHandlerContext, type StopEvent, type SystemEvent, type SystemEventListener, type TestHarness, type TestHarnessOptions, type Transition, type TransitionEvent, UnprovidedSlotsError, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, consoleInspector, createPersistentActor, createTestHarness, isPersistentMachine, makeInMemoryPersistenceAdapter, makeInspector, restorePersistentActor, simulate };
package/dist-v3/index.js DELETED
@@ -1,13 +0,0 @@
1
- import { Inspector, collectingInspector, consoleInspector, makeInspector } from "./inspection.js";
2
- import { AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError } from "./errors.js";
3
- import { isPersistentMachine } from "./persistence/persistent-machine.js";
4
- import { Slot } from "./slot.js";
5
- import { machine_exports } from "./machine.js";
6
- import { PersistenceAdapterTag, PersistenceError, VersionConflictError } from "./persistence/adapter.js";
7
- import { createPersistentActor, restorePersistentActor } from "./persistence/persistent-actor.js";
8
- import { ActorSystem, Default } from "./actor.js";
9
- import { Event, State } from "./schema.js";
10
- import { assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
11
- import { InMemoryPersistenceAdapter, makeInMemoryPersistenceAdapter } from "./persistence/adapters/in-memory.js";
12
- import "./persistence/index.js";
13
- export { Default as ActorSystemDefault, ActorSystem as ActorSystemService, AssertionError, DuplicateActorError, Event, InMemoryPersistenceAdapter, Inspector as InspectorService, InvalidSchemaError, machine_exports as Machine, MissingMatchHandlerError, MissingSchemaError, PersistenceAdapterTag, PersistenceError, ProvisionValidationError, Slot, SlotProvisionError, State, UnprovidedSlotsError, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, consoleInspector, createPersistentActor, createTestHarness, isPersistentMachine, makeInMemoryPersistenceAdapter, makeInspector, restorePersistentActor, simulate };
@@ -1,48 +0,0 @@
1
- import { Context } from "effect";
2
- //#region src-v3/inspection.ts
3
- /**
4
- * Inspector service tag - optional service for machine introspection
5
- * Uses `any` types to allow variance flexibility when providing the service
6
- */
7
- const Inspector = Context.GenericTag("@effect/machine/Inspector");
8
- /**
9
- * Create an inspector from a callback function.
10
- *
11
- * Type params accept either raw tagged types or Schema constructors:
12
- * - `makeInspector(cb)` — defaults to `AnyInspectionEvent`
13
- * - `makeInspector<MyState, MyEvent>(cb)` — explicit tagged types
14
- * - `makeInspector<typeof MyState, typeof MyEvent>(cb)` — schema constructors (auto-extracts `.Type`)
15
- */
16
- const makeInspector = (onInspect) => ({ onInspect });
17
- /**
18
- * Console inspector that logs events in a readable format
19
- */
20
- const consoleInspector = () => makeInspector((event) => {
21
- const prefix = `[${event.actorId}]`;
22
- switch (event.type) {
23
- case "@machine.spawn":
24
- console.log(prefix, "spawned →", event.initialState._tag);
25
- break;
26
- case "@machine.event":
27
- console.log(prefix, "received", event.event._tag, "in", event.state._tag);
28
- break;
29
- case "@machine.transition":
30
- console.log(prefix, event.fromState._tag, "→", event.toState._tag);
31
- break;
32
- case "@machine.effect":
33
- console.log(prefix, event.effectType, "effect in", event.state._tag);
34
- break;
35
- case "@machine.error":
36
- console.log(prefix, "error in", event.phase, event.state._tag, "-", event.error);
37
- break;
38
- case "@machine.stop":
39
- console.log(prefix, "stopped in", event.finalState._tag);
40
- break;
41
- }
42
- });
43
- /**
44
- * Collecting inspector that stores events in an array for testing
45
- */
46
- const collectingInspector = (events) => ({ onInspect: (event) => events.push(event) });
47
- //#endregion
48
- export { Inspector, collectingInspector, consoleInspector, makeInspector };
@@ -1,13 +0,0 @@
1
- import { Clock, Effect } from "effect";
2
- //#region src-v3/internal/inspection.ts
3
- /**
4
- * Emit an inspection event with timestamp from Clock.
5
- * @internal
6
- */
7
- const emitWithTimestamp = Effect.fn("effect-machine.emitWithTimestamp")(function* (inspector, makeEvent) {
8
- if (inspector === void 0) return;
9
- const timestamp = yield* Clock.currentTimeMillis;
10
- yield* Effect.try(() => inspector.onInspect(makeEvent(timestamp))).pipe(Effect.ignore);
11
- });
12
- //#endregion
13
- export { emitWithTimestamp };
File without changes
File without changes
File without changes
File without changes
File without changes