xstate 5.0.0-beta.33 → 5.0.0-beta.35

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 (41) hide show
  1. package/README.md +1 -1
  2. package/actions/dist/xstate-actions.cjs.js +3 -3
  3. package/actions/dist/xstate-actions.development.cjs.js +3 -3
  4. package/actions/dist/xstate-actions.development.esm.js +3 -3
  5. package/actions/dist/xstate-actions.esm.js +3 -3
  6. package/actions/dist/xstate-actions.umd.min.js +1 -1
  7. package/actions/dist/xstate-actions.umd.min.js.map +1 -1
  8. package/actors/dist/xstate-actors.cjs.js +3 -3
  9. package/actors/dist/xstate-actors.development.cjs.js +3 -3
  10. package/actors/dist/xstate-actors.development.esm.js +3 -3
  11. package/actors/dist/xstate-actors.esm.js +3 -3
  12. package/actors/dist/xstate-actors.umd.min.js +1 -1
  13. package/actors/dist/xstate-actors.umd.min.js.map +1 -1
  14. package/dist/declarations/src/index.d.ts +1 -0
  15. package/dist/declarations/src/interpreter.d.ts +3 -1
  16. package/dist/declarations/src/stateUtils.d.ts +6 -5
  17. package/dist/declarations/src/types.d.ts +3 -5
  18. package/dist/{interpreter-825f3d6e.development.esm.js → interpreter-5c4e6634.development.esm.js} +67 -65
  19. package/dist/{interpreter-054e9fb7.cjs.js → interpreter-69605bf0.cjs.js} +67 -65
  20. package/dist/{interpreter-0c630f66.development.cjs.js → interpreter-d3567419.development.cjs.js} +67 -65
  21. package/dist/{interpreter-03737810.esm.js → interpreter-de5217bc.esm.js} +67 -65
  22. package/dist/{raise-987c242e.cjs.js → raise-0ff57677.cjs.js} +142 -124
  23. package/dist/{raise-4c6a5a96.development.cjs.js → raise-26e4d83c.development.cjs.js} +145 -124
  24. package/dist/{raise-2d92eae8.esm.js → raise-511399cc.esm.js} +142 -124
  25. package/dist/{raise-46f122aa.development.esm.js → raise-cdcdf834.development.esm.js} +145 -124
  26. package/dist/{send-bd1bd0e3.cjs.js → send-19ffc568.cjs.js} +16 -8
  27. package/dist/{send-4d5b92dc.development.esm.js → send-1de74f4d.development.esm.js} +16 -8
  28. package/dist/{send-0edee2b4.esm.js → send-211a2a94.esm.js} +16 -8
  29. package/dist/{send-0e8675c8.development.cjs.js → send-894c4b18.development.cjs.js} +16 -8
  30. package/dist/xstate.cjs.js +28 -9
  31. package/dist/xstate.development.cjs.js +28 -9
  32. package/dist/xstate.development.esm.js +31 -12
  33. package/dist/xstate.esm.js +31 -12
  34. package/dist/xstate.umd.min.js +1 -1
  35. package/dist/xstate.umd.min.js.map +1 -1
  36. package/guards/dist/xstate-guards.cjs.js +2 -2
  37. package/guards/dist/xstate-guards.development.cjs.js +2 -2
  38. package/guards/dist/xstate-guards.development.esm.js +2 -2
  39. package/guards/dist/xstate-guards.esm.js +2 -2
  40. package/guards/dist/xstate-guards.umd.min.js.map +1 -1
  41. package/package.json +1 -1
@@ -9,62 +9,6 @@ const XSTATE_INIT = 'xstate.init';
9
9
  const XSTATE_ERROR = 'xstate.error';
10
10
  const XSTATE_STOP = 'xstate.stop';
11
11
 
12
- /**
13
- * Returns an event that represents an implicit event that
14
- * is sent after the specified `delay`.
15
- *
16
- * @param delayRef The delay in milliseconds
17
- * @param id The state node ID where this event is handled
18
- */
19
- function createAfterEvent(delayRef, id) {
20
- const idSuffix = id ? `#${id}` : '';
21
- return {
22
- type: `xstate.after(${delayRef})${idSuffix}`
23
- };
24
- }
25
-
26
- /**
27
- * Returns an event that represents that a final state node
28
- * has been reached in the parent state node.
29
- *
30
- * @param id The final state node's parent state node `id`
31
- * @param output The data to pass into the event
32
- */
33
- function createDoneStateEvent(id, output) {
34
- return {
35
- type: `xstate.done.state.${id}`,
36
- output
37
- };
38
- }
39
-
40
- /**
41
- * Returns an event that represents that an invoked service has terminated.
42
- *
43
- * An invoked service is terminated when it has reached a top-level final state node,
44
- * but not when it is canceled.
45
- *
46
- * @param invokeId The invoked service ID
47
- * @param output The data to pass into the event
48
- */
49
- function createDoneActorEvent(invokeId, output) {
50
- return {
51
- type: `xstate.done.actor.${invokeId}`,
52
- output
53
- };
54
- }
55
- function createErrorActorEvent(id, data) {
56
- return {
57
- type: `xstate.error.actor.${id}`,
58
- data
59
- };
60
- }
61
- function createInitEvent(input) {
62
- return {
63
- type: XSTATE_INIT,
64
- input
65
- };
66
- }
67
-
68
12
  class Mailbox {
69
13
  constructor(_process) {
70
14
  this._process = _process;
@@ -132,6 +76,62 @@ class Mailbox {
132
76
  }
133
77
  }
134
78
 
79
+ /**
80
+ * Returns an event that represents an implicit event that
81
+ * is sent after the specified `delay`.
82
+ *
83
+ * @param delayRef The delay in milliseconds
84
+ * @param id The state node ID where this event is handled
85
+ */
86
+ function createAfterEvent(delayRef, id) {
87
+ const idSuffix = id ? `#${id}` : '';
88
+ return {
89
+ type: `xstate.after(${delayRef})${idSuffix}`
90
+ };
91
+ }
92
+
93
+ /**
94
+ * Returns an event that represents that a final state node
95
+ * has been reached in the parent state node.
96
+ *
97
+ * @param id The final state node's parent state node `id`
98
+ * @param output The data to pass into the event
99
+ */
100
+ function createDoneStateEvent(id, output) {
101
+ return {
102
+ type: `xstate.done.state.${id}`,
103
+ output
104
+ };
105
+ }
106
+
107
+ /**
108
+ * Returns an event that represents that an invoked service has terminated.
109
+ *
110
+ * An invoked service is terminated when it has reached a top-level final state node,
111
+ * but not when it is canceled.
112
+ *
113
+ * @param invokeId The invoked service ID
114
+ * @param output The data to pass into the event
115
+ */
116
+ function createDoneActorEvent(invokeId, output) {
117
+ return {
118
+ type: `xstate.done.actor.${invokeId}`,
119
+ output
120
+ };
121
+ }
122
+ function createErrorActorEvent(id, data) {
123
+ return {
124
+ type: `xstate.error.actor.${id}`,
125
+ data
126
+ };
127
+ }
128
+ function createInitEvent(input) {
129
+ return {
130
+ type: XSTATE_INIT,
131
+ input
132
+ };
133
+ }
134
+
135
135
  /**
136
136
  * This function makes sure that unhandled errors are thrown in a separate macrotask.
137
137
  * It allows those errors to be detected by global error handlers and reported to bug tracking services
@@ -340,6 +340,7 @@ function resolveReferencedActor(referenced) {
340
340
  } : referenced : undefined;
341
341
  }
342
342
 
343
+ const $$ACTOR_TYPE = 1;
343
344
  let ActorStatus = /*#__PURE__*/function (ActorStatus) {
344
345
  ActorStatus[ActorStatus["NotStarted"] = 0] = "NotStarted";
345
346
  ActorStatus[ActorStatus["Running"] = 1] = "Running";
@@ -557,7 +558,7 @@ class Actor {
557
558
  const status = this._state.status;
558
559
  switch (status) {
559
560
  case 'done':
560
- // a state machine can be "done" upon intialization (it could reach a final state using initial microsteps)
561
+ // a state machine can be "done" upon initialization (it could reach a final state using initial microsteps)
561
562
  // we still need to complete observers, flush deferreds etc
562
563
  this.update(this._state, initEvent);
563
564
  // fallthrough
@@ -712,14 +713,14 @@ class Actor {
712
713
  }
713
714
 
714
715
  // TODO: make private (and figure out a way to do this within the machine)
715
- delaySend({
716
- event,
717
- id,
718
- delay,
719
- to
720
- }) {
716
+ delaySend(params) {
717
+ const {
718
+ event,
719
+ id,
720
+ delay
721
+ } = params;
721
722
  const timerId = this.clock.setTimeout(() => {
722
- this.system._relay(this, to ?? this, event);
723
+ this.system._relay(this, params.to ?? this, event);
723
724
  }, delay);
724
725
 
725
726
  // TODO: consider the rehydration story here
@@ -744,6 +745,7 @@ class Actor {
744
745
  }
745
746
  toJSON() {
746
747
  return {
748
+ xstate$$type: $$ACTOR_TYPE,
747
749
  id: this.id
748
750
  };
749
751
  }
@@ -781,4 +783,4 @@ const interpret = createActor;
781
783
  * @deprecated Use `Actor` instead.
782
784
  */
783
785
 
784
- export { Actor as A, InterpreterStatus as I, NULL_EVENT as N, STATE_DELIMITER as S, WILDCARD as W, XSTATE_INIT as X, toTransitionConfigArray as a, createInitEvent as b, createInvokeId as c, createActor as d, matchesState as e, ActorStatus as f, interpret as g, toObserver as h, isErrorActorEvent as i, XSTATE_STOP as j, createErrorActorEvent as k, toStateValue as l, mapValues as m, STATE_IDENTIFIER as n, normalizeTarget as o, pathToStateValue as p, toStatePath as q, resolveReferencedActor as r, createDoneStateEvent as s, toArray as t, resolveOutput as u, isArray as v, createAfterEvent as w, flatten as x, XSTATE_ERROR as y };
786
+ export { $$ACTOR_TYPE as $, Actor as A, InterpreterStatus as I, NULL_EVENT as N, STATE_DELIMITER as S, WILDCARD as W, XSTATE_STOP as X, toTransitionConfigArray as a, createInitEvent as b, createInvokeId as c, createActor as d, matchesState as e, ActorStatus as f, interpret as g, toObserver as h, isErrorActorEvent as i, createErrorActorEvent as j, toStateValue as k, STATE_IDENTIFIER as l, mapValues as m, normalizeTarget as n, toStatePath as o, pathToStateValue as p, createDoneStateEvent as q, resolveReferencedActor as r, resolveOutput as s, toArray as t, XSTATE_INIT as u, createAfterEvent as v, flatten as w, XSTATE_ERROR as x };
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var interpreter = require('./interpreter-054e9fb7.cjs.js');
3
+ var interpreter = require('./interpreter-69605bf0.cjs.js');
4
4
 
5
5
  const cache = new WeakMap();
6
6
  function memo(object, key, fn) {
@@ -279,20 +279,6 @@ function evaluateGuard(guard, context, event, state) {
279
279
  );
280
280
  }
281
281
 
282
- function getOutput(configuration, context, event, self) {
283
- const {
284
- machine
285
- } = configuration[0];
286
- const {
287
- root
288
- } = machine;
289
- if (!root.output) {
290
- return undefined;
291
- }
292
- const finalChildStateNode = configuration.find(stateNode => stateNode.type === 'final' && stateNode.parent === machine.root);
293
- const doneStateEvent = interpreter.createDoneStateEvent(finalChildStateNode.id, finalChildStateNode.output ? interpreter.resolveOutput(finalChildStateNode.output, context, event, self) : undefined);
294
- return interpreter.resolveOutput(root.output, context, doneStateEvent, self);
295
- }
296
282
  const isAtomicStateNode = stateNode => stateNode.type === 'atomic' || stateNode.type === 'final';
297
283
  function getChildren(stateNode) {
298
284
  return Object.values(stateNode.states).filter(sn => sn.type !== 'history');
@@ -317,7 +303,7 @@ function getConfiguration(stateNodes) {
317
303
  for (const s of configuration) {
318
304
  // if previously active, add existing child nodes
319
305
  if (s.type === 'compound' && (!adjList.get(s) || !adjList.get(s).length)) {
320
- getInitialStateNodes(s).forEach(sn => configurationSet.add(sn));
306
+ getInitialStateNodesWithTheirAncestors(s).forEach(sn => configurationSet.add(sn));
321
307
  } else {
322
308
  if (s.type === 'parallel') {
323
309
  for (const child of getChildren(s)) {
@@ -325,7 +311,8 @@ function getConfiguration(stateNodes) {
325
311
  continue;
326
312
  }
327
313
  if (!configurationSet.has(child)) {
328
- for (const initialStateNode of getInitialStateNodes(child)) {
314
+ const initialStates = getInitialStateNodesWithTheirAncestors(child);
315
+ for (const initialStateNode of initialStates) {
329
316
  configurationSet.add(initialStateNode);
330
317
  }
331
318
  }
@@ -385,14 +372,14 @@ function getStateValue(rootNode, configuration) {
385
372
  const config = getConfiguration(configuration);
386
373
  return getValueFromAdj(rootNode, getAdjList(config));
387
374
  }
388
- function isInFinalState(configuration, stateNode = configuration[0].machine.root) {
375
+ function isInFinalState(configuration, stateNode) {
389
376
  if (stateNode.type === 'compound') {
390
- return getChildren(stateNode).some(s => s.type === 'final' && configuration.includes(s));
377
+ return getChildren(stateNode).some(s => s.type === 'final' && configuration.has(s));
391
378
  }
392
379
  if (stateNode.type === 'parallel') {
393
380
  return getChildren(stateNode).every(sn => isInFinalState(configuration, sn));
394
381
  }
395
- return false;
382
+ return stateNode.type === 'final';
396
383
  }
397
384
  const isStateId = str => str[0] === interpreter.STATE_IDENTIFIER;
398
385
  function getCandidates(stateNode, receivedEventType) {
@@ -442,13 +429,7 @@ function getDelayedTransitions(stateNode) {
442
429
  stateNode.exit.push(cancel(eventType));
443
430
  return eventType;
444
431
  };
445
- const delayedTransitions = interpreter.isArray(afterConfig) ? afterConfig.map((transition, i) => {
446
- const eventType = mutateEntryExit(transition.delay, i);
447
- return {
448
- ...transition,
449
- event: eventType
450
- };
451
- }) : Object.keys(afterConfig).flatMap((delay, i) => {
432
+ const delayedTransitions = Object.keys(afterConfig).flatMap((delay, i) => {
452
433
  const configTransition = afterConfig[delay];
453
434
  const resolvedTransition = typeof configTransition === 'string' ? {
454
435
  target: configTransition
@@ -531,43 +512,23 @@ function formatTransitions(stateNode) {
531
512
  return transitions;
532
513
  }
533
514
  function formatInitialTransition(stateNode, _target) {
534
- if (typeof _target === 'string' || interpreter.isArray(_target)) {
535
- const targets = interpreter.toArray(_target).map(t => {
536
- // Resolve state string keys (which represent children)
537
- // to their state node
538
- const descStateNode = typeof t === 'string' ? isStateId(t) ? stateNode.machine.getStateNodeById(t) : stateNode.states[t] : t;
539
- if (!descStateNode) {
540
- throw new Error(`Initial state node "${t}" not found on parent state node #${stateNode.id}`);
541
- }
542
- if (!isDescendant(descStateNode, stateNode)) {
543
- throw new Error(`Invalid initial target: state node #${descStateNode.id} is not a descendant of #${stateNode.id}`);
544
- }
545
- return descStateNode;
546
- });
547
- const resolvedTarget = resolveTarget(stateNode, targets);
548
- const transition = {
549
- source: stateNode,
550
- actions: [],
551
- eventType: null,
552
- reenter: false,
553
- target: resolvedTarget,
554
- toJSON: () => ({
555
- ...transition,
556
- source: `#${stateNode.id}`,
557
- target: resolvedTarget ? resolvedTarget.map(t => `#${t.id}`) : undefined
558
- })
559
- };
560
- return transition;
515
+ const resolvedTarget = typeof _target === 'string' ? stateNode.states[_target] : _target ? stateNode.states[_target.target] : undefined;
516
+ if (!resolvedTarget && _target) {
517
+ throw new Error(`Initial state node "${_target}" not found on parent state node #${stateNode.id}`);
561
518
  }
562
- return formatTransition(stateNode, '__INITIAL__', {
563
- target: interpreter.toArray(_target.target).map(t => {
564
- if (typeof t === 'string') {
565
- return isStateId(t) ? t : `${interpreter.STATE_DELIMITER}${t}`;
566
- }
567
- return t;
568
- }),
569
- actions: _target.actions
570
- });
519
+ const transition = {
520
+ source: stateNode,
521
+ actions: !_target || typeof _target === 'string' ? [] : interpreter.toArray(_target.actions),
522
+ eventType: null,
523
+ reenter: false,
524
+ target: resolvedTarget ? [resolvedTarget] : [],
525
+ toJSON: () => ({
526
+ ...transition,
527
+ source: `#${stateNode.id}`,
528
+ target: resolvedTarget ? [`#${resolvedTarget.id}`] : []
529
+ })
530
+ };
531
+ return transition;
571
532
  }
572
533
  function resolveTarget(stateNode, targets) {
573
534
  if (targets === undefined) {
@@ -610,6 +571,15 @@ function resolveHistoryTarget(stateNode) {
610
571
  function isHistoryNode(stateNode) {
611
572
  return stateNode.type === 'history';
612
573
  }
574
+ function getInitialStateNodesWithTheirAncestors(stateNode) {
575
+ const states = getInitialStateNodes(stateNode);
576
+ for (const initialState of states) {
577
+ for (const ancestor of getProperAncestors(initialState, stateNode)) {
578
+ states.add(ancestor);
579
+ }
580
+ }
581
+ return states;
582
+ }
613
583
  function getInitialStateNodes(stateNode) {
614
584
  const set = new Set();
615
585
  function iter(descStateNode) {
@@ -618,12 +588,7 @@ function getInitialStateNodes(stateNode) {
618
588
  }
619
589
  set.add(descStateNode);
620
590
  if (descStateNode.type === 'compound') {
621
- for (const targetStateNode of descStateNode.initial.target) {
622
- for (const a of getProperAncestors(targetStateNode, stateNode)) {
623
- set.add(a);
624
- }
625
- iter(targetStateNode);
626
- }
591
+ iter(descStateNode.initial.target[0]);
627
592
  } else if (descStateNode.type === 'parallel') {
628
593
  for (const child of getChildren(descStateNode)) {
629
594
  iter(child);
@@ -631,7 +596,7 @@ function getInitialStateNodes(stateNode) {
631
596
  }
632
597
  }
633
598
  iter(stateNode);
634
- return [...set];
599
+ return set;
635
600
  }
636
601
  /**
637
602
  * Returns the child state node from its relative `stateKey`, or throws.
@@ -887,41 +852,37 @@ function microstep(transitions, currentState, actorCtx, event, isInitial) {
887
852
  }
888
853
 
889
854
  function microstepProcedure(transitions, currentState, mutConfiguration, event, actorCtx, isInitial) {
890
- const actions = [];
891
855
  const historyValue = {
892
856
  ...currentState.historyValue
893
857
  };
894
858
  const filteredTransitions = removeConflictingTransitions(transitions, mutConfiguration, historyValue);
895
859
  const internalQueue = [...currentState._internalQueue];
860
+ // TODO: this `cloneState` is really just a hack to prevent infinite loops
861
+ // we need to take another look at how internal queue is managed
862
+ let nextState = cloneState(currentState, {
863
+ _internalQueue: []
864
+ });
896
865
 
897
866
  // Exit states
898
867
  if (!isInitial) {
899
- exitStates(filteredTransitions, mutConfiguration, historyValue, actions);
868
+ nextState = exitStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, historyValue);
900
869
  }
901
870
 
902
871
  // Execute transition content
903
- actions.push(...filteredTransitions.flatMap(t => t.actions));
872
+ nextState = resolveActionsAndContext(nextState, event, actorCtx, filteredTransitions.flatMap(t => t.actions));
904
873
 
905
874
  // Enter states
906
- enterStates(event, filteredTransitions, mutConfiguration, actions, internalQueue, currentState, historyValue, isInitial, actorCtx);
875
+ nextState = enterStates(nextState, event, actorCtx, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial);
907
876
  const nextConfiguration = [...mutConfiguration];
908
- const done = isInFinalState(nextConfiguration);
909
- if (done) {
910
- const finalActions = nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit);
911
- actions.push(...finalActions);
877
+ if (nextState.status === 'done') {
878
+ nextState = resolveActionsAndContext(nextState, event, actorCtx, nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit));
912
879
  }
913
880
  try {
914
- const nextState = resolveActionsAndContext(actions, event, currentState, actorCtx);
915
- const output = done ? getOutput(nextConfiguration, nextState.context, event, actorCtx.self) : undefined;
916
881
  internalQueue.push(...nextState._internalQueue);
917
- return cloneState(currentState, {
882
+ return cloneState(nextState, {
918
883
  configuration: nextConfiguration,
919
884
  historyValue,
920
- _internalQueue: internalQueue,
921
- context: nextState.context,
922
- status: done ? 'done' : currentState.status,
923
- output,
924
- children: nextState.children
885
+ _internalQueue: internalQueue
925
886
  });
926
887
  } catch (e) {
927
888
  // TODO: Refactor this once proper error handling is implemented.
@@ -929,7 +890,15 @@ function microstepProcedure(transitions, currentState, mutConfiguration, event,
929
890
  throw e;
930
891
  }
931
892
  }
932
- function enterStates(event, filteredTransitions, mutConfiguration, actions, internalQueue, currentState, historyValue, isInitial, actorContext) {
893
+ function getMachineOutput(state, event, actorCtx, rootNode, rootCompletionNode) {
894
+ if (!rootNode.output) {
895
+ return;
896
+ }
897
+ const doneStateEvent = interpreter.createDoneStateEvent(rootCompletionNode.id, rootCompletionNode.output && rootCompletionNode.parent ? interpreter.resolveOutput(rootCompletionNode.output, state.context, event, actorCtx.self) : undefined);
898
+ return interpreter.resolveOutput(rootNode.output, state.context, doneStateEvent, actorCtx.self);
899
+ }
900
+ function enterStates(currentState, event, actorCtx, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial) {
901
+ let nextState = currentState;
933
902
  const statesToEnter = new Set();
934
903
  const statesForDefaultEntry = new Set();
935
904
  computeEntrySet(filteredTransitions, historyValue, statesForDefaultEntry, statesToEnter);
@@ -938,36 +907,48 @@ function enterStates(event, filteredTransitions, mutConfiguration, actions, inte
938
907
  if (isInitial) {
939
908
  statesForDefaultEntry.add(currentState.machine.root);
940
909
  }
910
+ const completedNodes = new Set();
941
911
  for (const stateNodeToEnter of [...statesToEnter].sort((a, b) => a.order - b.order)) {
942
912
  mutConfiguration.add(stateNodeToEnter);
943
- for (const invokeDef of stateNodeToEnter.invoke) {
944
- actions.push(invoke(invokeDef));
945
- }
913
+ const actions = [];
946
914
 
947
915
  // Add entry actions
948
916
  actions.push(...stateNodeToEnter.entry);
917
+ for (const invokeDef of stateNodeToEnter.invoke) {
918
+ actions.push(invoke(invokeDef));
919
+ }
949
920
  if (statesForDefaultEntry.has(stateNodeToEnter)) {
950
- for (const stateNode of statesForDefaultEntry) {
951
- const initialActions = stateNode.initial.actions;
952
- actions.push(...initialActions);
953
- }
921
+ const initialActions = stateNodeToEnter.initial.actions;
922
+ actions.push(...initialActions);
954
923
  }
924
+ nextState = resolveActionsAndContext(nextState, event, actorCtx, actions, stateNodeToEnter.invoke.map(invokeDef => invokeDef.id));
955
925
  if (stateNodeToEnter.type === 'final') {
956
926
  const parent = stateNodeToEnter.parent;
957
- if (!parent.parent) {
927
+ if (completedNodes.has(parent)) {
958
928
  continue;
959
929
  }
960
- internalQueue.push(interpreter.createDoneStateEvent(parent.id, stateNodeToEnter.output ? interpreter.resolveOutput(stateNodeToEnter.output, currentState.context, event, actorContext.self) : undefined));
961
- if (parent.parent) {
962
- const grandparent = parent.parent;
963
- if (grandparent.type === 'parallel') {
964
- if (getChildren(grandparent).every(parentNode => isInFinalState([...mutConfiguration], parentNode))) {
965
- internalQueue.push(interpreter.createDoneStateEvent(grandparent.id));
966
- }
930
+ completedNodes.add(parent);
931
+ let rootCompletionNode = parent?.type === 'parallel' ? parent : stateNodeToEnter;
932
+ let ancestorMarker = parent?.parent;
933
+ if (ancestorMarker) {
934
+ internalQueue.push(interpreter.createDoneStateEvent(parent.id, stateNodeToEnter.output ? interpreter.resolveOutput(stateNodeToEnter.output, nextState.context, event, actorCtx.self) : undefined));
935
+ while (ancestorMarker?.type === 'parallel' && !completedNodes.has(ancestorMarker) && isInFinalState(mutConfiguration, ancestorMarker)) {
936
+ completedNodes.add(ancestorMarker);
937
+ internalQueue.push(interpreter.createDoneStateEvent(ancestorMarker.id));
938
+ rootCompletionNode = ancestorMarker;
939
+ ancestorMarker = ancestorMarker.parent;
967
940
  }
968
941
  }
942
+ if (ancestorMarker) {
943
+ continue;
944
+ }
945
+ nextState = cloneState(nextState, {
946
+ status: 'done',
947
+ output: getMachineOutput(nextState, event, actorCtx, currentState.configuration[0].machine.root, rootCompletionNode)
948
+ });
969
949
  }
970
950
  }
951
+ return nextState;
971
952
  }
972
953
  function computeEntrySet(transitions, historyValue, statesForDefaultEntry, statesToEnter) {
973
954
  for (const t of transitions) {
@@ -1010,13 +991,9 @@ function addDescendantStatesToEnter(stateNode, historyValue, statesForDefaultEnt
1010
991
  statesToEnter.add(stateNode);
1011
992
  if (stateNode.type === 'compound') {
1012
993
  statesForDefaultEntry.add(stateNode);
1013
- const initialStates = stateNode.initial.target;
1014
- for (const initialState of initialStates) {
1015
- addDescendantStatesToEnter(initialState, historyValue, statesForDefaultEntry, statesToEnter);
1016
- }
1017
- for (const initialState of initialStates) {
1018
- addAncestorStatesToEnter(initialState, stateNode, statesToEnter, historyValue, statesForDefaultEntry);
1019
- }
994
+ const [initialState] = stateNode.initial.target;
995
+ addDescendantStatesToEnter(initialState, historyValue, statesForDefaultEntry, statesToEnter);
996
+ addAncestorStatesToEnter(initialState, stateNode, statesToEnter, historyValue, statesForDefaultEntry);
1020
997
  } else {
1021
998
  if (stateNode.type === 'parallel') {
1022
999
  for (const child of getChildren(stateNode).filter(sn => !isHistoryNode(sn))) {
@@ -1041,7 +1018,8 @@ function addAncestorStatesToEnter(stateNode, toStateNode, statesToEnter, history
1041
1018
  }
1042
1019
  }
1043
1020
  }
1044
- function exitStates(transitions, mutConfiguration, historyValue, actions) {
1021
+ function exitStates(currentState, event, actorCtx, transitions, mutConfiguration, historyValue) {
1022
+ let nextState = currentState;
1045
1023
  const statesToExit = computeExitSet(transitions, mutConfiguration, historyValue);
1046
1024
  statesToExit.sort((a, b) => b.order - a.order);
1047
1025
 
@@ -1060,19 +1038,16 @@ function exitStates(transitions, mutConfiguration, historyValue, actions) {
1060
1038
  }
1061
1039
  }
1062
1040
  for (const s of statesToExit) {
1063
- actions.push(...s.exit, ...s.invoke.map(def => stop(def.id)));
1041
+ nextState = resolveActionsAndContext(nextState, event, actorCtx, [...s.exit, ...s.invoke.map(def => stop(def.id))]);
1064
1042
  mutConfiguration.delete(s);
1065
1043
  }
1044
+ return nextState;
1066
1045
  }
1067
- function resolveActionsAndContext(actions, event, currentState, actorCtx) {
1046
+ function resolveActionsAndContextWorker(currentState, event, actorCtx, actions, extra, retries) {
1068
1047
  const {
1069
1048
  machine
1070
1049
  } = currentState;
1071
- // TODO: this `cloneState` is really just a hack to prevent infinite loops
1072
- // we need to take another look at how internal queue is managed
1073
- let intermediateState = cloneState(currentState, {
1074
- _internalQueue: []
1075
- });
1050
+ let intermediateState = currentState;
1076
1051
  for (const action of actions) {
1077
1052
  const isInline = typeof action === 'function';
1078
1053
  const resolvedAction = isInline ? action :
@@ -1111,11 +1086,14 @@ function resolveActionsAndContext(actions, event, currentState, actorCtx) {
1111
1086
  continue;
1112
1087
  }
1113
1088
  const builtinAction = resolvedAction;
1114
- const [nextState, params, actions] = builtinAction.resolve(actorCtx, intermediateState, actionArgs, resolvedAction // this holds all params
1115
- );
1116
-
1089
+ const [nextState, params, actions] = builtinAction.resolve(actorCtx, intermediateState, actionArgs, resolvedAction,
1090
+ // this holds all params
1091
+ extra);
1117
1092
  intermediateState = nextState;
1118
- if ('execute' in resolvedAction) {
1093
+ if ('retryResolve' in builtinAction) {
1094
+ retries?.push([builtinAction, params]);
1095
+ }
1096
+ if ('execute' in builtinAction) {
1119
1097
  if (actorCtx?.self.status === interpreter.ActorStatus.Running) {
1120
1098
  builtinAction.execute(actorCtx, params);
1121
1099
  } else {
@@ -1123,11 +1101,21 @@ function resolveActionsAndContext(actions, event, currentState, actorCtx) {
1123
1101
  }
1124
1102
  }
1125
1103
  if (actions) {
1126
- intermediateState = resolveActionsAndContext(actions, event, intermediateState, actorCtx);
1104
+ intermediateState = resolveActionsAndContextWorker(intermediateState, event, actorCtx, actions, extra, retries);
1127
1105
  }
1128
1106
  }
1129
1107
  return intermediateState;
1130
1108
  }
1109
+ function resolveActionsAndContext(currentState, event, actorCtx, actions, deferredActorIds) {
1110
+ const retries = deferredActorIds ? [] : undefined;
1111
+ const nextState = resolveActionsAndContextWorker(currentState, event, actorCtx, actions, deferredActorIds && {
1112
+ deferredActorIds
1113
+ }, retries);
1114
+ retries?.forEach(([builtinAction, params]) => {
1115
+ builtinAction.retryResolve(actorCtx, nextState, params);
1116
+ });
1117
+ return nextState;
1118
+ }
1131
1119
  function macrostep(state, event, actorCtx) {
1132
1120
  let nextState = state;
1133
1121
  const states = [];
@@ -1184,7 +1172,7 @@ function stopStep(event, nextState, actorCtx) {
1184
1172
  for (const child of Object.values(nextState.children)) {
1185
1173
  actions.push(stop(child));
1186
1174
  }
1187
- return resolveActionsAndContext(actions, event, nextState, actorCtx);
1175
+ return resolveActionsAndContext(nextState, event, actorCtx, actions);
1188
1176
  }
1189
1177
  function selectTransitions(event, nextState) {
1190
1178
  return nextState.machine.getTransitionData(nextState, event);
@@ -1393,6 +1381,7 @@ function getPersistedState(state) {
1393
1381
  tags,
1394
1382
  machine,
1395
1383
  children,
1384
+ context,
1396
1385
  ...jsonValues
1397
1386
  } = state;
1398
1387
  const childrenJson = {};
@@ -1405,9 +1394,38 @@ function getPersistedState(state) {
1405
1394
  }
1406
1395
  return {
1407
1396
  ...jsonValues,
1397
+ // TODO: this makes `PersistedMachineState`'s type kind of a lie
1398
+ // it doesn't truly use `TContext` but rather some kind of a derived form of it
1399
+ context: persistContext(context),
1408
1400
  children: childrenJson
1409
1401
  };
1410
1402
  }
1403
+ function persistContext(contextPart) {
1404
+ let copy;
1405
+ for (const key in contextPart) {
1406
+ const value = contextPart[key];
1407
+ if (value && typeof value === 'object') {
1408
+ if ('sessionId' in value && 'send' in value && 'ref' in value) {
1409
+ copy ??= Array.isArray(contextPart) ? contextPart.slice() : {
1410
+ ...contextPart
1411
+ };
1412
+ copy[key] = {
1413
+ xstate$$type: interpreter.$$ACTOR_TYPE,
1414
+ id: value.id
1415
+ };
1416
+ } else {
1417
+ const result = persistContext(value);
1418
+ if (result !== value) {
1419
+ copy ??= Array.isArray(contextPart) ? contextPart.slice() : {
1420
+ ...contextPart
1421
+ };
1422
+ copy[key] = result;
1423
+ }
1424
+ }
1425
+ }
1426
+ }
1427
+ return copy ?? contextPart;
1428
+ }
1411
1429
 
1412
1430
  function resolveRaise(_, state, args, {
1413
1431
  event: eventOrExpr,
@@ -1470,10 +1488,10 @@ exports.getCandidates = getCandidates;
1470
1488
  exports.getConfiguration = getConfiguration;
1471
1489
  exports.getDelayedTransitions = getDelayedTransitions;
1472
1490
  exports.getInitialConfiguration = getInitialConfiguration;
1491
+ exports.getInitialStateNodes = getInitialStateNodes;
1473
1492
  exports.getPersistedState = getPersistedState;
1474
1493
  exports.getStateNodeByPath = getStateNodeByPath;
1475
1494
  exports.getStateNodes = getStateNodes;
1476
- exports.isAtomicStateNode = isAtomicStateNode;
1477
1495
  exports.isInFinalState = isInFinalState;
1478
1496
  exports.isStateId = isStateId;
1479
1497
  exports.macrostep = macrostep;