xstate 5.0.0-beta.43 → 5.0.0-beta.45

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 (55) hide show
  1. package/actions/dist/xstate-actions.cjs.js +2 -3
  2. package/actions/dist/xstate-actions.development.cjs.js +2 -3
  3. package/actions/dist/xstate-actions.development.esm.js +2 -3
  4. package/actions/dist/xstate-actions.esm.js +2 -3
  5. package/actions/dist/xstate-actions.umd.min.js +1 -1
  6. package/actions/dist/xstate-actions.umd.min.js.map +1 -1
  7. package/actors/dist/xstate-actors.cjs.js +98 -10
  8. package/actors/dist/xstate-actors.development.cjs.js +98 -10
  9. package/actors/dist/xstate-actors.development.esm.js +93 -5
  10. package/actors/dist/xstate-actors.esm.js +93 -5
  11. package/actors/dist/xstate-actors.umd.min.js +1 -1
  12. package/actors/dist/xstate-actors.umd.min.js.map +1 -1
  13. package/dist/declarations/src/State.d.ts +14 -18
  14. package/dist/declarations/src/StateMachine.d.ts +1 -1
  15. package/dist/declarations/src/actions/choose.d.ts +3 -3
  16. package/dist/declarations/src/actions/pure.d.ts +4 -4
  17. package/dist/declarations/src/actions/spawn.d.ts +11 -16
  18. package/dist/declarations/src/actors/observable.d.ts +39 -0
  19. package/dist/declarations/src/actors/transition.d.ts +53 -4
  20. package/dist/declarations/src/{Machine.d.ts → createMachine.d.ts} +1 -1
  21. package/dist/declarations/src/guards.d.ts +27 -5
  22. package/dist/declarations/src/index.d.ts +3 -2
  23. package/dist/declarations/src/interpreter.d.ts +1 -0
  24. package/dist/declarations/src/setup.d.ts +32 -0
  25. package/dist/declarations/src/spawn.d.ts +9 -13
  26. package/dist/declarations/src/stateUtils.d.ts +11 -11
  27. package/dist/declarations/src/types.d.ts +31 -29
  28. package/dist/declarations/src/utils.d.ts +1 -3
  29. package/dist/{raise-8dc8e1aa.esm.js → raise-2b5a4e4c.esm.js} +934 -103
  30. package/dist/{raise-f4ad5a87.development.esm.js → raise-90139fbc.development.esm.js} +945 -103
  31. package/dist/{raise-23dea0d7.development.cjs.js → raise-b3fb3c65.development.cjs.js} +999 -137
  32. package/dist/{raise-e0fe5c2d.cjs.js → raise-fabffc3d.cjs.js} +986 -135
  33. package/dist/{send-5d129d95.development.esm.js → send-24cc8018.development.esm.js} +4 -30
  34. package/dist/{send-84e2e742.esm.js → send-8e7e41e7.esm.js} +4 -30
  35. package/dist/{send-87bbaaab.cjs.js → send-c124176f.cjs.js} +13 -39
  36. package/dist/{send-0174c155.development.cjs.js → send-d0bc7eed.development.cjs.js} +13 -39
  37. package/dist/xstate.cjs.js +67 -35
  38. package/dist/xstate.cjs.mjs +2 -0
  39. package/dist/xstate.development.cjs.js +67 -35
  40. package/dist/xstate.development.cjs.mjs +2 -0
  41. package/dist/xstate.development.esm.js +42 -13
  42. package/dist/xstate.esm.js +42 -13
  43. package/dist/xstate.umd.min.js +1 -1
  44. package/dist/xstate.umd.min.js.map +1 -1
  45. package/guards/dist/xstate-guards.cjs.js +1 -2
  46. package/guards/dist/xstate-guards.development.cjs.js +1 -2
  47. package/guards/dist/xstate-guards.development.esm.js +1 -2
  48. package/guards/dist/xstate-guards.esm.js +1 -2
  49. package/guards/dist/xstate-guards.umd.min.js +1 -1
  50. package/guards/dist/xstate-guards.umd.min.js.map +1 -1
  51. package/package.json +1 -1
  52. package/dist/interpreter-36d5556e.cjs.js +0 -887
  53. package/dist/interpreter-4e8e2a0d.development.cjs.js +0 -898
  54. package/dist/interpreter-63c80754.esm.js +0 -857
  55. package/dist/interpreter-80eb3bec.development.esm.js +0 -868
@@ -1,19 +1,883 @@
1
- import { r as resolveReferencedActor, d as createActor, P as ProcessingStatus, h as createErrorActorEvent, j as STATE_IDENTIFIER, n as normalizeTarget, t as toArray, N as NULL_EVENT, a as toTransitionConfigArray, S as STATE_DELIMITER, k as toStatePath, l as createDoneStateEvent, o as resolveOutput, W as WILDCARD, X as XSTATE_STOP, q as XSTATE_INIT, s as createAfterEvent, u as flatten, $ as $$ACTOR_TYPE, f as matchesState } from './interpreter-80eb3bec.development.esm.js';
2
-
3
- const cache = new WeakMap();
4
- function memo(object, key, fn) {
5
- let memoizedData = cache.get(object);
6
- if (!memoizedData) {
7
- memoizedData = {
8
- [key]: fn()
1
+ import { devToolsAdapter } from '../dev/dist/xstate-dev.development.esm.js';
2
+
3
+ class Mailbox {
4
+ constructor(_process) {
5
+ this._process = _process;
6
+ this._active = false;
7
+ this._current = null;
8
+ this._last = null;
9
+ }
10
+ start() {
11
+ this._active = true;
12
+ this.flush();
13
+ }
14
+ clear() {
15
+ // we can't set _current to null because we might be currently processing
16
+ // and enqueue following clear shouldnt start processing the enqueued item immediately
17
+ if (this._current) {
18
+ this._current.next = null;
19
+ this._last = this._current;
20
+ }
21
+ }
22
+ enqueue(event) {
23
+ const enqueued = {
24
+ value: event,
25
+ next: null
26
+ };
27
+ if (this._current) {
28
+ this._last.next = enqueued;
29
+ this._last = enqueued;
30
+ return;
31
+ }
32
+ this._current = enqueued;
33
+ this._last = enqueued;
34
+ if (this._active) {
35
+ this.flush();
36
+ }
37
+ }
38
+ flush() {
39
+ while (this._current) {
40
+ // atm the given _process is responsible for implementing proper try/catch handling
41
+ // we assume here that this won't throw in a way that can affect this mailbox
42
+ const consumed = this._current;
43
+ this._process(consumed.value);
44
+ this._current = consumed.next;
45
+ }
46
+ this._last = null;
47
+ }
48
+ }
49
+
50
+ const STATE_DELIMITER = '.';
51
+ const TARGETLESS_KEY = '';
52
+ const NULL_EVENT = '';
53
+ const STATE_IDENTIFIER = '#';
54
+ const WILDCARD = '*';
55
+ const XSTATE_INIT = 'xstate.init';
56
+ const XSTATE_ERROR = 'xstate.error';
57
+ const XSTATE_STOP = 'xstate.stop';
58
+
59
+ /**
60
+ * Returns an event that represents an implicit event that
61
+ * is sent after the specified `delay`.
62
+ *
63
+ * @param delayRef The delay in milliseconds
64
+ * @param id The state node ID where this event is handled
65
+ */
66
+ function createAfterEvent(delayRef, id) {
67
+ const idSuffix = id ? `#${id}` : '';
68
+ return {
69
+ type: `xstate.after(${delayRef})${idSuffix}`
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Returns an event that represents that a final state node
75
+ * has been reached in the parent state node.
76
+ *
77
+ * @param id The final state node's parent state node `id`
78
+ * @param output The data to pass into the event
79
+ */
80
+ function createDoneStateEvent(id, output) {
81
+ return {
82
+ type: `xstate.done.state.${id}`,
83
+ output
84
+ };
85
+ }
86
+
87
+ /**
88
+ * Returns an event that represents that an invoked service has terminated.
89
+ *
90
+ * An invoked service is terminated when it has reached a top-level final state node,
91
+ * but not when it is canceled.
92
+ *
93
+ * @param invokeId The invoked service ID
94
+ * @param output The data to pass into the event
95
+ */
96
+ function createDoneActorEvent(invokeId, output) {
97
+ return {
98
+ type: `xstate.done.actor.${invokeId}`,
99
+ output
100
+ };
101
+ }
102
+ function createErrorActorEvent(id, data) {
103
+ return {
104
+ type: `xstate.error.actor.${id}`,
105
+ data
106
+ };
107
+ }
108
+ function createInitEvent(input) {
109
+ return {
110
+ type: XSTATE_INIT,
111
+ input
112
+ };
113
+ }
114
+
115
+ /**
116
+ * This function makes sure that unhandled errors are thrown in a separate macrotask.
117
+ * It allows those errors to be detected by global error handlers and reported to bug tracking services
118
+ * without interrupting our own stack of execution.
119
+ *
120
+ * @param err error to be thrown
121
+ */
122
+ function reportUnhandledError(err) {
123
+ setTimeout(() => {
124
+ throw err;
125
+ });
126
+ }
127
+
128
+ const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
129
+
130
+ let idCounter = 0;
131
+ function createSystem(rootActor) {
132
+ const children = new Map();
133
+ const keyedActors = new Map();
134
+ const reverseKeyedActors = new WeakMap();
135
+ const observers = new Set();
136
+ const system = {
137
+ _bookId: () => `x:${idCounter++}`,
138
+ _register: (sessionId, actorRef) => {
139
+ children.set(sessionId, actorRef);
140
+ return sessionId;
141
+ },
142
+ _unregister: actorRef => {
143
+ children.delete(actorRef.sessionId);
144
+ const systemId = reverseKeyedActors.get(actorRef);
145
+ if (systemId !== undefined) {
146
+ keyedActors.delete(systemId);
147
+ reverseKeyedActors.delete(actorRef);
148
+ }
149
+ },
150
+ get: systemId => {
151
+ return keyedActors.get(systemId);
152
+ },
153
+ _set: (systemId, actorRef) => {
154
+ const existing = keyedActors.get(systemId);
155
+ if (existing && existing !== actorRef) {
156
+ throw new Error(`Actor with system ID '${systemId}' already exists.`);
157
+ }
158
+ keyedActors.set(systemId, actorRef);
159
+ reverseKeyedActors.set(actorRef, systemId);
160
+ },
161
+ inspect: observer => {
162
+ observers.add(observer);
163
+ },
164
+ _sendInspectionEvent: event => {
165
+ const resolvedInspectionEvent = {
166
+ ...event,
167
+ rootId: rootActor.sessionId
168
+ };
169
+ observers.forEach(observer => observer.next?.(resolvedInspectionEvent));
170
+ },
171
+ _relay: (source, target, event) => {
172
+ system._sendInspectionEvent({
173
+ type: '@xstate.event',
174
+ sourceRef: source,
175
+ actorRef: target,
176
+ event
177
+ });
178
+ target._send(event);
179
+ }
180
+ };
181
+ return system;
182
+ }
183
+
184
+ function matchesState(parentStateId, childStateId) {
185
+ const parentStateValue = toStateValue(parentStateId);
186
+ const childStateValue = toStateValue(childStateId);
187
+ if (typeof childStateValue === 'string') {
188
+ if (typeof parentStateValue === 'string') {
189
+ return childStateValue === parentStateValue;
190
+ }
191
+
192
+ // Parent more specific than child
193
+ return false;
194
+ }
195
+ if (typeof parentStateValue === 'string') {
196
+ return parentStateValue in childStateValue;
197
+ }
198
+ return Object.keys(parentStateValue).every(key => {
199
+ if (!(key in childStateValue)) {
200
+ return false;
201
+ }
202
+ return matchesState(parentStateValue[key], childStateValue[key]);
203
+ });
204
+ }
205
+ function toStatePath(stateId) {
206
+ try {
207
+ if (isArray(stateId)) {
208
+ return stateId;
209
+ }
210
+ return stateId.split(STATE_DELIMITER);
211
+ } catch (e) {
212
+ throw new Error(`'${stateId}' is not a valid state path.`);
213
+ }
214
+ }
215
+ function toStateValue(stateValue) {
216
+ if (isMachineSnapshot(stateValue)) {
217
+ return stateValue.value;
218
+ }
219
+ if (typeof stateValue !== 'string') {
220
+ return stateValue;
221
+ }
222
+ const statePath = toStatePath(stateValue);
223
+ return pathToStateValue(statePath);
224
+ }
225
+ function pathToStateValue(statePath) {
226
+ if (statePath.length === 1) {
227
+ return statePath[0];
228
+ }
229
+ const value = {};
230
+ let marker = value;
231
+ for (let i = 0; i < statePath.length - 1; i++) {
232
+ if (i === statePath.length - 2) {
233
+ marker[statePath[i]] = statePath[i + 1];
234
+ } else {
235
+ const previous = marker;
236
+ marker = {};
237
+ previous[statePath[i]] = marker;
238
+ }
239
+ }
240
+ return value;
241
+ }
242
+ function mapValues(collection, iteratee) {
243
+ const result = {};
244
+ const collectionKeys = Object.keys(collection);
245
+ for (let i = 0; i < collectionKeys.length; i++) {
246
+ const key = collectionKeys[i];
247
+ result[key] = iteratee(collection[key], key, collection, i);
248
+ }
249
+ return result;
250
+ }
251
+ function flatten(array) {
252
+ return [].concat(...array);
253
+ }
254
+ function toArrayStrict(value) {
255
+ if (isArray(value)) {
256
+ return value;
257
+ }
258
+ return [value];
259
+ }
260
+ function toArray(value) {
261
+ if (value === undefined) {
262
+ return [];
263
+ }
264
+ return toArrayStrict(value);
265
+ }
266
+ function resolveOutput(mapper, context, event, self) {
267
+ if (typeof mapper === 'function') {
268
+ return mapper({
269
+ context,
270
+ event,
271
+ self
272
+ });
273
+ }
274
+ if (!!mapper && typeof mapper === 'object' && Object.values(mapper).some(val => typeof val === 'function')) {
275
+ console.warn(`Dynamically mapping values to individual properties is deprecated. Use a single function that returns the mapped object instead.\nFound object containing properties whose values are possibly mapping functions: ${Object.entries(mapper).filter(([key, value]) => typeof value === 'function').map(([key, value]) => `\n - ${key}: ${value.toString().replace(/\n\s*/g, '')}`).join('')}`);
276
+ }
277
+ return mapper;
278
+ }
279
+ function isArray(value) {
280
+ return Array.isArray(value);
281
+ }
282
+ function isErrorActorEvent(event) {
283
+ return event.type.startsWith('xstate.error.actor');
284
+ }
285
+ function toTransitionConfigArray(configLike) {
286
+ return toArrayStrict(configLike).map(transitionLike => {
287
+ if (typeof transitionLike === 'undefined' || typeof transitionLike === 'string') {
288
+ return {
289
+ target: transitionLike
290
+ };
291
+ }
292
+ return transitionLike;
293
+ });
294
+ }
295
+ function normalizeTarget(target) {
296
+ if (target === undefined || target === TARGETLESS_KEY) {
297
+ return undefined;
298
+ }
299
+ return toArray(target);
300
+ }
301
+ function toObserver(nextHandler, errorHandler, completionHandler) {
302
+ const isObserver = typeof nextHandler === 'object';
303
+ const self = isObserver ? nextHandler : undefined;
304
+ return {
305
+ next: (isObserver ? nextHandler.next : nextHandler)?.bind(self),
306
+ error: (isObserver ? nextHandler.error : errorHandler)?.bind(self),
307
+ complete: (isObserver ? nextHandler.complete : completionHandler)?.bind(self)
308
+ };
309
+ }
310
+ function createInvokeId(stateNodeId, index) {
311
+ return `${stateNodeId}[${index}]`;
312
+ }
313
+ function resolveReferencedActor(machine, src) {
314
+ if (src.startsWith('xstate#')) {
315
+ const [, indexStr] = src.match(/\[(\d+)\]$/);
316
+ const node = machine.getStateNodeById(src.slice(7, -(indexStr.length + 2)));
317
+ const invokeConfig = node.config.invoke;
318
+ return (Array.isArray(invokeConfig) ? invokeConfig[indexStr] : invokeConfig).src;
319
+ }
320
+ return machine.implementations.actors[src];
321
+ }
322
+
323
+ const $$ACTOR_TYPE = 1;
324
+ // those values are currently used by @xstate/react directly so it's important to keep the assigned values in sync
325
+ let ProcessingStatus = /*#__PURE__*/function (ProcessingStatus) {
326
+ ProcessingStatus[ProcessingStatus["NotStarted"] = 0] = "NotStarted";
327
+ ProcessingStatus[ProcessingStatus["Running"] = 1] = "Running";
328
+ ProcessingStatus[ProcessingStatus["Stopped"] = 2] = "Stopped";
329
+ return ProcessingStatus;
330
+ }({});
331
+ const defaultOptions = {
332
+ clock: {
333
+ setTimeout: (fn, ms) => {
334
+ return setTimeout(fn, ms);
335
+ },
336
+ clearTimeout: id => {
337
+ return clearTimeout(id);
338
+ }
339
+ },
340
+ logger: console.log.bind(console),
341
+ devTools: false
342
+ };
343
+
344
+ /**
345
+ * An Actor is a running process that can receive events, send events and change its behavior based on the events it receives, which can cause effects outside of the actor. When you run a state machine, it becomes an actor.
346
+ */
347
+ class Actor {
348
+ /**
349
+ * The current internal state of the actor.
350
+ */
351
+
352
+ /**
353
+ * The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions.
354
+ */
355
+
356
+ /**
357
+ * The unique identifier for this actor relative to its parent.
358
+ */
359
+
360
+ /** @internal */
361
+
362
+ // Actor Ref
363
+
364
+ // TODO: add typings for system
365
+
366
+ /**
367
+ * The globally unique process ID for this invocation.
368
+ */
369
+
370
+ /**
371
+ * The system to which this actor belongs.
372
+ */
373
+
374
+ /**
375
+ * Creates a new actor instance for the given logic with the provided options, if any.
376
+ *
377
+ * @param logic The logic to create an actor from
378
+ * @param options Actor options
379
+ */
380
+ constructor(logic, options) {
381
+ this.logic = logic;
382
+ this._state = void 0;
383
+ this.clock = void 0;
384
+ this.options = void 0;
385
+ this.id = void 0;
386
+ this.mailbox = new Mailbox(this._process.bind(this));
387
+ this.delayedEventsMap = {};
388
+ this.observers = new Set();
389
+ this.logger = void 0;
390
+ this._processingStatus = ProcessingStatus.NotStarted;
391
+ this._parent = void 0;
392
+ this._syncSnapshot = void 0;
393
+ this.ref = void 0;
394
+ this._actorScope = void 0;
395
+ this._systemId = void 0;
396
+ this.sessionId = void 0;
397
+ this.system = void 0;
398
+ this._doneEvent = void 0;
399
+ this.src = void 0;
400
+ this._deferred = [];
401
+ const resolvedOptions = {
402
+ ...defaultOptions,
403
+ ...options
404
+ };
405
+ const {
406
+ clock,
407
+ logger,
408
+ parent,
409
+ syncSnapshot,
410
+ id,
411
+ systemId,
412
+ inspect
413
+ } = resolvedOptions;
414
+ this.system = parent?.system ?? createSystem(this);
415
+ if (inspect && !parent) {
416
+ // Always inspect at the system-level
417
+ this.system.inspect(toObserver(inspect));
418
+ }
419
+ this.sessionId = this.system._bookId();
420
+ this.id = id ?? this.sessionId;
421
+ this.logger = logger;
422
+ this.clock = clock;
423
+ this._parent = parent;
424
+ this._syncSnapshot = syncSnapshot;
425
+ this.options = resolvedOptions;
426
+ this.src = resolvedOptions.src ?? logic;
427
+ this.ref = this;
428
+ this._actorScope = {
429
+ self: this,
430
+ id: this.id,
431
+ sessionId: this.sessionId,
432
+ logger: this.logger,
433
+ defer: fn => {
434
+ this._deferred.push(fn);
435
+ },
436
+ system: this.system,
437
+ stopChild: child => {
438
+ if (child._parent !== this) {
439
+ throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`);
440
+ }
441
+ child._stop();
442
+ }
443
+ };
444
+
445
+ // Ensure that the send method is bound to this Actor instance
446
+ // if destructured
447
+ this.send = this.send.bind(this);
448
+ this.system._sendInspectionEvent({
449
+ type: '@xstate.actor',
450
+ actorRef: this
451
+ });
452
+ if (systemId) {
453
+ this._systemId = systemId;
454
+ this.system._set(systemId, this);
455
+ }
456
+ this._initState(options?.state);
457
+ if (systemId && this._state.status !== 'active') {
458
+ this.system._unregister(this);
459
+ }
460
+ }
461
+ _initState(persistedState) {
462
+ this._state = persistedState ? this.logic.restoreState ? this.logic.restoreState(persistedState, this._actorScope) : persistedState : this.logic.getInitialState(this._actorScope, this.options?.input);
463
+ }
464
+
465
+ // array of functions to defer
466
+
467
+ update(snapshot, event) {
468
+ // Update state
469
+ this._state = snapshot;
470
+
471
+ // Execute deferred effects
472
+ let deferredFn;
473
+ while (deferredFn = this._deferred.shift()) {
474
+ deferredFn();
475
+ }
476
+ for (const observer of this.observers) {
477
+ try {
478
+ observer.next?.(snapshot);
479
+ } catch (err) {
480
+ reportUnhandledError(err);
481
+ }
482
+ }
483
+ switch (this._state.status) {
484
+ case 'done':
485
+ this._stopProcedure();
486
+ this._complete();
487
+ this._doneEvent = createDoneActorEvent(this.id, this._state.output);
488
+ if (this._parent) {
489
+ this.system._relay(this, this._parent, this._doneEvent);
490
+ }
491
+ break;
492
+ case 'error':
493
+ this._stopProcedure();
494
+ this._error(this._state.error);
495
+ if (this._parent) {
496
+ this.system._relay(this, this._parent, createErrorActorEvent(this.id, this._state.error));
497
+ }
498
+ break;
499
+ }
500
+ this.system._sendInspectionEvent({
501
+ type: '@xstate.snapshot',
502
+ actorRef: this,
503
+ event,
504
+ snapshot
505
+ });
506
+ }
507
+
508
+ /**
509
+ * Subscribe an observer to an actor’s snapshot values.
510
+ *
511
+ * @remarks
512
+ * The observer will receive the actor’s snapshot value when it is emitted. The observer can be:
513
+ * - A plain function that receives the latest snapshot, or
514
+ * - An observer object whose `.next(snapshot)` method receives the latest snapshot
515
+ *
516
+ * @example
517
+ * ```ts
518
+ * // Observer as a plain function
519
+ * const subscription = actor.subscribe((snapshot) => {
520
+ * console.log(snapshot);
521
+ * });
522
+ * ```
523
+ *
524
+ * @example
525
+ * ```ts
526
+ * // Observer as an object
527
+ * const subscription = actor.subscribe({
528
+ * next(snapshot) {
529
+ * console.log(snapshot);
530
+ * },
531
+ * error(err) {
532
+ * // ...
533
+ * },
534
+ * complete() {
535
+ * // ...
536
+ * },
537
+ * });
538
+ * ```
539
+ *
540
+ * The return value of `actor.subscribe(observer)` is a subscription object that has an `.unsubscribe()` method. You can call `subscription.unsubscribe()` to unsubscribe the observer:
541
+ *
542
+ * @example
543
+ * ```ts
544
+ * const subscription = actor.subscribe((snapshot) => {
545
+ * // ...
546
+ * });
547
+ *
548
+ * // Unsubscribe the observer
549
+ * subscription.unsubscribe();
550
+ * ```
551
+ *
552
+ * When the actor is stopped, all of its observers will automatically be unsubscribed.
553
+ *
554
+ * @param observer - Either a plain function that receives the latest snapshot, or an observer object whose `.next(snapshot)` method receives the latest snapshot
555
+ */
556
+
557
+ subscribe(nextListenerOrObserver, errorListener, completeListener) {
558
+ const observer = toObserver(nextListenerOrObserver, errorListener, completeListener);
559
+ if (this._processingStatus !== ProcessingStatus.Stopped) {
560
+ this.observers.add(observer);
561
+ } else {
562
+ try {
563
+ observer.complete?.();
564
+ } catch (err) {
565
+ reportUnhandledError(err);
566
+ }
567
+ }
568
+ return {
569
+ unsubscribe: () => {
570
+ this.observers.delete(observer);
571
+ }
9
572
  };
10
- cache.set(object, memoizedData);
11
- } else if (!(key in memoizedData)) {
12
- memoizedData[key] = fn();
13
573
  }
14
- return memoizedData[key];
574
+
575
+ /**
576
+ * Starts the Actor from the initial state
577
+ */
578
+ start() {
579
+ if (this._processingStatus === ProcessingStatus.Running) {
580
+ // Do not restart the service if it is already started
581
+ return this;
582
+ }
583
+ if (this._syncSnapshot) {
584
+ this.subscribe({
585
+ next: snapshot => {
586
+ if (snapshot.status === 'active') {
587
+ this._parent.send({
588
+ type: `xstate.snapshot.${this.id}`,
589
+ snapshot
590
+ });
591
+ }
592
+ },
593
+ error: () => {}
594
+ });
595
+ }
596
+ this.system._register(this.sessionId, this);
597
+ if (this._systemId) {
598
+ this.system._set(this._systemId, this);
599
+ }
600
+ this._processingStatus = ProcessingStatus.Running;
601
+
602
+ // TODO: this isn't correct when rehydrating
603
+ const initEvent = createInitEvent(this.options.input);
604
+ this.system._sendInspectionEvent({
605
+ type: '@xstate.event',
606
+ sourceRef: this._parent,
607
+ actorRef: this,
608
+ event: initEvent
609
+ });
610
+ const status = this._state.status;
611
+ switch (status) {
612
+ case 'done':
613
+ // a state machine can be "done" upon initialization (it could reach a final state using initial microsteps)
614
+ // we still need to complete observers, flush deferreds etc
615
+ this.update(this._state, initEvent);
616
+ // fallthrough
617
+ case 'error':
618
+ // TODO: rethink cleanup of observers, mailbox, etc
619
+ return this;
620
+ }
621
+ if (this.logic.start) {
622
+ try {
623
+ this.logic.start(this._state, this._actorScope);
624
+ } catch (err) {
625
+ this._stopProcedure();
626
+ this._error(err);
627
+ this._parent?.send(createErrorActorEvent(this.id, err));
628
+ return this;
629
+ }
630
+ }
631
+
632
+ // TODO: this notifies all subscribers but usually this is redundant
633
+ // there is no real change happening here
634
+ // we need to rethink if this needs to be refactored
635
+ this.update(this._state, initEvent);
636
+ if (this.options.devTools) {
637
+ this.attachDevTools();
638
+ }
639
+ this.mailbox.start();
640
+ return this;
641
+ }
642
+ _process(event) {
643
+ // TODO: reexamine what happens when an action (or a guard or smth) throws
644
+ let nextState;
645
+ let caughtError;
646
+ try {
647
+ nextState = this.logic.transition(this._state, event, this._actorScope);
648
+ } catch (err) {
649
+ // we wrap it in a box so we can rethrow it later even if falsy value gets caught here
650
+ caughtError = {
651
+ err
652
+ };
653
+ }
654
+ if (caughtError) {
655
+ const {
656
+ err
657
+ } = caughtError;
658
+ this._stopProcedure();
659
+ this._error(err);
660
+ this._parent?.send(createErrorActorEvent(this.id, err));
661
+ return;
662
+ }
663
+ this.update(nextState, event);
664
+ if (event.type === XSTATE_STOP) {
665
+ this._stopProcedure();
666
+ this._complete();
667
+ }
668
+ }
669
+ _stop() {
670
+ if (this._processingStatus === ProcessingStatus.Stopped) {
671
+ return this;
672
+ }
673
+ this.mailbox.clear();
674
+ if (this._processingStatus === ProcessingStatus.NotStarted) {
675
+ this._processingStatus = ProcessingStatus.Stopped;
676
+ return this;
677
+ }
678
+ this.mailbox.enqueue({
679
+ type: XSTATE_STOP
680
+ });
681
+ return this;
682
+ }
683
+
684
+ /**
685
+ * Stops the Actor and unsubscribe all listeners.
686
+ */
687
+ stop() {
688
+ if (this._parent) {
689
+ throw new Error('A non-root actor cannot be stopped directly.');
690
+ }
691
+ return this._stop();
692
+ }
693
+ _complete() {
694
+ for (const observer of this.observers) {
695
+ try {
696
+ observer.complete?.();
697
+ } catch (err) {
698
+ reportUnhandledError(err);
699
+ }
700
+ }
701
+ this.observers.clear();
702
+ }
703
+ _error(err) {
704
+ if (!this.observers.size) {
705
+ if (!this._parent) {
706
+ reportUnhandledError(err);
707
+ }
708
+ return;
709
+ }
710
+ let reportError = false;
711
+ for (const observer of this.observers) {
712
+ const errorListener = observer.error;
713
+ reportError ||= !errorListener;
714
+ try {
715
+ errorListener?.(err);
716
+ } catch (err2) {
717
+ reportUnhandledError(err2);
718
+ }
719
+ }
720
+ this.observers.clear();
721
+ if (reportError) {
722
+ reportUnhandledError(err);
723
+ }
724
+ }
725
+ _stopProcedure() {
726
+ if (this._processingStatus !== ProcessingStatus.Running) {
727
+ // Actor already stopped; do nothing
728
+ return this;
729
+ }
730
+
731
+ // Cancel all delayed events
732
+ for (const key of Object.keys(this.delayedEventsMap)) {
733
+ this.clock.clearTimeout(this.delayedEventsMap[key]);
734
+ }
735
+
736
+ // TODO: mailbox.reset
737
+ this.mailbox.clear();
738
+ // TODO: after `stop` we must prepare ourselves for receiving events again
739
+ // events sent *after* stop signal must be queued
740
+ // it seems like this should be the common behavior for all of our consumers
741
+ // so perhaps this should be unified somehow for all of them
742
+ this.mailbox = new Mailbox(this._process.bind(this));
743
+ this._processingStatus = ProcessingStatus.Stopped;
744
+ this.system._unregister(this);
745
+ return this;
746
+ }
747
+
748
+ /**
749
+ * @internal
750
+ */
751
+ _send(event) {
752
+ if (this._processingStatus === ProcessingStatus.Stopped) {
753
+ // do nothing
754
+ {
755
+ const eventString = JSON.stringify(event);
756
+ console.warn(`Event "${event.type}" was sent to stopped actor "${this.id} (${this.sessionId})". This actor has already reached its final state, and will not transition.\nEvent: ${eventString}`);
757
+ }
758
+ return;
759
+ }
760
+ this.mailbox.enqueue(event);
761
+ }
762
+
763
+ /**
764
+ * Sends an event to the running Actor to trigger a transition.
765
+ *
766
+ * @param event The event to send
767
+ */
768
+ send(event) {
769
+ if (typeof event === 'string') {
770
+ throw new Error(`Only event objects may be sent to actors; use .send({ type: "${event}" }) instead`);
771
+ }
772
+ this.system._relay(undefined, this, event);
773
+ }
774
+
775
+ /**
776
+ * TODO: figure out a way to do this within the machine
777
+ * @internal
778
+ */
779
+ delaySend(params) {
780
+ const {
781
+ event,
782
+ id,
783
+ delay
784
+ } = params;
785
+ const timerId = this.clock.setTimeout(() => {
786
+ this.system._relay(this, params.to ?? this, event);
787
+ }, delay);
788
+
789
+ // TODO: consider the rehydration story here
790
+ if (id) {
791
+ this.delayedEventsMap[id] = timerId;
792
+ }
793
+ }
794
+
795
+ /**
796
+ * TODO: figure out a way to do this within the machine
797
+ * @internal
798
+ */
799
+ cancel(sendId) {
800
+ this.clock.clearTimeout(this.delayedEventsMap[sendId]);
801
+ delete this.delayedEventsMap[sendId];
802
+ }
803
+ attachDevTools() {
804
+ const {
805
+ devTools
806
+ } = this.options;
807
+ if (devTools) {
808
+ const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : devToolsAdapter;
809
+ resolvedDevToolsAdapter(this);
810
+ }
811
+ }
812
+ toJSON() {
813
+ return {
814
+ xstate$$type: $$ACTOR_TYPE,
815
+ id: this.id
816
+ };
817
+ }
818
+
819
+ /**
820
+ * Obtain the internal state of the actor, which can be persisted.
821
+ *
822
+ * @remarks
823
+ * The internal state can be persisted from any actor, not only machines.
824
+ *
825
+ * Note that the persisted state is not the same as the snapshot from {@link Actor.getSnapshot}. Persisted state represents the internal state of the actor, while snapshots represent the actor's last emitted value.
826
+ *
827
+ * Can be restored with {@link ActorOptions.state}
828
+ *
829
+ * @see https://stately.ai/docs/persistence
830
+ */
831
+
832
+ getPersistedState(options) {
833
+ return this.logic.getPersistedState(this._state, options);
834
+ }
835
+ [symbolObservable]() {
836
+ return this;
837
+ }
838
+
839
+ /**
840
+ * Read an actor’s snapshot synchronously.
841
+ *
842
+ * @remarks
843
+ * The snapshot represent an actor's last emitted value.
844
+ *
845
+ * When an actor receives an event, its internal state may change.
846
+ * An actor may emit a snapshot when a state transition occurs.
847
+ *
848
+ * Note that some actors, such as callback actors generated with `fromCallback`, will not emit snapshots.
849
+ *
850
+ * @see {@link Actor.subscribe} to subscribe to an actor’s snapshot values.
851
+ * @see {@link Actor.getPersistedState} to persist the internal state of an actor (which is more than just a snapshot).
852
+ */
853
+ getSnapshot() {
854
+ return this._state;
855
+ }
15
856
  }
16
857
 
858
+ /**
859
+ * Creates a new `ActorRef` instance for the given machine with the provided options, if any.
860
+ *
861
+ * @param machine The machine to create an actor from
862
+ * @param options `ActorRef` options
863
+ */
864
+
865
+ function createActor(logic, options) {
866
+ const interpreter = new Actor(logic, options);
867
+ return interpreter;
868
+ }
869
+
870
+ /**
871
+ * Creates a new Interpreter instance for the given machine with the provided options, if any.
872
+ *
873
+ * @deprecated Use `createActor` instead
874
+ */
875
+ const interpret = createActor;
876
+
877
+ /**
878
+ * @deprecated Use `Actor` instead.
879
+ */
880
+
17
881
  function resolveCancel(_, state, actionArgs, actionParams, {
18
882
  sendId
19
883
  }) {
@@ -58,6 +922,7 @@ function resolveSpawn(actorScope, state, actionArgs, _actionParams, {
58
922
  id: resolvedId,
59
923
  src,
60
924
  parent: actorScope?.self,
925
+ syncSnapshot,
61
926
  systemId,
62
927
  input: typeof input === 'function' ? input({
63
928
  context: state.context,
@@ -65,19 +930,6 @@ function resolveSpawn(actorScope, state, actionArgs, _actionParams, {
65
930
  self: actorScope?.self
66
931
  }) : input
67
932
  });
68
- if (syncSnapshot) {
69
- actorRef.subscribe({
70
- next: snapshot => {
71
- if (snapshot.status === 'active') {
72
- actorScope.self.send({
73
- type: `xstate.snapshot.${id}`,
74
- snapshot
75
- });
76
- }
77
- },
78
- error: () => {}
79
- });
80
- }
81
933
  }
82
934
  if (!actorRef) {
83
935
  console.warn(`Actor type '${src}' not found in machine '${actorScope.id}'.`);
@@ -196,7 +1048,7 @@ function checkStateIn(state, _, {
196
1048
  }) {
197
1049
  if (typeof stateValue === 'string' && isStateId(stateValue)) {
198
1050
  const target = state.machine.getStateNodeById(stateValue);
199
- return state.configuration.some(sn => sn === target);
1051
+ return state._nodes.some(sn => sn === target);
200
1052
  }
201
1053
  return state.matches(stateValue);
202
1054
  }
@@ -315,26 +1167,25 @@ function getProperAncestors(stateNode, toStateNode) {
315
1167
  }
316
1168
  return ancestors;
317
1169
  }
318
- function getConfiguration(stateNodes) {
319
- const configuration = new Set(stateNodes);
320
- const configurationSet = new Set(stateNodes);
321
- const adjList = getAdjList(configurationSet);
1170
+ function getAllStateNodes(stateNodes) {
1171
+ const nodeSet = new Set(stateNodes);
1172
+ const adjList = getAdjList(nodeSet);
322
1173
 
323
1174
  // add descendants
324
- for (const s of configuration) {
1175
+ for (const s of nodeSet) {
325
1176
  // if previously active, add existing child nodes
326
1177
  if (s.type === 'compound' && (!adjList.get(s) || !adjList.get(s).length)) {
327
- getInitialStateNodesWithTheirAncestors(s).forEach(sn => configurationSet.add(sn));
1178
+ getInitialStateNodesWithTheirAncestors(s).forEach(sn => nodeSet.add(sn));
328
1179
  } else {
329
1180
  if (s.type === 'parallel') {
330
1181
  for (const child of getChildren(s)) {
331
1182
  if (child.type === 'history') {
332
1183
  continue;
333
1184
  }
334
- if (!configurationSet.has(child)) {
1185
+ if (!nodeSet.has(child)) {
335
1186
  const initialStates = getInitialStateNodesWithTheirAncestors(child);
336
1187
  for (const initialStateNode of initialStates) {
337
- configurationSet.add(initialStateNode);
1188
+ nodeSet.add(initialStateNode);
338
1189
  }
339
1190
  }
340
1191
  }
@@ -343,14 +1194,14 @@ function getConfiguration(stateNodes) {
343
1194
  }
344
1195
 
345
1196
  // add all ancestors
346
- for (const s of configurationSet) {
1197
+ for (const s of nodeSet) {
347
1198
  let m = s.parent;
348
1199
  while (m) {
349
- configurationSet.add(m);
1200
+ nodeSet.add(m);
350
1201
  m = m.parent;
351
1202
  }
352
1203
  }
353
- return configurationSet;
1204
+ return nodeSet;
354
1205
  }
355
1206
  function getValueFromAdj(baseNode, adjList) {
356
1207
  const childStateNodes = adjList.get(baseNode);
@@ -374,9 +1225,9 @@ function getValueFromAdj(baseNode, adjList) {
374
1225
  }
375
1226
  return stateValue;
376
1227
  }
377
- function getAdjList(configuration) {
1228
+ function getAdjList(stateNodes) {
378
1229
  const adjList = new Map();
379
- for (const s of configuration) {
1230
+ for (const s of stateNodes) {
380
1231
  if (!adjList.has(s)) {
381
1232
  adjList.set(s, []);
382
1233
  }
@@ -389,16 +1240,16 @@ function getAdjList(configuration) {
389
1240
  }
390
1241
  return adjList;
391
1242
  }
392
- function getStateValue(rootNode, configuration) {
393
- const config = getConfiguration(configuration);
1243
+ function getStateValue(rootNode, stateNodes) {
1244
+ const config = getAllStateNodes(stateNodes);
394
1245
  return getValueFromAdj(rootNode, getAdjList(config));
395
1246
  }
396
- function isInFinalState(configuration, stateNode) {
1247
+ function isInFinalState(stateNodeSet, stateNode) {
397
1248
  if (stateNode.type === 'compound') {
398
- return getChildren(stateNode).some(s => s.type === 'final' && configuration.has(s));
1249
+ return getChildren(stateNode).some(s => s.type === 'final' && stateNodeSet.has(s));
399
1250
  }
400
1251
  if (stateNode.type === 'parallel') {
401
- return getChildren(stateNode).every(sn => isInFinalState(configuration, sn));
1252
+ return getChildren(stateNode).every(sn => isInFinalState(stateNodeSet, sn));
402
1253
  }
403
1254
  return stateNode.type === 'final';
404
1255
  }
@@ -769,13 +1620,13 @@ function hasIntersection(s1, s2) {
769
1620
  }
770
1621
  return false;
771
1622
  }
772
- function removeConflictingTransitions(enabledTransitions, configuration, historyValue) {
1623
+ function removeConflictingTransitions(enabledTransitions, stateNodeSet, historyValue) {
773
1624
  const filteredTransitions = new Set();
774
1625
  for (const t1 of enabledTransitions) {
775
1626
  let t1Preempted = false;
776
1627
  const transitionsToRemove = new Set();
777
1628
  for (const t2 of filteredTransitions) {
778
- if (hasIntersection(computeExitSet([t1], configuration, historyValue), computeExitSet([t2], configuration, historyValue))) {
1629
+ if (hasIntersection(computeExitSet([t1], stateNodeSet, historyValue), computeExitSet([t2], stateNodeSet, historyValue))) {
779
1630
  if (isDescendant(t1.source, t2.source)) {
780
1631
  transitionsToRemove.add(t2);
781
1632
  } else {
@@ -842,7 +1693,7 @@ function getTransitionDomain(transition, historyValue) {
842
1693
  }
843
1694
  return transition.source.machine.root;
844
1695
  }
845
- function computeExitSet(transitions, configuration, historyValue) {
1696
+ function computeExitSet(transitions, stateNodeSet, historyValue) {
846
1697
  const statesToExit = new Set();
847
1698
  for (const t of transitions) {
848
1699
  if (t.target?.length) {
@@ -850,7 +1701,7 @@ function computeExitSet(transitions, configuration, historyValue) {
850
1701
  if (t.reenter && t.source === domain) {
851
1702
  statesToExit.add(domain);
852
1703
  }
853
- for (const stateNode of configuration) {
1704
+ for (const stateNode of stateNodeSet) {
854
1705
  if (isDescendant(stateNode, domain)) {
855
1706
  statesToExit.add(stateNode);
856
1707
  }
@@ -859,12 +1710,12 @@ function computeExitSet(transitions, configuration, historyValue) {
859
1710
  }
860
1711
  return [...statesToExit];
861
1712
  }
862
- function areConfigurationsEqual(previousConfiguration, nextConfigurationSet) {
863
- if (previousConfiguration.length !== nextConfigurationSet.size) {
1713
+ function areStateNodeCollectionsEqual(prevStateNodes, nextStateNodeSet) {
1714
+ if (prevStateNodes.length !== nextStateNodeSet.size) {
864
1715
  return false;
865
1716
  }
866
- for (const node of previousConfiguration) {
867
- if (!nextConfigurationSet.has(node)) {
1717
+ for (const node of prevStateNodes) {
1718
+ if (!nextStateNodeSet.has(node)) {
868
1719
  return false;
869
1720
  }
870
1721
  }
@@ -878,31 +1729,31 @@ function microstep(transitions, currentState, actorScope, event, isInitial, inte
878
1729
  if (!transitions.length) {
879
1730
  return currentState;
880
1731
  }
881
- const mutConfiguration = new Set(currentState.configuration);
1732
+ const mutStateNodeSet = new Set(currentState._nodes);
882
1733
  let historyValue = currentState.historyValue;
883
- const filteredTransitions = removeConflictingTransitions(transitions, mutConfiguration, historyValue);
1734
+ const filteredTransitions = removeConflictingTransitions(transitions, mutStateNodeSet, historyValue);
884
1735
  let nextState = currentState;
885
1736
 
886
1737
  // Exit states
887
1738
  if (!isInitial) {
888
- [nextState, historyValue] = exitStates(nextState, event, actorScope, filteredTransitions, mutConfiguration, historyValue, internalQueue);
1739
+ [nextState, historyValue] = exitStates(nextState, event, actorScope, filteredTransitions, mutStateNodeSet, historyValue, internalQueue);
889
1740
  }
890
1741
 
891
1742
  // Execute transition content
892
1743
  nextState = resolveActionsAndContext(nextState, event, actorScope, filteredTransitions.flatMap(t => t.actions), internalQueue);
893
1744
 
894
1745
  // Enter states
895
- nextState = enterStates(nextState, event, actorScope, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial);
896
- const nextConfiguration = [...mutConfiguration];
1746
+ nextState = enterStates(nextState, event, actorScope, filteredTransitions, mutStateNodeSet, internalQueue, historyValue, isInitial);
1747
+ const nextStateNodes = [...mutStateNodeSet];
897
1748
  if (nextState.status === 'done') {
898
- nextState = resolveActionsAndContext(nextState, event, actorScope, nextConfiguration.sort((a, b) => b.order - a.order).flatMap(state => state.exit), internalQueue);
1749
+ nextState = resolveActionsAndContext(nextState, event, actorScope, nextStateNodes.sort((a, b) => b.order - a.order).flatMap(state => state.exit), internalQueue);
899
1750
  }
900
1751
  try {
901
- if (historyValue === currentState.historyValue && areConfigurationsEqual(currentState.configuration, mutConfiguration)) {
1752
+ if (historyValue === currentState.historyValue && areStateNodeCollectionsEqual(currentState._nodes, mutStateNodeSet)) {
902
1753
  return nextState;
903
1754
  }
904
1755
  return cloneMachineSnapshot(nextState, {
905
- configuration: nextConfiguration,
1756
+ _nodes: nextStateNodes,
906
1757
  historyValue
907
1758
  });
908
1759
  } catch (e) {
@@ -918,7 +1769,7 @@ function getMachineOutput(state, event, actorScope, rootNode, rootCompletionNode
918
1769
  const doneStateEvent = createDoneStateEvent(rootCompletionNode.id, rootCompletionNode.output && rootCompletionNode.parent ? resolveOutput(rootCompletionNode.output, state.context, event, actorScope.self) : undefined);
919
1770
  return resolveOutput(rootNode.output, state.context, doneStateEvent, actorScope.self);
920
1771
  }
921
- function enterStates(currentState, event, actorScope, filteredTransitions, mutConfiguration, internalQueue, historyValue, isInitial) {
1772
+ function enterStates(currentState, event, actorScope, filteredTransitions, mutStateNodeSet, internalQueue, historyValue, isInitial) {
922
1773
  let nextState = currentState;
923
1774
  const statesToEnter = new Set();
924
1775
  // those are states that were directly targeted or indirectly targeted by the explicit target
@@ -933,7 +1784,7 @@ function enterStates(currentState, event, actorScope, filteredTransitions, mutCo
933
1784
  }
934
1785
  const completedNodes = new Set();
935
1786
  for (const stateNodeToEnter of [...statesToEnter].sort((a, b) => a.order - b.order)) {
936
- mutConfiguration.add(stateNodeToEnter);
1787
+ mutStateNodeSet.add(stateNodeToEnter);
937
1788
  const actions = [];
938
1789
 
939
1790
  // Add entry actions
@@ -956,7 +1807,7 @@ function enterStates(currentState, event, actorScope, filteredTransitions, mutCo
956
1807
  if (parent?.type === 'compound') {
957
1808
  internalQueue.push(createDoneStateEvent(parent.id, stateNodeToEnter.output ? resolveOutput(stateNodeToEnter.output, nextState.context, event, actorScope.self) : undefined));
958
1809
  }
959
- while (ancestorMarker?.type === 'parallel' && !completedNodes.has(ancestorMarker) && isInFinalState(mutConfiguration, ancestorMarker)) {
1810
+ while (ancestorMarker?.type === 'parallel' && !completedNodes.has(ancestorMarker) && isInFinalState(mutStateNodeSet, ancestorMarker)) {
960
1811
  completedNodes.add(ancestorMarker);
961
1812
  internalQueue.push(createDoneStateEvent(ancestorMarker.id));
962
1813
  rootCompletionNode = ancestorMarker;
@@ -1066,9 +1917,9 @@ function addAncestorStatesToEnter(statesToEnter, historyValue, statesForDefaultE
1066
1917
  function addProperAncestorStatesToEnter(stateNode, toStateNode, statesToEnter, historyValue, statesForDefaultEntry) {
1067
1918
  addAncestorStatesToEnter(statesToEnter, historyValue, statesForDefaultEntry, getProperAncestors(stateNode, toStateNode));
1068
1919
  }
1069
- function exitStates(currentState, event, actorScope, transitions, mutConfiguration, historyValue, internalQueue) {
1920
+ function exitStates(currentState, event, actorScope, transitions, mutStateNodeSet, historyValue, internalQueue) {
1070
1921
  let nextState = currentState;
1071
- const statesToExit = computeExitSet(transitions, mutConfiguration, historyValue);
1922
+ const statesToExit = computeExitSet(transitions, mutStateNodeSet, historyValue);
1072
1923
  statesToExit.sort((a, b) => b.order - a.order);
1073
1924
  let changedHistory;
1074
1925
 
@@ -1086,12 +1937,12 @@ function exitStates(currentState, event, actorScope, transitions, mutConfigurati
1086
1937
  changedHistory ??= {
1087
1938
  ...historyValue
1088
1939
  };
1089
- changedHistory[historyNode.id] = Array.from(mutConfiguration).filter(predicate);
1940
+ changedHistory[historyNode.id] = Array.from(mutStateNodeSet).filter(predicate);
1090
1941
  }
1091
1942
  }
1092
1943
  for (const s of statesToExit) {
1093
1944
  nextState = resolveActionsAndContext(nextState, event, actorScope, [...s.exit, ...s.invoke.map(def => stop(def.id))], internalQueue);
1094
- mutConfiguration.delete(s);
1945
+ mutStateNodeSet.delete(s);
1095
1946
  }
1096
1947
  return [nextState, changedHistory || historyValue];
1097
1948
  }
@@ -1223,7 +2074,7 @@ function selectTransitions(event, nextState) {
1223
2074
  }
1224
2075
  function selectEventlessTransitions(nextState, event) {
1225
2076
  const enabledTransitionSet = new Set();
1226
- const atomicStates = nextState.configuration.filter(isAtomicStateNode);
2077
+ const atomicStates = nextState._nodes.filter(isAtomicStateNode);
1227
2078
  for (const stateNode of atomicStates) {
1228
2079
  loop: for (const s of [stateNode].concat(getProperAncestors(stateNode, undefined))) {
1229
2080
  if (!s.always) {
@@ -1237,7 +2088,7 @@ function selectEventlessTransitions(nextState, event) {
1237
2088
  }
1238
2089
  }
1239
2090
  }
1240
- return removeConflictingTransitions(Array.from(enabledTransitionSet), new Set(nextState.configuration), nextState.historyValue);
2091
+ return removeConflictingTransitions(Array.from(enabledTransitionSet), new Set(nextState._nodes), nextState.historyValue);
1241
2092
  }
1242
2093
 
1243
2094
  /**
@@ -1246,10 +2097,13 @@ function selectEventlessTransitions(nextState, event) {
1246
2097
  * @param stateValue The partial state value to resolve.
1247
2098
  */
1248
2099
  function resolveStateValue(rootNode, stateValue) {
1249
- const configuration = getConfiguration(getStateNodes(rootNode, stateValue));
1250
- return getStateValue(rootNode, [...configuration]);
2100
+ const allStateNodes = getAllStateNodes(getStateNodes(rootNode, stateValue));
2101
+ return getStateValue(rootNode, [...allStateNodes]);
1251
2102
  }
1252
2103
 
2104
+ function isMachineSnapshot(value) {
2105
+ return !!value && typeof value === 'object' && 'machine' in value && 'value' in value;
2106
+ }
1253
2107
  const machineSnapshotMatches = function matches(testValue) {
1254
2108
  return matchesState(testValue, this.value);
1255
2109
  };
@@ -1267,10 +2121,11 @@ const machineSnapshotCan = function can(event) {
1267
2121
  };
1268
2122
  const machineSnapshotToJSON = function toJSON() {
1269
2123
  const {
1270
- configuration,
2124
+ _nodes: nodes,
1271
2125
  tags,
1272
2126
  machine,
1273
- nextEvents,
2127
+ getNextEvents,
2128
+ getMeta,
1274
2129
  toJSON,
1275
2130
  can,
1276
2131
  hasTag,
@@ -1282,13 +2137,11 @@ const machineSnapshotToJSON = function toJSON() {
1282
2137
  tags: Array.from(tags)
1283
2138
  };
1284
2139
  };
1285
- const machineSnapshotNextEvents = function nextEvents() {
1286
- return memo(this, 'nextEvents', () => {
1287
- return [...new Set(flatten([...this.configuration.map(sn => sn.ownEvents)]))];
1288
- });
2140
+ const machineSnapshotGetNextEvents = function getNextEvents() {
2141
+ return [...new Set(flatten([...this._nodes.map(sn => sn.ownEvents)]))];
1289
2142
  };
1290
- const machineSnapshotMeta = function nextEvents() {
1291
- return this.configuration.reduce((acc, stateNode) => {
2143
+ const machineSnapshotGetMeta = function getMeta() {
2144
+ return this._nodes.reduce((acc, stateNode) => {
1292
2145
  if (stateNode.meta !== undefined) {
1293
2146
  acc[stateNode.id] = stateNode.meta;
1294
2147
  }
@@ -1296,48 +2149,35 @@ const machineSnapshotMeta = function nextEvents() {
1296
2149
  }, {});
1297
2150
  };
1298
2151
  function createMachineSnapshot(config, machine) {
1299
- const snapshot = {
2152
+ return {
1300
2153
  status: config.status,
1301
2154
  output: config.output,
1302
2155
  error: config.error,
1303
2156
  machine,
1304
2157
  context: config.context,
1305
- configuration: config.configuration,
1306
- value: getStateValue(machine.root, config.configuration),
1307
- tags: new Set(flatten(config.configuration.map(sn => sn.tags))),
2158
+ _nodes: config._nodes,
2159
+ value: getStateValue(machine.root, config._nodes),
2160
+ tags: new Set(flatten(config._nodes.map(sn => sn.tags))),
1308
2161
  children: config.children,
1309
2162
  historyValue: config.historyValue || {},
1310
2163
  // this one is generic in the target and it's hard to create a matching non-generic source signature
1311
2164
  matches: machineSnapshotMatches,
1312
2165
  hasTag: machineSnapshotHasTag,
1313
2166
  can: machineSnapshotCan,
2167
+ getNextEvents: machineSnapshotGetNextEvents,
2168
+ getMeta: machineSnapshotGetMeta,
1314
2169
  toJSON: machineSnapshotToJSON
1315
2170
  };
1316
- Object.defineProperties(snapshot, {
1317
- nextEvents: {
1318
- get: machineSnapshotNextEvents,
1319
- configurable: true,
1320
- enumerable: true
1321
- },
1322
- meta: {
1323
- get: machineSnapshotMeta,
1324
- configurable: true,
1325
- enumerable: true
1326
- }
1327
- });
1328
- return snapshot;
1329
2171
  }
1330
2172
  function cloneMachineSnapshot(state, config = {}) {
1331
- return createMachineSnapshot(
1332
- // TODO: it's wasteful that this spread triggers getters
1333
- {
2173
+ return createMachineSnapshot({
1334
2174
  ...state,
1335
2175
  ...config
1336
2176
  }, state.machine);
1337
2177
  }
1338
2178
  function getPersistedState(state, options) {
1339
2179
  const {
1340
- configuration,
2180
+ _nodes: nodes,
1341
2181
  tags,
1342
2182
  machine,
1343
2183
  children,
@@ -1345,8 +2185,9 @@ function getPersistedState(state, options) {
1345
2185
  can,
1346
2186
  hasTag,
1347
2187
  matches,
2188
+ getNextEvents,
2189
+ getMeta,
1348
2190
  toJSON,
1349
- nextEvents,
1350
2191
  ...jsonValues
1351
2192
  } = state;
1352
2193
  const childrenJson = {};
@@ -1358,7 +2199,8 @@ function getPersistedState(state, options) {
1358
2199
  childrenJson[id] = {
1359
2200
  state: child.getPersistedState(options),
1360
2201
  src: child.src,
1361
- systemId: child._systemId
2202
+ systemId: child._systemId,
2203
+ syncSnapshot: child._syncSnapshot
1362
2204
  };
1363
2205
  }
1364
2206
  const persisted = {
@@ -1450,4 +2292,4 @@ function raise(eventOrExpr, options) {
1450
2292
  return raise;
1451
2293
  }
1452
2294
 
1453
- export { raise as A, stop as B, spawn as C, formatTransition as a, formatInitialTransition as b, getCandidates as c, getConfiguration as d, evaluateGuard as e, formatTransitions as f, getDelayedTransitions as g, getStateNodes as h, createMachineSnapshot as i, isInFinalState as j, cloneMachineSnapshot as k, macrostep as l, memo as m, resolveActionsAndContext as n, microstep as o, getInitialStateNodes as p, isStateId as q, resolveStateValue as r, getStateNodeByPath as s, transitionNode as t, getPersistedState as u, and as v, not as w, or as x, stateIn as y, cancel as z };
2295
+ export { $$ACTOR_TYPE as $, resolveReferencedActor as A, createActor as B, Actor as C, interpret as D, isMachineSnapshot as E, matchesState as F, pathToStateValue as G, toObserver as H, and as I, not as J, or as K, stateIn as L, cancel as M, NULL_EVENT as N, raise as O, stop as P, spawn as Q, ProcessingStatus as R, STATE_DELIMITER as S, createErrorActorEvent as T, XSTATE_ERROR as U, XSTATE_STOP as X, toTransitionConfigArray as a, formatTransition as b, createInvokeId as c, formatInitialTransition as d, evaluateGuard as e, formatTransitions as f, getDelayedTransitions as g, getCandidates as h, getAllStateNodes as i, getStateNodes as j, createMachineSnapshot as k, isInFinalState as l, mapValues as m, isErrorActorEvent as n, cloneMachineSnapshot as o, macrostep as p, transitionNode as q, resolveStateValue as r, resolveActionsAndContext as s, toArray as t, createInitEvent as u, microstep as v, getInitialStateNodes as w, isStateId as x, getStateNodeByPath as y, getPersistedState as z };