effect-machine 0.9.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/actor.d.ts +55 -89
- package/dist/actor.js +135 -30
- package/dist/cluster/entity-machine.js +5 -3
- package/dist/errors.d.ts +12 -1
- package/dist/errors.js +8 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/internal/transition.d.ts +26 -2
- package/dist/internal/transition.js +37 -8
- package/dist/internal/utils.d.ts +7 -2
- package/dist/machine.d.ts +66 -3
- package/dist/machine.js +65 -0
- package/dist/persistence/persistent-actor.js +52 -16
- package/dist/testing.js +57 -3
- package/package.json +9 -8
- package/{dist-v3 → v3/dist}/actor.d.ts +65 -78
- package/{dist-v3 → v3/dist}/actor.js +173 -35
- package/{dist-v3 → v3/dist}/cluster/entity-machine.d.ts +1 -1
- package/{dist-v3 → v3/dist}/cluster/entity-machine.js +8 -6
- package/{dist-v3 → v3/dist}/cluster/to-entity.d.ts +1 -1
- package/{dist-v3 → v3/dist}/cluster/to-entity.js +1 -1
- package/v3/dist/errors.d.ts +76 -0
- package/{dist-v3 → v3/dist}/errors.js +9 -2
- 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 -15
- package/{dist-v3 → v3/dist}/internal/utils.d.ts +9 -4
- package/{dist-v3 → v3/dist}/internal/utils.js +1 -1
- package/{dist-v3 → v3/dist}/machine.d.ts +86 -9
- package/{dist-v3 → v3/dist}/machine.js +128 -2
- package/{dist-v3 → v3/dist}/persistence/adapter.d.ts +18 -5
- package/{dist-v3 → v3/dist}/persistence/adapter.js +1 -1
- package/{dist-v3 → v3/dist}/persistence/adapters/in-memory.d.ts +1 -1
- package/{dist-v3 → v3/dist}/persistence/adapters/in-memory.js +1 -1
- package/{dist-v3 → v3/dist}/persistence/persistent-actor.d.ts +7 -6
- package/{dist-v3 → v3/dist}/persistence/persistent-actor.js +58 -19
- package/{dist-v3 → v3/dist}/persistence/persistent-machine.d.ts +1 -1
- package/{dist-v3 → v3/dist}/persistence/persistent-machine.js +1 -1
- package/{dist-v3 → v3/dist}/schema.d.ts +1 -1
- package/{dist-v3 → v3/dist}/schema.js +5 -2
- package/{dist-v3 → v3/dist}/slot.d.ts +4 -3
- package/{dist-v3 → v3/dist}/slot.js +1 -1
- package/{dist-v3 → v3/dist}/testing.d.ts +14 -8
- package/{dist-v3 → v3/dist}/testing.js +60 -6
- package/dist-v3/errors.d.ts +0 -27
- package/dist-v3/index.d.ts +0 -12
- package/dist-v3/index.js +0 -13
- package/dist-v3/inspection.js +0 -48
- package/dist-v3/internal/inspection.js +0 -13
- /package/{dist-v3 → v3/dist}/_virtual/_rolldown/runtime.js +0 -0
- /package/{dist-v3 → v3/dist}/cluster/index.d.ts +0 -0
- /package/{dist-v3 → v3/dist}/cluster/index.js +0 -0
- /package/{dist-v3 → v3/dist}/internal/brands.js +0 -0
- /package/{dist-v3 → v3/dist}/persistence/index.d.ts +0 -0
- /package/{dist-v3 → v3/dist}/persistence/index.js +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { Inspector } from "./inspection.js";
|
|
2
2
|
import { INTERNAL_INIT_EVENT } from "./internal/utils.js";
|
|
3
|
-
import { DuplicateActorError } from "./errors.js";
|
|
3
|
+
import { ActorStoppedError, DuplicateActorError, NoReplyError } from "./errors.js";
|
|
4
4
|
import { isPersistentMachine } from "./persistence/persistent-machine.js";
|
|
5
|
-
import { processEventCore, resolveTransition, runSpawnEffects } from "./internal/transition.js";
|
|
6
5
|
import { emitWithTimestamp } from "./internal/inspection.js";
|
|
6
|
+
import { processEventCore, resolveTransition, runSpawnEffects, shouldPostpone } from "./internal/transition.js";
|
|
7
7
|
import { PersistenceAdapterTag, PersistenceError } from "./persistence/adapter.js";
|
|
8
8
|
import { createPersistentActor, restorePersistentActor } from "./persistence/persistent-actor.js";
|
|
9
9
|
import { Cause, Context, Deferred, Effect, Exit, Fiber, Layer, MutableHashMap, Option, PubSub, Queue, Ref, Runtime, Scope, Stream, SubscriptionRef } from "effect";
|
|
10
|
-
//#region src
|
|
10
|
+
//#region src/actor.ts
|
|
11
11
|
/**
|
|
12
12
|
* Actor system: spawning, lifecycle, and event processing.
|
|
13
13
|
*
|
|
@@ -31,10 +31,50 @@ const notifyListeners = (listeners, state) => {
|
|
|
31
31
|
/**
|
|
32
32
|
* Build core ActorRef methods shared between regular and persistent actors.
|
|
33
33
|
*/
|
|
34
|
-
const buildActorRefCore = (id, machine, stateRef, eventQueue, stoppedRef, listeners, stop, system, childrenMap) => {
|
|
34
|
+
const buildActorRefCore = (id, machine, stateRef, eventQueue, stoppedRef, listeners, stop, system, childrenMap, pendingReplies) => {
|
|
35
35
|
const send = Effect.fn("effect-machine.actor.send")(function* (event) {
|
|
36
36
|
if (yield* Ref.get(stoppedRef)) return;
|
|
37
|
-
yield* Queue.offer(eventQueue,
|
|
37
|
+
yield* Queue.offer(eventQueue, {
|
|
38
|
+
_tag: "send",
|
|
39
|
+
event
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
const call = Effect.fn("effect-machine.actor.call")(function* (event) {
|
|
43
|
+
if (yield* Ref.get(stoppedRef)) {
|
|
44
|
+
const currentState = yield* SubscriptionRef.get(stateRef);
|
|
45
|
+
return {
|
|
46
|
+
newState: currentState,
|
|
47
|
+
previousState: currentState,
|
|
48
|
+
transitioned: false,
|
|
49
|
+
lifecycleRan: false,
|
|
50
|
+
isFinal: machine.finalStates.has(currentState._tag)
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const reply = yield* Deferred.make();
|
|
54
|
+
pendingReplies.add(reply);
|
|
55
|
+
yield* Queue.offer(eventQueue, {
|
|
56
|
+
_tag: "call",
|
|
57
|
+
event,
|
|
58
|
+
reply
|
|
59
|
+
});
|
|
60
|
+
return yield* Deferred.await(reply).pipe(Effect.ensuring(Effect.sync(() => pendingReplies.delete(reply))), Effect.catchTag("ActorStoppedError", () => SubscriptionRef.get(stateRef).pipe(Effect.map((currentState) => ({
|
|
61
|
+
newState: currentState,
|
|
62
|
+
previousState: currentState,
|
|
63
|
+
transitioned: false,
|
|
64
|
+
lifecycleRan: false,
|
|
65
|
+
isFinal: machine.finalStates.has(currentState._tag)
|
|
66
|
+
})))));
|
|
67
|
+
});
|
|
68
|
+
const ask = Effect.fn("effect-machine.actor.ask")(function* (event) {
|
|
69
|
+
if (yield* Ref.get(stoppedRef)) return yield* new ActorStoppedError({ actorId: id });
|
|
70
|
+
const reply = yield* Deferred.make();
|
|
71
|
+
pendingReplies.add(reply);
|
|
72
|
+
yield* Queue.offer(eventQueue, {
|
|
73
|
+
_tag: "ask",
|
|
74
|
+
event,
|
|
75
|
+
reply
|
|
76
|
+
});
|
|
77
|
+
return yield* Deferred.await(reply).pipe(Effect.ensuring(Effect.sync(() => pendingReplies.delete(reply))));
|
|
38
78
|
});
|
|
39
79
|
const snapshot = SubscriptionRef.get(stateRef).pipe(Effect.withSpan("effect-machine.actor.snapshot"));
|
|
40
80
|
const matches = Effect.fn("effect-machine.actor.matches")(function* (tag) {
|
|
@@ -72,30 +112,38 @@ const buildActorRefCore = (id, machine, stateRef, eventQueue, stoppedRef, listen
|
|
|
72
112
|
return {
|
|
73
113
|
id,
|
|
74
114
|
send,
|
|
115
|
+
cast: send,
|
|
116
|
+
call,
|
|
117
|
+
ask,
|
|
75
118
|
state: stateRef,
|
|
76
119
|
stop,
|
|
77
|
-
stopSync: () => Effect.runFork(stop),
|
|
78
120
|
snapshot,
|
|
79
|
-
snapshotSync: () => Effect.runSync(SubscriptionRef.get(stateRef)),
|
|
80
121
|
matches,
|
|
81
|
-
matchesSync: (tag) => Effect.runSync(SubscriptionRef.get(stateRef))._tag === tag,
|
|
82
122
|
can,
|
|
83
|
-
canSync: (event) => {
|
|
84
|
-
return resolveTransition(machine, Effect.runSync(SubscriptionRef.get(stateRef)), event) !== void 0;
|
|
85
|
-
},
|
|
86
123
|
changes: stateRef.changes,
|
|
87
124
|
waitFor,
|
|
88
125
|
awaitFinal,
|
|
89
126
|
sendAndWait,
|
|
90
|
-
sendSync: (event) => {
|
|
91
|
-
if (!Effect.runSync(Ref.get(stoppedRef))) Effect.runSync(Queue.offer(eventQueue, event));
|
|
92
|
-
},
|
|
93
127
|
subscribe: (fn) => {
|
|
94
128
|
listeners.add(fn);
|
|
95
129
|
return () => {
|
|
96
130
|
listeners.delete(fn);
|
|
97
131
|
};
|
|
98
132
|
},
|
|
133
|
+
sync: {
|
|
134
|
+
send: (event) => {
|
|
135
|
+
if (!Effect.runSync(Ref.get(stoppedRef))) Effect.runSync(Queue.offer(eventQueue, {
|
|
136
|
+
_tag: "send",
|
|
137
|
+
event
|
|
138
|
+
}));
|
|
139
|
+
},
|
|
140
|
+
stop: () => Effect.runFork(stop),
|
|
141
|
+
snapshot: () => Effect.runSync(SubscriptionRef.get(stateRef)),
|
|
142
|
+
matches: (tag) => Effect.runSync(SubscriptionRef.get(stateRef))._tag === tag,
|
|
143
|
+
can: (event) => {
|
|
144
|
+
return resolveTransition(machine, Effect.runSync(SubscriptionRef.get(stateRef)), event) !== void 0;
|
|
145
|
+
}
|
|
146
|
+
},
|
|
99
147
|
system,
|
|
100
148
|
children: childrenMap
|
|
101
149
|
};
|
|
@@ -118,11 +166,16 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
118
166
|
const eventQueue = yield* Queue.unbounded();
|
|
119
167
|
const stoppedRef = yield* Ref.make(false);
|
|
120
168
|
const childrenMap = /* @__PURE__ */ new Map();
|
|
169
|
+
const selfSend = Effect.fn("effect-machine.actor.self.send")(function* (event) {
|
|
170
|
+
if (yield* Ref.get(stoppedRef)) return;
|
|
171
|
+
yield* Queue.offer(eventQueue, {
|
|
172
|
+
_tag: "send",
|
|
173
|
+
event
|
|
174
|
+
});
|
|
175
|
+
});
|
|
121
176
|
const self = {
|
|
122
|
-
send:
|
|
123
|
-
|
|
124
|
-
yield* Queue.offer(eventQueue, event);
|
|
125
|
-
}),
|
|
177
|
+
send: selfSend,
|
|
178
|
+
cast: selfSend,
|
|
126
179
|
spawn: (childId, childMachine) => Effect.gen(function* () {
|
|
127
180
|
const child = yield* system.spawn(childId, childMachine).pipe(Effect.provideService(ActorSystem, system));
|
|
128
181
|
childrenMap.set(childId, child);
|
|
@@ -145,6 +198,7 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
145
198
|
const backgroundFibers = [];
|
|
146
199
|
const initEvent = { _tag: INTERNAL_INIT_EVENT };
|
|
147
200
|
const ctx = {
|
|
201
|
+
actorId: id,
|
|
148
202
|
state: machine.initial,
|
|
149
203
|
event: initEvent,
|
|
150
204
|
self,
|
|
@@ -153,6 +207,7 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
153
207
|
const { effects: effectSlots } = machine._slots;
|
|
154
208
|
for (const bg of machine.backgroundEffects) {
|
|
155
209
|
const fiber = yield* Effect.forkDaemon(bg.handler({
|
|
210
|
+
actorId: id,
|
|
156
211
|
state: machine.initial,
|
|
157
212
|
event: initEvent,
|
|
158
213
|
self,
|
|
@@ -174,9 +229,10 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
174
229
|
}));
|
|
175
230
|
yield* Ref.set(stoppedRef, true);
|
|
176
231
|
if (implicitSystemScope !== void 0) yield* Scope.close(implicitSystemScope, Exit.void);
|
|
177
|
-
return buildActorRefCore(id, machine, stateRef, eventQueue, stoppedRef, listeners, Ref.set(stoppedRef, true).pipe(Effect.withSpan("effect-machine.actor.stop"), Effect.asVoid), system, childrenMap);
|
|
232
|
+
return buildActorRefCore(id, machine, stateRef, eventQueue, stoppedRef, listeners, Ref.set(stoppedRef, true).pipe(Effect.withSpan("effect-machine.actor.stop"), Effect.asVoid), system, childrenMap, /* @__PURE__ */ new Set());
|
|
178
233
|
}
|
|
179
|
-
const
|
|
234
|
+
const pendingReplies = /* @__PURE__ */ new Set();
|
|
235
|
+
const loopFiber = yield* Effect.forkDaemon(eventLoop(machine, stateRef, eventQueue, stoppedRef, self, listeners, backgroundFibers, stateScopeRef, id, inspectorValue, system, pendingReplies));
|
|
180
236
|
return buildActorRefCore(id, machine, stateRef, eventQueue, stoppedRef, listeners, Effect.gen(function* () {
|
|
181
237
|
const finalState = yield* SubscriptionRef.get(stateRef);
|
|
182
238
|
yield* emitWithTimestamp(inspectorValue, (timestamp) => ({
|
|
@@ -187,31 +243,104 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
187
243
|
}));
|
|
188
244
|
yield* Ref.set(stoppedRef, true);
|
|
189
245
|
yield* Fiber.interrupt(loopFiber);
|
|
246
|
+
yield* settlePendingReplies(pendingReplies, id);
|
|
190
247
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
191
248
|
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
192
249
|
if (implicitSystemScope !== void 0) yield* Scope.close(implicitSystemScope, Exit.void);
|
|
193
|
-
}).pipe(Effect.withSpan("effect-machine.actor.stop"), Effect.asVoid), system, childrenMap);
|
|
250
|
+
}).pipe(Effect.withSpan("effect-machine.actor.stop"), Effect.asVoid), system, childrenMap, pendingReplies);
|
|
251
|
+
});
|
|
252
|
+
/** Fail all pending call/ask Deferreds with ActorStoppedError. Safe to call multiple times. */
|
|
253
|
+
const settlePendingReplies = (pendingReplies, actorId) => Effect.sync(() => {
|
|
254
|
+
const error = new ActorStoppedError({ actorId });
|
|
255
|
+
for (const deferred of pendingReplies) Effect.runFork(Deferred.fail(deferred, error));
|
|
256
|
+
pendingReplies.clear();
|
|
194
257
|
});
|
|
195
258
|
/**
|
|
196
|
-
* Main event loop for the actor
|
|
259
|
+
* Main event loop for the actor.
|
|
260
|
+
* Includes postpone buffer — events matching postpone rules are buffered
|
|
261
|
+
* and drained after state tag changes (gen_statem semantics).
|
|
197
262
|
*/
|
|
198
|
-
const eventLoop = Effect.fn("effect-machine.actor.eventLoop")(function* (machine, stateRef, eventQueue, stoppedRef, self, listeners, backgroundFibers, stateScopeRef, actorId, inspector, system) {
|
|
199
|
-
|
|
200
|
-
|
|
263
|
+
const eventLoop = Effect.fn("effect-machine.actor.eventLoop")(function* (machine, stateRef, eventQueue, stoppedRef, self, listeners, backgroundFibers, stateScopeRef, actorId, inspector, system, pendingReplies) {
|
|
264
|
+
const postponed = [];
|
|
265
|
+
const hasPostponeRules = machine.postponeRules.length > 0;
|
|
266
|
+
const processQueued = Effect.fn("effect-machine.actor.processQueued")(function* (queued) {
|
|
267
|
+
const event = queued.event;
|
|
201
268
|
const currentState = yield* SubscriptionRef.get(stateRef);
|
|
202
|
-
if (
|
|
269
|
+
if (hasPostponeRules && shouldPostpone(machine, currentState._tag, event._tag)) {
|
|
270
|
+
postponed.push(queued);
|
|
271
|
+
if (queued._tag === "call") {
|
|
272
|
+
const postponedResult = {
|
|
273
|
+
newState: currentState,
|
|
274
|
+
previousState: currentState,
|
|
275
|
+
transitioned: false,
|
|
276
|
+
lifecycleRan: false,
|
|
277
|
+
isFinal: false,
|
|
278
|
+
hasReply: false,
|
|
279
|
+
reply: void 0,
|
|
280
|
+
postponed: true
|
|
281
|
+
};
|
|
282
|
+
yield* Deferred.succeed(queued.reply, postponedResult);
|
|
283
|
+
}
|
|
284
|
+
return {
|
|
285
|
+
shouldStop: false,
|
|
286
|
+
stateChanged: false
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
const { shouldStop, result } = yield* Effect.withSpan("effect-machine.event.process", { attributes: {
|
|
203
290
|
"effect_machine.actor.id": actorId,
|
|
204
291
|
"effect_machine.state.current": currentState._tag,
|
|
205
292
|
"effect_machine.event.type": event._tag
|
|
206
|
-
} })(processEvent(machine, currentState, event, stateRef, self, listeners, stateScopeRef, actorId, inspector, system))
|
|
293
|
+
} })(processEvent(machine, currentState, event, stateRef, self, listeners, stateScopeRef, actorId, inspector, system));
|
|
294
|
+
switch (queued._tag) {
|
|
295
|
+
case "call":
|
|
296
|
+
yield* Deferred.succeed(queued.reply, result);
|
|
297
|
+
break;
|
|
298
|
+
case "ask":
|
|
299
|
+
if (result.hasReply) yield* Deferred.succeed(queued.reply, result.reply);
|
|
300
|
+
else yield* Deferred.fail(queued.reply, new NoReplyError({
|
|
301
|
+
actorId,
|
|
302
|
+
eventTag: event._tag
|
|
303
|
+
}));
|
|
304
|
+
break;
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
shouldStop,
|
|
308
|
+
stateChanged: result.lifecycleRan
|
|
309
|
+
};
|
|
310
|
+
});
|
|
311
|
+
while (true) {
|
|
312
|
+
const { shouldStop, stateChanged } = yield* processQueued(yield* Queue.take(eventQueue));
|
|
313
|
+
if (shouldStop) {
|
|
207
314
|
yield* Ref.set(stoppedRef, true);
|
|
315
|
+
settlePostponedBuffer(postponed, pendingReplies, actorId);
|
|
316
|
+
yield* settlePendingReplies(pendingReplies, actorId);
|
|
208
317
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
209
318
|
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
210
319
|
return;
|
|
211
320
|
}
|
|
321
|
+
if (stateChanged && postponed.length > 0) {
|
|
322
|
+
const drained = postponed.splice(0);
|
|
323
|
+
for (const entry of drained) if ((yield* processQueued(entry)).shouldStop) {
|
|
324
|
+
yield* Ref.set(stoppedRef, true);
|
|
325
|
+
settlePostponedBuffer(postponed, pendingReplies, actorId);
|
|
326
|
+
yield* settlePendingReplies(pendingReplies, actorId);
|
|
327
|
+
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
328
|
+
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
212
332
|
}
|
|
213
333
|
});
|
|
214
334
|
/**
|
|
335
|
+
* Settle all reply-bearing entries in the postpone buffer on shutdown.
|
|
336
|
+
* Call entries already had their Deferred settled with the postponed result
|
|
337
|
+
* (so their pendingReplies entry is already removed). Ask/send entries
|
|
338
|
+
* with Deferreds are settled via the pendingReplies registry.
|
|
339
|
+
*/
|
|
340
|
+
const settlePostponedBuffer = (postponed, _pendingReplies, _actorId) => {
|
|
341
|
+
postponed.length = 0;
|
|
342
|
+
};
|
|
343
|
+
/**
|
|
215
344
|
* Process a single event, returning true if the actor should stop.
|
|
216
345
|
* Wraps processEventCore with actor-specific concerns (inspection, listeners, state ref).
|
|
217
346
|
*/
|
|
@@ -223,7 +352,7 @@ const processEvent = Effect.fn("effect-machine.actor.processEvent")(function* (m
|
|
|
223
352
|
event,
|
|
224
353
|
timestamp
|
|
225
354
|
}));
|
|
226
|
-
const result = yield* processEventCore(machine, currentState, event, self, stateScopeRef, system, inspector === void 0 ? void 0 : {
|
|
355
|
+
const result = yield* processEventCore(machine, currentState, event, self, stateScopeRef, system, actorId, inspector === void 0 ? void 0 : {
|
|
227
356
|
onSpawnEffect: (state) => emitWithTimestamp(inspector, (timestamp) => ({
|
|
228
357
|
type: "@machine.effect",
|
|
229
358
|
actorId,
|
|
@@ -251,7 +380,10 @@ const processEvent = Effect.fn("effect-machine.actor.processEvent")(function* (m
|
|
|
251
380
|
});
|
|
252
381
|
if (!result.transitioned) {
|
|
253
382
|
yield* Effect.annotateCurrentSpan("effect_machine.transition.matched", false);
|
|
254
|
-
return
|
|
383
|
+
return {
|
|
384
|
+
shouldStop: false,
|
|
385
|
+
result
|
|
386
|
+
};
|
|
255
387
|
}
|
|
256
388
|
yield* Effect.annotateCurrentSpan("effect_machine.transition.matched", true);
|
|
257
389
|
yield* SubscriptionRef.set(stateRef, result.newState);
|
|
@@ -266,10 +398,16 @@ const processEvent = Effect.fn("effect-machine.actor.processEvent")(function* (m
|
|
|
266
398
|
finalState: result.newState,
|
|
267
399
|
timestamp
|
|
268
400
|
}));
|
|
269
|
-
return
|
|
401
|
+
return {
|
|
402
|
+
shouldStop: true,
|
|
403
|
+
result
|
|
404
|
+
};
|
|
270
405
|
}
|
|
271
406
|
}
|
|
272
|
-
return
|
|
407
|
+
return {
|
|
408
|
+
shouldStop: false,
|
|
409
|
+
result
|
|
410
|
+
};
|
|
273
411
|
});
|
|
274
412
|
/**
|
|
275
413
|
* Run spawn effects with actor-specific inspection and tracing.
|
|
@@ -284,7 +422,7 @@ const runSpawnEffectsWithInspection = Effect.fn("effect-machine.actor.spawnEffec
|
|
|
284
422
|
state,
|
|
285
423
|
timestamp
|
|
286
424
|
}));
|
|
287
|
-
yield* runSpawnEffects(machine, state, event, self, stateScope, system, inspector === void 0 ? void 0 : (info) => emitWithTimestamp(inspector, (timestamp) => ({
|
|
425
|
+
yield* runSpawnEffects(machine, state, event, self, stateScope, system, actorId, inspector === void 0 ? void 0 : (info) => emitWithTimestamp(inspector, (timestamp) => ({
|
|
288
426
|
type: "@machine.error",
|
|
289
427
|
actorId,
|
|
290
428
|
phase: info.phase,
|
|
@@ -305,13 +443,13 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
|
|
|
305
443
|
const withSpawnGate = (yield* Effect.makeSemaphore(1)).withPermits(1);
|
|
306
444
|
const eventPubSub = yield* PubSub.unbounded();
|
|
307
445
|
const eventListeners = /* @__PURE__ */ new Set();
|
|
308
|
-
const emitSystemEvent = (event) => Effect.sync(() => notifySystemListeners(eventListeners, event)).pipe(Effect.
|
|
446
|
+
const emitSystemEvent = (event) => Effect.sync(() => notifySystemListeners(eventListeners, event)).pipe(Effect.zipRight(PubSub.publish(eventPubSub, event)), Effect.catchAllCause(() => Effect.void), Effect.asVoid);
|
|
309
447
|
yield* Effect.addFinalizer(() => {
|
|
310
448
|
const stops = [];
|
|
311
449
|
MutableHashMap.forEach(actorsMap, (actor) => {
|
|
312
450
|
stops.push(actor.stop);
|
|
313
451
|
});
|
|
314
|
-
return Effect.all(stops, { concurrency: "unbounded" }).pipe(Effect.
|
|
452
|
+
return Effect.all(stops, { concurrency: "unbounded" }).pipe(Effect.zipRight(PubSub.shutdown(eventPubSub)), Effect.asVoid);
|
|
315
453
|
});
|
|
316
454
|
/** Check for duplicate ID, register actor, attach scope cleanup if available */
|
|
317
455
|
const registerActor = Effect.fn("effect-machine.actorSystem.register")(function* (id, actor) {
|
|
@@ -454,4 +592,4 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
|
|
|
454
592
|
*/
|
|
455
593
|
const Default = Layer.scoped(ActorSystem, make());
|
|
456
594
|
//#endregion
|
|
457
|
-
export { ActorSystem, Default, buildActorRefCore, createActor, notifyListeners, processEventCore, resolveTransition, runSpawnEffects };
|
|
595
|
+
export { ActorSystem, Default, buildActorRefCore, createActor, notifyListeners, processEventCore, resolveTransition, runSpawnEffects, settlePendingReplies };
|
|
@@ -2,7 +2,7 @@ import { processEventCore, runSpawnEffects } from "../internal/transition.js";
|
|
|
2
2
|
import { ActorSystem } from "../actor.js";
|
|
3
3
|
import { Effect, Option, Queue, Ref, Scope } from "effect";
|
|
4
4
|
import { Entity } from "@effect/cluster";
|
|
5
|
-
//#region src
|
|
5
|
+
//#region src/cluster/entity-machine.ts
|
|
6
6
|
/**
|
|
7
7
|
* EntityMachine adapter - wires a machine to a cluster Entity layer.
|
|
8
8
|
*
|
|
@@ -13,7 +13,7 @@ import { Entity } from "@effect/cluster";
|
|
|
13
13
|
* Returns the new state after processing.
|
|
14
14
|
*/
|
|
15
15
|
const processEvent = Effect.fn("effect-machine.cluster.processEvent")(function* (machine, stateRef, event, self, stateScopeRef, system, hooks) {
|
|
16
|
-
const result = yield* processEventCore(machine, yield* Ref.get(stateRef), event, self, stateScopeRef, system, hooks);
|
|
16
|
+
const result = yield* processEventCore(machine, yield* Ref.get(stateRef), event, self, stateScopeRef, system, "*", hooks);
|
|
17
17
|
if (result.transitioned) yield* Ref.set(stateRef, result.newState);
|
|
18
18
|
return result.newState;
|
|
19
19
|
});
|
|
@@ -54,15 +54,17 @@ const EntityMachine = { layer: (entity, machine, options) => {
|
|
|
54
54
|
if (Option.isNone(existingSystem)) return yield* Effect.die("EntityMachine requires ActorSystem in context");
|
|
55
55
|
const system = existingSystem.value;
|
|
56
56
|
const internalQueue = yield* Queue.unbounded();
|
|
57
|
+
const clusterSend = Effect.fn("effect-machine.cluster.self.send")(function* (event) {
|
|
58
|
+
yield* Queue.offer(internalQueue, event);
|
|
59
|
+
});
|
|
57
60
|
const self = {
|
|
58
|
-
send:
|
|
59
|
-
|
|
60
|
-
}),
|
|
61
|
+
send: clusterSend,
|
|
62
|
+
cast: clusterSend,
|
|
61
63
|
spawn: (childId, childMachine) => system.spawn(childId, childMachine).pipe(Effect.provideService(ActorSystem, system))
|
|
62
64
|
};
|
|
63
65
|
const stateRef = yield* Ref.make(initialState);
|
|
64
66
|
const stateScopeRef = { current: yield* Scope.make() };
|
|
65
|
-
yield* runSpawnEffects(machine, initialState, { _tag: "$init" }, self, stateScopeRef.current, system, options?.hooks?.onError);
|
|
67
|
+
yield* runSpawnEffects(machine, initialState, { _tag: "$init" }, self, stateScopeRef.current, system, entityId, options?.hooks?.onError);
|
|
66
68
|
const runInternalEvent = Effect.fn("effect-machine.cluster.internalEvent")(function* () {
|
|
67
69
|
yield* processEvent(machine, stateRef, yield* Queue.take(internalQueue), self, stateScopeRef, system, options?.hooks);
|
|
68
70
|
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region src/errors.d.ts
|
|
4
|
+
declare const DuplicateActorError_base: Schema.TaggedErrorClass<DuplicateActorError, "DuplicateActorError", {
|
|
5
|
+
readonly _tag: Schema.tag<"DuplicateActorError">;
|
|
6
|
+
} & {
|
|
7
|
+
actorId: typeof Schema.String;
|
|
8
|
+
}>;
|
|
9
|
+
/** Attempted to spawn/restore actor with ID already in use */
|
|
10
|
+
declare class DuplicateActorError extends DuplicateActorError_base {}
|
|
11
|
+
declare const UnprovidedSlotsError_base: Schema.TaggedErrorClass<UnprovidedSlotsError, "UnprovidedSlotsError", {
|
|
12
|
+
readonly _tag: Schema.tag<"UnprovidedSlotsError">;
|
|
13
|
+
} & {
|
|
14
|
+
slots: Schema.Array$<typeof Schema.String>;
|
|
15
|
+
}>;
|
|
16
|
+
/** Machine has unprovided effect slots */
|
|
17
|
+
declare class UnprovidedSlotsError extends UnprovidedSlotsError_base {}
|
|
18
|
+
declare const MissingSchemaError_base: Schema.TaggedErrorClass<MissingSchemaError, "MissingSchemaError", {
|
|
19
|
+
readonly _tag: Schema.tag<"MissingSchemaError">;
|
|
20
|
+
} & {
|
|
21
|
+
operation: typeof Schema.String;
|
|
22
|
+
}>;
|
|
23
|
+
/** Operation requires schemas attached to machine */
|
|
24
|
+
declare class MissingSchemaError extends MissingSchemaError_base {}
|
|
25
|
+
declare const InvalidSchemaError_base: Schema.TaggedErrorClass<InvalidSchemaError, "InvalidSchemaError", {
|
|
26
|
+
readonly _tag: Schema.tag<"InvalidSchemaError">;
|
|
27
|
+
}>;
|
|
28
|
+
/** State/Event schema has no variants */
|
|
29
|
+
declare class InvalidSchemaError extends InvalidSchemaError_base {}
|
|
30
|
+
declare const MissingMatchHandlerError_base: Schema.TaggedErrorClass<MissingMatchHandlerError, "MissingMatchHandlerError", {
|
|
31
|
+
readonly _tag: Schema.tag<"MissingMatchHandlerError">;
|
|
32
|
+
} & {
|
|
33
|
+
tag: typeof Schema.String;
|
|
34
|
+
}>;
|
|
35
|
+
/** $match called with missing handler for tag */
|
|
36
|
+
declare class MissingMatchHandlerError extends MissingMatchHandlerError_base {}
|
|
37
|
+
declare const SlotProvisionError_base: Schema.TaggedErrorClass<SlotProvisionError, "SlotProvisionError", {
|
|
38
|
+
readonly _tag: Schema.tag<"SlotProvisionError">;
|
|
39
|
+
} & {
|
|
40
|
+
slotName: typeof Schema.String;
|
|
41
|
+
slotType: Schema.Literal<["guard", "effect"]>;
|
|
42
|
+
}>;
|
|
43
|
+
/** Slot handler not found at runtime (internal error) */
|
|
44
|
+
declare class SlotProvisionError extends SlotProvisionError_base {}
|
|
45
|
+
declare const ProvisionValidationError_base: Schema.TaggedErrorClass<ProvisionValidationError, "ProvisionValidationError", {
|
|
46
|
+
readonly _tag: Schema.tag<"ProvisionValidationError">;
|
|
47
|
+
} & {
|
|
48
|
+
missing: Schema.Array$<typeof Schema.String>;
|
|
49
|
+
extra: Schema.Array$<typeof Schema.String>;
|
|
50
|
+
}>;
|
|
51
|
+
/** Machine.build() validation failed - missing or extra handlers */
|
|
52
|
+
declare class ProvisionValidationError extends ProvisionValidationError_base {}
|
|
53
|
+
declare const AssertionError_base: Schema.TaggedErrorClass<AssertionError, "AssertionError", {
|
|
54
|
+
readonly _tag: Schema.tag<"AssertionError">;
|
|
55
|
+
} & {
|
|
56
|
+
message: typeof Schema.String;
|
|
57
|
+
}>;
|
|
58
|
+
/** Assertion failed in testing utilities */
|
|
59
|
+
declare class AssertionError extends AssertionError_base {}
|
|
60
|
+
declare const ActorStoppedError_base: Schema.TaggedErrorClass<ActorStoppedError, "ActorStoppedError", {
|
|
61
|
+
readonly _tag: Schema.tag<"ActorStoppedError">;
|
|
62
|
+
} & {
|
|
63
|
+
actorId: typeof Schema.String;
|
|
64
|
+
}>;
|
|
65
|
+
/** Actor was stopped while a call/ask was pending */
|
|
66
|
+
declare class ActorStoppedError extends ActorStoppedError_base {}
|
|
67
|
+
declare const NoReplyError_base: Schema.TaggedErrorClass<NoReplyError, "NoReplyError", {
|
|
68
|
+
readonly _tag: Schema.tag<"NoReplyError">;
|
|
69
|
+
} & {
|
|
70
|
+
actorId: typeof Schema.String;
|
|
71
|
+
eventTag: typeof Schema.String;
|
|
72
|
+
}>;
|
|
73
|
+
/** ask() was used but the transition handler did not call reply */
|
|
74
|
+
declare class NoReplyError extends NoReplyError_base {}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
|
-
//#region src
|
|
2
|
+
//#region src/errors.ts
|
|
3
3
|
/**
|
|
4
4
|
* Typed error classes for effect-machine.
|
|
5
5
|
*
|
|
@@ -32,5 +32,12 @@ var ProvisionValidationError = class extends Schema.TaggedError()("ProvisionVali
|
|
|
32
32
|
}) {};
|
|
33
33
|
/** Assertion failed in testing utilities */
|
|
34
34
|
var AssertionError = class extends Schema.TaggedError()("AssertionError", { message: Schema.String }) {};
|
|
35
|
+
/** Actor was stopped while a call/ask was pending */
|
|
36
|
+
var ActorStoppedError = class extends Schema.TaggedError()("ActorStoppedError", { actorId: Schema.String }) {};
|
|
37
|
+
/** ask() was used but the transition handler did not call reply */
|
|
38
|
+
var NoReplyError = class extends Schema.TaggedError()("NoReplyError", {
|
|
39
|
+
actorId: Schema.String,
|
|
40
|
+
eventTag: Schema.String
|
|
41
|
+
}) {};
|
|
35
42
|
//#endregion
|
|
36
|
-
export { AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError };
|
|
43
|
+
export { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { EffectHandlers, EffectSlot, EffectSlots, EffectsDef, EffectsSchema, GuardHandlers, GuardSlot, GuardSlots, GuardsDef, GuardsSchema, MachineContext, Slot } from "./slot.js";
|
|
2
|
+
import { Event, MachineEventSchema, MachineStateSchema, State } from "./schema.js";
|
|
3
|
+
import { PersistenceConfig, PersistentMachine, isPersistentMachine } from "./persistence/persistent-machine.js";
|
|
4
|
+
import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError } from "./errors.js";
|
|
5
|
+
import { ProcessEventResult } from "./internal/transition.js";
|
|
6
|
+
import { PersistentActorRef, createPersistentActor, restorePersistentActor } from "./persistence/persistent-actor.js";
|
|
7
|
+
import { ActorMetadata, PersistedEvent, PersistenceAdapter, PersistenceAdapterTag, PersistenceError, RestoreFailure, RestoreResult, Snapshot, VersionConflictError } from "./persistence/adapter.js";
|
|
8
|
+
import { InMemoryPersistenceAdapter, makeInMemoryPersistenceAdapter } from "./persistence/adapters/in-memory.js";
|
|
9
|
+
import { BackgroundEffect, BuiltMachine, HandlerContext, Machine, MachineRef, MakeConfig, PersistOptions, ProvideHandlers, SpawnEffect, StateHandlerContext, TaskOptions, Transition, machine_d_exports } from "./machine.js";
|
|
10
|
+
import { ActorRef, ActorRefSync, 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, InspectorHandler, SpawnEvent, StopEvent, TaskEvent, TracingInspectorOptions, TransitionEvent, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector } from "./inspection.js";
|
|
13
|
+
export { type ActorMetadata, type ActorRef, type ActorRefSync, ActorStoppedError, type ActorSystem, Default as ActorSystemDefault, ActorSystem as ActorSystemService, type AnyInspectionEvent, AssertionError, type BackgroundEffect, type BuiltMachine, DuplicateActorError, type EffectEvent, type EffectSlots, type EffectsDef, type EffectsSchema, type ErrorEvent, Event, type EventReceivedEvent, type GuardHandlers, type GuardSlot, type GuardSlots, type GuardsDef, type GuardsSchema, type HandlerContext, InMemoryPersistenceAdapter, type InspectionEvent, type Inspector, type InspectorHandler, Inspector as InspectorService, InvalidSchemaError, machine_d_exports as Machine, type MachineContext, type MachineEventSchema, type MachineRef, type MachineStateSchema, type Machine as MachineType, type MakeConfig, MissingMatchHandlerError, MissingSchemaError, NoReplyError, type PersistOptions, type PersistedEvent, type PersistenceAdapter, PersistenceAdapterTag, type PersistenceConfig, PersistenceError, type PersistentActorRef, type PersistentMachine, type ProcessEventResult, type ProvideHandlers, ProvisionValidationError, type RestoreFailure, type RestoreResult, type SimulationResult, Slot, type EffectHandlers as SlotEffectHandlers, type EffectSlot as SlotEffectSlot, SlotProvisionError, type Snapshot, type SpawnEffect, type SpawnEvent, State, type StateHandlerContext, type StopEvent, type SystemEvent, type SystemEventListener, type TaskEvent, type TaskOptions, type TestHarness, type TestHarnessOptions, type TracingInspectorOptions, type Transition, type TransitionEvent, UnprovidedSlotsError, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createPersistentActor, createTestHarness, isPersistentMachine, makeInMemoryPersistenceAdapter, makeInspector, makeInspectorEffect, restorePersistentActor, simulate, tracingInspector };
|
package/v3/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Inspector, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector } from "./inspection.js";
|
|
2
|
+
import { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, 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
|
+
export { ActorStoppedError, Default as ActorSystemDefault, ActorSystem as ActorSystemService, AssertionError, DuplicateActorError, Event, InMemoryPersistenceAdapter, Inspector as InspectorService, InvalidSchemaError, machine_exports as Machine, MissingMatchHandlerError, MissingSchemaError, NoReplyError, PersistenceAdapterTag, PersistenceError, ProvisionValidationError, Slot, SlotProvisionError, State, UnprovidedSlotsError, VersionConflictError, assertNeverReaches, assertPath, assertReaches, collectingInspector, combineInspectors, consoleInspector, createPersistentActor, createTestHarness, isPersistentMachine, makeInMemoryPersistenceAdapter, makeInspector, makeInspectorEffect, restorePersistentActor, simulate, tracingInspector };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Schema } from "effect";
|
|
1
|
+
import { Context, Effect, Schema } from "effect";
|
|
2
2
|
|
|
3
|
-
//#region src
|
|
3
|
+
//#region src/inspection.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Resolve a type param: if it's a Schema, extract `.Type`; otherwise use as-is.
|
|
6
6
|
*/
|
|
@@ -45,6 +45,18 @@ interface EffectEvent<S> {
|
|
|
45
45
|
readonly state: S;
|
|
46
46
|
readonly timestamp: number;
|
|
47
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* Event emitted when a task lifecycle phase occurs
|
|
50
|
+
*/
|
|
51
|
+
interface TaskEvent<S> {
|
|
52
|
+
readonly type: "@machine.task";
|
|
53
|
+
readonly actorId: string;
|
|
54
|
+
readonly state: S;
|
|
55
|
+
readonly taskName?: string;
|
|
56
|
+
readonly phase: "start" | "success" | "failure" | "interrupt";
|
|
57
|
+
readonly error?: string;
|
|
58
|
+
readonly timestamp: number;
|
|
59
|
+
}
|
|
48
60
|
/**
|
|
49
61
|
* Event emitted when a transition handler or spawn effect fails with a defect
|
|
50
62
|
*/
|
|
@@ -69,7 +81,7 @@ interface StopEvent<S> {
|
|
|
69
81
|
/**
|
|
70
82
|
* Union of all inspection events
|
|
71
83
|
*/
|
|
72
|
-
type InspectionEvent<S, E> = SpawnEvent<S> | EventReceivedEvent<S, E> | TransitionEvent<S, E> | EffectEvent<S> | ErrorEvent<S, E> | StopEvent<S>;
|
|
84
|
+
type InspectionEvent<S, E> = SpawnEvent<S> | EventReceivedEvent<S, E> | TransitionEvent<S, E> | EffectEvent<S> | TaskEvent<S> | ErrorEvent<S, E> | StopEvent<S>;
|
|
73
85
|
/**
|
|
74
86
|
* Convenience alias for untyped inspection events.
|
|
75
87
|
* Useful for general-purpose inspectors that don't need specific state/event types.
|
|
@@ -81,19 +93,23 @@ type AnyInspectionEvent = InspectionEvent<{
|
|
|
81
93
|
}, {
|
|
82
94
|
readonly _tag: string;
|
|
83
95
|
}>;
|
|
96
|
+
/**
|
|
97
|
+
* Inspector handler — sync callback or Effect-returning callback.
|
|
98
|
+
*/
|
|
99
|
+
type InspectorHandler<S, E> = (event: InspectionEvent<S, E>) => void | Effect.Effect<void, never, never>;
|
|
84
100
|
/**
|
|
85
101
|
* Inspector interface for observing machine behavior
|
|
86
102
|
*/
|
|
87
103
|
interface Inspector<S, E> {
|
|
88
|
-
readonly onInspect:
|
|
104
|
+
readonly onInspect: InspectorHandler<S, E>;
|
|
89
105
|
}
|
|
90
106
|
/**
|
|
91
107
|
* Inspector service tag - optional service for machine introspection
|
|
92
108
|
* Uses `any` types to allow variance flexibility when providing the service
|
|
93
109
|
*/
|
|
94
|
-
declare const Inspector: any
|
|
110
|
+
declare const Inspector: Context.Tag<Inspector<any, any>, Inspector<any, any>>;
|
|
95
111
|
/**
|
|
96
|
-
* Create an inspector from a callback function.
|
|
112
|
+
* Create an inspector from a sync callback function.
|
|
97
113
|
*
|
|
98
114
|
* Type params accept either raw tagged types or Schema constructors:
|
|
99
115
|
* - `makeInspector(cb)` — defaults to `AnyInspectionEvent`
|
|
@@ -104,7 +120,36 @@ declare const makeInspector: <S = {
|
|
|
104
120
|
readonly _tag: string;
|
|
105
121
|
}, E = {
|
|
106
122
|
readonly _tag: string;
|
|
107
|
-
}>(onInspect:
|
|
123
|
+
}>(onInspect: InspectorHandler<ResolveType<S>, ResolveType<E>>) => Inspector<ResolveType<S>, ResolveType<E>>;
|
|
124
|
+
/**
|
|
125
|
+
* Create an inspector from an Effect-returning callback function.
|
|
126
|
+
*/
|
|
127
|
+
declare const makeInspectorEffect: <S = {
|
|
128
|
+
readonly _tag: string;
|
|
129
|
+
}, E = {
|
|
130
|
+
readonly _tag: string;
|
|
131
|
+
}>(onInspect: (event: InspectionEvent<ResolveType<S>, ResolveType<E>>) => Effect.Effect<void, never, never>) => Inspector<ResolveType<S>, ResolveType<E>>;
|
|
132
|
+
/**
|
|
133
|
+
* Combine multiple inspectors into one. All run concurrently per event.
|
|
134
|
+
* Individual inspector failures are swallowed.
|
|
135
|
+
*/
|
|
136
|
+
declare const combineInspectors: <S, E>(...inspectors: ReadonlyArray<Inspector<S, E>>) => Inspector<S, E>;
|
|
137
|
+
/**
|
|
138
|
+
* Options for the tracing inspector.
|
|
139
|
+
*/
|
|
140
|
+
interface TracingInspectorOptions<S, E> {
|
|
141
|
+
readonly spanName?: string | ((event: InspectionEvent<S, E>) => string);
|
|
142
|
+
readonly attributes?: (event: InspectionEvent<S, E>) => Readonly<Record<string, string | number | boolean>>;
|
|
143
|
+
readonly eventName?: (event: InspectionEvent<S, E>) => string;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Inspector that emits OpenTelemetry spans and events for each inspection event.
|
|
147
|
+
*/
|
|
148
|
+
declare const tracingInspector: <S extends {
|
|
149
|
+
readonly _tag: string;
|
|
150
|
+
}, E extends {
|
|
151
|
+
readonly _tag: string;
|
|
152
|
+
}>(options?: TracingInspectorOptions<S, E>) => Inspector<S, E>;
|
|
108
153
|
/**
|
|
109
154
|
* Console inspector that logs events in a readable format
|
|
110
155
|
*/
|
|
@@ -122,4 +167,4 @@ declare const collectingInspector: <S extends {
|
|
|
122
167
|
readonly _tag: string;
|
|
123
168
|
}>(events: InspectionEvent<S, E>[]) => Inspector<S, E>;
|
|
124
169
|
//#endregion
|
|
125
|
-
export { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, InspectionEvent, Inspector, SpawnEvent, StopEvent, TransitionEvent, collectingInspector, consoleInspector, makeInspector };
|
|
170
|
+
export { AnyInspectionEvent, EffectEvent, ErrorEvent, EventReceivedEvent, InspectionEvent, Inspector, InspectorHandler, SpawnEvent, StopEvent, TaskEvent, TracingInspectorOptions, TransitionEvent, collectingInspector, combineInspectors, consoleInspector, makeInspector, makeInspectorEffect, tracingInspector };
|