effect-machine 0.13.0 → 0.14.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 +14 -9
- package/dist/actor.d.ts +9 -6
- package/dist/actor.js +97 -43
- package/dist/cluster/entity-machine.d.ts +1 -1
- package/dist/cluster/entity-machine.js +1 -1
- package/dist/cluster/to-entity.d.ts +1 -1
- package/dist/errors.d.ts +9 -2
- package/dist/errors.js +8 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +4 -4
- package/dist/internal/runtime.d.ts +2 -2
- package/dist/internal/runtime.js +5 -10
- package/dist/internal/transition.d.ts +9 -9
- package/dist/internal/transition.js +3 -5
- package/dist/machine.d.ts +122 -135
- package/dist/machine.js +97 -112
- package/dist/schema.d.ts +14 -0
- package/dist/schema.js +9 -0
- package/dist/slot.d.ts +112 -86
- package/dist/slot.js +92 -59
- package/dist/testing.d.ts +16 -16
- package/dist/testing.js +3 -3
- package/package.json +3 -3
- package/v3/dist/actor.d.ts +19 -12
- package/v3/dist/actor.js +130 -75
- package/v3/dist/cluster/entity-machine.d.ts +1 -1
- package/v3/dist/cluster/to-entity.d.ts +1 -1
- package/v3/dist/errors.d.ts +12 -3
- package/v3/dist/errors.js +10 -4
- package/v3/dist/index.d.ts +6 -6
- package/v3/dist/index.js +2 -2
- package/v3/dist/inspection.d.ts +3 -22
- package/v3/dist/inspection.js +1 -15
- package/v3/dist/internal/brands.d.ts +4 -8
- package/v3/dist/internal/inspection.js +1 -1
- package/v3/dist/internal/runtime.d.ts +8 -8
- package/v3/dist/internal/runtime.js +45 -28
- package/v3/dist/internal/transition.d.ts +10 -10
- package/v3/dist/internal/transition.js +8 -10
- package/v3/dist/internal/utils.js +5 -1
- package/v3/dist/machine.d.ts +153 -120
- package/v3/dist/machine.js +118 -115
- package/v3/dist/schema.d.ts +25 -11
- package/v3/dist/schema.js +18 -5
- package/v3/dist/slot.d.ts +112 -86
- package/v3/dist/slot.js +92 -59
- package/v3/dist/testing.d.ts +16 -16
- package/v3/dist/testing.js +7 -7
|
@@ -3,7 +3,7 @@ import { NoReplyError } from "../errors.js";
|
|
|
3
3
|
import { processEventCore, runSpawnEffects, shouldPostpone } from "./transition.js";
|
|
4
4
|
import { ActorExit } from "../supervision.js";
|
|
5
5
|
import { ActorSystem } from "../actor.js";
|
|
6
|
-
import { Cause, Deferred, Effect, Exit, Fiber, Queue, Ref, Schema, Scope, SubscriptionRef } from "effect";
|
|
6
|
+
import { Cause, Deferred, Effect, Exit, Fiber, Queue, Ref, Runtime, Schema, Scope, SubscriptionRef } from "effect";
|
|
7
7
|
//#region src/internal/runtime.ts
|
|
8
8
|
/**
|
|
9
9
|
* Shared runtime kernel for machine event processing.
|
|
@@ -28,7 +28,7 @@ import { Cause, Deferred, Effect, Exit, Fiber, Queue, Ref, Schema, Scope, Subscr
|
|
|
28
28
|
* and querying state. The runtime owns:
|
|
29
29
|
* - Event loop fiber
|
|
30
30
|
* - Postpone buffer
|
|
31
|
-
* - Background effects
|
|
31
|
+
* - Background effects (under actorScope)
|
|
32
32
|
* - State scope (spawn effects)
|
|
33
33
|
* - Final state detection
|
|
34
34
|
* - Exit reason via exitDeferred
|
|
@@ -40,11 +40,14 @@ import { Cause, Deferred, Effect, Exit, Fiber, Queue, Ref, Schema, Scope, Subscr
|
|
|
40
40
|
*/
|
|
41
41
|
const createRuntime = Effect.fn("effect-machine.runtime.create")(function* (machine, system, config) {
|
|
42
42
|
const { actorId, hooks, lifecycle } = config;
|
|
43
|
+
const rt = yield* Effect.runtime();
|
|
44
|
+
const fork = Runtime.runFork(rt);
|
|
43
45
|
const stateRef = config.cellResources?.stateRef ?? (yield* SubscriptionRef.make(machine.initial));
|
|
44
46
|
const stoppedRef = config.cellResources?.stoppedRef ?? (yield* Ref.make(false));
|
|
45
47
|
const eventQueue = config.cellResources?.eventQueue ?? (yield* config.queueFactory ?? Queue.unbounded());
|
|
46
48
|
const exitDeferred = yield* Deferred.make();
|
|
47
49
|
const actorScope = yield* Scope.make();
|
|
50
|
+
const deferredReplyRef = { current: void 0 };
|
|
48
51
|
const selfSend = Effect.fn("effect-machine.runtime.self.send")(function* (event) {
|
|
49
52
|
if (!(yield* Ref.get(stoppedRef))) yield* Queue.offer(eventQueue, {
|
|
50
53
|
_tag: "send",
|
|
@@ -57,7 +60,16 @@ const createRuntime = Effect.fn("effect-machine.runtime.create")(function* (mach
|
|
|
57
60
|
const self = {
|
|
58
61
|
send: selfSend,
|
|
59
62
|
cast: selfSend,
|
|
60
|
-
spawn: onChildSpawned !== void 0 ? (childId, childMachine) => defaultSpawn(childId, childMachine).pipe(Effect.tap((child) => onChildSpawned(childId, child))) : defaultSpawn
|
|
63
|
+
spawn: onChildSpawned !== void 0 ? (childId, childMachine) => defaultSpawn(childId, childMachine).pipe(Effect.tap((child) => onChildSpawned(childId, child))) : defaultSpawn,
|
|
64
|
+
reply: (value) => Effect.sync(() => {
|
|
65
|
+
const deferred = deferredReplyRef.current;
|
|
66
|
+
if (deferred !== void 0) {
|
|
67
|
+
deferredReplyRef.current = void 0;
|
|
68
|
+
fork(Deferred.succeed(deferred, value));
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
})
|
|
61
73
|
};
|
|
62
74
|
const stateScopeRef = { current: yield* Scope.make() };
|
|
63
75
|
const backgroundFibers = [];
|
|
@@ -69,21 +81,21 @@ const createRuntime = Effect.fn("effect-machine.runtime.create")(function* (mach
|
|
|
69
81
|
self,
|
|
70
82
|
system
|
|
71
83
|
};
|
|
72
|
-
const
|
|
84
|
+
const slots = machine._slots;
|
|
73
85
|
for (const bg of machine.backgroundEffects) {
|
|
74
|
-
const fiber = yield*
|
|
86
|
+
const fiber = yield* bg.handler({
|
|
75
87
|
actorId,
|
|
76
88
|
state: machine.initial,
|
|
77
89
|
event: initEvent,
|
|
78
90
|
self,
|
|
79
|
-
|
|
91
|
+
slots,
|
|
80
92
|
system
|
|
81
|
-
}).pipe(Effect.provideService(machine.Context, ctx)));
|
|
93
|
+
}).pipe(Effect.provideService(machine.Context, ctx), Effect.forkIn(actorScope));
|
|
82
94
|
backgroundFibers.push(fiber);
|
|
83
95
|
}
|
|
84
96
|
if (lifecycle?.onInitialSpawnEffects !== void 0) yield* lifecycle.onInitialSpawnEffects(machine.initial);
|
|
85
97
|
const loopFiberRef = { current: void 0 };
|
|
86
|
-
const initialSpawnDefectSignal = (cause) => Deferred.succeed(exitDeferred, ActorExit.Defect(cause, "initial-spawn")).pipe(Effect.
|
|
98
|
+
const initialSpawnDefectSignal = (cause) => Deferred.succeed(exitDeferred, ActorExit.Defect(cause, "initial-spawn")).pipe(Effect.andThen(Ref.set(stoppedRef, true)), Effect.andThen(Effect.suspend(() => loopFiberRef.current !== void 0 ? Fiber.interrupt(loopFiberRef.current) : Effect.void)), Effect.asVoid);
|
|
87
99
|
yield* runSpawnEffects(machine, machine.initial, initEvent, self, stateScopeRef.current, system, actorId, hooks?.onError, initialSpawnDefectSignal).pipe(Effect.catchAllCause((cause) => {
|
|
88
100
|
return Effect.gen(function* () {
|
|
89
101
|
yield* Ref.set(stoppedRef, true);
|
|
@@ -100,20 +112,24 @@ const createRuntime = Effect.fn("effect-machine.runtime.create")(function* (mach
|
|
|
100
112
|
yield* Ref.set(stoppedRef, true);
|
|
101
113
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
102
114
|
yield* Scope.close(actorScope, Exit.void);
|
|
103
|
-
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
104
115
|
yield* setExit(ActorExit.Final(machine.initial));
|
|
105
116
|
return makeHandle(stateRef, stoppedRef, eventQueue, exitDeferred, actorScope);
|
|
106
117
|
}
|
|
107
118
|
const augmentedHooks = {
|
|
108
119
|
...hooks,
|
|
109
|
-
onSpawnDefect: (cause) => Deferred.succeed(exitDeferred, ActorExit.Defect(cause, "spawn")).pipe(Effect.
|
|
120
|
+
onSpawnDefect: (cause) => Deferred.succeed(exitDeferred, ActorExit.Defect(cause, "spawn")).pipe(Effect.andThen(Ref.set(stoppedRef, true)), Effect.andThen(Effect.suspend(() => loopFiberRef.current !== void 0 ? Fiber.interrupt(loopFiberRef.current) : Effect.void)), Effect.asVoid)
|
|
110
121
|
};
|
|
111
|
-
const loopFiber = yield* Effect.forkDaemon(runtimeEventLoop(machine, stateRef, eventQueue, stoppedRef, self, stateScopeRef, actorId, system, exitDeferred, augmentedHooks, lifecycle, config.wrapProcess));
|
|
122
|
+
const loopFiber = yield* Effect.forkDaemon(runtimeEventLoop(machine, stateRef, eventQueue, stoppedRef, self, stateScopeRef, actorId, system, exitDeferred, augmentedHooks, deferredReplyRef, lifecycle, config.wrapProcess, fork));
|
|
112
123
|
loopFiberRef.current = loopFiber;
|
|
113
|
-
if (backgroundFibers.length > 0) yield* Effect.
|
|
114
|
-
if (exit._tag === "Failure" && !Cause.isInterruptedOnly(exit.cause)) return setExit(ActorExit.Defect(exit.cause, "background")).pipe(Effect.
|
|
124
|
+
if (backgroundFibers.length > 0) yield* Effect.raceAll(backgroundFibers.map((fiber) => Fiber.await(fiber).pipe(Effect.flatMap((exit) => {
|
|
125
|
+
if (exit._tag === "Failure" && !Cause.isInterruptedOnly(exit.cause)) return setExit(ActorExit.Defect(exit.cause, "background")).pipe(Effect.andThen(Ref.set(stoppedRef, true)), Effect.andThen(Fiber.interrupt(loopFiber)));
|
|
115
126
|
return Effect.never;
|
|
116
|
-
})))).pipe(Effect.
|
|
127
|
+
})))).pipe(Effect.forkIn(actorScope));
|
|
128
|
+
yield* Effect.forkDaemon(Effect.gen(function* () {
|
|
129
|
+
const loopExit = yield* Fiber.await(loopFiber);
|
|
130
|
+
if (loopExit._tag === "Success") yield* Scope.close(actorScope, Exit.void);
|
|
131
|
+
else yield* Scope.close(actorScope, loopExit);
|
|
132
|
+
}));
|
|
117
133
|
const stop = Effect.gen(function* () {
|
|
118
134
|
if (yield* Ref.get(stoppedRef)) return;
|
|
119
135
|
if (lifecycle?.onShutdown !== void 0) yield* lifecycle.onShutdown();
|
|
@@ -121,7 +137,6 @@ const createRuntime = Effect.fn("effect-machine.runtime.create")(function* (mach
|
|
|
121
137
|
yield* Fiber.interrupt(loopFiber);
|
|
122
138
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
123
139
|
yield* Scope.close(actorScope, Exit.void);
|
|
124
|
-
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
125
140
|
yield* setExit(ActorExit.Stopped);
|
|
126
141
|
}).pipe(Effect.asVoid);
|
|
127
142
|
if (config.skipFinalizer !== true) yield* Effect.addFinalizer(() => stop);
|
|
@@ -174,7 +189,8 @@ const makeHandle = (stateRef, stoppedRef, eventQueue, exitDeferred, actorScope)
|
|
|
174
189
|
exitDeferred,
|
|
175
190
|
actorScope
|
|
176
191
|
});
|
|
177
|
-
const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function* (machine, stateRef, eventQueue, stoppedRef, self, stateScopeRef, actorId, system, exitDeferred, hooks, lifecycle, wrapProcess) {
|
|
192
|
+
const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function* (machine, stateRef, eventQueue, stoppedRef, self, stateScopeRef, actorId, system, exitDeferred, hooks, deferredReplyRef, lifecycle, wrapProcess, fork) {
|
|
193
|
+
const forkEffect = fork ?? Effect.runFork;
|
|
178
194
|
/** Set the exit deferred exactly once. */
|
|
179
195
|
const setExit = (exit) => Deferred.succeed(exitDeferred, exit).pipe(Effect.asVoid);
|
|
180
196
|
const postponed = [];
|
|
@@ -242,7 +258,8 @@ const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function*
|
|
|
242
258
|
}
|
|
243
259
|
yield* Deferred.succeed(queued.reply, decoded);
|
|
244
260
|
} else yield* Deferred.succeed(queued.reply, result.reply);
|
|
245
|
-
} else
|
|
261
|
+
} else if (result.deferReply && deferredReplyRef !== void 0) deferredReplyRef.current = queued.reply;
|
|
262
|
+
else yield* Deferred.fail(queued.reply, new NoReplyError({
|
|
246
263
|
actorId,
|
|
247
264
|
eventTag: event._tag
|
|
248
265
|
}));
|
|
@@ -260,16 +277,16 @@ const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function*
|
|
|
260
277
|
const shutdown = (exitReason) => Effect.gen(function* () {
|
|
261
278
|
yield* Ref.set(stoppedRef, true);
|
|
262
279
|
if (lifecycle?.onShutdown !== void 0) yield* lifecycle.onShutdown();
|
|
263
|
-
settlePostponed(postponed, actorId);
|
|
280
|
+
settlePostponed(postponed, actorId, forkEffect);
|
|
264
281
|
const remaining = yield* Queue.takeAll(eventQueue);
|
|
265
|
-
for (const entry of remaining) if (entry._tag === "sendWait")
|
|
266
|
-
else if (entry._tag === "ask")
|
|
282
|
+
for (const entry of remaining) if (entry._tag === "sendWait") forkEffect(Deferred.succeed(entry.done, void 0));
|
|
283
|
+
else if (entry._tag === "ask") forkEffect(Deferred.fail(entry.reply, new NoReplyError({
|
|
267
284
|
actorId,
|
|
268
285
|
eventTag: entry.event._tag
|
|
269
286
|
})));
|
|
270
287
|
else if (entry._tag === "call") {
|
|
271
288
|
const currentState = yield* SubscriptionRef.get(stateRef);
|
|
272
|
-
|
|
289
|
+
forkEffect(Deferred.succeed(entry.reply, {
|
|
273
290
|
newState: currentState,
|
|
274
291
|
previousState: currentState,
|
|
275
292
|
transitioned: false,
|
|
@@ -296,10 +313,10 @@ const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function*
|
|
|
296
313
|
const { shouldStop, stateChanged } = yield* (wrapProcess !== void 0 ? Effect.gen(function* () {
|
|
297
314
|
return yield* wrapProcess(yield* SubscriptionRef.get(stateRef), eventQueued.event, processInner);
|
|
298
315
|
}) : processInner).pipe(Effect.catchAllCause((cause) => {
|
|
299
|
-
if (queued._tag === "sendWait")
|
|
300
|
-
else if (queued._tag === "ask")
|
|
301
|
-
else if (queued._tag === "call")
|
|
302
|
-
return shutdown(ActorExit.Defect(cause, "transition")).pipe(Effect.
|
|
316
|
+
if (queued._tag === "sendWait") forkEffect(Deferred.failCause(queued.done, cause));
|
|
317
|
+
else if (queued._tag === "ask") forkEffect(Deferred.die(queued.reply, cause));
|
|
318
|
+
else if (queued._tag === "call") forkEffect(Deferred.failCause(queued.reply, cause));
|
|
319
|
+
return shutdown(ActorExit.Defect(cause, "transition")).pipe(Effect.andThen(Effect.failCause(cause)));
|
|
303
320
|
}));
|
|
304
321
|
if (shouldStop) {
|
|
305
322
|
const finalState = yield* SubscriptionRef.get(stateRef);
|
|
@@ -323,12 +340,12 @@ const runtimeEventLoop = Effect.fn("effect-machine.runtime.eventLoop")(function*
|
|
|
323
340
|
}
|
|
324
341
|
});
|
|
325
342
|
/** Settle all pending Deferreds in the postpone buffer on shutdown. */
|
|
326
|
-
const settlePostponed = (postponed, actorId) => {
|
|
327
|
-
for (const entry of postponed) if (entry._tag === "ask")
|
|
343
|
+
const settlePostponed = (postponed, actorId, forkFn) => {
|
|
344
|
+
for (const entry of postponed) if (entry._tag === "ask") forkFn(Deferred.fail(entry.reply, new NoReplyError({
|
|
328
345
|
actorId,
|
|
329
346
|
eventTag: entry.event._tag
|
|
330
347
|
})));
|
|
331
|
-
else if (entry._tag === "sendWait")
|
|
348
|
+
else if (entry._tag === "sendWait") forkFn(Deferred.succeed(entry.done, void 0));
|
|
332
349
|
postponed.length = 0;
|
|
333
350
|
};
|
|
334
351
|
//#endregion
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MachineContext, SlotsDef } from "../slot.js";
|
|
2
2
|
import { Machine, MachineRef, SpawnEffect, Transition } from "../machine.js";
|
|
3
3
|
import { ActorSystem } from "../actor.js";
|
|
4
4
|
import { Cause, Effect, Scope } from "effect";
|
|
@@ -21,7 +21,7 @@ interface TransitionExecutionResult<S> {
|
|
|
21
21
|
*
|
|
22
22
|
* Used by:
|
|
23
23
|
* - executeTransition (actor event loop, testing)
|
|
24
|
-
* -
|
|
24
|
+
* - Machine.replay (event sourcing restore)
|
|
25
25
|
*
|
|
26
26
|
* @internal
|
|
27
27
|
*/
|
|
@@ -29,7 +29,7 @@ declare const runTransitionHandler: <S extends {
|
|
|
29
29
|
readonly _tag: string;
|
|
30
30
|
}, E extends {
|
|
31
31
|
readonly _tag: string;
|
|
32
|
-
}, R,
|
|
32
|
+
}, R, SD extends SlotsDef>(machine: Machine<S, E, R, any, any, SD>, transition: Transition<S, E, SD, R>, state: S, event: E, self: MachineRef<E>, system: ActorSystem, actorId: string) => Effect.Effect<{
|
|
33
33
|
newState: S;
|
|
34
34
|
hasReply: boolean;
|
|
35
35
|
deferReply: boolean;
|
|
@@ -50,7 +50,7 @@ declare const executeTransition: <S extends {
|
|
|
50
50
|
readonly _tag: string;
|
|
51
51
|
}, E extends {
|
|
52
52
|
readonly _tag: string;
|
|
53
|
-
}, R,
|
|
53
|
+
}, R, SD extends SlotsDef>(machine: Machine<S, E, R, any, any, SD>, currentState: S, event: E, self: MachineRef<E>, system: ActorSystem, actorId: string) => Effect.Effect<{
|
|
54
54
|
newState: S;
|
|
55
55
|
transitioned: boolean;
|
|
56
56
|
reenter: boolean;
|
|
@@ -111,7 +111,7 @@ declare const shouldPostpone: <S extends {
|
|
|
111
111
|
readonly _tag: string;
|
|
112
112
|
}, E extends {
|
|
113
113
|
readonly _tag: string;
|
|
114
|
-
}, R>(machine: Machine<S, E, R, any, any, any
|
|
114
|
+
}, R>(machine: Machine<S, E, R, any, any, any>, stateTag: string, eventTag: string) => boolean;
|
|
115
115
|
/**
|
|
116
116
|
* Process a single event through the machine.
|
|
117
117
|
*
|
|
@@ -128,7 +128,7 @@ declare const processEventCore: <S extends {
|
|
|
128
128
|
readonly _tag: string;
|
|
129
129
|
}, E extends {
|
|
130
130
|
readonly _tag: string;
|
|
131
|
-
}, R,
|
|
131
|
+
}, R, SD extends SlotsDef>(machine: Machine<S, E, R, any, any, SD>, currentState: S, event: E, self: MachineRef<E>, stateScopeRef: {
|
|
132
132
|
current: Scope.CloseableScope;
|
|
133
133
|
}, system: ActorSystem, actorId: string, hooks?: ProcessEventHooks<S, E> | undefined) => Effect.Effect<{
|
|
134
134
|
newState: S;
|
|
@@ -150,7 +150,7 @@ declare const runSpawnEffects: <S extends {
|
|
|
150
150
|
readonly _tag: string;
|
|
151
151
|
}, E extends {
|
|
152
152
|
readonly _tag: string;
|
|
153
|
-
}, R,
|
|
153
|
+
}, R, SD extends SlotsDef>(machine: Machine<S, E, R, any, any, SD>, state: S, event: E, self: MachineRef<E>, stateScope: Scope.CloseableScope, system: ActorSystem, actorId: string, onError?: ((info: ProcessEventError<S, E>) => Effect.Effect<void>) | undefined, onSpawnDefect?: ((cause: Cause.Cause<unknown>) => Effect.Effect<void>) | undefined) => Effect.Effect<void, never, Exclude<Exclude<R, MachineContext<S, E, MachineRef<E>>>, Scope.Scope>>;
|
|
154
154
|
/**
|
|
155
155
|
* Resolve which transition should fire for a given state and event.
|
|
156
156
|
* Uses indexed O(1) lookup. First matching transition wins.
|
|
@@ -159,7 +159,7 @@ declare const resolveTransition: <S extends {
|
|
|
159
159
|
readonly _tag: string;
|
|
160
160
|
}, E extends {
|
|
161
161
|
readonly _tag: string;
|
|
162
|
-
}, R>(machine: Machine<S, E, R, any, any, any
|
|
162
|
+
}, R>(machine: Machine<S, E, R, any, any, any>, currentState: S, event: E) => (typeof machine.transitions)[number] | undefined;
|
|
163
163
|
/**
|
|
164
164
|
* Invalidate cached index for a machine (call after mutation).
|
|
165
165
|
*/
|
|
@@ -174,7 +174,7 @@ declare const findTransitions: <S extends {
|
|
|
174
174
|
readonly _tag: string;
|
|
175
175
|
}, E extends {
|
|
176
176
|
readonly _tag: string;
|
|
177
|
-
}, R,
|
|
177
|
+
}, R, SD extends SlotsDef = Record<string, never>>(machine: Machine<S, E, R, any, any, SD>, stateTag: string, eventTag: string) => ReadonlyArray<Transition<S, E, SD, R>>;
|
|
178
178
|
/**
|
|
179
179
|
* Find all spawn effects for a state.
|
|
180
180
|
* Returns empty array if no matches.
|
|
@@ -185,6 +185,6 @@ declare const findSpawnEffects: <S extends {
|
|
|
185
185
|
readonly _tag: string;
|
|
186
186
|
}, E extends {
|
|
187
187
|
readonly _tag: string;
|
|
188
|
-
}, R,
|
|
188
|
+
}, R, SD extends SlotsDef = Record<string, never>>(machine: Machine<S, E, R, any, any, SD>, stateTag: string) => ReadonlyArray<SpawnEffect<S, E, SD, R>>;
|
|
189
189
|
//#endregion
|
|
190
190
|
export { ProcessEventError, ProcessEventHooks, ProcessEventResult, TransitionExecutionResult, executeTransition, findSpawnEffects, findTransitions, invalidateIndex, processEventCore, resolveTransition, runSpawnEffects, runTransitionHandler, shouldPostpone };
|
|
@@ -17,7 +17,7 @@ import { Cause, Effect, Exit, Scope } from "effect";
|
|
|
17
17
|
*
|
|
18
18
|
* Used by:
|
|
19
19
|
* - executeTransition (actor event loop, testing)
|
|
20
|
-
* -
|
|
20
|
+
* - Machine.replay (event sourcing restore)
|
|
21
21
|
*
|
|
22
22
|
* @internal
|
|
23
23
|
*/
|
|
@@ -29,12 +29,10 @@ const runTransitionHandler = Effect.fn("effect-machine.runTransitionHandler")(fu
|
|
|
29
29
|
self,
|
|
30
30
|
system
|
|
31
31
|
};
|
|
32
|
-
const { guards, effects } = machine._slots;
|
|
33
32
|
const handlerCtx = {
|
|
34
33
|
state,
|
|
35
34
|
event,
|
|
36
|
-
|
|
37
|
-
effects
|
|
35
|
+
slots: machine._slots
|
|
38
36
|
};
|
|
39
37
|
const raw = transition.handler(handlerCtx);
|
|
40
38
|
const resolved = isEffect(raw) ? yield* raw.pipe(Effect.provideService(machine.Context, ctx)) : raw;
|
|
@@ -118,7 +116,7 @@ const processEventCore = Effect.fn("effect-machine.processEventCore")(function*
|
|
|
118
116
|
state: currentState,
|
|
119
117
|
event,
|
|
120
118
|
cause
|
|
121
|
-
}).pipe(Effect.
|
|
119
|
+
}).pipe(Effect.andThen(Effect.failCause(cause).pipe(Effect.orDie)));
|
|
122
120
|
}));
|
|
123
121
|
if (!result.transitioned) return {
|
|
124
122
|
newState: currentState,
|
|
@@ -166,7 +164,7 @@ const runSpawnEffects = Effect.fn("effect-machine.runSpawnEffects")(function* (m
|
|
|
166
164
|
self,
|
|
167
165
|
system
|
|
168
166
|
};
|
|
169
|
-
const
|
|
167
|
+
const slots = machine._slots;
|
|
170
168
|
const reportError = onError;
|
|
171
169
|
const defectSignal = onSpawnDefect;
|
|
172
170
|
for (const spawnEffect of spawnEffects) {
|
|
@@ -175,7 +173,7 @@ const runSpawnEffects = Effect.fn("effect-machine.runSpawnEffects")(function* (m
|
|
|
175
173
|
state,
|
|
176
174
|
event,
|
|
177
175
|
self,
|
|
178
|
-
|
|
176
|
+
slots,
|
|
179
177
|
system
|
|
180
178
|
}).pipe(Effect.provideService(machine.Context, ctx), Effect.catchAllCause((cause) => {
|
|
181
179
|
if (Cause.isInterruptedOnly(cause)) return Effect.interrupt;
|
|
@@ -186,7 +184,7 @@ const runSpawnEffects = Effect.fn("effect-machine.runSpawnEffects")(function* (m
|
|
|
186
184
|
cause
|
|
187
185
|
}) : Effect.void;
|
|
188
186
|
const signal = defectSignal !== void 0 ? defectSignal(cause) : Effect.void;
|
|
189
|
-
return report.pipe(Effect.
|
|
187
|
+
return report.pipe(Effect.andThen(signal), Effect.andThen(Effect.failCause(cause).pipe(Effect.orDie)));
|
|
190
188
|
}));
|
|
191
189
|
yield* Effect.forkScoped(effect).pipe(Effect.provideService(Scope.Scope, stateScope));
|
|
192
190
|
}
|
|
@@ -261,8 +259,8 @@ const getIndex = (machine) => {
|
|
|
261
259
|
*
|
|
262
260
|
* O(1) lookup after first access (index is lazily built).
|
|
263
261
|
*/
|
|
264
|
-
const findTransitions = (
|
|
265
|
-
const index = getIndex(
|
|
262
|
+
const findTransitions = (machine, stateTag, eventTag) => {
|
|
263
|
+
const index = getIndex(machine);
|
|
266
264
|
const specific = index.transitions.get(stateTag)?.get(eventTag) ?? [];
|
|
267
265
|
if (specific.length > 0) return specific;
|
|
268
266
|
return index.transitions.get("*")?.get(eventTag) ?? [];
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { Effect, Stream } from "effect";
|
|
2
2
|
//#region src/internal/utils.ts
|
|
3
|
+
/**
|
|
4
|
+
* Internal utilities for effect-machine.
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
3
7
|
const ReplyResultSymbol = Symbol.for("effect-machine/ReplyResult");
|
|
4
8
|
/**
|
|
5
9
|
* Create a reply result for ask-bearing event handlers.
|
|
@@ -50,7 +54,7 @@ const getTag = (constructorOrValue) => {
|
|
|
50
54
|
}
|
|
51
55
|
};
|
|
52
56
|
/** Check if a value is an Effect */
|
|
53
|
-
const isEffect =
|
|
57
|
+
const isEffect = Effect.isEffect;
|
|
54
58
|
/**
|
|
55
59
|
* Stub ActorSystem that dies on any method call.
|
|
56
60
|
* Used in contexts where spawning/system access isn't supported
|