effect-machine 0.18.0 → 0.20.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 +183 -138
- package/dist/actor.d.ts +65 -22
- package/dist/actor.js +172 -78
- package/dist/atom.d.ts +56 -0
- package/dist/atom.js +47 -0
- package/dist/cluster/entity-machine.d.ts +9 -3
- package/dist/cluster/entity-machine.js +8 -8
- package/dist/cluster/index.d.ts +2 -2
- package/dist/cluster/to-entity.d.ts +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/inspection.d.ts +31 -3
- package/dist/inspection.js +21 -0
- package/dist/internal/inspection.d.ts +1 -1
- package/dist/internal/inspection.js +23 -1
- package/dist/internal/machine-definition.d.ts +1 -0
- package/dist/internal/machine-initialization.d.ts +21 -0
- package/dist/internal/machine-initialization.js +27 -0
- package/dist/internal/runtime.d.ts +15 -1
- package/dist/internal/runtime.js +67 -26
- package/dist/internal/transition.d.ts +51 -3
- package/dist/internal/transition.js +216 -38
- package/dist/machine.d.ts +151 -40
- package/dist/machine.js +139 -40
- package/dist/supervision.d.ts +3 -2
- package/dist/supervision.js +3 -2
- package/dist/testing.d.ts +39 -67
- package/dist/testing.js +13 -52
- package/package.json +29 -3
|
@@ -59,7 +59,7 @@ declare const toEntity: <S extends {
|
|
|
59
59
|
readonly _tag: string;
|
|
60
60
|
}, E extends {
|
|
61
61
|
readonly _tag: string;
|
|
62
|
-
}, R, SD extends Record<string, Schema.Struct.Fields>, ED extends Record<string, Schema.Struct.Fields
|
|
62
|
+
}, R, SD extends Record<string, Schema.Struct.Fields>, ED extends Record<string, Schema.Struct.Fields>, Input, Output>(machine: Machine<S, E, R, SD, ED, Input, Output>, options: ToEntityOptions) => Entity.Entity<string, EntityRpcs<MachineStateSchema<SD> & {
|
|
63
63
|
readonly Type: S;
|
|
64
64
|
}, MachineEventSchema<ED> & {
|
|
65
65
|
readonly Type: E;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,9 +2,9 @@ import { DeferReplyResult, ReplyResult } from "./internal/utils.js";
|
|
|
2
2
|
import { Event, MachineEventSchema, MachineStateSchema, ReplyFields, State } from "./schema.js";
|
|
3
3
|
import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, NoReplyError, PersistenceError, VersionConflictError } from "./errors.js";
|
|
4
4
|
import { ActorExit, DefectPhase, Supervision } from "./supervision.js";
|
|
5
|
-
import { Durability, DurabilityCommit, HandlerContext, Lifecycle, Machine, MachineRef, MakeConfig, Recovery, RecoveryContext, StateHandlerContext, TaskOptions, TimeoutConfig, machine_d_exports } from "./machine.js";
|
|
5
|
+
import { Durability, DurabilityCommit, FinalContext, GuardPredicate, HandlerContext, InputMakeConfig, Lifecycle, Machine, MachineRef, MakeConfig, Recovery, RecoveryContext, ReplayOptions, SpawnOptions, StateHandlerContext, TaskOptions, TimeoutConfig, machine_d_exports } from "./machine.js";
|
|
6
6
|
import { ProcessEventResult } from "./internal/transition.js";
|
|
7
|
-
import { ActorRef, ActorRefSync, ActorScope, ActorSystem, ActorSystemService, Default, SystemEvent, SystemEventListener, TransitionInfo } from "./actor.js";
|
|
8
|
-
import { SimulationResult, TestHarness, TestHarnessOptions, assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
|
|
9
|
-
import { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, InspectionEvent, Inspector, InspectorHandler, InspectorService, SpawnEvent, StopEvent, TaskEvent, TracingInspectorOptions, TransitionEvent, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector } from "./inspection.js";
|
|
10
|
-
export { ActorExit, type ActorRef, type ActorRefSync, ActorScope, ActorStoppedError, type ActorSystemService as ActorSystem, Default as ActorSystemDefault, ActorSystem as ActorSystemService, type AnyInspectionEvent, AssertionError, type DefectPhase, type DeferReplyResult, DuplicateActorError, type Durability, type DurabilityCommit, type EffectEvent, type ErrorEvent, Event, type EventReceivedEvent, type HandlerContext, type InspectionEvent, type InspectorService as Inspector, type InspectorHandler, Inspector as InspectorService, InvalidSchemaError, type Lifecycle, machine_d_exports as Machine, type MachineEventSchema, type MachineRef, type MachineStateSchema, type Machine as MachineType, type MakeConfig, MissingMatchHandlerError, NoReplyError, PersistenceError, type ProcessEventResult, type Recovery, type RecoveryContext, type ReplyFields, type ReplyResult, type SimulationResult, type SpawnEvent, State, type StateHandlerContext, type StopEvent, Supervision, type SystemEvent, type SystemEventListener, type TaskEvent, type TaskOptions, type TestHarness, type TestHarnessOptions, type TimeoutConfig, type TracingInspectorOptions, type TransitionEvent, type TransitionInfo, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createTestHarness, makeInspector, makeInspectorEffect, simulate, tracingInspector };
|
|
7
|
+
import { ActorClient, ActorLifecycle, ActorRef, ActorRefSync, ActorScope, ActorSystem, ActorSystemService, Default, SystemEvent, SystemEventListener, SystemSpawnOptions, TransitionInfo } from "./actor.js";
|
|
8
|
+
import { InputTestHarnessOptions, SimulationOptions, SimulationResult, TestHarness, TestHarnessOptions, assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
|
|
9
|
+
import { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, GuardEvent, InspectionEvent, Inspector, InspectorHandler, InspectorService, OperationEvent, SpawnEvent, StopEvent, TaskEvent, TracingInspectorOptions, TransitionEvent, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector } from "./inspection.js";
|
|
10
|
+
export { type ActorClient, ActorExit, type ActorExit as ActorExitType, type ActorLifecycle, type ActorRef, type ActorRefSync, ActorScope, ActorStoppedError, type ActorSystemService as ActorSystem, Default as ActorSystemDefault, ActorSystem as ActorSystemService, type AnyInspectionEvent, AssertionError, type DefectPhase, type DeferReplyResult, DuplicateActorError, type Durability, type DurabilityCommit, type EffectEvent, type ErrorEvent, Event, type EventReceivedEvent, type FinalContext, type GuardEvent, type GuardPredicate, type HandlerContext, type InputMakeConfig, type InputTestHarnessOptions, type InspectionEvent, type InspectorService as Inspector, type InspectorHandler, Inspector as InspectorService, InvalidSchemaError, type Lifecycle, machine_d_exports as Machine, type MachineEventSchema, type MachineRef, type MachineStateSchema, type Machine as MachineType, type MakeConfig, MissingMatchHandlerError, NoReplyError, type OperationEvent, PersistenceError, type ProcessEventResult, type Recovery, type RecoveryContext, type ReplayOptions, type ReplyFields, type ReplyResult, type SimulationOptions, type SimulationResult, type SpawnEvent, type SpawnOptions, State, type StateHandlerContext, type StopEvent, Supervision, type SystemEvent, type SystemEventListener, type SystemSpawnOptions, type TaskEvent, type TaskOptions, type TestHarness, type TestHarnessOptions, type TimeoutConfig, type TracingInspectorOptions, type TransitionEvent, type TransitionInfo, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createTestHarness, makeInspector, makeInspectorEffect, simulate, tracingInspector };
|
package/dist/inspection.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ type ResolveType<T> = T extends Schema.Schema<infer A> ? A : T;
|
|
|
10
10
|
interface SpawnEvent<S> {
|
|
11
11
|
readonly type: "@machine.spawn";
|
|
12
12
|
readonly actorId: string;
|
|
13
|
+
readonly generation: number;
|
|
13
14
|
readonly initialState: S;
|
|
14
15
|
readonly timestamp: number;
|
|
15
16
|
}
|
|
@@ -19,6 +20,7 @@ interface SpawnEvent<S> {
|
|
|
19
20
|
interface EventReceivedEvent<S, E> {
|
|
20
21
|
readonly type: "@machine.event";
|
|
21
22
|
readonly actorId: string;
|
|
23
|
+
readonly generation: number;
|
|
22
24
|
readonly state: S;
|
|
23
25
|
readonly event: E;
|
|
24
26
|
readonly timestamp: number;
|
|
@@ -29,17 +31,40 @@ interface EventReceivedEvent<S, E> {
|
|
|
29
31
|
interface TransitionEvent<S, E> {
|
|
30
32
|
readonly type: "@machine.transition";
|
|
31
33
|
readonly actorId: string;
|
|
34
|
+
readonly generation: number;
|
|
32
35
|
readonly fromState: S;
|
|
33
36
|
readonly toState: S;
|
|
34
37
|
readonly event: E;
|
|
35
38
|
readonly timestamp: number;
|
|
36
39
|
}
|
|
40
|
+
/** Event emitted after a transition guard runs. */
|
|
41
|
+
interface GuardEvent<S, E> {
|
|
42
|
+
readonly type: "@machine.guard";
|
|
43
|
+
readonly actorId: string;
|
|
44
|
+
readonly generation: number;
|
|
45
|
+
readonly state: S;
|
|
46
|
+
readonly event: E;
|
|
47
|
+
readonly guard: string;
|
|
48
|
+
readonly result: boolean;
|
|
49
|
+
readonly timestamp: number;
|
|
50
|
+
}
|
|
51
|
+
/** Event emitted before an accepted transition handler runs. */
|
|
52
|
+
interface OperationEvent<S, E> {
|
|
53
|
+
readonly type: "@machine.operation";
|
|
54
|
+
readonly actorId: string;
|
|
55
|
+
readonly generation: number;
|
|
56
|
+
readonly operation: string;
|
|
57
|
+
readonly state: S;
|
|
58
|
+
readonly event: E;
|
|
59
|
+
readonly timestamp: number;
|
|
60
|
+
}
|
|
37
61
|
/**
|
|
38
62
|
* Event emitted when a spawn effect runs
|
|
39
63
|
*/
|
|
40
64
|
interface EffectEvent<S> {
|
|
41
65
|
readonly type: "@machine.effect";
|
|
42
66
|
readonly actorId: string;
|
|
67
|
+
readonly generation: number;
|
|
43
68
|
readonly effectType: "spawn";
|
|
44
69
|
readonly state: S;
|
|
45
70
|
readonly timestamp: number;
|
|
@@ -47,9 +72,10 @@ interface EffectEvent<S> {
|
|
|
47
72
|
interface TaskEvent<S> {
|
|
48
73
|
readonly type: "@machine.task";
|
|
49
74
|
readonly actorId: string;
|
|
75
|
+
readonly generation: number;
|
|
50
76
|
readonly state: S;
|
|
51
77
|
readonly taskName?: string;
|
|
52
|
-
readonly phase: "start" | "success" | "failure" | "interrupt";
|
|
78
|
+
readonly phase: "start" | "success" | "failure" | "defect" | "interrupt";
|
|
53
79
|
readonly error?: string;
|
|
54
80
|
readonly timestamp: number;
|
|
55
81
|
}
|
|
@@ -59,6 +85,7 @@ interface TaskEvent<S> {
|
|
|
59
85
|
interface ErrorEvent<S, E> {
|
|
60
86
|
readonly type: "@machine.error";
|
|
61
87
|
readonly actorId: string;
|
|
88
|
+
readonly generation: number;
|
|
62
89
|
readonly phase: "transition" | "spawn";
|
|
63
90
|
readonly state: S;
|
|
64
91
|
readonly event: E;
|
|
@@ -71,13 +98,14 @@ interface ErrorEvent<S, E> {
|
|
|
71
98
|
interface StopEvent<S> {
|
|
72
99
|
readonly type: "@machine.stop";
|
|
73
100
|
readonly actorId: string;
|
|
101
|
+
readonly generation: number;
|
|
74
102
|
readonly finalState: S;
|
|
75
103
|
readonly timestamp: number;
|
|
76
104
|
}
|
|
77
105
|
/**
|
|
78
106
|
* Union of all inspection events
|
|
79
107
|
*/
|
|
80
|
-
type InspectionEvent<S, E> = SpawnEvent<S> | EventReceivedEvent<S, E> | TransitionEvent<S, E> | EffectEvent<S> | TaskEvent<S> | ErrorEvent<S, E> | StopEvent<S>;
|
|
108
|
+
type InspectionEvent<S, E> = SpawnEvent<S> | EventReceivedEvent<S, E> | TransitionEvent<S, E> | GuardEvent<S, E> | OperationEvent<S, E> | EffectEvent<S> | TaskEvent<S> | ErrorEvent<S, E> | StopEvent<S>;
|
|
81
109
|
/**
|
|
82
110
|
* Convenience alias for untyped inspection events.
|
|
83
111
|
* Useful for general-purpose inspectors that don't need specific state/event types.
|
|
@@ -148,4 +176,4 @@ declare const collectingInspector: <S extends {
|
|
|
148
176
|
readonly _tag: string;
|
|
149
177
|
}>(events: InspectionEvent<S, E>[]) => InspectorService<S, E>;
|
|
150
178
|
//#endregion
|
|
151
|
-
export { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, InspectionEvent, Inspector, InspectorHandler, InspectorService, SpawnEvent, StopEvent, TaskEvent, TracingInspectorOptions, TransitionEvent, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector };
|
|
179
|
+
export { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, GuardEvent, InspectionEvent, Inspector, InspectorHandler, InspectorService, OperationEvent, SpawnEvent, StopEvent, TaskEvent, TracingInspectorOptions, TransitionEvent, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector };
|
package/dist/inspection.js
CHANGED
|
@@ -29,6 +29,8 @@ const inspectionSpanName = (event) => {
|
|
|
29
29
|
case "@machine.spawn": return `Machine.inspect ${event.initialState._tag}`;
|
|
30
30
|
case "@machine.event": return `Machine.inspect ${event.event._tag}`;
|
|
31
31
|
case "@machine.transition": return `Machine.inspect ${event.fromState._tag}->${event.toState._tag}`;
|
|
32
|
+
case "@machine.guard": return `Machine.inspect guard:${event.guard}`;
|
|
33
|
+
case "@machine.operation": return `Machine.inspect operation:${event.operation}`;
|
|
32
34
|
case "@machine.effect": return `Machine.inspect ${event.effectType}`;
|
|
33
35
|
case "@machine.task": return `Machine.inspect task:${event.phase}`;
|
|
34
36
|
case "@machine.error": return `Machine.inspect ${event.phase}`;
|
|
@@ -40,6 +42,8 @@ const inspectionTraceName = (event) => {
|
|
|
40
42
|
case "@machine.spawn": return `machine.spawn ${event.initialState._tag}`;
|
|
41
43
|
case "@machine.event": return `machine.event ${event.event._tag}`;
|
|
42
44
|
case "@machine.transition": return `machine.transition ${event.fromState._tag}->${event.toState._tag}`;
|
|
45
|
+
case "@machine.guard": return `machine.guard ${event.guard}`;
|
|
46
|
+
case "@machine.operation": return `machine.operation ${event.operation}`;
|
|
43
47
|
case "@machine.effect": return `machine.effect ${event.effectType}`;
|
|
44
48
|
case "@machine.task": {
|
|
45
49
|
let taskSuffix = "";
|
|
@@ -53,6 +57,7 @@ const inspectionTraceName = (event) => {
|
|
|
53
57
|
const inspectionAttributes = (event) => {
|
|
54
58
|
const shared = {
|
|
55
59
|
"machine.actor.id": event.actorId,
|
|
60
|
+
"machine.actor.generation": event.generation,
|
|
56
61
|
"machine.inspection.type": event.type
|
|
57
62
|
};
|
|
58
63
|
switch (event.type) {
|
|
@@ -71,6 +76,19 @@ const inspectionAttributes = (event) => {
|
|
|
71
76
|
"machine.state.to": event.toState._tag,
|
|
72
77
|
"machine.event.tag": event.event._tag
|
|
73
78
|
};
|
|
79
|
+
case "@machine.guard": return {
|
|
80
|
+
...shared,
|
|
81
|
+
"machine.state.current": event.state._tag,
|
|
82
|
+
"machine.event.tag": event.event._tag,
|
|
83
|
+
"machine.guard.name": event.guard,
|
|
84
|
+
"machine.guard.result": event.result
|
|
85
|
+
};
|
|
86
|
+
case "@machine.operation": return {
|
|
87
|
+
...shared,
|
|
88
|
+
"machine.state.current": event.state._tag,
|
|
89
|
+
"machine.event.tag": event.event._tag,
|
|
90
|
+
"machine.operation.name": event.operation
|
|
91
|
+
};
|
|
74
92
|
case "@machine.effect": return {
|
|
75
93
|
...shared,
|
|
76
94
|
"machine.state.current": event.state._tag,
|
|
@@ -110,6 +128,7 @@ const tracingInspector = (options) => ({ onInspect: (event) => {
|
|
|
110
128
|
const currentSpan = yield* Effect.option(Effect.currentSpan);
|
|
111
129
|
if (Option.isSome(currentSpan)) currentSpan.value.event(traceName, BigInt(event.timestamp) * 1000000n, {
|
|
112
130
|
actorId: event.actorId,
|
|
131
|
+
generation: event.generation,
|
|
113
132
|
inspectionType: event.type
|
|
114
133
|
});
|
|
115
134
|
})().pipe(Effect.withSpan(spanName ?? inspectionSpanName(event), { attributes }));
|
|
@@ -123,6 +142,8 @@ const consoleInspector = () => makeInspectorEffect((event) => {
|
|
|
123
142
|
case "@machine.spawn": return Effect.log(`${prefix} spawned -> ${event.initialState._tag}`);
|
|
124
143
|
case "@machine.event": return Effect.log(`${prefix} received ${event.event._tag} in ${event.state._tag}`);
|
|
125
144
|
case "@machine.transition": return Effect.log(`${prefix} ${event.fromState._tag} -> ${event.toState._tag}`);
|
|
145
|
+
case "@machine.guard": return Effect.log(`${prefix} guard ${event.guard} -> ${String(event.result)}`);
|
|
146
|
+
case "@machine.operation": return Effect.log(`${prefix} operation ${event.operation} in ${event.state._tag}`);
|
|
126
147
|
case "@machine.effect": return Effect.log(`${prefix} ${event.effectType} effect in ${event.state._tag}`);
|
|
127
148
|
case "@machine.task": return Effect.log(`${prefix} task ${event.phase} ${event.taskName ?? "<unnamed>"} in ${event.state._tag}`);
|
|
128
149
|
case "@machine.error": return Effect.log(`${prefix} error in ${event.phase} ${event.state._tag} - ${String(event.error)}`);
|
|
@@ -2,6 +2,6 @@ import { ProcessEventHooks } from "./transition.js";
|
|
|
2
2
|
import { InspectorService } from "../inspection.js";
|
|
3
3
|
//#region src/internal/inspection.d.ts
|
|
4
4
|
/** Adapt the Inspector service to the transition kernel. */
|
|
5
|
-
declare const makeInspectionHooks: <S, E>(actorId: string, inspector: InspectorService<S, E
|
|
5
|
+
declare const makeInspectionHooks: <S, E>(actorId: string, inspector: InspectorService<S, E>, getGeneration?: () => number) => ProcessEventHooks<S, E>;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { makeInspectionHooks };
|
|
@@ -11,10 +11,30 @@ const emitWithTimestamp = Effect.fn("effect-machine.emitWithTimestamp")(function
|
|
|
11
11
|
if (Effect.isEffect(result)) yield* result.pipe(Effect.ignoreCause);
|
|
12
12
|
});
|
|
13
13
|
/** Adapt the Inspector service to the transition kernel. */
|
|
14
|
-
const makeInspectionHooks = (actorId, inspector) => ({
|
|
14
|
+
const makeInspectionHooks = (actorId, inspector, getGeneration = () => 0) => ({
|
|
15
|
+
onGuard: (evaluation) => emitWithTimestamp(inspector, (timestamp) => ({
|
|
16
|
+
type: "@machine.guard",
|
|
17
|
+
actorId,
|
|
18
|
+
generation: getGeneration(),
|
|
19
|
+
state: evaluation.state,
|
|
20
|
+
event: evaluation.event,
|
|
21
|
+
guard: evaluation.guard,
|
|
22
|
+
result: evaluation.result,
|
|
23
|
+
timestamp
|
|
24
|
+
})),
|
|
25
|
+
onOperation: (operation) => emitWithTimestamp(inspector, (timestamp) => ({
|
|
26
|
+
type: "@machine.operation",
|
|
27
|
+
actorId,
|
|
28
|
+
generation: getGeneration(),
|
|
29
|
+
operation: operation.operation,
|
|
30
|
+
state: operation.state,
|
|
31
|
+
event: operation.event,
|
|
32
|
+
timestamp
|
|
33
|
+
})),
|
|
15
34
|
onSpawnEffect: (state) => emitWithTimestamp(inspector, (timestamp) => ({
|
|
16
35
|
type: "@machine.effect",
|
|
17
36
|
actorId,
|
|
37
|
+
generation: getGeneration(),
|
|
18
38
|
effectType: "spawn",
|
|
19
39
|
state,
|
|
20
40
|
timestamp
|
|
@@ -22,6 +42,7 @@ const makeInspectionHooks = (actorId, inspector) => ({
|
|
|
22
42
|
onTransition: (from, to, event) => emitWithTimestamp(inspector, (timestamp) => ({
|
|
23
43
|
type: "@machine.transition",
|
|
24
44
|
actorId,
|
|
45
|
+
generation: getGeneration(),
|
|
25
46
|
fromState: from,
|
|
26
47
|
toState: to,
|
|
27
48
|
event,
|
|
@@ -30,6 +51,7 @@ const makeInspectionHooks = (actorId, inspector) => ({
|
|
|
30
51
|
onError: (info) => emitWithTimestamp(inspector, (timestamp) => ({
|
|
31
52
|
type: "@machine.error",
|
|
32
53
|
actorId,
|
|
54
|
+
generation: getGeneration(),
|
|
33
55
|
phase: info.phase,
|
|
34
56
|
state: info.state,
|
|
35
57
|
event: info.event,
|
|
@@ -4,6 +4,7 @@ interface Transition<State, Event, R> {
|
|
|
4
4
|
readonly eventTag: string;
|
|
5
5
|
readonly handler: TransitionHandler<State, Event, State, R>;
|
|
6
6
|
readonly reenter?: boolean;
|
|
7
|
+
readonly guard?: GuardPredicate<State, Event, never>;
|
|
7
8
|
}
|
|
8
9
|
interface SpawnEffect<State, Event, R> {
|
|
9
10
|
readonly stateTag: string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/internal/machine-initialization.d.ts
|
|
2
|
+
/** How a machine creates the initial state for one actor. */
|
|
3
|
+
type MachineInitialization<Input, State> = {
|
|
4
|
+
readonly _tag: "Static";
|
|
5
|
+
readonly state: State;
|
|
6
|
+
} | {
|
|
7
|
+
readonly _tag: "Input";
|
|
8
|
+
readonly initialize: (input: Input) => State;
|
|
9
|
+
};
|
|
10
|
+
declare const make: <Input, State>(initial: State | ((input: Input) => State)) => MachineInitialization<Input, State>;
|
|
11
|
+
/** Resolve one actor initial state. This is the only input erasure seam. */
|
|
12
|
+
declare const resolve: <Input, State>(initialization: MachineInitialization<Input, State>, input: unknown) => State;
|
|
13
|
+
/** Return the static value, or undefined for an input machine. */
|
|
14
|
+
declare const staticValue: <Input, State>(initialization: MachineInitialization<Input, State>) => State | undefined;
|
|
15
|
+
declare const MachineInitialization: {
|
|
16
|
+
make: typeof make;
|
|
17
|
+
resolve: typeof resolve;
|
|
18
|
+
staticValue: typeof staticValue;
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { MachineInitialization };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/internal/machine-initialization.ts
|
|
2
|
+
const make = (initial) => {
|
|
3
|
+
if (typeof initial === "function") return {
|
|
4
|
+
_tag: "Input",
|
|
5
|
+
initialize: initial
|
|
6
|
+
};
|
|
7
|
+
return {
|
|
8
|
+
_tag: "Static",
|
|
9
|
+
state: initial
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
/** Resolve one actor initial state. This is the only input erasure seam. */
|
|
13
|
+
const resolve = (initialization, input) => {
|
|
14
|
+
if (initialization._tag === "Static") return initialization.state;
|
|
15
|
+
return initialization.initialize(input);
|
|
16
|
+
};
|
|
17
|
+
/** Return the static value, or undefined for an input machine. */
|
|
18
|
+
const staticValue = (initialization) => {
|
|
19
|
+
if (initialization._tag === "Static") return initialization.state;
|
|
20
|
+
};
|
|
21
|
+
const MachineInitialization = {
|
|
22
|
+
make,
|
|
23
|
+
resolve,
|
|
24
|
+
staticValue
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { MachineInitialization };
|
|
@@ -1 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import { DefectPhase } from "../supervision.js";
|
|
2
|
+
//#region src/internal/runtime.d.ts
|
|
3
|
+
/** Internal exit reason for one runtime generation. */
|
|
4
|
+
type RuntimeExit<S> = {
|
|
5
|
+
readonly _tag: "Final";
|
|
6
|
+
readonly state: S;
|
|
7
|
+
} | {
|
|
8
|
+
readonly _tag: "Stopped";
|
|
9
|
+
} | {
|
|
10
|
+
readonly _tag: "Defect";
|
|
11
|
+
readonly cause: Cause.Cause<unknown>;
|
|
12
|
+
readonly phase: DefectPhase;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { RuntimeExit };
|
package/dist/internal/runtime.js
CHANGED
|
@@ -2,7 +2,6 @@ import { INTERNAL_INIT_EVENT, isEffect } from "./utils.js";
|
|
|
2
2
|
import { ActorStoppedError, NoReplyError } from "../errors.js";
|
|
3
3
|
import { makeEventAdvancement } from "./event-advancement.js";
|
|
4
4
|
import { processEventCoreImmediate, runSpawnEffects, shouldPostpone } from "./transition.js";
|
|
5
|
-
import { ActorExit } from "../supervision.js";
|
|
6
5
|
import { ActorSystem } from "../actor.js";
|
|
7
6
|
import { Cause, Deferred, Effect, Exit, Fiber, Queue, Ref, Schema, Scope, SubscriptionRef } from "effect";
|
|
8
7
|
//#region src/internal/runtime.ts
|
|
@@ -18,12 +17,24 @@ import { Cause, Deferred, Effect, Exit, Fiber, Queue, Ref, Schema, Scope, Subscr
|
|
|
18
17
|
* - Reply settlement (call/ask Deferreds)
|
|
19
18
|
* - Reply schema validation
|
|
20
19
|
* - Lifecycle hooks for actor-specific concerns (inspection, listeners, etc.)
|
|
21
|
-
* -
|
|
20
|
+
* - RuntimeExit with exit reason (Final/Stopped/Defect) via exitDeferred
|
|
22
21
|
*
|
|
23
22
|
* Used by entity-machine and local actor (actor.ts delegates here).
|
|
24
23
|
*
|
|
25
24
|
* @internal
|
|
26
25
|
*/
|
|
26
|
+
const RuntimeExit = {
|
|
27
|
+
Final: (state) => ({
|
|
28
|
+
_tag: "Final",
|
|
29
|
+
state
|
|
30
|
+
}),
|
|
31
|
+
Stopped: { _tag: "Stopped" },
|
|
32
|
+
Defect: (cause, phase) => ({
|
|
33
|
+
_tag: "Defect",
|
|
34
|
+
cause,
|
|
35
|
+
phase
|
|
36
|
+
})
|
|
37
|
+
};
|
|
27
38
|
/**
|
|
28
39
|
* Create a runtime for a machine. Returns a handle for sending events
|
|
29
40
|
* and querying state. The runtime owns:
|
|
@@ -41,6 +52,7 @@ import { Cause, Deferred, Effect, Exit, Fiber, Queue, Ref, Schema, Scope, Subscr
|
|
|
41
52
|
*/
|
|
42
53
|
const createRuntime = Effect.fn("effect-machine.runtime.create")(function* (machine, system, config) {
|
|
43
54
|
const { actorId, hooks, lifecycle } = config;
|
|
55
|
+
const generation = config.generation ?? 0;
|
|
44
56
|
const services = yield* Effect.context();
|
|
45
57
|
const fork = Effect.runForkWith(services);
|
|
46
58
|
const { stateRef, stoppedRef, eventQueue } = config.cellResources;
|
|
@@ -84,51 +96,78 @@ const createRuntime = Effect.fn("effect-machine.runtime.create")(function* (mach
|
|
|
84
96
|
yield* Deferred.await(startDeferred);
|
|
85
97
|
return;
|
|
86
98
|
}
|
|
99
|
+
const initialSpawnDefectSignal = (cause) => Deferred.succeed(exitDeferred, RuntimeExit.Defect(cause, "initial-spawn")).pipe(Effect.andThen(Ref.set(stoppedRef, true)), Effect.andThen(Effect.suspend(() => {
|
|
100
|
+
const loopFiber = loopFiberRef.current;
|
|
101
|
+
if (loopFiber !== void 0) return Fiber.interrupt(loopFiber);
|
|
102
|
+
return Effect.void;
|
|
103
|
+
})), Effect.asVoid);
|
|
104
|
+
const initialState = yield* SubscriptionRef.get(stateRef);
|
|
105
|
+
const initialProcessing = processEventCoreImmediate(machine, initialState, initEvent, self, stateScopeRef, system, actorId, {
|
|
106
|
+
...hooks,
|
|
107
|
+
onSpawnDefect: initialSpawnDefectSignal
|
|
108
|
+
}, generation);
|
|
109
|
+
let initialResult;
|
|
110
|
+
if (isEffect(initialProcessing)) initialResult = yield* initialProcessing.pipe(Effect.catchCause((cause) => Effect.gen(function* () {
|
|
111
|
+
yield* Ref.set(stoppedRef, true);
|
|
112
|
+
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
113
|
+
yield* Scope.close(actorScope, Exit.void);
|
|
114
|
+
yield* Deferred.succeed(exitDeferred, RuntimeExit.Defect(cause, "transition"));
|
|
115
|
+
return yield* Effect.failCause(cause);
|
|
116
|
+
})));
|
|
117
|
+
else initialResult = initialProcessing;
|
|
118
|
+
if (initialResult.transitioned) {
|
|
119
|
+
yield* SubscriptionRef.set(stateRef, initialResult.newState);
|
|
120
|
+
if (lifecycle?.onStateChange !== void 0) {
|
|
121
|
+
const stateChange = lifecycle.onStateChange(initialResult, initEvent);
|
|
122
|
+
if (isEffect(stateChange)) yield* stateChange;
|
|
123
|
+
}
|
|
124
|
+
if (lifecycle?.onProcessed !== void 0) {
|
|
125
|
+
const processed = lifecycle.onProcessed(initialResult, initEvent);
|
|
126
|
+
if (isEffect(processed)) yield* processed;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const stableInitialState = initialResult.newState;
|
|
87
130
|
const backgroundFibers = [];
|
|
88
131
|
for (const bg of machine._backgroundEffectEntries()) {
|
|
89
132
|
const fiber = yield* bg.handler({
|
|
90
133
|
actorId,
|
|
91
|
-
|
|
134
|
+
generation,
|
|
135
|
+
state: stableInitialState,
|
|
92
136
|
event: initEvent,
|
|
93
137
|
self,
|
|
94
138
|
system
|
|
95
139
|
}).pipe(Effect.forkIn(actorScope));
|
|
96
140
|
backgroundFibers.push(fiber);
|
|
97
141
|
}
|
|
98
|
-
if (lifecycle?.onInitialSpawnEffects !== void 0) yield* lifecycle.onInitialSpawnEffects(
|
|
99
|
-
|
|
100
|
-
const loopFiber = loopFiberRef.current;
|
|
101
|
-
if (loopFiber !== void 0) return Fiber.interrupt(loopFiber);
|
|
102
|
-
return Effect.void;
|
|
103
|
-
})), Effect.asVoid);
|
|
104
|
-
yield* runSpawnEffects(machine, machine.initial, initEvent, self, stateScopeRef.current, system, actorId, hooks?.onError, initialSpawnDefectSignal).pipe(Effect.catchCause((cause) => Effect.gen(function* () {
|
|
142
|
+
if (!initialResult.lifecycleRan && lifecycle?.onInitialSpawnEffects !== void 0) yield* lifecycle.onInitialSpawnEffects(stableInitialState);
|
|
143
|
+
if (!initialResult.lifecycleRan) yield* runSpawnEffects(machine, stableInitialState, initEvent, self, stateScopeRef.current, system, actorId, hooks?.onError, initialSpawnDefectSignal, generation).pipe(Effect.catchCause((cause) => Effect.gen(function* () {
|
|
105
144
|
yield* Ref.set(stoppedRef, true);
|
|
106
145
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
107
146
|
yield* Scope.close(actorScope, Exit.void);
|
|
108
|
-
yield* Deferred.succeed(exitDeferred,
|
|
147
|
+
yield* Deferred.succeed(exitDeferred, RuntimeExit.Defect(cause, "initial-spawn"));
|
|
109
148
|
return yield* Effect.failCause(cause);
|
|
110
149
|
})));
|
|
111
|
-
if (machine._isFinal(
|
|
112
|
-
if (lifecycle?.onFinal !== void 0) yield* lifecycle.onFinal(
|
|
150
|
+
if (machine._isFinal(stableInitialState._tag)) {
|
|
151
|
+
if (lifecycle?.onFinal !== void 0) yield* lifecycle.onFinal(stableInitialState);
|
|
113
152
|
yield* Ref.set(stoppedRef, true);
|
|
114
153
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
115
154
|
yield* Scope.close(actorScope, Exit.void);
|
|
116
|
-
yield* setExit(
|
|
155
|
+
yield* setExit(RuntimeExit.Final(stableInitialState));
|
|
117
156
|
yield* Deferred.succeed(startDeferred, void 0);
|
|
118
157
|
return;
|
|
119
158
|
}
|
|
120
159
|
const augmentedHooks = {
|
|
121
160
|
...hooks,
|
|
122
|
-
onSpawnDefect: (cause) => Deferred.succeed(exitDeferred,
|
|
161
|
+
onSpawnDefect: (cause) => Deferred.succeed(exitDeferred, RuntimeExit.Defect(cause, "spawn")).pipe(Effect.andThen(Ref.set(stoppedRef, true)), Effect.andThen(Effect.suspend(() => {
|
|
123
162
|
const loopFiber = loopFiberRef.current;
|
|
124
163
|
if (loopFiber !== void 0) return Fiber.interrupt(loopFiber);
|
|
125
164
|
return Effect.void;
|
|
126
165
|
})), Effect.asVoid)
|
|
127
166
|
};
|
|
128
|
-
const loopFiber = yield* runtimeEventLoop(machine, stateRef, eventQueue, pendingRequests, stoppedRef, self, stateScopeRef, actorId, system, exitDeferred, augmentedHooks, deferredReplyRef, lifecycle, fork).pipe(Effect.provide(services), Effect.forkDetach);
|
|
167
|
+
const loopFiber = yield* runtimeEventLoop(machine, stateRef, eventQueue, pendingRequests, stoppedRef, self, stateScopeRef, actorId, generation, system, exitDeferred, augmentedHooks, deferredReplyRef, lifecycle, fork).pipe(Effect.provide(services), Effect.forkDetach);
|
|
129
168
|
loopFiberRef.current = loopFiber;
|
|
130
169
|
if (backgroundFibers.length > 0) yield* Effect.raceAll(backgroundFibers.map((fiber) => Fiber.await(fiber).pipe(Effect.flatMap((exit) => {
|
|
131
|
-
if (exit._tag === "Failure" && !Cause.hasInterruptsOnly(exit.cause)) return setExit(
|
|
170
|
+
if (exit._tag === "Failure" && !Cause.hasInterruptsOnly(exit.cause)) return setExit(RuntimeExit.Defect(exit.cause, "background")).pipe(Effect.andThen(Ref.set(stoppedRef, true)), Effect.andThen(Fiber.interrupt(loopFiber)));
|
|
132
171
|
return Effect.never;
|
|
133
172
|
})))).pipe(Effect.forkIn(actorScope));
|
|
134
173
|
yield* Effect.forkDetach(Effect.gen(function* () {
|
|
@@ -137,7 +176,7 @@ const createRuntime = Effect.fn("effect-machine.runtime.create")(function* (mach
|
|
|
137
176
|
else yield* Scope.close(actorScope, loopExit);
|
|
138
177
|
}));
|
|
139
178
|
yield* Deferred.succeed(startDeferred, void 0);
|
|
140
|
-
}).pipe(Effect.catchCause((cause) => Deferred.failCause(startDeferred, cause)
|
|
179
|
+
}).pipe(Effect.catchCause((cause) => Ref.set(stoppedRef, true).pipe(Effect.andThen(Scope.close(stateScopeRef.current, Exit.void)), Effect.andThen(Scope.close(actorScope, Exit.void)), Effect.andThen(setExit(RuntimeExit.Defect(cause, "transition"))), Effect.andThen(Deferred.failCause(startDeferred, cause)), Effect.andThen(Effect.failCause(cause)))));
|
|
141
180
|
const stop = Effect.gen(function* () {
|
|
142
181
|
if (yield* Ref.get(stoppedRef)) return;
|
|
143
182
|
if (lifecycle?.onShutdown !== void 0) yield* lifecycle.onShutdown();
|
|
@@ -147,7 +186,7 @@ const createRuntime = Effect.fn("effect-machine.runtime.create")(function* (mach
|
|
|
147
186
|
if (loopFiber !== void 0) yield* Fiber.interrupt(loopFiber);
|
|
148
187
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
149
188
|
yield* Scope.close(actorScope, Exit.void);
|
|
150
|
-
yield* setExit(
|
|
189
|
+
yield* setExit(RuntimeExit.Stopped);
|
|
151
190
|
}).pipe(Effect.asVoid);
|
|
152
191
|
if (config.skipFinalizer !== true) yield* Effect.addFinalizer(() => stop);
|
|
153
192
|
return {
|
|
@@ -233,7 +272,7 @@ const settlePendingRequests = (pendingRequests, actorId) => Effect.gen(function*
|
|
|
233
272
|
for (const settle of pendingRequests) yield* settle(error);
|
|
234
273
|
pendingRequests.clear();
|
|
235
274
|
});
|
|
236
|
-
const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function* (machine, stateRef, eventQueue, pendingRequests, stoppedRef, self, stateScopeRef, actorId, system, exitDeferred, hooks, deferredReplyRef, lifecycle, fork) {
|
|
275
|
+
const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function* (machine, stateRef, eventQueue, pendingRequests, stoppedRef, self, stateScopeRef, actorId, generation, system, exitDeferred, hooks, deferredReplyRef, lifecycle, fork) {
|
|
237
276
|
const forkEffect = fork ?? Effect.runFork;
|
|
238
277
|
/** Set the exit deferred exactly once. */
|
|
239
278
|
const setExit = (exit) => Deferred.succeed(exitDeferred, exit).pipe(Effect.asVoid);
|
|
@@ -248,7 +287,8 @@ const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function*
|
|
|
248
287
|
hasReply: false,
|
|
249
288
|
deferReply: false,
|
|
250
289
|
reply: void 0,
|
|
251
|
-
postponed: true
|
|
290
|
+
postponed: true,
|
|
291
|
+
transitions: []
|
|
252
292
|
};
|
|
253
293
|
let input = queued;
|
|
254
294
|
if (queued._tag === "call") {
|
|
@@ -276,7 +316,7 @@ const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function*
|
|
|
276
316
|
const processQueued = (currentState, queued) => Effect.gen(function* () {
|
|
277
317
|
const event = queued.event;
|
|
278
318
|
if (lifecycle?.onEvent !== void 0) yield* lifecycle.onEvent(currentState, event);
|
|
279
|
-
const processing = processEventCoreImmediate(machine, currentState, event, self, stateScopeRef, system, actorId, hooks);
|
|
319
|
+
const processing = processEventCoreImmediate(machine, currentState, event, self, stateScopeRef, system, actorId, hooks, generation);
|
|
280
320
|
let result;
|
|
281
321
|
if (isEffect(processing)) result = yield* processing;
|
|
282
322
|
else result = processing;
|
|
@@ -364,7 +404,8 @@ const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function*
|
|
|
364
404
|
hasReply: false,
|
|
365
405
|
deferReply: false,
|
|
366
406
|
reply: void 0,
|
|
367
|
-
postponed: false
|
|
407
|
+
postponed: false,
|
|
408
|
+
transitions: []
|
|
368
409
|
}));
|
|
369
410
|
}
|
|
370
411
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
@@ -373,7 +414,7 @@ const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function*
|
|
|
373
414
|
while (true) {
|
|
374
415
|
const queued = yield* Queue.take(eventQueue);
|
|
375
416
|
if (queued._tag === "drain") {
|
|
376
|
-
yield* shutdown(
|
|
417
|
+
yield* shutdown(RuntimeExit.Stopped);
|
|
377
418
|
yield* Deferred.succeed(queued.done, void 0);
|
|
378
419
|
return;
|
|
379
420
|
}
|
|
@@ -382,7 +423,7 @@ const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function*
|
|
|
382
423
|
if (queued._tag === "sendWait") forkEffect(Deferred.failCause(queued.done, cause));
|
|
383
424
|
else if (queued._tag === "ask") forkEffect(Deferred.die(queued.reply, cause));
|
|
384
425
|
else if (queued._tag === "call") forkEffect(Deferred.failCause(queued.reply, cause));
|
|
385
|
-
return shutdown(
|
|
426
|
+
return shutdown(RuntimeExit.Defect(cause, "transition")).pipe(Effect.andThen(Effect.failCause(cause)));
|
|
386
427
|
}));
|
|
387
428
|
let stopped;
|
|
388
429
|
if (advancement === void 0) {
|
|
@@ -392,7 +433,7 @@ const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function*
|
|
|
392
433
|
} else stopped = (yield* catchEventDefect(advancement.advance(eventQueued))).stopped;
|
|
393
434
|
if (stopped) {
|
|
394
435
|
const finalState = yield* SubscriptionRef.get(stateRef);
|
|
395
|
-
yield* shutdown(
|
|
436
|
+
yield* shutdown(RuntimeExit.Final(finalState));
|
|
396
437
|
return;
|
|
397
438
|
}
|
|
398
439
|
}
|
|
@@ -1,10 +1,35 @@
|
|
|
1
1
|
import { Machine } from "../machine.js";
|
|
2
2
|
import { Transition } from "./machine-definition.js";
|
|
3
3
|
//#region src/internal/transition.d.ts
|
|
4
|
+
interface ExecutedStep<S, E> {
|
|
5
|
+
readonly previousState: S;
|
|
6
|
+
readonly newState: S;
|
|
7
|
+
readonly event: E;
|
|
8
|
+
readonly transition: Transition<S, E, never>;
|
|
9
|
+
}
|
|
10
|
+
interface ExecutedTransition<S, E = unknown> {
|
|
11
|
+
readonly newState: S;
|
|
12
|
+
readonly transitioned: boolean;
|
|
13
|
+
readonly reenter: boolean;
|
|
14
|
+
readonly hasReply: boolean;
|
|
15
|
+
readonly deferReply: boolean;
|
|
16
|
+
readonly reply: unknown;
|
|
17
|
+
readonly transition?: Transition<S, E, never>;
|
|
18
|
+
readonly steps: ReadonlyArray<ExecutedStep<S, E>>;
|
|
19
|
+
}
|
|
20
|
+
declare const executeTransitionImmediate: <S extends {
|
|
21
|
+
readonly _tag: string;
|
|
22
|
+
}, E extends {
|
|
23
|
+
readonly _tag: string;
|
|
24
|
+
}, R>(machine: Machine<S, E, R, any, any, any, any>, currentState: S, event: E, hooks?: ProcessEventHooks<S, E>) => ExecutedTransition<S, E> | Effect.Effect<ExecutedTransition<S, E>>;
|
|
4
25
|
/**
|
|
5
26
|
* Optional hooks for event processing inspection/tracing.
|
|
6
27
|
*/
|
|
7
28
|
interface ProcessEventHooks<S, E> {
|
|
29
|
+
/** Called after each guard candidate is evaluated. */
|
|
30
|
+
readonly onGuard?: (evaluation: GuardEvaluation<S, E>) => Effect.Effect<void>;
|
|
31
|
+
/** Called before an accepted transition handler runs. */
|
|
32
|
+
readonly onOperation?: (operation: TransitionOperation<S, E>) => Effect.Effect<void>;
|
|
8
33
|
/** Called before running spawn effects */
|
|
9
34
|
readonly onSpawnEffect?: (state: S) => Effect.Effect<void>;
|
|
10
35
|
/** Called after transition completes */
|
|
@@ -14,6 +39,17 @@ interface ProcessEventHooks<S, E> {
|
|
|
14
39
|
/** Called when a forked spawn fiber defects — signals the runtime to set exitDeferred */
|
|
15
40
|
readonly onSpawnDefect?: (cause: Cause.Cause<unknown>) => Effect.Effect<void>;
|
|
16
41
|
}
|
|
42
|
+
interface GuardEvaluation<S, E> {
|
|
43
|
+
readonly guard: string;
|
|
44
|
+
readonly state: S;
|
|
45
|
+
readonly event: E;
|
|
46
|
+
readonly result: boolean;
|
|
47
|
+
}
|
|
48
|
+
interface TransitionOperation<S, E> {
|
|
49
|
+
readonly operation: string;
|
|
50
|
+
readonly state: S;
|
|
51
|
+
readonly event: E;
|
|
52
|
+
}
|
|
17
53
|
/**
|
|
18
54
|
* Error info for inspection hooks.
|
|
19
55
|
*/
|
|
@@ -26,7 +62,7 @@ interface ProcessEventError<S, E> {
|
|
|
26
62
|
/**
|
|
27
63
|
* Result of processing an event through the machine.
|
|
28
64
|
*/
|
|
29
|
-
interface ProcessEventResult<S> {
|
|
65
|
+
interface ProcessEventResult<S, E = unknown> {
|
|
30
66
|
/** New state after processing */
|
|
31
67
|
readonly newState: S;
|
|
32
68
|
/** Previous state before processing */
|
|
@@ -45,6 +81,12 @@ interface ProcessEventResult<S> {
|
|
|
45
81
|
readonly reply?: unknown;
|
|
46
82
|
/** Whether the event was postponed (buffered for retry after next state change) */
|
|
47
83
|
readonly postponed: boolean;
|
|
84
|
+
/** Each accepted edge in the stable macrostep. */
|
|
85
|
+
readonly transitions: ReadonlyArray<{
|
|
86
|
+
readonly previousState: S;
|
|
87
|
+
readonly newState: S;
|
|
88
|
+
readonly event: E;
|
|
89
|
+
}>;
|
|
48
90
|
}
|
|
49
91
|
/**
|
|
50
92
|
* Resolve which transition should fire for a given state and event.
|
|
@@ -54,6 +96,12 @@ declare const resolveTransition: <S extends {
|
|
|
54
96
|
readonly _tag: string;
|
|
55
97
|
}, E extends {
|
|
56
98
|
readonly _tag: string;
|
|
57
|
-
}, R>(machine: Machine<S, E, R, any, any>, currentState: S, event: E) => Transition<S, E, never> | undefined;
|
|
99
|
+
}, R>(machine: Machine<S, E, R, any, any, any, any>, currentState: S, event: E) => Transition<S, E, never> | undefined;
|
|
100
|
+
/** Resolve a transition with pure or Effect guards. */
|
|
101
|
+
declare const resolveTransitionEffect: <S extends {
|
|
102
|
+
readonly _tag: string;
|
|
103
|
+
}, E extends {
|
|
104
|
+
readonly _tag: string;
|
|
105
|
+
}, R>(machine: Machine<S, E, R, any, any, any, any>, currentState: S, event: E) => Effect.Effect<Transition<S, E, never> | undefined>;
|
|
58
106
|
//#endregion
|
|
59
|
-
export { ProcessEventError, ProcessEventHooks, ProcessEventResult, resolveTransition };
|
|
107
|
+
export { GuardEvaluation, ProcessEventError, ProcessEventHooks, ProcessEventResult, TransitionOperation, executeTransitionImmediate, resolveTransition, resolveTransitionEffect };
|