xstate 6.0.0-alpha.70 → 6.0.0-alpha.71

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.
Files changed (69) hide show
  1. package/README.md +28 -0
  2. package/bin/agent.js +347 -0
  3. package/bin/xstate.js +16 -0
  4. package/dist/{createActor-11e36865.development.cjs.js → createActor-2136a8ad.development.cjs.js} +528 -461
  5. package/dist/{createActor-eaa95ae0.esm.js → createActor-22a0534b.esm.js} +528 -456
  6. package/dist/{createActor-9529bbaf.development.esm.js → createActor-286a0dbb.development.esm.js} +528 -462
  7. package/dist/{createActor-54296cf2.cjs.js → createActor-f4978450.cjs.js} +528 -455
  8. package/dist/declarations/src/StateMachine.d.ts +5 -3
  9. package/dist/declarations/src/base.types.d.ts +20 -20
  10. package/dist/declarations/src/graph/types.d.ts +22 -1
  11. package/dist/declarations/src/index.d.ts +2 -2
  12. package/dist/declarations/src/serialize.d.ts +14 -0
  13. package/dist/declarations/src/setup.d.ts +3 -1
  14. package/dist/declarations/src/system.d.ts +14 -1
  15. package/dist/declarations/src/types.d.ts +5 -2
  16. package/dist/{effectDescriptor-97802bb8.esm.js → effectDescriptor-2ae7e5e3.esm.js} +1 -1
  17. package/dist/{effectDescriptor-df768c71.development.esm.js → effectDescriptor-86f04325.development.esm.js} +1 -1
  18. package/dist/{effectDescriptor-425644eb.cjs.js → effectDescriptor-a6247f92.cjs.js} +1 -1
  19. package/dist/{effectDescriptor-fd2aaf45.development.cjs.js → effectDescriptor-e41e1627.development.cjs.js} +1 -1
  20. package/dist/{index-9826ee1d.development.cjs.js → index-31b3c878.cjs.js} +3 -3
  21. package/dist/{index-986372f2.cjs.js → index-5ce9cbf9.development.cjs.js} +3 -3
  22. package/dist/{index-e30fe161.development.esm.js → index-6923de25.development.esm.js} +3 -3
  23. package/dist/{index-967ad7fa.esm.js → index-74b77771.esm.js} +3 -3
  24. package/dist/xstate-actors.cjs.js +2 -2
  25. package/dist/xstate-actors.development.cjs.js +2 -2
  26. package/dist/xstate-actors.development.esm.js +2 -2
  27. package/dist/xstate-actors.esm.js +2 -2
  28. package/dist/xstate-actors.umd.min.js +1 -1
  29. package/dist/xstate-actors.umd.min.js.map +1 -1
  30. package/dist/xstate-durable.cjs.js +2 -2
  31. package/dist/xstate-durable.development.cjs.js +2 -2
  32. package/dist/xstate-durable.development.esm.js +2 -2
  33. package/dist/xstate-durable.esm.js +2 -2
  34. package/dist/xstate-durable.umd.min.js +1 -1
  35. package/dist/xstate-durable.umd.min.js.map +1 -1
  36. package/dist/xstate-graph.cjs.js +32 -6
  37. package/dist/xstate-graph.development.cjs.js +32 -6
  38. package/dist/xstate-graph.development.esm.js +33 -7
  39. package/dist/xstate-graph.esm.js +33 -7
  40. package/dist/xstate-graph.umd.min.js +1 -1
  41. package/dist/xstate-graph.umd.min.js.map +1 -1
  42. package/dist/xstate-validation.cjs.js +1 -1
  43. package/dist/xstate-validation.development.cjs.js +1 -1
  44. package/dist/xstate-validation.development.esm.js +1 -1
  45. package/dist/xstate-validation.esm.js +1 -1
  46. package/dist/xstate.cjs.js +161 -49
  47. package/dist/xstate.cjs.mjs +1 -0
  48. package/dist/xstate.development.cjs.js +161 -49
  49. package/dist/xstate.development.cjs.mjs +1 -0
  50. package/dist/xstate.development.esm.js +163 -52
  51. package/dist/xstate.esm.js +163 -52
  52. package/dist/xstate.umd.min.js +1 -1
  53. package/dist/xstate.umd.min.js.map +1 -1
  54. package/docs/agents.md +132 -0
  55. package/docs/api-stability.json +3672 -0
  56. package/docs/context.md +4 -0
  57. package/docs/create-actor.md +3 -2
  58. package/docs/emitted-events.md +20 -1
  59. package/docs/index.md +4 -2
  60. package/docs/model-based-testing.md +3 -1
  61. package/docs/persist-and-restore-actors.md +1 -1
  62. package/docs/persistence.md +2 -2
  63. package/docs/scxml.md +32 -0
  64. package/docs/serialization.md +3 -0
  65. package/docs/systems.md +33 -1
  66. package/docs/transition-functions.md +3 -1
  67. package/docs/transitions.md +4 -2
  68. package/docs/xstate-v5-to-v6.md +16 -1
  69. package/package.json +1 -1
@@ -1,5 +1,392 @@
1
1
  'use strict';
2
2
 
3
+ const STATE_DELIMITER = '.';
4
+ const TARGETLESS_KEY = '';
5
+ const NULL_EVENT = '';
6
+ const STATE_IDENTIFIER = '#';
7
+ const WILDCARD = '*';
8
+ const XSTATE_INIT = 'xstate.init';
9
+ const XSTATE_START = '@xstate.start';
10
+ const XSTATE_SPAWN = '@xstate.spawn';
11
+ /** The event an actor receives when it is stopped. */
12
+ const XSTATE_STOP = 'xstate.stop';
13
+ /** The effect that stops a child actor. */
14
+ const XSTATE_STOP_EFFECT = '@xstate.stop';
15
+ const XSTATE_TERMINATE = '@xstate.terminate';
16
+ const XSTATE_TIMER = 'xstate.timer';
17
+ const XSTATE_LOGIC_EFFECT_RESOLVE = 'xstate.logic.effect.resolve';
18
+ const XSTATE_LOGIC_EFFECT_REJECT = 'xstate.logic.effect.reject';
19
+ const XSTATE_LOGIC_EFFECT_START = 'xstate.logic.effect.start';
20
+
21
+ const emptySubscription = {
22
+ unsubscribe() {}
23
+ };
24
+ const restoreHint = 'or restore this snapshot with embedded children on the runtime that owns them.';
25
+
26
+ /** @internal */
27
+ function isRemoteActorRef(actorRef) {
28
+ return actorRef._remote === true;
29
+ }
30
+
31
+ /**
32
+ * @internal Whether a send target is an actor reference that went through
33
+ * JSON (`actor.toJSON()`): plain data carrying an address, not an actor.
34
+ */
35
+ function isSerializedActorRef(target) {
36
+ if (typeof target !== 'object' || target === null || Array.isArray(target) || typeof target.$actor !== 'string') {
37
+ return false;
38
+ }
39
+ for (const key in target) {
40
+ if (key !== '$actor' && key !== 'incarnation') {
41
+ return false;
42
+ }
43
+ }
44
+ const incarnation = target.incarnation;
45
+ return incarnation === undefined || typeof incarnation === 'string';
46
+ }
47
+
48
+ /** @internal The actor id that the last segment of an address encodes. */
49
+ function getAddressId(address) {
50
+ const segment = address.slice(address.lastIndexOf('/') + 1);
51
+ return segment.includes('%') ? segment.replaceAll('%2F', '/').replaceAll('%25', '%') : segment;
52
+ }
53
+
54
+ /** @internal The error reported when no live actor has a serialized address. */
55
+ function createMissingAddressError(target) {
56
+ return new Error(target.incarnation === undefined ? `Unable to send event to actor '${target.$actor}': no live actor has that address` : `Unable to send event to actor '${target.$actor}' (incarnation '${target.incarnation}'): no live actor has that address and incarnation`);
57
+ }
58
+
59
+ /**
60
+ * @internal The live actor a serialized ref names: the actor at its address,
61
+ * and, when the ref carries an `incarnation`, only that incarnation. A ref
62
+ * without one follows whichever actor is live at the address.
63
+ */
64
+ function resolveSerializedActorRef(system, target) {
65
+ const live = system._getByAddress?.(target.$actor);
66
+ return live && (target.incarnation === undefined || live.sessionId === target.incarnation) ? live : undefined;
67
+ }
68
+
69
+ /**
70
+ * The lifecycle-only snapshot a remote handle exposes. `active` is accurate
71
+ * by construction: a completion removes the child from its parent's
72
+ * `children`, so a handle only exists while the child is presumed active,
73
+ * and the terminal result arrives as a completion event instead of a
74
+ * snapshot. Full snapshots are a co-location capability.
75
+ */
76
+ const remoteSnapshot = Object.freeze({
77
+ status: 'active',
78
+ output: undefined,
79
+ error: undefined
80
+ });
81
+
82
+ /**
83
+ * Creates the inert ref `enq.spawn(...)` returns while a transition is only
84
+ * evaluated (for example by `snapshot.can(...)`, or to resolve conflicting
85
+ * transitions) and no actor is created. It carries the identity the spawn
86
+ * would get, accepts and drops events, exposes the same lifecycle-only
87
+ * snapshot as a remote handle, and serializes like any actor ref. Its address
88
+ * is unknown when the evaluating scope is detached from the parent actor.
89
+ *
90
+ * @internal
91
+ */
92
+ function createInertActorRef(options) {
93
+ const {
94
+ id,
95
+ address
96
+ } = options;
97
+ const handle = {
98
+ ref: undefined,
99
+ id,
100
+ address,
101
+ src: options.src,
102
+ sessionId: undefined,
103
+ send() {},
104
+ getSnapshot() {
105
+ return remoteSnapshot;
106
+ },
107
+ subscribe() {
108
+ return emptySubscription;
109
+ },
110
+ on() {
111
+ return emptySubscription;
112
+ },
113
+ toJSON() {
114
+ if (address === undefined) {
115
+ throw new Error(`Cannot serialize actor ref '${id}': it was returned by a spawn during speculative transition evaluation, which creates no actor and has no parent address.`);
116
+ }
117
+ return {
118
+ $actor: address
119
+ };
120
+ }
121
+ };
122
+ const ref = handle;
123
+ handle.ref = ref;
124
+ return ref;
125
+ }
126
+
127
+ /**
128
+ * Creates a location-transparent handle to an actor whose state lives with
129
+ * another runtime. The handle is constructed from identity alone — no lookup
130
+ * — and every send routes through the system's runtime; its state is not
131
+ * synchronously readable.
132
+ *
133
+ * The surface is deliberately minimal: it covers every member the runtime
134
+ * reaches for a restored child (send/_send, lifecycle via start/_stop and
135
+ * system.stopActor, persistence, subscribe/on as inert subscriptions).
136
+ * Members that only make sense for a co-located actor (public stop(),
137
+ * select(), trigger) throw a descriptive error rather than being absent, so
138
+ * calling one reports what went wrong instead of a bare TypeError. Observable
139
+ * interop and _processingStatus are omitted entirely.
140
+ *
141
+ * @internal
142
+ */
143
+ function createRemoteActorRef(system, options) {
144
+ const handle = {
145
+ _remote: true,
146
+ // Self-reference so context persistence recognizes the handle as an
147
+ // actor reference instead of recursing into it.
148
+ ref: undefined,
149
+ id: options.id,
150
+ address: options.address,
151
+ src: options.src,
152
+ registryKey: options.registryKey,
153
+ // The host-supplied incarnation token, when present: the owner's
154
+ // sessionId for this child, letting this side drop stale completions and
155
+ // journaled sends name the intended incarnation. Without one the handle
156
+ // does not know the child's incarnation and the owning runtime is the
157
+ // authority on staleness.
158
+ sessionId: options.incarnation,
159
+ system,
160
+ _parent: options.parent,
161
+ // Round-trips through persistence verbatim (undefined stays undefined,
162
+ // so re-persisting is byte-stable); a remote handle cannot act on it
163
+ // locally.
164
+ _syncSnapshot: options.syncSnapshot,
165
+ send(event) {
166
+ void system.sendEvent(undefined, ref, event);
167
+ },
168
+ _send(event) {
169
+ throw new Error(`Remote actor '${options.address}' has no local mailbox to receive "${event.type}". Its state lives with another runtime; install a runtime that can reach it (via \`createDurable\`'s adapter runtime operations, or \`system.runtime\`) before sending, ${restoreHint}`);
170
+ },
171
+ getSnapshot() {
172
+ return remoteSnapshot;
173
+ },
174
+ getPersistedSnapshot() {
175
+ throw new Error(`Cannot persist remote actor '${options.address}' from here: its state lives with the runtime that owns it. Persist it there, ${restoreHint}`);
176
+ },
177
+ start() {},
178
+ _stop() {},
179
+ stop() {
180
+ throw new Error(`Cannot stop remote actor '${options.address}' directly: stopping is a co-located operation. Stop it through the system runtime that owns it (\`system.stopActor(ref)\`), ${restoreHint}`);
181
+ },
182
+ select() {
183
+ throw new Error(`Cannot select from remote actor '${options.address}': its snapshot is not synchronously readable because its state lives with another runtime. Read it on the runtime that owns it, ${restoreHint}`);
184
+ },
185
+ get trigger() {
186
+ throw new Error(`Remote actor '${options.address}' has no \`trigger\` shorthand: it requires a co-located actor. Use \`send(...)\`, which routes through the system runtime.`);
187
+ },
188
+ // Observation is a co-location capability: a remote handle never emits,
189
+ // so subscriptions are inert rather than errors — generic observers may
190
+ // attach to any ref.
191
+ subscribe() {
192
+ return emptySubscription;
193
+ },
194
+ on() {
195
+ return emptySubscription;
196
+ },
197
+ _isRunning() {
198
+ return false;
199
+ },
200
+ // The same shape Actor.toJSON produces, so serialized snapshots carry
201
+ // one actor-reference shape whether a child is co-located or remote.
202
+ toJSON() {
203
+ return {
204
+ $actor: options.address
205
+ };
206
+ }
207
+ };
208
+ const ref = handle;
209
+ handle.ref = ref;
210
+ return ref;
211
+ }
212
+
213
+ /** @internal */
214
+ function publishEmittedEvent(source, event, runtime) {
215
+ source.system._notifyEmitted(source, event);
216
+ return runtime.emitEvent(source, event);
217
+ }
218
+ function getStepEffect(actor, key) {
219
+ const effects = actor.getSnapshot().effects;
220
+ return effects && Object.prototype.hasOwnProperty.call(effects, key) ? effects[key] : undefined;
221
+ }
222
+
223
+ // Live promises belong to an actor incarnation, unlike its persisted journal.
224
+ // A restored active record has no promise here and must be retried locally.
225
+ const pendingSteps = new WeakMap();
226
+
227
+ /**
228
+ * Runs one keyed step of an async actor with the built-in journal: the
229
+ * result is memoized in the actor's own snapshot (`effects[key]`), so a
230
+ * restored actor skips completed steps when its logic function re-runs.
231
+ * Custom runtimes that implement `runStep` use this for the default local
232
+ * behavior, the same way `deliverEvent` exposes local delivery.
233
+ *
234
+ * @experimental
235
+ */
236
+ async function runStep(actor, key, exec, sendSelf = event => void actor.system.sendEvent(actor, actor, event)) {
237
+ const effect = getStepEffect(actor, key);
238
+ if (effect?.status === 'done') {
239
+ return effect.output;
240
+ }
241
+ if (effect?.status === 'error') {
242
+ throw effect.error;
243
+ }
244
+ const running = pendingSteps.get(actor)?.get(key);
245
+ if (running) {
246
+ return running;
247
+ }
248
+ if (actor.getSnapshot().status !== 'active') {
249
+ throw new Error(`Actor terminated before step "${key}" completed`);
250
+ }
251
+ let resolve;
252
+ let reject;
253
+ const promise = new Promise((resolvePromise, rejectPromise) => {
254
+ resolve = resolvePromise;
255
+ reject = rejectPromise;
256
+ });
257
+ let steps = pendingSteps.get(actor);
258
+ if (!steps) {
259
+ steps = new Map();
260
+ pendingSteps.set(actor, steps);
261
+ }
262
+ steps.set(key, promise);
263
+ // oxlint-disable-next-line prefer-const
264
+ let subscription;
265
+ const cleanup = () => {
266
+ subscription?.unsubscribe();
267
+ steps.delete(key);
268
+ if (!steps.size) {
269
+ pendingSteps.delete(actor);
270
+ }
271
+ };
272
+ void promise.then(cleanup, cleanup);
273
+ subscription = actor.subscribe({
274
+ error: reject,
275
+ complete: () => reject(new Error(`Actor terminated before step "${key}" completed`))
276
+ });
277
+ void (async () => {
278
+ try {
279
+ sendSelf({
280
+ type: XSTATE_LOGIC_EFFECT_START,
281
+ key
282
+ });
283
+ const output = await exec();
284
+ if (actor.getSnapshot().status === 'active') {
285
+ sendSelf({
286
+ type: XSTATE_LOGIC_EFFECT_RESOLVE,
287
+ key,
288
+ output
289
+ });
290
+ resolve(output);
291
+ }
292
+ } catch (error) {
293
+ if (actor.getSnapshot().status === 'active') {
294
+ sendSelf({
295
+ type: XSTATE_LOGIC_EFFECT_REJECT,
296
+ key,
297
+ error
298
+ });
299
+ }
300
+ reject(error);
301
+ }
302
+ })().catch(reject);
303
+ return promise;
304
+ }
305
+
306
+ /**
307
+ * Delivers an event directly to a target actor, bypassing any installed host
308
+ * runtime. Custom runtimes use this for the default local delivery behavior
309
+ * inside their own `sendEvent` implementations.
310
+ *
311
+ * @experimental
312
+ */
313
+ function deliverEvent(source, target, event) {
314
+ if (isSerializedActorRef(target)) {
315
+ const serialized = target;
316
+ const system = source?.system;
317
+ const live = system && resolveSerializedActorRef(system, serialized);
318
+ if (!live) {
319
+ const error = createMissingAddressError(serialized);
320
+ if (!system) {
321
+ throw error;
322
+ }
323
+ void system.deadLetter(source, undefined, event, 'missingTarget', {
324
+ targetId: getAddressId(serialized.$actor),
325
+ error
326
+ });
327
+ return;
328
+ }
329
+ target = live;
330
+ }
331
+ if (rejectUndeliverableEvent(source, target, event)) {
332
+ return;
333
+ }
334
+ const runtimeTarget = target;
335
+ runtimeTarget._send(event, source);
336
+ }
337
+
338
+ /**
339
+ * Returns the boundary error preventing this delivery, if any: an internal
340
+ * event type cannot cross an actor boundary from an external sender.
341
+ */
342
+ function getEventBoundaryError(source, target, event) {
343
+ const runtimeTarget = target;
344
+ if (source !== target && runtimeTarget.logic?.isInternalEventType?.(event.type)) {
345
+ return new Error(`Internal event "${event.type}" cannot be sent to actor "${target.id}" from outside.`);
346
+ }
347
+ return undefined;
348
+ }
349
+
350
+ /**
351
+ * Rejects an event that must not cross the delivery boundary — an internal
352
+ * event type sent from outside its owning actor — by reporting it as a dead
353
+ * letter. Returns `true` when the event was rejected and must not be
354
+ * delivered. Host runtimes must call this before taking ownership of
355
+ * delivery.
356
+ */
357
+ function rejectUndeliverableEvent(source, target, event) {
358
+ const error = getEventBoundaryError(source, target, event);
359
+ if (error) {
360
+ void target.system.deadLetter(source, target, event, 'internalEvent', {
361
+ error
362
+ });
363
+ return true;
364
+ }
365
+ return false;
366
+ }
367
+
368
+ /**
369
+ * Publishes an actor's terminal result, notifying its parent and observers.
370
+ * Custom runtimes use this for the default local behavior inside their own
371
+ * `terminateActor` implementations.
372
+ *
373
+ * @experimental
374
+ */
375
+ function terminateActor(actor, termination) {
376
+ actor._terminate(termination);
377
+ }
378
+
379
+ /**
380
+ * Stops an actor without producing a completion result. Custom runtimes use
381
+ * this for the default local behavior inside their own `stopActor`
382
+ * implementations.
383
+ *
384
+ * @experimental
385
+ */
386
+ function stopActor(actor) {
387
+ actor._stop();
388
+ }
389
+
3
390
  class Mailbox {
4
391
  constructor(_process) {
5
392
  this._process = _process;
@@ -36,34 +423,16 @@ class Mailbox {
36
423
  }
37
424
  }
38
425
  flush() {
39
- while (this._current) {
40
- // atm the given _process is responsible for implementing proper try/catch handling
41
- // we assume here that this won't throw in a way that can affect this mailbox
42
- const consumed = this._current;
43
- this._process(consumed.value);
44
- this._current = consumed.next;
45
- }
46
- this._last = null;
47
- }
48
- }
49
-
50
- const STATE_DELIMITER = '.';
51
- const TARGETLESS_KEY = '';
52
- const NULL_EVENT = '';
53
- const STATE_IDENTIFIER = '#';
54
- const WILDCARD = '*';
55
- const XSTATE_INIT = 'xstate.init';
56
- const XSTATE_START = '@xstate.start';
57
- const XSTATE_SPAWN = '@xstate.spawn';
58
- /** The event an actor receives when it is stopped. */
59
- const XSTATE_STOP = 'xstate.stop';
60
- /** The effect that stops a child actor. */
61
- const XSTATE_STOP_EFFECT = '@xstate.stop';
62
- const XSTATE_TERMINATE = '@xstate.terminate';
63
- const XSTATE_TIMER = 'xstate.timer';
64
- const XSTATE_LOGIC_EFFECT_RESOLVE = 'xstate.logic.effect.resolve';
65
- const XSTATE_LOGIC_EFFECT_REJECT = 'xstate.logic.effect.reject';
66
- const XSTATE_LOGIC_EFFECT_START = 'xstate.logic.effect.start';
426
+ while (this._current) {
427
+ // atm the given _process is responsible for implementing proper try/catch handling
428
+ // we assume here that this won't throw in a way that can affect this mailbox
429
+ const consumed = this._current;
430
+ this._process(consumed.value);
431
+ this._current = consumed.next;
432
+ }
433
+ this._last = null;
434
+ }
435
+ }
67
436
 
68
437
  /**
69
438
  * Returns an event that represents an implicit event that is sent after the
@@ -543,254 +912,62 @@ function createListenerLogic() {
543
912
  }
544
913
 
545
914
  /** @internal The logic of helper actors created by `enq.listen()`. */
546
- const listenerLogic = /* #__PURE__ */createListenerLogic();
547
-
548
- /** @public */
549
-
550
- /** @public */
551
-
552
- /** @public */
553
-
554
- /** @public */
555
-
556
- /** @public */
557
-
558
- /**
559
- * Creates actor logic for subscribing to lifecycle events (done/error/snapshot)
560
- * from another actor. Used internally by `enq.subscribeTo()`.
561
- *
562
- * @public
563
- */
564
- function createSubscriptionLogic() {
565
- return createAttachedLogic(({
566
- actor,
567
- mappers
568
- }, {
569
- self,
570
- system
571
- }) => {
572
- const {
573
- done,
574
- error,
575
- snapshot: onSnapshot
576
- } = mappers;
577
- return actor.subscribe({
578
- next: snapshot => {
579
- if (snapshot.status === 'done' && done) {
580
- relayMappedToParent(self, system, () => done(snapshot.output));
581
- } else if (snapshot.status === 'error' && error) {
582
- relayMappedToParent(self, system, () => error(snapshot.error));
583
- } else if (snapshot.status === 'active' && onSnapshot) {
584
- relayMappedToParent(self, system, () => onSnapshot(snapshot));
585
- }
586
- },
587
- error: err => {
588
- if (error) {
589
- relayMappedToParent(self, system, () => error(err));
590
- }
591
- },
592
- complete: () => {
593
- // Actor completed without output (stopped); no action needed
594
- }
595
- });
596
- }, '@xstate.subscription');
597
- }
598
-
599
- /** @internal The logic of helper actors created by `enq.subscribeTo()`. */
600
- const subscriptionLogic = /* #__PURE__ */createSubscriptionLogic();
601
-
602
- const emptySubscription = {
603
- unsubscribe() {}
604
- };
605
- const restoreHint = 'or restore this snapshot with embedded children on the runtime that owns them.';
606
-
607
- /** @internal */
608
- function isRemoteActorRef(actorRef) {
609
- return actorRef._remote === true;
610
- }
611
-
612
- /**
613
- * @internal Whether a send target is an actor reference that went through
614
- * JSON (`actor.toJSON()`): plain data carrying an address, not an actor.
615
- */
616
- function isSerializedActorRef(target) {
617
- if (typeof target !== 'object' || target === null || Array.isArray(target) || typeof target.$actor !== 'string') {
618
- return false;
619
- }
620
- for (const key in target) {
621
- if (key !== '$actor' && key !== 'incarnation') {
622
- return false;
623
- }
624
- }
625
- const incarnation = target.incarnation;
626
- return incarnation === undefined || typeof incarnation === 'string';
627
- }
628
-
629
- /** @internal The actor id that the last segment of an address encodes. */
630
- function getAddressId(address) {
631
- const segment = address.slice(address.lastIndexOf('/') + 1);
632
- return segment.includes('%') ? segment.replaceAll('%2F', '/').replaceAll('%25', '%') : segment;
633
- }
634
-
635
- /** @internal The error reported when no live actor has a serialized address. */
636
- function createMissingAddressError(target) {
637
- return new Error(target.incarnation === undefined ? `Unable to send event to actor '${target.$actor}': no live actor has that address` : `Unable to send event to actor '${target.$actor}' (incarnation '${target.incarnation}'): no live actor has that address and incarnation`);
638
- }
639
-
640
- /**
641
- * @internal The live actor a serialized ref names: the actor at its address,
642
- * and, when the ref carries an `incarnation`, only that incarnation. A ref
643
- * without one follows whichever actor is live at the address.
644
- */
645
- function resolveSerializedActorRef(system, target) {
646
- const live = system._getByAddress?.(target.$actor);
647
- return live && (target.incarnation === undefined || live.sessionId === target.incarnation) ? live : undefined;
648
- }
649
-
650
- /**
651
- * The lifecycle-only snapshot a remote handle exposes. `active` is accurate
652
- * by construction: a completion removes the child from its parent's
653
- * `children`, so a handle only exists while the child is presumed active,
654
- * and the terminal result arrives as a completion event instead of a
655
- * snapshot. Full snapshots are a co-location capability.
656
- */
657
- const remoteSnapshot = Object.freeze({
658
- status: 'active',
659
- output: undefined,
660
- error: undefined
661
- });
662
-
663
- /**
664
- * Creates the inert ref `enq.spawn(...)` returns while a transition is only
665
- * evaluated (for example by `snapshot.can(...)`, or to resolve conflicting
666
- * transitions) and no actor is created. It carries the identity the spawn
667
- * would get, accepts and drops events, exposes the same lifecycle-only
668
- * snapshot as a remote handle, and serializes like any actor ref. Its address
669
- * is unknown when the evaluating scope is detached from the parent actor.
670
- *
671
- * @internal
672
- */
673
- function createInertActorRef(options) {
674
- const {
675
- id,
676
- address
677
- } = options;
678
- const handle = {
679
- ref: undefined,
680
- id,
681
- address,
682
- src: options.src,
683
- sessionId: undefined,
684
- send() {},
685
- getSnapshot() {
686
- return remoteSnapshot;
687
- },
688
- subscribe() {
689
- return emptySubscription;
690
- },
691
- on() {
692
- return emptySubscription;
693
- },
694
- toJSON() {
695
- if (address === undefined) {
696
- throw new Error(`Cannot serialize actor ref '${id}': it was returned by a spawn during speculative transition evaluation, which creates no actor and has no parent address.`);
697
- }
698
- return {
699
- $actor: address
700
- };
701
- }
702
- };
703
- const ref = handle;
704
- handle.ref = ref;
705
- return ref;
706
- }
707
-
708
- /**
709
- * Creates a location-transparent handle to an actor whose state lives with
710
- * another runtime. The handle is constructed from identity alone — no lookup
711
- * — and every send routes through the system's runtime; its state is not
712
- * synchronously readable.
713
- *
714
- * The surface is deliberately minimal: it covers every member the runtime
715
- * reaches for a restored child (send/_send, lifecycle via start/_stop and
716
- * system.stopActor, persistence, subscribe/on as inert subscriptions).
717
- * Members that only make sense for a co-located actor (public stop(),
718
- * select(), trigger) throw a descriptive error rather than being absent, so
719
- * calling one reports what went wrong instead of a bare TypeError. Observable
720
- * interop and _processingStatus are omitted entirely.
721
- *
722
- * @internal
723
- */
724
- function createRemoteActorRef(system, options) {
725
- const handle = {
726
- _remote: true,
727
- // Self-reference so context persistence recognizes the handle as an
728
- // actor reference instead of recursing into it.
729
- ref: undefined,
730
- id: options.id,
731
- address: options.address,
732
- src: options.src,
733
- registryKey: options.registryKey,
734
- // The host-supplied incarnation token, when present: the owner's
735
- // sessionId for this child, letting this side drop stale completions and
736
- // journaled sends name the intended incarnation. Without one the handle
737
- // does not know the child's incarnation and the owning runtime is the
738
- // authority on staleness.
739
- sessionId: options.incarnation,
740
- system,
741
- _parent: options.parent,
742
- // Round-trips through persistence verbatim (undefined stays undefined,
743
- // so re-persisting is byte-stable); a remote handle cannot act on it
744
- // locally.
745
- _syncSnapshot: options.syncSnapshot,
746
- send(event) {
747
- void system.sendEvent(undefined, ref, event);
748
- },
749
- _send(event) {
750
- throw new Error(`Remote actor '${options.address}' has no local mailbox to receive "${event.type}". Its state lives with another runtime; install a runtime that can reach it (via \`createDurable\`'s adapter runtime operations, or \`system.runtime\`) before sending, ${restoreHint}`);
751
- },
752
- getSnapshot() {
753
- return remoteSnapshot;
754
- },
755
- getPersistedSnapshot() {
756
- throw new Error(`Cannot persist remote actor '${options.address}' from here: its state lives with the runtime that owns it. Persist it there, ${restoreHint}`);
757
- },
758
- start() {},
759
- _stop() {},
760
- stop() {
761
- throw new Error(`Cannot stop remote actor '${options.address}' directly: stopping is a co-located operation. Stop it through the system runtime that owns it (\`system.stopActor(ref)\`), ${restoreHint}`);
762
- },
763
- select() {
764
- throw new Error(`Cannot select from remote actor '${options.address}': its snapshot is not synchronously readable because its state lives with another runtime. Read it on the runtime that owns it, ${restoreHint}`);
765
- },
766
- get trigger() {
767
- throw new Error(`Remote actor '${options.address}' has no \`trigger\` shorthand: it requires a co-located actor. Use \`send(...)\`, which routes through the system runtime.`);
768
- },
769
- // Observation is a co-location capability: a remote handle never emits,
770
- // so subscriptions are inert rather than errors — generic observers may
771
- // attach to any ref.
772
- subscribe() {
773
- return emptySubscription;
774
- },
775
- on() {
776
- return emptySubscription;
777
- },
778
- _isRunning() {
779
- return false;
780
- },
781
- // The same shape Actor.toJSON produces, so serialized snapshots carry
782
- // one actor-reference shape whether a child is co-located or remote.
783
- toJSON() {
784
- return {
785
- $actor: options.address
786
- };
787
- }
788
- };
789
- const ref = handle;
790
- handle.ref = ref;
791
- return ref;
915
+ const listenerLogic = /* #__PURE__ */createListenerLogic();
916
+
917
+ /** @public */
918
+
919
+ /** @public */
920
+
921
+ /** @public */
922
+
923
+ /** @public */
924
+
925
+ /** @public */
926
+
927
+ /**
928
+ * Creates actor logic for subscribing to lifecycle events (done/error/snapshot)
929
+ * from another actor. Used internally by `enq.subscribeTo()`.
930
+ *
931
+ * @public
932
+ */
933
+ function createSubscriptionLogic() {
934
+ return createAttachedLogic(({
935
+ actor,
936
+ mappers
937
+ }, {
938
+ self,
939
+ system
940
+ }) => {
941
+ const {
942
+ done,
943
+ error,
944
+ snapshot: onSnapshot
945
+ } = mappers;
946
+ return actor.subscribe({
947
+ next: snapshot => {
948
+ if (snapshot.status === 'done' && done) {
949
+ relayMappedToParent(self, system, () => done(snapshot.output));
950
+ } else if (snapshot.status === 'error' && error) {
951
+ relayMappedToParent(self, system, () => error(snapshot.error));
952
+ } else if (snapshot.status === 'active' && onSnapshot) {
953
+ relayMappedToParent(self, system, () => onSnapshot(snapshot));
954
+ }
955
+ },
956
+ error: err => {
957
+ if (error) {
958
+ relayMappedToParent(self, system, () => error(err));
959
+ }
960
+ },
961
+ complete: () => {
962
+ // Actor completed without output (stopped); no action needed
963
+ }
964
+ });
965
+ }, '@xstate.subscription');
792
966
  }
793
967
 
968
+ /** @internal The logic of helper actors created by `enq.subscribeTo()`. */
969
+ const subscriptionLogic = /* #__PURE__ */createSubscriptionLogic();
970
+
794
971
  function execCustomEffect() {
795
972
  const result = this.action?.(...this.args);
796
973
  {
@@ -821,7 +998,7 @@ function warnOnIgnoredEffectResult(effect, result) {
821
998
  console.warn(`Action "${effect.type || '(anonymous)'}" returned { ${keys.join(', ')} }, which is ignored: functions passed to enq(...) run as effects after the transition. Return the patch from the transition, entry or exit function instead; a named action can be called there directly and its result returned.`);
822
999
  }
823
1000
  function execEmitEffect(runtime = this.source.system) {
824
- return runtime.emitEvent(this.source, this.event);
1001
+ return publishEmittedEvent(this.source, this.event, runtime);
825
1002
  }
826
1003
 
827
1004
  /** @internal Creates an emitted-event effect. */
@@ -1945,6 +2122,8 @@ function createSnapshotSystem(baseSystem, children, baseState) {
1945
2122
  },
1946
2123
  get: registryKey => keyedActors.get(registryKey),
1947
2124
  getAll: () => Object.fromEntries(keyedActors),
2125
+ onEmitted: listener => baseSystem.onEmitted(listener),
2126
+ _notifyEmitted: (actorRef, event) => baseSystem._notifyEmitted(actorRef, event),
1948
2127
  // Pure transition resolution must not leak topology inspection events
1949
2128
  // into a live runtime system — planning branches stay silent. The one
1950
2129
  // exception is a durable execution's own transitions (marked by the
@@ -3574,10 +3753,9 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3574
3753
  }
3575
3754
  }
3576
3755
  if (contextChangedByEntry) {
3577
- nextState.context = context;
3578
- {
3579
- freezeContext(context);
3580
- }
3756
+ nextState = cloneMachineSnapshot(nextState, {
3757
+ context
3758
+ });
3581
3759
  }
3582
3760
  if (statesForDefaultEntry.has(stateNodeToEnter)) {
3583
3761
  const defaultTransitions = [stateNodeToEnter.initial, ...(historyDefaultsByParent.get(stateNodeToEnter) ?? [])].filter(Boolean);
@@ -3595,10 +3773,9 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3595
3773
  internalQueue.push(...initialInternalEvents);
3596
3774
  }
3597
3775
  if (initialContext !== undefined) {
3598
- nextState.context = mergeContextPatch(nextState.context, initialContext);
3599
- {
3600
- freezeContext(nextState.context);
3601
- }
3776
+ nextState = cloneMachineSnapshot(nextState, {
3777
+ context: mergeContextPatch(nextState.context, initialContext)
3778
+ });
3602
3779
  }
3603
3780
  if (initialInput && defaultTransition.target) {
3604
3781
  for (const targetNode of defaultTransition.target) {
@@ -3665,6 +3842,27 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
3665
3842
  context
3666
3843
  });
3667
3844
  }
3845
+ const transitionContent = nextState.machine._microstepHooks?.transitionContent?.(filteredTransitions, [...mutStateNodeSet]);
3846
+ if (transitionContent) {
3847
+ const source = filteredTransitions[0].source;
3848
+ const [actions, nextContext, raisedEvents, nextChildren] = getStateActionsAndContext(transitionContent, nextState.context, nextState.children, getStateInput(nextState, source.id), 'transition', source);
3849
+ if (raisedEvents?.length) {
3850
+ internalQueue.push(...raisedEvents);
3851
+ }
3852
+ if (nextContext || nextChildren) {
3853
+ nextState = cloneMachineSnapshot(nextState, {
3854
+ ...(nextContext ? {
3855
+ context: nextContext
3856
+ } : {}),
3857
+ ...(nextChildren ? {
3858
+ children: nextChildren
3859
+ } : {})
3860
+ });
3861
+ }
3862
+ const [resolvedState, effects] = resolveActionsWithContext(nextState, event, actorScope, actions);
3863
+ nextState = resolvedState;
3864
+ executableActions.push(...effects);
3865
+ }
3668
3866
 
3669
3867
  // Enter states
3670
3868
  if (isInitial || changesState) {
@@ -4055,7 +4253,7 @@ function hasEffect(transition, context, event, snapshot, actorScope) {
4055
4253
  function assertSyncTransitionResult(res, event, sourceId, kind) {
4056
4254
  if (res && typeof res.then === 'function') {
4057
4255
  void Promise.resolve(res).catch(() => {});
4058
- throw new Error(kind ? `${kind === 'entry' ? 'Entry' : 'Exit'} functions must be synchronous. The ${kind} function of state "${sourceId}" returned a promise (event "${event.type}"). Move async work into an invoked or spawned actor, or enq.effect.` : `Transition functions must be synchronous. Transition for event "${event.type}" in state "${sourceId}" returned a promise. Move async work into an invoked or spawned actor, or enq.effect.`);
4256
+ throw new Error(kind && kind !== 'transition' ? `${kind === 'entry' ? 'Entry' : 'Exit'} functions must be synchronous. The ${kind} function of state "${sourceId}" returned a promise (event "${event.type}"). Move async work into an invoked or spawned actor, or enq.effect.` : `Transition functions must be synchronous. Transition for event "${event.type}" in state "${sourceId}" returned a promise. Move async work into an invoked or spawned actor, or enq.effect.`);
4059
4257
  }
4060
4258
  }
4061
4259
  function createTransitionSelection(parent) {
@@ -5042,178 +5240,6 @@ function matchesEventDescriptor(eventType, descriptor) {
5042
5240
  return true;
5043
5241
  }
5044
5242
 
5045
- function getStepEffect(actor, key) {
5046
- const effects = actor.getSnapshot().effects;
5047
- return effects && Object.prototype.hasOwnProperty.call(effects, key) ? effects[key] : undefined;
5048
- }
5049
-
5050
- // Live promises belong to an actor incarnation, unlike its persisted journal.
5051
- // A restored active record has no promise here and must be retried locally.
5052
- const pendingSteps = new WeakMap();
5053
-
5054
- /**
5055
- * Runs one keyed step of an async actor with the built-in journal: the
5056
- * result is memoized in the actor's own snapshot (`effects[key]`), so a
5057
- * restored actor skips completed steps when its logic function re-runs.
5058
- * Custom runtimes that implement `runStep` use this for the default local
5059
- * behavior, the same way `deliverEvent` exposes local delivery.
5060
- *
5061
- * @experimental
5062
- */
5063
- async function runStep(actor, key, exec, sendSelf = event => void actor.system.sendEvent(actor, actor, event)) {
5064
- const effect = getStepEffect(actor, key);
5065
- if (effect?.status === 'done') {
5066
- return effect.output;
5067
- }
5068
- if (effect?.status === 'error') {
5069
- throw effect.error;
5070
- }
5071
- const running = pendingSteps.get(actor)?.get(key);
5072
- if (running) {
5073
- return running;
5074
- }
5075
- if (actor.getSnapshot().status !== 'active') {
5076
- throw new Error(`Actor terminated before step "${key}" completed`);
5077
- }
5078
- let resolve;
5079
- let reject;
5080
- const promise = new Promise((resolvePromise, rejectPromise) => {
5081
- resolve = resolvePromise;
5082
- reject = rejectPromise;
5083
- });
5084
- let steps = pendingSteps.get(actor);
5085
- if (!steps) {
5086
- steps = new Map();
5087
- pendingSteps.set(actor, steps);
5088
- }
5089
- steps.set(key, promise);
5090
- // oxlint-disable-next-line prefer-const
5091
- let subscription;
5092
- const cleanup = () => {
5093
- subscription?.unsubscribe();
5094
- steps.delete(key);
5095
- if (!steps.size) {
5096
- pendingSteps.delete(actor);
5097
- }
5098
- };
5099
- void promise.then(cleanup, cleanup);
5100
- subscription = actor.subscribe({
5101
- error: reject,
5102
- complete: () => reject(new Error(`Actor terminated before step "${key}" completed`))
5103
- });
5104
- void (async () => {
5105
- try {
5106
- sendSelf({
5107
- type: XSTATE_LOGIC_EFFECT_START,
5108
- key
5109
- });
5110
- const output = await exec();
5111
- if (actor.getSnapshot().status === 'active') {
5112
- sendSelf({
5113
- type: XSTATE_LOGIC_EFFECT_RESOLVE,
5114
- key,
5115
- output
5116
- });
5117
- resolve(output);
5118
- }
5119
- } catch (error) {
5120
- if (actor.getSnapshot().status === 'active') {
5121
- sendSelf({
5122
- type: XSTATE_LOGIC_EFFECT_REJECT,
5123
- key,
5124
- error
5125
- });
5126
- }
5127
- reject(error);
5128
- }
5129
- })().catch(reject);
5130
- return promise;
5131
- }
5132
-
5133
- /**
5134
- * Delivers an event directly to a target actor, bypassing any installed host
5135
- * runtime. Custom runtimes use this for the default local delivery behavior
5136
- * inside their own `sendEvent` implementations.
5137
- *
5138
- * @experimental
5139
- */
5140
- function deliverEvent(source, target, event) {
5141
- if (isSerializedActorRef(target)) {
5142
- const serialized = target;
5143
- const system = source?.system;
5144
- const live = system && resolveSerializedActorRef(system, serialized);
5145
- if (!live) {
5146
- const error = createMissingAddressError(serialized);
5147
- if (!system) {
5148
- throw error;
5149
- }
5150
- void system.deadLetter(source, undefined, event, 'missingTarget', {
5151
- targetId: getAddressId(serialized.$actor),
5152
- error
5153
- });
5154
- return;
5155
- }
5156
- target = live;
5157
- }
5158
- if (rejectUndeliverableEvent(source, target, event)) {
5159
- return;
5160
- }
5161
- const runtimeTarget = target;
5162
- runtimeTarget._send(event, source);
5163
- }
5164
-
5165
- /**
5166
- * Returns the boundary error preventing this delivery, if any: an internal
5167
- * event type cannot cross an actor boundary from an external sender.
5168
- */
5169
- function getEventBoundaryError(source, target, event) {
5170
- const runtimeTarget = target;
5171
- if (source !== target && runtimeTarget.logic?.isInternalEventType?.(event.type)) {
5172
- return new Error(`Internal event "${event.type}" cannot be sent to actor "${target.id}" from outside.`);
5173
- }
5174
- return undefined;
5175
- }
5176
-
5177
- /**
5178
- * Rejects an event that must not cross the delivery boundary — an internal
5179
- * event type sent from outside its owning actor — by reporting it as a dead
5180
- * letter. Returns `true` when the event was rejected and must not be
5181
- * delivered. Host runtimes must call this before taking ownership of
5182
- * delivery.
5183
- */
5184
- function rejectUndeliverableEvent(source, target, event) {
5185
- const error = getEventBoundaryError(source, target, event);
5186
- if (error) {
5187
- void target.system.deadLetter(source, target, event, 'internalEvent', {
5188
- error
5189
- });
5190
- return true;
5191
- }
5192
- return false;
5193
- }
5194
-
5195
- /**
5196
- * Publishes an actor's terminal result, notifying its parent and observers.
5197
- * Custom runtimes use this for the default local behavior inside their own
5198
- * `terminateActor` implementations.
5199
- *
5200
- * @experimental
5201
- */
5202
- function terminateActor(actor, termination) {
5203
- actor._terminate(termination);
5204
- }
5205
-
5206
- /**
5207
- * Stops an actor without producing a completion result. Custom runtimes use
5208
- * this for the default local behavior inside their own `stopActor`
5209
- * implementations.
5210
- *
5211
- * @experimental
5212
- */
5213
- function stopActor(actor) {
5214
- actor._stop();
5215
- }
5216
-
5217
5243
  let executionIdPrefix;
5218
5244
  let nextExecutionId = 0;
5219
5245
  function createExecutionIdPrefix() {
@@ -5409,6 +5435,8 @@ function bookSessionId(system) {
5409
5435
  * @public
5410
5436
  */
5411
5437
 
5438
+ /** @public */
5439
+
5412
5440
  /** @experimental */
5413
5441
 
5414
5442
  /** @internal Every operation of `ActorSystemRuntime`, for runtime wrappers. */
@@ -5656,6 +5684,32 @@ class RuntimeSystem {
5656
5684
  }
5657
5685
  };
5658
5686
  }
5687
+ onEmitted(listener) {
5688
+ const entry = emission => listener(emission);
5689
+ (this._emissionListeners ??= new Set()).add(entry);
5690
+ return {
5691
+ unsubscribe: () => {
5692
+ this._emissionListeners?.delete(entry);
5693
+ }
5694
+ };
5695
+ }
5696
+ _notifyEmitted(actorRef, event) {
5697
+ const listeners = this._emissionListeners;
5698
+ if (!listeners?.size) {
5699
+ return;
5700
+ }
5701
+ const emission = {
5702
+ actorRef,
5703
+ event
5704
+ };
5705
+ for (const listener of Array.from(listeners)) {
5706
+ try {
5707
+ listener(emission);
5708
+ } catch (err) {
5709
+ reportUnhandledError(err);
5710
+ }
5711
+ }
5712
+ }
5659
5713
  _hasInspectionObservers() {
5660
5714
  return !!this._inspectionObservers?.size;
5661
5715
  }
@@ -5858,6 +5912,17 @@ function createRuntimeSystem(rootActor, options) {
5858
5912
 
5859
5913
  let executingCustomAction = false;
5860
5914
  const emptyInspectionRecords = Object.freeze([]);
5915
+ const reservedMachineEventTypes = {
5916
+ 'xstate.done.actor': true,
5917
+ 'xstate.error.actor': true,
5918
+ 'xstate.error.execution': true,
5919
+ 'xstate.snapshot.actor': true,
5920
+ 'xstate.done.state': true,
5921
+ 'xstate.after': true,
5922
+ 'xstate.timeout.state': true,
5923
+ 'xstate.timeout.actor': true,
5924
+ [XSTATE_TIMER]: true
5925
+ };
5861
5926
 
5862
5927
  // those values are currently used by @xstate/react directly so it's important to keep the assigned values in sync
5863
5928
  let ProcessingStatus = /*#__PURE__*/function (ProcessingStatus) {
@@ -6029,6 +6094,7 @@ class Actor {
6029
6094
  });
6030
6095
  if (!parent && resolvedOptions._systemRef && !resolvedOptions._systemRef.current) {
6031
6096
  resolvedOptions._systemRef.current = this.system;
6097
+ resolvedOptions._systemRef.initialize?.();
6032
6098
  }
6033
6099
  if (inspect && !parent) {
6034
6100
  // Always inspect at the system-level
@@ -6132,7 +6198,7 @@ class Actor {
6132
6198
  return stopChild;
6133
6199
  }
6134
6200
  get emit() {
6135
- const emit = event => this.system.emitEvent(this, event);
6201
+ const emit = event => publishEmittedEvent(this, event, this.system);
6136
6202
  Object.defineProperty(this, 'emit', {
6137
6203
  value: emit
6138
6204
  });
@@ -6595,10 +6661,7 @@ class Actor {
6595
6661
  const [nextSnapshot, effects] = nextState;
6596
6662
  if (nextSnapshot === previousSnapshot && !effects.length &&
6597
6663
  // State machine snapshots only; other logic may ignore events freely.
6598
- 'machine' in previousSnapshot && (
6599
- // `xstate.route` is sent by users, so a route that matches nothing is
6600
- // reported like any other unhandled event.
6601
- !event.type.startsWith('xstate.') || event.type === 'xstate.route')) {
6664
+ 'machine' in previousSnapshot && event.type !== XSTATE_STOP && (!sourceRef || !Object.hasOwn(reservedMachineEventTypes, event.type))) {
6602
6665
  this._reportUnhandledEvent(event);
6603
6666
  }
6604
6667
  snapshot = nextSnapshot;
@@ -6929,6 +6992,9 @@ class Actor {
6929
6992
  * @public
6930
6993
  */
6931
6994
  function createActor(logic, ...[options]) {
6995
+ if (options && 'parent' in options) {
6996
+ throw new Error('The "parent" actor option was removed. Create child actors through invoke, spawn, or enq.spawn instead.');
6997
+ }
6932
6998
  return new Actor(logic, options);
6933
6999
  }
6934
7000
 
@@ -7017,6 +7083,7 @@ exports.matchesTimerKey = matchesTimerKey;
7017
7083
  exports.mergeActorIdCounters = mergeActorIdCounters;
7018
7084
  exports.parseDelayToMilliseconds = parseDelayToMilliseconds;
7019
7085
  exports.parseGeneratedActorId = parseGeneratedActorId;
7086
+ exports.publishEmittedEvent = publishEmittedEvent;
7020
7087
  exports.readTimerKey = readTimerKey;
7021
7088
  exports.recordTimerStart = recordTimerStart;
7022
7089
  exports.reserveChildId = reserveChildId;