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
package/README.md
CHANGED
|
@@ -74,8 +74,12 @@ const orderMachine = Machine.make({
|
|
|
74
74
|
const program = Effect.gen(function* () {
|
|
75
75
|
const actor = yield* Machine.spawn(orderMachine);
|
|
76
76
|
|
|
77
|
+
// fire-and-forget
|
|
77
78
|
yield* actor.send(OrderEvent.Process);
|
|
78
|
-
|
|
79
|
+
|
|
80
|
+
// request-reply — get ProcessEventResult back
|
|
81
|
+
const result = yield* actor.call(OrderEvent.Ship({ trackingId: "TRACK-123" }));
|
|
82
|
+
console.log(result.transitioned); // true
|
|
79
83
|
|
|
80
84
|
const state = yield* actor.waitFor(OrderState.Shipped);
|
|
81
85
|
console.log(state); // Shipped { orderId: "order-1", trackingId: "TRACK-123" }
|
|
@@ -183,6 +187,53 @@ machine.task(State.Loading, ({ effects, state }) => effects.fetchData({ url: sta
|
|
|
183
187
|
});
|
|
184
188
|
```
|
|
185
189
|
|
|
190
|
+
### State Timeouts
|
|
191
|
+
|
|
192
|
+
`.timeout()` — gen_statem-style state timeouts. Timer starts on state entry, cancels on exit:
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
machine
|
|
196
|
+
.timeout(State.Loading, {
|
|
197
|
+
duration: Duration.seconds(30),
|
|
198
|
+
event: Event.Timeout,
|
|
199
|
+
})
|
|
200
|
+
// Dynamic duration from state
|
|
201
|
+
.timeout(State.Retrying, {
|
|
202
|
+
duration: (state) => Duration.seconds(state.backoff),
|
|
203
|
+
event: Event.GiveUp,
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
`.reenter()` restarts the timer with fresh state values.
|
|
208
|
+
|
|
209
|
+
### Event Postpone
|
|
210
|
+
|
|
211
|
+
`.postpone()` — gen_statem-style event postpone. When a matching event arrives in the given state, it is buffered. After the next state transition (tag change), buffered events drain in FIFO order:
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
machine
|
|
215
|
+
.postpone(State.Connecting, Event.Data) // single event
|
|
216
|
+
.postpone(State.Connecting, [Event.Data, Event.Cmd]); // multiple events
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Reply-bearing events (`call`/`ask`) in the postpone buffer are settled with `ActorStoppedError` on stop/interrupt/final-state.
|
|
220
|
+
|
|
221
|
+
### ask / reply
|
|
222
|
+
|
|
223
|
+
Handlers can return a domain reply via `{ state, reply }`:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
.on(State.Active, Event.GetCount, ({ state }) => ({
|
|
227
|
+
state, // stay in same state
|
|
228
|
+
reply: state.count, // domain value returned to caller
|
|
229
|
+
}))
|
|
230
|
+
|
|
231
|
+
// Caller side:
|
|
232
|
+
const count = yield* actor.ask<number>(Event.GetCount);
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
`ask` fails with `NoReplyError` if the handler doesn't provide a reply, and `ActorStoppedError` if the actor stops while the request is pending.
|
|
236
|
+
|
|
186
237
|
### Child Actors
|
|
187
238
|
|
|
188
239
|
Spawn children from `.spawn()` handlers with `self.spawn`. Children are state-scoped — auto-stopped on state exit:
|
|
@@ -253,7 +304,7 @@ See the [primer](./primer/) for comprehensive documentation:
|
|
|
253
304
|
| ----------- | ----------------------------------------- | ------------------------------ |
|
|
254
305
|
| Overview | [index.md](./primer/index.md) | Navigation and quick reference |
|
|
255
306
|
| Basics | [basics.md](./primer/basics.md) | Core concepts |
|
|
256
|
-
| Handlers | [handlers.md](./primer/handlers.md) | Transitions
|
|
307
|
+
| Handlers | [handlers.md](./primer/handlers.md) | Transitions, guards, reply |
|
|
257
308
|
| Effects | [effects.md](./primer/effects.md) | spawn, background, timeouts |
|
|
258
309
|
| Testing | [testing.md](./primer/testing.md) | simulate, harness, assertions |
|
|
259
310
|
| Actors | [actors.md](./primer/actors.md) | ActorSystem, ActorRef |
|
|
@@ -273,6 +324,8 @@ See the [primer](./primer/) for comprehensive documentation:
|
|
|
273
324
|
| `.reenter(State.X, Event.Y, handler)` | Force re-entry on same state |
|
|
274
325
|
| `.spawn(State.X, handler)` | State-scoped effect |
|
|
275
326
|
| `.task(State.X, run, { onSuccess })` | State-scoped task |
|
|
327
|
+
| `.timeout(State.X, { duration, event })` | State timeout (gen_statem) |
|
|
328
|
+
| `.postpone(State.X, Event.Y)` | Postpone event in state (gen_statem) |
|
|
276
329
|
| `.background(handler)` | Machine-lifetime effect |
|
|
277
330
|
| `.final(State.X)` | Mark final state |
|
|
278
331
|
| `.build({ slot: impl })` | Provide implementations, returns `BuiltMachine` (terminal) |
|
|
@@ -308,20 +361,27 @@ See the [primer](./primer/) for comprehensive documentation:
|
|
|
308
361
|
|
|
309
362
|
### Actor
|
|
310
363
|
|
|
311
|
-
| Method | Description
|
|
312
|
-
| -------------------------------- |
|
|
313
|
-
| `actor.send(event)` |
|
|
314
|
-
| `actor.
|
|
315
|
-
| `actor.
|
|
316
|
-
| `actor.
|
|
317
|
-
| `actor.
|
|
318
|
-
| `actor.
|
|
319
|
-
| `actor.
|
|
320
|
-
| `actor.
|
|
321
|
-
| `actor.
|
|
322
|
-
| `actor.
|
|
323
|
-
| `actor.
|
|
324
|
-
| `actor.
|
|
364
|
+
| Method | Description |
|
|
365
|
+
| -------------------------------- | ------------------------------------------- |
|
|
366
|
+
| `actor.send(event)` | Fire-and-forget (queue event) |
|
|
367
|
+
| `actor.cast(event)` | Alias for send (OTP gen_server:cast) |
|
|
368
|
+
| `actor.call(event)` | Request-reply, returns `ProcessEventResult` |
|
|
369
|
+
| `actor.ask<R>(event)` | Typed domain reply from handler |
|
|
370
|
+
| `actor.snapshot` | Get current state |
|
|
371
|
+
| `actor.matches(tag)` | Check state tag |
|
|
372
|
+
| `actor.can(event)` | Can handle event? |
|
|
373
|
+
| `actor.changes` | Stream of changes |
|
|
374
|
+
| `actor.waitFor(State.X)` | Wait for state (constructor or fn) |
|
|
375
|
+
| `actor.awaitFinal` | Wait final state |
|
|
376
|
+
| `actor.sendAndWait(ev, State.X)` | Send + wait for state |
|
|
377
|
+
| `actor.subscribe(fn)` | Sync callback |
|
|
378
|
+
| `actor.sync.send(event)` | Sync fire-and-forget (for UI) |
|
|
379
|
+
| `actor.sync.stop()` | Sync stop |
|
|
380
|
+
| `actor.sync.snapshot()` | Sync get state |
|
|
381
|
+
| `actor.sync.matches(tag)` | Sync check state tag |
|
|
382
|
+
| `actor.sync.can(event)` | Sync can handle event? |
|
|
383
|
+
| `actor.system` | Access the actor's `ActorSystem` |
|
|
384
|
+
| `actor.children` | Child actors (`ReadonlyMap`) |
|
|
325
385
|
|
|
326
386
|
### ActorSystem
|
|
327
387
|
|
package/dist/actor.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EffectsDef, GuardsDef, MachineContext } from "./slot.js";
|
|
2
2
|
import { PersistentMachine } from "./persistence/persistent-machine.js";
|
|
3
|
-
import { DuplicateActorError } from "./errors.js";
|
|
3
|
+
import { ActorStoppedError, DuplicateActorError, NoReplyError } from "./errors.js";
|
|
4
4
|
import { ProcessEventError, ProcessEventHooks, ProcessEventResult, processEventCore, resolveTransition, runSpawnEffects } from "./internal/transition.js";
|
|
5
5
|
import { PersistentActorRef } from "./persistence/persistent-actor.js";
|
|
6
6
|
import { ActorMetadata, PersistenceAdapterTag, PersistenceError, RestoreResult, VersionConflictError } from "./persistence/adapter.js";
|
|
@@ -9,87 +9,77 @@ import { Deferred, Effect, Layer, Option, Queue, Ref, Scope, ServiceMap, Stream,
|
|
|
9
9
|
import * as effect_Tracer0 from "effect/Tracer";
|
|
10
10
|
|
|
11
11
|
//#region src/actor.d.ts
|
|
12
|
-
/**
|
|
13
|
-
|
|
12
|
+
/** Discriminated mailbox request */
|
|
13
|
+
type QueuedEvent<E> = {
|
|
14
|
+
readonly _tag: "send";
|
|
14
15
|
readonly event: E;
|
|
15
|
-
|
|
16
|
+
} | {
|
|
17
|
+
readonly _tag: "call";
|
|
18
|
+
readonly event: E;
|
|
19
|
+
readonly reply: Deferred.Deferred<ProcessEventResult<{
|
|
16
20
|
readonly _tag: string;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
21
|
+
}>, ActorStoppedError>;
|
|
22
|
+
} | {
|
|
23
|
+
readonly _tag: "ask";
|
|
24
|
+
readonly event: E;
|
|
25
|
+
readonly reply: Deferred.Deferred<unknown, NoReplyError | ActorStoppedError>;
|
|
26
|
+
};
|
|
19
27
|
/**
|
|
20
28
|
* Reference to a running actor.
|
|
21
29
|
*/
|
|
30
|
+
/**
|
|
31
|
+
* Sync projection of ActorRef for non-Effect boundaries (React hooks, framework callbacks).
|
|
32
|
+
*/
|
|
33
|
+
interface ActorRefSync<State extends {
|
|
34
|
+
readonly _tag: string;
|
|
35
|
+
}, Event> {
|
|
36
|
+
readonly send: (event: Event) => void;
|
|
37
|
+
readonly stop: () => void;
|
|
38
|
+
readonly snapshot: () => State;
|
|
39
|
+
readonly matches: (tag: State["_tag"]) => boolean;
|
|
40
|
+
readonly can: (event: Event) => boolean;
|
|
41
|
+
}
|
|
22
42
|
interface ActorRef<State extends {
|
|
23
43
|
readonly _tag: string;
|
|
24
44
|
}, Event> {
|
|
25
|
-
/**
|
|
26
|
-
* Unique identifier for this actor
|
|
27
|
-
*/
|
|
28
45
|
readonly id: string;
|
|
29
|
-
/**
|
|
30
|
-
* Send an event to the actor
|
|
31
|
-
*/
|
|
46
|
+
/** Send an event (fire-and-forget). */
|
|
32
47
|
readonly send: (event: Event) => Effect.Effect<void>;
|
|
48
|
+
/** Fire-and-forget alias for send (OTP gen_server:cast). */
|
|
49
|
+
readonly cast: (event: Event) => Effect.Effect<void>;
|
|
33
50
|
/**
|
|
34
|
-
*
|
|
51
|
+
* Serialized request-reply (OTP gen_server:call).
|
|
52
|
+
* Event is processed through the queue; caller gets ProcessEventResult back.
|
|
35
53
|
*/
|
|
36
|
-
readonly
|
|
54
|
+
readonly call: (event: Event) => Effect.Effect<ProcessEventResult<State>>;
|
|
37
55
|
/**
|
|
38
|
-
*
|
|
56
|
+
* Typed request-reply. Event is processed through the queue; caller gets
|
|
57
|
+
* the domain value returned by the handler's `reply` field.
|
|
58
|
+
* Fails with NoReplyError if the handler doesn't provide a reply.
|
|
39
59
|
*/
|
|
60
|
+
readonly ask: <R>(event: Event) => Effect.Effect<R, NoReplyError | ActorStoppedError>;
|
|
61
|
+
/** Observable state. */
|
|
62
|
+
readonly state: SubscriptionRef.SubscriptionRef<State>;
|
|
63
|
+
/** Stop the actor gracefully. */
|
|
40
64
|
readonly stop: Effect.Effect<void>;
|
|
41
|
-
/**
|
|
42
|
-
* Stop the actor (fire-and-forget).
|
|
43
|
-
* Signals graceful shutdown without waiting for completion.
|
|
44
|
-
* Use when stopping from sync contexts (e.g. framework cleanup hooks).
|
|
45
|
-
*/
|
|
46
|
-
readonly stopSync: () => void;
|
|
47
|
-
/**
|
|
48
|
-
* Get current state snapshot (Effect)
|
|
49
|
-
*/
|
|
65
|
+
/** Get current state snapshot. */
|
|
50
66
|
readonly snapshot: Effect.Effect<State>;
|
|
51
|
-
/**
|
|
52
|
-
* Get current state snapshot (sync)
|
|
53
|
-
*/
|
|
54
|
-
readonly snapshotSync: () => State;
|
|
55
|
-
/**
|
|
56
|
-
* Check if current state matches tag (Effect)
|
|
57
|
-
*/
|
|
67
|
+
/** Check if current state matches tag. */
|
|
58
68
|
readonly matches: (tag: State["_tag"]) => Effect.Effect<boolean>;
|
|
59
|
-
/**
|
|
60
|
-
* Check if current state matches tag (sync)
|
|
61
|
-
*/
|
|
62
|
-
readonly matchesSync: (tag: State["_tag"]) => boolean;
|
|
63
|
-
/**
|
|
64
|
-
* Check if event can be handled in current state (Effect)
|
|
65
|
-
*/
|
|
69
|
+
/** Check if event can be handled in current state. */
|
|
66
70
|
readonly can: (event: Event) => Effect.Effect<boolean>;
|
|
67
|
-
/**
|
|
68
|
-
* Check if event can be handled in current state (sync)
|
|
69
|
-
*/
|
|
70
|
-
readonly canSync: (event: Event) => boolean;
|
|
71
|
-
/**
|
|
72
|
-
* Stream of state changes
|
|
73
|
-
*/
|
|
71
|
+
/** Stream of state changes. */
|
|
74
72
|
readonly changes: Stream.Stream<State>;
|
|
75
|
-
/**
|
|
76
|
-
* Wait for a state that matches predicate or state variant (includes current snapshot).
|
|
77
|
-
* Accepts a predicate function or a state constructor/value (e.g. `State.Active`).
|
|
78
|
-
*/
|
|
73
|
+
/** Wait for a state matching predicate or variant (includes current snapshot). */
|
|
79
74
|
readonly waitFor: {
|
|
80
75
|
(predicate: (state: State) => boolean): Effect.Effect<State>;
|
|
81
76
|
(state: {
|
|
82
77
|
readonly _tag: State["_tag"];
|
|
83
78
|
}): Effect.Effect<State>;
|
|
84
79
|
};
|
|
85
|
-
/**
|
|
86
|
-
* Wait for a final state (includes current snapshot)
|
|
87
|
-
*/
|
|
80
|
+
/** Wait for a final state (includes current snapshot). */
|
|
88
81
|
readonly awaitFinal: Effect.Effect<State>;
|
|
89
|
-
/**
|
|
90
|
-
* Send event and wait for predicate, state variant, or final state.
|
|
91
|
-
* Accepts a predicate function or a state constructor/value (e.g. `State.Active`).
|
|
92
|
-
*/
|
|
82
|
+
/** Send event and wait for predicate, state variant, or final state. */
|
|
93
83
|
readonly sendAndWait: {
|
|
94
84
|
(event: Event, predicate: (state: State) => boolean): Effect.Effect<State>;
|
|
95
85
|
(event: Event, state: {
|
|
@@ -97,39 +87,13 @@ interface ActorRef<State extends {
|
|
|
97
87
|
}): Effect.Effect<State>;
|
|
98
88
|
(event: Event): Effect.Effect<State>;
|
|
99
89
|
};
|
|
100
|
-
/**
|
|
101
|
-
* Send event synchronously (fire-and-forget).
|
|
102
|
-
* No-op on stopped actors. Use when you need to send from sync contexts
|
|
103
|
-
* (e.g. framework hooks, event handlers).
|
|
104
|
-
*/
|
|
105
|
-
readonly sendSync: (event: Event) => void;
|
|
106
|
-
/**
|
|
107
|
-
* Send event and wait for the transition result (synchronous processing).
|
|
108
|
-
* The event is processed through the queue (preserving serialization)
|
|
109
|
-
* but the caller gets back the ProcessEventResult.
|
|
110
|
-
*
|
|
111
|
-
* OTP gen_server:call equivalent — use when you need to know what happened.
|
|
112
|
-
*/
|
|
113
|
-
readonly dispatch: (event: Event) => Effect.Effect<ProcessEventResult<State>>;
|
|
114
|
-
/**
|
|
115
|
-
* Promise-based dispatch — send event and get back the transition result.
|
|
116
|
-
* Use at non-Effect boundaries (React event handlers, framework hooks, tests).
|
|
117
|
-
*/
|
|
118
|
-
readonly dispatchPromise: (event: Event) => Promise<ProcessEventResult<State>>;
|
|
119
|
-
/**
|
|
120
|
-
* Subscribe to state changes (sync callback)
|
|
121
|
-
* Returns unsubscribe function
|
|
122
|
-
*/
|
|
90
|
+
/** Subscribe to state changes (sync callback). Returns unsubscribe function. */
|
|
123
91
|
readonly subscribe: (fn: (state: State) => void) => () => void;
|
|
124
|
-
/**
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
*/
|
|
92
|
+
/** Sync helpers for non-Effect boundaries. */
|
|
93
|
+
readonly sync: ActorRefSync<State, Event>;
|
|
94
|
+
/** The actor system this actor belongs to. */
|
|
128
95
|
readonly system: ActorSystem;
|
|
129
|
-
/**
|
|
130
|
-
* Child actors spawned via `self.spawn` in this actor's handlers.
|
|
131
|
-
* State-scoped children are auto-removed on state exit.
|
|
132
|
-
*/
|
|
96
|
+
/** Child actors spawned via `self.spawn` in this actor's handlers. */
|
|
133
97
|
readonly children: ReadonlyMap<string, ActorRef<AnyState, unknown>>;
|
|
134
98
|
}
|
|
135
99
|
/** Base type for stored actors (internal) */
|
|
@@ -295,7 +259,7 @@ declare const buildActorRefCore: <S extends {
|
|
|
295
259
|
readonly _tag: string;
|
|
296
260
|
}, E extends {
|
|
297
261
|
readonly _tag: string;
|
|
298
|
-
}, R, GD extends GuardsDef, EFD extends EffectsDef>(id: string, machine: Machine<S, E, R, any, any, GD, EFD>, stateRef: SubscriptionRef.SubscriptionRef<S>, eventQueue: Queue.Queue<QueuedEvent<E>>, stoppedRef: Ref.Ref<boolean>, listeners: Listeners<S>, stop: Effect.Effect<void>, system: ActorSystem, childrenMap: ReadonlyMap<string, ActorRef<AnyState, unknown>>) => ActorRef<S, E>;
|
|
262
|
+
}, R, GD extends GuardsDef, EFD extends EffectsDef>(id: string, machine: Machine<S, E, R, any, any, GD, EFD>, stateRef: SubscriptionRef.SubscriptionRef<S>, eventQueue: Queue.Queue<QueuedEvent<E>>, stoppedRef: Ref.Ref<boolean>, listeners: Listeners<S>, stop: Effect.Effect<void>, system: ActorSystem, childrenMap: ReadonlyMap<string, ActorRef<AnyState, unknown>>, pendingReplies: Set<Deferred.Deferred<unknown, unknown>>) => ActorRef<S, E>;
|
|
299
263
|
/**
|
|
300
264
|
* Create and start an actor for a machine
|
|
301
265
|
*/
|
|
@@ -304,9 +268,11 @@ declare const createActor: <S extends {
|
|
|
304
268
|
}, E extends {
|
|
305
269
|
readonly _tag: string;
|
|
306
270
|
}, R, GD extends GuardsDef, EFD extends EffectsDef>(id: string, machine: Machine<S, E, R, Record<string, never>, Record<string, never>, GD, EFD>) => Effect.Effect<ActorRef<S, E>, never, Exclude<R, MachineContext<S, E, MachineRef<E>>> | Exclude<Exclude<R, MachineContext<S, E, MachineRef<E>>>, effect_Tracer0.ParentSpan> | Exclude<Exclude<R, MachineContext<S, E, MachineRef<E>>>, Scope.Scope> | Exclude<Exclude<Exclude<R, MachineContext<S, E, MachineRef<E>>>, Scope.Scope>, effect_Tracer0.ParentSpan>>;
|
|
271
|
+
/** Fail all pending call/ask Deferreds with ActorStoppedError. Safe to call multiple times. */
|
|
272
|
+
declare const settlePendingReplies: (pendingReplies: Set<Deferred.Deferred<unknown, unknown>>, actorId: string) => Effect.Effect<void, never, never>;
|
|
307
273
|
/**
|
|
308
274
|
* Default ActorSystem layer
|
|
309
275
|
*/
|
|
310
276
|
declare const Default: Layer.Layer<ActorSystem, never, never>;
|
|
311
277
|
//#endregion
|
|
312
|
-
export { ActorRef, ActorSystem, Default, Listeners, type ProcessEventError, type ProcessEventHooks, type ProcessEventResult, QueuedEvent, SystemEvent, SystemEventListener, buildActorRefCore, createActor, notifyListeners, processEventCore, resolveTransition, runSpawnEffects };
|
|
278
|
+
export { ActorRef, ActorRefSync, ActorSystem, Default, Listeners, type ProcessEventError, type ProcessEventHooks, type ProcessEventResult, QueuedEvent, SystemEvent, SystemEventListener, buildActorRefCore, createActor, notifyListeners, processEventCore, resolveTransition, runSpawnEffects, settlePendingReplies };
|
package/dist/actor.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
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
5
|
import { emitWithTimestamp } from "./internal/inspection.js";
|
|
6
|
-
import { processEventCore, resolveTransition, runSpawnEffects } from "./internal/transition.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, Deferred, Effect, Exit, Fiber, Layer, MutableHashMap, Option, PubSub, Queue, Ref, Scope, Semaphore, ServiceMap, Stream, SubscriptionRef } from "effect";
|
|
@@ -31,12 +31,15 @@ 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
|
+
});
|
|
38
41
|
});
|
|
39
|
-
const
|
|
42
|
+
const call = Effect.fn("effect-machine.actor.call")(function* (event) {
|
|
40
43
|
if (yield* Ref.get(stoppedRef)) {
|
|
41
44
|
const currentState = yield* SubscriptionRef.get(stateRef);
|
|
42
45
|
return {
|
|
@@ -48,11 +51,30 @@ const buildActorRefCore = (id, machine, stateRef, eventQueue, stoppedRef, listen
|
|
|
48
51
|
};
|
|
49
52
|
}
|
|
50
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);
|
|
51
72
|
yield* Queue.offer(eventQueue, {
|
|
73
|
+
_tag: "ask",
|
|
52
74
|
event,
|
|
53
75
|
reply
|
|
54
76
|
});
|
|
55
|
-
return yield* Deferred.await(reply);
|
|
77
|
+
return yield* Deferred.await(reply).pipe(Effect.ensuring(Effect.sync(() => pendingReplies.delete(reply))));
|
|
56
78
|
});
|
|
57
79
|
const snapshot = SubscriptionRef.get(stateRef).pipe(Effect.withSpan("effect-machine.actor.snapshot"));
|
|
58
80
|
const matches = Effect.fn("effect-machine.actor.matches")(function* (tag) {
|
|
@@ -88,32 +110,38 @@ const buildActorRefCore = (id, machine, stateRef, eventQueue, stoppedRef, listen
|
|
|
88
110
|
return {
|
|
89
111
|
id,
|
|
90
112
|
send,
|
|
113
|
+
cast: send,
|
|
114
|
+
call,
|
|
115
|
+
ask,
|
|
91
116
|
state: stateRef,
|
|
92
117
|
stop,
|
|
93
|
-
stopSync: () => Effect.runFork(stop),
|
|
94
118
|
snapshot,
|
|
95
|
-
snapshotSync: () => Effect.runSync(SubscriptionRef.get(stateRef)),
|
|
96
119
|
matches,
|
|
97
|
-
matchesSync: (tag) => Effect.runSync(SubscriptionRef.get(stateRef))._tag === tag,
|
|
98
120
|
can,
|
|
99
|
-
canSync: (event) => {
|
|
100
|
-
return resolveTransition(machine, Effect.runSync(SubscriptionRef.get(stateRef)), event) !== void 0;
|
|
101
|
-
},
|
|
102
121
|
changes: SubscriptionRef.changes(stateRef),
|
|
103
122
|
waitFor,
|
|
104
123
|
awaitFinal,
|
|
105
124
|
sendAndWait,
|
|
106
|
-
sendSync: (event) => {
|
|
107
|
-
if (!Effect.runSync(Ref.get(stoppedRef))) Effect.runSync(Queue.offer(eventQueue, { event }));
|
|
108
|
-
},
|
|
109
|
-
dispatch,
|
|
110
|
-
dispatchPromise: (event) => Effect.runPromise(dispatch(event)),
|
|
111
125
|
subscribe: (fn) => {
|
|
112
126
|
listeners.add(fn);
|
|
113
127
|
return () => {
|
|
114
128
|
listeners.delete(fn);
|
|
115
129
|
};
|
|
116
130
|
},
|
|
131
|
+
sync: {
|
|
132
|
+
send: (event) => {
|
|
133
|
+
if (!Effect.runSync(Ref.get(stoppedRef))) Effect.runSync(Queue.offer(eventQueue, {
|
|
134
|
+
_tag: "send",
|
|
135
|
+
event
|
|
136
|
+
}));
|
|
137
|
+
},
|
|
138
|
+
stop: () => Effect.runFork(stop),
|
|
139
|
+
snapshot: () => Effect.runSync(SubscriptionRef.get(stateRef)),
|
|
140
|
+
matches: (tag) => Effect.runSync(SubscriptionRef.get(stateRef))._tag === tag,
|
|
141
|
+
can: (event) => {
|
|
142
|
+
return resolveTransition(machine, Effect.runSync(SubscriptionRef.get(stateRef)), event) !== void 0;
|
|
143
|
+
}
|
|
144
|
+
},
|
|
117
145
|
system,
|
|
118
146
|
children: childrenMap
|
|
119
147
|
};
|
|
@@ -136,11 +164,16 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
136
164
|
const eventQueue = yield* Queue.unbounded();
|
|
137
165
|
const stoppedRef = yield* Ref.make(false);
|
|
138
166
|
const childrenMap = /* @__PURE__ */ new Map();
|
|
167
|
+
const selfSend = Effect.fn("effect-machine.actor.self.send")(function* (event) {
|
|
168
|
+
if (yield* Ref.get(stoppedRef)) return;
|
|
169
|
+
yield* Queue.offer(eventQueue, {
|
|
170
|
+
_tag: "send",
|
|
171
|
+
event
|
|
172
|
+
});
|
|
173
|
+
});
|
|
139
174
|
const self = {
|
|
140
|
-
send:
|
|
141
|
-
|
|
142
|
-
yield* Queue.offer(eventQueue, { event });
|
|
143
|
-
}),
|
|
175
|
+
send: selfSend,
|
|
176
|
+
cast: selfSend,
|
|
144
177
|
spawn: (childId, childMachine) => Effect.gen(function* () {
|
|
145
178
|
const child = yield* system.spawn(childId, childMachine).pipe(Effect.provideService(ActorSystem, system));
|
|
146
179
|
childrenMap.set(childId, child);
|
|
@@ -194,9 +227,10 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
194
227
|
}));
|
|
195
228
|
yield* Ref.set(stoppedRef, true);
|
|
196
229
|
if (implicitSystemScope !== void 0) yield* Scope.close(implicitSystemScope, Exit.void);
|
|
197
|
-
return buildActorRefCore(id, machine, stateRef, eventQueue, stoppedRef, listeners, Ref.set(stoppedRef, true).pipe(Effect.withSpan("effect-machine.actor.stop"), Effect.asVoid), system, childrenMap);
|
|
230
|
+
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());
|
|
198
231
|
}
|
|
199
|
-
const
|
|
232
|
+
const pendingReplies = /* @__PURE__ */ new Set();
|
|
233
|
+
const loopFiber = yield* Effect.forkDetach(eventLoop(machine, stateRef, eventQueue, stoppedRef, self, listeners, backgroundFibers, stateScopeRef, id, inspectorValue, system, pendingReplies));
|
|
200
234
|
return buildActorRefCore(id, machine, stateRef, eventQueue, stoppedRef, listeners, Effect.gen(function* () {
|
|
201
235
|
const finalState = yield* SubscriptionRef.get(stateRef);
|
|
202
236
|
yield* emitWithTimestamp(inspectorValue, (timestamp) => ({
|
|
@@ -207,33 +241,104 @@ const createActor = Effect.fn("effect-machine.actor.spawn")(function* (id, machi
|
|
|
207
241
|
}));
|
|
208
242
|
yield* Ref.set(stoppedRef, true);
|
|
209
243
|
yield* Fiber.interrupt(loopFiber);
|
|
244
|
+
yield* settlePendingReplies(pendingReplies, id);
|
|
210
245
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
211
246
|
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
212
247
|
if (implicitSystemScope !== void 0) yield* Scope.close(implicitSystemScope, Exit.void);
|
|
213
|
-
}).pipe(Effect.withSpan("effect-machine.actor.stop"), Effect.asVoid), system, childrenMap);
|
|
248
|
+
}).pipe(Effect.withSpan("effect-machine.actor.stop"), Effect.asVoid), system, childrenMap, pendingReplies);
|
|
249
|
+
});
|
|
250
|
+
/** Fail all pending call/ask Deferreds with ActorStoppedError. Safe to call multiple times. */
|
|
251
|
+
const settlePendingReplies = (pendingReplies, actorId) => Effect.sync(() => {
|
|
252
|
+
const error = new ActorStoppedError({ actorId });
|
|
253
|
+
for (const deferred of pendingReplies) Effect.runFork(Deferred.fail(deferred, error));
|
|
254
|
+
pendingReplies.clear();
|
|
214
255
|
});
|
|
215
256
|
/**
|
|
216
|
-
* Main event loop for the actor
|
|
257
|
+
* Main event loop for the actor.
|
|
258
|
+
* Includes postpone buffer — events matching postpone rules are buffered
|
|
259
|
+
* and drained after state tag changes (gen_statem semantics).
|
|
217
260
|
*/
|
|
218
|
-
const eventLoop = Effect.fn("effect-machine.actor.eventLoop")(function* (machine, stateRef, eventQueue, stoppedRef, self, listeners, backgroundFibers, stateScopeRef, actorId, inspector, system) {
|
|
219
|
-
|
|
220
|
-
|
|
261
|
+
const eventLoop = Effect.fn("effect-machine.actor.eventLoop")(function* (machine, stateRef, eventQueue, stoppedRef, self, listeners, backgroundFibers, stateScopeRef, actorId, inspector, system, pendingReplies) {
|
|
262
|
+
const postponed = [];
|
|
263
|
+
const hasPostponeRules = machine.postponeRules.length > 0;
|
|
264
|
+
const processQueued = Effect.fn("effect-machine.actor.processQueued")(function* (queued) {
|
|
265
|
+
const event = queued.event;
|
|
221
266
|
const currentState = yield* SubscriptionRef.get(stateRef);
|
|
267
|
+
if (hasPostponeRules && shouldPostpone(machine, currentState._tag, event._tag)) {
|
|
268
|
+
postponed.push(queued);
|
|
269
|
+
if (queued._tag === "call") {
|
|
270
|
+
const postponedResult = {
|
|
271
|
+
newState: currentState,
|
|
272
|
+
previousState: currentState,
|
|
273
|
+
transitioned: false,
|
|
274
|
+
lifecycleRan: false,
|
|
275
|
+
isFinal: false,
|
|
276
|
+
hasReply: false,
|
|
277
|
+
reply: void 0,
|
|
278
|
+
postponed: true
|
|
279
|
+
};
|
|
280
|
+
yield* Deferred.succeed(queued.reply, postponedResult);
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
shouldStop: false,
|
|
284
|
+
stateChanged: false
|
|
285
|
+
};
|
|
286
|
+
}
|
|
222
287
|
const { shouldStop, result } = yield* Effect.withSpan("effect-machine.event.process", { attributes: {
|
|
223
288
|
"effect_machine.actor.id": actorId,
|
|
224
289
|
"effect_machine.state.current": currentState._tag,
|
|
225
290
|
"effect_machine.event.type": event._tag
|
|
226
291
|
} })(processEvent(machine, currentState, event, stateRef, self, listeners, stateScopeRef, actorId, inspector, system));
|
|
227
|
-
|
|
292
|
+
switch (queued._tag) {
|
|
293
|
+
case "call":
|
|
294
|
+
yield* Deferred.succeed(queued.reply, result);
|
|
295
|
+
break;
|
|
296
|
+
case "ask":
|
|
297
|
+
if (result.hasReply) yield* Deferred.succeed(queued.reply, result.reply);
|
|
298
|
+
else yield* Deferred.fail(queued.reply, new NoReplyError({
|
|
299
|
+
actorId,
|
|
300
|
+
eventTag: event._tag
|
|
301
|
+
}));
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
shouldStop,
|
|
306
|
+
stateChanged: result.lifecycleRan
|
|
307
|
+
};
|
|
308
|
+
});
|
|
309
|
+
while (true) {
|
|
310
|
+
const { shouldStop, stateChanged } = yield* processQueued(yield* Queue.take(eventQueue));
|
|
228
311
|
if (shouldStop) {
|
|
229
312
|
yield* Ref.set(stoppedRef, true);
|
|
313
|
+
settlePostponedBuffer(postponed, pendingReplies, actorId);
|
|
314
|
+
yield* settlePendingReplies(pendingReplies, actorId);
|
|
230
315
|
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
231
316
|
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
232
317
|
return;
|
|
233
318
|
}
|
|
319
|
+
if (stateChanged && postponed.length > 0) {
|
|
320
|
+
const drained = postponed.splice(0);
|
|
321
|
+
for (const entry of drained) if ((yield* processQueued(entry)).shouldStop) {
|
|
322
|
+
yield* Ref.set(stoppedRef, true);
|
|
323
|
+
settlePostponedBuffer(postponed, pendingReplies, actorId);
|
|
324
|
+
yield* settlePendingReplies(pendingReplies, actorId);
|
|
325
|
+
yield* Scope.close(stateScopeRef.current, Exit.void);
|
|
326
|
+
yield* Effect.all(backgroundFibers.map(Fiber.interrupt), { concurrency: "unbounded" });
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
234
330
|
}
|
|
235
331
|
});
|
|
236
332
|
/**
|
|
333
|
+
* Settle all reply-bearing entries in the postpone buffer on shutdown.
|
|
334
|
+
* Call entries already had their Deferred settled with the postponed result
|
|
335
|
+
* (so their pendingReplies entry is already removed). Ask/send entries
|
|
336
|
+
* with Deferreds are settled via the pendingReplies registry.
|
|
337
|
+
*/
|
|
338
|
+
const settlePostponedBuffer = (postponed, _pendingReplies, _actorId) => {
|
|
339
|
+
postponed.length = 0;
|
|
340
|
+
};
|
|
341
|
+
/**
|
|
237
342
|
* Process a single event, returning true if the actor should stop.
|
|
238
343
|
* Wraps processEventCore with actor-specific concerns (inspection, listeners, state ref).
|
|
239
344
|
*/
|
|
@@ -485,4 +590,4 @@ const make = Effect.fn("effect-machine.actorSystem.make")(function* () {
|
|
|
485
590
|
*/
|
|
486
591
|
const Default = Layer.effect(ActorSystem, make());
|
|
487
592
|
//#endregion
|
|
488
|
-
export { ActorSystem, Default, buildActorRefCore, createActor, notifyListeners, processEventCore, resolveTransition, runSpawnEffects };
|
|
593
|
+
export { ActorSystem, Default, buildActorRefCore, createActor, notifyListeners, processEventCore, resolveTransition, runSpawnEffects, settlePendingReplies };
|
|
@@ -54,10 +54,12 @@ 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);
|
package/dist/errors.d.ts
CHANGED
|
@@ -42,5 +42,16 @@ declare const AssertionError_base: Schema.ErrorClass<AssertionError, Schema.Tagg
|
|
|
42
42
|
}>, effect_Cause0.YieldableError>;
|
|
43
43
|
/** Assertion failed in testing utilities */
|
|
44
44
|
declare class AssertionError extends AssertionError_base {}
|
|
45
|
+
declare const ActorStoppedError_base: Schema.ErrorClass<ActorStoppedError, Schema.TaggedStruct<"ActorStoppedError", {
|
|
46
|
+
readonly actorId: Schema.String;
|
|
47
|
+
}>, effect_Cause0.YieldableError>;
|
|
48
|
+
/** Actor was stopped while a call/ask was pending */
|
|
49
|
+
declare class ActorStoppedError extends ActorStoppedError_base {}
|
|
50
|
+
declare const NoReplyError_base: Schema.ErrorClass<NoReplyError, Schema.TaggedStruct<"NoReplyError", {
|
|
51
|
+
readonly actorId: Schema.String;
|
|
52
|
+
readonly eventTag: Schema.String;
|
|
53
|
+
}>, effect_Cause0.YieldableError>;
|
|
54
|
+
/** ask() was used but the transition handler did not call reply */
|
|
55
|
+
declare class NoReplyError extends NoReplyError_base {}
|
|
45
56
|
//#endregion
|
|
46
|
-
export { AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError };
|
|
57
|
+
export { ActorStoppedError, AssertionError, DuplicateActorError, InvalidSchemaError, MissingMatchHandlerError, MissingSchemaError, NoReplyError, ProvisionValidationError, SlotProvisionError, UnprovidedSlotsError };
|
package/dist/errors.js
CHANGED
|
@@ -32,5 +32,12 @@ var ProvisionValidationError = class extends Schema.TaggedErrorClass()("Provisio
|
|
|
32
32
|
}) {};
|
|
33
33
|
/** Assertion failed in testing utilities */
|
|
34
34
|
var AssertionError = class extends Schema.TaggedErrorClass()("AssertionError", { message: Schema.String }) {};
|
|
35
|
+
/** Actor was stopped while a call/ask was pending */
|
|
36
|
+
var ActorStoppedError = class extends Schema.TaggedErrorClass()("ActorStoppedError", { actorId: Schema.String }) {};
|
|
37
|
+
/** ask() was used but the transition handler did not call reply */
|
|
38
|
+
var NoReplyError = class extends Schema.TaggedErrorClass()("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 };
|