xstate 5.0.0-beta.15 → 5.0.0-beta.16
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.
- package/actions/dist/xstate-actions.cjs.js +1 -3
- package/actions/dist/xstate-actions.cjs.mjs +0 -2
- package/actions/dist/xstate-actions.development.cjs.js +1 -3
- package/actions/dist/xstate-actions.development.esm.js +1 -1
- package/actions/dist/xstate-actions.esm.js +1 -1
- package/actions/dist/xstate-actions.umd.min.js +1 -1
- package/actions/dist/xstate-actions.umd.min.js.map +1 -1
- package/actors/dist/xstate-actors.cjs.js +1 -1
- package/actors/dist/xstate-actors.development.cjs.js +1 -1
- package/actors/dist/xstate-actors.development.esm.js +1 -1
- package/actors/dist/xstate-actors.esm.js +1 -1
- package/actors/dist/xstate-actors.umd.min.js +1 -1
- package/actors/dist/xstate-actors.umd.min.js.map +1 -1
- package/dist/{actions-6884fae8.esm.js → actions-0386b622.esm.js} +707 -742
- package/dist/{actions-d71ac253.development.cjs.js → actions-0f903c0d.development.cjs.js} +836 -874
- package/dist/{actions-81cc7f2b.cjs.js → actions-6b9073db.cjs.js} +706 -744
- package/dist/{actions-98f362b9.development.esm.js → actions-6f7fbc84.development.esm.js} +837 -872
- package/dist/declarations/src/StateMachine.d.ts +2 -4
- package/dist/declarations/src/actionTypes.d.ts +1 -1
- package/dist/declarations/src/actions/assign.d.ts +2 -2
- package/dist/declarations/src/actions/cancel.d.ts +2 -2
- package/dist/declarations/src/actions/send.d.ts +12 -22
- package/dist/declarations/src/actions/stop.d.ts +2 -2
- package/dist/declarations/src/actions.d.ts +1 -4
- package/dist/declarations/src/interpreter.d.ts +2 -2
- package/dist/declarations/src/stateUtils.d.ts +1 -1
- package/dist/declarations/src/types.d.ts +29 -49
- package/dist/xstate.cjs.js +20 -34
- package/dist/xstate.development.cjs.js +20 -34
- package/dist/xstate.development.esm.js +21 -35
- package/dist/xstate.esm.js +21 -35
- package/dist/xstate.umd.min.js +1 -1
- package/dist/xstate.umd.min.js.map +1 -1
- package/guards/dist/xstate-guards.cjs.js +1 -1
- package/guards/dist/xstate-guards.development.cjs.js +1 -1
- package/guards/dist/xstate-guards.development.esm.js +1 -1
- package/guards/dist/xstate-guards.esm.js +1 -1
- package/guards/dist/xstate-guards.umd.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -35,7 +35,7 @@ import { devToolsAdapter } from '../dev/dist/xstate-dev.esm.js';
|
|
|
35
35
|
let ActionTypes = /*#__PURE__*/function (ActionTypes) {
|
|
36
36
|
ActionTypes["Stop"] = "xstate.stop";
|
|
37
37
|
ActionTypes["Raise"] = "xstate.raise";
|
|
38
|
-
ActionTypes["
|
|
38
|
+
ActionTypes["SendTo"] = "xstate.sendTo";
|
|
39
39
|
ActionTypes["Cancel"] = "xstate.cancel";
|
|
40
40
|
ActionTypes["Assign"] = "xstate.assign";
|
|
41
41
|
ActionTypes["After"] = "xstate.after";
|
|
@@ -61,7 +61,7 @@ let SpecialTargets = /*#__PURE__*/function (SpecialTargets) {
|
|
|
61
61
|
// xstate-specific action types
|
|
62
62
|
const stop$1 = ActionTypes.Stop;
|
|
63
63
|
const raise$1 = ActionTypes.Raise;
|
|
64
|
-
const
|
|
64
|
+
const sendTo$1 = ActionTypes.SendTo;
|
|
65
65
|
const cancel$1 = ActionTypes.Cancel;
|
|
66
66
|
const assign$1 = ActionTypes.Assign;
|
|
67
67
|
const after$1 = ActionTypes.After;
|
|
@@ -79,7 +79,7 @@ var actionTypes = /*#__PURE__*/Object.freeze({
|
|
|
79
79
|
__proto__: null,
|
|
80
80
|
stop: stop$1,
|
|
81
81
|
raise: raise$1,
|
|
82
|
-
|
|
82
|
+
sendTo: sendTo$1,
|
|
83
83
|
cancel: cancel$1,
|
|
84
84
|
assign: assign$1,
|
|
85
85
|
after: after$1,
|
|
@@ -304,22 +304,19 @@ function isDynamicAction(action) {
|
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
/**
|
|
307
|
-
* Sends an event
|
|
308
|
-
* send the event in the next step, after the current step is finished executing.
|
|
309
|
-
*
|
|
310
|
-
* @deprecated Use the `sendTo(...)` action creator instead.
|
|
307
|
+
* Sends an event to an actor.
|
|
311
308
|
*
|
|
312
|
-
* @param
|
|
313
|
-
* @param
|
|
309
|
+
* @param actor The `ActorRef` to send the event to.
|
|
310
|
+
* @param event The event to send, or an expression that evaluates to the event to send
|
|
311
|
+
* @param options Send action options
|
|
314
312
|
* - `id` - The unique send event identifier (used with `cancel()`).
|
|
315
313
|
* - `delay` - The number of milliseconds to delay the sending of the event.
|
|
316
|
-
* - `to` - The target of this event (by default, the machine the event was sent from).
|
|
317
314
|
*/
|
|
318
|
-
function
|
|
315
|
+
function sendTo(actor, eventOrExpr, options) {
|
|
319
316
|
return createDynamicAction({
|
|
320
|
-
type:
|
|
317
|
+
type: sendTo$1,
|
|
321
318
|
params: {
|
|
322
|
-
to:
|
|
319
|
+
to: actor,
|
|
323
320
|
delay: options ? options.delay : undefined,
|
|
324
321
|
event: eventOrExpr,
|
|
325
322
|
id: options && options.id !== undefined ? options.id : isFunction(eventOrExpr) ? eventOrExpr.name : eventOrExpr.type
|
|
@@ -329,7 +326,7 @@ function send(eventOrExpr, options) {
|
|
|
329
326
|
state
|
|
330
327
|
}) => {
|
|
331
328
|
const params = {
|
|
332
|
-
to:
|
|
329
|
+
to: actor,
|
|
333
330
|
delay: options ? options.delay : undefined,
|
|
334
331
|
event: eventOrExpr,
|
|
335
332
|
// TODO: don't auto-generate IDs here like that
|
|
@@ -377,13 +374,12 @@ function send(eventOrExpr, options) {
|
|
|
377
374
|
targetActorRef = resolvedTarget || actorContext?.self;
|
|
378
375
|
}
|
|
379
376
|
const resolvedAction = {
|
|
380
|
-
type:
|
|
377
|
+
type: sendTo$1,
|
|
381
378
|
params: {
|
|
382
379
|
...params,
|
|
383
380
|
to: targetActorRef,
|
|
384
381
|
event: resolvedEvent,
|
|
385
|
-
delay: resolvedDelay
|
|
386
|
-
internal: resolvedTarget === SpecialTargets.Internal
|
|
382
|
+
delay: resolvedDelay
|
|
387
383
|
},
|
|
388
384
|
execute: actorCtx => {
|
|
389
385
|
const sendAction = resolvedAction;
|
|
@@ -413,12 +409,8 @@ function send(eventOrExpr, options) {
|
|
|
413
409
|
* @param options Options to pass into the send event.
|
|
414
410
|
*/
|
|
415
411
|
function sendParent(event, options) {
|
|
416
|
-
return
|
|
417
|
-
...options,
|
|
418
|
-
to: SpecialTargets.Parent
|
|
419
|
-
});
|
|
412
|
+
return sendTo(SpecialTargets.Parent, event, options);
|
|
420
413
|
}
|
|
421
|
-
|
|
422
414
|
/**
|
|
423
415
|
* Forwards (sends) an event to a specified service.
|
|
424
416
|
*
|
|
@@ -426,12 +418,9 @@ function sendParent(event, options) {
|
|
|
426
418
|
* @param options Options to pass into the send action creator.
|
|
427
419
|
*/
|
|
428
420
|
function forwardTo(target, options) {
|
|
429
|
-
return
|
|
421
|
+
return sendTo(target, ({
|
|
430
422
|
event
|
|
431
|
-
}) => event,
|
|
432
|
-
...options,
|
|
433
|
-
to: target
|
|
434
|
-
});
|
|
423
|
+
}) => event, options);
|
|
435
424
|
}
|
|
436
425
|
|
|
437
426
|
/**
|
|
@@ -447,25 +436,7 @@ function escalate(errorData, options) {
|
|
|
447
436
|
type: error$1,
|
|
448
437
|
data: isFunction(errorData) ? errorData(arg) : errorData
|
|
449
438
|
};
|
|
450
|
-
},
|
|
451
|
-
...options,
|
|
452
|
-
to: SpecialTargets.Parent
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* Sends an event to an actor.
|
|
458
|
-
*
|
|
459
|
-
* @param actor The `ActorRef` to send the event to.
|
|
460
|
-
* @param event The event to send, or an expression that evaluates to the event to send
|
|
461
|
-
* @param options Send action options
|
|
462
|
-
* @returns An XState send action object
|
|
463
|
-
*/
|
|
464
|
-
function sendTo(actor, event, options) {
|
|
465
|
-
return send(event, {
|
|
466
|
-
...options,
|
|
467
|
-
to: actor
|
|
468
|
-
});
|
|
439
|
+
}, options);
|
|
469
440
|
}
|
|
470
441
|
|
|
471
442
|
const cache = new WeakMap();
|
|
@@ -519,8 +490,6 @@ function cancel(sendId) {
|
|
|
519
490
|
});
|
|
520
491
|
}
|
|
521
492
|
|
|
522
|
-
const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
|
|
523
|
-
|
|
524
493
|
class Mailbox {
|
|
525
494
|
constructor(_process) {
|
|
526
495
|
this._process = _process;
|
|
@@ -588,507 +557,131 @@ class Mailbox {
|
|
|
588
557
|
}
|
|
589
558
|
}
|
|
590
559
|
|
|
591
|
-
function
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
reverseKeyedActors.delete(actorRef);
|
|
608
|
-
}
|
|
560
|
+
const symbolObservable = (() => typeof Symbol === 'function' && Symbol.observable || '@@observable')();
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Returns actor logic from a transition function and its initial state.
|
|
564
|
+
*
|
|
565
|
+
* A transition function is a function that takes the current state and an event and returns the next state.
|
|
566
|
+
*
|
|
567
|
+
* @param transition The transition function that returns the next state given the current state and event.
|
|
568
|
+
* @param initialState The initial state of the transition function.
|
|
569
|
+
* @returns Actor logic
|
|
570
|
+
*/
|
|
571
|
+
function fromTransition(transition, initialState) {
|
|
572
|
+
const logic = {
|
|
573
|
+
config: transition,
|
|
574
|
+
transition: (state, event, actorContext) => {
|
|
575
|
+
return transition(state, event, actorContext);
|
|
609
576
|
},
|
|
610
|
-
|
|
611
|
-
return
|
|
577
|
+
getInitialState: (_, input) => {
|
|
578
|
+
return typeof initialState === 'function' ? initialState({
|
|
579
|
+
input
|
|
580
|
+
}) : initialState;
|
|
612
581
|
},
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
throw new Error(`Actor with system ID '${systemId}' already exists.`);
|
|
617
|
-
}
|
|
618
|
-
keyedActors.set(systemId, actorRef);
|
|
619
|
-
reverseKeyedActors.set(actorRef, systemId);
|
|
620
|
-
}
|
|
582
|
+
getSnapshot: state => state,
|
|
583
|
+
getPersistedState: state => state,
|
|
584
|
+
restoreState: state => state
|
|
621
585
|
};
|
|
622
|
-
return
|
|
586
|
+
return logic;
|
|
623
587
|
}
|
|
624
588
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
589
|
+
const resolveEventType = '$$xstate.resolve';
|
|
590
|
+
const rejectEventType = '$$xstate.reject';
|
|
591
|
+
function fromPromise(
|
|
592
|
+
// TODO: add types
|
|
593
|
+
promiseCreator) {
|
|
594
|
+
// TODO: add event types, consider making the `PromiseEvent` a private type or smth alike
|
|
595
|
+
const logic = {
|
|
596
|
+
config: promiseCreator,
|
|
597
|
+
transition: (state, event) => {
|
|
598
|
+
if (state.status !== 'active') {
|
|
599
|
+
return state;
|
|
600
|
+
}
|
|
601
|
+
switch (event.type) {
|
|
602
|
+
case resolveEventType:
|
|
603
|
+
return {
|
|
604
|
+
...state,
|
|
605
|
+
status: 'done',
|
|
606
|
+
data: event.data,
|
|
607
|
+
input: undefined
|
|
608
|
+
};
|
|
609
|
+
case rejectEventType:
|
|
610
|
+
return {
|
|
611
|
+
...state,
|
|
612
|
+
status: 'error',
|
|
613
|
+
data: event.data,
|
|
614
|
+
input: undefined
|
|
615
|
+
};
|
|
616
|
+
case stopSignalType:
|
|
617
|
+
return {
|
|
618
|
+
...state,
|
|
619
|
+
status: 'canceled',
|
|
620
|
+
input: undefined
|
|
621
|
+
};
|
|
622
|
+
default:
|
|
623
|
+
return state;
|
|
624
|
+
}
|
|
636
625
|
},
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
626
|
+
start: (state, {
|
|
627
|
+
self,
|
|
628
|
+
system
|
|
629
|
+
}) => {
|
|
630
|
+
// TODO: determine how to allow customizing this so that promises
|
|
631
|
+
// can be restarted if necessary
|
|
632
|
+
if (state.status !== 'active') {
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
const resolvedPromise = Promise.resolve(promiseCreator({
|
|
636
|
+
input: state.input,
|
|
637
|
+
system
|
|
638
|
+
}));
|
|
639
|
+
resolvedPromise.then(response => {
|
|
640
|
+
// TODO: remove this condition once dead letter queue lands
|
|
641
|
+
if (self._state.status !== 'active') {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
self.send({
|
|
645
|
+
type: resolveEventType,
|
|
646
|
+
data: response
|
|
647
|
+
});
|
|
648
|
+
}, errorData => {
|
|
649
|
+
// TODO: remove this condition once dead letter queue lands
|
|
650
|
+
if (self._state.status !== 'active') {
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
self.send({
|
|
654
|
+
type: rejectEventType,
|
|
655
|
+
data: errorData
|
|
656
|
+
});
|
|
657
|
+
});
|
|
658
|
+
},
|
|
659
|
+
getInitialState: (_, input) => {
|
|
660
|
+
return {
|
|
661
|
+
status: 'active',
|
|
662
|
+
data: undefined,
|
|
663
|
+
input
|
|
664
|
+
};
|
|
665
|
+
},
|
|
666
|
+
getSnapshot: state => state.data,
|
|
667
|
+
getStatus: state => state,
|
|
668
|
+
getPersistedState: state => state,
|
|
669
|
+
restoreState: state => state
|
|
670
|
+
};
|
|
671
|
+
return logic;
|
|
672
|
+
}
|
|
664
673
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
674
|
+
// TODO: this likely shouldn't accept TEvent, observable actor doesn't accept external events
|
|
675
|
+
function fromObservable(observableCreator) {
|
|
676
|
+
const nextEventType = '$$xstate.next';
|
|
677
|
+
const errorEventType = '$$xstate.error';
|
|
678
|
+
const completeEventType = '$$xstate.complete';
|
|
668
679
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
*/
|
|
675
|
-
constructor(logic, options) {
|
|
676
|
-
this.logic = logic;
|
|
677
|
-
this._state = void 0;
|
|
678
|
-
this.clock = void 0;
|
|
679
|
-
this.options = void 0;
|
|
680
|
-
this.id = void 0;
|
|
681
|
-
this.mailbox = new Mailbox(this._process.bind(this));
|
|
682
|
-
this.delayedEventsMap = {};
|
|
683
|
-
this.observers = new Set();
|
|
684
|
-
this.logger = void 0;
|
|
685
|
-
this.status = ActorStatus.NotStarted;
|
|
686
|
-
this._parent = void 0;
|
|
687
|
-
this.ref = void 0;
|
|
688
|
-
this._actorContext = void 0;
|
|
689
|
-
this._systemId = void 0;
|
|
690
|
-
this.sessionId = void 0;
|
|
691
|
-
this.system = void 0;
|
|
692
|
-
this._doneEvent = void 0;
|
|
693
|
-
this.src = void 0;
|
|
694
|
-
this._deferred = [];
|
|
695
|
-
const resolvedOptions = {
|
|
696
|
-
...defaultOptions,
|
|
697
|
-
...options
|
|
698
|
-
};
|
|
699
|
-
const {
|
|
700
|
-
clock,
|
|
701
|
-
logger,
|
|
702
|
-
parent,
|
|
703
|
-
id,
|
|
704
|
-
systemId
|
|
705
|
-
} = resolvedOptions;
|
|
706
|
-
const self = this;
|
|
707
|
-
this.system = parent?.system ?? createSystem();
|
|
708
|
-
if (systemId) {
|
|
709
|
-
this._systemId = systemId;
|
|
710
|
-
this.system._set(systemId, this);
|
|
711
|
-
}
|
|
712
|
-
this.sessionId = this.system._bookId();
|
|
713
|
-
this.id = id ?? this.sessionId;
|
|
714
|
-
this.logger = logger;
|
|
715
|
-
this.clock = clock;
|
|
716
|
-
this._parent = parent;
|
|
717
|
-
this.options = resolvedOptions;
|
|
718
|
-
this.src = resolvedOptions.src;
|
|
719
|
-
this.ref = this;
|
|
720
|
-
this._actorContext = {
|
|
721
|
-
self,
|
|
722
|
-
id: this.id,
|
|
723
|
-
sessionId: this.sessionId,
|
|
724
|
-
logger: this.logger,
|
|
725
|
-
defer: fn => {
|
|
726
|
-
this._deferred.push(fn);
|
|
727
|
-
},
|
|
728
|
-
system: this.system,
|
|
729
|
-
stopChild: child => {
|
|
730
|
-
if (child._parent !== this) {
|
|
731
|
-
throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`);
|
|
732
|
-
}
|
|
733
|
-
child._stop();
|
|
734
|
-
}
|
|
735
|
-
};
|
|
736
|
-
|
|
737
|
-
// Ensure that the send method is bound to this interpreter instance
|
|
738
|
-
// if destructured
|
|
739
|
-
this.send = this.send.bind(this);
|
|
740
|
-
this._initState();
|
|
741
|
-
}
|
|
742
|
-
_initState() {
|
|
743
|
-
this._state = this.options.state ? this.logic.restoreState ? this.logic.restoreState(this.options.state, this._actorContext) : this.options.state : this.logic.getInitialState(this._actorContext, this.options?.input);
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
// array of functions to defer
|
|
747
|
-
|
|
748
|
-
update(state) {
|
|
749
|
-
// Update state
|
|
750
|
-
this._state = state;
|
|
751
|
-
const snapshot = this.getSnapshot();
|
|
752
|
-
|
|
753
|
-
// Execute deferred effects
|
|
754
|
-
let deferredFn;
|
|
755
|
-
while (deferredFn = this._deferred.shift()) {
|
|
756
|
-
deferredFn();
|
|
757
|
-
}
|
|
758
|
-
for (const observer of this.observers) {
|
|
759
|
-
observer.next?.(snapshot);
|
|
760
|
-
}
|
|
761
|
-
const status = this.logic.getStatus?.(state);
|
|
762
|
-
switch (status?.status) {
|
|
763
|
-
case 'done':
|
|
764
|
-
this._stopProcedure();
|
|
765
|
-
this._doneEvent = doneInvoke(this.id, status.data);
|
|
766
|
-
this._parent?.send(this._doneEvent);
|
|
767
|
-
this._complete();
|
|
768
|
-
break;
|
|
769
|
-
case 'error':
|
|
770
|
-
this._stopProcedure();
|
|
771
|
-
this._parent?.send(error(this.id, status.data));
|
|
772
|
-
this._error(status.data);
|
|
773
|
-
break;
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
subscribe(nextListenerOrObserver, errorListener, completeListener) {
|
|
777
|
-
const observer = toObserver(nextListenerOrObserver, errorListener, completeListener);
|
|
778
|
-
this.observers.add(observer);
|
|
779
|
-
if (this.status === ActorStatus.Stopped) {
|
|
780
|
-
observer.complete?.();
|
|
781
|
-
this.observers.delete(observer);
|
|
782
|
-
}
|
|
783
|
-
return {
|
|
784
|
-
unsubscribe: () => {
|
|
785
|
-
this.observers.delete(observer);
|
|
786
|
-
}
|
|
787
|
-
};
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
/**
|
|
791
|
-
* Starts the interpreter from the initial state
|
|
792
|
-
*/
|
|
793
|
-
start() {
|
|
794
|
-
if (this.status === ActorStatus.Running) {
|
|
795
|
-
// Do not restart the service if it is already started
|
|
796
|
-
return this;
|
|
797
|
-
}
|
|
798
|
-
this.system._register(this.sessionId, this);
|
|
799
|
-
if (this._systemId) {
|
|
800
|
-
this.system._set(this._systemId, this);
|
|
801
|
-
}
|
|
802
|
-
this.status = ActorStatus.Running;
|
|
803
|
-
if (this.logic.start) {
|
|
804
|
-
this.logic.start(this._state, this._actorContext);
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
// TODO: this notifies all subscribers but usually this is redundant
|
|
808
|
-
// there is no real change happening here
|
|
809
|
-
// we need to rethink if this needs to be refactored
|
|
810
|
-
this.update(this._state);
|
|
811
|
-
if (this.options.devTools) {
|
|
812
|
-
this.attachDevTools();
|
|
813
|
-
}
|
|
814
|
-
this.mailbox.start();
|
|
815
|
-
return this;
|
|
816
|
-
}
|
|
817
|
-
_process(event) {
|
|
818
|
-
try {
|
|
819
|
-
const nextState = this.logic.transition(this._state, event, this._actorContext);
|
|
820
|
-
this.update(nextState);
|
|
821
|
-
if (event.type === stopSignalType) {
|
|
822
|
-
this._stopProcedure();
|
|
823
|
-
this._complete();
|
|
824
|
-
}
|
|
825
|
-
} catch (err) {
|
|
826
|
-
// TODO: properly handle errors
|
|
827
|
-
if (this.observers.size > 0) {
|
|
828
|
-
this.observers.forEach(observer => {
|
|
829
|
-
observer.error?.(err);
|
|
830
|
-
});
|
|
831
|
-
this.stop();
|
|
832
|
-
} else {
|
|
833
|
-
throw err;
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
_stop() {
|
|
838
|
-
if (this.status === ActorStatus.Stopped) {
|
|
839
|
-
return this;
|
|
840
|
-
}
|
|
841
|
-
this.mailbox.clear();
|
|
842
|
-
if (this.status === ActorStatus.NotStarted) {
|
|
843
|
-
this.status = ActorStatus.Stopped;
|
|
844
|
-
return this;
|
|
845
|
-
}
|
|
846
|
-
this.mailbox.enqueue({
|
|
847
|
-
type: stopSignalType
|
|
848
|
-
});
|
|
849
|
-
return this;
|
|
850
|
-
}
|
|
851
|
-
|
|
852
|
-
/**
|
|
853
|
-
* Stops the interpreter and unsubscribe all listeners.
|
|
854
|
-
*/
|
|
855
|
-
stop() {
|
|
856
|
-
if (this._parent) {
|
|
857
|
-
throw new Error('A non-root actor cannot be stopped directly.');
|
|
858
|
-
}
|
|
859
|
-
return this._stop();
|
|
860
|
-
}
|
|
861
|
-
_complete() {
|
|
862
|
-
for (const observer of this.observers) {
|
|
863
|
-
observer.complete?.();
|
|
864
|
-
}
|
|
865
|
-
this.observers.clear();
|
|
866
|
-
}
|
|
867
|
-
_error(data) {
|
|
868
|
-
for (const observer of this.observers) {
|
|
869
|
-
observer.error?.(data);
|
|
870
|
-
}
|
|
871
|
-
this.observers.clear();
|
|
872
|
-
}
|
|
873
|
-
_stopProcedure() {
|
|
874
|
-
if (this.status !== ActorStatus.Running) {
|
|
875
|
-
// Interpreter already stopped; do nothing
|
|
876
|
-
return this;
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
// Cancel all delayed events
|
|
880
|
-
for (const key of Object.keys(this.delayedEventsMap)) {
|
|
881
|
-
this.clock.clearTimeout(this.delayedEventsMap[key]);
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
// TODO: mailbox.reset
|
|
885
|
-
this.mailbox.clear();
|
|
886
|
-
// TODO: after `stop` we must prepare ourselves for receiving events again
|
|
887
|
-
// events sent *after* stop signal must be queued
|
|
888
|
-
// it seems like this should be the common behavior for all of our consumers
|
|
889
|
-
// so perhaps this should be unified somehow for all of them
|
|
890
|
-
this.mailbox = new Mailbox(this._process.bind(this));
|
|
891
|
-
this.status = ActorStatus.Stopped;
|
|
892
|
-
this.system._unregister(this);
|
|
893
|
-
return this;
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
/**
|
|
897
|
-
* Sends an event to the running interpreter to trigger a transition.
|
|
898
|
-
*
|
|
899
|
-
* @param event The event to send
|
|
900
|
-
*/
|
|
901
|
-
send(event) {
|
|
902
|
-
if (typeof event === 'string') {
|
|
903
|
-
throw new Error(`Only event objects may be sent to actors; use .send({ type: "${event}" }) instead`);
|
|
904
|
-
}
|
|
905
|
-
if (this.status === ActorStatus.Stopped) {
|
|
906
|
-
return;
|
|
907
|
-
}
|
|
908
|
-
if (this.status !== ActorStatus.Running && !this.options.deferEvents) {
|
|
909
|
-
throw new Error(`Event "${event.type}" was sent to uninitialized actor "${this.id
|
|
910
|
-
// tslint:disable-next-line:max-line-length
|
|
911
|
-
}". Make sure .start() is called for this actor, or set { deferEvents: true } in the actor options.\nEvent: ${JSON.stringify(event)}`);
|
|
912
|
-
}
|
|
913
|
-
this.mailbox.enqueue(event);
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
// TODO: make private (and figure out a way to do this within the machine)
|
|
917
|
-
delaySend(sendAction) {
|
|
918
|
-
this.delayedEventsMap[sendAction.params.id] = this.clock.setTimeout(() => {
|
|
919
|
-
if ('to' in sendAction.params && sendAction.params.to) {
|
|
920
|
-
sendAction.params.to.send(sendAction.params.event);
|
|
921
|
-
} else {
|
|
922
|
-
this.send(sendAction.params.event);
|
|
923
|
-
}
|
|
924
|
-
}, sendAction.params.delay);
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
// TODO: make private (and figure out a way to do this within the machine)
|
|
928
|
-
cancel(sendId) {
|
|
929
|
-
this.clock.clearTimeout(this.delayedEventsMap[sendId]);
|
|
930
|
-
delete this.delayedEventsMap[sendId];
|
|
931
|
-
}
|
|
932
|
-
attachDevTools() {
|
|
933
|
-
const {
|
|
934
|
-
devTools
|
|
935
|
-
} = this.options;
|
|
936
|
-
if (devTools) {
|
|
937
|
-
const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : devToolsAdapter;
|
|
938
|
-
resolvedDevToolsAdapter(this);
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
toJSON() {
|
|
942
|
-
return {
|
|
943
|
-
id: this.id
|
|
944
|
-
};
|
|
945
|
-
}
|
|
946
|
-
getPersistedState() {
|
|
947
|
-
return this.logic.getPersistedState?.(this._state);
|
|
948
|
-
}
|
|
949
|
-
[symbolObservable]() {
|
|
950
|
-
return this;
|
|
951
|
-
}
|
|
952
|
-
getSnapshot() {
|
|
953
|
-
return this.logic.getSnapshot ? this.logic.getSnapshot(this._state) : this._state;
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
/**
|
|
958
|
-
* Creates a new Interpreter instance for the given machine with the provided options, if any.
|
|
959
|
-
*
|
|
960
|
-
* @param machine The machine to interpret
|
|
961
|
-
* @param options Interpreter options
|
|
962
|
-
*/
|
|
963
|
-
|
|
964
|
-
function interpret(logic, options) {
|
|
965
|
-
const interpreter = new Interpreter(logic, options);
|
|
966
|
-
return interpreter;
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
/**
|
|
970
|
-
* Returns actor logic from a transition function and its initial state.
|
|
971
|
-
*
|
|
972
|
-
* A transition function is a function that takes the current state and an event and returns the next state.
|
|
973
|
-
*
|
|
974
|
-
* @param transition The transition function that returns the next state given the current state and event.
|
|
975
|
-
* @param initialState The initial state of the transition function.
|
|
976
|
-
* @returns Actor logic
|
|
977
|
-
*/
|
|
978
|
-
function fromTransition(transition, initialState) {
|
|
979
|
-
const logic = {
|
|
980
|
-
config: transition,
|
|
981
|
-
transition: (state, event, actorContext) => {
|
|
982
|
-
return transition(state, event, actorContext);
|
|
983
|
-
},
|
|
984
|
-
getInitialState: (_, input) => {
|
|
985
|
-
return typeof initialState === 'function' ? initialState({
|
|
986
|
-
input
|
|
987
|
-
}) : initialState;
|
|
988
|
-
},
|
|
989
|
-
getSnapshot: state => state,
|
|
990
|
-
getPersistedState: state => state,
|
|
991
|
-
restoreState: state => state
|
|
992
|
-
};
|
|
993
|
-
return logic;
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
const resolveEventType = '$$xstate.resolve';
|
|
997
|
-
const rejectEventType = '$$xstate.reject';
|
|
998
|
-
function fromPromise(
|
|
999
|
-
// TODO: add types
|
|
1000
|
-
promiseCreator) {
|
|
1001
|
-
// TODO: add event types, consider making the `PromiseEvent` a private type or smth alike
|
|
1002
|
-
const logic = {
|
|
1003
|
-
config: promiseCreator,
|
|
1004
|
-
transition: (state, event) => {
|
|
1005
|
-
if (state.status !== 'active') {
|
|
1006
|
-
return state;
|
|
1007
|
-
}
|
|
1008
|
-
switch (event.type) {
|
|
1009
|
-
case resolveEventType:
|
|
1010
|
-
return {
|
|
1011
|
-
...state,
|
|
1012
|
-
status: 'done',
|
|
1013
|
-
data: event.data,
|
|
1014
|
-
input: undefined
|
|
1015
|
-
};
|
|
1016
|
-
case rejectEventType:
|
|
1017
|
-
return {
|
|
1018
|
-
...state,
|
|
1019
|
-
status: 'error',
|
|
1020
|
-
data: event.data,
|
|
1021
|
-
input: undefined
|
|
1022
|
-
};
|
|
1023
|
-
case stopSignalType:
|
|
1024
|
-
return {
|
|
1025
|
-
...state,
|
|
1026
|
-
status: 'canceled',
|
|
1027
|
-
input: undefined
|
|
1028
|
-
};
|
|
1029
|
-
default:
|
|
1030
|
-
return state;
|
|
1031
|
-
}
|
|
1032
|
-
},
|
|
1033
|
-
start: (state, {
|
|
1034
|
-
self,
|
|
1035
|
-
system
|
|
1036
|
-
}) => {
|
|
1037
|
-
// TODO: determine how to allow customizing this so that promises
|
|
1038
|
-
// can be restarted if necessary
|
|
1039
|
-
if (state.status !== 'active') {
|
|
1040
|
-
return;
|
|
1041
|
-
}
|
|
1042
|
-
const resolvedPromise = Promise.resolve(promiseCreator({
|
|
1043
|
-
input: state.input,
|
|
1044
|
-
system
|
|
1045
|
-
}));
|
|
1046
|
-
resolvedPromise.then(response => {
|
|
1047
|
-
// TODO: remove this condition once dead letter queue lands
|
|
1048
|
-
if (self._state.status !== 'active') {
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
|
-
self.send({
|
|
1052
|
-
type: resolveEventType,
|
|
1053
|
-
data: response
|
|
1054
|
-
});
|
|
1055
|
-
}, errorData => {
|
|
1056
|
-
// TODO: remove this condition once dead letter queue lands
|
|
1057
|
-
if (self._state.status !== 'active') {
|
|
1058
|
-
return;
|
|
1059
|
-
}
|
|
1060
|
-
self.send({
|
|
1061
|
-
type: rejectEventType,
|
|
1062
|
-
data: errorData
|
|
1063
|
-
});
|
|
1064
|
-
});
|
|
1065
|
-
},
|
|
1066
|
-
getInitialState: (_, input) => {
|
|
1067
|
-
return {
|
|
1068
|
-
status: 'active',
|
|
1069
|
-
data: undefined,
|
|
1070
|
-
input
|
|
1071
|
-
};
|
|
1072
|
-
},
|
|
1073
|
-
getSnapshot: state => state.data,
|
|
1074
|
-
getStatus: state => state,
|
|
1075
|
-
getPersistedState: state => state,
|
|
1076
|
-
restoreState: state => state
|
|
1077
|
-
};
|
|
1078
|
-
return logic;
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
// TODO: this likely shouldn't accept TEvent, observable actor doesn't accept external events
|
|
1082
|
-
function fromObservable(observableCreator) {
|
|
1083
|
-
const nextEventType = '$$xstate.next';
|
|
1084
|
-
const errorEventType = '$$xstate.error';
|
|
1085
|
-
const completeEventType = '$$xstate.complete';
|
|
1086
|
-
|
|
1087
|
-
// TODO: add event types
|
|
1088
|
-
const logic = {
|
|
1089
|
-
config: observableCreator,
|
|
1090
|
-
transition: (state, event, {
|
|
1091
|
-
self,
|
|
680
|
+
// TODO: add event types
|
|
681
|
+
const logic = {
|
|
682
|
+
config: observableCreator,
|
|
683
|
+
transition: (state, event, {
|
|
684
|
+
self,
|
|
1092
685
|
id,
|
|
1093
686
|
defer
|
|
1094
687
|
}) => {
|
|
@@ -1278,140 +871,518 @@ function fromEventObservable(lazyObservable) {
|
|
|
1278
871
|
}
|
|
1279
872
|
});
|
|
1280
873
|
},
|
|
1281
|
-
getSnapshot: _ => undefined,
|
|
1282
|
-
getPersistedState: ({
|
|
1283
|
-
status,
|
|
1284
|
-
data,
|
|
1285
|
-
input
|
|
1286
|
-
}) => ({
|
|
1287
|
-
status,
|
|
1288
|
-
data,
|
|
1289
|
-
input
|
|
1290
|
-
}),
|
|
1291
|
-
getStatus: state => state,
|
|
1292
|
-
restoreState: state => ({
|
|
1293
|
-
...state,
|
|
1294
|
-
subscription: undefined
|
|
1295
|
-
})
|
|
874
|
+
getSnapshot: _ => undefined,
|
|
875
|
+
getPersistedState: ({
|
|
876
|
+
status,
|
|
877
|
+
data,
|
|
878
|
+
input
|
|
879
|
+
}) => ({
|
|
880
|
+
status,
|
|
881
|
+
data,
|
|
882
|
+
input
|
|
883
|
+
}),
|
|
884
|
+
getStatus: state => state,
|
|
885
|
+
restoreState: state => ({
|
|
886
|
+
...state,
|
|
887
|
+
subscription: undefined
|
|
888
|
+
})
|
|
889
|
+
};
|
|
890
|
+
return logic;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
function fromCallback(invokeCallback) {
|
|
894
|
+
const logic = {
|
|
895
|
+
config: invokeCallback,
|
|
896
|
+
start: (_state, {
|
|
897
|
+
self
|
|
898
|
+
}) => {
|
|
899
|
+
self.send({
|
|
900
|
+
type: startSignalType
|
|
901
|
+
});
|
|
902
|
+
},
|
|
903
|
+
transition: (state, event, {
|
|
904
|
+
self,
|
|
905
|
+
id,
|
|
906
|
+
system
|
|
907
|
+
}) => {
|
|
908
|
+
if (event.type === startSignalType) {
|
|
909
|
+
const sender = eventForParent => {
|
|
910
|
+
if (state.canceled) {
|
|
911
|
+
return;
|
|
912
|
+
}
|
|
913
|
+
self._parent?.send(eventForParent);
|
|
914
|
+
};
|
|
915
|
+
const receiver = newListener => {
|
|
916
|
+
state.receivers.add(newListener);
|
|
917
|
+
};
|
|
918
|
+
state.dispose = invokeCallback(sender, receiver, {
|
|
919
|
+
input: state.input,
|
|
920
|
+
system
|
|
921
|
+
});
|
|
922
|
+
if (isPromiseLike(state.dispose)) {
|
|
923
|
+
state.dispose.then(resolved => {
|
|
924
|
+
self._parent?.send(doneInvoke(id, resolved));
|
|
925
|
+
state.canceled = true;
|
|
926
|
+
}, errorData => {
|
|
927
|
+
state.canceled = true;
|
|
928
|
+
self._parent?.send(error(id, errorData));
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
return state;
|
|
932
|
+
}
|
|
933
|
+
if (event.type === stopSignalType) {
|
|
934
|
+
state.canceled = true;
|
|
935
|
+
if (isFunction(state.dispose)) {
|
|
936
|
+
state.dispose();
|
|
937
|
+
}
|
|
938
|
+
return state;
|
|
939
|
+
}
|
|
940
|
+
if (isSignal(event)) {
|
|
941
|
+
// TODO: unrecognized signal
|
|
942
|
+
return state;
|
|
943
|
+
}
|
|
944
|
+
state.receivers.forEach(receiver => receiver(event));
|
|
945
|
+
return state;
|
|
946
|
+
},
|
|
947
|
+
getInitialState: (_, input) => {
|
|
948
|
+
return {
|
|
949
|
+
canceled: false,
|
|
950
|
+
receivers: new Set(),
|
|
951
|
+
dispose: undefined,
|
|
952
|
+
input
|
|
953
|
+
};
|
|
954
|
+
},
|
|
955
|
+
getSnapshot: () => undefined,
|
|
956
|
+
getPersistedState: ({
|
|
957
|
+
input
|
|
958
|
+
}) => input
|
|
959
|
+
};
|
|
960
|
+
return logic;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
const startSignalType = 'xstate.init';
|
|
964
|
+
const stopSignalType = 'xstate.stop';
|
|
965
|
+
const startSignal = {
|
|
966
|
+
type: 'xstate.init'
|
|
967
|
+
};
|
|
968
|
+
const stopSignal = {
|
|
969
|
+
type: 'xstate.stop'
|
|
970
|
+
};
|
|
971
|
+
/**
|
|
972
|
+
* An object that expresses the actor logic in reaction to received events,
|
|
973
|
+
* as well as an optionally emitted stream of values.
|
|
974
|
+
*
|
|
975
|
+
* @template TReceived The received event
|
|
976
|
+
* @template TSnapshot The emitted value
|
|
977
|
+
*/
|
|
978
|
+
|
|
979
|
+
function isSignal(event) {
|
|
980
|
+
return event.type === startSignalType || event.type === stopSignalType;
|
|
981
|
+
}
|
|
982
|
+
function isActorRef(item) {
|
|
983
|
+
return !!item && typeof item === 'object' && typeof item.send === 'function';
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
// TODO: refactor the return type, this could be written in a better way
|
|
987
|
+
// but it's best to avoid unneccessary breaking changes now
|
|
988
|
+
// @deprecated use `interpret(actorLogic)` instead
|
|
989
|
+
function toActorRef(actorRefLike) {
|
|
990
|
+
return {
|
|
991
|
+
subscribe: () => ({
|
|
992
|
+
unsubscribe: () => void 0
|
|
993
|
+
}),
|
|
994
|
+
id: 'anonymous',
|
|
995
|
+
sessionId: '',
|
|
996
|
+
getSnapshot: () => undefined,
|
|
997
|
+
[symbolObservable]: function () {
|
|
998
|
+
return this;
|
|
999
|
+
},
|
|
1000
|
+
status: ActorStatus.Running,
|
|
1001
|
+
stop: () => void 0,
|
|
1002
|
+
...actorRefLike
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
const emptyLogic = fromTransition(_ => undefined, undefined);
|
|
1006
|
+
function createEmptyActor() {
|
|
1007
|
+
return interpret(emptyLogic);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
function createSystem() {
|
|
1011
|
+
let sessionIdCounter = 0;
|
|
1012
|
+
const children = new Map();
|
|
1013
|
+
const keyedActors = new Map();
|
|
1014
|
+
const reverseKeyedActors = new WeakMap();
|
|
1015
|
+
const system = {
|
|
1016
|
+
_bookId: () => `x:${sessionIdCounter++}`,
|
|
1017
|
+
_register: (sessionId, actorRef) => {
|
|
1018
|
+
children.set(sessionId, actorRef);
|
|
1019
|
+
return sessionId;
|
|
1020
|
+
},
|
|
1021
|
+
_unregister: actorRef => {
|
|
1022
|
+
children.delete(actorRef.sessionId);
|
|
1023
|
+
const systemId = reverseKeyedActors.get(actorRef);
|
|
1024
|
+
if (systemId !== undefined) {
|
|
1025
|
+
keyedActors.delete(systemId);
|
|
1026
|
+
reverseKeyedActors.delete(actorRef);
|
|
1027
|
+
}
|
|
1028
|
+
},
|
|
1029
|
+
get: systemId => {
|
|
1030
|
+
return keyedActors.get(systemId);
|
|
1031
|
+
},
|
|
1032
|
+
_set: (systemId, actorRef) => {
|
|
1033
|
+
const existing = keyedActors.get(systemId);
|
|
1034
|
+
if (existing && existing !== actorRef) {
|
|
1035
|
+
throw new Error(`Actor with system ID '${systemId}' already exists.`);
|
|
1036
|
+
}
|
|
1037
|
+
keyedActors.set(systemId, actorRef);
|
|
1038
|
+
reverseKeyedActors.set(actorRef, systemId);
|
|
1039
|
+
}
|
|
1296
1040
|
};
|
|
1297
|
-
return
|
|
1041
|
+
return system;
|
|
1298
1042
|
}
|
|
1299
1043
|
|
|
1300
|
-
function
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1044
|
+
let ActorStatus = /*#__PURE__*/function (ActorStatus) {
|
|
1045
|
+
ActorStatus[ActorStatus["NotStarted"] = 0] = "NotStarted";
|
|
1046
|
+
ActorStatus[ActorStatus["Running"] = 1] = "Running";
|
|
1047
|
+
ActorStatus[ActorStatus["Stopped"] = 2] = "Stopped";
|
|
1048
|
+
return ActorStatus;
|
|
1049
|
+
}({});
|
|
1050
|
+
const defaultOptions = {
|
|
1051
|
+
deferEvents: true,
|
|
1052
|
+
clock: {
|
|
1053
|
+
setTimeout: (fn, ms) => {
|
|
1054
|
+
return setTimeout(fn, ms);
|
|
1309
1055
|
},
|
|
1310
|
-
|
|
1311
|
-
|
|
1056
|
+
clearTimeout: id => {
|
|
1057
|
+
return clearTimeout(id);
|
|
1058
|
+
}
|
|
1059
|
+
},
|
|
1060
|
+
logger: console.log.bind(console),
|
|
1061
|
+
devTools: false
|
|
1062
|
+
};
|
|
1063
|
+
class Interpreter {
|
|
1064
|
+
/**
|
|
1065
|
+
* The current state of the interpreted logic.
|
|
1066
|
+
*/
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* The clock that is responsible for setting and clearing timeouts, such as delayed events and transitions.
|
|
1070
|
+
*/
|
|
1071
|
+
|
|
1072
|
+
/**
|
|
1073
|
+
* The unique identifier for this actor relative to its parent.
|
|
1074
|
+
*/
|
|
1075
|
+
|
|
1076
|
+
/**
|
|
1077
|
+
* Whether the service is started.
|
|
1078
|
+
*/
|
|
1079
|
+
|
|
1080
|
+
// Actor Ref
|
|
1081
|
+
|
|
1082
|
+
// TODO: add typings for system
|
|
1083
|
+
|
|
1084
|
+
/**
|
|
1085
|
+
* The globally unique process ID for this invocation.
|
|
1086
|
+
*/
|
|
1087
|
+
|
|
1088
|
+
/**
|
|
1089
|
+
* Creates a new Interpreter instance (i.e., service) for the given logic with the provided options, if any.
|
|
1090
|
+
*
|
|
1091
|
+
* @param logic The logic to be interpreted
|
|
1092
|
+
* @param options Interpreter options
|
|
1093
|
+
*/
|
|
1094
|
+
constructor(logic, options) {
|
|
1095
|
+
this.logic = logic;
|
|
1096
|
+
this._state = void 0;
|
|
1097
|
+
this.clock = void 0;
|
|
1098
|
+
this.options = void 0;
|
|
1099
|
+
this.id = void 0;
|
|
1100
|
+
this.mailbox = new Mailbox(this._process.bind(this));
|
|
1101
|
+
this.delayedEventsMap = {};
|
|
1102
|
+
this.observers = new Set();
|
|
1103
|
+
this.logger = void 0;
|
|
1104
|
+
this.status = ActorStatus.NotStarted;
|
|
1105
|
+
this._parent = void 0;
|
|
1106
|
+
this.ref = void 0;
|
|
1107
|
+
this._actorContext = void 0;
|
|
1108
|
+
this._systemId = void 0;
|
|
1109
|
+
this.sessionId = void 0;
|
|
1110
|
+
this.system = void 0;
|
|
1111
|
+
this._doneEvent = void 0;
|
|
1112
|
+
this.src = void 0;
|
|
1113
|
+
this._deferred = [];
|
|
1114
|
+
const resolvedOptions = {
|
|
1115
|
+
...defaultOptions,
|
|
1116
|
+
...options
|
|
1117
|
+
};
|
|
1118
|
+
const {
|
|
1119
|
+
clock,
|
|
1120
|
+
logger,
|
|
1121
|
+
parent,
|
|
1312
1122
|
id,
|
|
1313
|
-
|
|
1314
|
-
}
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1123
|
+
systemId
|
|
1124
|
+
} = resolvedOptions;
|
|
1125
|
+
const self = this;
|
|
1126
|
+
this.system = parent?.system ?? createSystem();
|
|
1127
|
+
if (systemId) {
|
|
1128
|
+
this._systemId = systemId;
|
|
1129
|
+
this.system._set(systemId, this);
|
|
1130
|
+
}
|
|
1131
|
+
this.sessionId = this.system._bookId();
|
|
1132
|
+
this.id = id ?? this.sessionId;
|
|
1133
|
+
this.logger = logger;
|
|
1134
|
+
this.clock = clock;
|
|
1135
|
+
this._parent = parent;
|
|
1136
|
+
this.options = resolvedOptions;
|
|
1137
|
+
this.src = resolvedOptions.src;
|
|
1138
|
+
this.ref = this;
|
|
1139
|
+
this._actorContext = {
|
|
1140
|
+
self,
|
|
1141
|
+
id: this.id,
|
|
1142
|
+
sessionId: this.sessionId,
|
|
1143
|
+
logger: this.logger,
|
|
1144
|
+
defer: fn => {
|
|
1145
|
+
this._deferred.push(fn);
|
|
1146
|
+
},
|
|
1147
|
+
system: this.system,
|
|
1148
|
+
stopChild: child => {
|
|
1149
|
+
if (child._parent !== this) {
|
|
1150
|
+
throw new Error(`Cannot stop child actor ${child.id} of ${this.id} because it is not a child`);
|
|
1337
1151
|
}
|
|
1338
|
-
|
|
1152
|
+
child._stop();
|
|
1153
|
+
}
|
|
1154
|
+
};
|
|
1155
|
+
|
|
1156
|
+
// Ensure that the send method is bound to this interpreter instance
|
|
1157
|
+
// if destructured
|
|
1158
|
+
this.send = this.send.bind(this);
|
|
1159
|
+
this._initState();
|
|
1160
|
+
}
|
|
1161
|
+
_initState() {
|
|
1162
|
+
this._state = this.options.state ? this.logic.restoreState ? this.logic.restoreState(this.options.state, this._actorContext) : this.options.state : this.logic.getInitialState(this._actorContext, this.options?.input);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
// array of functions to defer
|
|
1166
|
+
|
|
1167
|
+
update(state) {
|
|
1168
|
+
// Update state
|
|
1169
|
+
this._state = state;
|
|
1170
|
+
const snapshot = this.getSnapshot();
|
|
1171
|
+
|
|
1172
|
+
// Execute deferred effects
|
|
1173
|
+
let deferredFn;
|
|
1174
|
+
while (deferredFn = this._deferred.shift()) {
|
|
1175
|
+
deferredFn();
|
|
1176
|
+
}
|
|
1177
|
+
for (const observer of this.observers) {
|
|
1178
|
+
observer.next?.(snapshot);
|
|
1179
|
+
}
|
|
1180
|
+
const status = this.logic.getStatus?.(state);
|
|
1181
|
+
switch (status?.status) {
|
|
1182
|
+
case 'done':
|
|
1183
|
+
this._stopProcedure();
|
|
1184
|
+
this._doneEvent = doneInvoke(this.id, status.data);
|
|
1185
|
+
this._parent?.send(this._doneEvent);
|
|
1186
|
+
this._complete();
|
|
1187
|
+
break;
|
|
1188
|
+
case 'error':
|
|
1189
|
+
this._stopProcedure();
|
|
1190
|
+
this._parent?.send(error(this.id, status.data));
|
|
1191
|
+
this._error(status.data);
|
|
1192
|
+
break;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
subscribe(nextListenerOrObserver, errorListener, completeListener) {
|
|
1196
|
+
const observer = toObserver(nextListenerOrObserver, errorListener, completeListener);
|
|
1197
|
+
this.observers.add(observer);
|
|
1198
|
+
if (this.status === ActorStatus.Stopped) {
|
|
1199
|
+
observer.complete?.();
|
|
1200
|
+
this.observers.delete(observer);
|
|
1201
|
+
}
|
|
1202
|
+
return {
|
|
1203
|
+
unsubscribe: () => {
|
|
1204
|
+
this.observers.delete(observer);
|
|
1339
1205
|
}
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
/**
|
|
1210
|
+
* Starts the interpreter from the initial state
|
|
1211
|
+
*/
|
|
1212
|
+
start() {
|
|
1213
|
+
if (this.status === ActorStatus.Running) {
|
|
1214
|
+
// Do not restart the service if it is already started
|
|
1215
|
+
return this;
|
|
1216
|
+
}
|
|
1217
|
+
this.system._register(this.sessionId, this);
|
|
1218
|
+
if (this._systemId) {
|
|
1219
|
+
this.system._set(this._systemId, this);
|
|
1220
|
+
}
|
|
1221
|
+
this.status = ActorStatus.Running;
|
|
1222
|
+
if (this.logic.start) {
|
|
1223
|
+
this.logic.start(this._state, this._actorContext);
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
// TODO: this notifies all subscribers but usually this is redundant
|
|
1227
|
+
// there is no real change happening here
|
|
1228
|
+
// we need to rethink if this needs to be refactored
|
|
1229
|
+
this.update(this._state);
|
|
1230
|
+
if (this.options.devTools) {
|
|
1231
|
+
this.attachDevTools();
|
|
1232
|
+
}
|
|
1233
|
+
this.mailbox.start();
|
|
1234
|
+
return this;
|
|
1235
|
+
}
|
|
1236
|
+
_process(event) {
|
|
1237
|
+
try {
|
|
1238
|
+
const nextState = this.logic.transition(this._state, event, this._actorContext);
|
|
1239
|
+
this.update(nextState);
|
|
1340
1240
|
if (event.type === stopSignalType) {
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
state.dispose();
|
|
1344
|
-
}
|
|
1345
|
-
return state;
|
|
1241
|
+
this._stopProcedure();
|
|
1242
|
+
this._complete();
|
|
1346
1243
|
}
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1244
|
+
} catch (err) {
|
|
1245
|
+
// TODO: properly handle errors
|
|
1246
|
+
if (this.observers.size > 0) {
|
|
1247
|
+
this.observers.forEach(observer => {
|
|
1248
|
+
observer.error?.(err);
|
|
1249
|
+
});
|
|
1250
|
+
this.stop();
|
|
1251
|
+
} else {
|
|
1252
|
+
throw err;
|
|
1350
1253
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
return
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
}
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
_stop() {
|
|
1257
|
+
if (this.status === ActorStatus.Stopped) {
|
|
1258
|
+
return this;
|
|
1259
|
+
}
|
|
1260
|
+
this.mailbox.clear();
|
|
1261
|
+
if (this.status === ActorStatus.NotStarted) {
|
|
1262
|
+
this.status = ActorStatus.Stopped;
|
|
1263
|
+
return this;
|
|
1264
|
+
}
|
|
1265
|
+
this.mailbox.enqueue({
|
|
1266
|
+
type: stopSignalType
|
|
1267
|
+
});
|
|
1268
|
+
return this;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* Stops the interpreter and unsubscribe all listeners.
|
|
1273
|
+
*/
|
|
1274
|
+
stop() {
|
|
1275
|
+
if (this._parent) {
|
|
1276
|
+
throw new Error('A non-root actor cannot be stopped directly.');
|
|
1277
|
+
}
|
|
1278
|
+
return this._stop();
|
|
1279
|
+
}
|
|
1280
|
+
_complete() {
|
|
1281
|
+
for (const observer of this.observers) {
|
|
1282
|
+
observer.complete?.();
|
|
1283
|
+
}
|
|
1284
|
+
this.observers.clear();
|
|
1285
|
+
}
|
|
1286
|
+
_error(data) {
|
|
1287
|
+
for (const observer of this.observers) {
|
|
1288
|
+
observer.error?.(data);
|
|
1289
|
+
}
|
|
1290
|
+
this.observers.clear();
|
|
1291
|
+
}
|
|
1292
|
+
_stopProcedure() {
|
|
1293
|
+
if (this.status !== ActorStatus.Running) {
|
|
1294
|
+
// Interpreter already stopped; do nothing
|
|
1295
|
+
return this;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// Cancel all delayed events
|
|
1299
|
+
for (const key of Object.keys(this.delayedEventsMap)) {
|
|
1300
|
+
this.clock.clearTimeout(this.delayedEventsMap[key]);
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// TODO: mailbox.reset
|
|
1304
|
+
this.mailbox.clear();
|
|
1305
|
+
// TODO: after `stop` we must prepare ourselves for receiving events again
|
|
1306
|
+
// events sent *after* stop signal must be queued
|
|
1307
|
+
// it seems like this should be the common behavior for all of our consumers
|
|
1308
|
+
// so perhaps this should be unified somehow for all of them
|
|
1309
|
+
this.mailbox = new Mailbox(this._process.bind(this));
|
|
1310
|
+
this.status = ActorStatus.Stopped;
|
|
1311
|
+
this.system._unregister(this);
|
|
1312
|
+
return this;
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* Sends an event to the running interpreter to trigger a transition.
|
|
1317
|
+
*
|
|
1318
|
+
* @param event The event to send
|
|
1319
|
+
*/
|
|
1320
|
+
send(event) {
|
|
1321
|
+
if (typeof event === 'string') {
|
|
1322
|
+
throw new Error(`Only event objects may be sent to actors; use .send({ type: "${event}" }) instead`);
|
|
1323
|
+
}
|
|
1324
|
+
if (this.status === ActorStatus.Stopped) {
|
|
1325
|
+
return;
|
|
1326
|
+
}
|
|
1327
|
+
if (this.status !== ActorStatus.Running && !this.options.deferEvents) {
|
|
1328
|
+
throw new Error(`Event "${event.type}" was sent to uninitialized actor "${this.id
|
|
1329
|
+
// tslint:disable-next-line:max-line-length
|
|
1330
|
+
}". Make sure .start() is called for this actor, or set { deferEvents: true } in the actor options.\nEvent: ${JSON.stringify(event)}`);
|
|
1331
|
+
}
|
|
1332
|
+
this.mailbox.enqueue(event);
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
// TODO: make private (and figure out a way to do this within the machine)
|
|
1336
|
+
delaySend(sendAction) {
|
|
1337
|
+
this.delayedEventsMap[sendAction.params.id] = this.clock.setTimeout(() => {
|
|
1338
|
+
if ('to' in sendAction.params && sendAction.params.to) {
|
|
1339
|
+
sendAction.params.to.send(sendAction.params.event);
|
|
1340
|
+
} else {
|
|
1341
|
+
this.send(sendAction.params.event);
|
|
1342
|
+
}
|
|
1343
|
+
}, sendAction.params.delay);
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
// TODO: make private (and figure out a way to do this within the machine)
|
|
1347
|
+
cancel(sendId) {
|
|
1348
|
+
this.clock.clearTimeout(this.delayedEventsMap[sendId]);
|
|
1349
|
+
delete this.delayedEventsMap[sendId];
|
|
1350
|
+
}
|
|
1351
|
+
attachDevTools() {
|
|
1352
|
+
const {
|
|
1353
|
+
devTools
|
|
1354
|
+
} = this.options;
|
|
1355
|
+
if (devTools) {
|
|
1356
|
+
const resolvedDevToolsAdapter = typeof devTools === 'function' ? devTools : devToolsAdapter;
|
|
1357
|
+
resolvedDevToolsAdapter(this);
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
toJSON() {
|
|
1361
|
+
return {
|
|
1362
|
+
id: this.id
|
|
1363
|
+
};
|
|
1364
|
+
}
|
|
1365
|
+
getPersistedState() {
|
|
1366
|
+
return this.logic.getPersistedState?.(this._state);
|
|
1367
|
+
}
|
|
1368
|
+
[symbolObservable]() {
|
|
1369
|
+
return this;
|
|
1370
|
+
}
|
|
1371
|
+
getSnapshot() {
|
|
1372
|
+
return this.logic.getSnapshot ? this.logic.getSnapshot(this._state) : this._state;
|
|
1373
|
+
}
|
|
1368
1374
|
}
|
|
1369
1375
|
|
|
1370
|
-
const startSignalType = 'xstate.init';
|
|
1371
|
-
const stopSignalType = 'xstate.stop';
|
|
1372
|
-
const startSignal = {
|
|
1373
|
-
type: 'xstate.init'
|
|
1374
|
-
};
|
|
1375
|
-
const stopSignal = {
|
|
1376
|
-
type: 'xstate.stop'
|
|
1377
|
-
};
|
|
1378
1376
|
/**
|
|
1379
|
-
*
|
|
1380
|
-
* as well as an optionally emitted stream of values.
|
|
1377
|
+
* Creates a new Interpreter instance for the given machine with the provided options, if any.
|
|
1381
1378
|
*
|
|
1382
|
-
* @
|
|
1383
|
-
* @
|
|
1379
|
+
* @param machine The machine to interpret
|
|
1380
|
+
* @param options Interpreter options
|
|
1384
1381
|
*/
|
|
1385
1382
|
|
|
1386
|
-
function
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
function isActorRef(item) {
|
|
1390
|
-
return !!item && typeof item === 'object' && typeof item.send === 'function';
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
// TODO: refactor the return type, this could be written in a better way
|
|
1394
|
-
// but it's best to avoid unneccessary breaking changes now
|
|
1395
|
-
// @deprecated use `interpret(actorLogic)` instead
|
|
1396
|
-
function toActorRef(actorRefLike) {
|
|
1397
|
-
return {
|
|
1398
|
-
subscribe: () => ({
|
|
1399
|
-
unsubscribe: () => void 0
|
|
1400
|
-
}),
|
|
1401
|
-
id: 'anonymous',
|
|
1402
|
-
sessionId: '',
|
|
1403
|
-
getSnapshot: () => undefined,
|
|
1404
|
-
[symbolObservable]: function () {
|
|
1405
|
-
return this;
|
|
1406
|
-
},
|
|
1407
|
-
status: ActorStatus.Running,
|
|
1408
|
-
stop: () => void 0,
|
|
1409
|
-
...actorRefLike
|
|
1410
|
-
};
|
|
1411
|
-
}
|
|
1412
|
-
const emptyLogic = fromTransition(_ => undefined, undefined);
|
|
1413
|
-
function createEmptyActor() {
|
|
1414
|
-
return interpret(emptyLogic);
|
|
1383
|
+
function interpret(logic, options) {
|
|
1384
|
+
const interpreter = new Interpreter(logic, options);
|
|
1385
|
+
return interpreter;
|
|
1415
1386
|
}
|
|
1416
1387
|
|
|
1417
1388
|
function invoke(invokeDef) {
|
|
@@ -1428,42 +1399,32 @@ function invoke(invokeDef) {
|
|
|
1428
1399
|
src
|
|
1429
1400
|
} = invokeDef;
|
|
1430
1401
|
let resolvedInvokeAction;
|
|
1431
|
-
|
|
1402
|
+
const referenced = resolveReferencedActor(state.machine.implementations.actors[src]);
|
|
1403
|
+
if (!referenced) {
|
|
1404
|
+
resolvedInvokeAction = {
|
|
1405
|
+
type,
|
|
1406
|
+
params: invokeDef
|
|
1407
|
+
};
|
|
1408
|
+
} else {
|
|
1409
|
+
const input = 'input' in invokeDef ? invokeDef.input : referenced.input;
|
|
1410
|
+
const ref = interpret(referenced.src, {
|
|
1411
|
+
id,
|
|
1412
|
+
src,
|
|
1413
|
+
parent: actorContext?.self,
|
|
1414
|
+
systemId: invokeDef.systemId,
|
|
1415
|
+
input: typeof input === 'function' ? input({
|
|
1416
|
+
context: state.context,
|
|
1417
|
+
event,
|
|
1418
|
+
self: actorContext?.self
|
|
1419
|
+
}) : input
|
|
1420
|
+
});
|
|
1432
1421
|
resolvedInvokeAction = {
|
|
1433
1422
|
type,
|
|
1434
1423
|
params: {
|
|
1435
1424
|
...invokeDef,
|
|
1436
|
-
ref
|
|
1425
|
+
ref
|
|
1437
1426
|
}
|
|
1438
1427
|
};
|
|
1439
|
-
} else {
|
|
1440
|
-
const referenced = resolveReferencedActor(state.machine.implementations.actors[src]);
|
|
1441
|
-
if (!referenced) {
|
|
1442
|
-
resolvedInvokeAction = {
|
|
1443
|
-
type,
|
|
1444
|
-
params: invokeDef
|
|
1445
|
-
};
|
|
1446
|
-
} else {
|
|
1447
|
-
const input = 'input' in invokeDef ? invokeDef.input : referenced.input;
|
|
1448
|
-
const ref = interpret(referenced.src, {
|
|
1449
|
-
id,
|
|
1450
|
-
src,
|
|
1451
|
-
parent: actorContext?.self,
|
|
1452
|
-
systemId: invokeDef.systemId,
|
|
1453
|
-
input: typeof input === 'function' ? input({
|
|
1454
|
-
context: state.context,
|
|
1455
|
-
event,
|
|
1456
|
-
self: actorContext?.self
|
|
1457
|
-
}) : input
|
|
1458
|
-
});
|
|
1459
|
-
resolvedInvokeAction = {
|
|
1460
|
-
type,
|
|
1461
|
-
params: {
|
|
1462
|
-
...invokeDef,
|
|
1463
|
-
ref
|
|
1464
|
-
}
|
|
1465
|
-
};
|
|
1466
|
-
}
|
|
1467
1428
|
}
|
|
1468
1429
|
const actorRef = resolvedInvokeAction.params.ref;
|
|
1469
1430
|
const invokedState = cloneState(state, {
|
|
@@ -2454,7 +2415,7 @@ function resolveActionsAndContext(actions, event, currentState, actorCtx) {
|
|
|
2454
2415
|
});
|
|
2455
2416
|
const matchedActions = resolvedAction.params?.actions;
|
|
2456
2417
|
intermediateState = nextState;
|
|
2457
|
-
if (
|
|
2418
|
+
if (resolvedAction.type === raise$1 && typeof resolvedAction.params.delay !== 'number') {
|
|
2458
2419
|
raiseActions.push(resolvedAction);
|
|
2459
2420
|
}
|
|
2460
2421
|
|
|
@@ -2766,11 +2727,14 @@ function stop(actorRef) {
|
|
|
2766
2727
|
actor
|
|
2767
2728
|
}
|
|
2768
2729
|
}, (event, {
|
|
2769
|
-
state
|
|
2730
|
+
state,
|
|
2731
|
+
actorContext
|
|
2770
2732
|
}) => {
|
|
2771
2733
|
const actorRefOrString = isFunction(actor) ? actor({
|
|
2772
2734
|
context: state.context,
|
|
2773
|
-
event
|
|
2735
|
+
event,
|
|
2736
|
+
self: actorContext?.self ?? {},
|
|
2737
|
+
system: actorContext?.system
|
|
2774
2738
|
}) : actor;
|
|
2775
2739
|
const actorRef = typeof actorRefOrString === 'string' ? state.children[actorRefOrString] : actorRefOrString;
|
|
2776
2740
|
let children = state.children;
|
|
@@ -2854,59 +2818,60 @@ function log(expr = defaultLogExpr, label) {
|
|
|
2854
2818
|
});
|
|
2855
2819
|
}
|
|
2856
2820
|
|
|
2857
|
-
function createSpawner(
|
|
2858
|
-
|
|
2821
|
+
function createSpawner(actorContext, {
|
|
2822
|
+
machine,
|
|
2823
|
+
context
|
|
2824
|
+
}, event, spawnedChildren) {
|
|
2825
|
+
const spawn = (src, options = {}) => {
|
|
2859
2826
|
const {
|
|
2860
2827
|
systemId
|
|
2861
2828
|
} = options;
|
|
2862
|
-
if (
|
|
2829
|
+
if (typeof src === 'string') {
|
|
2863
2830
|
const referenced = resolveReferencedActor(machine.implementations.actors[src]);
|
|
2864
|
-
if (referenced) {
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
ref: actorRef,
|
|
2883
|
-
meta: undefined,
|
|
2884
|
-
input,
|
|
2885
|
-
systemId
|
|
2886
|
-
}));
|
|
2887
|
-
return actorRef; // TODO: fix types
|
|
2888
|
-
}
|
|
2889
|
-
|
|
2890
|
-
throw new Error(`Actor logic '${src}' not implemented in machine '${machine.id}'`);
|
|
2831
|
+
if (!referenced) {
|
|
2832
|
+
throw new Error(`Actor logic '${src}' not implemented in machine '${machine.id}'`);
|
|
2833
|
+
}
|
|
2834
|
+
const input = 'input' in options ? options.input : referenced.input;
|
|
2835
|
+
|
|
2836
|
+
// TODO: this should also receive `src`
|
|
2837
|
+
const actor = interpret(referenced.src, {
|
|
2838
|
+
id: options.id,
|
|
2839
|
+
parent: actorContext.self,
|
|
2840
|
+
input: typeof input === 'function' ? input({
|
|
2841
|
+
context,
|
|
2842
|
+
event,
|
|
2843
|
+
self: actorContext.self
|
|
2844
|
+
}) : input,
|
|
2845
|
+
systemId
|
|
2846
|
+
});
|
|
2847
|
+
spawnedChildren[actor.id] = actor;
|
|
2848
|
+
return actor;
|
|
2891
2849
|
} else {
|
|
2892
2850
|
// TODO: this should also receive `src`
|
|
2893
|
-
|
|
2851
|
+
return interpret(src, {
|
|
2894
2852
|
id: options.id,
|
|
2895
|
-
parent: self,
|
|
2853
|
+
parent: actorContext.self,
|
|
2896
2854
|
input: options.input,
|
|
2897
2855
|
systemId
|
|
2898
2856
|
});
|
|
2899
|
-
mutCapturedActions.push(invoke({
|
|
2900
|
-
// @ts-ignore TODO: fix types
|
|
2901
|
-
src: actorRef,
|
|
2902
|
-
ref: actorRef,
|
|
2903
|
-
id: actorRef.id,
|
|
2904
|
-
meta: undefined,
|
|
2905
|
-
input: options.input
|
|
2906
|
-
}));
|
|
2907
|
-
return actorRef; // TODO: fix types
|
|
2908
2857
|
}
|
|
2909
2858
|
};
|
|
2859
|
+
return (src, options) => {
|
|
2860
|
+
const actorRef = spawn(src, options);
|
|
2861
|
+
spawnedChildren[actorRef.id] = actorRef;
|
|
2862
|
+
actorContext.defer(() => {
|
|
2863
|
+
if (actorRef.status === ActorStatus.Stopped) {
|
|
2864
|
+
return;
|
|
2865
|
+
}
|
|
2866
|
+
try {
|
|
2867
|
+
actorRef.start?.();
|
|
2868
|
+
} catch (err) {
|
|
2869
|
+
actorContext.self.send(error(actorRef.id, err));
|
|
2870
|
+
return;
|
|
2871
|
+
}
|
|
2872
|
+
});
|
|
2873
|
+
return actorRef;
|
|
2874
|
+
};
|
|
2910
2875
|
}
|
|
2911
2876
|
|
|
2912
2877
|
/**
|
|
@@ -2925,15 +2890,15 @@ function assign(assignment) {
|
|
|
2925
2890
|
action,
|
|
2926
2891
|
actorContext
|
|
2927
2892
|
}) => {
|
|
2928
|
-
const capturedActions = [];
|
|
2929
2893
|
if (!state.context) {
|
|
2930
2894
|
throw new Error('Cannot assign to undefined `context`. Ensure that `context` is defined in the machine config.');
|
|
2931
2895
|
}
|
|
2896
|
+
const spawnedChildren = {};
|
|
2932
2897
|
const args = {
|
|
2933
2898
|
context: state.context,
|
|
2934
2899
|
event,
|
|
2935
2900
|
action,
|
|
2936
|
-
spawn: createSpawner(actorContext
|
|
2901
|
+
spawn: createSpawner(actorContext, state, event, spawnedChildren),
|
|
2937
2902
|
self: actorContext?.self ?? {},
|
|
2938
2903
|
system: actorContext?.system
|
|
2939
2904
|
};
|
|
@@ -2948,12 +2913,15 @@ function assign(assignment) {
|
|
|
2948
2913
|
}
|
|
2949
2914
|
const updatedContext = Object.assign({}, state.context, partialUpdate);
|
|
2950
2915
|
return [cloneState(state, {
|
|
2951
|
-
context: updatedContext
|
|
2916
|
+
context: updatedContext,
|
|
2917
|
+
children: Object.keys(spawnedChildren).length ? {
|
|
2918
|
+
...state.children,
|
|
2919
|
+
...spawnedChildren
|
|
2920
|
+
} : state.children
|
|
2952
2921
|
}), {
|
|
2953
2922
|
type: assign$1,
|
|
2954
2923
|
params: {
|
|
2955
|
-
context: updatedContext
|
|
2956
|
-
actions: capturedActions
|
|
2924
|
+
context: updatedContext
|
|
2957
2925
|
}
|
|
2958
2926
|
}];
|
|
2959
2927
|
});
|
|
@@ -3064,9 +3032,6 @@ function pure(getActions) {
|
|
|
3064
3032
|
});
|
|
3065
3033
|
}
|
|
3066
3034
|
|
|
3067
|
-
const initEvent = {
|
|
3068
|
-
type: init
|
|
3069
|
-
};
|
|
3070
3035
|
function resolveActionObject(actionObject, actionFunctionMap) {
|
|
3071
3036
|
if (isDynamicAction(actionObject)) {
|
|
3072
3037
|
return actionObject;
|
|
@@ -3211,4 +3176,4 @@ function createInitEvent(input) {
|
|
|
3211
3176
|
};
|
|
3212
3177
|
}
|
|
3213
3178
|
|
|
3214
|
-
export {
|
|
3179
|
+
export { fromPromise as $, assign as A, microstep as B, isAtomicStateNode as C, error as D, isStateId as E, getStateNodeByPath as F, getPersistedState as G, resolveReferencedActor as H, interpret as I, createInitEvent as J, matchesState as K, sendTo as L, sendParent as M, NULL_EVENT as N, forwardTo as O, Interpreter as P, ActorStatus as Q, doneInvoke as R, STATE_DELIMITER as S, cancel as T, choose as U, log as V, pure as W, raise as X, stop as Y, pathToStateValue as Z, toObserver as _, toArray as a, fromObservable as a0, fromCallback as a1, fromEventObservable as a2, fromTransition as a3, stateIn as a4, not as a5, and as a6, or as a7, ActionTypes as a8, SpecialTargets as a9, startSignalType as aa, stopSignalType as ab, startSignal as ac, stopSignal as ad, isSignal as ae, isActorRef as af, toActorRef as ag, createEmptyActor as ah, toGuardDefinition as ai, actionTypes as aj, resolveActionObject as ak, toActionObject as al, after as am, done as an, escalate as ao, toTransitionConfigArray as b, formatTransition as c, memo as d, evaluateGuard as e, formatTransitions as f, flatten as g, createInvokeId as h, isString as i, invoke$1 as j, getDelayedTransitions as k, formatInitialTransition as l, mapValues as m, getCandidates as n, toInvokeConfig as o, getConfiguration as p, getStateNodes as q, resolveStateValue as r, isInFinalState as s, toActionObjects as t, State as u, isErrorEvent as v, macrostep as w, transitionNode as x, getInitialConfiguration as y, resolveActionsAndContext as z };
|