xstate 6.0.0-alpha.2 → 6.0.0-alpha.4

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 (44) hide show
  1. package/dist/{StateMachine-64813f46.cjs.js → StateMachine-445a8480.cjs.js} +15 -6
  2. package/dist/{StateMachine-2ea0a7fa.development.esm.js → StateMachine-4deb4090.development.esm.js} +15 -6
  3. package/dist/{StateMachine-2dcdb1f5.esm.js → StateMachine-f310bc72.esm.js} +15 -6
  4. package/dist/{StateMachine-8d22a79c.development.cjs.js → StateMachine-f83f01f9.development.cjs.js} +15 -6
  5. package/dist/declarations/src/StateMachine.d.ts +9 -8
  6. package/dist/declarations/src/actions.d.ts +1 -1
  7. package/dist/declarations/src/createActor.d.ts +3 -2
  8. package/dist/declarations/src/createMachine.d.ts +10 -7
  9. package/dist/declarations/src/graph/graph.d.ts +3 -3
  10. package/dist/declarations/src/graph/shortestPaths.d.ts +2 -2
  11. package/dist/declarations/src/graph/simplePaths.d.ts +2 -2
  12. package/dist/declarations/src/index.d.ts +2 -3
  13. package/dist/declarations/src/serialize.d.ts +13 -8
  14. package/dist/declarations/src/setup.d.ts +79 -33
  15. package/dist/declarations/src/transition.d.ts +8 -5
  16. package/dist/declarations/src/transitionActions.d.ts +4 -0
  17. package/dist/declarations/src/types.d.ts +69 -21
  18. package/dist/declarations/src/types.v6.d.ts +47 -27
  19. package/dist/{index-9cb3b3a0.cjs.js → index-918ab496.cjs.js} +245 -816
  20. package/dist/{index-93edd3bd.esm.js → index-9cce3480.esm.js} +244 -811
  21. package/dist/{index-e61170ba.development.esm.js → index-ccbe7c0b.development.esm.js} +244 -811
  22. package/dist/{index-f6ef20d1.development.cjs.js → index-ebaf6fd8.development.cjs.js} +245 -816
  23. package/dist/xstate-actors.cjs.js +1 -1
  24. package/dist/xstate-actors.development.cjs.js +1 -1
  25. package/dist/xstate-actors.development.esm.js +1 -1
  26. package/dist/xstate-actors.esm.js +1 -1
  27. package/dist/xstate-actors.umd.min.js +1 -1
  28. package/dist/xstate-actors.umd.min.js.map +1 -1
  29. package/dist/xstate-graph.cjs.js +2 -2
  30. package/dist/xstate-graph.development.cjs.js +2 -2
  31. package/dist/xstate-graph.development.esm.js +2 -2
  32. package/dist/xstate-graph.esm.js +2 -2
  33. package/dist/xstate-graph.umd.min.js +1 -1
  34. package/dist/xstate-graph.umd.min.js.map +1 -1
  35. package/dist/xstate.cjs.js +150 -53
  36. package/dist/xstate.cjs.mjs +1 -5
  37. package/dist/xstate.development.cjs.js +150 -53
  38. package/dist/xstate.development.cjs.mjs +1 -5
  39. package/dist/xstate.development.esm.js +151 -50
  40. package/dist/xstate.esm.js +151 -50
  41. package/dist/xstate.umd.min.js +1 -1
  42. package/dist/xstate.umd.min.js.map +1 -1
  43. package/package.json +1 -1
  44. package/dist/declarations/src/atom.d.ts +0 -81
@@ -1,16 +1,3 @@
1
- /**
2
- * Reactivity interop between actors and atoms.
3
- *
4
- * `Actor#get()` calls this hook (when installed) so that computed atoms can
5
- * track actor reads as dependencies. The hook is installed by `atom.ts` on
6
- * module evaluation, which only happens when atoms are actually used — apps
7
- * that never import atoms don't bundle the reactive system.
8
- */
9
- let onActorRead;
10
- function installActorReadHook(hook) {
11
- onActorRead = hook;
12
- }
13
-
14
1
  class Mailbox {
15
2
  constructor(_process) {
16
3
  this._process = _process;
@@ -186,7 +173,7 @@ const builtInActions = {
186
173
  ['@xstate.cancel']: (actorScope, sendId) => {
187
174
  actorScope.system.scheduler.cancel(actorScope.self, sendId);
188
175
  },
189
- ['@xstate.stopChild']: (actorScope, actor) => {
176
+ ['@xstate.stop']: (actorScope, actor) => {
190
177
  actorScope.stopChild(actor);
191
178
  }
192
179
  };
@@ -198,15 +185,20 @@ const subscriptions = /* #__PURE__ */new WeakMap();
198
185
  * (`enq.listen()` / `enq.subscribeTo()`) and detaches when stopped.
199
186
  */
200
187
  function createAttachedLogic(attach) {
188
+ const initialTransition = (input, _) => [{
189
+ status: 'active',
190
+ output: undefined,
191
+ error: undefined,
192
+ input
193
+ }, []];
201
194
  return {
202
195
  start: (state, {
203
196
  self,
204
197
  system
205
198
  }) => {
206
- // Don't attach if the target doesn't exist, or (for actors) is stopped.
207
- // Atoms have no `getSnapshot` / lifecycle, so they always attach.
199
+ // Don't attach if the target doesn't exist or is stopped.
208
200
  const target = state.input.actor;
209
- if (!target || typeof target.getSnapshot === 'function' && target.getSnapshot().status === 'stopped') {
201
+ if (!target || target.getSnapshot().status === 'stopped') {
210
202
  return;
211
203
  }
212
204
  const subscription = attach(state.input, {
@@ -249,20 +241,16 @@ function createAttachedLogic(attach) {
249
241
  if (event.type === XSTATE_STOP) {
250
242
  subscriptions.get(self)?.unsubscribe();
251
243
  subscriptions.delete(self);
252
- return {
244
+ return [{
253
245
  ...state,
254
246
  status: 'stopped',
255
247
  error: undefined
256
- };
248
+ }, []];
257
249
  }
258
- return state;
250
+ return [state, []];
259
251
  },
260
- getInitialSnapshot: (_, input) => ({
261
- status: 'active',
262
- output: undefined,
263
- error: undefined,
264
- input
265
- }),
252
+ initialTransition,
253
+ getInitialSnapshot: (actorScope, input) => initialTransition(input)[0],
266
254
  getPersistedSnapshot: snapshot => snapshot,
267
255
  restoreSnapshot: snapshot => snapshot
268
256
  };
@@ -308,620 +296,6 @@ function createListenerLogic() {
308
296
  // Singleton logic instance
309
297
  const listenerLogic = /* #__PURE__ */createListenerLogic();
310
298
 
311
- /* eslint-disable */
312
- // Adapted from Alien Signals
313
- // https://github.com/stackblitz/alien-signals/
314
-
315
- let ReactiveFlags = /*#__PURE__*/function (ReactiveFlags) {
316
- ReactiveFlags[ReactiveFlags["None"] = 0] = "None";
317
- ReactiveFlags[ReactiveFlags["Mutable"] = 1] = "Mutable";
318
- ReactiveFlags[ReactiveFlags["Watching"] = 2] = "Watching";
319
- ReactiveFlags[ReactiveFlags["RecursedCheck"] = 4] = "RecursedCheck";
320
- ReactiveFlags[ReactiveFlags["Recursed"] = 8] = "Recursed";
321
- ReactiveFlags[ReactiveFlags["Dirty"] = 16] = "Dirty";
322
- ReactiveFlags[ReactiveFlags["Pending"] = 32] = "Pending";
323
- return ReactiveFlags;
324
- }({});
325
- function createReactiveSystem({
326
- update,
327
- notify,
328
- unwatched
329
- }) {
330
- return {
331
- link,
332
- unlink,
333
- propagate,
334
- checkDirty,
335
- shallowPropagate
336
- };
337
- function link(dep, sub, version) {
338
- const prevDep = sub.depsTail;
339
- if (prevDep !== undefined && prevDep.dep === dep) {
340
- return;
341
- }
342
- const nextDep = prevDep !== undefined ? prevDep.nextDep : sub.deps;
343
- if (nextDep !== undefined && nextDep.dep === dep) {
344
- nextDep.version = version;
345
- sub.depsTail = nextDep;
346
- return;
347
- }
348
- const prevSub = dep.subsTail;
349
- if (prevSub !== undefined && prevSub.version === version && prevSub.sub === sub) {
350
- return;
351
- }
352
- const newLink = sub.depsTail = dep.subsTail = {
353
- version,
354
- dep,
355
- sub,
356
- prevDep,
357
- nextDep,
358
- prevSub,
359
- nextSub: undefined
360
- };
361
- if (nextDep !== undefined) {
362
- nextDep.prevDep = newLink;
363
- }
364
- if (prevDep !== undefined) {
365
- prevDep.nextDep = newLink;
366
- } else {
367
- sub.deps = newLink;
368
- }
369
- if (prevSub !== undefined) {
370
- prevSub.nextSub = newLink;
371
- } else {
372
- dep.subs = newLink;
373
- }
374
- }
375
- function unlink(link, sub = link.sub) {
376
- const dep = link.dep;
377
- const prevDep = link.prevDep;
378
- const nextDep = link.nextDep;
379
- const nextSub = link.nextSub;
380
- const prevSub = link.prevSub;
381
- if (nextDep !== undefined) {
382
- nextDep.prevDep = prevDep;
383
- } else {
384
- sub.depsTail = prevDep;
385
- }
386
- if (prevDep !== undefined) {
387
- prevDep.nextDep = nextDep;
388
- } else {
389
- sub.deps = nextDep;
390
- }
391
- if (nextSub !== undefined) {
392
- nextSub.prevSub = prevSub;
393
- } else {
394
- dep.subsTail = prevSub;
395
- }
396
- if (prevSub !== undefined) {
397
- prevSub.nextSub = nextSub;
398
- } else if ((dep.subs = nextSub) === undefined) {
399
- unwatched(dep);
400
- }
401
- return nextDep;
402
- }
403
- function propagate(link) {
404
- let next = link.nextSub;
405
- let stack;
406
- top: do {
407
- const sub = link.sub;
408
- let flags = sub.flags;
409
- if (!(flags & (ReactiveFlags.RecursedCheck | ReactiveFlags.Recursed | ReactiveFlags.Dirty | ReactiveFlags.Pending))) {
410
- sub.flags = flags | ReactiveFlags.Pending;
411
- } else if (!(flags & (ReactiveFlags.RecursedCheck | ReactiveFlags.Recursed))) {
412
- flags = ReactiveFlags.None;
413
- } else if (!(flags & ReactiveFlags.RecursedCheck)) {
414
- sub.flags = flags & ~ReactiveFlags.Recursed | ReactiveFlags.Pending;
415
- } else if (!(flags & (ReactiveFlags.Dirty | ReactiveFlags.Pending)) && isValidLink(link, sub)) {
416
- sub.flags = flags | (ReactiveFlags.Recursed | ReactiveFlags.Pending);
417
- flags &= ReactiveFlags.Mutable;
418
- } else {
419
- flags = ReactiveFlags.None;
420
- }
421
- if (flags & ReactiveFlags.Watching) {
422
- notify(sub);
423
- }
424
- if (flags & ReactiveFlags.Mutable) {
425
- const subSubs = sub.subs;
426
- if (subSubs !== undefined) {
427
- const nextSub = (link = subSubs).nextSub;
428
- if (nextSub !== undefined) {
429
- stack = {
430
- value: next,
431
- prev: stack
432
- };
433
- next = nextSub;
434
- }
435
- continue;
436
- }
437
- }
438
- if ((link = next) !== undefined) {
439
- next = link.nextSub;
440
- continue;
441
- }
442
- while (stack !== undefined) {
443
- link = stack.value;
444
- stack = stack.prev;
445
- if (link !== undefined) {
446
- next = link.nextSub;
447
- continue top;
448
- }
449
- }
450
- break;
451
- } while (true);
452
- }
453
- function checkDirty(link, sub) {
454
- let stack;
455
- let checkDepth = 0;
456
- let dirty = false;
457
- top: do {
458
- const dep = link.dep;
459
- const flags = dep.flags;
460
- if (sub.flags & ReactiveFlags.Dirty) {
461
- dirty = true;
462
- } else if ((flags & (ReactiveFlags.Mutable | ReactiveFlags.Dirty)) === (ReactiveFlags.Mutable | ReactiveFlags.Dirty)) {
463
- if (update(dep)) {
464
- const subs = dep.subs;
465
- if (subs.nextSub !== undefined) {
466
- shallowPropagate(subs);
467
- }
468
- dirty = true;
469
- }
470
- } else if ((flags & (ReactiveFlags.Mutable | ReactiveFlags.Pending)) === (ReactiveFlags.Mutable | ReactiveFlags.Pending)) {
471
- if (link.nextSub !== undefined || link.prevSub !== undefined) {
472
- stack = {
473
- value: link,
474
- prev: stack
475
- };
476
- }
477
- link = dep.deps;
478
- sub = dep;
479
- ++checkDepth;
480
- continue;
481
- }
482
- if (!dirty) {
483
- const nextDep = link.nextDep;
484
- if (nextDep !== undefined) {
485
- link = nextDep;
486
- continue;
487
- }
488
- }
489
- while (checkDepth--) {
490
- const firstSub = sub.subs;
491
- const hasMultipleSubs = firstSub.nextSub !== undefined;
492
- if (hasMultipleSubs) {
493
- link = stack.value;
494
- stack = stack.prev;
495
- } else {
496
- link = firstSub;
497
- }
498
- if (dirty) {
499
- if (update(sub)) {
500
- if (hasMultipleSubs) {
501
- shallowPropagate(firstSub);
502
- }
503
- sub = link.sub;
504
- continue;
505
- }
506
- dirty = false;
507
- } else {
508
- sub.flags &= ~ReactiveFlags.Pending;
509
- }
510
- sub = link.sub;
511
- const nextDep = link.nextDep;
512
- if (nextDep !== undefined) {
513
- link = nextDep;
514
- continue top;
515
- }
516
- }
517
- return dirty;
518
- } while (true);
519
- }
520
- function shallowPropagate(link) {
521
- do {
522
- const sub = link.sub;
523
- const flags = sub.flags;
524
- if ((flags & (ReactiveFlags.Pending | ReactiveFlags.Dirty)) === ReactiveFlags.Pending) {
525
- sub.flags = flags | ReactiveFlags.Dirty;
526
- if ((flags & (ReactiveFlags.Watching | ReactiveFlags.RecursedCheck)) === ReactiveFlags.Watching) {
527
- notify(sub);
528
- }
529
- }
530
- } while ((link = link.nextSub) !== undefined);
531
- }
532
- function isValidLink(checkLink, sub) {
533
- let link = sub.depsTail;
534
- while (link !== undefined) {
535
- if (link === checkLink) {
536
- return true;
537
- }
538
- link = link.prevDep;
539
- }
540
- return false;
541
- }
542
- }
543
-
544
- /**
545
- * Nominal brand (phantom, compile-time only) marking a value as an XState atom.
546
- * Real atoms get the runtime brand ({@link $$atom}) in `createAtom`; this type
547
- * brand keeps atom-only APIs (e.g. `enq.subscribeTo`) from structurally
548
- * accepting plain readables like `actor.select(...)` that would be dispatched
549
- * down the non-atom path at runtime.
550
- */
551
-
552
- /** Brand marking an object as an atom, so it can be detected structurally. */
553
- const $$atom = /* #__PURE__ */Symbol.for('xstate.atom');
554
-
555
- /**
556
- * Returns `true` if the value is an atom (writable, computed, async, or
557
- * reducer). Lets actor-consuming APIs (e.g. `enq.subscribeTo`) accept atoms
558
- * directly.
559
- */
560
- function isAtom(value) {
561
- return !!value && typeof value === 'object' && $$atom in value;
562
- }
563
- const queuedEffects = [];
564
- let cycle = 0;
565
- // Initialized lazily on first atom creation (instead of at module evaluation)
566
- // so the reactive system stays tree-shakeable for apps that never use atoms —
567
-
568
- // would be retained by consumer bundlers even when atoms are unused.
569
- let link;
570
- let unlink;
571
- let propagate;
572
- let checkDirty;
573
- let shallowPropagate;
574
- let reactiveSystemInstalled = false;
575
- function ensureReactiveSystem() {
576
- if (reactiveSystemInstalled) {
577
- return;
578
- }
579
- reactiveSystemInstalled = true;
580
- ({
581
- link,
582
- unlink,
583
- propagate,
584
- checkDirty,
585
- shallowPropagate
586
- } = createReactiveSystem({
587
- update(atom) {
588
- return atom._update();
589
- },
590
- notify(effect) {
591
- queuedEffects[queuedEffectsLength++] = effect;
592
- effect.flags &= ~ReactiveFlags.Watching;
593
- },
594
- unwatched(atom) {
595
- if (atom.depsTail !== undefined) {
596
- atom.depsTail = undefined;
597
- atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty;
598
- purgeDeps(atom);
599
- }
600
- }
601
- }));
602
- }
603
- let notifyIndex = 0;
604
- let queuedEffectsLength = 0;
605
- let activeSub;
606
- function purgeDeps(sub) {
607
- const depsTail = sub.depsTail;
608
- let dep = depsTail !== undefined ? depsTail.nextDep : sub.deps;
609
- while (dep !== undefined) {
610
- dep = unlink(dep, sub);
611
- }
612
- }
613
- function flush() {
614
- while (notifyIndex < queuedEffectsLength) {
615
- const effect = queuedEffects[notifyIndex];
616
- queuedEffects[notifyIndex++] = undefined;
617
- effect.notify();
618
- }
619
- notifyIndex = 0;
620
- queuedEffectsLength = 0;
621
- }
622
-
623
- /** The current state of an async atom. */
624
-
625
- /** Options passed to an async atom getter. */
626
-
627
- function compareAsyncAtomState(a, b) {
628
- if (a.status !== b.status) {
629
- return false;
630
- }
631
- if (a.status === 'done' && b.status === 'done') {
632
- return Object.is(a.data, b.data);
633
- }
634
- if (a.status === 'error' && b.status === 'error') {
635
- return Object.is(a.error, b.error);
636
- }
637
- // both 'pending'
638
- return true;
639
- }
640
- function updateAsyncAtom(atom, nextValue) {
641
- if (atom._update(nextValue)) {
642
- const subs = atom.subs;
643
- if (subs !== undefined) {
644
- propagate(subs);
645
- shallowPropagate(subs);
646
- flush();
647
- }
648
- }
649
- }
650
-
651
- /**
652
- * Creates a read-only atom whose value is loaded from an async getter.
653
- *
654
- * The getter receives an `AbortSignal`; when the async atom recomputes, the
655
- * previous signal is aborted and stale resolutions are ignored.
656
- */
657
- function createAsyncAtom(getValue, options) {
658
- const ref = {};
659
- let currentController;
660
- let currentRunId = 0;
661
- const atom = createAtom(() => {
662
- currentController?.abort();
663
- const controller = new AbortController();
664
- const runId = ++currentRunId;
665
- currentController = controller;
666
- getValue({
667
- signal: controller.signal
668
- }).then(data => {
669
- if (runId !== currentRunId || controller.signal.aborted) {
670
- return;
671
- }
672
- updateAsyncAtom(ref.current, {
673
- status: 'done',
674
- data
675
- });
676
- }, error => {
677
- if (runId !== currentRunId || controller.signal.aborted) {
678
- return;
679
- }
680
- updateAsyncAtom(ref.current, {
681
- status: 'error',
682
- error
683
- });
684
- });
685
- return {
686
- status: 'pending'
687
- };
688
- }, {
689
- compare: compareAsyncAtomState,
690
- ...options
691
- });
692
- ref.current = atom;
693
- return atom;
694
- }
695
-
696
- /**
697
- * Mirror atoms that bump a version whenever a tracked actor emits a snapshot,
698
- * letting computed atoms depend on `actor.get()` reads.
699
- *
700
- * The hook is installed lazily on first atom creation (not at module
701
- * evaluation) so that it remains tree-shakeable for apps that never use atoms —
702
- * any tracked read necessarily happens inside an atom computation, so first-use
703
- * installation is always early enough.
704
- */
705
- let actorInteropInstalled = false;
706
- function ensureActorInterop() {
707
- if (actorInteropInstalled) {
708
- return;
709
- }
710
- actorInteropInstalled = true;
711
- const actorVersions = new WeakMap();
712
- installActorReadHook(actorRef => {
713
- if (activeSub === undefined) {
714
- return;
715
- }
716
- let version = actorVersions.get(actorRef);
717
- if (version === undefined) {
718
- version = createAtom(0);
719
- actorVersions.set(actorRef, version);
720
- actorRef.subscribe({
721
- next: () => version.set(v => v + 1),
722
- error: () => {}
723
- });
724
- }
725
- version.get();
726
- });
727
- }
728
-
729
- /**
730
- * Creates an atom.
731
- *
732
- * Pass a value for a writable atom or a getter for a computed read-only atom.
733
- */
734
-
735
- function createAtom(valueOrFn, optionsOrInput) {
736
- ensureReactiveSystem();
737
- ensureActorInterop();
738
- const isComputed = typeof valueOrFn === 'function';
739
- const getter = valueOrFn;
740
-
741
- // Create plain object atom
742
- const atom = {
743
- _snapshot: isComputed ? undefined : valueOrFn,
744
- subs: undefined,
745
- subsTail: undefined,
746
- deps: undefined,
747
- depsTail: undefined,
748
- flags: isComputed ? ReactiveFlags.None : ReactiveFlags.Mutable,
749
- get() {
750
- if (activeSub !== undefined) {
751
- link(atom, activeSub, cycle);
752
- }
753
- return atom._snapshot;
754
- },
755
- subscribe(observerOrFn) {
756
- const observer = typeof observerOrFn === 'function' ? {
757
- next: observerOrFn
758
- } : observerOrFn;
759
- const observed = {
760
- current: false
761
- };
762
- const e = effect(() => {
763
- atom.get();
764
- if (!observed.current) {
765
- observed.current = true;
766
- } else {
767
- const prevSub = activeSub;
768
- activeSub = undefined;
769
- try {
770
- observer.next?.(atom._snapshot);
771
- } catch (err) {
772
- reportUnhandledError(err);
773
- } finally {
774
- activeSub = prevSub;
775
- }
776
-
777
- // If the observer synchronously updates any of our deps we'll be
778
- // marked as dirty preventing this effect from re-running. Request
779
- // the value again to reconcile any dirty deps.
780
- atom.get();
781
- }
782
- });
783
- return {
784
- unsubscribe: () => {
785
- e.stop();
786
- }
787
- };
788
- },
789
- _update(getValue) {
790
- const prevSub = activeSub;
791
- const compare = optionsOrInput?.compare ?? Object.is;
792
- activeSub = atom;
793
- ++cycle;
794
- atom.depsTail = undefined;
795
- if (isComputed) {
796
- atom.flags = ReactiveFlags.Mutable | ReactiveFlags.RecursedCheck;
797
- }
798
- try {
799
- const oldValue = atom._snapshot;
800
- const newValue = typeof getValue === 'function' ? getValue(oldValue) : getValue === undefined && isComputed ? getter(oldValue) : getValue;
801
- if (oldValue === undefined || !compare(oldValue, newValue)) {
802
- atom._snapshot = newValue;
803
- return true;
804
- }
805
- return false;
806
- } finally {
807
- activeSub = prevSub;
808
- if (isComputed) {
809
- atom.flags &= ~ReactiveFlags.RecursedCheck;
810
- }
811
- purgeDeps(atom);
812
- }
813
- }
814
- };
815
- if (isComputed) {
816
- atom.flags = ReactiveFlags.Mutable | ReactiveFlags.Dirty;
817
- atom.get = function () {
818
- const flags = atom.flags;
819
- if (flags & ReactiveFlags.Dirty || flags & ReactiveFlags.Pending && checkDirty(atom.deps, atom)) {
820
- if (atom._update()) {
821
- const subs = atom.subs;
822
- if (subs !== undefined) {
823
- shallowPropagate(subs);
824
- }
825
- }
826
- } else if (flags & ReactiveFlags.Pending) {
827
- atom.flags = flags & ~ReactiveFlags.Pending;
828
- }
829
- if (activeSub !== undefined) {
830
- link(atom, activeSub, cycle);
831
- }
832
- return atom._snapshot;
833
- };
834
- } else {
835
- atom.set = function (valueOrFn) {
836
- if (atom._update(valueOrFn)) {
837
- const subs = atom.subs;
838
- if (subs !== undefined) {
839
- propagate(subs);
840
- shallowPropagate(subs);
841
- flush();
842
- }
843
- }
844
- };
845
- }
846
- atom[$$atom] = true;
847
- return atom;
848
- }
849
-
850
- /**
851
- * Creates an inert atom config that can be instantiated later.
852
- *
853
- * Useful for framework hooks that need to create a stable local atom from
854
- * component input.
855
- */
856
-
857
- function createAtomConfig(initialValueOrFn, options) {
858
- return {
859
- createAtom(input) {
860
- const initialValue = typeof initialValueOrFn === 'function' ? initialValueOrFn(input) : initialValueOrFn;
861
- return createAtom(initialValue, options);
862
- }
863
- };
864
- }
865
-
866
- /** Creates an atom whose updates are handled by a reducer function. */
867
- function createReducerAtom(initialValue, reducer, options) {
868
- const atom = createAtom(initialValue, options);
869
- return {
870
- [$$atom]: true,
871
- get: atom.get.bind(atom),
872
- subscribe: atom.subscribe.bind(atom),
873
- send(event) {
874
- const prevSub = activeSub;
875
- activeSub = undefined;
876
- let nextState;
877
- try {
878
- nextState = reducer(atom.get(), event);
879
- } finally {
880
- activeSub = prevSub;
881
- }
882
- atom.set(nextState);
883
- }
884
- };
885
- }
886
- function effect(fn) {
887
- const run = () => {
888
- const prevSub = activeSub;
889
- activeSub = effectObj;
890
- ++cycle;
891
- effectObj.depsTail = undefined;
892
- effectObj.flags = ReactiveFlags.Watching | ReactiveFlags.RecursedCheck;
893
- try {
894
- return fn();
895
- } finally {
896
- activeSub = prevSub;
897
- effectObj.flags &= ~ReactiveFlags.RecursedCheck;
898
- purgeDeps(effectObj);
899
- }
900
- };
901
- const effectObj = {
902
- deps: undefined,
903
- depsTail: undefined,
904
- subs: undefined,
905
- subsTail: undefined,
906
- flags: ReactiveFlags.Watching | ReactiveFlags.RecursedCheck,
907
- notify() {
908
- const flags = this.flags;
909
- if (flags & ReactiveFlags.Dirty || flags & ReactiveFlags.Pending && checkDirty(this.deps, this)) {
910
- run();
911
- } else {
912
- this.flags = ReactiveFlags.Watching;
913
- }
914
- },
915
- stop() {
916
- this.flags = ReactiveFlags.None;
917
- this.depsTail = undefined;
918
- purgeDeps(this);
919
- }
920
- };
921
- run();
922
- return effectObj;
923
- }
924
-
925
299
  /**
926
300
  * Creates actor logic for subscribing to lifecycle events (done/error/snapshot)
927
301
  * from another actor. Used internally by `enq.subscribeTo()`.
@@ -939,15 +313,6 @@ function createSubscriptionLogic() {
939
313
  error,
940
314
  snapshot: onSnapshot
941
315
  } = mappers;
942
-
943
- // Atoms emit a raw value (no `status`) and have no done/error lifecycle —
944
- // pass the value straight to the `snapshot` mapper.
945
- if (isAtom(actor)) {
946
- if (!onSnapshot) {
947
- return;
948
- }
949
- return actor.subscribe(value => relayMappedToParent(self, system, () => onSnapshot(value)));
950
- }
951
316
  return actor.subscribe({
952
317
  next: snapshot => {
953
318
  if (snapshot.status === 'done' && done) {
@@ -1048,7 +413,7 @@ function createTransitionEnqueue(actorScope, actions, internalEvents, actorSubsc
1048
413
  },
1049
414
  stop: actor => {
1050
415
  if (actor) {
1051
- pushBuiltInAction(actions, builtInActions['@xstate.stopChild'], actorScope, actor);
416
+ pushBuiltInAction(actions, builtInActions['@xstate.stop'], actorScope, actor);
1052
417
  actions.push(unregisterChild(actor));
1053
418
  }
1054
419
  }
@@ -1089,16 +454,65 @@ function createTransitionEnqueue(actorScope, actions, internalEvents, actorSubsc
1089
454
  pushBuiltInAction(actions, action, ...args);
1090
455
  });
1091
456
  }
1092
- function resolveAndExecuteActionsWithContext(currentSnapshot, event, actorScope, actions) {
457
+ function getBuiltInActionFields(action, args) {
458
+ switch (action) {
459
+ case builtInActions['@xstate.start']:
460
+ {
461
+ const [actor] = args;
462
+ return {
463
+ actor,
464
+ id: actor.id,
465
+ logic: actor.logic,
466
+ src: actor.src,
467
+ input: actor.options?.input
468
+ };
469
+ }
470
+ case builtInActions['@xstate.raise']:
471
+ {
472
+ const [, event, options] = args;
473
+ return {
474
+ event,
475
+ id: options?.id,
476
+ delay: options?.delay
477
+ };
478
+ }
479
+ case builtInActions['@xstate.sendTo']:
480
+ {
481
+ const [, target, event, options] = args;
482
+ return {
483
+ target,
484
+ event,
485
+ id: options?.id,
486
+ delay: options?.delay
487
+ };
488
+ }
489
+ case builtInActions['@xstate.cancel']:
490
+ {
491
+ const [, id] = args;
492
+ return {
493
+ id
494
+ };
495
+ }
496
+ case builtInActions['@xstate.stop']:
497
+ {
498
+ const [, actor] = args;
499
+ return {
500
+ actor
501
+ };
502
+ }
503
+ default:
504
+ return undefined;
505
+ }
506
+ }
507
+ function isBuiltInExecutableAction(action) {
508
+ return Object.prototype.hasOwnProperty.call(builtInActions, action.type);
509
+ }
510
+ function resolveActionsWithContext(currentSnapshot, event, actorScope, actions) {
1093
511
  let intermediateSnapshot = currentSnapshot;
512
+ const executableActions = [];
1094
513
  for (const action of actions) {
1095
514
  const isInline = typeof action === 'function';
1096
515
  const resolvedAction = isInline ? action : typeof action === 'object' && 'action' in action && typeof action.action === 'function' ? action.action.bind(null, ...action.args) : false;
1097
- if (!resolvedAction && typeof action === 'object' && action !== null) {
1098
- actorScope.defer(() => {
1099
- actorScope.emit(action);
1100
- });
1101
- }
1102
516
  const actionArgs = {
1103
517
  context: intermediateSnapshot.context,
1104
518
  event,
@@ -1118,7 +532,7 @@ function resolveAndExecuteActionsWithContext(currentSnapshot, event, actorScope,
1118
532
  actionParams = emittedEventParams;
1119
533
  }
1120
534
  if (resolvedAction && '_special' in resolvedAction) {
1121
- actorScope.actionExecutor({
535
+ executableActions.push({
1122
536
  type: typeof action === 'object' ? 'action' in action && typeof action.action === 'function' ? action.action.name ?? '(anonymous)' : action.type ?? '(anonymous)' : action.name || '(anonymous)',
1123
537
  params: actionParams,
1124
538
  args: [],
@@ -1139,16 +553,18 @@ function resolveAndExecuteActionsWithContext(currentSnapshot, event, actorScope,
1139
553
  continue;
1140
554
  }
1141
555
  if (!resolvedAction || !('resolve' in resolvedAction)) {
1142
- actorScope.actionExecutor({
556
+ const builtInFields = typeof action === 'object' && action !== null && 'action' in action && typeof action.action === 'function' ? getBuiltInActionFields(action.action, action.args) : undefined;
557
+ executableActions.push({
1143
558
  type: typeof action === 'object' ? 'action' in action && typeof action.action === 'function' ? action.action.name ?? '(anonymous)' : action.type : action.name || '(anonymous)',
1144
559
  params: actionParams,
1145
560
  args: typeof action === 'object' && 'action' in action ? action.args : [],
1146
- exec: resolvedAction
561
+ exec: resolvedAction || (typeof action === 'object' && action !== null ? () => actorScope.defer(() => actorScope.emit(action)) : undefined),
562
+ ...builtInFields
1147
563
  });
1148
564
  continue;
1149
565
  }
1150
566
  }
1151
- return intermediateSnapshot;
567
+ return [intermediateSnapshot, executableActions];
1152
568
  }
1153
569
  function createEnqueueObject$1(props, action) {
1154
570
  const enqueueFn = (fn, ...args) => {
@@ -1342,22 +758,9 @@ function isInFinalState(stateNodeSet, stateNode) {
1342
758
  }
1343
759
  const isStateId = str => str[0] === STATE_IDENTIFIER;
1344
760
  function getCandidates(stateNode, receivedEventType) {
1345
- const candidates = stateNode.transitions.get(receivedEventType);
1346
- if (candidates) {
1347
- return candidates;
1348
- }
1349
- const matchingDescriptors = [];
1350
- for (const eventDescriptor of stateNode.transitions.keys()) {
1351
- if (matchesEventDescriptor(receivedEventType, eventDescriptor)) {
1352
- matchingDescriptors.push(eventDescriptor);
1353
- }
1354
- }
1355
- matchingDescriptors.sort((a, b) => b.length - a.length);
1356
- const wildcardCandidates = [];
1357
- for (const descriptor of matchingDescriptors) {
1358
- wildcardCandidates.push(...stateNode.transitions.get(descriptor));
1359
- }
1360
- return wildcardCandidates;
761
+ const exactMatch = stateNode.transitions.get(receivedEventType);
762
+ const wildcardCandidates = [...stateNode.transitions.keys()].filter(eventDescriptor => eventDescriptor !== receivedEventType && matchesEventDescriptor(receivedEventType, eventDescriptor)).sort((a, b) => b.length - a.length).flatMap(key => stateNode.transitions.get(key));
763
+ return exactMatch ? [...exactMatch, ...wildcardCandidates] : wildcardCandidates;
1361
764
  }
1362
765
  function scheduleDelayedEvent(stateNode, event, resolveScheduledDelay) {
1363
766
  const eventType = event.type;
@@ -1396,61 +799,68 @@ function getDelayedTransitions(stateNode) {
1396
799
  }
1397
800
  }
1398
801
  }
1399
- const mutateEntryExitWithDelay = delay => {
1400
- const afterEvent = createAfterEvent(delay, stateNode.id);
1401
- return scheduleDelayedEvent(stateNode, afterEvent, x => resolveDelay(delay, x.delays, {
1402
- context: x.context,
1403
- event: x.event,
1404
- stateNode
1405
- }));
1406
- };
1407
- const delayedTransitions = [];
1408
- const addDelayedTransitions = (transitionsConfig, event, delay) => {
1409
- for (const transition of toTransitionConfigArray(transitionsConfig)) {
1410
- delayedTransitions.push({
1411
- ...transition,
1412
- event,
1413
- delay
1414
- });
1415
- }
1416
- };
802
+
803
+ // Every delayed transition — `after`, state-level `timeout`/`onTimeout`, and
804
+ // invoke-level `timeout`/`onTimeout` has the same shape: an event raised on
805
+ // entry (and cancelled on exit) plus a transition that catches it. They
806
+ // differ only in the event raised, the transition(s) caught, and whether the
807
+ // delay resolves against the machine's `delays` map (invoke timeouts do not).
808
+ //
809
+ // `xstate.timeout.<id>` is a dedicated event so a state-level `timeout` cannot
810
+ // collide with an explicit `after` entry on the same state. Invoke timeouts
811
+ // are scheduled on the enclosing state; completion transitions cancel the
812
+ // timer separately, so it clears even when the parent state stays active.
813
+ const sources = [];
1417
814
  if (afterConfig) {
1418
- for (const delay of Object.keys(afterConfig)) {
1419
- const configTransition = afterConfig[delay];
1420
- const parsedDelay = Number.isNaN(+delay) ? delay : +delay;
1421
- const eventType = mutateEntryExitWithDelay(parsedDelay);
1422
- const resolvedDelay = getConfiguredDelayValue(parsedDelay, stateNode.machine.implementations.delays);
1423
- addDelayedTransitions(configTransition, eventType, resolvedDelay);
815
+ for (const key of Object.keys(afterConfig)) {
816
+ const delay = Number.isNaN(+key) ? key : +key;
817
+ sources.push({
818
+ event: createAfterEvent(delay, stateNode.id),
819
+ delay,
820
+ transitions: afterConfig[key],
821
+ fromDelaysMap: true
822
+ });
1424
823
  }
1425
824
  }
1426
-
1427
- // Desugar state-level `timeout` + `onTimeout` into a delayed transition.
1428
- // Uses a dedicated `xstate.timeout.<id>` event so it cannot collide with
1429
- // explicit `after` entries on the same state.
1430
825
  if (timeoutConfig !== undefined && onTimeoutConfig) {
1431
- const timeoutEvent = createTimeoutEvent(stateNode.id);
1432
- const timeoutEventType = scheduleDelayedEvent(stateNode, timeoutEvent, x => resolveDelay(timeoutConfig, x.delays, {
1433
- context: x.context,
1434
- event: x.event,
1435
- stateNode
1436
- }));
1437
- const resolvedDelay = typeof timeoutConfig === 'function' ? timeoutConfig : getConfiguredDelayValue(timeoutConfig, stateNode.machine.implementations.delays);
1438
- addDelayedTransitions(onTimeoutConfig, timeoutEventType, resolvedDelay);
826
+ sources.push({
827
+ event: createTimeoutEvent(stateNode.id),
828
+ delay: timeoutConfig,
829
+ transitions: onTimeoutConfig,
830
+ fromDelaysMap: true
831
+ });
1439
832
  }
1440
-
1441
- // Desugar invoke-level `timeout` + `onTimeout` into a delayed transition on
1442
- // the enclosing state. Completion transitions cancel this timer separately,
1443
- // so the timeout is cleared even when the parent state stays active.
1444
833
  for (const invokeDef of invokeDefs) {
1445
- const invokeTimeoutEvent = createInvokeTimeoutEvent(invokeDef.id);
1446
- const invokeTimeout = invokeDef.timeout;
1447
- const invokeTimeoutEventType = scheduleDelayedEvent(stateNode, invokeTimeoutEvent, x => resolveDelay(invokeTimeout, {}, {
834
+ sources.push({
835
+ event: createInvokeTimeoutEvent(invokeDef.id),
836
+ delay: invokeDef.timeout,
837
+ transitions: invokeDef.onTimeout,
838
+ fromDelaysMap: false
839
+ });
840
+ }
841
+
842
+ // `delay` here is the raw config value, retained only as metadata on the
843
+ // transition definition — the live delay is resolved at runtime in the
844
+ // scheduled entry action, so no eager resolution is needed.
845
+ const delayedTransitions = [];
846
+ for (const {
847
+ event,
848
+ delay,
849
+ transitions,
850
+ fromDelaysMap
851
+ } of sources) {
852
+ const eventType = scheduleDelayedEvent(stateNode, event, x => resolveDelay(delay, fromDelaysMap ? x.delays : {}, {
1448
853
  context: x.context,
1449
854
  event: x.event,
1450
855
  stateNode
1451
856
  }));
1452
- const invokeOnTimeout = invokeDef.onTimeout;
1453
- addDelayedTransitions(invokeOnTimeout, invokeTimeoutEventType, invokeTimeout);
857
+ for (const transition of toTransitionConfigArray(transitions)) {
858
+ delayedTransitions.push({
859
+ ...transition,
860
+ event: eventType,
861
+ delay
862
+ });
863
+ }
1454
864
  }
1455
865
  return delayedTransitions.map(delayedTransition => ({
1456
866
  ...formatTransition(stateNode, delayedTransition.event, delayedTransition),
@@ -1515,27 +925,13 @@ function formatRouteTransitions(rootStateNode) {
1515
925
  if ('$unserializable' in routeConfig) {
1516
926
  throw new Error(`State "${sn.id}" has a route that is not serializable. Re-provide the route function when reviving this machine.`);
1517
927
  }
1518
-
1519
- // Object-form route. A `guard` (string or function) on the object is
1520
- // only produced by the JSON layer (createMachineFromConfig) —
1521
- // authoring uses the function form above.
1522
- const userGuard = routeConfig.guard;
928
+ const {
929
+ guard: _guard,
930
+ ...routeOptions
931
+ } = routeConfig;
1523
932
  const transition = {
1524
- ...routeConfig,
1525
- guard: userGuard ? args => {
1526
- if (!routeMatches(args)) return false;
1527
- if (typeof userGuard === 'function') return userGuard(args);
1528
- if (typeof userGuard === 'string') {
1529
- const guardImpl = args.guards?.[userGuard];
1530
- if (!guardImpl) {
1531
- // A typo'd guard name must fail loudly — silently passing
1532
- // would allow the route and corrupt machine behavior.
1533
- throw new Error(`Guard '${userGuard}' is not implemented in machine '${rootStateNode.machine.id}'. Available guards: ${Object.keys(args.guards ?? {}).map(key => `'${key}'`).join(', ') || '(none)'}.` );
1534
- }
1535
- return guardImpl(args);
1536
- }
1537
- return true;
1538
- } : routeMatches,
933
+ ...routeOptions,
934
+ guard: routeMatches,
1539
935
  target: `#${routeId}`
1540
936
  };
1541
937
  routeTransitions.push(formatTransition(rootStateNode, 'xstate.route', transition));
@@ -1866,16 +1262,11 @@ function initialMicrostep(root, preInitialState, actorScope, initEvent, internal
1866
1262
 
1867
1263
  /** https://www.w3.org/TR/scxml/#microstepProcedure */
1868
1264
  function microstep(transitions, currentSnapshot, actorScope, event, isInitial, internalQueue) {
1869
- const actions = [];
1265
+ const executableActions = [];
1870
1266
  if (!transitions.length) {
1871
- return [currentSnapshot, actions];
1267
+ return [currentSnapshot, executableActions];
1872
1268
  }
1873
- const originalExecutor = actorScope.actionExecutor;
1874
- actorScope.actionExecutor = action => {
1875
- actions.push(action);
1876
- originalExecutor(action);
1877
- };
1878
- try {
1269
+ {
1879
1270
  const mutStateNodeSet = new Set(currentSnapshot._nodes);
1880
1271
  let historyValue = currentSnapshot.historyValue;
1881
1272
  const originalContext = currentSnapshot.context;
@@ -1948,7 +1339,9 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
1948
1339
  context: nextContext
1949
1340
  });
1950
1341
  }
1951
- nextState = resolveAndExecuteActionsWithContext(nextState, event, actorScope, exitActions);
1342
+ const [resolvedState, resolvedActions] = resolveActionsWithContext(nextState, event, actorScope, exitActions);
1343
+ nextState = resolvedState;
1344
+ executableActions.push(...resolvedActions);
1952
1345
  for (const def of exitStateNode.invoke) {
1953
1346
  const childActor = nextState.children[def.id];
1954
1347
  if (childActor && !childActor._isExternal) {
@@ -2183,7 +1576,10 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
2183
1576
  }
2184
1577
  }
2185
1578
  }
2186
- nextState = resolveAndExecuteActionsWithContext(nextState, event, actorScope, actions);
1579
+ const [resolvedState, resolvedActions] = resolveActionsWithContext(nextState, event, actorScope, actions);
1580
+ nextState = resolvedState;
1581
+ actions.length = 0;
1582
+ executableActions.push(...resolvedActions);
2187
1583
  if (context) {
2188
1584
  nextState.context = context;
2189
1585
  }
@@ -2234,7 +1630,9 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
2234
1630
  };
2235
1631
 
2236
1632
  // Execute transition content
2237
- nextState = resolveAndExecuteActionsWithContext(nextState, event, actorScope, transitionActions);
1633
+ const [resolvedTransitionState, transitionExecutableActions] = resolveActionsWithContext(nextState, event, actorScope, transitionActions);
1634
+ nextState = resolvedTransitionState;
1635
+ executableActions.push(...transitionExecutableActions);
2238
1636
  if (context && context !== currentSnapshot.context) {
2239
1637
  nextState = cloneMachineSnapshot(nextState, {
2240
1638
  context
@@ -2257,22 +1655,22 @@ function microstep(transitions, currentSnapshot, actorScope, event, isInitial, i
2257
1655
  }
2258
1656
  }
2259
1657
  });
2260
- nextState = resolveAndExecuteActionsWithContext(nextState, event, actorScope, allExitActions);
1658
+ const [resolvedState, resolvedActions] = resolveActionsWithContext(nextState, event, actorScope, allExitActions);
1659
+ nextState = resolvedState;
1660
+ executableActions.push(...resolvedActions);
2261
1661
  }
2262
1662
  if (historyValue === currentSnapshot.historyValue && currentSnapshot._nodes.length === mutStateNodeSet.size && currentSnapshot._nodes.every(node => mutStateNodeSet.has(node))) {
2263
1663
  // If context was changed (e.g. by entry actions during self-transition),
2264
1664
  // clone to ensure reference inequality for eventless transition re-evaluation
2265
1665
  if (nextState.context !== originalContext) {
2266
- return [cloneMachineSnapshot(nextState), actions];
1666
+ return [cloneMachineSnapshot(nextState), executableActions];
2267
1667
  }
2268
- return [nextState, actions];
1668
+ return [nextState, executableActions];
2269
1669
  }
2270
1670
  return [cloneMachineSnapshot(nextState, {
2271
1671
  _nodes: nextStateNodes,
2272
1672
  historyValue
2273
- }), actions];
2274
- } finally {
2275
- actorScope.actionExecutor = originalExecutor;
1673
+ }), executableActions];
2276
1674
  }
2277
1675
  }
2278
1676
 
@@ -2533,24 +1931,7 @@ function evaluateCandidate(candidate, event, snapshot, stateNode, self) {
2533
1931
  delays: stateNode.machine.implementations.delays,
2534
1932
  _snapshot: snapshot
2535
1933
  };
2536
- const guardConfig = candidate.guard;
2537
- const guardParams = typeof guardConfig?.params === 'function' ? guardConfig.params({
2538
- context: snapshot.context,
2539
- event
2540
- }) : guardConfig?.params;
2541
- let guardPassed = true;
2542
- if (typeof guardConfig === 'function') {
2543
- guardPassed = guardConfig(guardArgs, guardParams);
2544
- } else if (typeof guardConfig?.type === 'string') {
2545
- const guardImpl = stateNode.machine.implementations.guards[guardConfig.type];
2546
- if (!guardImpl) {
2547
- // A typo'd guard name must fail loudly — silently passing would
2548
- // take the guarded transition and corrupt machine behavior.
2549
- throw new Error(`Guard '${guardConfig.type}' is not implemented in machine '${stateNode.machine.id}'. Available guards: ${Object.keys(stateNode.machine.implementations.guards).map(key => `'${key}'`).join(', ') || '(none)'}.` );
2550
- }
2551
- guardPassed = guardImpl(guardArgs, guardParams);
2552
- }
2553
- if (!guardPassed) {
1934
+ if (!candidate.guard(guardArgs)) {
2554
1935
  return false;
2555
1936
  }
2556
1937
  }
@@ -3375,7 +2756,7 @@ function createLogic(config) {
3375
2756
  Object.assign(snapshot, nextSnapshot);
3376
2757
  executeLogicEffects(effects, actorScope);
3377
2758
  },
3378
- getInitialSnapshot: (_, input) => {
2759
+ initialTransition: (input, _) => {
3379
2760
  const context = resolveContext(config.context, input);
3380
2761
  const snapshot = {
3381
2762
  status: 'active',
@@ -3386,10 +2767,11 @@ function createLogic(config) {
3386
2767
  if (context !== undefined) {
3387
2768
  snapshot.context = context;
3388
2769
  }
3389
- return {
2770
+ return [{
3390
2771
  ...snapshot
3391
- };
2772
+ }, []];
3392
2773
  },
2774
+ getInitialSnapshot: (actorScope, input) => logic.initialTransition(input, actorScope)[0],
3393
2775
  getPersistedSnapshot: snapshot => snapshot,
3394
2776
  restoreSnapshot: snapshot => snapshot
3395
2777
  };
@@ -3419,6 +2801,23 @@ const defaultOptions = {
3419
2801
  },
3420
2802
  logger: console.log.bind(console)
3421
2803
  };
2804
+ function isExecutableActionObject(effect) {
2805
+ return typeof effect === 'object' && effect !== null && 'args' in effect && 'exec' in effect;
2806
+ }
2807
+ function executeExecutableEffects(effects, actorScope) {
2808
+ if (!effects?.length) {
2809
+ return [];
2810
+ }
2811
+ const logicEffects = [];
2812
+ for (const effect of effects) {
2813
+ if (isExecutableActionObject(effect)) {
2814
+ actorScope.actionExecutor(effect);
2815
+ } else {
2816
+ logicEffects.push(effect);
2817
+ }
2818
+ }
2819
+ return logicEffects;
2820
+ }
3422
2821
 
3423
2822
  /**
3424
2823
  * An Actor is a running process that can receive events, send events and change
@@ -3457,6 +2856,7 @@ class Actor {
3457
2856
  this.logger = void 0;
3458
2857
  /** @internal */
3459
2858
  this._processingStatus = ProcessingStatus.NotStarted;
2859
+ this._forceDeferredActions = false;
3460
2860
  // Actor Ref
3461
2861
  this._parent = void 0;
3462
2862
  /** @internal */
@@ -3472,6 +2872,7 @@ class Actor {
3472
2872
  this._collectedActions = [];
3473
2873
  /** @internal Events relayed to other actors during the in-flight transition. */
3474
2874
  this._collectedSent = [];
2875
+ this._initialEffects = void 0;
3475
2876
  this.systemId = void 0;
3476
2877
  /** The globally unique process ID for this invocation. */
3477
2878
  this.sessionId = void 0;
@@ -3574,7 +2975,7 @@ class Actor {
3574
2975
  executingCustomAction = saveExecutingCustomAction;
3575
2976
  }
3576
2977
  };
3577
- if (this._processingStatus === ProcessingStatus.Running) {
2978
+ if (this._processingStatus === ProcessingStatus.Running && !this._forceDeferredActions) {
3578
2979
  exec();
3579
2980
  } else {
3580
2981
  this._deferred.push(exec);
@@ -3603,7 +3004,7 @@ class Actor {
3603
3004
  this.system._set(systemId, this);
3604
3005
  }
3605
3006
 
3606
- // prepare to collect initial microsteps during getInitialSnapshot
3007
+ // prepare to collect initial microsteps during initialTransition
3607
3008
  this._collectedMicrosteps = [];
3608
3009
  let persistedState = options?.snapshot ?? options?.state;
3609
3010
  if (persistedState && typeof persistedState === 'object' && '_pendingEffects' in persistedState) {
@@ -3617,7 +3018,13 @@ class Actor {
3617
3018
  persistedState = rest;
3618
3019
  }
3619
3020
  try {
3620
- this._snapshot = persistedState ? this.logic.restoreSnapshot ? this.logic.restoreSnapshot(persistedState, this._actorScope) : persistedState : this.logic.getInitialSnapshot(this._actorScope, this.options?.input);
3021
+ if (persistedState) {
3022
+ this._snapshot = this.logic.restoreSnapshot ? this.logic.restoreSnapshot(persistedState, this._actorScope) : persistedState;
3023
+ } else {
3024
+ const [snapshot, effects] = this.logic.initialTransition(this.options?.input, this._actorScope);
3025
+ this._snapshot = snapshot;
3026
+ this._initialEffects = effects;
3027
+ }
3621
3028
  } catch (err) {
3622
3029
  // if we get here then it means that we assign a value to this._snapshot that is not of the correct type
3623
3030
  // we can't get the true `TSnapshot & { status: 'error'; }`, it's impossible
@@ -3726,6 +3133,26 @@ class Actor {
3726
3133
  this._collectedActions = [];
3727
3134
  this._collectedSent = [];
3728
3135
  }
3136
+ _flushInitialEffects() {
3137
+ if (!this._initialEffects) {
3138
+ return true;
3139
+ }
3140
+ this._forceDeferredActions = true;
3141
+ try {
3142
+ const logicEffects = executeExecutableEffects(this._initialEffects, this._actorScope);
3143
+ executeLogicEffects(logicEffects, this._actorScope);
3144
+ this._initialEffects = undefined;
3145
+ return true;
3146
+ } catch (err) {
3147
+ this._initialEffects = undefined;
3148
+ this._deferred.length = 0;
3149
+ this._setErrorSnapshot(err);
3150
+ this._error(err);
3151
+ return false;
3152
+ } finally {
3153
+ this._forceDeferredActions = false;
3154
+ }
3155
+ }
3729
3156
 
3730
3157
  /**
3731
3158
  * Subscribe an observer to an actor’s snapshot values.
@@ -3852,7 +3279,7 @@ class Actor {
3852
3279
  complete: observer.complete
3853
3280
  });
3854
3281
  },
3855
- get: () => selector(this.get())
3282
+ get: () => selector(this.getSnapshot())
3856
3283
  };
3857
3284
  }
3858
3285
 
@@ -3890,6 +3317,9 @@ class Actor {
3890
3317
  case 'done':
3891
3318
  // a state machine can be "done" upon initialization (it could reach a final state using initial microsteps)
3892
3319
  // we still need to complete observers, flush deferreds etc
3320
+ if (!this._flushInitialEffects()) {
3321
+ return this;
3322
+ }
3893
3323
  this.update(this._snapshot, initEvent);
3894
3324
  // TODO: rethink cleanup of observers, mailbox, etc
3895
3325
  return this;
@@ -3909,6 +3339,9 @@ class Actor {
3909
3339
  return this;
3910
3340
  }
3911
3341
  }
3342
+ if (!this._flushInitialEffects()) {
3343
+ return this;
3344
+ }
3912
3345
 
3913
3346
  // TODO: this notifies all subscribers but usually this is redundant
3914
3347
  // there is no real change happening here
@@ -3947,9 +3380,16 @@ class Actor {
3947
3380
  this._error(err);
3948
3381
  return;
3949
3382
  }
3950
- const [snapshot, effects] = Array.isArray(nextState) ? nextState : [nextState, undefined];
3951
- this.update(snapshot, event);
3952
- executeLogicEffects(effects, this._actorScope);
3383
+ try {
3384
+ const [snapshot, effects] = nextState;
3385
+ const logicEffects = executeExecutableEffects(effects, this._actorScope);
3386
+ this.update(snapshot, event);
3387
+ executeLogicEffects(logicEffects, this._actorScope);
3388
+ } catch (err) {
3389
+ this._setErrorSnapshot(err);
3390
+ this._error(err);
3391
+ return;
3392
+ }
3953
3393
  if (event.type === XSTATE_STOP) {
3954
3394
  this._stopProcedure();
3955
3395
  this._complete();
@@ -4141,15 +3581,9 @@ class Actor {
4141
3581
  * @see {@link Actor.getPersistedSnapshot} to persist the internal state of an actor (which is more than just a snapshot).
4142
3582
  */
4143
3583
  getSnapshot() {
4144
- return this.get();
4145
- }
4146
-
4147
- /** Read the actor's current snapshot as an atom value. */
4148
- get() {
4149
3584
  if (!this._snapshot) {
4150
3585
  throw new Error(`Snapshot can't be read while the actor initializes itself`);
4151
3586
  }
4152
- onActorRead?.(this);
4153
3587
  return this._snapshot;
4154
3588
  }
4155
3589
  }
@@ -4588,46 +4022,45 @@ function createEventObservableLogic(lazyObservableOrConfig) {
4588
4022
  config: lazyObservable,
4589
4023
  transition: (state, event) => {
4590
4024
  if (state.status !== 'active') {
4591
- return state;
4025
+ return [state, []];
4592
4026
  }
4593
4027
  switch (event.type) {
4594
4028
  case XSTATE_OBSERVABLE_ERROR:
4595
- return {
4029
+ return [{
4596
4030
  ...state,
4597
4031
  status: 'error',
4598
4032
  error: event.data,
4599
4033
  input: undefined,
4600
4034
  _subscription: undefined
4601
- };
4035
+ }, []];
4602
4036
  case XSTATE_OBSERVABLE_COMPLETE:
4603
- return {
4037
+ return [{
4604
4038
  ...state,
4605
4039
  status: 'done',
4606
4040
  input: undefined,
4607
4041
  _subscription: undefined
4608
- };
4042
+ }, []];
4609
4043
  case XSTATE_STOP:
4610
4044
  state._subscription.unsubscribe();
4611
- return {
4045
+ return [{
4612
4046
  ...state,
4613
4047
  status: 'stopped',
4614
4048
  input: undefined,
4615
4049
  _subscription: undefined
4616
- };
4050
+ }, []];
4617
4051
  default:
4618
- return state;
4052
+ return [state, []];
4619
4053
  }
4620
4054
  },
4621
- getInitialSnapshot: (_, input) => {
4622
- return {
4623
- status: 'active',
4624
- output: undefined,
4625
- error: undefined,
4626
- context: undefined,
4627
- input,
4628
- _subscription: undefined
4629
- };
4630
- },
4055
+ initialTransition: (input, _) => [{
4056
+ status: 'active',
4057
+ output: undefined,
4058
+ error: undefined,
4059
+ context: undefined,
4060
+ input,
4061
+ _subscription: undefined
4062
+ }, []],
4063
+ getInitialSnapshot: (actorScope, input) => logic.initialTransition(input, actorScope)[0],
4631
4064
  start: (state, {
4632
4065
  self,
4633
4066
  system,
@@ -4945,4 +4378,4 @@ function createEmptyActor() {
4945
4378
  return createActor(emptyLogic);
4946
4379
  }
4947
4380
 
4948
- export { isStateId as $, Actor as A, createAsyncLogic as B, createListenerLogic as C, listenerLogic as D, createSubscriptionLogic as E, subscriptionLogic as F, resolveReferencedActor as G, mapValues as H, createInvokeId as I, getDelayedTransitions as J, evaluateCandidate as K, formatTransition as L, toTransitionConfigArray as M, NULL_EVENT as N, createInvokeTimeoutEvent as O, ProcessingStatus as P, getCandidates as Q, formatRouteTransitions as R, STATE_DELIMITER as S, TimeoutError as T, resolveStateValue as U, getAllStateNodes as V, createMachineSnapshot as W, isInFinalState as X, transitionNode as Y, resolveAndExecuteActionsWithContext as Z, toStatePath as _, macrostep as a, getStateNodeByPath as a0, getPersistedSnapshot as a1, $$ACTOR_TYPE as a2, XSTATE_INIT as a3, createInitEvent as b, createActor as c, initialMicrostep as d, createAtom as e, createAtomConfig as f, getProperAncestors as g, createAsyncAtom as h, isAtomicStateNode as i, createReducerAtom as j, isAtom as k, isMachineSnapshot as l, matchesEventDescriptor as m, getStateNodes as n, getAllOwnEventDescriptors as o, parseDelayToMilliseconds as p, matchesState as q, checkStateIn as r, pathToStateValue as s, toArray as t, toObserver as u, createEmptyActor as v, createCallbackLogic as w, createObservableLogic as x, createEventObservableLogic as y, createLogic as z };
4381
+ export { $$ACTOR_TYPE as $, Actor as A, subscriptionLogic as B, resolveReferencedActor as C, mapValues as D, createInvokeId as E, getDelayedTransitions as F, evaluateCandidate as G, formatTransition as H, toTransitionConfigArray as I, createInvokeTimeoutEvent as J, getCandidates as K, formatRouteTransitions as L, resolveStateValue as M, NULL_EVENT as N, getAllStateNodes as O, ProcessingStatus as P, createMachineSnapshot as Q, isInFinalState as R, STATE_DELIMITER as S, TimeoutError as T, transitionNode as U, resolveActionsWithContext as V, toStatePath as W, isStateId as X, getStateNodeByPath as Y, getPersistedSnapshot as Z, XSTATE_INIT as _, macrostep as a, createInitEvent as b, createActor as c, initialMicrostep as d, isMachineSnapshot as e, getStateNodes as f, getProperAncestors as g, getAllOwnEventDescriptors as h, isAtomicStateNode as i, matchesState as j, checkStateIn as k, pathToStateValue as l, matchesEventDescriptor as m, toObserver as n, isBuiltInExecutableAction as o, parseDelayToMilliseconds as p, createEmptyActor as q, createCallbackLogic as r, createObservableLogic as s, toArray as t, createEventObservableLogic as u, createLogic as v, createAsyncLogic as w, createListenerLogic as x, listenerLogic as y, createSubscriptionLogic as z };