xstate 5.0.0-beta.43 → 5.0.0-beta.44

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 (46) 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 +6 -6
  8. package/actors/dist/xstate-actors.development.cjs.js +6 -6
  9. package/actors/dist/xstate-actors.development.esm.js +1 -1
  10. package/actors/dist/xstate-actors.esm.js +1 -1
  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 +3 -7
  14. package/dist/declarations/src/actions/spawn.d.ts +11 -16
  15. package/dist/declarations/src/guards.d.ts +2 -2
  16. package/dist/declarations/src/index.d.ts +1 -1
  17. package/dist/declarations/src/spawn.d.ts +9 -13
  18. package/dist/declarations/src/stateUtils.d.ts +4 -4
  19. package/dist/declarations/src/types.d.ts +15 -16
  20. package/dist/declarations/src/utils.d.ts +1 -3
  21. package/dist/{raise-e0fe5c2d.cjs.js → raise-348cc74e.development.esm.js} +946 -68
  22. package/dist/{raise-f4ad5a87.development.esm.js → raise-5854eaca.esm.js} +860 -49
  23. package/dist/{raise-23dea0d7.development.cjs.js → raise-ed700d14.development.cjs.js} +922 -36
  24. package/dist/{raise-8dc8e1aa.esm.js → raise-fb6f017b.cjs.js} +907 -2
  25. package/dist/{send-0174c155.development.cjs.js → send-00466e37.development.cjs.js} +11 -12
  26. package/dist/{send-87bbaaab.cjs.js → send-53e5693c.cjs.js} +11 -12
  27. package/dist/{send-5d129d95.development.esm.js → send-a0193bdb.development.esm.js} +2 -3
  28. package/dist/{send-84e2e742.esm.js → send-b7b4befa.esm.js} +2 -3
  29. package/dist/xstate.cjs.js +25 -25
  30. package/dist/xstate.cjs.mjs +1 -0
  31. package/dist/xstate.development.cjs.js +25 -25
  32. package/dist/xstate.development.cjs.mjs +1 -0
  33. package/dist/xstate.development.esm.js +4 -6
  34. package/dist/xstate.esm.js +4 -6
  35. package/dist/xstate.umd.min.js +1 -1
  36. package/dist/xstate.umd.min.js.map +1 -1
  37. package/guards/dist/xstate-guards.cjs.js +1 -2
  38. package/guards/dist/xstate-guards.development.cjs.js +1 -2
  39. package/guards/dist/xstate-guards.development.esm.js +1 -2
  40. package/guards/dist/xstate-guards.esm.js +1 -2
  41. package/guards/dist/xstate-guards.umd.min.js.map +1 -1
  42. package/package.json +1 -1
  43. package/dist/interpreter-36d5556e.cjs.js +0 -887
  44. package/dist/interpreter-4e8e2a0d.development.cjs.js +0 -898
  45. package/dist/interpreter-63c80754.esm.js +0 -857
  46. package/dist/interpreter-80eb3bec.development.esm.js +0 -868
@@ -1,4 +1,857 @@
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, X as XSTATE_STOP, q as XSTATE_INIT, W as WILDCARD, s as createAfterEvent, u as flatten, $ as $$ACTOR_TYPE, f as matchesState } from './interpreter-63c80754.esm.js';
1
+ 'use strict';
2
+
3
+ var dev_dist_xstateDev = require('../dev/dist/xstate-dev.cjs.js');
4
+
5
+ class Mailbox {
6
+ constructor(_process) {
7
+ this._process = _process;
8
+ this._active = false;
9
+ this._current = null;
10
+ this._last = null;
11
+ }
12
+ start() {
13
+ this._active = true;
14
+ this.flush();
15
+ }
16
+ clear() {
17
+ // we can't set _current to null because we might be currently processing
18
+ // and enqueue following clear shouldnt start processing the enqueued item immediately
19
+ if (this._current) {
20
+ this._current.next = null;
21
+ this._last = this._current;
22
+ }
23
+ }
24
+ enqueue(event) {
25
+ const enqueued = {
26
+ value: event,
27
+ next: null
28
+ };
29
+ if (this._current) {
30
+ this._last.next = enqueued;
31
+ this._last = enqueued;
32
+ return;
33
+ }
34
+ this._current = enqueued;
35
+ this._last = enqueued;
36
+ if (this._active) {
37
+ this.flush();
38
+ }
39
+ }
40
+ flush() {
41
+ while (this._current) {
42
+ // atm the given _process is responsible for implementing proper try/catch handling
43
+ // we assume here that this won't throw in a way that can affect this mailbox
44
+ const consumed = this._current;
45
+ this._process(consumed.value);
46
+ this._current = consumed.next;
47
+ }
48
+ this._last = null;
49
+ }
50
+ }
51
+
52
+ const STATE_DELIMITER = '.';
53
+ const TARGETLESS_KEY = '';
54
+ const NULL_EVENT = '';
55
+ const STATE_IDENTIFIER = '#';
56
+ const WILDCARD = '*';
57
+ const XSTATE_INIT = 'xstate.init';
58
+ const XSTATE_ERROR = 'xstate.error';
59
+ const XSTATE_STOP = 'xstate.stop';
60
+
61
+ /**
62
+ * Returns an event that represents an implicit event that
63
+ * is sent after the specified `delay`.
64
+ *
65
+ * @param delayRef The delay in milliseconds
66
+ * @param id The state node ID where this event is handled
67
+ */
68
+ function createAfterEvent(delayRef, id) {
69
+ const idSuffix = id ? `#${id}` : '';
70
+ return {
71
+ type: `xstate.after(${delayRef})${idSuffix}`
72
+ };
73
+ }
74
+
75
+ /**
76
+ * Returns an event that represents that a final state node
77
+ * has been reached in the parent state node.
78
+ *
79
+ * @param id The final state node's parent state node `id`
80
+ * @param output The data to pass into the event
81
+ */
82
+ function createDoneStateEvent(id, output) {
83
+ return {
84
+ type: `xstate.done.state.${id}`,
85
+ output
86
+ };
87
+ }
88
+
89
+ /**
90
+ * Returns an event that represents that an invoked service has terminated.
91
+ *
92
+ * An invoked service is terminated when it has reached a top-level final state node,
93
+ * but not when it is canceled.
94
+ *
95
+ * @param invokeId The invoked service ID
96
+ * @param output The data to pass into the event
97
+ */
98
+ function createDoneActorEvent(invokeId, output) {
99
+ return {
100
+ type: `xstate.done.actor.${invokeId}`,
101
+ output
102
+ };
103
+ }
104
+ function createErrorActorEvent(id, data) {
105
+ return {
106
+ type: `xstate.error.actor.${id}`,
107
+ data
108
+ };
109
+ }
110
+ function createInitEvent(input) {
111
+ return {
112
+ type: XSTATE_INIT,
113
+ input
114
+ };
115
+ }
116
+
117
+ /**
118
+ * This function makes sure that unhandled errors are thrown in a separate macrotask.
119
+ * It allows those errors to be detected by global error handlers and reported to bug tracking services
120
+ * without interrupting our own stack of execution.
121
+ *
122
+ * @param err error to be thrown
123
+ */
124
+ function reportUnhandledError(err) {
125
+ setTimeout(() => {
126
+ throw err;
127
+ });
128
+ }
129
+
130
+ const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
131
+
132
+ let idCounter = 0;
133
+ function createSystem(rootActor) {
134
+ const children = new Map();
135
+ const keyedActors = new Map();
136
+ const reverseKeyedActors = new WeakMap();
137
+ const observers = new Set();
138
+ const system = {
139
+ _bookId: () => `x:${idCounter++}`,
140
+ _register: (sessionId, actorRef) => {
141
+ children.set(sessionId, actorRef);
142
+ return sessionId;
143
+ },
144
+ _unregister: actorRef => {
145
+ children.delete(actorRef.sessionId);
146
+ const systemId = reverseKeyedActors.get(actorRef);
147
+ if (systemId !== undefined) {
148
+ keyedActors.delete(systemId);
149
+ reverseKeyedActors.delete(actorRef);
150
+ }
151
+ },
152
+ get: systemId => {
153
+ return keyedActors.get(systemId);
154
+ },
155
+ _set: (systemId, actorRef) => {
156
+ const existing = keyedActors.get(systemId);
157
+ if (existing && existing !== actorRef) {
158
+ throw new Error(`Actor with system ID '${systemId}' already exists.`);
159
+ }
160
+ keyedActors.set(systemId, actorRef);
161
+ reverseKeyedActors.set(actorRef, systemId);
162
+ },
163
+ inspect: observer => {
164
+ observers.add(observer);
165
+ },
166
+ _sendInspectionEvent: event => {
167
+ const resolvedInspectionEvent = {
168
+ ...event,
169
+ rootId: rootActor.sessionId
170
+ };
171
+ observers.forEach(observer => observer.next?.(resolvedInspectionEvent));
172
+ },
173
+ _relay: (source, target, event) => {
174
+ system._sendInspectionEvent({
175
+ type: '@xstate.event',
176
+ sourceRef: source,
177
+ actorRef: target,
178
+ event
179
+ });
180
+ target._send(event);
181
+ }
182
+ };
183
+ return system;
184
+ }
185
+
186
+ function matchesState(parentStateId, childStateId) {
187
+ const parentStateValue = toStateValue(parentStateId);
188
+ const childStateValue = toStateValue(childStateId);
189
+ if (typeof childStateValue === 'string') {
190
+ if (typeof parentStateValue === 'string') {
191
+ return childStateValue === parentStateValue;
192
+ }
193
+
194
+ // Parent more specific than child
195
+ return false;
196
+ }
197
+ if (typeof parentStateValue === 'string') {
198
+ return parentStateValue in childStateValue;
199
+ }
200
+ return Object.keys(parentStateValue).every(key => {
201
+ if (!(key in childStateValue)) {
202
+ return false;
203
+ }
204
+ return matchesState(parentStateValue[key], childStateValue[key]);
205
+ });
206
+ }
207
+ function toStatePath(stateId) {
208
+ try {
209
+ if (isArray(stateId)) {
210
+ return stateId;
211
+ }
212
+ return stateId.split(STATE_DELIMITER);
213
+ } catch (e) {
214
+ throw new Error(`'${stateId}' is not a valid state path.`);
215
+ }
216
+ }
217
+ function toStateValue(stateValue) {
218
+ if (isMachineSnapshot(stateValue)) {
219
+ return stateValue.value;
220
+ }
221
+ if (typeof stateValue !== 'string') {
222
+ return stateValue;
223
+ }
224
+ const statePath = toStatePath(stateValue);
225
+ return pathToStateValue(statePath);
226
+ }
227
+ function pathToStateValue(statePath) {
228
+ if (statePath.length === 1) {
229
+ return statePath[0];
230
+ }
231
+ const value = {};
232
+ let marker = value;
233
+ for (let i = 0; i < statePath.length - 1; i++) {
234
+ if (i === statePath.length - 2) {
235
+ marker[statePath[i]] = statePath[i + 1];
236
+ } else {
237
+ const previous = marker;
238
+ marker = {};
239
+ previous[statePath[i]] = marker;
240
+ }
241
+ }
242
+ return value;
243
+ }
244
+ function mapValues(collection, iteratee) {
245
+ const result = {};
246
+ const collectionKeys = Object.keys(collection);
247
+ for (let i = 0; i < collectionKeys.length; i++) {
248
+ const key = collectionKeys[i];
249
+ result[key] = iteratee(collection[key], key, collection, i);
250
+ }
251
+ return result;
252
+ }
253
+ function flatten(array) {
254
+ return [].concat(...array);
255
+ }
256
+ function toArrayStrict(value) {
257
+ if (isArray(value)) {
258
+ return value;
259
+ }
260
+ return [value];
261
+ }
262
+ function toArray(value) {
263
+ if (value === undefined) {
264
+ return [];
265
+ }
266
+ return toArrayStrict(value);
267
+ }
268
+ function resolveOutput(mapper, context, event, self) {
269
+ if (typeof mapper === 'function') {
270
+ return mapper({
271
+ context,
272
+ event,
273
+ self
274
+ });
275
+ }
276
+ return mapper;
277
+ }
278
+ function isArray(value) {
279
+ return Array.isArray(value);
280
+ }
281
+ function isErrorActorEvent(event) {
282
+ return event.type.startsWith('xstate.error.actor');
283
+ }
284
+ function toTransitionConfigArray(configLike) {
285
+ return toArrayStrict(configLike).map(transitionLike => {
286
+ if (typeof transitionLike === 'undefined' || typeof transitionLike === 'string') {
287
+ return {
288
+ target: transitionLike
289
+ };
290
+ }
291
+ return transitionLike;
292
+ });
293
+ }
294
+ function normalizeTarget(target) {
295
+ if (target === undefined || target === TARGETLESS_KEY) {
296
+ return undefined;
297
+ }
298
+ return toArray(target);
299
+ }
300
+ function toObserver(nextHandler, errorHandler, completionHandler) {
301
+ const isObserver = typeof nextHandler === 'object';
302
+ const self = isObserver ? nextHandler : undefined;
303
+ return {
304
+ next: (isObserver ? nextHandler.next : nextHandler)?.bind(self),
305
+ error: (isObserver ? nextHandler.error : errorHandler)?.bind(self),
306
+ complete: (isObserver ? nextHandler.complete : completionHandler)?.bind(self)
307
+ };
308
+ }
309
+ function createInvokeId(stateNodeId, index) {
310
+ return `${stateNodeId}[${index}]`;
311
+ }
312
+ function resolveReferencedActor(machine, src) {
313
+ if (src.startsWith('xstate#')) {
314
+ const [, indexStr] = src.match(/\[(\d+)\]$/);
315
+ const node = machine.getStateNodeById(src.slice(7, -(indexStr.length + 2)));
316
+ const invokeConfig = node.config.invoke;
317
+ return (Array.isArray(invokeConfig) ? invokeConfig[indexStr] : invokeConfig).src;
318
+ }
319
+ return machine.implementations.actors[src];
320
+ }
321
+
322
+ const $$ACTOR_TYPE = 1;
323
+ // those values are currently used by @xstate/react directly so it's important to keep the assigned values in sync
324
+ let ProcessingStatus = /*#__PURE__*/function (ProcessingStatus) {
325
+ ProcessingStatus[ProcessingStatus["NotStarted"] = 0] = "NotStarted";
326
+ ProcessingStatus[ProcessingStatus["Running"] = 1] = "Running";
327
+ ProcessingStatus[ProcessingStatus["Stopped"] = 2] = "Stopped";
328
+ return ProcessingStatus;
329
+ }({});
330
+ const defaultOptions = {
331
+ clock: {
332
+ setTimeout: (fn, ms) => {
333
+ return setTimeout(fn, ms);
334
+ },
335
+ clearTimeout: id => {
336
+ return clearTimeout(id);
337
+ }
338
+ },
339
+ logger: console.log.bind(console),
340
+ devTools: false
341
+ };
342
+
343
+ /**
344
+ * 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.
345
+ */
346
+ class Actor {
347
+ /**
348
+ * The current internal state of the actor.
349
+ */
350
+
351
+ /**
352
+ * The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions.
353
+ */
354
+
355
+ /**
356
+ * The unique identifier for this actor relative to its parent.
357
+ */
358
+
359
+ /** @internal */
360
+
361
+ // Actor Ref
362
+
363
+ // TODO: add typings for system
364
+
365
+ /**
366
+ * The globally unique process ID for this invocation.
367
+ */
368
+
369
+ /**
370
+ * The system to which this actor belongs.
371
+ */
372
+
373
+ /**
374
+ * Creates a new actor instance for the given logic with the provided options, if any.
375
+ *
376
+ * @param logic The logic to create an actor from
377
+ * @param options Actor options
378
+ */
379
+ constructor(logic, options) {
380
+ this.logic = logic;
381
+ this._state = void 0;
382
+ this.clock = void 0;
383
+ this.options = void 0;
384
+ this.id = void 0;
385
+ this.mailbox = new Mailbox(this._process.bind(this));
386
+ this.delayedEventsMap = {};
387
+ this.observers = new Set();
388
+ this.logger = void 0;
389
+ this._processingStatus = ProcessingStatus.NotStarted;
390
+ this._parent = void 0;
391
+ this.ref = void 0;
392
+ this._actorScope = void 0;
393
+ this._systemId = void 0;
394
+ this.sessionId = void 0;
395
+ this.system = void 0;
396
+ this._doneEvent = void 0;
397
+ this.src = void 0;
398
+ this._deferred = [];
399
+ const resolvedOptions = {
400
+ ...defaultOptions,
401
+ ...options
402
+ };
403
+ const {
404
+ clock,
405
+ logger,
406
+ parent,
407
+ id,
408
+ systemId,
409
+ inspect
410
+ } = resolvedOptions;
411
+ this.system = parent?.system ?? createSystem(this);
412
+ if (inspect && !parent) {
413
+ // Always inspect at the system-level
414
+ this.system.inspect(toObserver(inspect));
415
+ }
416
+ this.sessionId = this.system._bookId();
417
+ this.id = id ?? this.sessionId;
418
+ this.logger = logger;
419
+ this.clock = clock;
420
+ this._parent = parent;
421
+ this.options = resolvedOptions;
422
+ this.src = resolvedOptions.src ?? logic;
423
+ this.ref = this;
424
+ this._actorScope = {
425
+ self: this,
426
+ id: this.id,
427
+ sessionId: this.sessionId,
428
+ logger: this.logger,
429
+ defer: fn => {
430
+ this._deferred.push(fn);
431
+ },
432
+ system: this.system,
433
+ stopChild: child => {
434
+ if (child._parent !== this) {
435
+ throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`);
436
+ }
437
+ child._stop();
438
+ }
439
+ };
440
+
441
+ // Ensure that the send method is bound to this Actor instance
442
+ // if destructured
443
+ this.send = this.send.bind(this);
444
+ this.system._sendInspectionEvent({
445
+ type: '@xstate.actor',
446
+ actorRef: this
447
+ });
448
+ if (systemId) {
449
+ this._systemId = systemId;
450
+ this.system._set(systemId, this);
451
+ }
452
+ this._initState(options?.state);
453
+ if (systemId && this._state.status !== 'active') {
454
+ this.system._unregister(this);
455
+ }
456
+ }
457
+ _initState(persistedState) {
458
+ this._state = persistedState ? this.logic.restoreState ? this.logic.restoreState(persistedState, this._actorScope) : persistedState : this.logic.getInitialState(this._actorScope, this.options?.input);
459
+ }
460
+
461
+ // array of functions to defer
462
+
463
+ update(snapshot, event) {
464
+ // Update state
465
+ this._state = snapshot;
466
+
467
+ // Execute deferred effects
468
+ let deferredFn;
469
+ while (deferredFn = this._deferred.shift()) {
470
+ deferredFn();
471
+ }
472
+ for (const observer of this.observers) {
473
+ try {
474
+ observer.next?.(snapshot);
475
+ } catch (err) {
476
+ reportUnhandledError(err);
477
+ }
478
+ }
479
+ switch (this._state.status) {
480
+ case 'done':
481
+ this._stopProcedure();
482
+ this._complete();
483
+ this._doneEvent = createDoneActorEvent(this.id, this._state.output);
484
+ if (this._parent) {
485
+ this.system._relay(this, this._parent, this._doneEvent);
486
+ }
487
+ break;
488
+ case 'error':
489
+ this._stopProcedure();
490
+ this._error(this._state.error);
491
+ if (this._parent) {
492
+ this.system._relay(this, this._parent, createErrorActorEvent(this.id, this._state.error));
493
+ }
494
+ break;
495
+ }
496
+ this.system._sendInspectionEvent({
497
+ type: '@xstate.snapshot',
498
+ actorRef: this,
499
+ event,
500
+ snapshot
501
+ });
502
+ }
503
+
504
+ /**
505
+ * Subscribe an observer to an actor’s snapshot values.
506
+ *
507
+ * @remarks
508
+ * The observer will receive the actor’s snapshot value when it is emitted. The observer can be:
509
+ * - A plain function that receives the latest snapshot, or
510
+ * - An observer object whose `.next(snapshot)` method receives the latest snapshot
511
+ *
512
+ * @example
513
+ * ```ts
514
+ * // Observer as a plain function
515
+ * const subscription = actor.subscribe((snapshot) => {
516
+ * console.log(snapshot);
517
+ * });
518
+ * ```
519
+ *
520
+ * @example
521
+ * ```ts
522
+ * // Observer as an object
523
+ * const subscription = actor.subscribe({
524
+ * next(snapshot) {
525
+ * console.log(snapshot);
526
+ * },
527
+ * error(err) {
528
+ * // ...
529
+ * },
530
+ * complete() {
531
+ * // ...
532
+ * },
533
+ * });
534
+ * ```
535
+ *
536
+ * 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:
537
+ *
538
+ * @example
539
+ * ```ts
540
+ * const subscription = actor.subscribe((snapshot) => {
541
+ * // ...
542
+ * });
543
+ *
544
+ * // Unsubscribe the observer
545
+ * subscription.unsubscribe();
546
+ * ```
547
+ *
548
+ * When the actor is stopped, all of its observers will automatically be unsubscribed.
549
+ *
550
+ * @param observer - Either a plain function that receives the latest snapshot, or an observer object whose `.next(snapshot)` method receives the latest snapshot
551
+ */
552
+
553
+ subscribe(nextListenerOrObserver, errorListener, completeListener) {
554
+ const observer = toObserver(nextListenerOrObserver, errorListener, completeListener);
555
+ if (this._processingStatus !== ProcessingStatus.Stopped) {
556
+ this.observers.add(observer);
557
+ } else {
558
+ try {
559
+ observer.complete?.();
560
+ } catch (err) {
561
+ reportUnhandledError(err);
562
+ }
563
+ }
564
+ return {
565
+ unsubscribe: () => {
566
+ this.observers.delete(observer);
567
+ }
568
+ };
569
+ }
570
+
571
+ /**
572
+ * Starts the Actor from the initial state
573
+ */
574
+ start() {
575
+ if (this._processingStatus === ProcessingStatus.Running) {
576
+ // Do not restart the service if it is already started
577
+ return this;
578
+ }
579
+ this.system._register(this.sessionId, this);
580
+ if (this._systemId) {
581
+ this.system._set(this._systemId, this);
582
+ }
583
+ this._processingStatus = ProcessingStatus.Running;
584
+
585
+ // TODO: this isn't correct when rehydrating
586
+ const initEvent = createInitEvent(this.options.input);
587
+ this.system._sendInspectionEvent({
588
+ type: '@xstate.event',
589
+ sourceRef: this._parent,
590
+ actorRef: this,
591
+ event: initEvent
592
+ });
593
+ const status = this._state.status;
594
+ switch (status) {
595
+ case 'done':
596
+ // a state machine can be "done" upon initialization (it could reach a final state using initial microsteps)
597
+ // we still need to complete observers, flush deferreds etc
598
+ this.update(this._state, initEvent);
599
+ // fallthrough
600
+ case 'error':
601
+ // TODO: rethink cleanup of observers, mailbox, etc
602
+ return this;
603
+ }
604
+ if (this.logic.start) {
605
+ try {
606
+ this.logic.start(this._state, this._actorScope);
607
+ } catch (err) {
608
+ this._stopProcedure();
609
+ this._error(err);
610
+ this._parent?.send(createErrorActorEvent(this.id, err));
611
+ return this;
612
+ }
613
+ }
614
+
615
+ // TODO: this notifies all subscribers but usually this is redundant
616
+ // there is no real change happening here
617
+ // we need to rethink if this needs to be refactored
618
+ this.update(this._state, initEvent);
619
+ if (this.options.devTools) {
620
+ this.attachDevTools();
621
+ }
622
+ this.mailbox.start();
623
+ return this;
624
+ }
625
+ _process(event) {
626
+ // TODO: reexamine what happens when an action (or a guard or smth) throws
627
+ let nextState;
628
+ let caughtError;
629
+ try {
630
+ nextState = this.logic.transition(this._state, event, this._actorScope);
631
+ } catch (err) {
632
+ // we wrap it in a box so we can rethrow it later even if falsy value gets caught here
633
+ caughtError = {
634
+ err
635
+ };
636
+ }
637
+ if (caughtError) {
638
+ const {
639
+ err
640
+ } = caughtError;
641
+ this._stopProcedure();
642
+ this._error(err);
643
+ this._parent?.send(createErrorActorEvent(this.id, err));
644
+ return;
645
+ }
646
+ this.update(nextState, event);
647
+ if (event.type === XSTATE_STOP) {
648
+ this._stopProcedure();
649
+ this._complete();
650
+ }
651
+ }
652
+ _stop() {
653
+ if (this._processingStatus === ProcessingStatus.Stopped) {
654
+ return this;
655
+ }
656
+ this.mailbox.clear();
657
+ if (this._processingStatus === ProcessingStatus.NotStarted) {
658
+ this._processingStatus = ProcessingStatus.Stopped;
659
+ return this;
660
+ }
661
+ this.mailbox.enqueue({
662
+ type: XSTATE_STOP
663
+ });
664
+ return this;
665
+ }
666
+
667
+ /**
668
+ * Stops the Actor and unsubscribe all listeners.
669
+ */
670
+ stop() {
671
+ if (this._parent) {
672
+ throw new Error('A non-root actor cannot be stopped directly.');
673
+ }
674
+ return this._stop();
675
+ }
676
+ _complete() {
677
+ for (const observer of this.observers) {
678
+ try {
679
+ observer.complete?.();
680
+ } catch (err) {
681
+ reportUnhandledError(err);
682
+ }
683
+ }
684
+ this.observers.clear();
685
+ }
686
+ _error(err) {
687
+ if (!this.observers.size) {
688
+ if (!this._parent) {
689
+ reportUnhandledError(err);
690
+ }
691
+ return;
692
+ }
693
+ let reportError = false;
694
+ for (const observer of this.observers) {
695
+ const errorListener = observer.error;
696
+ reportError ||= !errorListener;
697
+ try {
698
+ errorListener?.(err);
699
+ } catch (err2) {
700
+ reportUnhandledError(err2);
701
+ }
702
+ }
703
+ this.observers.clear();
704
+ if (reportError) {
705
+ reportUnhandledError(err);
706
+ }
707
+ }
708
+ _stopProcedure() {
709
+ if (this._processingStatus !== ProcessingStatus.Running) {
710
+ // Actor already stopped; do nothing
711
+ return this;
712
+ }
713
+
714
+ // Cancel all delayed events
715
+ for (const key of Object.keys(this.delayedEventsMap)) {
716
+ this.clock.clearTimeout(this.delayedEventsMap[key]);
717
+ }
718
+
719
+ // TODO: mailbox.reset
720
+ this.mailbox.clear();
721
+ // TODO: after `stop` we must prepare ourselves for receiving events again
722
+ // events sent *after* stop signal must be queued
723
+ // it seems like this should be the common behavior for all of our consumers
724
+ // so perhaps this should be unified somehow for all of them
725
+ this.mailbox = new Mailbox(this._process.bind(this));
726
+ this._processingStatus = ProcessingStatus.Stopped;
727
+ this.system._unregister(this);
728
+ return this;
729
+ }
730
+
731
+ /**
732
+ * @internal
733
+ */
734
+ _send(event) {
735
+ if (this._processingStatus === ProcessingStatus.Stopped) {
736
+ return;
737
+ }
738
+ this.mailbox.enqueue(event);
739
+ }
740
+
741
+ /**
742
+ * Sends an event to the running Actor to trigger a transition.
743
+ *
744
+ * @param event The event to send
745
+ */
746
+ send(event) {
747
+ this.system._relay(undefined, this, event);
748
+ }
749
+
750
+ /**
751
+ * TODO: figure out a way to do this within the machine
752
+ * @internal
753
+ */
754
+ delaySend(params) {
755
+ const {
756
+ event,
757
+ id,
758
+ delay
759
+ } = params;
760
+ const timerId = this.clock.setTimeout(() => {
761
+ this.system._relay(this, params.to ?? this, event);
762
+ }, delay);
763
+
764
+ // TODO: consider the rehydration story here
765
+ if (id) {
766
+ this.delayedEventsMap[id] = timerId;
767
+ }
768
+ }
769
+
770
+ /**
771
+ * TODO: figure out a way to do this within the machine
772
+ * @internal
773
+ */
774
+ cancel(sendId) {
775
+ this.clock.clearTimeout(this.delayedEventsMap[sendId]);
776
+ delete this.delayedEventsMap[sendId];
777
+ }
778
+ attachDevTools() {
779
+ const {
780
+ devTools
781
+ } = this.options;
782
+ if (devTools) {
783
+ const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : dev_dist_xstateDev.devToolsAdapter;
784
+ resolvedDevToolsAdapter(this);
785
+ }
786
+ }
787
+ toJSON() {
788
+ return {
789
+ xstate$$type: $$ACTOR_TYPE,
790
+ id: this.id
791
+ };
792
+ }
793
+
794
+ /**
795
+ * Obtain the internal state of the actor, which can be persisted.
796
+ *
797
+ * @remarks
798
+ * The internal state can be persisted from any actor, not only machines.
799
+ *
800
+ * 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.
801
+ *
802
+ * Can be restored with {@link ActorOptions.state}
803
+ *
804
+ * @see https://stately.ai/docs/persistence
805
+ */
806
+
807
+ getPersistedState(options) {
808
+ return this.logic.getPersistedState(this._state, options);
809
+ }
810
+ [symbolObservable]() {
811
+ return this;
812
+ }
813
+
814
+ /**
815
+ * Read an actor’s snapshot synchronously.
816
+ *
817
+ * @remarks
818
+ * The snapshot represent an actor's last emitted value.
819
+ *
820
+ * When an actor receives an event, its internal state may change.
821
+ * An actor may emit a snapshot when a state transition occurs.
822
+ *
823
+ * Note that some actors, such as callback actors generated with `fromCallback`, will not emit snapshots.
824
+ *
825
+ * @see {@link Actor.subscribe} to subscribe to an actor’s snapshot values.
826
+ * @see {@link Actor.getPersistedState} to persist the internal state of an actor (which is more than just a snapshot).
827
+ */
828
+ getSnapshot() {
829
+ return this._state;
830
+ }
831
+ }
832
+
833
+ /**
834
+ * Creates a new `ActorRef` instance for the given machine with the provided options, if any.
835
+ *
836
+ * @param machine The machine to create an actor from
837
+ * @param options `ActorRef` options
838
+ */
839
+
840
+ function createActor(logic, options) {
841
+ const interpreter = new Actor(logic, options);
842
+ return interpreter;
843
+ }
844
+
845
+ /**
846
+ * Creates a new Interpreter instance for the given machine with the provided options, if any.
847
+ *
848
+ * @deprecated Use `createActor` instead
849
+ */
850
+ const interpret = createActor;
851
+
852
+ /**
853
+ * @deprecated Use `Actor` instead.
854
+ */
2
855
 
3
856
  const cache = new WeakMap();
4
857
  function memo(object, key, fn) {
@@ -1216,6 +2069,9 @@ function resolveStateValue(rootNode, stateValue) {
1216
2069
  return getStateValue(rootNode, [...configuration]);
1217
2070
  }
1218
2071
 
2072
+ function isMachineSnapshot(value) {
2073
+ return !!value && typeof value === 'object' && 'machine' in value && 'value' in value;
2074
+ }
1219
2075
  const machineSnapshotMatches = function matches(testValue) {
1220
2076
  return matchesState(testValue, this.value);
1221
2077
  };
@@ -1407,4 +2263,53 @@ function raise(eventOrExpr, options) {
1407
2263
  return raise;
1408
2264
  }
1409
2265
 
1410
- 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 };
2266
+ exports.$$ACTOR_TYPE = $$ACTOR_TYPE;
2267
+ exports.Actor = Actor;
2268
+ exports.NULL_EVENT = NULL_EVENT;
2269
+ exports.ProcessingStatus = ProcessingStatus;
2270
+ exports.STATE_DELIMITER = STATE_DELIMITER;
2271
+ exports.XSTATE_ERROR = XSTATE_ERROR;
2272
+ exports.XSTATE_STOP = XSTATE_STOP;
2273
+ exports.and = and;
2274
+ exports.cancel = cancel;
2275
+ exports.cloneMachineSnapshot = cloneMachineSnapshot;
2276
+ exports.createActor = createActor;
2277
+ exports.createErrorActorEvent = createErrorActorEvent;
2278
+ exports.createInitEvent = createInitEvent;
2279
+ exports.createInvokeId = createInvokeId;
2280
+ exports.createMachineSnapshot = createMachineSnapshot;
2281
+ exports.evaluateGuard = evaluateGuard;
2282
+ exports.formatInitialTransition = formatInitialTransition;
2283
+ exports.formatTransition = formatTransition;
2284
+ exports.formatTransitions = formatTransitions;
2285
+ exports.getCandidates = getCandidates;
2286
+ exports.getConfiguration = getConfiguration;
2287
+ exports.getDelayedTransitions = getDelayedTransitions;
2288
+ exports.getInitialStateNodes = getInitialStateNodes;
2289
+ exports.getPersistedState = getPersistedState;
2290
+ exports.getStateNodeByPath = getStateNodeByPath;
2291
+ exports.getStateNodes = getStateNodes;
2292
+ exports.interpret = interpret;
2293
+ exports.isErrorActorEvent = isErrorActorEvent;
2294
+ exports.isInFinalState = isInFinalState;
2295
+ exports.isMachineSnapshot = isMachineSnapshot;
2296
+ exports.isStateId = isStateId;
2297
+ exports.macrostep = macrostep;
2298
+ exports.mapValues = mapValues;
2299
+ exports.matchesState = matchesState;
2300
+ exports.memo = memo;
2301
+ exports.microstep = microstep;
2302
+ exports.not = not;
2303
+ exports.or = or;
2304
+ exports.pathToStateValue = pathToStateValue;
2305
+ exports.raise = raise;
2306
+ exports.resolveActionsAndContext = resolveActionsAndContext;
2307
+ exports.resolveReferencedActor = resolveReferencedActor;
2308
+ exports.resolveStateValue = resolveStateValue;
2309
+ exports.spawn = spawn;
2310
+ exports.stateIn = stateIn;
2311
+ exports.stop = stop;
2312
+ exports.toArray = toArray;
2313
+ exports.toObserver = toObserver;
2314
+ exports.toTransitionConfigArray = toTransitionConfigArray;
2315
+ exports.transitionNode = transitionNode;