effect-machine 0.17.0 → 0.18.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/LICENSE +21 -0
- package/README.md +50 -54
- package/dist/actor.d.ts +8 -45
- package/dist/actor.js +157 -231
- package/dist/cluster/adapters/in-memory.d.ts +0 -1
- package/dist/cluster/adapters/in-memory.js +10 -5
- package/dist/cluster/entity-actor-ref.d.ts +2 -3
- package/dist/cluster/entity-actor-ref.js +14 -17
- package/dist/cluster/entity-machine.d.ts +2 -8
- package/dist/cluster/entity-machine.js +57 -34
- package/dist/cluster/index.js +2 -2
- package/dist/cluster/persistence.d.ts +0 -1
- package/dist/cluster/to-entity.d.ts +19 -21
- package/dist/cluster/to-entity.js +18 -19
- package/dist/errors.d.ts +11 -37
- package/dist/errors.js +12 -30
- package/dist/index.d.ts +4 -5
- package/dist/index.js +4 -5
- package/dist/inspection.d.ts +0 -1
- package/dist/inspection.js +24 -13
- package/dist/internal/brands.d.ts +0 -1
- package/dist/internal/event-advancement.d.ts +50 -0
- package/dist/internal/event-advancement.js +79 -0
- package/dist/internal/inspection.d.ts +5 -9
- package/dist/internal/inspection.js +31 -10
- package/dist/internal/machine-definition.d.ts +16 -0
- package/dist/internal/runtime.d.ts +1 -161
- package/dist/internal/runtime.js +191 -150
- package/dist/internal/transition.d.ts +4 -135
- package/dist/internal/transition.js +82 -157
- package/dist/internal/utils.d.ts +3 -40
- package/dist/internal/utils.js +2 -2
- package/dist/machine.d.ts +47 -137
- package/dist/machine.js +147 -215
- package/dist/schema.d.ts +42 -21
- package/dist/schema.js +28 -18
- package/dist/supervision.d.ts +1 -24
- package/dist/supervision.js +2 -3
- package/dist/testing.d.ts +15 -29
- package/dist/testing.js +76 -95
- package/package.json +19 -38
- package/dist/slot.d.ts +0 -159
- package/dist/slot.js +0 -165
- package/v3/dist/_virtual/_rolldown/runtime.js +0 -13
- package/v3/dist/actor.d.ts +0 -250
- package/v3/dist/actor.js +0 -577
- package/v3/dist/cluster/adapters/in-memory.d.ts +0 -15
- package/v3/dist/cluster/adapters/in-memory.js +0 -62
- package/v3/dist/cluster/entity-actor-ref.d.ts +0 -49
- package/v3/dist/cluster/entity-actor-ref.js +0 -19
- package/v3/dist/cluster/entity-machine.d.ts +0 -74
- package/v3/dist/cluster/entity-machine.js +0 -166
- package/v3/dist/cluster/index.d.ts +0 -6
- package/v3/dist/cluster/index.js +0 -6
- package/v3/dist/cluster/persistence.d.ts +0 -48
- package/v3/dist/cluster/persistence.js +0 -14
- package/v3/dist/cluster/to-entity.d.ts +0 -69
- package/v3/dist/cluster/to-entity.js +0 -59
- package/v3/dist/errors.d.ts +0 -95
- package/v3/dist/errors.js +0 -54
- package/v3/dist/index.d.ts +0 -11
- package/v3/dist/index.js +0 -9
- package/v3/dist/inspection.d.ts +0 -151
- package/v3/dist/inspection.js +0 -128
- package/v3/dist/internal/brands.d.ts +0 -50
- package/v3/dist/internal/inspection.d.ts +0 -11
- package/v3/dist/internal/inspection.js +0 -20
- package/v3/dist/internal/runtime.d.ts +0 -161
- package/v3/dist/internal/runtime.js +0 -360
- package/v3/dist/internal/transition.d.ts +0 -190
- package/v3/dist/internal/transition.js +0 -278
- package/v3/dist/internal/utils.d.ts +0 -101
- package/v3/dist/internal/utils.js +0 -75
- package/v3/dist/machine.d.ts +0 -398
- package/v3/dist/machine.js +0 -487
- package/v3/dist/schema.d.ts +0 -174
- package/v3/dist/schema.js +0 -206
- package/v3/dist/slot.d.ts +0 -158
- package/v3/dist/slot.js +0 -165
- package/v3/dist/supervision.d.ts +0 -97
- package/v3/dist/supervision.js +0 -42
- package/v3/dist/testing.d.ts +0 -151
- package/v3/dist/testing.js +0 -189
- /package/{v3/dist/internal/brands.js → dist/internal/machine-definition.js} +0 -0
package/dist/inspection.js
CHANGED
|
@@ -17,10 +17,11 @@ const makeInspector = (onInspect) => ({ onInspect });
|
|
|
17
17
|
const makeInspectorEffect = (onInspect) => ({ onInspect });
|
|
18
18
|
const inspectionEffect = (inspector, event) => {
|
|
19
19
|
const result = inspector.onInspect(event);
|
|
20
|
-
|
|
20
|
+
if (Effect.isEffect(result)) return result;
|
|
21
|
+
return Effect.void;
|
|
21
22
|
};
|
|
22
|
-
const combineInspectors = (...inspectors) => ({ onInspect: (event) => Effect.forEach(inspectors, (inspector) => inspectionEffect(inspector, event).pipe(Effect.
|
|
23
|
-
concurrency:
|
|
23
|
+
const combineInspectors = (...inspectors) => ({ onInspect: (event) => Effect.forEach(inspectors, (inspector) => inspectionEffect(inspector, event).pipe(Effect.ignoreCause), {
|
|
24
|
+
concurrency: 16,
|
|
24
25
|
discard: true
|
|
25
26
|
}) });
|
|
26
27
|
const inspectionSpanName = (event) => {
|
|
@@ -40,7 +41,11 @@ const inspectionTraceName = (event) => {
|
|
|
40
41
|
case "@machine.event": return `machine.event ${event.event._tag}`;
|
|
41
42
|
case "@machine.transition": return `machine.transition ${event.fromState._tag}->${event.toState._tag}`;
|
|
42
43
|
case "@machine.effect": return `machine.effect ${event.effectType}`;
|
|
43
|
-
case "@machine.task":
|
|
44
|
+
case "@machine.task": {
|
|
45
|
+
let taskSuffix = "";
|
|
46
|
+
if (event.taskName !== void 0) taskSuffix = ` ${event.taskName}`;
|
|
47
|
+
return `machine.task ${event.phase}${taskSuffix}`;
|
|
48
|
+
}
|
|
44
49
|
case "@machine.error": return `machine.error ${event.phase}`;
|
|
45
50
|
case "@machine.stop": return `machine.stop ${event.finalState._tag}`;
|
|
46
51
|
}
|
|
@@ -71,12 +76,16 @@ const inspectionAttributes = (event) => {
|
|
|
71
76
|
"machine.state.current": event.state._tag,
|
|
72
77
|
"machine.effect.kind": event.effectType
|
|
73
78
|
};
|
|
74
|
-
case "@machine.task":
|
|
75
|
-
|
|
76
|
-
"machine.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
case "@machine.task": {
|
|
80
|
+
const taskNameAttribute = {};
|
|
81
|
+
if (event.taskName !== void 0) taskNameAttribute["machine.task.name"] = event.taskName;
|
|
82
|
+
return {
|
|
83
|
+
...shared,
|
|
84
|
+
"machine.state.current": event.state._tag,
|
|
85
|
+
"machine.task.phase": event.phase,
|
|
86
|
+
...taskNameAttribute
|
|
87
|
+
};
|
|
88
|
+
}
|
|
80
89
|
case "@machine.error": return {
|
|
81
90
|
...shared,
|
|
82
91
|
"machine.phase": event.phase,
|
|
@@ -89,19 +98,21 @@ const inspectionAttributes = (event) => {
|
|
|
89
98
|
}
|
|
90
99
|
};
|
|
91
100
|
const tracingInspector = (options) => ({ onInspect: (event) => {
|
|
92
|
-
|
|
101
|
+
let spanName = void 0;
|
|
102
|
+
if (typeof options?.spanName === "function") spanName = options.spanName(event);
|
|
103
|
+
else spanName = options?.spanName;
|
|
93
104
|
const traceName = options?.eventName?.(event) ?? inspectionTraceName(event);
|
|
94
105
|
const attributes = {
|
|
95
106
|
...inspectionAttributes(event),
|
|
96
107
|
...options?.attributes?.(event) ?? {}
|
|
97
108
|
};
|
|
98
|
-
return Effect.
|
|
109
|
+
return Effect.fn("effect-machine.inspector.trace")(function* () {
|
|
99
110
|
const currentSpan = yield* Effect.option(Effect.currentSpan);
|
|
100
111
|
if (Option.isSome(currentSpan)) currentSpan.value.event(traceName, BigInt(event.timestamp) * 1000000n, {
|
|
101
112
|
actorId: event.actorId,
|
|
102
113
|
inspectionType: event.type
|
|
103
114
|
});
|
|
104
|
-
}).pipe(Effect.withSpan(spanName ?? inspectionSpanName(event), { attributes }));
|
|
115
|
+
})().pipe(Effect.withSpan(spanName ?? inspectionSpanName(event), { attributes }));
|
|
105
116
|
} });
|
|
106
117
|
/**
|
|
107
118
|
* Console inspector that logs events in a readable format
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//#region src/internal/event-advancement.d.ts
|
|
2
|
+
interface AdvancementStep<S, A> {
|
|
3
|
+
readonly state: S;
|
|
4
|
+
readonly transitioned: boolean;
|
|
5
|
+
readonly stateChanged: boolean;
|
|
6
|
+
readonly shouldStop: boolean;
|
|
7
|
+
readonly value: A;
|
|
8
|
+
}
|
|
9
|
+
interface PostponedStep<I, A> {
|
|
10
|
+
readonly input: I;
|
|
11
|
+
readonly value: A;
|
|
12
|
+
}
|
|
13
|
+
interface EventAdvancementOptions<S, I, A, R> {
|
|
14
|
+
readonly initial: S;
|
|
15
|
+
readonly isFinal: (state: S) => boolean;
|
|
16
|
+
readonly shouldPostpone: (state: S, input: I) => boolean;
|
|
17
|
+
readonly postpone: (state: S, input: I) => Effect.Effect<PostponedStep<I, A>, never, R>;
|
|
18
|
+
readonly process: (state: S, input: I, draining: boolean) => Effect.Effect<AdvancementStep<S, A>, never, R>;
|
|
19
|
+
readonly commit?: (previousState: S, input: I, step: AdvancementStep<S, A>) => Effect.Effect<void, never, R>;
|
|
20
|
+
readonly discard?: (input: I) => Effect.Effect<void, never, R>;
|
|
21
|
+
}
|
|
22
|
+
interface AdvancementResult<S, A> {
|
|
23
|
+
readonly state: S;
|
|
24
|
+
readonly value: A | undefined;
|
|
25
|
+
readonly stopped: boolean;
|
|
26
|
+
readonly postponed: boolean;
|
|
27
|
+
}
|
|
28
|
+
declare const makeEventAdvancement: <S, I, A, R>(options: EventAdvancementOptions<S, I, A, R>) => {
|
|
29
|
+
advance: (input: I) => Effect.Effect<{
|
|
30
|
+
state: S;
|
|
31
|
+
value: undefined;
|
|
32
|
+
stopped: true;
|
|
33
|
+
postponed: false;
|
|
34
|
+
} | {
|
|
35
|
+
state: S;
|
|
36
|
+
value: A;
|
|
37
|
+
stopped: false;
|
|
38
|
+
postponed: true;
|
|
39
|
+
} | {
|
|
40
|
+
state: S;
|
|
41
|
+
value: A;
|
|
42
|
+
stopped: boolean;
|
|
43
|
+
postponed: false;
|
|
44
|
+
}, never, R>;
|
|
45
|
+
close: () => Effect.Effect<void, never, R>;
|
|
46
|
+
readonly state: S;
|
|
47
|
+
readonly stopped: boolean;
|
|
48
|
+
};
|
|
49
|
+
//#endregion
|
|
50
|
+
export { AdvancementResult, AdvancementStep, EventAdvancementOptions, PostponedStep, makeEventAdvancement };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
//#region src/internal/event-advancement.ts
|
|
3
|
+
/**
|
|
4
|
+
* Event advancement policy shared by live and offline machine execution.
|
|
5
|
+
*
|
|
6
|
+
* Owns postponed event order, cascading drain, and terminal state handling.
|
|
7
|
+
* Callers supply the effects that execute one event.
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
const makeEventAdvancement = (options) => {
|
|
12
|
+
let state = options.initial;
|
|
13
|
+
let stopped = options.isFinal(state);
|
|
14
|
+
const postponed = [];
|
|
15
|
+
const advance = (input) => Effect.gen(function* () {
|
|
16
|
+
const postponedStep = (entry) => options.postpone(state, entry);
|
|
17
|
+
if (stopped) return {
|
|
18
|
+
state,
|
|
19
|
+
value: void 0,
|
|
20
|
+
stopped: true,
|
|
21
|
+
postponed: false
|
|
22
|
+
};
|
|
23
|
+
if (options.shouldPostpone(state, input)) {
|
|
24
|
+
const result = yield* postponedStep(input);
|
|
25
|
+
postponed.push(result.input);
|
|
26
|
+
return {
|
|
27
|
+
state,
|
|
28
|
+
value: result.value,
|
|
29
|
+
stopped,
|
|
30
|
+
postponed: true
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const previousState = state;
|
|
34
|
+
const first = yield* options.process(previousState, input, false);
|
|
35
|
+
state = first.state;
|
|
36
|
+
if (options.commit !== void 0) yield* options.commit(previousState, input, first);
|
|
37
|
+
stopped = first.shouldStop || options.isFinal(state);
|
|
38
|
+
let stateChanged = first.stateChanged;
|
|
39
|
+
while (!stopped && stateChanged && postponed.length > 0) {
|
|
40
|
+
stateChanged = false;
|
|
41
|
+
const drained = postponed.splice(0);
|
|
42
|
+
for (const entry of drained) {
|
|
43
|
+
if (options.shouldPostpone(state, entry)) {
|
|
44
|
+
postponed.push(entry);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const drainedPreviousState = state;
|
|
48
|
+
const step = yield* options.process(drainedPreviousState, entry, true);
|
|
49
|
+
state = step.state;
|
|
50
|
+
if (options.commit !== void 0) yield* options.commit(drainedPreviousState, entry, step);
|
|
51
|
+
stopped = step.shouldStop || options.isFinal(state);
|
|
52
|
+
stateChanged = stateChanged || step.stateChanged;
|
|
53
|
+
if (stopped) break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
state,
|
|
58
|
+
value: first.value,
|
|
59
|
+
stopped,
|
|
60
|
+
postponed: false
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
const close = () => Effect.gen(function* () {
|
|
64
|
+
if (options.discard !== void 0) for (const input of postponed) yield* options.discard(input);
|
|
65
|
+
postponed.length = 0;
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
advance,
|
|
69
|
+
close,
|
|
70
|
+
get state() {
|
|
71
|
+
return state;
|
|
72
|
+
},
|
|
73
|
+
get stopped() {
|
|
74
|
+
return stopped;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
//#endregion
|
|
79
|
+
export { makeEventAdvancement };
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { ProcessEventHooks } from "./transition.js";
|
|
2
|
+
import { InspectorService } from "../inspection.js";
|
|
4
3
|
//#region src/internal/inspection.d.ts
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
* @internal
|
|
8
|
-
*/
|
|
9
|
-
declare const emitWithTimestamp: <S, E>(inspector: InspectorService<S, E> | undefined, makeEvent: (timestamp: number) => InspectionEvent<S, E>) => Effect.Effect<void, never, never>;
|
|
4
|
+
/** Adapt the Inspector service to the transition kernel. */
|
|
5
|
+
declare const makeInspectionHooks: <S, E>(actorId: string, inspector: InspectorService<S, E>) => ProcessEventHooks<S, E>;
|
|
10
6
|
//#endregion
|
|
11
|
-
export {
|
|
7
|
+
export { makeInspectionHooks };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Clock, Effect } from "effect";
|
|
1
|
+
import { Cause, Clock, Effect } from "effect";
|
|
2
2
|
//#region src/internal/inspection.ts
|
|
3
3
|
/**
|
|
4
4
|
* Emit an inspection event with timestamp from Clock.
|
|
@@ -7,14 +7,35 @@ import { Clock, Effect } from "effect";
|
|
|
7
7
|
const emitWithTimestamp = Effect.fn("effect-machine.emitWithTimestamp")(function* (inspector, makeEvent) {
|
|
8
8
|
if (inspector === void 0) return;
|
|
9
9
|
const event = makeEvent(yield* Clock.currentTimeMillis);
|
|
10
|
-
const result = yield* Effect.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
const result = yield* Effect.try(() => inspector.onInspect(event)).pipe(Effect.orElseSucceed(() => void 0));
|
|
11
|
+
if (Effect.isEffect(result)) yield* result.pipe(Effect.ignoreCause);
|
|
12
|
+
});
|
|
13
|
+
/** Adapt the Inspector service to the transition kernel. */
|
|
14
|
+
const makeInspectionHooks = (actorId, inspector) => ({
|
|
15
|
+
onSpawnEffect: (state) => emitWithTimestamp(inspector, (timestamp) => ({
|
|
16
|
+
type: "@machine.effect",
|
|
17
|
+
actorId,
|
|
18
|
+
effectType: "spawn",
|
|
19
|
+
state,
|
|
20
|
+
timestamp
|
|
21
|
+
})),
|
|
22
|
+
onTransition: (from, to, event) => emitWithTimestamp(inspector, (timestamp) => ({
|
|
23
|
+
type: "@machine.transition",
|
|
24
|
+
actorId,
|
|
25
|
+
fromState: from,
|
|
26
|
+
toState: to,
|
|
27
|
+
event,
|
|
28
|
+
timestamp
|
|
29
|
+
})),
|
|
30
|
+
onError: (info) => emitWithTimestamp(inspector, (timestamp) => ({
|
|
31
|
+
type: "@machine.error",
|
|
32
|
+
actorId,
|
|
33
|
+
phase: info.phase,
|
|
34
|
+
state: info.state,
|
|
35
|
+
event: info.event,
|
|
36
|
+
error: Cause.pretty(info.cause),
|
|
37
|
+
timestamp
|
|
38
|
+
}))
|
|
18
39
|
});
|
|
19
40
|
//#endregion
|
|
20
|
-
export { emitWithTimestamp };
|
|
41
|
+
export { emitWithTimestamp, makeInspectionHooks };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/internal/machine-definition.d.ts
|
|
2
|
+
interface Transition<State, Event, R> {
|
|
3
|
+
readonly stateTag: string;
|
|
4
|
+
readonly eventTag: string;
|
|
5
|
+
readonly handler: TransitionHandler<State, Event, State, R>;
|
|
6
|
+
readonly reenter?: boolean;
|
|
7
|
+
}
|
|
8
|
+
interface SpawnEffect<State, Event, R> {
|
|
9
|
+
readonly stateTag: string;
|
|
10
|
+
readonly handler: StateEffectHandler<State, Event, R>;
|
|
11
|
+
}
|
|
12
|
+
interface BackgroundEffect<State, Event, R> {
|
|
13
|
+
readonly handler: StateEffectHandler<State, Event, R>;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { BackgroundEffect, SpawnEffect, Transition };
|
|
@@ -1,161 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { MachineContextTag, SlotsDef } from "../slot.js";
|
|
3
|
-
import { ActorExit } from "../supervision.js";
|
|
4
|
-
import { ProcessEventHooks, ProcessEventResult } from "./transition.js";
|
|
5
|
-
import { Machine } from "../machine.js";
|
|
6
|
-
import { ActorSystemService } from "../actor.js";
|
|
7
|
-
import { Deferred, Effect, Queue, Ref, Scope, SubscriptionRef } from "effect";
|
|
8
|
-
|
|
9
|
-
//#region src/internal/runtime.d.ts
|
|
10
|
-
/** @internal */
|
|
11
|
-
type RuntimeQueuedEvent<E> = {
|
|
12
|
-
readonly _tag: "send";
|
|
13
|
-
readonly event: E;
|
|
14
|
-
} | {
|
|
15
|
-
readonly _tag: "sendWait";
|
|
16
|
-
readonly event: E;
|
|
17
|
-
readonly done: Deferred.Deferred<void, unknown>;
|
|
18
|
-
} | {
|
|
19
|
-
readonly _tag: "call";
|
|
20
|
-
readonly event: E;
|
|
21
|
-
readonly reply: Deferred.Deferred<ProcessEventResult<{
|
|
22
|
-
readonly _tag: string;
|
|
23
|
-
}>, unknown>;
|
|
24
|
-
} | {
|
|
25
|
-
readonly _tag: "ask";
|
|
26
|
-
readonly event: E;
|
|
27
|
-
readonly reply: Deferred.Deferred<unknown, NoReplyError>;
|
|
28
|
-
} | {
|
|
29
|
-
readonly _tag: "drain";
|
|
30
|
-
readonly done: Deferred.Deferred<void>;
|
|
31
|
-
};
|
|
32
|
-
/**
|
|
33
|
-
* Resources owned by the actor cell (stable across generations).
|
|
34
|
-
* When provided, createRuntime uses these instead of allocating its own.
|
|
35
|
-
* @internal
|
|
36
|
-
*/
|
|
37
|
-
interface RuntimeCellResources<S, E> {
|
|
38
|
-
readonly stateRef: SubscriptionRef.SubscriptionRef<S>;
|
|
39
|
-
readonly eventQueue: Queue.Queue<RuntimeQueuedEvent<E>>;
|
|
40
|
-
readonly stoppedRef: Ref.Ref<boolean>;
|
|
41
|
-
}
|
|
42
|
-
/** @internal */
|
|
43
|
-
interface RuntimeHandle<S, E> {
|
|
44
|
-
/** Enqueue a fire-and-forget event */
|
|
45
|
-
readonly send: (event: E) => Effect.Effect<void>;
|
|
46
|
-
/** Enqueue event and wait for processing to complete (for RPC Send). Fails on defect. */
|
|
47
|
-
readonly sendWait: (event: E) => Effect.Effect<void, unknown>;
|
|
48
|
-
/** Enqueue an ask event, returns the reply value */
|
|
49
|
-
readonly ask: (event: E) => Effect.Effect<unknown, NoReplyError>;
|
|
50
|
-
/** Get current state */
|
|
51
|
-
readonly getState: Effect.Effect<S>;
|
|
52
|
-
/** SubscriptionRef for state observation (WatchState streaming) */
|
|
53
|
-
readonly stateRef: SubscriptionRef.SubscriptionRef<S>;
|
|
54
|
-
/** Whether the runtime has stopped (final state reached) */
|
|
55
|
-
readonly isStopped: Effect.Effect<boolean>;
|
|
56
|
-
/** Stop the runtime (interrupt event loop, clean up) */
|
|
57
|
-
readonly stop: Effect.Effect<void>;
|
|
58
|
-
/**
|
|
59
|
-
* Start the runtime — fork event loop, background effects, spawn effects.
|
|
60
|
-
* Idempotent: first caller runs initialization, subsequent callers await completion.
|
|
61
|
-
* Events sent before start() are queued and processed when start() runs.
|
|
62
|
-
*/
|
|
63
|
-
readonly start: Effect.Effect<void>;
|
|
64
|
-
/** @internal — raw event queue for direct enqueue (actor.ts uses this for pendingReplies tracking) */
|
|
65
|
-
readonly _queue: Queue.Queue<RuntimeQueuedEvent<E>>;
|
|
66
|
-
/** @internal — stopped ref for direct access */
|
|
67
|
-
readonly _stoppedRef: Ref.Ref<boolean>;
|
|
68
|
-
/**
|
|
69
|
-
* Exit deferred — set exactly once with the exit reason when the runtime stops.
|
|
70
|
-
* Final state → ActorExit.Final, explicit stop → ActorExit.Stopped, defect → ActorExit.Defect.
|
|
71
|
-
*/
|
|
72
|
-
readonly exitDeferred: Deferred.Deferred<ActorExit<S>>;
|
|
73
|
-
/**
|
|
74
|
-
* Actor scope — owns background fibers for this generation.
|
|
75
|
-
* Closing this scope interrupts all background fibers.
|
|
76
|
-
*/
|
|
77
|
-
readonly actorScope: Scope.Closeable;
|
|
78
|
-
}
|
|
79
|
-
/** @internal */
|
|
80
|
-
interface RuntimeLifecycleHooks<S, E> {
|
|
81
|
-
/** Before processEventCore — actor emits @machine.event inspection */
|
|
82
|
-
readonly onEvent?: (state: S, event: E) => Effect.Effect<void>;
|
|
83
|
-
/** After SubscriptionRef.set on transition — actor notifies listeners, annotates spans */
|
|
84
|
-
readonly onStateChange?: (result: ProcessEventResult<S>, event: E) => Effect.Effect<void>;
|
|
85
|
-
/** After reply settlement when transition occurred — actor publishes to transitionsPubSub */
|
|
86
|
-
readonly onProcessed?: (result: ProcessEventResult<S>, event: E) => Effect.Effect<void>;
|
|
87
|
-
/** When final state detected in event loop — actor emits @machine.stop */
|
|
88
|
-
readonly onFinal?: (state: S) => Effect.Effect<void>;
|
|
89
|
-
/** Before stop resource cleanup — actor emits @machine.stop, settles pending replies */
|
|
90
|
-
readonly onShutdown?: () => Effect.Effect<void>;
|
|
91
|
-
/** Before initial spawn effects — actor emits @machine.effect inspection */
|
|
92
|
-
readonly onInitialSpawnEffects?: (state: S) => Effect.Effect<void>;
|
|
93
|
-
}
|
|
94
|
-
/** @internal */
|
|
95
|
-
interface RuntimeConfig<S, E> {
|
|
96
|
-
readonly actorId: string;
|
|
97
|
-
readonly hooks?: ProcessEventHooks<S, E>;
|
|
98
|
-
/**
|
|
99
|
-
* Cell-owned resources. When provided, the runtime uses the cell's stateRef,
|
|
100
|
-
* eventQueue, and stoppedRef instead of creating its own.
|
|
101
|
-
* Used by actor.ts for supervision (cell owns stable resources across generations).
|
|
102
|
-
*/
|
|
103
|
-
readonly cellResources?: RuntimeCellResources<S, E>;
|
|
104
|
-
/**
|
|
105
|
-
* Custom queue factory. Default: `Queue.unbounded()`.
|
|
106
|
-
* Use `Queue.sliding(n)` or `Queue.dropping(n)` for bounded queues.
|
|
107
|
-
* Ignored when cellResources is provided.
|
|
108
|
-
*/
|
|
109
|
-
readonly queueFactory?: Effect.Effect<Queue.Queue<RuntimeQueuedEvent<E>>>;
|
|
110
|
-
/** Lifecycle callbacks for actor-specific concerns */
|
|
111
|
-
readonly lifecycle?: RuntimeLifecycleHooks<S, E>;
|
|
112
|
-
/** Wrap each processQueued invocation — actor uses for span annotations */
|
|
113
|
-
readonly wrapProcess?: (state: S, event: E, inner: Effect.Effect<ProcessQueuedResult<S>>) => Effect.Effect<ProcessQueuedResult<S>>;
|
|
114
|
-
/** Called after self.spawn succeeds — actor tracks children */
|
|
115
|
-
readonly onChildSpawned?: (childId: string, child: unknown) => Effect.Effect<void>;
|
|
116
|
-
/** Skip registering stop as scope finalizer — actor manages its own lifecycle */
|
|
117
|
-
readonly skipFinalizer?: boolean;
|
|
118
|
-
/** Prefix for child actor IDs in self.spawn. Entity-machine uses `${actorId}/`. Default: no prefix. */
|
|
119
|
-
readonly childIdPrefix?: string;
|
|
120
|
-
}
|
|
121
|
-
/** @internal */
|
|
122
|
-
interface ProcessQueuedResult<S> {
|
|
123
|
-
readonly shouldStop: boolean;
|
|
124
|
-
readonly stateChanged: boolean;
|
|
125
|
-
readonly result: ProcessEventResult<S>;
|
|
126
|
-
}
|
|
127
|
-
/**
|
|
128
|
-
* Create a runtime for a machine. Returns a handle for sending events
|
|
129
|
-
* and querying state. The runtime owns:
|
|
130
|
-
* - Event loop fiber
|
|
131
|
-
* - Postpone buffer
|
|
132
|
-
* - Background effects (under actorScope)
|
|
133
|
-
* - State scope (spawn effects)
|
|
134
|
-
* - Final state detection
|
|
135
|
-
* - Exit reason via exitDeferred
|
|
136
|
-
*
|
|
137
|
-
* Resources (stateRef, eventQueue, stoppedRef) are either cell-provided
|
|
138
|
-
* or allocated fresh by the runtime.
|
|
139
|
-
*
|
|
140
|
-
* @internal
|
|
141
|
-
*/
|
|
142
|
-
declare const createRuntime: <S extends {
|
|
143
|
-
readonly _tag: string;
|
|
144
|
-
}, E extends {
|
|
145
|
-
readonly _tag: string;
|
|
146
|
-
}, R, SD extends SlotsDef>(machine: Machine<S, E, R, any, any, SD>, system: ActorSystemService, config: RuntimeConfig<S, E>) => Effect.Effect<{
|
|
147
|
-
stop: Effect.Effect<void, never, never>;
|
|
148
|
-
start: Effect.Effect<void, unknown, Exclude<R, MachineContextTag> | Exclude<Exclude<R, MachineContextTag>, Scope.Scope>>;
|
|
149
|
-
send: (event: E) => Effect.Effect<void>;
|
|
150
|
-
sendWait: (event: E) => Effect.Effect<void, unknown>;
|
|
151
|
-
ask: (event: E) => Effect.Effect<unknown, NoReplyError>;
|
|
152
|
-
getState: Effect.Effect<S, never, never>;
|
|
153
|
-
stateRef: SubscriptionRef.SubscriptionRef<S>;
|
|
154
|
-
isStopped: Effect.Effect<boolean>;
|
|
155
|
-
_queue: Queue.Queue<RuntimeQueuedEvent<E>, never>;
|
|
156
|
-
_stoppedRef: Ref.Ref<boolean>;
|
|
157
|
-
exitDeferred: Deferred.Deferred<ActorExit<S>, never>;
|
|
158
|
-
actorScope: Scope.Closeable;
|
|
159
|
-
}, never, Scope.Scope>;
|
|
160
|
-
//#endregion
|
|
161
|
-
export { ProcessQueuedResult, RuntimeCellResources, RuntimeConfig, RuntimeHandle, RuntimeLifecycleHooks, RuntimeQueuedEvent, createRuntime };
|
|
1
|
+
export {}
|