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
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Inspector } from "../inspection.js";
|
|
2
2
|
import { INTERNAL_INIT_EVENT, stubSystem } from "../internal/utils.js";
|
|
3
|
-
import {
|
|
3
|
+
import { NoReplyError } from "../errors.js";
|
|
4
4
|
import { emitWithTimestamp } from "../internal/inspection.js";
|
|
5
|
+
import { processEventCore, resolveTransition, runSpawnEffects, runTransitionHandler, shouldPostpone } from "../internal/transition.js";
|
|
5
6
|
import { PersistenceAdapterTag } from "./adapter.js";
|
|
6
|
-
import { ActorSystem, buildActorRefCore, notifyListeners } from "../actor.js";
|
|
7
|
-
import { Cause, Clock, Effect, Exit, Fiber, Option, Queue, Ref, Schedule, Scope, SubscriptionRef } from "effect";
|
|
8
|
-
|
|
9
|
-
//#region src-v3/persistence/persistent-actor.ts
|
|
7
|
+
import { ActorSystem, buildActorRefCore, notifyListeners, settlePendingReplies } from "../actor.js";
|
|
8
|
+
import { Cause, Clock, Deferred, Effect, Exit, Fiber, Option, Queue, Ref, Schedule, Scope, SubscriptionRef } from "effect";
|
|
9
|
+
//#region src/persistence/persistent-actor.ts
|
|
10
10
|
/** Get current time in milliseconds using Effect Clock */
|
|
11
11
|
const now = Clock.currentTimeMillis;
|
|
12
12
|
/**
|
|
@@ -20,7 +20,7 @@ const replayEvents = Effect.fn("effect-machine.persistentActor.replayEvents")(fu
|
|
|
20
20
|
for (const persistedEvent of events) {
|
|
21
21
|
if (stopVersion !== void 0 && persistedEvent.version > stopVersion) break;
|
|
22
22
|
const transition = resolveTransition(machine, state, persistedEvent.event);
|
|
23
|
-
if (transition !== void 0) state = yield* runTransitionHandler(machine, transition, state, persistedEvent.event, self, stubSystem);
|
|
23
|
+
if (transition !== void 0) state = (yield* runTransitionHandler(machine, transition, state, persistedEvent.event, self, stubSystem, "restore")).newState;
|
|
24
24
|
version = persistedEvent.version;
|
|
25
25
|
}
|
|
26
26
|
return {
|
|
@@ -31,7 +31,7 @@ const replayEvents = Effect.fn("effect-machine.persistentActor.replayEvents")(fu
|
|
|
31
31
|
/**
|
|
32
32
|
* Build PersistentActorRef with all methods
|
|
33
33
|
*/
|
|
34
|
-
const buildPersistentActorRef = (id, persistentMachine, stateRef, versionRef, eventQueue, stoppedRef, listeners, stop, adapter, system, childrenMap) => {
|
|
34
|
+
const buildPersistentActorRef = (id, persistentMachine, stateRef, versionRef, eventQueue, stoppedRef, listeners, stop, adapter, system, childrenMap, pendingReplies) => {
|
|
35
35
|
const { machine, persistence } = persistentMachine;
|
|
36
36
|
const typedMachine = machine;
|
|
37
37
|
const persist = Effect.gen(function* () {
|
|
@@ -45,8 +45,10 @@ const buildPersistentActorRef = (id, persistentMachine, stateRef, versionRef, ev
|
|
|
45
45
|
const version = Ref.get(versionRef).pipe(Effect.withSpan("effect-machine.persistentActor.version"));
|
|
46
46
|
const replayTo = Effect.fn("effect-machine.persistentActor.replayTo")(function* (targetVersion) {
|
|
47
47
|
if (targetVersion <= (yield* Ref.get(versionRef))) {
|
|
48
|
+
const dummySend = Effect.fn("effect-machine.persistentActor.replay.send")((_event) => Effect.void);
|
|
48
49
|
const dummySelf = {
|
|
49
|
-
send:
|
|
50
|
+
send: dummySend,
|
|
51
|
+
cast: dummySend,
|
|
50
52
|
spawn: () => Effect.die("spawn not supported in replay")
|
|
51
53
|
};
|
|
52
54
|
const maybeSnapshot = yield* adapter.loadSnapshot(id, persistence.stateSchema);
|
|
@@ -71,7 +73,7 @@ const buildPersistentActorRef = (id, persistentMachine, stateRef, versionRef, ev
|
|
|
71
73
|
}
|
|
72
74
|
});
|
|
73
75
|
return {
|
|
74
|
-
...buildActorRefCore(id, typedMachine, stateRef, eventQueue, stoppedRef, listeners, stop, system, childrenMap),
|
|
76
|
+
...buildActorRefCore(id, typedMachine, stateRef, eventQueue, stoppedRef, listeners, stop, system, childrenMap, pendingReplies),
|
|
75
77
|
persist,
|
|
76
78
|
version,
|
|
77
79
|
replayTo
|
|
@@ -93,11 +95,16 @@ const createPersistentActor = Effect.fn("effect-machine.persistentActor.spawn")(
|
|
|
93
95
|
const eventQueue = yield* Queue.unbounded();
|
|
94
96
|
const stoppedRef = yield* Ref.make(false);
|
|
95
97
|
const childrenMap = /* @__PURE__ */ new Map();
|
|
98
|
+
const selfSend = Effect.fn("effect-machine.persistentActor.self.send")(function* (event) {
|
|
99
|
+
if (yield* Ref.get(stoppedRef)) return;
|
|
100
|
+
yield* Queue.offer(eventQueue, {
|
|
101
|
+
_tag: "send",
|
|
102
|
+
event
|
|
103
|
+
});
|
|
104
|
+
});
|
|
96
105
|
const self = {
|
|
97
|
-
send:
|
|
98
|
-
|
|
99
|
-
yield* Queue.offer(eventQueue, event);
|
|
100
|
-
}),
|
|
106
|
+
send: selfSend,
|
|
107
|
+
cast: selfSend,
|
|
101
108
|
spawn: (childId, childMachine) => Effect.gen(function* () {
|
|
102
109
|
const child = yield* system.spawn(childId, childMachine).pipe(Effect.provideService(ActorSystem, system));
|
|
103
110
|
childrenMap.set(childId, child);
|
|
@@ -146,6 +153,7 @@ const createPersistentActor = Effect.fn("effect-machine.persistentActor.spawn")(
|
|
|
146
153
|
const backgroundFibers = [];
|
|
147
154
|
const initEvent = { _tag: INTERNAL_INIT_EVENT };
|
|
148
155
|
const initCtx = {
|
|
156
|
+
actorId: id,
|
|
149
157
|
state: resolvedInitial,
|
|
150
158
|
event: initEvent,
|
|
151
159
|
self,
|
|
@@ -154,6 +162,7 @@ const createPersistentActor = Effect.fn("effect-machine.persistentActor.spawn")(
|
|
|
154
162
|
const { effects: effectSlots } = typedMachine._slots;
|
|
155
163
|
for (const bg of typedMachine.backgroundEffects) {
|
|
156
164
|
const fiber = yield* Effect.forkDaemon(bg.handler({
|
|
165
|
+
actorId: id,
|
|
157
166
|
state: resolvedInitial,
|
|
158
167
|
event: initEvent,
|
|
159
168
|
self,
|
|
@@ -176,9 +185,10 @@ const createPersistentActor = Effect.fn("effect-machine.persistentActor.spawn")(
|
|
|
176
185
|
finalState: resolvedInitial,
|
|
177
186
|
timestamp
|
|
178
187
|
}));
|
|
179
|
-
return buildPersistentActorRef(id, persistentMachine, stateRef, versionRef, eventQueue, stoppedRef, listeners, Ref.set(stoppedRef, true).pipe(Effect.withSpan("effect-machine.persistentActor.stop"), Effect.asVoid), adapter, system, childrenMap);
|
|
188
|
+
return buildPersistentActorRef(id, persistentMachine, stateRef, versionRef, eventQueue, stoppedRef, listeners, Ref.set(stoppedRef, true).pipe(Effect.withSpan("effect-machine.persistentActor.stop"), Effect.asVoid), adapter, system, childrenMap, /* @__PURE__ */ new Set());
|
|
180
189
|
}
|
|
181
|
-
const
|
|
190
|
+
const pendingReplies = /* @__PURE__ */ new Set();
|
|
191
|
+
const loopFiber = yield* Effect.forkDaemon(persistentEventLoop(id, persistentMachine, stateRef, versionRef, eventQueue, stoppedRef, self, listeners, adapter, createdAt, stateScopeRef, backgroundFibers, snapshotQueue, snapshotEnabledRef, persistenceQueue, snapshotFiber, persistenceFiber, inspector, system, pendingReplies));
|
|
182
192
|
return buildPersistentActorRef(id, persistentMachine, stateRef, versionRef, eventQueue, stoppedRef, listeners, Effect.gen(function* () {
|
|
183
193
|
const finalState = yield* SubscriptionRef.get(stateRef);
|
|
184
194
|
yield* emitWithTimestamp(inspector, (timestamp) => ({
|
|
@@ -189,16 +199,17 @@ const createPersistentActor = Effect.fn("effect-machine.persistentActor.spawn")(
|
|
|
189
199
|
}));
|
|
190
200
|
yield* Ref.set(stoppedRef, true);
|
|
191
201
|
yield* Fiber.interrupt(loopFiber);
|
|
202
|
+
yield* settlePendingReplies(pendingReplies, id);
|
|
192
203
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
193
204
|
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
194
205
|
yield* Fiber.interrupt(snapshotFiber);
|
|
195
206
|
yield* Fiber.interrupt(persistenceFiber);
|
|
196
|
-
}).pipe(Effect.withSpan("effect-machine.persistentActor.stop"), Effect.asVoid), adapter, system, childrenMap);
|
|
207
|
+
}).pipe(Effect.withSpan("effect-machine.persistentActor.stop"), Effect.asVoid), adapter, system, childrenMap, pendingReplies);
|
|
197
208
|
});
|
|
198
209
|
/**
|
|
199
210
|
* Main event loop for persistent actor
|
|
200
211
|
*/
|
|
201
|
-
const persistentEventLoop = Effect.fn("effect-machine.persistentActor.eventLoop")(function* (id, persistentMachine, stateRef, versionRef, eventQueue, stoppedRef, self, listeners, adapter, createdAt, stateScopeRef, backgroundFibers, snapshotQueue, snapshotEnabledRef, persistenceQueue, snapshotFiber, persistenceFiber, inspector, system) {
|
|
212
|
+
const persistentEventLoop = Effect.fn("effect-machine.persistentActor.eventLoop")(function* (id, persistentMachine, stateRef, versionRef, eventQueue, stoppedRef, self, listeners, adapter, createdAt, stateScopeRef, backgroundFibers, snapshotQueue, snapshotEnabledRef, persistenceQueue, snapshotFiber, persistenceFiber, inspector, system, pendingReplies) {
|
|
202
213
|
const { machine, persistence } = persistentMachine;
|
|
203
214
|
const typedMachine = machine;
|
|
204
215
|
const hooks = inspector === void 0 ? void 0 : {
|
|
@@ -227,10 +238,28 @@ const persistentEventLoop = Effect.fn("effect-machine.persistentActor.eventLoop"
|
|
|
227
238
|
timestamp
|
|
228
239
|
}))
|
|
229
240
|
};
|
|
241
|
+
const postponed = [];
|
|
242
|
+
const pendingDrain = [];
|
|
243
|
+
const hasPostponeRules = machine.postponeRules.length > 0;
|
|
230
244
|
while (true) {
|
|
231
|
-
const
|
|
245
|
+
const queued = pendingDrain.length > 0 ? pendingDrain.shift() : yield* Queue.take(eventQueue);
|
|
246
|
+
const event = queued.event;
|
|
232
247
|
const currentState = yield* SubscriptionRef.get(stateRef);
|
|
233
248
|
const currentVersion = yield* Ref.get(versionRef);
|
|
249
|
+
if (hasPostponeRules && shouldPostpone(typedMachine, currentState._tag, event._tag)) {
|
|
250
|
+
postponed.push(queued);
|
|
251
|
+
if (queued._tag === "call") yield* Deferred.succeed(queued.reply, {
|
|
252
|
+
newState: currentState,
|
|
253
|
+
previousState: currentState,
|
|
254
|
+
transitioned: false,
|
|
255
|
+
lifecycleRan: false,
|
|
256
|
+
isFinal: false,
|
|
257
|
+
hasReply: false,
|
|
258
|
+
reply: void 0,
|
|
259
|
+
postponed: true
|
|
260
|
+
});
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
234
263
|
yield* emitWithTimestamp(inspector, (timestamp) => ({
|
|
235
264
|
type: "@machine.event",
|
|
236
265
|
actorId: id,
|
|
@@ -238,7 +267,13 @@ const persistentEventLoop = Effect.fn("effect-machine.persistentActor.eventLoop"
|
|
|
238
267
|
event,
|
|
239
268
|
timestamp
|
|
240
269
|
}));
|
|
241
|
-
const result = yield* processEventCore(typedMachine, currentState, event, self, stateScopeRef, system, hooks);
|
|
270
|
+
const result = yield* processEventCore(typedMachine, currentState, event, self, stateScopeRef, system, id, hooks);
|
|
271
|
+
if (queued._tag === "call") yield* Deferred.succeed(queued.reply, result);
|
|
272
|
+
else if (queued._tag === "ask") if (result.hasReply) yield* Deferred.succeed(queued.reply, result.reply);
|
|
273
|
+
else yield* Deferred.fail(queued.reply, new NoReplyError({
|
|
274
|
+
actorId: id,
|
|
275
|
+
eventTag: event._tag
|
|
276
|
+
}));
|
|
242
277
|
if (!result.transitioned) continue;
|
|
243
278
|
const newVersion = currentVersion + 1;
|
|
244
279
|
yield* Ref.set(versionRef, newVersion);
|
|
@@ -266,12 +301,15 @@ const persistentEventLoop = Effect.fn("effect-machine.persistentActor.eventLoop"
|
|
|
266
301
|
timestamp
|
|
267
302
|
}));
|
|
268
303
|
yield* Ref.set(stoppedRef, true);
|
|
304
|
+
postponed.length = 0;
|
|
305
|
+
yield* settlePendingReplies(pendingReplies, id);
|
|
269
306
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
270
307
|
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
271
308
|
yield* Fiber.interrupt(snapshotFiber);
|
|
272
309
|
yield* Fiber.interrupt(persistenceFiber);
|
|
273
310
|
return;
|
|
274
311
|
}
|
|
312
|
+
if (result.lifecycleRan && postponed.length > 0) pendingDrain.push(...postponed.splice(0));
|
|
275
313
|
}
|
|
276
314
|
});
|
|
277
315
|
/**
|
|
@@ -286,7 +324,7 @@ const runSpawnEffectsWithInspection = Effect.fn("effect-machine.persistentActor.
|
|
|
286
324
|
state,
|
|
287
325
|
timestamp
|
|
288
326
|
}));
|
|
289
|
-
yield* runSpawnEffects(machine, state, event, self, stateScope, system, inspector === void 0 ? void 0 : (info) => emitWithTimestamp(inspector, (timestamp) => ({
|
|
327
|
+
yield* runSpawnEffects(machine, state, event, self, stateScope, system, actorId, inspector === void 0 ? void 0 : (info) => emitWithTimestamp(inspector, (timestamp) => ({
|
|
290
328
|
type: "@machine.error",
|
|
291
329
|
actorId,
|
|
292
330
|
phase: info.phase,
|
|
@@ -362,6 +400,5 @@ const restorePersistentActor = Effect.fn("effect-machine.persistentActor.restore
|
|
|
362
400
|
const actor = yield* createPersistentActor(id, persistentMachine, maybeSnapshot, events);
|
|
363
401
|
return Option.some(actor);
|
|
364
402
|
});
|
|
365
|
-
|
|
366
403
|
//#endregion
|
|
367
|
-
export { createPersistentActor, restorePersistentActor };
|
|
404
|
+
export { createPersistentActor, restorePersistentActor };
|
|
@@ -2,7 +2,7 @@ import { EventBrand, StateBrand } from "../internal/brands.js";
|
|
|
2
2
|
import { Machine } from "../machine.js";
|
|
3
3
|
import { Schedule, Schema } from "effect";
|
|
4
4
|
|
|
5
|
-
//#region src
|
|
5
|
+
//#region src/persistence/persistent-machine.d.ts
|
|
6
6
|
type BrandedState = {
|
|
7
7
|
readonly _tag: string;
|
|
8
8
|
} & StateBrand;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { MissingSchemaError } from "../errors.js";
|
|
2
|
-
|
|
3
|
-
//#region src-v3/persistence/persistent-machine.ts
|
|
2
|
+
//#region src/persistence/persistent-machine.ts
|
|
4
3
|
/**
|
|
5
4
|
* Type guard to check if a value is a PersistentMachine
|
|
6
5
|
*/
|
|
@@ -19,6 +18,5 @@ const persist = (config) => (machine) => {
|
|
|
19
18
|
}
|
|
20
19
|
};
|
|
21
20
|
};
|
|
22
|
-
|
|
23
21
|
//#endregion
|
|
24
|
-
export { isPersistentMachine, persist };
|
|
22
|
+
export { isPersistentMachine, persist };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { InvalidSchemaError, MissingMatchHandlerError } from "./errors.js";
|
|
2
2
|
import { Schema } from "effect";
|
|
3
|
-
|
|
4
|
-
//#region src-v3/schema.ts
|
|
3
|
+
//#region src/schema.ts
|
|
5
4
|
/**
|
|
6
5
|
* Schema-first State/Event definitions for effect-machine.
|
|
7
6
|
*
|
|
@@ -59,7 +58,10 @@ const buildMachineSchema = (definition) => {
|
|
|
59
58
|
constructor.derive = (source, partial) => {
|
|
60
59
|
const result = { _tag: tag };
|
|
61
60
|
for (const key of fieldNames) if (key in source) result[key] = source[key];
|
|
62
|
-
if (partial !== void 0) for (const [key, value] of Object.entries(partial))
|
|
61
|
+
if (partial !== void 0) for (const [key, value] of Object.entries(partial)) {
|
|
62
|
+
if (key === "_tag") continue;
|
|
63
|
+
result[key] = value;
|
|
64
|
+
}
|
|
63
65
|
return result;
|
|
64
66
|
};
|
|
65
67
|
constructors[tag] = constructor;
|
|
@@ -160,6 +162,5 @@ const State = (definition) => createMachineSchema(definition);
|
|
|
160
162
|
* ```
|
|
161
163
|
*/
|
|
162
164
|
const Event = (definition) => createMachineSchema(definition);
|
|
163
|
-
|
|
164
165
|
//#endregion
|
|
165
|
-
export { Event, State };
|
|
166
|
+
export { Event, State };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ActorSystem } from "./actor.js";
|
|
2
|
-
import { Effect, Schema } from "effect";
|
|
2
|
+
import { Context, Effect, Schema } from "effect";
|
|
3
3
|
|
|
4
|
-
//#region src
|
|
4
|
+
//#region src/slot.d.ts
|
|
5
5
|
/** Schema fields definition (like Schema.Struct.Fields) */
|
|
6
6
|
type Fields = Record<string, Schema.Schema.All>;
|
|
7
7
|
/** Extract the encoded type from schema fields (used for parameters) */
|
|
@@ -43,6 +43,7 @@ type EffectSlots<D extends EffectsDef> = { readonly [K in keyof D & string]: Eff
|
|
|
43
43
|
* Shared across all machines via MachineContextTag.
|
|
44
44
|
*/
|
|
45
45
|
interface MachineContext<State, Event, Self> {
|
|
46
|
+
readonly actorId: string;
|
|
46
47
|
readonly state: State;
|
|
47
48
|
readonly event: Event;
|
|
48
49
|
readonly self: Self;
|
|
@@ -53,7 +54,7 @@ interface MachineContext<State, Event, Self> {
|
|
|
53
54
|
* Single module-level tag instead of per-machine allocation.
|
|
54
55
|
* @internal
|
|
55
56
|
*/
|
|
56
|
-
declare const MachineContextTag: any
|
|
57
|
+
declare const MachineContextTag: Context.Tag<MachineContext<any, any, any>, MachineContext<any, any, any>>;
|
|
57
58
|
/**
|
|
58
59
|
* Guard handler implementation.
|
|
59
60
|
* Receives params and context, returns Effect<boolean>.
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Context } from "effect";
|
|
2
|
-
|
|
3
|
-
//#region src-v3/slot.ts
|
|
2
|
+
//#region src/slot.ts
|
|
4
3
|
/**
|
|
5
4
|
* Slot module - schema-based, parameterized guards and effects.
|
|
6
5
|
*
|
|
@@ -94,6 +93,5 @@ const Slot = {
|
|
|
94
93
|
Guards,
|
|
95
94
|
Effects
|
|
96
95
|
};
|
|
97
|
-
|
|
98
96
|
//#endregion
|
|
99
|
-
export { Effects, Guards, MachineContextTag, Slot };
|
|
97
|
+
export { Effects, Guards, MachineContextTag, Slot };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { EffectsDef, GuardsDef, MachineContext } from "./slot.js";
|
|
1
2
|
import { AssertionError } from "./errors.js";
|
|
2
|
-
import {
|
|
3
|
-
import { BuiltMachine, Machine } from "./machine.js";
|
|
3
|
+
import { BuiltMachine, Machine, MachineRef } from "./machine.js";
|
|
4
4
|
import { Effect, SubscriptionRef } from "effect";
|
|
5
5
|
|
|
6
|
-
//#region src
|
|
6
|
+
//#region src/testing.d.ts
|
|
7
7
|
/** Accept either Machine or BuiltMachine for testing utilities. */
|
|
8
8
|
type MachineInput<S, E, R, GD extends GuardsDef, EFD extends EffectsDef> = Machine<S, E, R, any, any, GD, EFD> | BuiltMachine<S, E, R>;
|
|
9
9
|
/**
|
|
@@ -40,7 +40,7 @@ declare const simulate: <S extends {
|
|
|
40
40
|
}, R, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>>(input: MachineInput<S, E, R, GD, EFD>, events: readonly E[]) => Effect.Effect<{
|
|
41
41
|
states: S[];
|
|
42
42
|
finalState: S;
|
|
43
|
-
}, never, Exclude<R,
|
|
43
|
+
}, never, Exclude<R, MachineContext<S, E, MachineRef<E>>>>;
|
|
44
44
|
/**
|
|
45
45
|
* Assert that a machine can reach a specific state given a sequence of events
|
|
46
46
|
*/
|
|
@@ -48,7 +48,7 @@ declare const assertReaches: <S extends {
|
|
|
48
48
|
readonly _tag: string;
|
|
49
49
|
}, E extends {
|
|
50
50
|
readonly _tag: string;
|
|
51
|
-
}, R, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>>(input: MachineInput<S, E, R, GD, EFD>, events: readonly E[], expectedTag: string) => Effect.Effect<
|
|
51
|
+
}, R, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>>(input: MachineInput<S, E, R, GD, EFD>, events: readonly E[], expectedTag: string) => Effect.Effect<S, AssertionError, Exclude<R, MachineContext<S, E, MachineRef<E>>>>;
|
|
52
52
|
/**
|
|
53
53
|
* Assert that a machine follows a specific path of state tags
|
|
54
54
|
*
|
|
@@ -65,7 +65,10 @@ declare const assertPath: <S extends {
|
|
|
65
65
|
readonly _tag: string;
|
|
66
66
|
}, E extends {
|
|
67
67
|
readonly _tag: string;
|
|
68
|
-
}, R, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>>(input: MachineInput<S, E, R, GD, EFD>, events: readonly E[], expectedPath: readonly string[]) => Effect.Effect<
|
|
68
|
+
}, R, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>>(input: MachineInput<S, E, R, GD, EFD>, events: readonly E[], expectedPath: readonly string[]) => Effect.Effect<{
|
|
69
|
+
states: S[];
|
|
70
|
+
finalState: S;
|
|
71
|
+
}, AssertionError, Exclude<R, MachineContext<S, E, MachineRef<E>>>>;
|
|
69
72
|
/**
|
|
70
73
|
* Assert that a machine never reaches a specific state given a sequence of events
|
|
71
74
|
*
|
|
@@ -83,7 +86,10 @@ declare const assertNeverReaches: <S extends {
|
|
|
83
86
|
readonly _tag: string;
|
|
84
87
|
}, E extends {
|
|
85
88
|
readonly _tag: string;
|
|
86
|
-
}, R, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>>(input: MachineInput<S, E, R, GD, EFD>, events: readonly E[], forbiddenTag: string) => Effect.Effect<
|
|
89
|
+
}, R, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>>(input: MachineInput<S, E, R, GD, EFD>, events: readonly E[], forbiddenTag: string) => Effect.Effect<{
|
|
90
|
+
states: S[];
|
|
91
|
+
finalState: S;
|
|
92
|
+
}, AssertionError, Exclude<R, MachineContext<S, E, MachineRef<E>>>>;
|
|
87
93
|
/**
|
|
88
94
|
* Create a controllable test harness for a machine
|
|
89
95
|
*/
|
|
@@ -129,7 +135,7 @@ declare const createTestHarness: <S extends {
|
|
|
129
135
|
readonly _tag: string;
|
|
130
136
|
}, R, GD extends GuardsDef = Record<string, never>, EFD extends EffectsDef = Record<string, never>>(input: MachineInput<S, E, R, GD, EFD>, options?: TestHarnessOptions<S, E> | undefined) => Effect.Effect<{
|
|
131
137
|
state: SubscriptionRef.SubscriptionRef<S>;
|
|
132
|
-
send: (event: E) => Effect.Effect<S, never,
|
|
138
|
+
send: (event: E) => Effect.Effect<S, never, Exclude<R, MachineContext<S, E, MachineRef<E>>>>;
|
|
133
139
|
getState: Effect.Effect<S, never, never>;
|
|
134
140
|
}, never, never>;
|
|
135
141
|
//#endregion
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { stubSystem } from "./internal/utils.js";
|
|
2
2
|
import { AssertionError } from "./errors.js";
|
|
3
3
|
import { BuiltMachine } from "./machine.js";
|
|
4
|
-
import { executeTransition } from "./internal/transition.js";
|
|
4
|
+
import { executeTransition, shouldPostpone } from "./internal/transition.js";
|
|
5
5
|
import { Effect, SubscriptionRef } from "effect";
|
|
6
|
-
|
|
7
|
-
//#region src-v3/testing.ts
|
|
6
|
+
//#region src/testing.ts
|
|
8
7
|
/**
|
|
9
8
|
* Simulate a sequence of events through a machine without running an actor.
|
|
10
9
|
* Useful for testing state transitions in isolation.
|
|
@@ -27,18 +26,44 @@ import { Effect, SubscriptionRef } from "effect";
|
|
|
27
26
|
*/
|
|
28
27
|
const simulate = Effect.fn("effect-machine.simulate")(function* (input, events) {
|
|
29
28
|
const machine = input instanceof BuiltMachine ? input._inner : input;
|
|
29
|
+
const dummySend = Effect.fn("effect-machine.testing.simulate.send")((_event) => Effect.void);
|
|
30
30
|
const dummySelf = {
|
|
31
|
-
send:
|
|
31
|
+
send: dummySend,
|
|
32
|
+
cast: dummySend,
|
|
32
33
|
spawn: () => Effect.die("spawn not supported in simulation")
|
|
33
34
|
};
|
|
34
35
|
let currentState = machine.initial;
|
|
35
36
|
const states = [currentState];
|
|
37
|
+
const hasPostponeRules = machine.postponeRules.length > 0;
|
|
38
|
+
const postponed = [];
|
|
36
39
|
for (const event of events) {
|
|
37
|
-
|
|
40
|
+
if (hasPostponeRules && shouldPostpone(machine, currentState._tag, event._tag)) {
|
|
41
|
+
postponed.push(event);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const result = yield* executeTransition(machine, currentState, event, dummySelf, stubSystem, "simulation");
|
|
38
45
|
if (!result.transitioned) continue;
|
|
46
|
+
const prevTag = currentState._tag;
|
|
39
47
|
currentState = result.newState;
|
|
40
48
|
states.push(currentState);
|
|
41
49
|
if (machine.finalStates.has(currentState._tag)) break;
|
|
50
|
+
let drainTag = prevTag;
|
|
51
|
+
while (currentState._tag !== drainTag && postponed.length > 0) {
|
|
52
|
+
drainTag = currentState._tag;
|
|
53
|
+
const drained = postponed.splice(0);
|
|
54
|
+
for (const postponedEvent of drained) {
|
|
55
|
+
if (shouldPostpone(machine, currentState._tag, postponedEvent._tag)) {
|
|
56
|
+
postponed.push(postponedEvent);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const drainResult = yield* executeTransition(machine, currentState, postponedEvent, dummySelf, stubSystem, "simulation");
|
|
60
|
+
if (drainResult.transitioned) {
|
|
61
|
+
currentState = drainResult.newState;
|
|
62
|
+
states.push(currentState);
|
|
63
|
+
if (machine.finalStates.has(currentState._tag)) break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
42
67
|
}
|
|
43
68
|
return {
|
|
44
69
|
states,
|
|
@@ -114,25 +139,52 @@ const assertNeverReaches = Effect.fn("effect-machine.assertNeverReaches")(functi
|
|
|
114
139
|
*/
|
|
115
140
|
const createTestHarness = Effect.fn("effect-machine.createTestHarness")(function* (input, options) {
|
|
116
141
|
const machine = input instanceof BuiltMachine ? input._inner : input;
|
|
142
|
+
const dummySend = Effect.fn("effect-machine.testing.harness.send")((_event) => Effect.void);
|
|
117
143
|
const dummySelf = {
|
|
118
|
-
send:
|
|
144
|
+
send: dummySend,
|
|
145
|
+
cast: dummySend,
|
|
119
146
|
spawn: () => Effect.die("spawn not supported in test harness")
|
|
120
147
|
};
|
|
121
148
|
const stateRef = yield* SubscriptionRef.make(machine.initial);
|
|
149
|
+
const hasPostponeRules = machine.postponeRules.length > 0;
|
|
150
|
+
const postponed = [];
|
|
122
151
|
return {
|
|
123
152
|
state: stateRef,
|
|
124
153
|
send: Effect.fn("effect-machine.testHarness.send")(function* (event) {
|
|
125
154
|
const currentState = yield* SubscriptionRef.get(stateRef);
|
|
126
|
-
|
|
155
|
+
if (hasPostponeRules && shouldPostpone(machine, currentState._tag, event._tag)) {
|
|
156
|
+
postponed.push(event);
|
|
157
|
+
return currentState;
|
|
158
|
+
}
|
|
159
|
+
const result = yield* executeTransition(machine, currentState, event, dummySelf, stubSystem, "test-harness");
|
|
127
160
|
if (!result.transitioned) return currentState;
|
|
161
|
+
const prevTag = currentState._tag;
|
|
128
162
|
const newState = result.newState;
|
|
129
163
|
yield* SubscriptionRef.set(stateRef, newState);
|
|
130
164
|
if (options?.onTransition !== void 0) options.onTransition(currentState, event, newState);
|
|
165
|
+
let drainTag = prevTag;
|
|
166
|
+
let currentTag = newState._tag;
|
|
167
|
+
while (currentTag !== drainTag && postponed.length > 0) {
|
|
168
|
+
drainTag = currentTag;
|
|
169
|
+
const drained = postponed.splice(0);
|
|
170
|
+
for (const postponedEvent of drained) {
|
|
171
|
+
const state = yield* SubscriptionRef.get(stateRef);
|
|
172
|
+
if (shouldPostpone(machine, state._tag, postponedEvent._tag)) {
|
|
173
|
+
postponed.push(postponedEvent);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const drainResult = yield* executeTransition(machine, state, postponedEvent, dummySelf, stubSystem, "test-harness");
|
|
177
|
+
if (drainResult.transitioned) {
|
|
178
|
+
yield* SubscriptionRef.set(stateRef, drainResult.newState);
|
|
179
|
+
currentTag = drainResult.newState._tag;
|
|
180
|
+
if (options?.onTransition !== void 0) options.onTransition(state, postponedEvent, drainResult.newState);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
131
184
|
return newState;
|
|
132
185
|
}),
|
|
133
186
|
getState: SubscriptionRef.get(stateRef)
|
|
134
187
|
};
|
|
135
188
|
});
|
|
136
|
-
|
|
137
189
|
//#endregion
|
|
138
|
-
export { AssertionError, assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate };
|
|
190
|
+
export { AssertionError, assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate };
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
//#region \0rolldown/runtime.js
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __exportAll = (all, no_symbols) => {
|
|
4
|
-
let target = {};
|
|
5
|
-
for (var name in all) {
|
|
6
|
-
__defProp(target, name, {
|
|
7
|
-
get: all[name],
|
|
8
|
-
enumerable: true
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
if (!no_symbols) {
|
|
12
|
-
__defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
13
|
-
}
|
|
14
|
-
return target;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
//#endregion
|
|
18
|
-
export { __exportAll };
|
package/dist-v3/errors.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
//#region src-v3/errors.d.ts
|
|
2
|
-
declare const DuplicateActorError_base: any;
|
|
3
|
-
/** Attempted to spawn/restore actor with ID already in use */
|
|
4
|
-
declare class DuplicateActorError extends DuplicateActorError_base {}
|
|
5
|
-
declare const UnprovidedSlotsError_base: any;
|
|
6
|
-
/** Machine has unprovided effect slots */
|
|
7
|
-
declare class UnprovidedSlotsError extends UnprovidedSlotsError_base {}
|
|
8
|
-
declare const MissingSchemaError_base: any;
|
|
9
|
-
/** Operation requires schemas attached to machine */
|
|
10
|
-
declare class MissingSchemaError extends MissingSchemaError_base {}
|
|
11
|
-
declare const InvalidSchemaError_base: any;
|
|
12
|
-
/** State/Event schema has no variants */
|
|
13
|
-
declare class InvalidSchemaError extends InvalidSchemaError_base {}
|
|
14
|
-
declare const MissingMatchHandlerError_base: any;
|
|
15
|
-
/** $match called with missing handler for tag */
|
|
16
|
-
declare class MissingMatchHandlerError extends MissingMatchHandlerError_base {}
|
|
17
|
-
declare const SlotProvisionError_base: any;
|
|
18
|
-
/** Slot handler not found at runtime (internal error) */
|
|
19
|
-
declare class SlotProvisionError extends SlotProvisionError_base {}
|
|
20
|
-
declare const ProvisionValidationError_base: any;
|
|
21
|
-
/** Machine.build() validation failed - missing or extra handlers */
|
|
22
|
-
declare class ProvisionValidationError extends ProvisionValidationError_base {}
|
|
23
|
-
declare const AssertionError_base: any;
|
|
24
|
-
/** Assertion failed in testing utilities */
|
|
25
|
-
declare class AssertionError extends AssertionError_base {}
|
|
26
|
-
//#endregion
|
|
27
|
-
export { AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError };
|
package/dist-v3/index.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Event, MachineEventSchema, MachineStateSchema, State } from "./schema.js";
|
|
2
|
-
import { PersistenceConfig, PersistentMachine, isPersistentMachine } from "./persistence/persistent-machine.js";
|
|
3
|
-
import { AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError } from "./errors.js";
|
|
4
|
-
import { EffectHandlers, EffectSlot, EffectSlots, EffectsDef, EffectsSchema, GuardHandlers, GuardSlot, GuardSlots, GuardsDef, GuardsSchema, MachineContext, Slot } from "./slot.js";
|
|
5
|
-
import { PersistentActorRef, createPersistentActor, restorePersistentActor } from "./persistence/persistent-actor.js";
|
|
6
|
-
import { ActorMetadata, PersistedEvent, PersistenceAdapter, PersistenceAdapterTag, PersistenceError, RestoreFailure, RestoreResult, Snapshot, VersionConflictError } from "./persistence/adapter.js";
|
|
7
|
-
import { InMemoryPersistenceAdapter, makeInMemoryPersistenceAdapter } from "./persistence/adapters/in-memory.js";
|
|
8
|
-
import "./persistence/index.js";
|
|
9
|
-
import { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig, PersistOptions, ProvideHandlers, SpawnEffect, StateHandlerContext, Transition, machine_d_exports } from "./machine.js";
|
|
10
|
-
import { ActorRef, ActorSystem, Default, SystemEvent, SystemEventListener } from "./actor.js";
|
|
11
|
-
import { SimulationResult, TestHarness, TestHarnessOptions, assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
|
|
12
|
-
import { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, InspectionEvent, Inspector, SpawnEvent, StopEvent, TransitionEvent, collectingInspector, consoleInspector, makeInspector } from "./inspection.js";
|
|
13
|
-
export { type ActorMetadata, type ActorRef, type ActorSystem, Default as ActorSystemDefault, ActorSystem as ActorSystemService, type AnyInspectionEvent, AssertionError, type BackgroundEffect, type BuiltMachine, DuplicateActorError, type EffectEvent, type EffectSlots, type EffectsDef, type EffectsSchema, type ErrorEvent, Event, type EventReceivedEvent, type GuardHandlers, type GuardSlot, type GuardSlots, type GuardsDef, type GuardsSchema, type HandlerContext, InMemoryPersistenceAdapter, type InspectionEvent, type Inspector, Inspector as InspectorService, InvalidSchemaError, machine_d_exports as Machine, type MachineContext, type MachineEventSchema, type MachineRef, type MachineStateSchema, type Machine as MachineType, type MakeConfig, MissingMatchHandlerError, MissingSchemaError, type PersistOptions, type PersistedEvent, type PersistenceAdapter, PersistenceAdapterTag, type PersistenceConfig, PersistenceError, type PersistentActorRef, type PersistentMachine, type ProvideHandlers, ProvisionValidationError, type RestoreFailure, type RestoreResult, type SimulationResult, Slot, type EffectHandlers as SlotEffectHandlers, type EffectSlot as SlotEffectSlot, SlotProvisionError, type Snapshot, type SpawnEffect, type SpawnEvent, State, type StateHandlerContext, type StopEvent, type SystemEvent, type SystemEventListener, type TestHarness, type TestHarnessOptions, type Transition, type TransitionEvent, UnprovidedSlotsError, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, consoleInspector, createPersistentActor, createTestHarness, isPersistentMachine, makeInMemoryPersistenceAdapter, makeInspector, restorePersistentActor, simulate };
|
package/dist-v3/index.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Inspector, collectingInspector, consoleInspector, makeInspector } from "./inspection.js";
|
|
2
|
-
import { AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError } from "./errors.js";
|
|
3
|
-
import { isPersistentMachine } from "./persistence/persistent-machine.js";
|
|
4
|
-
import { Slot } from "./slot.js";
|
|
5
|
-
import { machine_exports } from "./machine.js";
|
|
6
|
-
import { PersistenceAdapterTag, PersistenceError, VersionConflictError } from "./persistence/adapter.js";
|
|
7
|
-
import { createPersistentActor, restorePersistentActor } from "./persistence/persistent-actor.js";
|
|
8
|
-
import { ActorSystem, Default } from "./actor.js";
|
|
9
|
-
import { Event, State } from "./schema.js";
|
|
10
|
-
import { assertNeverReaches, assertPath, assertReaches, createTestHarness, simulate } from "./testing.js";
|
|
11
|
-
import { InMemoryPersistenceAdapter, makeInMemoryPersistenceAdapter } from "./persistence/adapters/in-memory.js";
|
|
12
|
-
import "./persistence/index.js";
|
|
13
|
-
|
|
14
|
-
export { Default as ActorSystemDefault, ActorSystem as ActorSystemService, AssertionError, DuplicateActorError, Event, InMemoryPersistenceAdapter, Inspector as InspectorService, InvalidSchemaError, machine_exports as Machine, MissingMatchHandlerError, MissingSchemaError, PersistenceAdapterTag, PersistenceError, ProvisionValidationError, Slot, SlotProvisionError, State, UnprovidedSlotsError, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, consoleInspector, createPersistentActor, createTestHarness, isPersistentMachine, makeInMemoryPersistenceAdapter, makeInspector, restorePersistentActor, simulate };
|
package/dist-v3/inspection.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { Context } from "effect";
|
|
2
|
-
|
|
3
|
-
//#region src-v3/inspection.ts
|
|
4
|
-
/**
|
|
5
|
-
* Inspector service tag - optional service for machine introspection
|
|
6
|
-
* Uses `any` types to allow variance flexibility when providing the service
|
|
7
|
-
*/
|
|
8
|
-
const Inspector = Context.GenericTag("@effect/machine/Inspector");
|
|
9
|
-
/**
|
|
10
|
-
* Create an inspector from a callback function.
|
|
11
|
-
*
|
|
12
|
-
* Type params accept either raw tagged types or Schema constructors:
|
|
13
|
-
* - `makeInspector(cb)` — defaults to `AnyInspectionEvent`
|
|
14
|
-
* - `makeInspector<MyState, MyEvent>(cb)` — explicit tagged types
|
|
15
|
-
* - `makeInspector<typeof MyState, typeof MyEvent>(cb)` — schema constructors (auto-extracts `.Type`)
|
|
16
|
-
*/
|
|
17
|
-
const makeInspector = (onInspect) => ({ onInspect });
|
|
18
|
-
/**
|
|
19
|
-
* Console inspector that logs events in a readable format
|
|
20
|
-
*/
|
|
21
|
-
const consoleInspector = () => makeInspector((event) => {
|
|
22
|
-
const prefix = `[${event.actorId}]`;
|
|
23
|
-
switch (event.type) {
|
|
24
|
-
case "@machine.spawn":
|
|
25
|
-
console.log(prefix, "spawned →", event.initialState._tag);
|
|
26
|
-
break;
|
|
27
|
-
case "@machine.event":
|
|
28
|
-
console.log(prefix, "received", event.event._tag, "in", event.state._tag);
|
|
29
|
-
break;
|
|
30
|
-
case "@machine.transition":
|
|
31
|
-
console.log(prefix, event.fromState._tag, "→", event.toState._tag);
|
|
32
|
-
break;
|
|
33
|
-
case "@machine.effect":
|
|
34
|
-
console.log(prefix, event.effectType, "effect in", event.state._tag);
|
|
35
|
-
break;
|
|
36
|
-
case "@machine.error":
|
|
37
|
-
console.log(prefix, "error in", event.phase, event.state._tag, "-", event.error);
|
|
38
|
-
break;
|
|
39
|
-
case "@machine.stop":
|
|
40
|
-
console.log(prefix, "stopped in", event.finalState._tag);
|
|
41
|
-
break;
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
/**
|
|
45
|
-
* Collecting inspector that stores events in an array for testing
|
|
46
|
-
*/
|
|
47
|
-
const collectingInspector = (events) => ({ onInspect: (event) => events.push(event) });
|
|
48
|
-
|
|
49
|
-
//#endregion
|
|
50
|
-
export { Inspector, collectingInspector, consoleInspector, makeInspector };
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Clock, Effect } from "effect";
|
|
2
|
-
|
|
3
|
-
//#region src-v3/internal/inspection.ts
|
|
4
|
-
/**
|
|
5
|
-
* Emit an inspection event with timestamp from Clock.
|
|
6
|
-
* @internal
|
|
7
|
-
*/
|
|
8
|
-
const emitWithTimestamp = Effect.fn("effect-machine.emitWithTimestamp")(function* (inspector, makeEvent) {
|
|
9
|
-
if (inspector === void 0) return;
|
|
10
|
-
const timestamp = yield* Clock.currentTimeMillis;
|
|
11
|
-
yield* Effect.try(() => inspector.onInspect(makeEvent(timestamp))).pipe(Effect.ignore);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
//#endregion
|
|
15
|
-
export { emitWithTimestamp };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|