xstate 5.0.0-beta.49 → 5.0.0-beta.50
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 +2 -2
- package/actions/dist/xstate-actions.development.cjs.js +2 -2
- package/actions/dist/xstate-actions.development.esm.js +2 -2
- package/actions/dist/xstate-actions.esm.js +2 -2
- 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 +2 -4
- package/actors/dist/xstate-actors.development.cjs.js +2 -4
- package/actors/dist/xstate-actors.development.esm.js +2 -4
- package/actors/dist/xstate-actors.esm.js +2 -4
- package/actors/dist/xstate-actors.umd.min.js +1 -1
- package/actors/dist/xstate-actors.umd.min.js.map +1 -1
- package/dist/declarations/src/actors/callback.d.ts +5 -5
- package/dist/declarations/src/actors/observable.d.ts +5 -5
- package/dist/declarations/src/actors/promise.d.ts +2 -2
- package/dist/declarations/src/actors/transition.d.ts +3 -3
- package/dist/declarations/src/interpreter.d.ts +1 -0
- package/dist/declarations/src/setup.d.ts +2 -2
- package/dist/declarations/src/types.d.ts +5 -3
- package/dist/{raise-e4cc6d4f.esm.js → raise-32ec7226.esm.js} +92 -27
- package/dist/{raise-1873c645.development.esm.js → raise-6c05c91b.development.esm.js} +92 -27
- package/dist/{raise-8f9c4a5a.cjs.js → raise-8176cd35.cjs.js} +91 -27
- package/dist/{raise-495f4b9f.development.cjs.js → raise-dc9c2c58.development.cjs.js} +91 -27
- package/dist/{send-0a381ca2.development.esm.js → send-2b001f05.development.esm.js} +2 -7
- package/dist/{send-8ed5c8b2.cjs.js → send-7f3db830.cjs.js} +2 -7
- package/dist/{send-22880315.esm.js → send-88351a33.esm.js} +2 -7
- package/dist/{send-8d30b415.development.cjs.js → send-df1c8ef2.development.cjs.js} +2 -7
- package/dist/xstate.cjs.js +3 -13
- package/dist/xstate.development.cjs.js +3 -13
- package/dist/xstate.development.esm.js +5 -15
- package/dist/xstate.esm.js +5 -15
- 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
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ActorLogic, ActorRefFrom, ActorSystem, AnyActorSystem, Snapshot } from "../types.js";
|
|
2
1
|
import { XSTATE_STOP } from "../constants.js";
|
|
2
|
+
import { ActorLogic, ActorRefFrom, ActorSystem, AnyActorSystem, NonReducibleUnknown, Snapshot } from "../types.js";
|
|
3
3
|
export type PromiseSnapshot<TOutput, TInput> = Snapshot<TOutput> & {
|
|
4
4
|
input: TInput | undefined;
|
|
5
5
|
};
|
|
@@ -64,7 +64,7 @@ export type PromiseActorRef<TOutput> = ActorRefFrom<PromiseActorLogic<TOutput, u
|
|
|
64
64
|
* // }
|
|
65
65
|
* ```
|
|
66
66
|
*/
|
|
67
|
-
export declare function fromPromise<TOutput, TInput =
|
|
67
|
+
export declare function fromPromise<TOutput, TInput = NonReducibleUnknown>(promiseCreator: ({ input, system }: {
|
|
68
68
|
/**
|
|
69
69
|
* Data that was provided to the promise actor
|
|
70
70
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ActorLogic, ActorScope, ActorSystem, EventObject, ActorRefFrom, AnyActorSystem, Snapshot } from "../types.js";
|
|
1
|
+
import { ActorLogic, ActorScope, ActorSystem, EventObject, ActorRefFrom, AnyActorSystem, Snapshot, NonReducibleUnknown } from "../types.js";
|
|
2
2
|
export type TransitionSnapshot<TContext> = Snapshot<undefined> & {
|
|
3
3
|
context: TContext;
|
|
4
4
|
};
|
|
5
|
-
export type TransitionActorLogic<TContext, TEvent extends EventObject, TInput> = ActorLogic<TransitionSnapshot<TContext>, TEvent, TInput, AnyActorSystem>;
|
|
5
|
+
export type TransitionActorLogic<TContext, TEvent extends EventObject, TInput extends NonReducibleUnknown> = ActorLogic<TransitionSnapshot<TContext>, TEvent, TInput, AnyActorSystem>;
|
|
6
6
|
export type TransitionActorRef<TContext, TEvent extends EventObject> = ActorRefFrom<TransitionActorLogic<TransitionSnapshot<TContext>, TEvent, unknown>>;
|
|
7
7
|
/**
|
|
8
8
|
* Returns actor logic given a transition function and its initial state.
|
|
@@ -62,7 +62,7 @@ export type TransitionActorRef<TContext, TEvent extends EventObject> = ActorRefF
|
|
|
62
62
|
* // }
|
|
63
63
|
* ```
|
|
64
64
|
*/
|
|
65
|
-
export declare function fromTransition<TContext, TEvent extends EventObject, TSystem extends ActorSystem<any>, TInput>(transition: (state: TContext, event: TEvent, actorScope: ActorScope<TransitionSnapshot<TContext>, TEvent, TSystem>) => TContext, initialContext: TContext | (({ input, self }: {
|
|
65
|
+
export declare function fromTransition<TContext, TEvent extends EventObject, TSystem extends ActorSystem<any>, TInput extends NonReducibleUnknown>(transition: (state: TContext, event: TEvent, actorScope: ActorScope<TransitionSnapshot<TContext>, TEvent, TSystem>) => TContext, initialContext: TContext | (({ input, self }: {
|
|
66
66
|
input: TInput;
|
|
67
67
|
self: TransitionActorRef<TContext, TEvent>;
|
|
68
68
|
}) => TContext)): TransitionActorLogic<TContext, TEvent, TInput>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { StateMachine } from "./StateMachine.js";
|
|
2
2
|
import { GuardPredicate } from "./guards.js";
|
|
3
3
|
import { ResolveTypegenMeta, TypegenDisabled } from "./typegenTypes.js";
|
|
4
|
-
import { ActionFunction, AnyActorLogic, AnyActorRef, AnyEventObject, Cast, ConditionalRequired, DelayConfig, Invert, IsNever, MachineConfig, MachineContext, NonReducibleUnknown, ParameterizedObject, SetupTypes, StateSchema, ToChildren, Values } from "./types.js";
|
|
4
|
+
import { ActionFunction, AnyActorLogic, AnyActorRef, AnyEventObject, Cast, ConditionalRequired, DelayConfig, Invert, IsNever, MachineConfig, MachineContext, NonReducibleUnknown, ParameterizedObject, SetupTypes, StateSchema, ToChildren, UnknownActorLogic, Values } from "./types.js";
|
|
5
5
|
type ToParameterizedObject<TParameterizedMap extends Record<string, ParameterizedObject['params'] | undefined>> = Values<{
|
|
6
6
|
[K in keyof TParameterizedMap & string]: {
|
|
7
7
|
type: K;
|
|
@@ -33,7 +33,7 @@ type ToStateValue<T extends StateSchema> = T extends {
|
|
|
33
33
|
type: 'parallel';
|
|
34
34
|
} ? true : false> : never) : {};
|
|
35
35
|
export declare function setup<TContext extends MachineContext, TEvent extends AnyEventObject, // TODO: consider using a stricter `EventObject` here
|
|
36
|
-
TActors extends Record<Values<TChildrenMap>,
|
|
36
|
+
TActors extends Record<Values<TChildrenMap>, UnknownActorLogic>, TActions extends Record<string, ParameterizedObject['params'] | undefined>, TGuards extends Record<string, ParameterizedObject['params'] | undefined>, TDelay extends string, TTag extends string, TInput, TOutput extends NonReducibleUnknown, TChildrenMap extends Record<string, string> = never>({ actors, actions, guards, delays }: {
|
|
37
37
|
types?: SetupTypes<TContext, TEvent, TChildrenMap, TTag, TInput, TOutput>;
|
|
38
38
|
actors?: TActors;
|
|
39
39
|
actions?: {
|
|
@@ -736,7 +736,7 @@ export interface ActorRef<TEvent extends EventObject, TSnapshot extends Snapshot
|
|
|
736
736
|
id: string;
|
|
737
737
|
sessionId: string;
|
|
738
738
|
send: (event: TEvent) => void;
|
|
739
|
-
start
|
|
739
|
+
start: () => void;
|
|
740
740
|
getSnapshot: () => TSnapshot;
|
|
741
741
|
getPersistedState: () => Snapshot<unknown>;
|
|
742
742
|
stop: () => void;
|
|
@@ -800,7 +800,7 @@ export type Snapshot<TOutput> = {
|
|
|
800
800
|
* @template TInput - The type of the input.
|
|
801
801
|
* @template TSystem - The type of the actor system.
|
|
802
802
|
*/
|
|
803
|
-
export interface ActorLogic<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject, TInput =
|
|
803
|
+
export interface ActorLogic<TSnapshot extends Snapshot<unknown>, TEvent extends EventObject, TInput = NonReducibleUnknown, TSystem extends ActorSystem<any> = ActorSystem<any>> {
|
|
804
804
|
/** The initial setup/configuration used to create the actor logic. */
|
|
805
805
|
config?: unknown;
|
|
806
806
|
/**
|
|
@@ -811,7 +811,7 @@ export interface ActorLogic<TSnapshot extends Snapshot<unknown>, TEvent extends
|
|
|
811
811
|
* @param ctx - The actor scope.
|
|
812
812
|
* @returns The new state.
|
|
813
813
|
*/
|
|
814
|
-
transition: (
|
|
814
|
+
transition: (snapshot: TSnapshot, message: TEvent, ctx: ActorScope<TSnapshot, TEvent, TSystem>) => TSnapshot;
|
|
815
815
|
/**
|
|
816
816
|
* Called to provide the initial state of the actor.
|
|
817
817
|
* @param actorScope - The actor scope.
|
|
@@ -845,6 +845,8 @@ export type AnyActorLogic = ActorLogic<any, // snapshot
|
|
|
845
845
|
any, // event
|
|
846
846
|
any, // input
|
|
847
847
|
any>;
|
|
848
|
+
export type UnknownActorLogic = ActorLogic<any, // this is invariant and it's hard to figure out a better default than `any`
|
|
849
|
+
EventObject, NonReducibleUnknown, ActorSystem<any>>;
|
|
848
850
|
export type SnapshotFrom<T> = ReturnTypeOrValue<T> extends infer R ? R extends ActorRef<infer _, infer TSnapshot> ? TSnapshot : R extends Actor<infer TLogic> ? SnapshotFrom<TLogic> : R extends ActorLogic<infer _, infer __, infer ___, infer ____> ? ReturnType<R['transition']> : R extends ActorScope<infer TSnapshot, infer _, infer __> ? TSnapshot : never : never;
|
|
849
851
|
export type EventFromLogic<TLogic extends ActorLogic<any, any, any, any>> = TLogic extends ActorLogic<infer _, infer TEvent, infer __, infer _____> ? TEvent : never;
|
|
850
852
|
type ResolveEventType<T> = ReturnTypeOrValue<T> extends infer R ? R extends StateMachine<infer _TContext, infer TEvent, infer _TChildren, infer _TActor, infer _TAction, infer _TGuard, infer _TDelay, infer _TStateValue, infer _TTag, infer _TInput, infer _TOutput, infer _TResolvedTypesMeta> ? TEvent : R extends MachineSnapshot<infer _TContext, infer TEvent, infer _TChildren, infer _TTag, infer _TOutput, infer _TResolvedTypesMeta> ? TEvent : R extends ActorRef<infer TEvent, infer _> ? TEvent : never : never;
|
|
@@ -449,7 +449,18 @@ class Actor {
|
|
|
449
449
|
}
|
|
450
450
|
}
|
|
451
451
|
_initState(persistedState) {
|
|
452
|
-
|
|
452
|
+
try {
|
|
453
|
+
this._state = persistedState ? this.logic.restoreState ? this.logic.restoreState(persistedState, this._actorScope) : persistedState : this.logic.getInitialState(this._actorScope, this.options?.input);
|
|
454
|
+
} catch (err) {
|
|
455
|
+
// if we get here then it means that we assign a value to this._state that is not of the correct type
|
|
456
|
+
// we can't get the true `TSnapshot & { status: 'error'; }`, it's impossible
|
|
457
|
+
// so right now this is a lie of sorts
|
|
458
|
+
this._state = {
|
|
459
|
+
status: 'error',
|
|
460
|
+
output: undefined,
|
|
461
|
+
error: err
|
|
462
|
+
};
|
|
463
|
+
}
|
|
453
464
|
}
|
|
454
465
|
update(snapshot, event) {
|
|
455
466
|
// Update state
|
|
@@ -458,17 +469,46 @@ class Actor {
|
|
|
458
469
|
// Execute deferred effects
|
|
459
470
|
let deferredFn;
|
|
460
471
|
while (deferredFn = this._deferred.shift()) {
|
|
461
|
-
deferredFn();
|
|
462
|
-
}
|
|
463
|
-
for (const observer of this.observers) {
|
|
464
472
|
try {
|
|
465
|
-
|
|
473
|
+
deferredFn();
|
|
466
474
|
} catch (err) {
|
|
467
|
-
|
|
475
|
+
// this error can only be caught when executing *initial* actions
|
|
476
|
+
// it's the only time when we call actions provided by the user through those deferreds
|
|
477
|
+
// when the actor is already running we always execute them synchronously while transitioning
|
|
478
|
+
// no "builtin deferred" should actually throw an error since they are either safe
|
|
479
|
+
// or the control flow is passed through the mailbox and errors should be caught by the `_process` used by the mailbox
|
|
480
|
+
this._deferred.length = 0;
|
|
481
|
+
this._state = {
|
|
482
|
+
...snapshot,
|
|
483
|
+
status: 'error',
|
|
484
|
+
error: err
|
|
485
|
+
};
|
|
468
486
|
}
|
|
469
487
|
}
|
|
470
488
|
switch (this._state.status) {
|
|
489
|
+
case 'active':
|
|
490
|
+
for (const observer of this.observers) {
|
|
491
|
+
try {
|
|
492
|
+
observer.next?.(snapshot);
|
|
493
|
+
} catch (err) {
|
|
494
|
+
reportUnhandledError(err);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
break;
|
|
471
498
|
case 'done':
|
|
499
|
+
// next observers are meant to be notified about done snapshots
|
|
500
|
+
// this can be seen as something that is different from how observable work
|
|
501
|
+
// but with observables `complete` callback is called without any arguments
|
|
502
|
+
// it's more ergonomic for XState to treat a done snapshot as a "next" value
|
|
503
|
+
// and the completion event as something that is separate,
|
|
504
|
+
// something that merely follows emitting that done snapshot
|
|
505
|
+
for (const observer of this.observers) {
|
|
506
|
+
try {
|
|
507
|
+
observer.next?.(snapshot);
|
|
508
|
+
} catch (err) {
|
|
509
|
+
reportUnhandledError(err);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
472
512
|
this._stopProcedure();
|
|
473
513
|
this._complete();
|
|
474
514
|
this._doneEvent = createDoneActorEvent(this.id, this._state.output);
|
|
@@ -477,11 +517,7 @@ class Actor {
|
|
|
477
517
|
}
|
|
478
518
|
break;
|
|
479
519
|
case 'error':
|
|
480
|
-
this._stopProcedure();
|
|
481
520
|
this._error(this._state.error);
|
|
482
|
-
if (this._parent) {
|
|
483
|
-
this.system._relay(this, this._parent, createErrorActorEvent(this.id, this._state.error));
|
|
484
|
-
}
|
|
485
521
|
break;
|
|
486
522
|
}
|
|
487
523
|
this.system._sendInspectionEvent({
|
|
@@ -571,7 +607,7 @@ class Actor {
|
|
|
571
607
|
this.subscribe({
|
|
572
608
|
next: snapshot => {
|
|
573
609
|
if (snapshot.status === 'active') {
|
|
574
|
-
this.
|
|
610
|
+
this.system._relay(this, this._parent, {
|
|
575
611
|
type: `xstate.snapshot.${this.id}`,
|
|
576
612
|
snapshot
|
|
577
613
|
});
|
|
@@ -600,18 +636,22 @@ class Actor {
|
|
|
600
636
|
// a state machine can be "done" upon initialization (it could reach a final state using initial microsteps)
|
|
601
637
|
// we still need to complete observers, flush deferreds etc
|
|
602
638
|
this.update(this._state, initEvent);
|
|
603
|
-
// fallthrough
|
|
604
|
-
case 'error':
|
|
605
639
|
// TODO: rethink cleanup of observers, mailbox, etc
|
|
606
640
|
return this;
|
|
641
|
+
case 'error':
|
|
642
|
+
this._error(this._state.error);
|
|
643
|
+
return this;
|
|
607
644
|
}
|
|
608
645
|
if (this.logic.start) {
|
|
609
646
|
try {
|
|
610
647
|
this.logic.start(this._state, this._actorScope);
|
|
611
648
|
} catch (err) {
|
|
612
|
-
this.
|
|
649
|
+
this._state = {
|
|
650
|
+
...this._state,
|
|
651
|
+
status: 'error',
|
|
652
|
+
error: err
|
|
653
|
+
};
|
|
613
654
|
this._error(err);
|
|
614
|
-
this._parent?.send(createErrorActorEvent(this.id, err));
|
|
615
655
|
return this;
|
|
616
656
|
}
|
|
617
657
|
}
|
|
@@ -627,7 +667,6 @@ class Actor {
|
|
|
627
667
|
return this;
|
|
628
668
|
}
|
|
629
669
|
_process(event) {
|
|
630
|
-
// TODO: reexamine what happens when an action (or a guard or smth) throws
|
|
631
670
|
let nextState;
|
|
632
671
|
let caughtError;
|
|
633
672
|
try {
|
|
@@ -642,9 +681,12 @@ class Actor {
|
|
|
642
681
|
const {
|
|
643
682
|
err
|
|
644
683
|
} = caughtError;
|
|
645
|
-
this.
|
|
684
|
+
this._state = {
|
|
685
|
+
...this._state,
|
|
686
|
+
status: 'error',
|
|
687
|
+
error: err
|
|
688
|
+
};
|
|
646
689
|
this._error(err);
|
|
647
|
-
this._parent?.send(createErrorActorEvent(this.id, err));
|
|
648
690
|
return;
|
|
649
691
|
}
|
|
650
692
|
this.update(nextState, event);
|
|
@@ -687,7 +729,7 @@ class Actor {
|
|
|
687
729
|
}
|
|
688
730
|
this.observers.clear();
|
|
689
731
|
}
|
|
690
|
-
|
|
732
|
+
_reportError(err) {
|
|
691
733
|
if (!this.observers.size) {
|
|
692
734
|
if (!this._parent) {
|
|
693
735
|
reportUnhandledError(err);
|
|
@@ -709,6 +751,18 @@ class Actor {
|
|
|
709
751
|
reportUnhandledError(err);
|
|
710
752
|
}
|
|
711
753
|
}
|
|
754
|
+
_error(err) {
|
|
755
|
+
this._stopProcedure();
|
|
756
|
+
this._reportError(err);
|
|
757
|
+
if (this._parent) {
|
|
758
|
+
this.system._relay(this, this._parent, createErrorActorEvent(this.id, err));
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
// TODO: atm children don't belong entirely to the actor so
|
|
762
|
+
// in a way - it's not even super aware of them
|
|
763
|
+
// so we can't stop them from here but we really should!
|
|
764
|
+
// right now, they are being stopped within the machine's transition
|
|
765
|
+
// but that could throw and leave us with "orphaned" active actors
|
|
712
766
|
_stopProcedure() {
|
|
713
767
|
if (this._processingStatus !== ProcessingStatus.Running) {
|
|
714
768
|
// Actor already stopped; do nothing
|
|
@@ -954,12 +1008,7 @@ function executeSpawn(actorScope, {
|
|
|
954
1008
|
if (actorRef._processingStatus === ProcessingStatus.Stopped) {
|
|
955
1009
|
return;
|
|
956
1010
|
}
|
|
957
|
-
|
|
958
|
-
actorRef.start?.();
|
|
959
|
-
} catch (err) {
|
|
960
|
-
actorScope.self.send(createErrorActorEvent(id, err));
|
|
961
|
-
return;
|
|
962
|
-
}
|
|
1011
|
+
actorRef.start();
|
|
963
1012
|
});
|
|
964
1013
|
}
|
|
965
1014
|
function spawnChild(...[src, {
|
|
@@ -2014,7 +2063,23 @@ function macrostep(state, event, actorScope, internalQueue = []) {
|
|
|
2014
2063
|
// Assume the state is at rest (no raised events)
|
|
2015
2064
|
// Determine the next state based on the next microstep
|
|
2016
2065
|
if (nextEvent.type !== XSTATE_INIT) {
|
|
2017
|
-
const
|
|
2066
|
+
const currentEvent = nextEvent;
|
|
2067
|
+
const isErr = isErrorActorEvent(currentEvent);
|
|
2068
|
+
const transitions = selectTransitions(currentEvent, nextState);
|
|
2069
|
+
if (isErr && !transitions.length) {
|
|
2070
|
+
// TODO: we should likely only allow transitions selected by very explicit descriptors
|
|
2071
|
+
// `*` shouldn't be matched, likely `xstate.error.*` shouldnt be either
|
|
2072
|
+
// similarly `xstate.error.actor.*` and `xstate.error.actor.todo.*` have to be considered too
|
|
2073
|
+
nextState = cloneMachineSnapshot(state, {
|
|
2074
|
+
status: 'error',
|
|
2075
|
+
error: currentEvent.data
|
|
2076
|
+
});
|
|
2077
|
+
states.push(nextState);
|
|
2078
|
+
return {
|
|
2079
|
+
state: nextState,
|
|
2080
|
+
microstates: states
|
|
2081
|
+
};
|
|
2082
|
+
}
|
|
2018
2083
|
nextState = microstep(transitions, state, actorScope, nextEvent, false, internalQueue);
|
|
2019
2084
|
states.push(nextState);
|
|
2020
2085
|
}
|
|
@@ -2254,4 +2319,4 @@ function raise(eventOrExpr, options) {
|
|
|
2254
2319
|
return raise;
|
|
2255
2320
|
}
|
|
2256
2321
|
|
|
2257
|
-
export { $$ACTOR_TYPE as $,
|
|
2322
|
+
export { $$ACTOR_TYPE as $, Actor as A, interpret as B, isMachineSnapshot as C, matchesState as D, pathToStateValue as E, toObserver as F, getAllOwnEventDescriptors as G, and as H, not as I, or as J, stateIn as K, cancel as L, raise as M, NULL_EVENT as N, stop as O, stopChild as P, spawnChild as Q, ProcessingStatus as R, STATE_DELIMITER as S, cloneMachineSnapshot as T, XSTATE_ERROR as U, createErrorActorEvent as V, XSTATE_STOP as X, toTransitionConfigArray as a, formatTransition as b, createInvokeId as c, formatInitialTransition as d, evaluateGuard as e, formatTransitions as f, getDelayedTransitions as g, getCandidates as h, getAllStateNodes as i, getStateNodes as j, createMachineSnapshot as k, isInFinalState as l, mapValues as m, macrostep as n, transitionNode as o, resolveActionsAndContext as p, createInitEvent as q, resolveStateValue as r, microstep as s, toArray as t, getInitialStateNodes as u, isStateId as v, getStateNodeByPath as w, getPersistedState as x, resolveReferencedActor as y, createActor as z };
|
|
@@ -452,7 +452,18 @@ class Actor {
|
|
|
452
452
|
}
|
|
453
453
|
}
|
|
454
454
|
_initState(persistedState) {
|
|
455
|
-
|
|
455
|
+
try {
|
|
456
|
+
this._state = persistedState ? this.logic.restoreState ? this.logic.restoreState(persistedState, this._actorScope) : persistedState : this.logic.getInitialState(this._actorScope, this.options?.input);
|
|
457
|
+
} catch (err) {
|
|
458
|
+
// if we get here then it means that we assign a value to this._state that is not of the correct type
|
|
459
|
+
// we can't get the true `TSnapshot & { status: 'error'; }`, it's impossible
|
|
460
|
+
// so right now this is a lie of sorts
|
|
461
|
+
this._state = {
|
|
462
|
+
status: 'error',
|
|
463
|
+
output: undefined,
|
|
464
|
+
error: err
|
|
465
|
+
};
|
|
466
|
+
}
|
|
456
467
|
}
|
|
457
468
|
update(snapshot, event) {
|
|
458
469
|
// Update state
|
|
@@ -461,17 +472,46 @@ class Actor {
|
|
|
461
472
|
// Execute deferred effects
|
|
462
473
|
let deferredFn;
|
|
463
474
|
while (deferredFn = this._deferred.shift()) {
|
|
464
|
-
deferredFn();
|
|
465
|
-
}
|
|
466
|
-
for (const observer of this.observers) {
|
|
467
475
|
try {
|
|
468
|
-
|
|
476
|
+
deferredFn();
|
|
469
477
|
} catch (err) {
|
|
470
|
-
|
|
478
|
+
// this error can only be caught when executing *initial* actions
|
|
479
|
+
// it's the only time when we call actions provided by the user through those deferreds
|
|
480
|
+
// when the actor is already running we always execute them synchronously while transitioning
|
|
481
|
+
// no "builtin deferred" should actually throw an error since they are either safe
|
|
482
|
+
// or the control flow is passed through the mailbox and errors should be caught by the `_process` used by the mailbox
|
|
483
|
+
this._deferred.length = 0;
|
|
484
|
+
this._state = {
|
|
485
|
+
...snapshot,
|
|
486
|
+
status: 'error',
|
|
487
|
+
error: err
|
|
488
|
+
};
|
|
471
489
|
}
|
|
472
490
|
}
|
|
473
491
|
switch (this._state.status) {
|
|
492
|
+
case 'active':
|
|
493
|
+
for (const observer of this.observers) {
|
|
494
|
+
try {
|
|
495
|
+
observer.next?.(snapshot);
|
|
496
|
+
} catch (err) {
|
|
497
|
+
reportUnhandledError(err);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
break;
|
|
474
501
|
case 'done':
|
|
502
|
+
// next observers are meant to be notified about done snapshots
|
|
503
|
+
// this can be seen as something that is different from how observable work
|
|
504
|
+
// but with observables `complete` callback is called without any arguments
|
|
505
|
+
// it's more ergonomic for XState to treat a done snapshot as a "next" value
|
|
506
|
+
// and the completion event as something that is separate,
|
|
507
|
+
// something that merely follows emitting that done snapshot
|
|
508
|
+
for (const observer of this.observers) {
|
|
509
|
+
try {
|
|
510
|
+
observer.next?.(snapshot);
|
|
511
|
+
} catch (err) {
|
|
512
|
+
reportUnhandledError(err);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
475
515
|
this._stopProcedure();
|
|
476
516
|
this._complete();
|
|
477
517
|
this._doneEvent = createDoneActorEvent(this.id, this._state.output);
|
|
@@ -480,11 +520,7 @@ class Actor {
|
|
|
480
520
|
}
|
|
481
521
|
break;
|
|
482
522
|
case 'error':
|
|
483
|
-
this._stopProcedure();
|
|
484
523
|
this._error(this._state.error);
|
|
485
|
-
if (this._parent) {
|
|
486
|
-
this.system._relay(this, this._parent, createErrorActorEvent(this.id, this._state.error));
|
|
487
|
-
}
|
|
488
524
|
break;
|
|
489
525
|
}
|
|
490
526
|
this.system._sendInspectionEvent({
|
|
@@ -574,7 +610,7 @@ class Actor {
|
|
|
574
610
|
this.subscribe({
|
|
575
611
|
next: snapshot => {
|
|
576
612
|
if (snapshot.status === 'active') {
|
|
577
|
-
this.
|
|
613
|
+
this.system._relay(this, this._parent, {
|
|
578
614
|
type: `xstate.snapshot.${this.id}`,
|
|
579
615
|
snapshot
|
|
580
616
|
});
|
|
@@ -603,18 +639,22 @@ class Actor {
|
|
|
603
639
|
// a state machine can be "done" upon initialization (it could reach a final state using initial microsteps)
|
|
604
640
|
// we still need to complete observers, flush deferreds etc
|
|
605
641
|
this.update(this._state, initEvent);
|
|
606
|
-
// fallthrough
|
|
607
|
-
case 'error':
|
|
608
642
|
// TODO: rethink cleanup of observers, mailbox, etc
|
|
609
643
|
return this;
|
|
644
|
+
case 'error':
|
|
645
|
+
this._error(this._state.error);
|
|
646
|
+
return this;
|
|
610
647
|
}
|
|
611
648
|
if (this.logic.start) {
|
|
612
649
|
try {
|
|
613
650
|
this.logic.start(this._state, this._actorScope);
|
|
614
651
|
} catch (err) {
|
|
615
|
-
this.
|
|
652
|
+
this._state = {
|
|
653
|
+
...this._state,
|
|
654
|
+
status: 'error',
|
|
655
|
+
error: err
|
|
656
|
+
};
|
|
616
657
|
this._error(err);
|
|
617
|
-
this._parent?.send(createErrorActorEvent(this.id, err));
|
|
618
658
|
return this;
|
|
619
659
|
}
|
|
620
660
|
}
|
|
@@ -630,7 +670,6 @@ class Actor {
|
|
|
630
670
|
return this;
|
|
631
671
|
}
|
|
632
672
|
_process(event) {
|
|
633
|
-
// TODO: reexamine what happens when an action (or a guard or smth) throws
|
|
634
673
|
let nextState;
|
|
635
674
|
let caughtError;
|
|
636
675
|
try {
|
|
@@ -645,9 +684,12 @@ class Actor {
|
|
|
645
684
|
const {
|
|
646
685
|
err
|
|
647
686
|
} = caughtError;
|
|
648
|
-
this.
|
|
687
|
+
this._state = {
|
|
688
|
+
...this._state,
|
|
689
|
+
status: 'error',
|
|
690
|
+
error: err
|
|
691
|
+
};
|
|
649
692
|
this._error(err);
|
|
650
|
-
this._parent?.send(createErrorActorEvent(this.id, err));
|
|
651
693
|
return;
|
|
652
694
|
}
|
|
653
695
|
this.update(nextState, event);
|
|
@@ -690,7 +732,7 @@ class Actor {
|
|
|
690
732
|
}
|
|
691
733
|
this.observers.clear();
|
|
692
734
|
}
|
|
693
|
-
|
|
735
|
+
_reportError(err) {
|
|
694
736
|
if (!this.observers.size) {
|
|
695
737
|
if (!this._parent) {
|
|
696
738
|
reportUnhandledError(err);
|
|
@@ -712,6 +754,18 @@ class Actor {
|
|
|
712
754
|
reportUnhandledError(err);
|
|
713
755
|
}
|
|
714
756
|
}
|
|
757
|
+
_error(err) {
|
|
758
|
+
this._stopProcedure();
|
|
759
|
+
this._reportError(err);
|
|
760
|
+
if (this._parent) {
|
|
761
|
+
this.system._relay(this, this._parent, createErrorActorEvent(this.id, err));
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
// TODO: atm children don't belong entirely to the actor so
|
|
765
|
+
// in a way - it's not even super aware of them
|
|
766
|
+
// so we can't stop them from here but we really should!
|
|
767
|
+
// right now, they are being stopped within the machine's transition
|
|
768
|
+
// but that could throw and leave us with "orphaned" active actors
|
|
715
769
|
_stopProcedure() {
|
|
716
770
|
if (this._processingStatus !== ProcessingStatus.Running) {
|
|
717
771
|
// Actor already stopped; do nothing
|
|
@@ -971,12 +1025,7 @@ function executeSpawn(actorScope, {
|
|
|
971
1025
|
if (actorRef._processingStatus === ProcessingStatus.Stopped) {
|
|
972
1026
|
return;
|
|
973
1027
|
}
|
|
974
|
-
|
|
975
|
-
actorRef.start?.();
|
|
976
|
-
} catch (err) {
|
|
977
|
-
actorScope.self.send(createErrorActorEvent(id, err));
|
|
978
|
-
return;
|
|
979
|
-
}
|
|
1028
|
+
actorRef.start();
|
|
980
1029
|
});
|
|
981
1030
|
}
|
|
982
1031
|
function spawnChild(...[src, {
|
|
@@ -2059,7 +2108,23 @@ function macrostep(state, event, actorScope, internalQueue = []) {
|
|
|
2059
2108
|
// Assume the state is at rest (no raised events)
|
|
2060
2109
|
// Determine the next state based on the next microstep
|
|
2061
2110
|
if (nextEvent.type !== XSTATE_INIT) {
|
|
2062
|
-
const
|
|
2111
|
+
const currentEvent = nextEvent;
|
|
2112
|
+
const isErr = isErrorActorEvent(currentEvent);
|
|
2113
|
+
const transitions = selectTransitions(currentEvent, nextState);
|
|
2114
|
+
if (isErr && !transitions.length) {
|
|
2115
|
+
// TODO: we should likely only allow transitions selected by very explicit descriptors
|
|
2116
|
+
// `*` shouldn't be matched, likely `xstate.error.*` shouldnt be either
|
|
2117
|
+
// similarly `xstate.error.actor.*` and `xstate.error.actor.todo.*` have to be considered too
|
|
2118
|
+
nextState = cloneMachineSnapshot(state, {
|
|
2119
|
+
status: 'error',
|
|
2120
|
+
error: currentEvent.data
|
|
2121
|
+
});
|
|
2122
|
+
states.push(nextState);
|
|
2123
|
+
return {
|
|
2124
|
+
state: nextState,
|
|
2125
|
+
microstates: states
|
|
2126
|
+
};
|
|
2127
|
+
}
|
|
2063
2128
|
nextState = microstep(transitions, state, actorScope, nextEvent, false, internalQueue);
|
|
2064
2129
|
states.push(nextState);
|
|
2065
2130
|
}
|
|
@@ -2308,4 +2373,4 @@ function raise(eventOrExpr, options) {
|
|
|
2308
2373
|
return raise;
|
|
2309
2374
|
}
|
|
2310
2375
|
|
|
2311
|
-
export { $$ACTOR_TYPE as $,
|
|
2376
|
+
export { $$ACTOR_TYPE as $, Actor as A, interpret as B, isMachineSnapshot as C, matchesState as D, pathToStateValue as E, toObserver as F, getAllOwnEventDescriptors as G, and as H, not as I, or as J, stateIn as K, cancel as L, raise as M, NULL_EVENT as N, stop as O, stopChild as P, spawnChild as Q, ProcessingStatus as R, STATE_DELIMITER as S, cloneMachineSnapshot as T, XSTATE_ERROR as U, createErrorActorEvent as V, XSTATE_STOP as X, toTransitionConfigArray as a, formatTransition as b, createInvokeId as c, formatInitialTransition as d, evaluateGuard as e, formatTransitions as f, getDelayedTransitions as g, getCandidates as h, getAllStateNodes as i, getStateNodes as j, createMachineSnapshot as k, isInFinalState as l, mapValues as m, macrostep as n, transitionNode as o, resolveActionsAndContext as p, createInitEvent as q, resolveStateValue as r, microstep as s, toArray as t, getInitialStateNodes as u, isStateId as v, getStateNodeByPath as w, getPersistedState as x, resolveReferencedActor as y, createActor as z };
|