effect-machine 0.8.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.
- package/README.md +76 -16
- package/dist/_virtual/_rolldown/runtime.js +6 -11
- package/dist/actor.d.ts +58 -72
- package/dist/actor.js +166 -32
- package/dist/cluster/entity-machine.d.ts +0 -1
- package/dist/cluster/entity-machine.js +6 -6
- package/dist/cluster/index.js +1 -2
- package/dist/cluster/to-entity.js +1 -3
- package/dist/errors.d.ts +12 -1
- package/dist/errors.js +8 -3
- package/dist/index.d.ts +4 -4
- package/dist/index.js +2 -3
- package/dist/inspection.js +1 -3
- package/dist/internal/inspection.js +1 -3
- package/dist/internal/transition.d.ts +26 -2
- package/dist/internal/transition.js +37 -10
- package/dist/internal/utils.d.ts +7 -2
- package/dist/internal/utils.js +1 -3
- package/dist/machine.d.ts +66 -4
- package/dist/machine.js +67 -31
- package/dist/persistence/adapter.js +1 -3
- package/dist/persistence/adapters/in-memory.js +1 -3
- package/dist/persistence/index.js +1 -2
- package/dist/persistence/persistent-actor.js +54 -19
- package/dist/persistence/persistent-machine.js +1 -3
- package/dist/schema.js +1 -3
- package/dist/slot.js +1 -3
- package/dist/testing.js +58 -6
- package/package.json +19 -18
- package/v3/dist/_virtual/_rolldown/runtime.js +13 -0
- package/{dist-v3 → v3/dist}/actor.d.ts +65 -78
- package/{dist-v3 → v3/dist}/actor.js +173 -37
- package/{dist-v3 → v3/dist}/cluster/entity-machine.d.ts +1 -2
- package/{dist-v3 → v3/dist}/cluster/entity-machine.js +9 -9
- package/{dist-v3 → v3/dist}/cluster/index.js +1 -2
- package/{dist-v3 → v3/dist}/cluster/to-entity.d.ts +1 -1
- package/{dist-v3 → v3/dist}/cluster/to-entity.js +2 -4
- package/v3/dist/errors.d.ts +76 -0
- package/{dist-v3 → v3/dist}/errors.js +9 -4
- package/v3/dist/index.d.ts +13 -0
- package/v3/dist/index.js +13 -0
- package/{dist-v3 → v3/dist}/inspection.d.ts +53 -8
- package/v3/dist/inspection.js +156 -0
- package/{dist-v3 → v3/dist}/internal/brands.d.ts +1 -1
- package/{dist-v3 → v3/dist}/internal/inspection.d.ts +1 -1
- package/v3/dist/internal/inspection.js +20 -0
- package/{dist-v3 → v3/dist}/internal/transition.d.ts +35 -11
- package/{dist-v3 → v3/dist}/internal/transition.js +47 -17
- package/{dist-v3 → v3/dist}/internal/utils.d.ts +9 -4
- package/{dist-v3 → v3/dist}/internal/utils.js +2 -4
- package/{dist-v3 → v3/dist}/machine.d.ts +86 -10
- package/{dist-v3 → v3/dist}/machine.js +130 -33
- package/{dist-v3 → v3/dist}/persistence/adapter.d.ts +18 -5
- package/{dist-v3 → v3/dist}/persistence/adapter.js +2 -4
- package/{dist-v3 → v3/dist}/persistence/adapters/in-memory.d.ts +1 -1
- package/{dist-v3 → v3/dist}/persistence/adapters/in-memory.js +2 -4
- package/{dist-v3 → v3/dist}/persistence/index.js +1 -2
- package/{dist-v3 → v3/dist}/persistence/persistent-actor.d.ts +7 -6
- package/{dist-v3 → v3/dist}/persistence/persistent-actor.js +59 -22
- package/{dist-v3 → v3/dist}/persistence/persistent-machine.d.ts +1 -1
- package/{dist-v3 → v3/dist}/persistence/persistent-machine.js +2 -4
- package/{dist-v3 → v3/dist}/schema.d.ts +1 -1
- package/{dist-v3 → v3/dist}/schema.js +6 -5
- package/{dist-v3 → v3/dist}/slot.d.ts +4 -3
- package/{dist-v3 → v3/dist}/slot.js +2 -4
- package/{dist-v3 → v3/dist}/testing.d.ts +14 -8
- package/{dist-v3 → v3/dist}/testing.js +61 -9
- package/dist-v3/_virtual/_rolldown/runtime.js +0 -18
- package/dist-v3/errors.d.ts +0 -27
- package/dist-v3/index.d.ts +0 -13
- package/dist-v3/index.js +0 -14
- package/dist-v3/inspection.js +0 -50
- package/dist-v3/internal/inspection.js +0 -15
- /package/{dist-v3 → v3/dist}/cluster/index.d.ts +0 -0
- /package/{dist-v3 → v3/dist}/internal/brands.js +0 -0
- /package/{dist-v3 → v3/dist}/persistence/index.d.ts +0 -0
|
@@ -2,7 +2,6 @@ import { processEventCore, runSpawnEffects } from "../internal/transition.js";
|
|
|
2
2
|
import { ActorSystem } from "../actor.js";
|
|
3
3
|
import { Effect, Option, Queue, Ref, Scope } from "effect";
|
|
4
4
|
import { Entity } from "effect/unstable/cluster";
|
|
5
|
-
|
|
6
5
|
//#region src/cluster/entity-machine.ts
|
|
7
6
|
/**
|
|
8
7
|
* EntityMachine adapter - wires a machine to a cluster Entity layer.
|
|
@@ -55,10 +54,12 @@ const EntityMachine = { layer: (entity, machine, options) => {
|
|
|
55
54
|
if (Option.isNone(existingSystem)) return yield* Effect.die("EntityMachine requires ActorSystem in context");
|
|
56
55
|
const system = existingSystem.value;
|
|
57
56
|
const internalQueue = yield* Queue.unbounded();
|
|
57
|
+
const clusterSend = Effect.fn("effect-machine.cluster.self.send")(function* (event) {
|
|
58
|
+
yield* Queue.offer(internalQueue, event);
|
|
59
|
+
});
|
|
58
60
|
const self = {
|
|
59
|
-
send:
|
|
60
|
-
|
|
61
|
-
}),
|
|
61
|
+
send: clusterSend,
|
|
62
|
+
cast: clusterSend,
|
|
62
63
|
spawn: (childId, childMachine) => system.spawn(childId, childMachine).pipe(Effect.provideService(ActorSystem, system))
|
|
63
64
|
};
|
|
64
65
|
const stateRef = yield* Ref.make(initialState);
|
|
@@ -75,6 +76,5 @@ const EntityMachine = { layer: (entity, machine, options) => {
|
|
|
75
76
|
});
|
|
76
77
|
return entity.toLayer(layer());
|
|
77
78
|
} };
|
|
78
|
-
|
|
79
79
|
//#endregion
|
|
80
|
-
export { EntityMachine };
|
|
80
|
+
export { EntityMachine };
|
package/dist/cluster/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { MissingSchemaError } from "../errors.js";
|
|
2
2
|
import { Entity } from "effect/unstable/cluster";
|
|
3
3
|
import { Rpc } from "effect/unstable/rpc";
|
|
4
|
-
|
|
5
4
|
//#region src/cluster/to-entity.ts
|
|
6
5
|
/**
|
|
7
6
|
* Generate Entity definition from a machine.
|
|
@@ -48,6 +47,5 @@ const toEntity = (machine, options) => {
|
|
|
48
47
|
success: stateSchema
|
|
49
48
|
}), Rpc.make("GetState", { success: stateSchema })]);
|
|
50
49
|
};
|
|
51
|
-
|
|
52
50
|
//#endregion
|
|
53
|
-
export { toEntity };
|
|
51
|
+
export { toEntity };
|
package/dist/errors.d.ts
CHANGED
|
@@ -42,5 +42,16 @@ declare const AssertionError_base: Schema.ErrorClass<AssertionError, Schema.Tagg
|
|
|
42
42
|
}>, effect_Cause0.YieldableError>;
|
|
43
43
|
/** Assertion failed in testing utilities */
|
|
44
44
|
declare class AssertionError extends AssertionError_base {}
|
|
45
|
+
declare const ActorStoppedError_base: Schema.ErrorClass<ActorStoppedError, Schema.TaggedStruct<"ActorStoppedError", {
|
|
46
|
+
readonly actorId: Schema.String;
|
|
47
|
+
}>, effect_Cause0.YieldableError>;
|
|
48
|
+
/** Actor was stopped while a call/ask was pending */
|
|
49
|
+
declare class ActorStoppedError extends ActorStoppedError_base {}
|
|
50
|
+
declare const NoReplyError_base: Schema.ErrorClass<NoReplyError, Schema.TaggedStruct<"NoReplyError", {
|
|
51
|
+
readonly actorId: Schema.String;
|
|
52
|
+
readonly eventTag: Schema.String;
|
|
53
|
+
}>, effect_Cause0.YieldableError>;
|
|
54
|
+
/** ask() was used but the transition handler did not call reply */
|
|
55
|
+
declare class NoReplyError extends NoReplyError_base {}
|
|
45
56
|
//#endregion
|
|
46
|
-
export { AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError };
|
|
57
|
+
export { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError };
|
package/dist/errors.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
|
-
|
|
3
2
|
//#region src/errors.ts
|
|
4
3
|
/**
|
|
5
4
|
* Typed error classes for effect-machine.
|
|
@@ -33,6 +32,12 @@ var ProvisionValidationError = class extends Schema.TaggedErrorClass()("Provisio
|
|
|
33
32
|
}) {};
|
|
34
33
|
/** Assertion failed in testing utilities */
|
|
35
34
|
var AssertionError = class extends Schema.TaggedErrorClass()("AssertionError", { message: Schema.String }) {};
|
|
36
|
-
|
|
35
|
+
/** Actor was stopped while a call/ask was pending */
|
|
36
|
+
var ActorStoppedError = class extends Schema.TaggedErrorClass()("ActorStoppedError", { actorId: Schema.String }) {};
|
|
37
|
+
/** ask() was used but the transition handler did not call reply */
|
|
38
|
+
var NoReplyError = class extends Schema.TaggedErrorClass()("NoReplyError", {
|
|
39
|
+
actorId: Schema.String,
|
|
40
|
+
eventTag: Schema.String
|
|
41
|
+
}) {};
|
|
37
42
|
//#endregion
|
|
38
|
-
export { AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError };
|
|
43
|
+
export { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { EffectHandlers, EffectSlot, EffectSlots, EffectsDef, EffectsSchema, GuardHandlers, GuardSlot, GuardSlots, GuardsDef, GuardsSchema, MachineContext, Slot } from "./slot.js";
|
|
2
2
|
import { Event, MachineEventSchema, MachineStateSchema, State } from "./schema.js";
|
|
3
3
|
import { PersistenceConfig, PersistentMachine, isPersistentMachine } from "./persistence/persistent-machine.js";
|
|
4
|
-
import { AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError } from "./errors.js";
|
|
4
|
+
import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError } from "./errors.js";
|
|
5
|
+
import { ProcessEventResult } from "./internal/transition.js";
|
|
5
6
|
import { PersistentActorRef, createPersistentActor, restorePersistentActor } from "./persistence/persistent-actor.js";
|
|
6
7
|
import { ActorMetadata, PersistedEvent, PersistenceAdapter, PersistenceAdapterTag, PersistenceError, RestoreFailure, RestoreResult, Snapshot, VersionConflictError } from "./persistence/adapter.js";
|
|
7
8
|
import { InMemoryPersistenceAdapter, makeInMemoryPersistenceAdapter } from "./persistence/adapters/in-memory.js";
|
|
8
|
-
import "./persistence/index.js";
|
|
9
9
|
import { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig, PersistOptions, ProvideHandlers, SpawnEffect, StateHandlerContext, TaskOptions, Transition, machine_d_exports } from "./machine.js";
|
|
10
|
-
import { ActorRef, ActorSystem, Default, SystemEvent, SystemEventListener } from "./actor.js";
|
|
10
|
+
import { ActorRef, ActorRefSync, ActorSystem, Default, SystemEvent, SystemEventListener } from "./actor.js";
|
|
11
11
|
import { SimulationResult, TestHarness, TestHarnessOptions, assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
|
|
12
12
|
import { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, InspectionEvent, Inspector, InspectorHandler, SpawnEvent, StopEvent, TaskEvent, TracingInspectorOptions, TransitionEvent, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector } 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, 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, 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 TaskEvent, type TaskOptions, type TestHarness, type TestHarnessOptions, type TracingInspectorOptions, type Transition, type TransitionEvent, UnprovidedSlotsError, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createPersistentActor, createTestHarness, isPersistentMachine, makeInMemoryPersistenceAdapter, makeInspector, makeInspectorEffect, restorePersistentActor, simulate, tracingInspector };
|
|
13
|
+
export { type ActorMetadata, type ActorRef, type ActorRefSync, ActorStoppedError, 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, 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, type PersistOptions, type PersistedEvent, type PersistenceAdapter, PersistenceAdapterTag, type PersistenceConfig, PersistenceError, type PersistentActorRef, type PersistentMachine, type ProcessEventResult, 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 TaskEvent, type TaskOptions, type TestHarness, type TestHarnessOptions, type TracingInspectorOptions, type Transition, type TransitionEvent, UnprovidedSlotsError, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createPersistentActor, createTestHarness, isPersistentMachine, makeInMemoryPersistenceAdapter, makeInspector, makeInspectorEffect, restorePersistentActor, simulate, tracingInspector };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Inspector, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector } from "./inspection.js";
|
|
2
|
-
import { AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError } from "./errors.js";
|
|
2
|
+
import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError } from "./errors.js";
|
|
3
3
|
import { isPersistentMachine } from "./persistence/persistent-machine.js";
|
|
4
4
|
import { Slot } from "./slot.js";
|
|
5
5
|
import { machine_exports } from "./machine.js";
|
|
@@ -10,5 +10,4 @@ import { Event, State } from "./schema.js";
|
|
|
10
10
|
import { assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
|
|
11
11
|
import { InMemoryPersistenceAdapter, makeInMemoryPersistenceAdapter } from "./persistence/adapters/in-memory.js";
|
|
12
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, combineInspectors, consoleInspector, createPersistentActor, createTestHarness, isPersistentMachine, makeInMemoryPersistenceAdapter, makeInspector, makeInspectorEffect, restorePersistentActor, simulate, tracingInspector };
|
|
13
|
+
export { ActorStoppedError, Default as ActorSystemDefault, ActorSystem as ActorSystemService, AssertionError, DuplicateActorError, Event, InMemoryPersistenceAdapter, Inspector as InspectorService, InvalidSchemaError, machine_exports as Machine, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceAdapterTag, PersistenceError, ProvisionValidationError, Slot, SlotProvisionError, State, UnprovidedSlotsError, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createPersistentActor, createTestHarness, isPersistentMachine, makeInMemoryPersistenceAdapter, makeInspector, makeInspectorEffect, restorePersistentActor, simulate, tracingInspector };
|
package/dist/inspection.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Effect, Option, ServiceMap } from "effect";
|
|
2
|
-
|
|
3
2
|
//#region src/inspection.ts
|
|
4
3
|
/**
|
|
5
4
|
* Inspector service tag - optional service for machine introspection
|
|
@@ -139,6 +138,5 @@ const consoleInspector = () => makeInspector((event) => {
|
|
|
139
138
|
const collectingInspector = (events) => ({ onInspect: (event) => {
|
|
140
139
|
events.push(event);
|
|
141
140
|
} });
|
|
142
|
-
|
|
143
141
|
//#endregion
|
|
144
|
-
export { Inspector, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector };
|
|
142
|
+
export { Inspector, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Clock, Effect } from "effect";
|
|
2
|
-
|
|
3
2
|
//#region src/internal/inspection.ts
|
|
4
3
|
/**
|
|
5
4
|
* Emit an inspection event with timestamp from Clock.
|
|
@@ -17,6 +16,5 @@ const emitWithTimestamp = Effect.fn("effect-machine.emitWithTimestamp")(function
|
|
|
17
16
|
});
|
|
18
17
|
if (Effect.isEffect(result)) yield* result.pipe(Effect.catchCause(() => Effect.void));
|
|
19
18
|
});
|
|
20
|
-
|
|
21
19
|
//#endregion
|
|
22
|
-
export { emitWithTimestamp };
|
|
20
|
+
export { emitWithTimestamp };
|
|
@@ -29,7 +29,11 @@ declare const runTransitionHandler: <S extends {
|
|
|
29
29
|
readonly _tag: string;
|
|
30
30
|
}, E extends {
|
|
31
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, actorId: string) => Effect.Effect<
|
|
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, actorId: string) => Effect.Effect<{
|
|
33
|
+
newState: S;
|
|
34
|
+
hasReply: boolean;
|
|
35
|
+
reply: unknown;
|
|
36
|
+
}, never, Exclude<R, MachineContext<S, E, MachineRef<E>>>>;
|
|
33
37
|
/**
|
|
34
38
|
* Execute a transition for a given state and event.
|
|
35
39
|
* Handles transition resolution, handler invocation, and guard/effect slot creation.
|
|
@@ -49,6 +53,8 @@ declare const executeTransition: <S extends {
|
|
|
49
53
|
newState: S;
|
|
50
54
|
transitioned: boolean;
|
|
51
55
|
reenter: boolean;
|
|
56
|
+
hasReply: boolean;
|
|
57
|
+
reply: unknown;
|
|
52
58
|
}, never, Exclude<R, MachineContext<S, E, MachineRef<E>>>>;
|
|
53
59
|
/**
|
|
54
60
|
* Optional hooks for event processing inspection/tracing.
|
|
@@ -84,7 +90,22 @@ interface ProcessEventResult<S> {
|
|
|
84
90
|
readonly lifecycleRan: boolean;
|
|
85
91
|
/** Whether new state is final */
|
|
86
92
|
readonly isFinal: boolean;
|
|
93
|
+
/** Whether the handler provided a reply (structural, not value-based) */
|
|
94
|
+
readonly hasReply: boolean;
|
|
95
|
+
/** Domain reply value from handler (used by ask). Only meaningful when hasReply is true. */
|
|
96
|
+
readonly reply?: unknown;
|
|
97
|
+
/** Whether the event was postponed (buffered for retry after next state change) */
|
|
98
|
+
readonly postponed: boolean;
|
|
87
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Check if an event should be postponed in the current state.
|
|
102
|
+
* @internal
|
|
103
|
+
*/
|
|
104
|
+
declare const shouldPostpone: <S extends {
|
|
105
|
+
readonly _tag: string;
|
|
106
|
+
}, E extends {
|
|
107
|
+
readonly _tag: string;
|
|
108
|
+
}, R>(machine: Machine<S, E, R, any, any, any, any>, stateTag: string, eventTag: string) => boolean;
|
|
88
109
|
/**
|
|
89
110
|
* Process a single event through the machine.
|
|
90
111
|
*
|
|
@@ -109,6 +130,9 @@ declare const processEventCore: <S extends {
|
|
|
109
130
|
transitioned: boolean;
|
|
110
131
|
lifecycleRan: boolean;
|
|
111
132
|
isFinal: boolean;
|
|
133
|
+
hasReply: boolean;
|
|
134
|
+
reply: unknown;
|
|
135
|
+
postponed: boolean;
|
|
112
136
|
}, never, Exclude<R, MachineContext<S, E, MachineRef<E>>> | Exclude<Exclude<R, MachineContext<S, E, MachineRef<E>>>, Scope.Scope>>;
|
|
113
137
|
/**
|
|
114
138
|
* Run spawn effects for a state (forked into state scope, auto-cancelled on state exit).
|
|
@@ -157,4 +181,4 @@ declare const findSpawnEffects: <S extends {
|
|
|
157
181
|
readonly _tag: string;
|
|
158
182
|
}, 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
183
|
//#endregion
|
|
160
|
-
export { ProcessEventError, ProcessEventHooks, ProcessEventResult, TransitionExecutionResult, executeTransition, findSpawnEffects, findTransitions, invalidateIndex, processEventCore, resolveTransition, runSpawnEffects, runTransitionHandler };
|
|
184
|
+
export { ProcessEventError, ProcessEventHooks, ProcessEventResult, TransitionExecutionResult, executeTransition, findSpawnEffects, findTransitions, invalidateIndex, processEventCore, resolveTransition, runSpawnEffects, runTransitionHandler, shouldPostpone };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { INTERNAL_ENTER_EVENT, isEffect } from "./utils.js";
|
|
2
2
|
import { BuiltMachine } from "../machine.js";
|
|
3
3
|
import { Cause, Effect, Exit, Scope } from "effect";
|
|
4
|
-
|
|
5
4
|
//#region src/internal/transition.ts
|
|
6
5
|
/**
|
|
7
6
|
* Transition execution and indexing.
|
|
@@ -38,8 +37,18 @@ const runTransitionHandler = Effect.fn("effect-machine.runTransitionHandler")(fu
|
|
|
38
37
|
guards,
|
|
39
38
|
effects
|
|
40
39
|
};
|
|
41
|
-
const
|
|
42
|
-
|
|
40
|
+
const raw = transition.handler(handlerCtx);
|
|
41
|
+
const resolved = isEffect(raw) ? yield* raw.pipe(Effect.provideService(machine.Context, ctx)) : raw;
|
|
42
|
+
if (resolved !== null && typeof resolved === "object" && "state" in resolved && "reply" in resolved && !("_tag" in resolved)) return {
|
|
43
|
+
newState: resolved.state,
|
|
44
|
+
hasReply: true,
|
|
45
|
+
reply: resolved.reply
|
|
46
|
+
};
|
|
47
|
+
return {
|
|
48
|
+
newState: resolved,
|
|
49
|
+
hasReply: false,
|
|
50
|
+
reply: void 0
|
|
51
|
+
};
|
|
43
52
|
});
|
|
44
53
|
/**
|
|
45
54
|
* Execute a transition for a given state and event.
|
|
@@ -57,15 +66,28 @@ const executeTransition = Effect.fn("effect-machine.executeTransition")(function
|
|
|
57
66
|
if (transition === void 0) return {
|
|
58
67
|
newState: currentState,
|
|
59
68
|
transitioned: false,
|
|
60
|
-
reenter: false
|
|
69
|
+
reenter: false,
|
|
70
|
+
hasReply: false,
|
|
71
|
+
reply: void 0
|
|
61
72
|
};
|
|
73
|
+
const { newState, hasReply, reply } = yield* runTransitionHandler(machine, transition, currentState, event, self, system, actorId);
|
|
62
74
|
return {
|
|
63
|
-
newState
|
|
75
|
+
newState,
|
|
64
76
|
transitioned: true,
|
|
65
|
-
reenter: transition.reenter === true
|
|
77
|
+
reenter: transition.reenter === true,
|
|
78
|
+
hasReply,
|
|
79
|
+
reply
|
|
66
80
|
};
|
|
67
81
|
});
|
|
68
82
|
/**
|
|
83
|
+
* Check if an event should be postponed in the current state.
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
const shouldPostpone = (machine, stateTag, eventTag) => {
|
|
87
|
+
for (const rule of machine.postponeRules) if (rule.stateTag === stateTag && rule.eventTag === eventTag) return true;
|
|
88
|
+
return false;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
69
91
|
* Process a single event through the machine.
|
|
70
92
|
*
|
|
71
93
|
* Handles:
|
|
@@ -94,7 +116,10 @@ const processEventCore = Effect.fn("effect-machine.processEventCore")(function*
|
|
|
94
116
|
previousState: currentState,
|
|
95
117
|
transitioned: false,
|
|
96
118
|
lifecycleRan: false,
|
|
97
|
-
isFinal: false
|
|
119
|
+
isFinal: false,
|
|
120
|
+
hasReply: false,
|
|
121
|
+
reply: void 0,
|
|
122
|
+
postponed: false
|
|
98
123
|
};
|
|
99
124
|
const newState = result.newState;
|
|
100
125
|
const runLifecycle = newState._tag !== currentState._tag || result.reenter;
|
|
@@ -110,7 +135,10 @@ const processEventCore = Effect.fn("effect-machine.processEventCore")(function*
|
|
|
110
135
|
previousState: currentState,
|
|
111
136
|
transitioned: true,
|
|
112
137
|
lifecycleRan: runLifecycle,
|
|
113
|
-
isFinal: machine.finalStates.has(newState._tag)
|
|
138
|
+
isFinal: machine.finalStates.has(newState._tag),
|
|
139
|
+
hasReply: result.hasReply,
|
|
140
|
+
reply: result.reply,
|
|
141
|
+
postponed: false
|
|
114
142
|
};
|
|
115
143
|
});
|
|
116
144
|
/**
|
|
@@ -236,6 +264,5 @@ const findTransitions = (input, stateTag, eventTag) => {
|
|
|
236
264
|
const findSpawnEffects = (machine, stateTag) => {
|
|
237
265
|
return getIndex(machine).spawn.get(stateTag) ?? [];
|
|
238
266
|
};
|
|
239
|
-
|
|
240
267
|
//#endregion
|
|
241
|
-
export { executeTransition, findSpawnEffects, findTransitions, invalidateIndex, processEventCore, resolveTransition, runSpawnEffects, runTransitionHandler };
|
|
268
|
+
export { executeTransition, findSpawnEffects, findTransitions, invalidateIndex, processEventCore, resolveTransition, runSpawnEffects, runTransitionHandler, shouldPostpone };
|
package/dist/internal/utils.d.ts
CHANGED
|
@@ -26,7 +26,12 @@ type TaggedConstructor<T extends {
|
|
|
26
26
|
/**
|
|
27
27
|
* Transition handler result - either a new state or Effect producing one
|
|
28
28
|
*/
|
|
29
|
-
|
|
29
|
+
/** Reply tuple returned from transition handlers for ask support */
|
|
30
|
+
interface TransitionReply<State> {
|
|
31
|
+
readonly state: State;
|
|
32
|
+
readonly reply: unknown;
|
|
33
|
+
}
|
|
34
|
+
type TransitionResult<State, R> = State | TransitionReply<State> | Effect.Effect<State | TransitionReply<State>, never, R>;
|
|
30
35
|
/**
|
|
31
36
|
* Internal event tags used for lifecycle effect contexts.
|
|
32
37
|
* Prefixed with $ to distinguish from user events.
|
|
@@ -57,4 +62,4 @@ declare const isEffect: (value: unknown) => value is Effect.Effect<unknown, unkn
|
|
|
57
62
|
*/
|
|
58
63
|
declare const stubSystem: ActorSystem;
|
|
59
64
|
//#endregion
|
|
60
|
-
export { ArgsOf, INTERNAL_ENTER_EVENT, INTERNAL_INIT_EVENT, InstanceOf, TagOf, TaggedConstructor, TransitionResult, getTag, isEffect, stubSystem };
|
|
65
|
+
export { ArgsOf, INTERNAL_ENTER_EVENT, INTERNAL_INIT_EVENT, InstanceOf, TagOf, TaggedConstructor, TransitionReply, TransitionResult, getTag, isEffect, stubSystem };
|
package/dist/internal/utils.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Effect, Stream } from "effect";
|
|
2
|
-
|
|
3
2
|
//#region src/internal/utils.ts
|
|
4
3
|
/**
|
|
5
4
|
* Internal utilities for effect-machine.
|
|
@@ -50,6 +49,5 @@ const stubSystem = {
|
|
|
50
49
|
restoreMany: () => Effect.die("restoreMany not supported in stub system"),
|
|
51
50
|
restoreAll: () => Effect.die("restoreAll not supported in stub system")
|
|
52
51
|
};
|
|
53
|
-
|
|
54
52
|
//#endregion
|
|
55
|
-
export { INTERNAL_ENTER_EVENT, INTERNAL_INIT_EVENT, getTag, isEffect, stubSystem };
|
|
53
|
+
export { INTERNAL_ENTER_EVENT, INTERNAL_INIT_EVENT, getTag, isEffect, stubSystem };
|
package/dist/machine.d.ts
CHANGED
|
@@ -5,19 +5,20 @@ import { MachineEventSchema, MachineStateSchema, VariantsUnion } from "./schema.
|
|
|
5
5
|
import { PersistenceConfig, PersistentMachine } from "./persistence/persistent-machine.js";
|
|
6
6
|
import { DuplicateActorError } from "./errors.js";
|
|
7
7
|
import { findTransitions } from "./internal/transition.js";
|
|
8
|
-
import "./persistence/index.js";
|
|
9
8
|
import { ActorRef, ActorSystem } from "./actor.js";
|
|
10
|
-
import { Cause, Effect, Schedule, Schema, Scope, ServiceMap } from "effect";
|
|
9
|
+
import { Cause, Duration, Effect, Schedule, Schema, Scope, ServiceMap } from "effect";
|
|
11
10
|
|
|
12
11
|
//#region src/machine.d.ts
|
|
13
12
|
declare namespace machine_d_exports {
|
|
14
|
-
export { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig, PersistOptions, PersistenceConfig, PersistentMachine, ProvideHandlers, SlotContext, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, Transition, TransitionHandler, findTransitions, make, spawn };
|
|
13
|
+
export { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig, PersistOptions, PersistenceConfig, PersistentMachine, ProvideHandlers, SlotContext, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, TransitionHandler, findTransitions, make, spawn };
|
|
15
14
|
}
|
|
16
15
|
/**
|
|
17
16
|
* Self reference for sending events back to the machine
|
|
18
17
|
*/
|
|
19
18
|
interface MachineRef<Event> {
|
|
20
19
|
readonly send: (event: Event) => Effect.Effect<void>;
|
|
20
|
+
/** Fire-and-forget alias for send (OTP gen_server:cast). */
|
|
21
|
+
readonly cast: (event: Event) => Effect.Effect<void>;
|
|
21
22
|
readonly spawn: <S2 extends {
|
|
22
23
|
readonly _tag: string;
|
|
23
24
|
}, E2 extends {
|
|
@@ -87,6 +88,18 @@ interface TaskOptions<State, Event, ED extends EffectsDef, A, E1, ES, EF> {
|
|
|
87
88
|
readonly onFailure?: (cause: Cause.Cause<E1>, ctx: StateHandlerContext<State, Event, ED>) => EF;
|
|
88
89
|
readonly name?: string;
|
|
89
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Configuration for `.timeout()` — gen_statem-style state timeouts.
|
|
93
|
+
*
|
|
94
|
+
* Entering the state starts a timer. Leaving cancels it.
|
|
95
|
+
* `.reenter()` restarts the timer with fresh state values.
|
|
96
|
+
*/
|
|
97
|
+
interface TimeoutConfig<State, Event> {
|
|
98
|
+
/** Duration before firing. Static or derived from current state. */
|
|
99
|
+
readonly duration: Duration.Input | ((state: State) => Duration.Input);
|
|
100
|
+
/** Event to send when the timer fires. Static or derived from current state. */
|
|
101
|
+
readonly event: Event | ((state: State) => Event);
|
|
102
|
+
}
|
|
90
103
|
type IsAny<T> = 0 extends 1 & T ? true : false;
|
|
91
104
|
type IsUnknown<T> = unknown extends T ? ([T] extends [unknown] ? true : false) : false;
|
|
92
105
|
type NormalizeR<T> = IsAny<T> extends true ? T : IsUnknown<T> extends true ? never : T;
|
|
@@ -153,6 +166,11 @@ declare class Machine<State, Event, R = never, _SD extends Record<string, Schema
|
|
|
153
166
|
/** @internal */
|
|
154
167
|
readonly _finalStates: Set<string>;
|
|
155
168
|
/** @internal */
|
|
169
|
+
readonly _postponeRules: Array<{
|
|
170
|
+
readonly stateTag: string;
|
|
171
|
+
readonly eventTag: string;
|
|
172
|
+
}>;
|
|
173
|
+
/** @internal */
|
|
156
174
|
readonly _guardsSchema?: GuardsSchema<GD>;
|
|
157
175
|
/** @internal */
|
|
158
176
|
readonly _effectsSchema?: EffectsSchema<EFD>;
|
|
@@ -176,6 +194,10 @@ declare class Machine<State, Event, R = never, _SD extends Record<string, Schema
|
|
|
176
194
|
get spawnEffects(): ReadonlyArray<SpawnEffect<State, Event, EFD, R>>;
|
|
177
195
|
get backgroundEffects(): ReadonlyArray<BackgroundEffect<State, Event, EFD, R>>;
|
|
178
196
|
get finalStates(): ReadonlySet<string>;
|
|
197
|
+
get postponeRules(): ReadonlyArray<{
|
|
198
|
+
readonly stateTag: string;
|
|
199
|
+
readonly eventTag: string;
|
|
200
|
+
}>;
|
|
179
201
|
get guardsSchema(): GuardsSchema<GD> | undefined;
|
|
180
202
|
get effectsSchema(): EffectsSchema<EFD> | undefined;
|
|
181
203
|
/** @internal */
|
|
@@ -231,6 +253,28 @@ declare class Machine<State, Event, R = never, _SD extends Record<string, Schema
|
|
|
231
253
|
* Interrupts do not emit failure events.
|
|
232
254
|
*/
|
|
233
255
|
task<NS extends VariantsUnion<_SD> & BrandedState, A, E1, ES extends VariantsUnion<_ED> & BrandedEvent, EF extends VariantsUnion<_ED> & BrandedEvent>(state: TaggedOrConstructor<NS>, run: (ctx: StateHandlerContext<NS, VariantsUnion<_ED> & BrandedEvent, EFD>) => Effect.Effect<A, E1, Scope.Scope>, options: TaskOptions<NS, VariantsUnion<_ED> & BrandedEvent, EFD, A, E1, ES, EF>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
256
|
+
/**
|
|
257
|
+
* State timeout — gen_statem's `state_timeout`.
|
|
258
|
+
*
|
|
259
|
+
* Entering the state starts a timer. Leaving cancels it (via state scope).
|
|
260
|
+
* `.reenter()` restarts the timer with fresh state values.
|
|
261
|
+
* Compiles to `.task()` internally — preserves `@machine.task` inspection events.
|
|
262
|
+
*
|
|
263
|
+
* @example
|
|
264
|
+
* ```ts
|
|
265
|
+
* machine
|
|
266
|
+
* .timeout(State.Loading, {
|
|
267
|
+
* duration: Duration.seconds(30),
|
|
268
|
+
* event: Event.Timeout,
|
|
269
|
+
* })
|
|
270
|
+
* // Dynamic duration from state
|
|
271
|
+
* .timeout(State.Retrying, {
|
|
272
|
+
* duration: (state) => Duration.seconds(state.backoff),
|
|
273
|
+
* event: Event.GiveUp,
|
|
274
|
+
* })
|
|
275
|
+
* ```
|
|
276
|
+
*/
|
|
277
|
+
timeout<NS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>, config: TimeoutConfig<NS, VariantsUnion<_ED> & BrandedEvent>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
234
278
|
/**
|
|
235
279
|
* Machine-lifetime effect that is forked on actor spawn and runs until the actor stops.
|
|
236
280
|
* Use effect slots defined via `Slot.Effects` for the actual work.
|
|
@@ -252,6 +296,24 @@ declare class Machine<State, Event, R = never, _SD extends Record<string, Schema
|
|
|
252
296
|
* ```
|
|
253
297
|
*/
|
|
254
298
|
background(handler: StateEffectHandler<State, Event, EFD, Scope.Scope>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
299
|
+
/**
|
|
300
|
+
* Postpone events — gen_statem's event postpone.
|
|
301
|
+
*
|
|
302
|
+
* When a matching event arrives in the given state, it is buffered instead of
|
|
303
|
+
* processed. After the next state transition (tag change), all buffered events
|
|
304
|
+
* are drained through the loop in FIFO order.
|
|
305
|
+
*
|
|
306
|
+
* Reply-bearing events (from `call`/`ask`) in the postpone buffer are settled
|
|
307
|
+
* with `ActorStoppedError` on stop/interrupt/final-state.
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* ```ts
|
|
311
|
+
* machine
|
|
312
|
+
* .postpone(State.Connecting, Event.Data) // single event
|
|
313
|
+
* .postpone(State.Connecting, [Event.Data, Event.Cmd]) // multiple events
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
316
|
+
postpone<NS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>, events: TaggedOrConstructor<VariantsUnion<_ED> & BrandedEvent> | ReadonlyArray<TaggedOrConstructor<VariantsUnion<_ED> & BrandedEvent>>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
255
317
|
final<NS extends VariantsUnion<_SD> & BrandedState>(state: TaggedOrConstructor<NS>): Machine<State, Event, R, _SD, _ED, GD, EFD>;
|
|
256
318
|
/**
|
|
257
319
|
* Finalize the machine. Returns a `BuiltMachine` — the only type accepted by `Machine.spawn`.
|
|
@@ -289,4 +351,4 @@ declare const spawn: {
|
|
|
289
351
|
}, R>(machine: BuiltMachine<S, E, R>, id: string): Effect.Effect<ActorRef<S, E>, never, R>;
|
|
290
352
|
};
|
|
291
353
|
//#endregion
|
|
292
|
-
export { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig, PersistOptions, type PersistenceConfig, type PersistentMachine, ProvideHandlers, SlotContext, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, Transition, TransitionHandler, findTransitions, machine_d_exports, make, spawn };
|
|
354
|
+
export { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig, PersistOptions, type PersistenceConfig, type PersistentMachine, ProvideHandlers, SlotContext, SpawnEffect, StateEffectHandler, StateHandlerContext, TaskOptions, TimeoutConfig, Transition, TransitionHandler, findTransitions, machine_d_exports, make, spawn };
|
package/dist/machine.js
CHANGED
|
@@ -8,7 +8,6 @@ import { MachineContextTag } from "./slot.js";
|
|
|
8
8
|
import { findTransitions, invalidateIndex } from "./internal/transition.js";
|
|
9
9
|
import { createActor } from "./actor.js";
|
|
10
10
|
import { Cause, Effect, Exit, Option, Scope } from "effect";
|
|
11
|
-
|
|
12
11
|
//#region src/machine.ts
|
|
13
12
|
var machine_exports = /* @__PURE__ */ __exportAll({
|
|
14
13
|
BuiltMachine: () => BuiltMachine,
|
|
@@ -65,6 +64,7 @@ var Machine = class Machine {
|
|
|
65
64
|
/** @internal */ _spawnEffects;
|
|
66
65
|
/** @internal */ _backgroundEffects;
|
|
67
66
|
/** @internal */ _finalStates;
|
|
67
|
+
/** @internal */ _postponeRules;
|
|
68
68
|
/** @internal */ _guardsSchema;
|
|
69
69
|
/** @internal */ _effectsSchema;
|
|
70
70
|
/** @internal */ _guardHandlers;
|
|
@@ -89,6 +89,9 @@ var Machine = class Machine {
|
|
|
89
89
|
get finalStates() {
|
|
90
90
|
return this._finalStates;
|
|
91
91
|
}
|
|
92
|
+
get postponeRules() {
|
|
93
|
+
return this._postponeRules;
|
|
94
|
+
}
|
|
92
95
|
get guardsSchema() {
|
|
93
96
|
return this._guardsSchema;
|
|
94
97
|
}
|
|
@@ -102,6 +105,7 @@ var Machine = class Machine {
|
|
|
102
105
|
this._spawnEffects = [];
|
|
103
106
|
this._backgroundEffects = [];
|
|
104
107
|
this._finalStates = /* @__PURE__ */ new Set();
|
|
108
|
+
this._postponeRules = [];
|
|
105
109
|
this._guardsSchema = guardsSchema;
|
|
106
110
|
this._effectsSchema = effectsSchema;
|
|
107
111
|
this._guardHandlers = /* @__PURE__ */ new Map();
|
|
@@ -260,6 +264,36 @@ var Machine = class Machine {
|
|
|
260
264
|
return this.spawn(state, handler);
|
|
261
265
|
}
|
|
262
266
|
/**
|
|
267
|
+
* State timeout — gen_statem's `state_timeout`.
|
|
268
|
+
*
|
|
269
|
+
* Entering the state starts a timer. Leaving cancels it (via state scope).
|
|
270
|
+
* `.reenter()` restarts the timer with fresh state values.
|
|
271
|
+
* Compiles to `.task()` internally — preserves `@machine.task` inspection events.
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* ```ts
|
|
275
|
+
* machine
|
|
276
|
+
* .timeout(State.Loading, {
|
|
277
|
+
* duration: Duration.seconds(30),
|
|
278
|
+
* event: Event.Timeout,
|
|
279
|
+
* })
|
|
280
|
+
* // Dynamic duration from state
|
|
281
|
+
* .timeout(State.Retrying, {
|
|
282
|
+
* duration: (state) => Duration.seconds(state.backoff),
|
|
283
|
+
* event: Event.GiveUp,
|
|
284
|
+
* })
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
timeout(state, config) {
|
|
288
|
+
const stateTag = getTag(state);
|
|
289
|
+
const resolveDuration = typeof config.duration === "function" ? config.duration : () => config.duration;
|
|
290
|
+
const resolveEvent = typeof config.event === "function" ? config.event : () => config.event;
|
|
291
|
+
return this.task(state, (ctx) => Effect.sleep(resolveDuration(ctx.state)), {
|
|
292
|
+
onSuccess: (_, ctx) => resolveEvent(ctx.state),
|
|
293
|
+
name: `$timeout:${stateTag}`
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
263
297
|
* Machine-lifetime effect that is forked on actor spawn and runs until the actor stops.
|
|
264
298
|
* Use effect slots defined via `Slot.Effects` for the actual work.
|
|
265
299
|
*
|
|
@@ -283,6 +317,35 @@ var Machine = class Machine {
|
|
|
283
317
|
this._backgroundEffects.push({ handler });
|
|
284
318
|
return this;
|
|
285
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* Postpone events — gen_statem's event postpone.
|
|
322
|
+
*
|
|
323
|
+
* When a matching event arrives in the given state, it is buffered instead of
|
|
324
|
+
* processed. After the next state transition (tag change), all buffered events
|
|
325
|
+
* are drained through the loop in FIFO order.
|
|
326
|
+
*
|
|
327
|
+
* Reply-bearing events (from `call`/`ask`) in the postpone buffer are settled
|
|
328
|
+
* with `ActorStoppedError` on stop/interrupt/final-state.
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* ```ts
|
|
332
|
+
* machine
|
|
333
|
+
* .postpone(State.Connecting, Event.Data) // single event
|
|
334
|
+
* .postpone(State.Connecting, [Event.Data, Event.Cmd]) // multiple events
|
|
335
|
+
* ```
|
|
336
|
+
*/
|
|
337
|
+
postpone(state, events) {
|
|
338
|
+
const stateTag = getTag(state);
|
|
339
|
+
const eventList = Array.isArray(events) ? events : [events];
|
|
340
|
+
for (const ev of eventList) {
|
|
341
|
+
const eventTag = getTag(ev);
|
|
342
|
+
this._postponeRules.push({
|
|
343
|
+
stateTag,
|
|
344
|
+
eventTag
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
return this;
|
|
348
|
+
}
|
|
286
349
|
final(state) {
|
|
287
350
|
const stateTag = getTag(state);
|
|
288
351
|
this._finalStates.add(stateTag);
|
|
@@ -314,6 +377,7 @@ var Machine = class Machine {
|
|
|
314
377
|
result._finalStates = new Set(this._finalStates);
|
|
315
378
|
result._spawnEffects = [...this._spawnEffects];
|
|
316
379
|
result._backgroundEffects = [...this._backgroundEffects];
|
|
380
|
+
result._postponeRules = [...this._postponeRules];
|
|
317
381
|
const anyHandlers = handlers;
|
|
318
382
|
if (this._guardsSchema !== void 0) for (const name of Object.keys(this._guardsSchema.definitions)) result._guardHandlers.set(name, anyHandlers[name]);
|
|
319
383
|
if (this._effectsSchema !== void 0) for (const name of Object.keys(this._effectsSchema.definitions)) result._effectHandlers.set(name, anyHandlers[name]);
|
|
@@ -344,39 +408,11 @@ var TransitionScope = class {
|
|
|
344
408
|
}
|
|
345
409
|
};
|
|
346
410
|
const make = Machine.make;
|
|
347
|
-
|
|
348
|
-
* Spawn an actor directly without ActorSystem ceremony.
|
|
349
|
-
* Accepts only `BuiltMachine` (call `.build()` first).
|
|
350
|
-
*
|
|
351
|
-
* **Single actor, no registry.** Caller manages lifetime via `actor.stop`.
|
|
352
|
-
* If a `Scope` exists in context, cleanup attaches automatically on scope close.
|
|
353
|
-
*
|
|
354
|
-
* For registry, lookup by ID, persistence, or multi-actor coordination,
|
|
355
|
-
* use `ActorSystemService` / `system.spawn` instead.
|
|
356
|
-
*
|
|
357
|
-
* @example
|
|
358
|
-
* ```ts
|
|
359
|
-
* // Fire-and-forget — caller manages lifetime
|
|
360
|
-
* const actor = yield* Machine.spawn(machine.build());
|
|
361
|
-
* yield* actor.send(Event.Start);
|
|
362
|
-
* yield* actor.awaitFinal;
|
|
363
|
-
* yield* actor.stop;
|
|
364
|
-
*
|
|
365
|
-
* // Scope-aware — auto-cleans up on scope close
|
|
366
|
-
* yield* Effect.scoped(Effect.gen(function* () {
|
|
367
|
-
* const actor = yield* Machine.spawn(machine.build());
|
|
368
|
-
* yield* actor.send(Event.Start);
|
|
369
|
-
* // actor.stop called automatically when scope closes
|
|
370
|
-
* }));
|
|
371
|
-
* ```
|
|
372
|
-
*/
|
|
373
|
-
const spawnImpl = Effect.fn("effect-machine.spawn")(function* (built, id) {
|
|
411
|
+
const spawn = Effect.fn("effect-machine.spawn")(function* (built, id) {
|
|
374
412
|
const actor = yield* createActor(id ?? `actor-${Math.random().toString(36).slice(2)}`, built._inner);
|
|
375
413
|
const maybeScope = yield* Effect.serviceOption(Scope.Scope);
|
|
376
414
|
if (Option.isSome(maybeScope)) yield* Scope.addFinalizer(maybeScope.value, actor.stop);
|
|
377
415
|
return actor;
|
|
378
416
|
});
|
|
379
|
-
const spawn = spawnImpl;
|
|
380
|
-
|
|
381
417
|
//#endregion
|
|
382
|
-
export { BuiltMachine, Machine, findTransitions, machine_exports, make, spawn };
|
|
418
|
+
export { BuiltMachine, Machine, findTransitions, machine_exports, make, spawn };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Schema, ServiceMap } from "effect";
|
|
2
|
-
|
|
3
2
|
//#region src/persistence/adapter.ts
|
|
4
3
|
/**
|
|
5
4
|
* Error type for persistence operations
|
|
@@ -22,6 +21,5 @@ var VersionConflictError = class extends Schema.TaggedErrorClass()("VersionConfl
|
|
|
22
21
|
* PersistenceAdapter service tag
|
|
23
22
|
*/
|
|
24
23
|
var PersistenceAdapterTag = class extends ServiceMap.Service()("effect-machine/src/persistence/adapter/PersistenceAdapterTag") {};
|
|
25
|
-
|
|
26
24
|
//#endregion
|
|
27
|
-
export { PersistenceAdapterTag, PersistenceError, VersionConflictError };
|
|
25
|
+
export { PersistenceAdapterTag, PersistenceError, VersionConflictError };
|