xstate 6.0.0-alpha.2 → 6.0.0-alpha.20

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 (54) hide show
  1. package/README.md +19 -17
  2. package/bin/xstate.js +36 -0
  3. package/dist/{StateMachine-2dcdb1f5.esm.js → StateMachine-42f1d26c.esm.js} +182 -40
  4. package/dist/{StateMachine-8d22a79c.development.cjs.js → StateMachine-6661eb0d.development.cjs.js} +193 -36
  5. package/dist/{StateMachine-2ea0a7fa.development.esm.js → StateMachine-ba3ccedf.development.esm.js} +193 -36
  6. package/dist/{StateMachine-64813f46.cjs.js → StateMachine-f2b70732.cjs.js} +182 -40
  7. package/dist/declarations/src/State.d.ts +13 -2
  8. package/dist/declarations/src/StateMachine.d.ts +23 -13
  9. package/dist/declarations/src/actions.d.ts +2 -1
  10. package/dist/declarations/src/actors/promise.d.ts +4 -2
  11. package/dist/declarations/src/createActor.d.ts +9 -11
  12. package/dist/declarations/src/createMachine.d.ts +14 -11
  13. package/dist/declarations/src/createMachineFromConfig.d.ts +61 -28
  14. package/dist/declarations/src/fsm.d.ts +74 -0
  15. package/dist/declarations/src/graph/graph.d.ts +3 -3
  16. package/dist/declarations/src/graph/shortestPaths.d.ts +2 -2
  17. package/dist/declarations/src/graph/simplePaths.d.ts +2 -2
  18. package/dist/declarations/src/index.d.ts +6 -5
  19. package/dist/declarations/src/serialize.d.ts +10 -18
  20. package/dist/declarations/src/setup.d.ts +266 -46
  21. package/dist/declarations/src/spawn.d.ts +3 -3
  22. package/dist/declarations/src/stateUtils.d.ts +4 -1
  23. package/dist/declarations/src/system.d.ts +1 -1
  24. package/dist/declarations/src/transition.d.ts +8 -5
  25. package/dist/declarations/src/transitionActions.d.ts +12 -0
  26. package/dist/declarations/src/types.d.ts +237 -102
  27. package/dist/declarations/src/types.v6.d.ts +129 -58
  28. package/dist/declarations/src/utils.d.ts +3 -2
  29. package/dist/{index-9cb3b3a0.cjs.js → index-42956779.cjs.js} +977 -1419
  30. package/dist/{index-f6ef20d1.development.cjs.js → index-49293864.development.cjs.js} +981 -1423
  31. package/dist/{index-93edd3bd.esm.js → index-d88b0c55.esm.js} +968 -1414
  32. package/dist/{index-e61170ba.development.esm.js → index-dc3443b6.development.esm.js} +972 -1418
  33. package/dist/xstate-actors.cjs.js +1 -1
  34. package/dist/xstate-actors.development.cjs.js +1 -1
  35. package/dist/xstate-actors.development.esm.js +1 -1
  36. package/dist/xstate-actors.esm.js +1 -1
  37. package/dist/xstate-actors.umd.min.js +1 -1
  38. package/dist/xstate-actors.umd.min.js.map +1 -1
  39. package/dist/xstate-graph.cjs.js +2 -2
  40. package/dist/xstate-graph.development.cjs.js +2 -2
  41. package/dist/xstate-graph.development.esm.js +2 -2
  42. package/dist/xstate-graph.esm.js +2 -2
  43. package/dist/xstate-graph.umd.min.js +1 -1
  44. package/dist/xstate-graph.umd.min.js.map +1 -1
  45. package/dist/xstate.cjs.js +1100 -182
  46. package/dist/xstate.cjs.mjs +3 -5
  47. package/dist/xstate.development.cjs.js +1100 -182
  48. package/dist/xstate.development.cjs.mjs +3 -5
  49. package/dist/xstate.development.esm.js +1101 -181
  50. package/dist/xstate.esm.js +1101 -181
  51. package/dist/xstate.umd.min.js +1 -1
  52. package/dist/xstate.umd.min.js.map +1 -1
  53. package/package.json +6 -2
  54. package/dist/declarations/src/atom.d.ts +0 -81
package/README.md CHANGED
@@ -119,7 +119,7 @@ npm install xstate
119
119
  ```
120
120
 
121
121
  ```ts
122
- import { createMachine, createActor, assign } from 'xstate';
122
+ import { createMachine, createActor } from 'xstate';
123
123
 
124
124
  // State machine
125
125
  const toggleMachine = createMachine({
@@ -135,7 +135,9 @@ const toggleMachine = createMachine({
135
135
  }
136
136
  },
137
137
  active: {
138
- entry: assign({ count: ({ context }) => context.count + 1 }),
138
+ entry: ({ context }) => ({
139
+ context: { count: context.count + 1 }
140
+ }),
139
141
  on: {
140
142
  TOGGLE: { target: 'inactive' }
141
143
  }
@@ -164,7 +166,7 @@ toggleActor.send({ type: 'TOGGLE' });
164
166
  - Deploy to Stately Sky
165
167
  - Generate & modify machines with Stately AI
166
168
 
167
- <a href="stately.ai/registry/new?ref=github" title="Stately Studio">
169
+ <a href="https://stately.ai/registry/new?ref=github" title="Stately Studio">
168
170
  <img src="https://github.com/statelyai/xstate/assets/1093738/74ed9cbc-b824-4ed7-a16d-f104947af8a7" alt="XState Viz" width="800" />
169
171
  </a>
170
172
 
@@ -365,10 +367,10 @@ const wordMachine = createMachine({
365
367
  initial: 'off',
366
368
  states: {
367
369
  on: {
368
- on: { TOGGLE_BOLD: 'off' }
370
+ on: { TOGGLE_BOLD: { target: 'off' } }
369
371
  },
370
372
  off: {
371
- on: { TOGGLE_BOLD: 'on' }
373
+ on: { TOGGLE_BOLD: { target: 'on' } }
372
374
  }
373
375
  }
374
376
  },
@@ -376,10 +378,10 @@ const wordMachine = createMachine({
376
378
  initial: 'off',
377
379
  states: {
378
380
  on: {
379
- on: { TOGGLE_UNDERLINE: 'off' }
381
+ on: { TOGGLE_UNDERLINE: { target: 'off' } }
380
382
  },
381
383
  off: {
382
- on: { TOGGLE_UNDERLINE: 'on' }
384
+ on: { TOGGLE_UNDERLINE: { target: 'on' } }
383
385
  }
384
386
  }
385
387
  },
@@ -387,10 +389,10 @@ const wordMachine = createMachine({
387
389
  initial: 'off',
388
390
  states: {
389
391
  on: {
390
- on: { TOGGLE_ITALICS: 'off' }
392
+ on: { TOGGLE_ITALICS: { target: 'off' } }
391
393
  },
392
394
  off: {
393
- on: { TOGGLE_ITALICS: 'on' }
395
+ on: { TOGGLE_ITALICS: { target: 'on' } }
394
396
  }
395
397
  }
396
398
  },
@@ -399,20 +401,20 @@ const wordMachine = createMachine({
399
401
  states: {
400
402
  none: {
401
403
  on: {
402
- BULLETS: 'bullets',
403
- NUMBERS: 'numbers'
404
+ BULLETS: { target: 'bullets' },
405
+ NUMBERS: { target: 'numbers' }
404
406
  }
405
407
  },
406
408
  bullets: {
407
409
  on: {
408
- NONE: 'none',
409
- NUMBERS: 'numbers'
410
+ NONE: { target: 'none' },
411
+ NUMBERS: { target: 'numbers' }
410
412
  }
411
413
  },
412
414
  numbers: {
413
415
  on: {
414
- BULLETS: 'bullets',
415
- NONE: 'none'
416
+ BULLETS: { target: 'bullets' },
417
+ NONE: { target: 'none' }
416
418
  }
417
419
  }
418
420
  }
@@ -493,10 +495,10 @@ const paymentMachine = createMachine({
493
495
  },
494
496
  hist: { type: 'history' }
495
497
  },
496
- on: { NEXT: 'review' }
498
+ on: { NEXT: { target: 'review' } }
497
499
  },
498
500
  review: {
499
- on: { PREVIOUS: 'method.hist' }
501
+ on: { PREVIOUS: { target: 'method.hist' } }
500
502
  }
501
503
  }
502
504
  });
package/bin/xstate.js ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ // Lightweight `xstate` CLI. Heavy commands are delegated to dedicated
3
+ // packages fetched on demand so the core package stays dependency-free.
4
+ const { spawnSync } = require('child_process');
5
+
6
+ const [command, ...rest] = process.argv.slice(2);
7
+
8
+ switch (command) {
9
+ case 'migrate': {
10
+ // Delegates to @xstate/codemod (ts-morph based v5 → v6 codemods).
11
+ const result = spawnSync(
12
+ process.platform === 'win32' ? 'npx.cmd' : 'npx',
13
+ ['-y', '@xstate/codemod', 'migrate', ...rest],
14
+ { stdio: 'inherit' }
15
+ );
16
+ process.exit(result.status ?? 1);
17
+ break;
18
+ }
19
+ case '--help':
20
+ case 'help':
21
+ case undefined:
22
+ console.log(
23
+ [
24
+ 'Usage: xstate <command>',
25
+ '',
26
+ 'Commands:',
27
+ ' migrate [globs...] [--dry] Migrate source files to the current XState version',
28
+ ' (delegates to @xstate/codemod)'
29
+ ].join('\n')
30
+ );
31
+ process.exit(command ? 0 : 1);
32
+ break;
33
+ default:
34
+ console.error(`Unknown command: ${command}`);
35
+ process.exit(1);
36
+ }
@@ -1,4 +1,4 @@
1
- import { P as ProcessingStatus, G as resolveReferencedActor, c as createActor, S as STATE_DELIMITER, H as mapValues, t as toArray, I as createInvokeId, J as getDelayedTransitions, K as evaluateCandidate, L as formatTransition, N as NULL_EVENT, M as toTransitionConfigArray, O as createInvokeTimeoutEvent, Q as getCandidates, R as formatRouteTransitions, U as resolveStateValue, V as getAllStateNodes, n as getStateNodes, W as createMachineSnapshot, X as isInFinalState, a as macrostep, Y as transitionNode, m as matchesEventDescriptor, Z as resolveAndExecuteActionsWithContext, b as createInitEvent, d as initialMicrostep, _ as toStatePath, $ as isStateId, a0 as getStateNodeByPath, a1 as getPersistedSnapshot, a2 as $$ACTOR_TYPE } from './index-93edd3bd.esm.js';
1
+ import { P as ProcessingStatus, H as resolveReferencedActor, e as createActor, S as STATE_DELIMITER, I as mapValues, t as toArray, J as createInvokeId, K as getDelayedTransitions, L as evaluateCandidate, M as formatTransition, N as NULL_EVENT, O as toTransitionConfigArray, Q as createInvokeTimeoutEvent, R as getCandidates, U as formatRouteTransitions, V as resolveStateValue, W as getAllStateNodes, l as getStateNodes, Y as createMachineSnapshot, Z as isInFinalState, f as macrostep, d as deriveDeferredStarts, _ as cloneMachineSnapshot, $ as transitionNode, m as matchesEventDescriptor, a0 as getTransitionResult, a1 as hasEffect, a2 as createErrorPlatformEvent, r as resolveActionsWithContext, g as createInitEvent, h as initialMicrostep, a3 as toStatePath, a4 as isStateId, a5 as getStateNodeByPath, a6 as getPersistedSnapshot, a7 as $$ACTOR_TYPE } from './index-d88b0c55.esm.js';
2
2
 
3
3
  function createSpawner(actorScope, {
4
4
  machine,
@@ -20,7 +20,7 @@ function createSpawner(actorScope, {
20
20
  self: actorScope.self
21
21
  }) : options?.input,
22
22
  src,
23
- systemId: options?.systemId
23
+ registryKey: options?.registryKey
24
24
  });
25
25
  spawnedChildren[actor.id] = actor;
26
26
  return actor;
@@ -31,7 +31,7 @@ function createSpawner(actorScope, {
31
31
  syncSnapshot: options?.syncSnapshot,
32
32
  input: options?.input,
33
33
  src,
34
- systemId: options?.systemId
34
+ registryKey: options?.registryKey
35
35
  });
36
36
  return actor;
37
37
  }
@@ -64,7 +64,6 @@ function memo(object, key, fn) {
64
64
  }
65
65
 
66
66
  const EMPTY_OBJECT = {};
67
- const CHOICE_CONFIG_KEYS = ['invoke', 'after', 'on', 'entry', 'exit', 'always', 'states', 'initial', 'onDone', 'timeout', 'onTimeout', 'history', 'target', 'output'];
68
67
  class StateNode {
69
68
  constructor(/** The raw config used to create the machine. */
70
69
  config, options) {
@@ -171,7 +170,7 @@ class StateNode {
171
170
  this.invoke = toArray(this.config.invoke).map((invokeConfig, i) => {
172
171
  const {
173
172
  src,
174
- systemId
173
+ registryKey
175
174
  } = invokeConfig;
176
175
  const invokeId = createInvokeId(this.id, i);
177
176
  const resolvedId = invokeConfig.id ?? invokeId;
@@ -184,7 +183,7 @@ class StateNode {
184
183
  src: sourceName,
185
184
  logic: src,
186
185
  id: resolvedId,
187
- systemId
186
+ registryKey
188
187
  };
189
188
  });
190
189
  }
@@ -244,30 +243,17 @@ class StateNode {
244
243
  function validateStateNodeConfig(stateNode) {
245
244
  const config = stateNode.config;
246
245
  if (stateNode.type !== 'choice') {
247
- if (config.choice !== undefined) {
248
- throw new Error(`State "${stateNode.id}" has \`choice\`, but \`choice\` can only be used with \`type: 'choice'\`.`);
249
- }
250
246
  return;
251
247
  }
252
248
  if (typeof config.choice !== 'function') {
253
- throw new Error(`Choice state "${stateNode.id}" must declare a \`choice\` function.`);
254
- }
255
- for (const key of CHOICE_CONFIG_KEYS) {
256
- if (config[key] !== undefined) {
257
- throw new Error(`Choice state "${stateNode.id}" cannot declare \`${key}\`.`);
258
- }
249
+ throw new Error(`Missing \`choice\` function on "${stateNode.id}"`);
259
250
  }
260
251
  }
261
252
  function formatChoiceTransitions(stateNode) {
262
253
  const choice = stateNode.config.choice;
263
254
  const validateChoiceResult = result => {
264
255
  if (!result || result.target === undefined) {
265
- throw new Error(`Choice state "${stateNode.id}" must resolve to a target.`);
266
- }
267
- for (const key of ['actions', 'to', 'context']) {
268
- if (result[key] !== undefined) {
269
- throw new Error(`Choice state "${stateNode.id}" cannot declare \`${key}\` on a choice.`);
270
- }
256
+ throw new Error(`Choice "${stateNode.id}" has no target`);
271
257
  }
272
258
  return result;
273
259
  };
@@ -288,7 +274,7 @@ function formatTransitions(stateNode) {
288
274
  if (stateNode.config.on) {
289
275
  for (const descriptor of Object.keys(stateNode.config.on)) {
290
276
  if (descriptor === NULL_EVENT) {
291
- throw new Error('Null events ("") cannot be specified as a transition key. Use `always: { ... }` instead.');
277
+ throw new Error('Null event transition key');
292
278
  }
293
279
  const transitionsConfig = stateNode.config.on[descriptor];
294
280
  transitions.set(descriptor, mapTransitionConfigs(transitionsConfig, transition => formatTransition(stateNode, descriptor, transition)));
@@ -298,6 +284,10 @@ function formatTransitions(stateNode) {
298
284
  const descriptor = `xstate.done.state.${stateNode.id}`;
299
285
  transitions.set(descriptor, mapTransitionConfigs(stateNode.config.onDone, transition => formatTransition(stateNode, descriptor, transition)));
300
286
  }
287
+ if (stateNode.config.onError) {
288
+ const descriptor = 'xstate.error.*';
289
+ transitions.set(descriptor, mapTransitionConfigs(stateNode.config.onError, transition => formatTransition(stateNode, descriptor, transition)));
290
+ }
301
291
  const createCancelInvokeTimeoutTransition = (descriptor, timeoutEventType) => formatTransition(stateNode, descriptor, {
302
292
  to: (_args, enq) => {
303
293
  enq.cancel(timeoutEventType);
@@ -384,7 +374,7 @@ function formatInitialTransition(stateNode, _target) {
384
374
  const input = typeof _target === 'object' && _target !== null ? _target.input : undefined;
385
375
  const resolvedTarget = typeof targetString === 'string' ? stateNode.states[targetString] : undefined;
386
376
  if (!resolvedTarget && targetString) {
387
- throw new Error(`Initial state node "${targetString}" not found on parent state node #${stateNode.id}`);
377
+ throw new Error(`Initial state "${targetString}" not found on "#${stateNode.id}"`);
388
378
  }
389
379
  const transition = {
390
380
  source: stateNode,
@@ -395,6 +385,45 @@ function formatInitialTransition(stateNode, _target) {
395
385
  }
396
386
 
397
387
  const STATE_IDENTIFIER = '#';
388
+ let emptyCanActor;
389
+ let emptyCanActorScope;
390
+ function getEmptyCanActor() {
391
+ // A minimal inert actor used purely as the `self`/`parent` argument when
392
+ // dry-running transitions for `snapshot.can(...)`. Intentionally not built
393
+ // on `createLogic` so `can()` does not pull that machinery into bundles.
394
+ return emptyCanActor ??= createActor({
395
+ transition: snapshot => [snapshot, []],
396
+ initialTransition: () => [{
397
+ status: 'active',
398
+ output: undefined,
399
+ error: undefined
400
+ }, []],
401
+ getInitialSnapshot: () => ({
402
+ status: 'active',
403
+ output: undefined,
404
+ error: undefined
405
+ }),
406
+ getPersistedSnapshot: snapshot => snapshot
407
+ });
408
+ }
409
+ function getEmptyCanActorScope() {
410
+ if (emptyCanActorScope) {
411
+ return emptyCanActorScope;
412
+ }
413
+ const actor = getEmptyCanActor();
414
+ emptyCanActorScope = {
415
+ self: actor,
416
+ logger: () => {},
417
+ id: '',
418
+ sessionId: '',
419
+ defer: () => {},
420
+ system: actor.system,
421
+ stopChild: () => {},
422
+ emit: () => {},
423
+ actionExecutor: () => {}
424
+ };
425
+ return emptyCanActorScope;
426
+ }
398
427
  class StateMachine {
399
428
  constructor(/** The raw config used to create the machine. */
400
429
  config, implementations) {
@@ -422,7 +451,7 @@ class StateMachine {
422
451
  this._json = void 0;
423
452
  this.id = config.id || '(machine)';
424
453
  this.implementations = {
425
- actors: config.actors ?? {},
454
+ actorSources: config.actorSources ?? {},
426
455
  actions: config.actions ?? {},
427
456
  delays: config.delays ?? {},
428
457
  guards: config.guards ?? {},
@@ -436,6 +465,7 @@ class StateMachine {
436
465
  ...this.config.options
437
466
  };
438
467
  this.transition = this.transition.bind(this);
468
+ this.initialTransition = this.initialTransition.bind(this);
439
469
  this.getInitialSnapshot = this.getInitialSnapshot.bind(this);
440
470
  this.getPersistedSnapshot = this.getPersistedSnapshot.bind(this);
441
471
  this.restoreSnapshot = this.restoreSnapshot.bind(this);
@@ -454,15 +484,15 @@ class StateMachine {
454
484
  /**
455
485
  * Clones this state machine with the provided implementations.
456
486
  *
457
- * @param implementations Options (`actions`, `guards`, `actors`, `delays`) to
458
- * recursively merge with the existing options.
487
+ * @param implementations Options (`actions`, `guards`, `actorSources`,
488
+ * `delays`) to recursively merge with the existing options.
459
489
  * @returns A new `StateMachine` instance with the provided implementations.
460
490
  */
461
491
  provide(implementations) {
462
492
  const {
463
493
  actions,
464
494
  guards,
465
- actors,
495
+ actorSources,
466
496
  delays
467
497
  } = this.implementations;
468
498
  const provided = new StateMachine(this.config, {
@@ -474,9 +504,9 @@ class StateMachine {
474
504
  ...guards,
475
505
  ...implementations.guards
476
506
  },
477
- actors: {
478
- ...actors,
479
- ...implementations.actors
507
+ actorSources: {
508
+ ...actorSources,
509
+ ...implementations.actorSources
480
510
  },
481
511
  delays: {
482
512
  ...delays,
@@ -511,7 +541,56 @@ class StateMachine {
511
541
  * @param event The received event
512
542
  */
513
543
  transition(snapshot, event, actorScope) {
514
- return macrostep(snapshot, event, actorScope, []).snapshot;
544
+ const fastSnapshot = this._transitionFast(snapshot, event, actorScope);
545
+ if (fastSnapshot) {
546
+ return [fastSnapshot, []];
547
+ }
548
+ const {
549
+ snapshot: nextSnapshot,
550
+ microsteps
551
+ } = macrostep(snapshot, event, actorScope, []);
552
+ return [nextSnapshot, this._collectEffects(microsteps)];
553
+ }
554
+ _collectEffects(microsteps, initialActions = []) {
555
+ const effects = [...initialActions, ...microsteps.flatMap(([, actions]) => actions)];
556
+ return [...effects, ...deriveDeferredStarts(effects)];
557
+ }
558
+ _transitionFast(snapshot, event, actorScope) {
559
+ if (snapshot.status !== 'active' || typeof snapshot.value !== 'string' || this.root.always?.length) {
560
+ return undefined;
561
+ }
562
+ const sourceNode = this.root.states[snapshot.value];
563
+ if (!sourceNode || sourceNode.type !== 'atomic' || sourceNode.exit || sourceNode.invoke.length || sourceNode.always?.length || sourceNode.after?.length) {
564
+ return undefined;
565
+ }
566
+ const transitions = sourceNode.transitions.get(event.type);
567
+ if (transitions?.length !== 1) {
568
+ return undefined;
569
+ }
570
+ const selected = transitions[0];
571
+ if (selected.guard || selected.actions || selected.to || selected.reenter || selected.input || typeof selected.context === 'function' || selected.target && selected.target.length !== 1) {
572
+ return undefined;
573
+ }
574
+ const targetNode = selected.target?.[0] ?? sourceNode;
575
+ const stateChanged = targetNode !== sourceNode;
576
+ if (targetNode.parent !== this.root || targetNode.type !== 'atomic' || stateChanged && (targetNode.entry || targetNode.invoke.length || targetNode.always?.length || targetNode.after?.length)) {
577
+ return undefined;
578
+ }
579
+ const context = selected.context !== undefined ? {
580
+ ...snapshot.context,
581
+ ...selected.context
582
+ } : snapshot.context;
583
+ const collectedMicrosteps = actorScope.self._collectedMicrosteps || [];
584
+ collectedMicrosteps.push(selected);
585
+ actorScope.self._collectedMicrosteps = collectedMicrosteps;
586
+ return cloneMachineSnapshot(snapshot, {
587
+ ...(context !== snapshot.context ? {
588
+ context
589
+ } : {}),
590
+ ...(stateChanged ? {
591
+ _nodes: [this.root, targetNode]
592
+ } : {})
593
+ });
515
594
  }
516
595
 
517
596
  /**
@@ -543,6 +622,49 @@ class StateMachine {
543
622
  return false;
544
623
  }
545
624
 
625
+ /**
626
+ * Determines whether sending the `event` to the given snapshot would select a
627
+ * non-forbidden transition. Backs `snapshot.can(...)`; lives here so that
628
+ * non-machine bundles don't pay for the transition-resolution machinery.
629
+ *
630
+ * @internal
631
+ */
632
+ _canTransition(snapshot, event) {
633
+ const emptyActor = getEmptyCanActor();
634
+ const emptyActorScope = getEmptyCanActorScope();
635
+ const transitionData = this.getTransitionData(snapshot, event, emptyActor);
636
+ if (!transitionData?.length) {
637
+ return false;
638
+ }
639
+
640
+ // Check that at least one transition is not forbidden
641
+ for (const transition of transitionData) {
642
+ if (transition.target !== undefined) {
643
+ return true;
644
+ }
645
+ const res = getTransitionResult(transition, snapshot, event, emptyActorScope, {
646
+ resolveActions: false
647
+ });
648
+ if (res.targets?.length || res.context || hasEffect(transition, snapshot.context, event, snapshot, emptyActor)) {
649
+ return true;
650
+ }
651
+ }
652
+ return false;
653
+ }
654
+
655
+ /**
656
+ * Returns the error event that the actor should transition with to recover
657
+ * from an execution error, if any active state node declares `onError`.
658
+ *
659
+ * @internal
660
+ */
661
+ getExecutionErrorEvent(snapshot, error) {
662
+ if (snapshot?.status !== 'active' || !snapshot._nodes?.some(stateNode => stateNode.config.onError)) {
663
+ return undefined;
664
+ }
665
+ return createErrorPlatformEvent('execution', error);
666
+ }
667
+
546
668
  /**
547
669
  * The initial state _before_ evaluating any microsteps. This "pre-initial"
548
670
  * state is provided to initial actions executed in the initial state.
@@ -566,9 +688,9 @@ class StateMachine {
566
688
  spawn,
567
689
  input: initEvent.input,
568
690
  self: actorScope.self,
569
- actors: this.implementations.actors
691
+ actorSources: this.implementations.actorSources
570
692
  });
571
- const nextState = resolveAndExecuteActionsWithContext(preInitial, initEvent, actorScope, []);
693
+ const [nextState] = resolveActionsWithContext(preInitial, initEvent, actorScope, []);
572
694
  if (resolvedContext) {
573
695
  nextState.context = resolvedContext;
574
696
  }
@@ -588,14 +710,33 @@ class StateMachine {
588
710
  * `ActorRef`.
589
711
  */
590
712
  getInitialSnapshot(actorScope, input) {
713
+ return this.initialTransition(input, actorScope)[0];
714
+ }
715
+ initialTransition(input, actorScope) {
591
716
  const initEvent = createInitEvent(input); // TODO: fix;
592
717
  const internalQueue = [];
593
718
  const preInitialState = this._getPreInitialState(actorScope, initEvent);
594
- const [nextState] = initialMicrostep(this.root, preInitialState, actorScope, initEvent, internalQueue);
595
- const {
596
- snapshot: macroState
597
- } = macrostep(nextState, initEvent, actorScope, internalQueue);
598
- return macroState;
719
+ let nextState;
720
+ let initialActions = [];
721
+ let microsteps = [];
722
+ let macroState;
723
+ try {
724
+ [nextState, initialActions] = initialMicrostep(this.root, preInitialState, actorScope, initEvent, internalQueue);
725
+ ({
726
+ snapshot: macroState,
727
+ microsteps
728
+ } = macrostep(nextState, initEvent, actorScope, internalQueue));
729
+ } catch (err) {
730
+ if (!this.root.config.onError) {
731
+ throw err;
732
+ }
733
+ const errorEvent = createErrorPlatformEvent('execution', err);
734
+ const errorMacrostep = macrostep(preInitialState, errorEvent, actorScope, []);
735
+ macroState = errorMacrostep.snapshot;
736
+ microsteps = errorMacrostep.microsteps;
737
+ initialActions = [];
738
+ }
739
+ return [macroState, this._collectEffects(microsteps, initialActions)];
599
740
  }
600
741
  start(snapshot) {
601
742
  // Start rehydrated children that were active when persisted. Freshly
@@ -649,7 +790,7 @@ class StateMachine {
649
790
  syncSnapshot: actorData.syncSnapshot,
650
791
  snapshot: childState,
651
792
  src,
652
- systemId: actorData.systemId
793
+ registryKey: actorData.registryKey
653
794
  });
654
795
  // Mark so `start()` knows to start this child (freshly invoked/spawned
655
796
  // children are started via deferred `@xstate.start` actions instead).
@@ -693,7 +834,8 @@ class StateMachine {
693
834
  children,
694
835
  _nodes: nodes,
695
836
  value: snapshotData.value,
696
- historyValue: revivedHistoryValue
837
+ historyValue: revivedHistoryValue,
838
+ _stateInputs: snapshotData.stateInputs ?? {}
697
839
  }, this);
698
840
  const seen = new WeakSet();
699
841
  function reviveContext(contextPart) {