effect-machine 0.6.0 → 0.7.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 (68) hide show
  1. package/dist/actor.d.ts +2 -2
  2. package/dist/actor.js +12 -14
  3. package/dist/cluster/entity-machine.d.ts +2 -2
  4. package/dist/cluster/entity-machine.js +1 -1
  5. package/dist/cluster/to-entity.d.ts +5 -5
  6. package/dist/cluster/to-entity.js +2 -2
  7. package/dist/errors.d.ts +25 -40
  8. package/dist/errors.js +10 -10
  9. package/dist/inspection.d.ts +3 -3
  10. package/dist/inspection.js +2 -2
  11. package/dist/internal/brands.d.ts +3 -6
  12. package/dist/internal/inspection.js +5 -1
  13. package/dist/internal/transition.d.ts +2 -2
  14. package/dist/internal/transition.js +6 -6
  15. package/dist/internal/utils.js +5 -1
  16. package/dist/machine.d.ts +5 -5
  17. package/dist/machine.js +9 -5
  18. package/dist/persistence/adapter.d.ts +18 -21
  19. package/dist/persistence/adapter.js +4 -4
  20. package/dist/persistence/adapters/in-memory.js +4 -4
  21. package/dist/persistence/persistent-actor.js +9 -9
  22. package/dist/persistence/persistent-machine.d.ts +3 -3
  23. package/dist/schema.d.ts +4 -4
  24. package/dist/schema.js +2 -2
  25. package/dist/slot.d.ts +3 -3
  26. package/dist/slot.js +2 -2
  27. package/dist-v3/_virtual/_rolldown/runtime.js +18 -0
  28. package/dist-v3/actor.d.ts +291 -0
  29. package/dist-v3/actor.js +459 -0
  30. package/dist-v3/cluster/entity-machine.d.ts +90 -0
  31. package/dist-v3/cluster/entity-machine.js +80 -0
  32. package/dist-v3/cluster/index.d.ts +3 -0
  33. package/dist-v3/cluster/index.js +4 -0
  34. package/dist-v3/cluster/to-entity.d.ts +61 -0
  35. package/dist-v3/cluster/to-entity.js +53 -0
  36. package/dist-v3/errors.d.ts +27 -0
  37. package/dist-v3/errors.js +38 -0
  38. package/dist-v3/index.d.ts +13 -0
  39. package/dist-v3/index.js +14 -0
  40. package/dist-v3/inspection.d.ts +125 -0
  41. package/dist-v3/inspection.js +50 -0
  42. package/dist-v3/internal/brands.d.ts +40 -0
  43. package/dist-v3/internal/brands.js +0 -0
  44. package/dist-v3/internal/inspection.d.ts +11 -0
  45. package/dist-v3/internal/inspection.js +15 -0
  46. package/dist-v3/internal/transition.d.ts +160 -0
  47. package/dist-v3/internal/transition.js +238 -0
  48. package/dist-v3/internal/utils.d.ts +60 -0
  49. package/dist-v3/internal/utils.js +51 -0
  50. package/dist-v3/machine.d.ts +278 -0
  51. package/dist-v3/machine.js +317 -0
  52. package/dist-v3/persistence/adapter.d.ts +125 -0
  53. package/dist-v3/persistence/adapter.js +27 -0
  54. package/dist-v3/persistence/adapters/in-memory.d.ts +32 -0
  55. package/dist-v3/persistence/adapters/in-memory.js +176 -0
  56. package/dist-v3/persistence/index.d.ts +5 -0
  57. package/dist-v3/persistence/index.js +6 -0
  58. package/dist-v3/persistence/persistent-actor.d.ts +49 -0
  59. package/dist-v3/persistence/persistent-actor.js +367 -0
  60. package/dist-v3/persistence/persistent-machine.d.ts +105 -0
  61. package/dist-v3/persistence/persistent-machine.js +24 -0
  62. package/dist-v3/schema.d.ts +141 -0
  63. package/dist-v3/schema.js +165 -0
  64. package/dist-v3/slot.d.ts +130 -0
  65. package/dist-v3/slot.js +99 -0
  66. package/dist-v3/testing.d.ts +136 -0
  67. package/dist-v3/testing.js +138 -0
  68. package/package.json +29 -21
@@ -0,0 +1,61 @@
1
+ import { Machine } from "../machine.js";
2
+ import { Schema } from "effect";
3
+ import { Rpc } from "@effect/rpc";
4
+
5
+ //#region src-v3/cluster/to-entity.d.ts
6
+ /**
7
+ * Options for toEntity.
8
+ */
9
+ interface ToEntityOptions {
10
+ /**
11
+ * Entity type name (e.g., "Order", "User")
12
+ */
13
+ readonly type: string;
14
+ }
15
+ /**
16
+ * Default RPC protocol for entity machines.
17
+ *
18
+ * - `Send` - Send event to machine, returns new state
19
+ * - `GetState` - Get current state
20
+ */
21
+ type EntityRpcs<StateSchema extends Schema.Schema.Any, EventSchema extends Schema.Schema.Any> = readonly [Rpc.Rpc<"Send", Schema.Struct<{
22
+ readonly event: EventSchema;
23
+ }>, StateSchema, typeof Schema.Never, never>, Rpc.Rpc<"GetState", typeof Schema.Void, StateSchema, typeof Schema.Never, never>];
24
+ /**
25
+ * Generate an Entity definition from a machine.
26
+ *
27
+ * Creates an Entity with a standard RPC protocol:
28
+ * - `Send(event)` - Process event through machine, returns new state
29
+ * - `GetState()` - Returns current state
30
+ *
31
+ * Schemas are read from the machine - must use `Machine.make({ state, event, initial })`.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const OrderState = State({
36
+ * Pending: { orderId: Schema.String },
37
+ * Shipped: { trackingId: Schema.String },
38
+ * })
39
+ *
40
+ * const OrderEvent = Event({
41
+ * Ship: { trackingId: Schema.String },
42
+ * })
43
+ *
44
+ * const orderMachine = Machine.make({
45
+ * state: OrderState,
46
+ * event: OrderEvent,
47
+ * initial: OrderState.Pending({ orderId: "" }),
48
+ * }).pipe(
49
+ * Machine.on(OrderState.Pending, OrderEvent.Ship, ...),
50
+ * )
51
+ *
52
+ * const OrderEntity = toEntity(orderMachine, { type: "Order" })
53
+ * ```
54
+ */
55
+ declare const toEntity: <S extends {
56
+ readonly _tag: string;
57
+ }, E extends {
58
+ readonly _tag: string;
59
+ }, R>(machine: Machine<S, E, R, any, any, any, any>, options: ToEntityOptions) => any;
60
+ //#endregion
61
+ export { EntityRpcs, ToEntityOptions, toEntity };
@@ -0,0 +1,53 @@
1
+ import { MissingSchemaError } from "../errors.js";
2
+ import { Entity } from "@effect/cluster";
3
+ import { Rpc } from "@effect/rpc";
4
+
5
+ //#region src-v3/cluster/to-entity.ts
6
+ /**
7
+ * Generate Entity definition from a machine.
8
+ *
9
+ * @module
10
+ */
11
+ /**
12
+ * Generate an Entity definition from a machine.
13
+ *
14
+ * Creates an Entity with a standard RPC protocol:
15
+ * - `Send(event)` - Process event through machine, returns new state
16
+ * - `GetState()` - Returns current state
17
+ *
18
+ * Schemas are read from the machine - must use `Machine.make({ state, event, initial })`.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const OrderState = State({
23
+ * Pending: { orderId: Schema.String },
24
+ * Shipped: { trackingId: Schema.String },
25
+ * })
26
+ *
27
+ * const OrderEvent = Event({
28
+ * Ship: { trackingId: Schema.String },
29
+ * })
30
+ *
31
+ * const orderMachine = Machine.make({
32
+ * state: OrderState,
33
+ * event: OrderEvent,
34
+ * initial: OrderState.Pending({ orderId: "" }),
35
+ * }).pipe(
36
+ * Machine.on(OrderState.Pending, OrderEvent.Ship, ...),
37
+ * )
38
+ *
39
+ * const OrderEntity = toEntity(orderMachine, { type: "Order" })
40
+ * ```
41
+ */
42
+ const toEntity = (machine, options) => {
43
+ const stateSchema = machine.stateSchema;
44
+ const eventSchema = machine.eventSchema;
45
+ if (stateSchema === void 0 || eventSchema === void 0) throw new MissingSchemaError({ operation: "toEntity" });
46
+ return Entity.make(options.type, [Rpc.make("Send", {
47
+ payload: { event: eventSchema },
48
+ success: stateSchema
49
+ }), Rpc.make("GetState", { success: stateSchema })]);
50
+ };
51
+
52
+ //#endregion
53
+ export { toEntity };
@@ -0,0 +1,27 @@
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 };
@@ -0,0 +1,38 @@
1
+ import { Schema } from "effect";
2
+
3
+ //#region src-v3/errors.ts
4
+ /**
5
+ * Typed error classes for effect-machine.
6
+ *
7
+ * All errors extend Schema.TaggedError for:
8
+ * - Type-safe catching via Effect.catchTag
9
+ * - Serialization support
10
+ * - Composable error handling
11
+ *
12
+ * @module
13
+ */
14
+ /** Attempted to spawn/restore actor with ID already in use */
15
+ var DuplicateActorError = class extends Schema.TaggedError()("DuplicateActorError", { actorId: Schema.String }) {};
16
+ /** Machine has unprovided effect slots */
17
+ var UnprovidedSlotsError = class extends Schema.TaggedError()("UnprovidedSlotsError", { slots: Schema.Array(Schema.String) }) {};
18
+ /** Operation requires schemas attached to machine */
19
+ var MissingSchemaError = class extends Schema.TaggedError()("MissingSchemaError", { operation: Schema.String }) {};
20
+ /** State/Event schema has no variants */
21
+ var InvalidSchemaError = class extends Schema.TaggedError()("InvalidSchemaError", {}) {};
22
+ /** $match called with missing handler for tag */
23
+ var MissingMatchHandlerError = class extends Schema.TaggedError()("MissingMatchHandlerError", { tag: Schema.String }) {};
24
+ /** Slot handler not found at runtime (internal error) */
25
+ var SlotProvisionError = class extends Schema.TaggedError()("SlotProvisionError", {
26
+ slotName: Schema.String,
27
+ slotType: Schema.Literal("guard", "effect")
28
+ }) {};
29
+ /** Machine.build() validation failed - missing or extra handlers */
30
+ var ProvisionValidationError = class extends Schema.TaggedError()("ProvisionValidationError", {
31
+ missing: Schema.Array(Schema.String),
32
+ extra: Schema.Array(Schema.String)
33
+ }) {};
34
+ /** Assertion failed in testing utilities */
35
+ var AssertionError = class extends Schema.TaggedError()("AssertionError", { message: Schema.String }) {};
36
+
37
+ //#endregion
38
+ export { AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError };
@@ -0,0 +1,13 @@
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 "./persistence/index.js";
9
+ import { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig, PersistOptions, ProvideHandlers, SpawnEffect, StateHandlerContext, Transition, machine_d_exports } from "./machine.js";
10
+ import { ActorRef, ActorSystem, Default, SystemEvent, SystemEventListener } from "./actor.js";
11
+ import { SimulationResult, TestHarness, TestHarnessOptions, assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
12
+ import { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, InspectionEvent, Inspector, SpawnEvent, StopEvent, TransitionEvent, collectingInspector, consoleInspector, makeInspector } from "./inspection.js";
13
+ 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 };
@@ -0,0 +1,14 @@
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
+
14
+ 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 };
@@ -0,0 +1,125 @@
1
+ import { Schema } from "effect";
2
+
3
+ //#region src-v3/inspection.d.ts
4
+ /**
5
+ * Resolve a type param: if it's a Schema, extract `.Type`; otherwise use as-is.
6
+ */
7
+ type ResolveType<T> = T extends Schema.Schema<infer A, infer _I, infer _R> ? A : T;
8
+ /**
9
+ * Event emitted when an actor is spawned
10
+ */
11
+ interface SpawnEvent<S> {
12
+ readonly type: "@machine.spawn";
13
+ readonly actorId: string;
14
+ readonly initialState: S;
15
+ readonly timestamp: number;
16
+ }
17
+ /**
18
+ * Event emitted when an actor receives an event
19
+ */
20
+ interface EventReceivedEvent<S, E> {
21
+ readonly type: "@machine.event";
22
+ readonly actorId: string;
23
+ readonly state: S;
24
+ readonly event: E;
25
+ readonly timestamp: number;
26
+ }
27
+ /**
28
+ * Event emitted when a transition occurs
29
+ */
30
+ interface TransitionEvent<S, E> {
31
+ readonly type: "@machine.transition";
32
+ readonly actorId: string;
33
+ readonly fromState: S;
34
+ readonly toState: S;
35
+ readonly event: E;
36
+ readonly timestamp: number;
37
+ }
38
+ /**
39
+ * Event emitted when a spawn effect runs
40
+ */
41
+ interface EffectEvent<S> {
42
+ readonly type: "@machine.effect";
43
+ readonly actorId: string;
44
+ readonly effectType: "spawn";
45
+ readonly state: S;
46
+ readonly timestamp: number;
47
+ }
48
+ /**
49
+ * Event emitted when a transition handler or spawn effect fails with a defect
50
+ */
51
+ interface ErrorEvent<S, E> {
52
+ readonly type: "@machine.error";
53
+ readonly actorId: string;
54
+ readonly phase: "transition" | "spawn";
55
+ readonly state: S;
56
+ readonly event: E;
57
+ readonly error: string;
58
+ readonly timestamp: number;
59
+ }
60
+ /**
61
+ * Event emitted when an actor stops
62
+ */
63
+ interface StopEvent<S> {
64
+ readonly type: "@machine.stop";
65
+ readonly actorId: string;
66
+ readonly finalState: S;
67
+ readonly timestamp: number;
68
+ }
69
+ /**
70
+ * Union of all inspection events
71
+ */
72
+ type InspectionEvent<S, E> = SpawnEvent<S> | EventReceivedEvent<S, E> | TransitionEvent<S, E> | EffectEvent<S> | ErrorEvent<S, E> | StopEvent<S>;
73
+ /**
74
+ * Convenience alias for untyped inspection events.
75
+ * Useful for general-purpose inspectors that don't need specific state/event types.
76
+ * State and event fields are typed as `{ readonly _tag: string }` so discriminated
77
+ * access to `_tag` works without casting.
78
+ */
79
+ type AnyInspectionEvent = InspectionEvent<{
80
+ readonly _tag: string;
81
+ }, {
82
+ readonly _tag: string;
83
+ }>;
84
+ /**
85
+ * Inspector interface for observing machine behavior
86
+ */
87
+ interface Inspector<S, E> {
88
+ readonly onInspect: (event: InspectionEvent<S, E>) => void;
89
+ }
90
+ /**
91
+ * Inspector service tag - optional service for machine introspection
92
+ * Uses `any` types to allow variance flexibility when providing the service
93
+ */
94
+ declare const Inspector: any;
95
+ /**
96
+ * Create an inspector from a callback function.
97
+ *
98
+ * Type params accept either raw tagged types or Schema constructors:
99
+ * - `makeInspector(cb)` — defaults to `AnyInspectionEvent`
100
+ * - `makeInspector<MyState, MyEvent>(cb)` — explicit tagged types
101
+ * - `makeInspector<typeof MyState, typeof MyEvent>(cb)` — schema constructors (auto-extracts `.Type`)
102
+ */
103
+ declare const makeInspector: <S = {
104
+ readonly _tag: string;
105
+ }, E = {
106
+ readonly _tag: string;
107
+ }>(onInspect: (event: InspectionEvent<ResolveType<S>, ResolveType<E>>) => void) => Inspector<ResolveType<S>, ResolveType<E>>;
108
+ /**
109
+ * Console inspector that logs events in a readable format
110
+ */
111
+ declare const consoleInspector: () => Inspector<{
112
+ readonly _tag: string;
113
+ }, {
114
+ readonly _tag: string;
115
+ }>;
116
+ /**
117
+ * Collecting inspector that stores events in an array for testing
118
+ */
119
+ declare const collectingInspector: <S extends {
120
+ readonly _tag: string;
121
+ }, E extends {
122
+ readonly _tag: string;
123
+ }>(events: InspectionEvent<S, E>[]) => Inspector<S, E>;
124
+ //#endregion
125
+ export { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, InspectionEvent, Inspector, SpawnEvent, StopEvent, TransitionEvent, collectingInspector, consoleInspector, makeInspector };
@@ -0,0 +1,50 @@
1
+ import { Context } from "effect";
2
+
3
+ //#region src-v3/inspection.ts
4
+ /**
5
+ * Inspector service tag - optional service for machine introspection
6
+ * Uses `any` types to allow variance flexibility when providing the service
7
+ */
8
+ const Inspector = Context.GenericTag("@effect/machine/Inspector");
9
+ /**
10
+ * Create an inspector from a callback function.
11
+ *
12
+ * Type params accept either raw tagged types or Schema constructors:
13
+ * - `makeInspector(cb)` — defaults to `AnyInspectionEvent`
14
+ * - `makeInspector<MyState, MyEvent>(cb)` — explicit tagged types
15
+ * - `makeInspector<typeof MyState, typeof MyEvent>(cb)` — schema constructors (auto-extracts `.Type`)
16
+ */
17
+ const makeInspector = (onInspect) => ({ onInspect });
18
+ /**
19
+ * Console inspector that logs events in a readable format
20
+ */
21
+ const consoleInspector = () => makeInspector((event) => {
22
+ const prefix = `[${event.actorId}]`;
23
+ switch (event.type) {
24
+ case "@machine.spawn":
25
+ console.log(prefix, "spawned →", event.initialState._tag);
26
+ break;
27
+ case "@machine.event":
28
+ console.log(prefix, "received", event.event._tag, "in", event.state._tag);
29
+ break;
30
+ case "@machine.transition":
31
+ console.log(prefix, event.fromState._tag, "→", event.toState._tag);
32
+ break;
33
+ case "@machine.effect":
34
+ console.log(prefix, event.effectType, "effect in", event.state._tag);
35
+ break;
36
+ case "@machine.error":
37
+ console.log(prefix, "error in", event.phase, event.state._tag, "-", event.error);
38
+ break;
39
+ case "@machine.stop":
40
+ console.log(prefix, "stopped in", event.finalState._tag);
41
+ break;
42
+ }
43
+ });
44
+ /**
45
+ * Collecting inspector that stores events in an array for testing
46
+ */
47
+ const collectingInspector = (events) => ({ onInspect: (event) => events.push(event) });
48
+
49
+ //#endregion
50
+ export { Inspector, collectingInspector, consoleInspector, makeInspector };
@@ -0,0 +1,40 @@
1
+ import { Brand } from "effect";
2
+
3
+ //#region src-v3/internal/brands.d.ts
4
+ declare const StateTypeId: unique symbol;
5
+ declare const EventTypeId: unique symbol;
6
+ type StateTypeId = typeof StateTypeId;
7
+ type EventTypeId = typeof EventTypeId;
8
+ interface StateBrand extends Brand.Brand<StateTypeId> {}
9
+ interface EventBrand extends Brand.Brand<EventTypeId> {}
10
+ type BrandedState = {
11
+ readonly _tag: string;
12
+ } & StateBrand;
13
+ type BrandedEvent = {
14
+ readonly _tag: string;
15
+ } & EventBrand;
16
+ declare const SchemaIdTypeId: unique symbol;
17
+ type SchemaIdTypeId = typeof SchemaIdTypeId;
18
+ /**
19
+ * Brand that captures the schema definition type D.
20
+ * Two schemas with identical definition shapes will have compatible brands.
21
+ * Different definitions = incompatible brands.
22
+ */
23
+ interface SchemaIdBrand<_D extends Record<string, unknown>> extends Brand.Brand<SchemaIdTypeId> {}
24
+ /**
25
+ * Full state brand: combines base state brand with schema-specific brand
26
+ */
27
+ type FullStateBrand<D extends Record<string, unknown>> = StateBrand & SchemaIdBrand<D>;
28
+ /**
29
+ * Full event brand: combines base event brand with schema-specific brand
30
+ */
31
+ type FullEventBrand<D extends Record<string, unknown>> = EventBrand & SchemaIdBrand<D>;
32
+ /**
33
+ * Value or constructor for a tagged type.
34
+ * Accepts both plain values (empty structs) and constructor functions (non-empty structs).
35
+ */
36
+ type TaggedOrConstructor<T extends {
37
+ readonly _tag: string;
38
+ }> = T | ((...args: never[]) => T);
39
+ //#endregion
40
+ export { BrandedEvent, BrandedState, EventBrand, EventTypeId, FullEventBrand, FullStateBrand, SchemaIdBrand, StateBrand, StateTypeId, TaggedOrConstructor };
File without changes
@@ -0,0 +1,11 @@
1
+ import { InspectionEvent, Inspector } from "../inspection.js";
2
+ import { Effect } from "effect";
3
+
4
+ //#region src-v3/internal/inspection.d.ts
5
+ /**
6
+ * Emit an inspection event with timestamp from Clock.
7
+ * @internal
8
+ */
9
+ declare const emitWithTimestamp: <S, E>(inspector: Inspector<S, E> | undefined, makeEvent: (timestamp: number) => InspectionEvent<S, E>) => Effect.Effect<void, never, never>;
10
+ //#endregion
11
+ export { emitWithTimestamp };
@@ -0,0 +1,15 @@
1
+ import { Clock, Effect } from "effect";
2
+
3
+ //#region src-v3/internal/inspection.ts
4
+ /**
5
+ * Emit an inspection event with timestamp from Clock.
6
+ * @internal
7
+ */
8
+ const emitWithTimestamp = Effect.fn("effect-machine.emitWithTimestamp")(function* (inspector, makeEvent) {
9
+ if (inspector === void 0) return;
10
+ const timestamp = yield* Clock.currentTimeMillis;
11
+ yield* Effect.try(() => inspector.onInspect(makeEvent(timestamp))).pipe(Effect.ignore);
12
+ });
13
+
14
+ //#endregion
15
+ export { emitWithTimestamp };
@@ -0,0 +1,160 @@
1
+ import { EffectsDef, GuardsDef } from "../slot.js";
2
+ import { BuiltMachine, Machine, MachineRef, SpawnEffect, Transition } from "../machine.js";
3
+ import { ActorSystem } from "../actor.js";
4
+ import { Cause, Effect, Scope } from "effect";
5
+
6
+ //#region src-v3/internal/transition.d.ts
7
+ /**
8
+ * Result of executing a transition.
9
+ */
10
+ interface TransitionExecutionResult<S> {
11
+ /** New state after transition (or current state if no transition matched) */
12
+ readonly newState: S;
13
+ /** Whether a transition was executed */
14
+ readonly transitioned: boolean;
15
+ /** Whether reenter was specified on the transition */
16
+ readonly reenter: boolean;
17
+ }
18
+ /**
19
+ * Run a transition handler and return the new state.
20
+ * Shared logic for executing handlers with proper context.
21
+ *
22
+ * Used by:
23
+ * - executeTransition (actor event loop, testing)
24
+ * - persistent-actor replay (restore, replayTo)
25
+ *
26
+ * @internal
27
+ */
28
+ declare const runTransitionHandler: <S extends {
29
+ readonly _tag: string;
30
+ }, E extends {
31
+ readonly _tag: string;
32
+ }, R, GD extends GuardsDef, EFD extends EffectsDef>(machine: Machine<S, E, R, Record<string, never>, Record<string, never>, GD, EFD>, transition: Transition<S, E, GD, EFD, R>, state: S, event: E, self: MachineRef<E>, system: ActorSystem) => Effect.Effect<S, never, Exclude<R, unknown>>;
33
+ /**
34
+ * Execute a transition for a given state and event.
35
+ * Handles transition resolution, handler invocation, and guard/effect slot creation.
36
+ *
37
+ * Used by:
38
+ * - processEvent in actor.ts (actual actor event loop)
39
+ * - simulate in testing.ts (pure transition simulation)
40
+ * - createTestHarness.send in testing.ts (step-by-step testing)
41
+ *
42
+ * @internal
43
+ */
44
+ declare const executeTransition: <S extends {
45
+ readonly _tag: string;
46
+ }, E extends {
47
+ readonly _tag: string;
48
+ }, R, GD extends GuardsDef, EFD extends EffectsDef>(machine: Machine<S, E, R, Record<string, never>, Record<string, never>, GD, EFD>, currentState: S, event: E, self: MachineRef<E>, system: ActorSystem) => Effect.Effect<{
49
+ newState: S;
50
+ transitioned: boolean;
51
+ reenter: boolean;
52
+ }, never, Exclude<R, unknown>>;
53
+ /**
54
+ * Optional hooks for event processing inspection/tracing.
55
+ */
56
+ interface ProcessEventHooks<S, E> {
57
+ /** Called before running spawn effects */
58
+ readonly onSpawnEffect?: (state: S) => Effect.Effect<void>;
59
+ /** Called after transition completes */
60
+ readonly onTransition?: (from: S, to: S, event: E) => Effect.Effect<void>;
61
+ /** Called when a transition handler or spawn effect fails with a defect */
62
+ readonly onError?: (info: ProcessEventError<S, E>) => Effect.Effect<void>;
63
+ }
64
+ /**
65
+ * Error info for inspection hooks.
66
+ */
67
+ interface ProcessEventError<S, E> {
68
+ readonly phase: "transition" | "spawn";
69
+ readonly state: S;
70
+ readonly event: E;
71
+ readonly cause: Cause.Cause<unknown>;
72
+ }
73
+ /**
74
+ * Result of processing an event through the machine.
75
+ */
76
+ interface ProcessEventResult<S> {
77
+ /** New state after processing */
78
+ readonly newState: S;
79
+ /** Previous state before processing */
80
+ readonly previousState: S;
81
+ /** Whether a transition occurred */
82
+ readonly transitioned: boolean;
83
+ /** Whether lifecycle effects ran (state change or reenter) */
84
+ readonly lifecycleRan: boolean;
85
+ /** Whether new state is final */
86
+ readonly isFinal: boolean;
87
+ }
88
+ /**
89
+ * Process a single event through the machine.
90
+ *
91
+ * Handles:
92
+ * - Transition execution
93
+ * - State scope lifecycle (close old, create new)
94
+ * - Running spawn effects
95
+ *
96
+ * Optional hooks allow inspection/tracing without coupling to specific impl.
97
+ *
98
+ * @internal
99
+ */
100
+ declare const processEventCore: <S extends {
101
+ readonly _tag: string;
102
+ }, E extends {
103
+ readonly _tag: string;
104
+ }, R, GD extends GuardsDef, EFD extends EffectsDef>(machine: Machine<S, E, R, Record<string, never>, Record<string, never>, GD, EFD>, currentState: S, event: E, self: MachineRef<E>, stateScopeRef: {
105
+ current: Scope.CloseableScope;
106
+ }, system: ActorSystem, hooks?: ProcessEventHooks<S, E> | undefined) => Effect.Effect<{
107
+ newState: any;
108
+ previousState: S;
109
+ transitioned: boolean;
110
+ lifecycleRan: any;
111
+ isFinal: boolean;
112
+ }, unknown, unknown>;
113
+ /**
114
+ * Run spawn effects for a state (forked into state scope, auto-cancelled on state exit).
115
+ *
116
+ * @internal
117
+ */
118
+ declare const runSpawnEffects: <S extends {
119
+ readonly _tag: string;
120
+ }, E extends {
121
+ readonly _tag: string;
122
+ }, R, GD extends GuardsDef, EFD extends EffectsDef>(machine: Machine<S, E, R, Record<string, never>, Record<string, never>, GD, EFD>, state: S, event: E, self: MachineRef<E>, stateScope: Scope.CloseableScope, system: ActorSystem, onError?: ((info: ProcessEventError<S, E>) => Effect.Effect<void>) | undefined) => Effect.Effect<void, never, unknown>;
123
+ /**
124
+ * Resolve which transition should fire for a given state and event.
125
+ * Uses indexed O(1) lookup. First matching transition wins.
126
+ */
127
+ declare const resolveTransition: <S extends {
128
+ readonly _tag: string;
129
+ }, E extends {
130
+ readonly _tag: string;
131
+ }, R>(machine: Machine<S, E, R, any, any, any, any>, currentState: S, event: E) => (typeof machine.transitions)[number] | undefined;
132
+ /**
133
+ * Invalidate cached index for a machine (call after mutation).
134
+ */
135
+ declare const invalidateIndex: (machine: object) => void;
136
+ /**
137
+ * Find all transitions matching a state/event pair.
138
+ * Returns empty array if no matches.
139
+ *
140
+ * Accepts both `Machine` and `BuiltMachine`.
141
+ * O(1) lookup after first access (index is lazily built).
142
+ */
143
+ declare const findTransitions: <S extends {
144
+ readonly _tag: string;
145
+ }, E extends {
146
+ readonly _tag: string;
147
+ }, R, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>>(input: Machine<S, E, R, any, any, GD, EFD> | BuiltMachine<S, E, R>, stateTag: string, eventTag: string) => ReadonlyArray<Transition<S, E, GD, EFD, R>>;
148
+ /**
149
+ * Find all spawn effects for a state.
150
+ * Returns empty array if no matches.
151
+ *
152
+ * O(1) lookup after first access (index is lazily built).
153
+ */
154
+ declare const findSpawnEffects: <S extends {
155
+ readonly _tag: string;
156
+ }, E extends {
157
+ readonly _tag: string;
158
+ }, R, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>>(machine: Machine<S, E, R, any, any, GD, EFD>, stateTag: string) => ReadonlyArray<SpawnEffect<S, E, EFD, R>>;
159
+ //#endregion
160
+ export { ProcessEventError, ProcessEventHooks, ProcessEventResult, TransitionExecutionResult, executeTransition, findSpawnEffects, findTransitions, invalidateIndex, processEventCore, resolveTransition, runSpawnEffects, runTransitionHandler };