@xstate/effect 1.0.0-alpha.9 → 1.0.0-beta.1

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.
@@ -1,13 +1,97 @@
1
- import { Queue, Effect, Fiber, Scope, Exit, Cause, Context, Clock, Duration, Data } from 'effect';
2
- import { stopActor, terminateActor, deliverEvent, isMachineSnapshot } from 'xstate';
1
+ import { Cause, Data, Queue, Effect, Exit, Fiber, Scope, Context, Clock, Duration } from 'effect';
2
+ import { StateMachine, stopActor, terminateActor, deliverEvent, isMachineSnapshot } from 'xstate';
3
3
  import { createDurable } from 'xstate/durable';
4
4
 
5
- /** A mailbox item that reports a failed fire-and-forget action. */
5
+ function _checkPrivateRedeclaration(e, t) {
6
+ if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object");
7
+ }
8
+
9
+ function _classPrivateFieldInitSpec(e, t, a) {
10
+ _checkPrivateRedeclaration(e, t), t.set(e, a);
11
+ }
12
+
13
+ function _checkInRHS(e) {
14
+ if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null"));
15
+ return e;
16
+ }
17
+
18
+ function _assertClassBrand(e, t, n) {
19
+ if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n;
20
+ throw new TypeError("Private element is not present on this object");
21
+ }
22
+
23
+ function _classPrivateFieldGet2(s, a) {
24
+ return s.get(_assertClassBrand(s, a));
25
+ }
26
+
27
+ var _effectFailure = /*#__PURE__*/new WeakMap();
28
+ /**
29
+ * Preserves an Effect failure, defect or interruption through XState error routing.
30
+ *
31
+ * @experimental
32
+ */
33
+ class EffectFailure extends Error {
34
+ static is(value) {
35
+ return typeof value === 'object' && value !== null && _effectFailure.has(_checkInRHS(value)) && _classPrivateFieldGet2(_effectFailure, value);
36
+ }
37
+ constructor(cause) {
38
+ super(Cause.pretty(cause));
39
+ this.cause = cause;
40
+ this._tag = 'EffectFailure';
41
+ _classPrivateFieldInitSpec(this, _effectFailure, true);
42
+ this.name = 'EffectFailure';
43
+ }
44
+ }
45
+
46
+ /**
47
+ * @deprecated Inspect `EffectFailure.cause` for interruption instead.
48
+ *
49
+ * @experimental
50
+ */
51
+ class EffectInterruptedError extends Data.TaggedError('EffectInterruptedError') {
52
+ get message() {
53
+ return 'Effect was interrupted before the actor completed';
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Reported by `waitFor` when the actor stops or errors before a snapshot
59
+ * matches, and by `join` when the actor stops without output. `join` reports
60
+ * an errored actor's outcome instead, preserving an Effect failure's Cause.
61
+ *
62
+ * @experimental
63
+ */
64
+ class ActorStoppedError extends Data.TaggedError('ActorStoppedError') {
65
+ get message() {
66
+ return `Actor "${this.actorId}" ${this.snapshot.status === 'error' ? 'errored' : 'stopped'} before completing`;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Reported by the `send` atom of `createActorAtoms` when an event is sent
72
+ * before the actor's runtime has finished building.
73
+ *
74
+ * @experimental
75
+ */
76
+ class NotReadyError extends Data.TaggedError('NotReadyError') {
77
+ get message() {
78
+ return 'The actor is not ready yet';
79
+ }
80
+ }
6
81
 
7
- const actionFailure = Symbol.for('@xstate/effect/actionFailure');
8
- function isActionFailure(value) {
9
- return typeof value === 'object' && value !== null && actionFailure in value;
82
+ /** @internal */
83
+ function causeFromError(error) {
84
+ return error instanceof EffectFailure ? error.cause : Cause.fail(error);
10
85
  }
86
+ /**
87
+ * An event rejected at the actor's delivery boundary.
88
+ *
89
+ * @experimental
90
+ */
91
+ class EventRejectedError extends Data.TaggedError('EventRejectedError') {}
92
+
93
+ /** @internal */
94
+
11
95
  const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
12
96
 
13
97
  /**
@@ -39,6 +123,8 @@ function toObserver(nextHandler, errorHandler, completionHandler) {
39
123
  * contract (`send`, `getSnapshot`, `subscribe`, `on`), so it works with
40
124
  * `useSelector`, this package's actor functions and the inspection APIs, while
41
125
  * the actor itself is driven by an Effect fiber over pure transitions.
126
+ *
127
+ * @experimental
42
128
  */
43
129
  class EffectActor {
44
130
  constructor(logic, root, snapshot, _mailbox, _stopExecution, _inspectors) {
@@ -57,6 +143,10 @@ class EffectActor {
57
143
  this._observers = new Set();
58
144
  this._listeners = new Map();
59
145
  this._settled = false;
146
+ this._pending = new Set();
147
+ this._inStep = false;
148
+ this._deliveryDepth = 0;
149
+ this._stopHeld = false;
60
150
  this._root = root;
61
151
  this.id = root.id;
62
152
  this.address = root.address;
@@ -73,15 +163,76 @@ class EffectActor {
73
163
 
74
164
  /** Sends an event; the actor processes it on its own fiber. */
75
165
  send(event) {
166
+ if (this._deliveryError(event)) return;
167
+ Queue.offerUnsafe(this._mailbox, {
168
+ kind: 'event',
169
+ event
170
+ });
171
+ }
172
+
173
+ /** @internal */
174
+ _sendAndAwait(event) {
175
+ return Effect.callback(resume => {
176
+ const error = this._deliveryError(event);
177
+ if (error) {
178
+ resume(Effect.fail(error));
179
+ return;
180
+ }
181
+ const receipt = {
182
+ resume: exit => resume(exit)
183
+ };
184
+ this._pending.add(receipt);
185
+ Queue.offerUnsafe(this._mailbox, {
186
+ kind: 'event',
187
+ event,
188
+ receipt
189
+ });
190
+ return Effect.sync(() => {
191
+ this._pending.delete(receipt);
192
+ receipt.resume = undefined;
193
+ });
194
+ });
195
+ }
196
+ _deliveryError(event) {
76
197
  if (this._settled) {
77
198
  this.system.deadLetter(undefined, this._root, event, 'stopped');
78
- return;
199
+ return this._stoppedError();
200
+ }
201
+ if (this.logic instanceof StateMachine && this.logic.isInternalEventType(event.type)) {
202
+ this.system.deadLetter(undefined, this._root, event, 'internalEvent');
203
+ return new EventRejectedError({
204
+ actorId: this.id,
205
+ event,
206
+ reason: 'internalEvent'
207
+ });
79
208
  }
80
- Queue.offerUnsafe(this._mailbox, event);
209
+ return undefined;
210
+ }
211
+ _stoppedError() {
212
+ return new ActorStoppedError({
213
+ actorId: this.id,
214
+ snapshot: this._snapshot
215
+ });
216
+ }
217
+
218
+ /** @internal */
219
+ _completeReceipt(receipt, exit) {
220
+ if (!receipt || !this._pending.delete(receipt)) return;
221
+ const resume = receipt.resume;
222
+ receipt.resume = undefined;
223
+ resume?.(exit);
81
224
  }
82
225
 
83
- /** Stops the actor, its children and every Effect it hosts. */
226
+ /**
227
+ * Stops the actor, its children and every Effect it hosts. If a listener or
228
+ * an observer calls `stop()` while the actor delivers a macrostep to it, the
229
+ * actor stops when that macrostep ends. `createActor` does the same.
230
+ */
84
231
  stop() {
232
+ if (this._inStep && this._deliveryDepth > 0) {
233
+ this._stopHeld = true;
234
+ return this;
235
+ }
85
236
  this._stopExecution();
86
237
  return this;
87
238
  }
@@ -122,9 +273,20 @@ class EffectActor {
122
273
 
123
274
  /** @internal Delivers an emitted event to `on` listeners. */
124
275
  _emit(event) {
276
+ if (this._settled) return;
125
277
  const listeners = [...(this._listeners.get(event.type) ?? []), ...(this._listeners.get('*') ?? [])];
126
- for (const listener of listeners) {
127
- safeCall(listener, event);
278
+ this._deliver(() => {
279
+ for (const listener of listeners) {
280
+ safeCall(listener, event);
281
+ }
282
+ });
283
+ }
284
+ _deliver(notify) {
285
+ this._deliveryDepth++;
286
+ try {
287
+ notify();
288
+ } finally {
289
+ this._deliveryDepth--;
128
290
  }
129
291
  }
130
292
 
@@ -146,25 +308,41 @@ class EffectActor {
146
308
  }
147
309
  toJSON() {
148
310
  return {
149
- $actor: this.address
311
+ '@actor': this.address
150
312
  };
151
313
  }
152
314
 
153
- /** @internal Publishes a snapshot produced by the execution loop. */
154
- _publish(snapshot) {
155
- this._snapshot = snapshot;
156
- const status = snapshot.status;
157
- if (status === 'active') {
158
- for (const observer of this._observers) {
159
- safeCall(observer.next, snapshot);
315
+ /** @internal */
316
+ _runStep(step) {
317
+ return Effect.gen({
318
+ self: this
319
+ }, function* () {
320
+ if (this._settled) return;
321
+ this._snapshot = step.snapshot;
322
+ this._inStep = true;
323
+ yield* step.effects;
324
+ if (this._settled) return;
325
+ if (this._snapshot.status !== 'active') {
326
+ this._settle(this._snapshot, step.kind === 'transition' ? step.receipt : undefined);
327
+ } else if (step.kind === 'transition') {
328
+ this._deliver(() => {
329
+ for (const observer of this._observers) {
330
+ safeCall(observer.next, this._snapshot);
331
+ }
332
+ });
160
333
  }
161
- return;
162
- }
163
- this._settle(snapshot);
334
+ }).pipe(Effect.onExit(exit => Effect.sync(() => {
335
+ this._inStep = false;
336
+ if (this._stopHeld) {
337
+ this._stopExecution();
338
+ } else if (step.kind === 'transition' && Exit.isSuccess(exit)) {
339
+ this._completeReceipt(step.receipt, step.rejection ? Exit.fail(step.rejection) : Exit.succeed(step.snapshot));
340
+ }
341
+ })));
164
342
  }
165
343
 
166
- /** @internal Marks the actor stopped and notifies observers. */
167
- _settle(snapshot) {
344
+ /** @internal Settles the actor and notifies its observers. */
345
+ _settle(snapshot, processing) {
168
346
  if (this._settled) {
169
347
  return;
170
348
  }
@@ -173,17 +351,23 @@ class EffectActor {
173
351
  const observers = [...this._observers];
174
352
  this._observers.clear();
175
353
  const status = snapshot.status;
176
- if (status === 'done') {
177
- for (const observer of observers) {
178
- safeCall(observer.next, snapshot);
354
+ this._deliver(() => {
355
+ if (status === 'done') {
356
+ for (const observer of observers) {
357
+ safeCall(observer.next, snapshot);
358
+ }
179
359
  }
180
- }
181
- for (const observer of observers) {
182
- if (status === 'error') {
183
- safeCall(observer.error, snapshot.error);
184
- } else {
185
- safeCall(observer.complete);
360
+ for (const observer of observers) {
361
+ if (status === 'error') {
362
+ safeCall(observer.error, snapshot.error);
363
+ } else {
364
+ safeCall(observer.complete);
365
+ }
186
366
  }
367
+ });
368
+ this._completeReceipt(processing, Exit.succeed(snapshot));
369
+ for (const receipt of this._pending) {
370
+ this._completeReceipt(receipt, Exit.fail(this._stoppedError()));
187
371
  }
188
372
  }
189
373
 
@@ -314,7 +498,7 @@ function trackEffect(actor, host, interrupt) {
314
498
  * The fiber belongs to the host scope, so closing the owning actor also
315
499
  * waits for asynchronous invocation finalizers.
316
500
  */
317
- function startHostedEffect(actor, effect, spanName, onExit) {
501
+ function startHostedEffect(actor, effect, spanName, onExit, onCancel) {
318
502
  const host = requireEffectHost(actor);
319
503
  let active = true;
320
504
  const traced = Effect.withSpan(spanName, {
@@ -331,11 +515,18 @@ function startHostedEffect(actor, effect, spanName, onExit) {
331
515
  }
332
516
  active = false;
333
517
  untrackEffect(actor, host, cancel);
518
+ onCancel?.();
334
519
  interrupt();
335
520
  };
336
- const fiber = Fiber.runIn(Effect.runForkWith(host.context)(traced), host.scope);
521
+ // Register the fiber before its body runs: the body can synchronously
522
+ // trigger the host's close, which only awaits registered fibers.
523
+ const registered = Effect.withFiber(fiber => {
524
+ Fiber.runIn(fiber, host.scope);
525
+ host.fibers.add(fiber);
526
+ return traced;
527
+ });
528
+ const fiber = Effect.runForkWith(host.context)(registered);
337
529
  const interrupt = () => fiber.interruptUnsafe();
338
- host.fibers.add(fiber);
339
530
  fiber.addObserver(exit => {
340
531
  host.fibers.delete(fiber);
341
532
  if (!active) {
@@ -351,22 +542,16 @@ function startHostedEffect(actor, effect, spanName, onExit) {
351
542
  return cancel;
352
543
  }
353
544
 
354
- /**
355
- * Runs an Effect in the actor's host context and settles when it exits.
356
- * Interruption settles without error; failures and defects reject with the
357
- * squashed cause so the actor's error handling can observe them.
358
- */
545
+ /** @internal */
359
546
  function runHostedEffect(actor, effect, spanName) {
360
547
  return new Promise((resolve, reject) => {
361
548
  startHostedEffect(actor, effect, spanName, exit => {
362
- if (Exit.isSuccess(exit) || Cause.hasInterruptsOnly(exit.cause)) {
549
+ if (Exit.isSuccess(exit)) {
363
550
  resolve();
364
551
  } else {
365
- // Effect failures are arbitrary values, not necessarily Errors.
366
- // oxlint-disable-next-line typescript/prefer-promise-reject-errors
367
- reject(Cause.squash(exit.cause));
552
+ reject(new EffectFailure(exit.cause));
368
553
  }
369
- });
554
+ }, resolve);
370
555
  });
371
556
  }
372
557
 
@@ -403,12 +588,18 @@ function relayToParent(actor, event) {
403
588
  }
404
589
  }
405
590
 
406
- /** The owning Effect actor's scope, supplied by `createEffectActor`. */
591
+ /**
592
+ * The owning Effect actor's scope, supplied by `createEffectActor`.
593
+ *
594
+ * @experimental
595
+ */
407
596
  class ActorScope extends Context.Service()('@xstate/effect/ActorScope') {}
408
597
 
409
598
  /**
410
599
  * Acquires resources in the owning actor's scope. Their finalizers run when
411
600
  * that actor stops, even if the invoking task finishes or is cancelled first.
601
+ *
602
+ * @experimental
412
603
  */
413
604
  function withActorScope(effect) {
414
605
  return ActorScope.use(scope => Scope.provide(effect, scope));
@@ -417,7 +608,11 @@ function withActorScope(effect) {
417
608
  const XSTATE_TIMER = 'xstate.timer';
418
609
  const XSTATE_INIT = 'xstate.init';
419
610
 
420
- /** Options for {@link createEffectActor}. */
611
+ /**
612
+ * Options for {@link createEffectActor}.
613
+ *
614
+ * @experimental
615
+ */
421
616
 
422
617
  /**
423
618
  * Creates and starts an actor as an Effect interpreter over pure transitions.
@@ -432,6 +627,8 @@ const XSTATE_INIT = 'xstate.init';
432
627
  * The actor is a scoped resource: it stops, and every Effect it hosts is
433
628
  * interrupted, when the enclosing `Scope` closes. The returned Effect never
434
629
  * fails; the actor's own outcome is its snapshot status, read with `join`.
630
+ *
631
+ * @experimental
435
632
  */
436
633
  function createEffectActor(logic, ...[options]) {
437
634
  return Effect.acquireRelease(Effect.gen(function* () {
@@ -443,6 +640,8 @@ function createEffectActor(logic, ...[options]) {
443
640
  const runFork = Effect.runForkWith(context);
444
641
  const runPromise = Effect.runPromiseWith(context);
445
642
  const mailbox = yield* Queue.unbounded();
643
+ let delivered;
644
+ const getDelivered = () => delivered;
446
645
  const timers = new Map();
447
646
  // `root` and `actor` are declared after the adapter below; its
448
647
  // callbacks only run once they are initialized.
@@ -469,14 +668,14 @@ function createEffectActor(logic, ...[options]) {
469
668
  if (result && typeof result.then === 'function') {
470
669
  void Promise.resolve(result).catch(error => {
471
670
  offer({
472
- [actionFailure]: true,
671
+ kind: 'actionFailure',
473
672
  error
474
673
  });
475
674
  });
476
675
  }
477
676
  } catch (error) {
478
677
  offer({
479
- [actionFailure]: true,
678
+ kind: 'actionFailure',
480
679
  error
481
680
  });
482
681
  }
@@ -500,7 +699,10 @@ function createEffectActor(logic, ...[options]) {
500
699
  },
501
700
  sendEvent: (source, target, event) => {
502
701
  if (isRoot(target)) {
503
- offer(event);
702
+ offer({
703
+ kind: 'event',
704
+ event: event
705
+ });
504
706
  return;
505
707
  }
506
708
  deliverEvent(source, target, event);
@@ -522,7 +724,10 @@ function createEffectActor(logic, ...[options]) {
522
724
  ...timer
523
725
  };
524
726
  if (isRoot(source)) {
525
- offer(timerEvent);
727
+ offer({
728
+ kind: 'event',
729
+ event: timerEvent
730
+ });
526
731
  } else {
527
732
  deliverEvent(source, source, timerEvent);
528
733
  }
@@ -542,8 +747,15 @@ function createEffectActor(logic, ...[options]) {
542
747
  }
543
748
  }
544
749
  },
545
- waitForEvent: () => runPromise(Queue.take(mailbox))
750
+ waitForEvent: () => runPromise(Queue.take(mailbox)).then(item => {
751
+ delivered = item;
752
+ return item.kind === 'event' ? item.event : {
753
+ type: 'xstate.effect.actionFailure'
754
+ };
755
+ })
546
756
  }, {
757
+ // A live actor needs one FIFO for child events, sends and timers.
758
+ captureRootEvents: false,
547
759
  inspect: event => {
548
760
  // The pure step scope re-materializes the root ref per step and
549
761
  // announces it again; observers should see the root once.
@@ -586,10 +798,11 @@ function createEffectActor(logic, ...[options]) {
586
798
  }
587
799
  runFork(Queue.shutdown(mailbox));
588
800
  if (!actor._isSettled) {
589
- actor._settle({
590
- ...actor.getSnapshot(),
801
+ const current = actor.getSnapshot();
802
+ actor._settle(current.status === 'active' ? {
803
+ ...current,
591
804
  status: 'stopped'
592
- });
805
+ } : current);
593
806
  }
594
807
  closeEffectHost(host);
595
808
  };
@@ -624,39 +837,67 @@ function createEffectActor(logic, ...[options]) {
624
837
  bindEffectHost(actor, host);
625
838
  const executeEffects = batch => Effect.promise(() => durable.executeEffects(batch).then(() => undefined, error => {
626
839
  offer({
627
- [actionFailure]: true,
840
+ kind: 'actionFailure',
628
841
  error
629
842
  });
630
843
  }));
631
844
  const loop = Effect.gen(function* () {
632
- yield* executeEffects(effects);
845
+ yield* actor._runStep({
846
+ kind: 'start',
847
+ snapshot,
848
+ effects: executeEffects(effects)
849
+ });
633
850
  while (snapshot.status === 'active' && !stopped) {
634
- const item = yield* Effect.promise(() => durable.waitForEvent().then(event => event, () => undefined));
635
- if (item === undefined || stopped) {
636
- break;
637
- }
851
+ delivered = undefined;
852
+ const received = yield* Effect.promise(() => durable.waitForEvent().catch(() => undefined));
853
+ if (received === undefined || stopped) break;
854
+ const item = getDelivered() ?? {
855
+ kind: 'event',
856
+ event: received
857
+ };
858
+ const receipt = item.kind === 'event' ? item.receipt : undefined;
638
859
  let event;
639
- if (isActionFailure(item)) {
860
+ if (item.kind === 'actionFailure') {
640
861
  const errorEvent = logic.getExecutionErrorEvent?.(snapshot, item.error);
641
862
  if (!errorEvent) {
642
863
  snapshot = errorSnapshot(snapshot, item.error);
864
+ yield* actor._runStep({
865
+ kind: 'transition',
866
+ snapshot,
867
+ effects: Effect.void
868
+ });
643
869
  break;
644
870
  }
645
871
  event = errorEvent;
646
872
  } else {
647
- event = item;
873
+ event = item.event;
648
874
  }
649
875
  try {
650
876
  [snapshot, effects] = durable.transition(snapshot, event);
651
877
  } catch (error) {
652
878
  snapshot = errorSnapshot(snapshot, error);
879
+ yield* actor._runStep({
880
+ kind: 'transition',
881
+ snapshot,
882
+ effects: Effect.void,
883
+ receipt
884
+ });
653
885
  break;
654
886
  }
655
- actor._publish(snapshot);
656
- yield* executeEffects(effects);
887
+ const rejectedReason = effects.length === 1 && effects[0].effect.type === '@xstate.deadLetter' && 'reason' in effects[0].effect && effects[0].effect.reason === 'invalidEvent' ? effects[0].effect.reason : undefined;
888
+ yield* actor._runStep({
889
+ kind: 'transition',
890
+ snapshot,
891
+ effects: executeEffects(effects),
892
+ receipt,
893
+ rejection: rejectedReason !== undefined ? new EventRejectedError({
894
+ actorId: actor.id,
895
+ event,
896
+ reason: rejectedReason
897
+ }) : undefined
898
+ });
657
899
  }
658
900
  if (!stopped) {
659
- actor._publish(snapshot);
660
901
  if (snapshot.status !== 'active') {
661
902
  stopChildren(snapshot);
662
903
  closeEffectHost(host);
@@ -666,13 +907,14 @@ function createEffectActor(logic, ...[options]) {
666
907
  yield* Effect.forkIn(loop, actorScope);
667
908
  return {
668
909
  actor,
669
- host
910
+ host,
911
+ stopNow: stop
670
912
  };
671
913
  }), ({
672
- actor,
673
- host
914
+ host,
915
+ stopNow
674
916
  }) => Effect.gen(function* () {
675
- actor.stop();
917
+ stopNow();
676
918
  if (host.closing) {
677
919
  yield* Fiber.join(host.closing);
678
920
  } else {
@@ -683,52 +925,28 @@ function createEffectActor(logic, ...[options]) {
683
925
  }) => actor));
684
926
  }
685
927
 
686
- /**
687
- * The failure an Effect-backed actor reports when its Effect was interrupted
688
- * by something other than the actor being stopped, such as `Effect.interrupt`,
689
- * losing an `Effect.race`, or an `Effect.timeout` that interrupts.
690
- */
691
- class EffectInterruptedError extends Data.TaggedError('EffectInterruptedError') {
692
- get message() {
693
- return 'Effect was interrupted before the actor completed';
694
- }
695
- }
696
-
697
- /**
698
- * Reported by `waitFor` when the actor stops or errors before a snapshot
699
- * matches, and by `join` when the actor stops without output. `join` reports
700
- * an errored actor's own `snapshot.error` instead.
701
- */
702
- class ActorStoppedError extends Data.TaggedError('ActorStoppedError') {
703
- get message() {
704
- return `Actor "${this.actorId}" ${this.snapshot.status === 'error' ? 'errored' : 'stopped'} before completing`;
705
- }
706
- }
707
-
708
- /**
709
- * Reported by the `send` atom of `createActorAtoms` when an event is sent
710
- * before the actor's runtime has finished building.
711
- */
712
- class NotReadyError extends Data.TaggedError('NotReadyError') {
713
- get message() {
714
- return 'The actor is not ready yet';
715
- }
716
- }
717
-
718
928
  /**
719
929
  * The dotted path of a state value: `'idle'`, `'form.editing'`. A parallel
720
930
  * state has no single path, so its tag stops at the parallel state. When the
721
931
  * machine itself is parallel, the tag is `TRootTag`: the machine id, or `''`
722
932
  * for a machine without one.
933
+ *
934
+ * @experimental
723
935
  */
724
936
 
725
937
  /**
726
938
  * A machine snapshot as a tagged union over its states. `_tag` is the state's
727
939
  * dotted path and `context` is the context of that state, including any
728
940
  * per-state context schema, so `Match.tag` narrows both.
941
+ *
942
+ * @experimental
729
943
  */
730
944
 
731
- /** The tagged state union of a machine. */
945
+ /**
946
+ * The tagged state union of a machine.
947
+ *
948
+ * @experimental
949
+ */
732
950
 
733
951
  /** Computes the dotted path tag of a state value. */
734
952
  function stateTag(value, rootTag, prefix = '') {
@@ -757,6 +975,8 @@ function stateTag(value, rootTag, prefix = '') {
757
975
  * );
758
976
  * view(taggedState(snapshot));
759
977
  * ```
978
+ *
979
+ * @experimental
760
980
  */
761
981
  function taggedState(snapshot) {
762
982
  return {
@@ -767,4 +987,4 @@ function taggedState(snapshot) {
767
987
  };
768
988
  }
769
989
 
770
- export { ActorStoppedError as A, EffectInterruptedError as E, NotReadyError as N, runHostedEffect as a, EffectActor as b, createEffectActor as c, ActorScope as d, relayToParent as r, startHostedEffect as s, taggedState as t, withActorScope as w };
990
+ export { ActorStoppedError as A, EffectFailure as E, NotReadyError as N, causeFromError as a, runHostedEffect as b, createEffectActor as c, EffectActor as d, ActorScope as e, EventRejectedError as f, EffectInterruptedError as g, relayToParent as r, startHostedEffect as s, taggedState as t, withActorScope as w };