UNPKG

26.3 kBJavaScriptView Raw
1export { createEmptyActor, fromCallback, fromEventObservable, fromObservable, fromPromise, fromTransition } from '../actors/dist/xstate-actors.esm.js';
2import { S as STATE_DELIMITER, m as mapValues, t as toArray, f as formatTransitions, a as toTransitionConfigArray, b as formatTransition, N as NULL_EVENT, e as evaluateGuard, c as createInvokeId, g as getDelayedTransitions, d as formatInitialTransition, h as getCandidates, r as resolveStateValue, i as getAllStateNodes, j as getStateNodes, k as createMachineSnapshot, l as isInFinalState, n as macrostep, o as transitionNode, p as resolveActionsAndContext, q as createInitEvent, s as microstep, u as getInitialStateNodes, v as toStatePath, w as isStateId, x as getStateNodeByPath, y as getPersistedSnapshot, z as resolveReferencedActor, A as createActor, $ as $$ACTOR_TYPE } from './raise-040ba012.esm.js';
3export { B as Actor, I as __unsafe_getAllOwnEventDescriptors, E as and, M as cancel, A as createActor, j as getStateNodes, C as interpret, D as isMachineSnapshot, J as matchesState, F as not, G as or, K as pathToStateValue, O as raise, P as spawnChild, H as stateIn, Q as stop, R as stopChild, L as toObserver } from './raise-040ba012.esm.js';
4import { a as assign } from './log-cd22d72c.esm.js';
5export { S as SpecialTargets, a as assign, e as emit, b as enqueueActions, f as forwardTo, l as log, s as sendParent, c as sendTo } from './log-cd22d72c.esm.js';
6import '../dev/dist/xstate-dev.esm.js';
7
8class SimulatedClock {
9 constructor() {
10 this.timeouts = new Map();
11 this._now = 0;
12 this._id = 0;
13 this._flushing = false;
14 this._flushingInvalidated = false;
15 }
16 now() {
17 return this._now;
18 }
19 getId() {
20 return this._id++;
21 }
22 setTimeout(fn, timeout) {
23 this._flushingInvalidated = this._flushing;
24 const id = this.getId();
25 this.timeouts.set(id, {
26 start: this.now(),
27 timeout,
28 fn
29 });
30 return id;
31 }
32 clearTimeout(id) {
33 this._flushingInvalidated = this._flushing;
34 this.timeouts.delete(id);
35 }
36 set(time) {
37 if (this._now > time) {
38 throw new Error('Unable to travel back in time');
39 }
40 this._now = time;
41 this.flushTimeouts();
42 }
43 flushTimeouts() {
44 if (this._flushing) {
45 this._flushingInvalidated = true;
46 return;
47 }
48 this._flushing = true;
49 const sorted = [...this.timeouts].sort(([_idA, timeoutA], [_idB, timeoutB]) => {
50 const endA = timeoutA.start + timeoutA.timeout;
51 const endB = timeoutB.start + timeoutB.timeout;
52 return endB > endA ? -1 : 1;
53 });
54 for (const [id, timeout] of sorted) {
55 if (this._flushingInvalidated) {
56 this._flushingInvalidated = false;
57 this._flushing = false;
58 this.flushTimeouts();
59 return;
60 }
61 if (this.now() - timeout.start >= timeout.timeout) {
62 this.timeouts.delete(id);
63 timeout.fn.call(null);
64 }
65 }
66 this._flushing = false;
67 }
68 increment(ms) {
69 this._now += ms;
70 this.flushTimeouts();
71 }
72}
73
74const cache = new WeakMap();
75function memo(object, key, fn) {
76 let memoizedData = cache.get(object);
77 if (!memoizedData) {
78 memoizedData = {
79 [key]: fn()
80 };
81 cache.set(object, memoizedData);
82 } else if (!(key in memoizedData)) {
83 memoizedData[key] = fn();
84 }
85 return memoizedData[key];
86}
87
88const EMPTY_OBJECT = {};
89const toSerializableAction = action => {
90 if (typeof action === 'string') {
91 return {
92 type: action
93 };
94 }
95 if (typeof action === 'function') {
96 if ('resolve' in action) {
97 return {
98 type: action.type
99 };
100 }
101 return {
102 type: action.name
103 };
104 }
105 return action;
106};
107class StateNode {
108 constructor(
109 /**
110 * The raw config used to create the machine.
111 */
112 config, options) {
113 this.config = config;
114 /**
115 * The relative key of the state node, which represents its location in the overall state value.
116 */
117 this.key = void 0;
118 /**
119 * The unique ID of the state node.
120 */
121 this.id = void 0;
122 /**
123 * The type of this state node:
124 *
125 * - `'atomic'` - no child state nodes
126 * - `'compound'` - nested child state nodes (XOR)
127 * - `'parallel'` - orthogonal nested child state nodes (AND)
128 * - `'history'` - history state node
129 * - `'final'` - final state node
130 */
131 this.type = void 0;
132 /**
133 * The string path from the root machine node to this node.
134 */
135 this.path = void 0;
136 /**
137 * The child state nodes.
138 */
139 this.states = void 0;
140 /**
141 * The type of history on this state node. Can be:
142 *
143 * - `'shallow'` - recalls only top-level historical state value
144 * - `'deep'` - recalls historical state value at all levels
145 */
146 this.history = void 0;
147 /**
148 * The action(s) to be executed upon entering the state node.
149 */
150 this.entry = void 0;
151 /**
152 * The action(s) to be executed upon exiting the state node.
153 */
154 this.exit = void 0;
155 /**
156 * The parent state node.
157 */
158 this.parent = void 0;
159 /**
160 * The root machine node.
161 */
162 this.machine = void 0;
163 /**
164 * The meta data associated with this state node, which will be returned in State instances.
165 */
166 this.meta = void 0;
167 /**
168 * The output data sent with the "xstate.done.state._id_" event if this is a final state node.
169 */
170 this.output = void 0;
171 /**
172 * The order this state node appears. Corresponds to the implicit document order.
173 */
174 this.order = -1;
175 this.description = void 0;
176 this.tags = [];
177 this.transitions = void 0;
178 this.always = void 0;
179 this.parent = options._parent;
180 this.key = options._key;
181 this.machine = options._machine;
182 this.path = this.parent ? this.parent.path.concat(this.key) : [];
183 this.id = this.config.id || [this.machine.id, ...this.path].join(STATE_DELIMITER);
184 this.type = this.config.type || (this.config.states && Object.keys(this.config.states).length ? 'compound' : this.config.history ? 'history' : 'atomic');
185 this.description = this.config.description;
186 this.order = this.machine.idMap.size;
187 this.machine.idMap.set(this.id, this);
188 this.states = this.config.states ? mapValues(this.config.states, (stateConfig, key) => {
189 const stateNode = new StateNode(stateConfig, {
190 _parent: this,
191 _key: key,
192 _machine: this.machine
193 });
194 return stateNode;
195 }) : EMPTY_OBJECT;
196 if (this.type === 'compound' && !this.config.initial) {
197 throw new Error(`No initial state specified for compound state node "#${this.id}". Try adding { initial: "${Object.keys(this.states)[0]}" } to the state config.`);
198 }
199
200 // History config
201 this.history = this.config.history === true ? 'shallow' : this.config.history || false;
202 this.entry = toArray(this.config.entry).slice();
203 this.exit = toArray(this.config.exit).slice();
204 this.meta = this.config.meta;
205 this.output = this.type === 'final' || !this.parent ? this.config.output : undefined;
206 this.tags = toArray(config.tags).slice();
207 }
208
209 /** @internal */
210 _initialize() {
211 this.transitions = formatTransitions(this);
212 if (this.config.always) {
213 this.always = toTransitionConfigArray(this.config.always).map(t => formatTransition(this, NULL_EVENT, t));
214 }
215 Object.keys(this.states).forEach(key => {
216 this.states[key]._initialize();
217 });
218 }
219
220 /**
221 * The well-structured state node definition.
222 */
223 get definition() {
224 return {
225 id: this.id,
226 key: this.key,
227 version: this.machine.version,
228 type: this.type,
229 initial: this.initial ? {
230 target: this.initial.target,
231 source: this,
232 actions: this.initial.actions.map(toSerializableAction),
233 eventType: null,
234 reenter: false,
235 toJSON: () => ({
236 target: this.initial.target.map(t => `#${t.id}`),
237 source: `#${this.id}`,
238 actions: this.initial.actions.map(toSerializableAction),
239 eventType: null
240 })
241 } : undefined,
242 history: this.history,
243 states: mapValues(this.states, state => {
244 return state.definition;
245 }),
246 on: this.on,
247 transitions: [...this.transitions.values()].flat().map(t => ({
248 ...t,
249 actions: t.actions.map(toSerializableAction)
250 })),
251 entry: this.entry.map(toSerializableAction),
252 exit: this.exit.map(toSerializableAction),
253 meta: this.meta,
254 order: this.order || -1,
255 output: this.output,
256 invoke: this.invoke,
257 description: this.description,
258 tags: this.tags
259 };
260 }
261
262 /** @internal */
263 toJSON() {
264 return this.definition;
265 }
266
267 /**
268 * The logic invoked as actors by this state node.
269 */
270 get invoke() {
271 return memo(this, 'invoke', () => toArray(this.config.invoke).map((invokeConfig, i) => {
272 const {
273 src,
274 systemId
275 } = invokeConfig;
276 const resolvedId = invokeConfig.id ?? createInvokeId(this.id, i);
277 const resolvedSrc = typeof src === 'string' ? src : `xstate.invoke.${createInvokeId(this.id, i)}`;
278 return {
279 ...invokeConfig,
280 src: resolvedSrc,
281 id: resolvedId,
282 systemId: systemId,
283 toJSON() {
284 const {
285 onDone,
286 onError,
287 ...invokeDefValues
288 } = invokeConfig;
289 return {
290 ...invokeDefValues,
291 type: 'xstate.invoke',
292 src: resolvedSrc,
293 id: resolvedId
294 };
295 }
296 };
297 }));
298 }
299
300 /**
301 * The mapping of events to transitions.
302 */
303 get on() {
304 return memo(this, 'on', () => {
305 const transitions = this.transitions;
306 return [...transitions].flatMap(([descriptor, t]) => t.map(t => [descriptor, t])).reduce((map, [descriptor, transition]) => {
307 map[descriptor] = map[descriptor] || [];
308 map[descriptor].push(transition);
309 return map;
310 }, {});
311 });
312 }
313 get after() {
314 return memo(this, 'delayedTransitions', () => getDelayedTransitions(this));
315 }
316 get initial() {
317 return memo(this, 'initial', () => formatInitialTransition(this, this.config.initial));
318 }
319
320 /** @internal */
321 next(snapshot, event) {
322 const eventType = event.type;
323 const actions = [];
324 let selectedTransition;
325 const candidates = memo(this, `candidates-${eventType}`, () => getCandidates(this, eventType));
326 for (const candidate of candidates) {
327 const {
328 guard
329 } = candidate;
330 const resolvedContext = snapshot.context;
331 let guardPassed = false;
332 try {
333 guardPassed = !guard || evaluateGuard(guard, resolvedContext, event, snapshot);
334 } catch (err) {
335 const guardType = typeof guard === 'string' ? guard : typeof guard === 'object' ? guard.type : undefined;
336 throw new Error(`Unable to evaluate guard ${guardType ? `'${guardType}' ` : ''}in transition for event '${eventType}' in state node '${this.id}':\n${err.message}`);
337 }
338 if (guardPassed) {
339 actions.push(...candidate.actions);
340 selectedTransition = candidate;
341 break;
342 }
343 }
344 return selectedTransition ? [selectedTransition] : undefined;
345 }
346
347 /**
348 * All the event types accepted by this state node and its descendants.
349 */
350 get events() {
351 return memo(this, 'events', () => {
352 const {
353 states
354 } = this;
355 const events = new Set(this.ownEvents);
356 if (states) {
357 for (const stateId of Object.keys(states)) {
358 const state = states[stateId];
359 if (state.states) {
360 for (const event of state.events) {
361 events.add(`${event}`);
362 }
363 }
364 }
365 }
366 return Array.from(events);
367 });
368 }
369
370 /**
371 * All the events that have transitions directly from this state node.
372 *
373 * Excludes any inert events.
374 */
375 get ownEvents() {
376 const events = new Set([...this.transitions.keys()].filter(descriptor => {
377 return this.transitions.get(descriptor).some(transition => !(!transition.target && !transition.actions.length && !transition.reenter));
378 }));
379 return Array.from(events);
380 }
381}
382
383const STATE_IDENTIFIER = '#';
384class StateMachine {
385 constructor(
386 /**
387 * The raw config used to create the machine.
388 */
389 config, implementations) {
390 this.config = config;
391 /**
392 * The machine's own version.
393 */
394 this.version = void 0;
395 this.schemas = void 0;
396 this.implementations = void 0;
397 /** @internal */
398 this.__xstatenode = true;
399 /** @internal */
400 this.idMap = new Map();
401 this.root = void 0;
402 this.id = void 0;
403 this.states = void 0;
404 this.events = void 0;
405 /**
406 * @deprecated an internal property that was acting as a "phantom" type, it's not used by anything right now but it's kept around for compatibility reasons
407 **/
408 this.__TResolvedTypesMeta = void 0;
409 this.id = config.id || '(machine)';
410 this.implementations = {
411 actors: implementations?.actors ?? {},
412 actions: implementations?.actions ?? {},
413 delays: implementations?.delays ?? {},
414 guards: implementations?.guards ?? {}
415 };
416 this.version = this.config.version;
417 this.schemas = this.config.schemas;
418 this.transition = this.transition.bind(this);
419 this.getInitialSnapshot = this.getInitialSnapshot.bind(this);
420 this.getPersistedSnapshot = this.getPersistedSnapshot.bind(this);
421 this.restoreSnapshot = this.restoreSnapshot.bind(this);
422 this.start = this.start.bind(this);
423 this.root = new StateNode(config, {
424 _key: this.id,
425 _machine: this
426 });
427 this.root._initialize();
428 this.states = this.root.states; // TODO: remove!
429 this.events = this.root.events;
430 }
431
432 /**
433 * Clones this state machine with the provided implementations
434 * and merges the `context` (if provided).
435 *
436 * @param implementations Options (`actions`, `guards`, `actors`, `delays`, `context`)
437 * to recursively merge with the existing options.
438 *
439 * @returns A new `StateMachine` instance with the provided implementations.
440 */
441 provide(implementations) {
442 const {
443 actions,
444 guards,
445 actors,
446 delays
447 } = this.implementations;
448 return new StateMachine(this.config, {
449 actions: {
450 ...actions,
451 ...implementations.actions
452 },
453 guards: {
454 ...guards,
455 ...implementations.guards
456 },
457 actors: {
458 ...actors,
459 ...implementations.actors
460 },
461 delays: {
462 ...delays,
463 ...implementations.delays
464 }
465 });
466 }
467 resolveState(config) {
468 const resolvedStateValue = resolveStateValue(this.root, config.value);
469 const nodeSet = getAllStateNodes(getStateNodes(this.root, resolvedStateValue));
470 return createMachineSnapshot({
471 _nodes: [...nodeSet],
472 context: config.context || {},
473 children: {},
474 status: isInFinalState(nodeSet, this.root) ? 'done' : config.status || 'active',
475 output: config.output,
476 error: config.error,
477 historyValue: config.historyValue
478 }, this);
479 }
480
481 /**
482 * Determines the next snapshot given the current `snapshot` and received `event`.
483 * Calculates a full macrostep from all microsteps.
484 *
485 * @param snapshot The current snapshot
486 * @param event The received event
487 */
488 transition(snapshot, event, actorScope) {
489 return macrostep(snapshot, event, actorScope).snapshot;
490 }
491
492 /**
493 * Determines the next state given the current `state` and `event`.
494 * Calculates a microstep.
495 *
496 * @param state The current state
497 * @param event The received event
498 */
499 microstep(snapshot, event, actorScope) {
500 return macrostep(snapshot, event, actorScope).microstates;
501 }
502 getTransitionData(snapshot, event) {
503 return transitionNode(this.root, snapshot.value, snapshot, event) || [];
504 }
505
506 /**
507 * The initial state _before_ evaluating any microsteps.
508 * This "pre-initial" state is provided to initial actions executed in the initial state.
509 */
510 getPreInitialState(actorScope, initEvent, internalQueue) {
511 const {
512 context
513 } = this.config;
514 const preInitial = createMachineSnapshot({
515 context: typeof context !== 'function' && context ? context : {},
516 _nodes: [this.root],
517 children: {},
518 status: 'active'
519 }, this);
520 if (typeof context === 'function') {
521 const assignment = ({
522 spawn,
523 event,
524 self
525 }) => context({
526 spawn,
527 input: event.input,
528 self
529 });
530 return resolveActionsAndContext(preInitial, initEvent, actorScope, [assign(assignment)], internalQueue);
531 }
532 return preInitial;
533 }
534
535 /**
536 * Returns the initial `State` instance, with reference to `self` as an `ActorRef`.
537 */
538 getInitialSnapshot(actorScope, input) {
539 const initEvent = createInitEvent(input); // TODO: fix;
540 const internalQueue = [];
541 const preInitialState = this.getPreInitialState(actorScope, initEvent, internalQueue);
542 const nextState = microstep([{
543 target: [...getInitialStateNodes(this.root)],
544 source: this.root,
545 reenter: true,
546 actions: [],
547 eventType: null,
548 toJSON: null // TODO: fix
549 }], preInitialState, actorScope, initEvent, true, internalQueue);
550 const {
551 snapshot: macroState
552 } = macrostep(nextState, initEvent, actorScope, internalQueue);
553 return macroState;
554 }
555 start(snapshot) {
556 Object.values(snapshot.children).forEach(child => {
557 if (child.getSnapshot().status === 'active') {
558 child.start();
559 }
560 });
561 }
562 getStateNodeById(stateId) {
563 const fullPath = toStatePath(stateId);
564 const relativePath = fullPath.slice(1);
565 const resolvedStateId = isStateId(fullPath[0]) ? fullPath[0].slice(STATE_IDENTIFIER.length) : fullPath[0];
566 const stateNode = this.idMap.get(resolvedStateId);
567 if (!stateNode) {
568 throw new Error(`Child state node '#${resolvedStateId}' does not exist on machine '${this.id}'`);
569 }
570 return getStateNodeByPath(stateNode, relativePath);
571 }
572 get definition() {
573 return this.root.definition;
574 }
575 toJSON() {
576 return this.definition;
577 }
578 getPersistedSnapshot(snapshot, options) {
579 return getPersistedSnapshot(snapshot, options);
580 }
581 restoreSnapshot(snapshot, _actorScope) {
582 const children = {};
583 const snapshotChildren = snapshot.children;
584 Object.keys(snapshotChildren).forEach(actorId => {
585 const actorData = snapshotChildren[actorId];
586 const childState = actorData.snapshot;
587 const src = actorData.src;
588 const logic = typeof src === 'string' ? resolveReferencedActor(this, src) : src;
589 if (!logic) {
590 return;
591 }
592 const actorRef = createActor(logic, {
593 id: actorId,
594 parent: _actorScope.self,
595 syncSnapshot: actorData.syncSnapshot,
596 snapshot: childState,
597 src,
598 systemId: actorData.systemId
599 });
600 children[actorId] = actorRef;
601 });
602 const restoredSnapshot = createMachineSnapshot({
603 ...snapshot,
604 children,
605 _nodes: Array.from(getAllStateNodes(getStateNodes(this.root, snapshot.value)))
606 }, this);
607 let seen = new Set();
608 function reviveContext(contextPart, children) {
609 if (seen.has(contextPart)) {
610 return;
611 }
612 seen.add(contextPart);
613 for (let key in contextPart) {
614 const value = contextPart[key];
615 if (value && typeof value === 'object') {
616 if ('xstate$$type' in value && value.xstate$$type === $$ACTOR_TYPE) {
617 contextPart[key] = children[value.id];
618 continue;
619 }
620 reviveContext(value, children);
621 }
622 }
623 }
624 reviveContext(restoredSnapshot.context, children);
625 return restoredSnapshot;
626 }
627}
628
629const defaultWaitForOptions = {
630 timeout: Infinity // much more than 10 seconds
631};
632
633/**
634 * Subscribes to an actor ref and waits for its emitted value to satisfy
635 * a predicate, and then resolves with that value.
636 * Will throw if the desired state is not reached after an optional timeout.
637 * (defaults to Infinity).
638 *
639 * @example
640 * ```js
641 * const state = await waitFor(someService, state => {
642 * return state.hasTag('loaded');
643 * });
644 *
645 * state.hasTag('loaded'); // true
646 * ```
647 *
648 * @param actorRef The actor ref to subscribe to
649 * @param predicate Determines if a value matches the condition to wait for
650 * @param options
651 * @returns A promise that eventually resolves to the emitted value
652 * that matches the condition
653 */
654function waitFor(actorRef, predicate, options) {
655 const resolvedOptions = {
656 ...defaultWaitForOptions,
657 ...options
658 };
659 return new Promise((res, rej) => {
660 let done = false;
661 const handle = resolvedOptions.timeout === Infinity ? undefined : setTimeout(() => {
662 sub.unsubscribe();
663 rej(new Error(`Timeout of ${resolvedOptions.timeout} ms exceeded`));
664 }, resolvedOptions.timeout);
665 const dispose = () => {
666 clearTimeout(handle);
667 done = true;
668 sub?.unsubscribe();
669 };
670 function checkEmitted(emitted) {
671 if (predicate(emitted)) {
672 dispose();
673 res(emitted);
674 }
675 }
676 let sub; // avoid TDZ when disposing synchronously
677
678 // See if the current snapshot already matches the predicate
679 checkEmitted(actorRef.getSnapshot());
680 if (done) {
681 return;
682 }
683 sub = actorRef.subscribe({
684 next: checkEmitted,
685 error: err => {
686 dispose();
687 rej(err);
688 },
689 complete: () => {
690 dispose();
691 rej(new Error(`Actor terminated without satisfying predicate`));
692 }
693 });
694 if (done) {
695 sub.unsubscribe();
696 }
697 });
698}
699
700// this is not 100% accurate since we can't make parallel regions required in the result
701// `TTestValue` doesn't encode this information anyhow for us to be able to do that
702// this is fine for most practical use cases anyway though
703/**
704 * Creates a state machine (statechart) with the given configuration.
705 *
706 * The state machine represents the pure logic of a state machine actor.
707 *
708 * @param config The state machine configuration.
709 * @param options DEPRECATED: use `setup({ ... })` or `machine.provide({ ... })` to provide machine implementations instead.
710 *
711 * @example
712 ```ts
713 import { createMachine } from 'xstate';
714
715 const lightMachine = createMachine({
716 id: 'light',
717 initial: 'green',
718 states: {
719 green: {
720 on: {
721 TIMER: { target: 'yellow' }
722 }
723 },
724 yellow: {
725 on: {
726 TIMER: { target: 'red' }
727 }
728 },
729 red: {
730 on: {
731 TIMER: { target: 'green' }
732 }
733 }
734 }
735 });
736
737 const lightActor = createActor(lightMachine);
738 lightActor.start();
739
740 lightActor.send({ type: 'TIMER' });
741 ```
742 */
743function createMachine(config, implementations) {
744 return new StateMachine(config, implementations);
745}
746
747/** @internal */
748function createInertActorScope(actorLogic) {
749 const self = createActor(actorLogic);
750 const inertActorScope = {
751 self,
752 defer: () => {},
753 id: '',
754 logger: () => {},
755 sessionId: '',
756 stopChild: () => {},
757 system: self.system,
758 emit: () => {}
759 };
760 return inertActorScope;
761}
762function getInitialSnapshot(actorLogic, ...[input]) {
763 const actorScope = createInertActorScope(actorLogic);
764 return actorLogic.getInitialSnapshot(actorScope, input);
765}
766
767/**
768 * Determines the next snapshot for the given `actorLogic` based on
769 * the given `snapshot` and `event`.
770 *
771 * If the `snapshot` is `undefined`, the initial snapshot of the
772 * `actorLogic` is used.
773 *
774 * @example
775 ```ts
776 import { getNextSnapshot } from 'xstate';
777 import { trafficLightMachine } from './trafficLightMachine.ts';
778
779 const nextSnapshot = getNextSnapshot(
780 trafficLightMachine, // actor logic
781 undefined, // snapshot (or initial state if undefined)
782 { type: 'TIMER' }); // event object
783
784 console.log(nextSnapshot.value);
785 // => 'yellow'
786
787 const nextSnapshot2 = getNextSnapshot(
788 trafficLightMachine, // actor logic
789 nextSnapshot, // snapshot
790 { type: 'TIMER' }); // event object
791
792 console.log(nextSnapshot2.value);
793 // =>'red'
794 ```
795 */
796function getNextSnapshot(actorLogic, snapshot, event) {
797 const inertActorScope = createInertActorScope(actorLogic);
798 inertActorScope.self._snapshot = snapshot;
799 return actorLogic.transition(snapshot, event, inertActorScope);
800}
801
802// at the moment we allow extra actors - ones that are not specified by `children`
803// this could be reconsidered in the future
804function setup({
805 schemas,
806 actors,
807 actions,
808 guards,
809 delays
810}) {
811 return {
812 createMachine: config => createMachine({
813 ...config,
814 schemas
815 }, {
816 actors,
817 actions,
818 guards,
819 delays
820 })
821 };
822}
823
824/**
825 * Returns a promise that resolves to the `output` of the actor when it is done.
826 *
827 * @example
828 * ```ts
829 * const machine = createMachine({
830 * // ...
831 * output: {
832 * count: 42
833 * }
834 * });
835 *
836 * const actor = createActor(machine);
837 *
838 * actor.start();
839 *
840 * const output = await toPromise(actor);
841 *
842 * console.log(output);
843 * // logs { count: 42 }
844 * ```
845 */
846function toPromise(actor) {
847 return new Promise((resolve, reject) => {
848 actor.subscribe({
849 complete: () => {
850 resolve(actor.getSnapshot().output);
851 },
852 error: reject
853 });
854 });
855}
856
857/**
858 * Asserts that the given event object is of the specified type or types.
859 * Throws an error if the event object is not of the specified types.
860 @example
861
862 ```ts
863 // ...
864 entry: ({ event }) => {
865 assertEvent(event, 'doNothing');
866 // event is { type: 'doNothing' }
867 },
868 // ...
869 exit: ({ event }) => {
870 assertEvent(event, 'greet');
871 // event is { type: 'greet'; message: string }
872
873 assertEvent(event, ['greet', 'notify']);
874 // event is { type: 'greet'; message: string }
875 // or { type: 'notify'; message: string; level: 'info' | 'error' }
876 },
877 ```
878 */
879function assertEvent(event, type) {
880 const types = toArray(type);
881 if (!types.includes(event.type)) {
882 const typesText = types.length === 1 ? `type "${types[0]}"` : `one of types "${types.join('", "')}"`;
883 throw new Error(`Expected event ${JSON.stringify(event)} to have ${typesText}`);
884 }
885}
886
887export { SimulatedClock, StateMachine, StateNode, assertEvent, createMachine, getInitialSnapshot, getNextSnapshot, setup, toPromise, waitFor };