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