xstate 6.0.0-alpha.8 → 6.0.0-beta.0
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/README.md +223 -78
- package/bin/agent.js +347 -0
- package/bin/xstate.js +52 -0
- package/dist/createActor-25900f76.cjs.js +7015 -0
- package/dist/createActor-551369be.development.esm.js +7175 -0
- package/dist/createActor-a49ae0ce.development.cjs.js +7289 -0
- package/dist/createActor-cbe3abac.esm.js +6902 -0
- package/dist/declarations/src/SimulatedClock.d.ts +2 -1
- package/dist/declarations/src/State.d.ts +66 -5
- package/dist/declarations/src/StateMachine.d.ts +107 -32
- package/dist/declarations/src/StateNode.d.ts +21 -16
- package/dist/declarations/src/actions.d.ts +11 -6
- package/dist/declarations/src/actors/callback.d.ts +11 -2
- package/dist/declarations/src/actors/index.d.ts +6 -5
- package/dist/declarations/src/actors/listener.d.ts +8 -3
- package/dist/declarations/src/actors/logic.d.ts +42 -52
- package/dist/declarations/src/actors/observable.d.ts +15 -2
- package/dist/declarations/src/actors/promise.d.ts +90 -22
- package/dist/declarations/src/actors/subscription.d.ts +9 -3
- package/dist/declarations/src/assert.d.ts +1 -0
- package/dist/declarations/src/base.types.d.ts +102 -0
- package/dist/declarations/src/createActor.d.ts +101 -27
- package/dist/declarations/src/createMachine.d.ts +38 -17
- package/dist/declarations/src/delay.d.ts +8 -0
- package/dist/declarations/src/durable/index.d.ts +231 -0
- package/dist/declarations/src/effectDescriptor.d.ts +95 -0
- package/dist/declarations/src/eventTypes.d.ts +9 -0
- package/dist/declarations/src/fsm/index.d.ts +2 -0
- package/dist/declarations/src/fsm.d.ts +169 -0
- package/dist/declarations/src/graph/adjacency.d.ts +6 -3
- package/dist/declarations/src/graph/graph.d.ts +6 -3
- package/dist/declarations/src/graph/index.d.ts +2 -3
- package/dist/declarations/src/graph/pathFromEvents.d.ts +5 -2
- package/dist/declarations/src/graph/shortestPaths.d.ts +5 -3
- package/dist/declarations/src/graph/simplePaths.d.ts +5 -3
- package/dist/declarations/src/graph/types.d.ts +113 -59
- package/dist/declarations/src/hotSwap.d.ts +18 -0
- package/dist/declarations/src/index.d.ts +28 -19
- package/dist/declarations/src/inspection.d.ts +24 -1
- package/dist/declarations/src/machineFromJSON.d.ts +171 -0
- package/dist/declarations/src/machineSchemas.d.ts +27 -0
- package/dist/declarations/src/machineVersion.types.d.ts +53 -0
- package/dist/declarations/src/machineVersions.d.ts +103 -0
- package/dist/declarations/src/mapState.d.ts +2 -0
- package/dist/declarations/src/persist/index.d.ts +36 -0
- package/dist/declarations/src/persistedSnapshotValidation.d.ts +18 -0
- package/dist/declarations/src/runtimeHelpers.d.ts +43 -0
- package/dist/declarations/src/schema.types.d.ts +31 -4
- package/dist/declarations/src/serialize.d.ts +39 -28
- package/dist/declarations/src/setup.d.ts +1086 -147
- package/dist/declarations/src/spawn.d.ts +6 -4
- package/dist/declarations/src/stateUtils.d.ts +57 -14
- package/dist/declarations/src/system.d.ts +178 -17
- package/dist/declarations/src/systemTransition.d.ts +108 -0
- package/dist/declarations/src/toPromise.d.ts +1 -0
- package/dist/declarations/src/transition.d.ts +48 -10
- package/dist/declarations/src/transitionActions.d.ts +22 -4
- package/dist/declarations/src/typeUtils.d.ts +51 -0
- package/dist/declarations/src/types.d.ts +835 -318
- package/dist/declarations/src/types.v6.d.ts +547 -104
- package/dist/declarations/src/utils.d.ts +38 -8
- package/dist/declarations/src/validation/index.d.ts +49 -0
- package/dist/declarations/src/validation.types.d.ts +29 -0
- package/dist/declarations/src/waitFor.d.ts +1 -0
- package/dist/effectDescriptor-2fa27c54.cjs.js +351 -0
- package/dist/effectDescriptor-321a8ce9.development.esm.js +343 -0
- package/dist/effectDescriptor-d8b0f749.esm.js +343 -0
- package/dist/effectDescriptor-f73da4ec.development.cjs.js +351 -0
- package/dist/machineSchemas-45c21bc2.esm.js +1292 -0
- package/dist/machineSchemas-6d96bef4.development.cjs.js +1379 -0
- package/dist/machineSchemas-88d01821.cjs.js +1300 -0
- package/dist/machineSchemas-b5736804.development.esm.js +1371 -0
- package/dist/schema.types-0ecd17b8.esm.js +71 -0
- package/dist/schema.types-15a68ddc.cjs.js +74 -0
- package/dist/schema.types-1c16f035.development.cjs.js +74 -0
- package/dist/schema.types-1cd4652e.development.esm.js +71 -0
- package/dist/validation-05f1d517.esm.js +8 -0
- package/dist/validation-4561b43c.cjs.js +10 -0
- package/dist/validation-e69470ad.development.esm.js +8 -0
- package/dist/validation-f2714a35.development.cjs.js +10 -0
- package/dist/xstate-actors.cjs.js +1068 -12
- package/dist/xstate-actors.cjs.mjs +2 -4
- package/dist/xstate-actors.development.cjs.js +1068 -12
- package/dist/xstate-actors.development.cjs.mjs +2 -4
- package/dist/xstate-actors.development.esm.js +1064 -1
- package/dist/xstate-actors.esm.js +1064 -1
- package/dist/xstate-actors.umd.min.js +1 -1
- package/dist/xstate-actors.umd.min.js.map +1 -1
- package/dist/xstate-durable.cjs.d.mts +2 -0
- package/dist/xstate-durable.cjs.d.ts +2 -0
- package/dist/xstate-durable.cjs.js +513 -0
- package/dist/xstate-durable.cjs.mjs +5 -0
- package/dist/xstate-durable.development.cjs.js +513 -0
- package/dist/xstate-durable.development.cjs.mjs +5 -0
- package/dist/xstate-durable.development.esm.js +507 -0
- package/dist/xstate-durable.esm.js +507 -0
- package/dist/xstate-durable.umd.min.js +2 -0
- package/dist/xstate-durable.umd.min.js.map +1 -0
- package/dist/xstate-fsm.cjs.d.mts +2 -0
- package/dist/xstate-fsm.cjs.d.ts +2 -0
- package/dist/xstate-fsm.cjs.js +111 -0
- package/dist/xstate-fsm.cjs.mjs +5 -0
- package/dist/xstate-fsm.development.cjs.js +111 -0
- package/dist/xstate-fsm.development.cjs.mjs +5 -0
- package/dist/xstate-fsm.development.esm.js +105 -0
- package/dist/xstate-fsm.esm.js +105 -0
- package/dist/xstate-fsm.umd.min.js +2 -0
- package/dist/xstate-fsm.umd.min.js.map +1 -0
- package/dist/xstate-graph.cjs.js +173 -457
- package/dist/xstate-graph.cjs.mjs +2 -5
- package/dist/xstate-graph.development.cjs.js +173 -457
- package/dist/xstate-graph.development.cjs.mjs +2 -5
- package/dist/xstate-graph.development.esm.js +171 -451
- package/dist/xstate-graph.esm.js +171 -451
- package/dist/xstate-graph.umd.min.js +1 -1
- package/dist/xstate-graph.umd.min.js.map +1 -1
- package/dist/xstate-persist.cjs.d.mts +2 -0
- package/dist/xstate-persist.cjs.d.ts +2 -0
- package/dist/xstate-persist.cjs.js +314 -0
- package/dist/xstate-persist.cjs.mjs +6 -0
- package/dist/xstate-persist.development.cjs.js +325 -0
- package/dist/xstate-persist.development.cjs.mjs +6 -0
- package/dist/xstate-persist.development.esm.js +319 -0
- package/dist/xstate-persist.esm.js +308 -0
- package/dist/xstate-persist.umd.min.js +2 -0
- package/dist/xstate-persist.umd.min.js.map +1 -0
- package/dist/xstate-validation.cjs.d.mts +2 -0
- package/dist/xstate-validation.cjs.d.ts +2 -0
- package/dist/xstate-validation.cjs.js +330 -0
- package/dist/xstate-validation.cjs.mjs +5 -0
- package/dist/xstate-validation.development.cjs.js +330 -0
- package/dist/xstate-validation.development.cjs.mjs +5 -0
- package/dist/xstate-validation.development.esm.js +324 -0
- package/dist/xstate-validation.esm.js +324 -0
- package/dist/xstate-validation.umd.min.js +2 -0
- package/dist/xstate-validation.umd.min.js.map +1 -0
- package/dist/xstate.cjs.js +2486 -1430
- package/dist/xstate.cjs.mjs +23 -13
- package/dist/xstate.development.cjs.js +2486 -1430
- package/dist/xstate.development.cjs.mjs +23 -13
- package/dist/xstate.development.esm.js +2445 -1398
- package/dist/xstate.esm.js +2445 -1398
- package/dist/xstate.umd.min.js +1 -1
- package/dist/xstate.umd.min.js.map +1 -1
- package/docs/actions.md +75 -0
- package/docs/actor-logic.md +250 -0
- package/docs/actors.md +64 -0
- package/docs/agents.md +132 -0
- package/docs/api-stability.json +4287 -0
- package/docs/async-logic.md +75 -0
- package/docs/async-requests.md +157 -0
- package/docs/backend-workflows.md +124 -0
- package/docs/cancellation.md +42 -0
- package/docs/cheatsheet.md +563 -0
- package/docs/choice-states.md +109 -0
- package/docs/choose-xstate.md +47 -0
- package/docs/configuration.md +161 -0
- package/docs/context.md +67 -0
- package/docs/create-actor.md +159 -0
- package/docs/data-and-effects.md +48 -0
- package/docs/delays.md +81 -0
- package/docs/durable-execution.md +520 -0
- package/docs/emitted-events.md +146 -0
- package/docs/errors.md +812 -0
- package/docs/examples.md +75 -0
- package/docs/faq.md +60 -0
- package/docs/final-states.md +149 -0
- package/docs/forms-and-wizards.md +166 -0
- package/docs/frameworks.md +69 -0
- package/docs/fsm.md +164 -0
- package/docs/glossary.md +68 -0
- package/docs/guards.md +137 -0
- package/docs/history-states.md +161 -0
- package/docs/how-xstate-runs-machines.md +86 -0
- package/docs/index.md +74 -0
- package/docs/input-output.md +69 -0
- package/docs/inspect-actor-systems.md +118 -0
- package/docs/inspection.md +75 -0
- package/docs/internal-events.md +156 -0
- package/docs/invoke.md +371 -0
- package/docs/lifecycle-and-errors.md +48 -0
- package/docs/listen-and-subscribe.md +126 -0
- package/docs/model-based-testing.md +321 -0
- package/docs/modeling.md +40 -0
- package/docs/parallel-states.md +182 -0
- package/docs/persist-and-restore-actors.md +120 -0
- package/docs/persistence.md +312 -0
- package/docs/quick-start.md +55 -0
- package/docs/retries-and-timeouts.md +122 -0
- package/docs/route-states.md +104 -0
- package/docs/scxml.md +92 -0
- package/docs/selectors.md +99 -0
- package/docs/serialization.md +127 -0
- package/docs/setup-and-provide.md +273 -0
- package/docs/snapshots.md +134 -0
- package/docs/spawn.md +212 -0
- package/docs/state-input.md +162 -0
- package/docs/statecharts.md +54 -0
- package/docs/states-events-transitions.md +82 -0
- package/docs/states.md +168 -0
- package/docs/system-transitions.md +172 -0
- package/docs/systems.md +166 -0
- package/docs/testing.md +152 -0
- package/docs/timeouts.md +125 -0
- package/docs/transition-functions.md +89 -0
- package/docs/transitions.md +187 -0
- package/docs/troubleshooting.md +56 -0
- package/docs/tutorial.md +481 -0
- package/docs/typescript.md +213 -0
- package/docs/typestates.md +112 -0
- package/docs/utilities.md +39 -0
- package/docs/why-state-machines.md +59 -0
- package/docs/xstate-v5-to-v6.md +1923 -0
- package/docs/your-first-machine.md +79 -0
- package/durable/package.json +8 -0
- package/fsm/package.json +8 -0
- package/package.json +72 -10
- package/persist/package.json +8 -0
- package/validation/package.json +8 -0
- package/actions/package.json +0 -8
- package/dev/package.json +0 -8
- package/dist/StateMachine-0aa98f54.development.esm.js +0 -746
- package/dist/StateMachine-aef700df.cjs.js +0 -732
- package/dist/StateMachine-d4931336.esm.js +0 -729
- package/dist/StateMachine-da872dde.development.cjs.js +0 -749
- package/dist/declarations/src/createMachineFromConfig.d.ts +0 -177
- package/dist/declarations/src/getNextSnapshot.d.ts +0 -37
- package/dist/declarations/src/graph/TestModel.d.ts +0 -70
- package/dist/declarations/src/graph/pathGenerators.d.ts +0 -4
- package/dist/index-219cb621.development.cjs.js +0 -4476
- package/dist/index-2f2fbd9b.development.esm.js +0 -4421
- package/dist/index-559ceab3.cjs.js +0 -4437
- package/dist/index-8828376f.esm.js +0 -4382
- package/guards/package.json +0 -8
- package/invoke/package.json +0 -4
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export * from "./declarations/src/durable/index.js";
|
|
2
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieHN0YXRlLWR1cmFibGUuY2pzLmQubXRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi9kZWNsYXJhdGlvbnMvc3JjL2R1cmFibGUvaW5kZXguZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSJ9
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export * from "./declarations/src/durable/index.js";
|
|
2
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoieHN0YXRlLWR1cmFibGUuY2pzLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuL2RlY2xhcmF0aW9ucy9zcmMvZHVyYWJsZS9pbmRleC5kLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBIn0=
|
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var dist_xstatePersist = require('./xstate-persist.cjs.js');
|
|
6
|
+
var createActor = require('./createActor-25900f76.cjs.js');
|
|
7
|
+
var effectDescriptor = require('./effectDescriptor-2fa27c54.cjs.js');
|
|
8
|
+
require('./machineSchemas-88d01821.cjs.js');
|
|
9
|
+
require('./validation-4561b43c.cjs.js');
|
|
10
|
+
|
|
11
|
+
/** @experimental */
|
|
12
|
+
|
|
13
|
+
/** @experimental */
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* An event addressed to a durable execution's root actor, captured while
|
|
17
|
+
* effects settled. `source` is the live reference of the sending actor when
|
|
18
|
+
* one initiated the send.
|
|
19
|
+
*
|
|
20
|
+
* @experimental
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/** @experimental */
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A durable host adapter: the runtime operations that execute this
|
|
27
|
+
* execution's effects, plus the durable loop hooks.
|
|
28
|
+
*
|
|
29
|
+
* The runtime operations (`sendEvent`, `scheduleTimer`, …) are installed on
|
|
30
|
+
* the actor system of every snapshot the execution produces, including
|
|
31
|
+
* children created during transitions and actors rehydrated from restored
|
|
32
|
+
* snapshots. Operations initiated by live child actors (parent sends,
|
|
33
|
+
* timers, terminations) route to them without any per-actor wiring; omitted
|
|
34
|
+
* operations keep their default local behavior.
|
|
35
|
+
*
|
|
36
|
+
* By default, events addressed to this execution's root actor do not reach
|
|
37
|
+
* `sendEvent` during `executeEffects`: the execution captures and retains
|
|
38
|
+
* them, and `waitForEvent()` hands them out before deferring to this adapter. While the loop is parked, a root-addressed event reaches
|
|
39
|
+
* `enqueueRootEvent`, or the broader `sendEvent` override when implemented,
|
|
40
|
+
* so the host can place it in its own mailbox.
|
|
41
|
+
*
|
|
42
|
+
* @experimental
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/** @experimental */
|
|
46
|
+
class DurableExecutionCancelledError extends Error {
|
|
47
|
+
constructor() {
|
|
48
|
+
super('Durable execution was stopped');
|
|
49
|
+
this.name = 'DurableExecutionCancelledError';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** @experimental */
|
|
54
|
+
class DurableExecutionResumeError extends Error {
|
|
55
|
+
constructor() {
|
|
56
|
+
super('run() can only start a fresh durable execution; resume checkpoints with restore() and the explicit transition loop');
|
|
57
|
+
this.name = 'DurableExecutionResumeError';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* The snapshot type a durable execution hands back: the logic's own snapshot,
|
|
63
|
+
* intersected with the base `Snapshot` union so the `status`/`output`/`error`
|
|
64
|
+
* discriminant stays visible even when `TLogic` is an unresolved type
|
|
65
|
+
* parameter (a generic host library), where `SnapshotFrom` alone is opaque.
|
|
66
|
+
*
|
|
67
|
+
* @experimental
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
/** @experimental */
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Creates a host-neutral durable execution around pure actor transitions.
|
|
74
|
+
*
|
|
75
|
+
* The returned transition methods only calculate snapshots and tag their
|
|
76
|
+
* effects. Persistence, retries, messaging, timers and child execution remain
|
|
77
|
+
* responsibilities of the adapter.
|
|
78
|
+
*
|
|
79
|
+
* @experimental
|
|
80
|
+
*/
|
|
81
|
+
|
|
82
|
+
/** @experimental */
|
|
83
|
+
function createDurable(logic, adapter, options) {
|
|
84
|
+
let nextTransitionIndex = adapter.transitionIndex ?? 0;
|
|
85
|
+
const startingTransitionIndex = nextTransitionIndex;
|
|
86
|
+
let restored = false;
|
|
87
|
+
const now = () => adapter.now?.() ?? Date.now();
|
|
88
|
+
const observedRoots = new WeakSet();
|
|
89
|
+
let lastTransitionIndex = nextTransitionIndex === 0 ? undefined : nextTransitionIndex - 1;
|
|
90
|
+
const restoredTimerDeadlines = new WeakMap();
|
|
91
|
+
if (!Number.isSafeInteger(nextTransitionIndex) || nextTransitionIndex < 0) {
|
|
92
|
+
throw new RangeError('transitionIndex must be a non-negative safe integer');
|
|
93
|
+
}
|
|
94
|
+
const tagEffects = (effects, restoring = false) => {
|
|
95
|
+
const transitionIndex = restoring ? nextTransitionIndex : nextTransitionIndex++;
|
|
96
|
+
lastTransitionIndex = restoring ? lastTransitionIndex ?? transitionIndex : transitionIndex;
|
|
97
|
+
return effects.map((effect, effectIndex) => {
|
|
98
|
+
const tagged = {
|
|
99
|
+
id: `${restoring ? 'restore:' : ''}${transitionIndex}:${effectIndex}`,
|
|
100
|
+
transitionIndex,
|
|
101
|
+
effectIndex,
|
|
102
|
+
effect
|
|
103
|
+
};
|
|
104
|
+
// Journaling hosts read the descriptor; executing hosts never do, so
|
|
105
|
+
// compute it (and its address walks) lazily, once.
|
|
106
|
+
let descriptor;
|
|
107
|
+
Object.defineProperty(tagged, 'descriptor', {
|
|
108
|
+
enumerable: true,
|
|
109
|
+
get: () => descriptor ??= effectDescriptor.describeExecutableEffect(effect)
|
|
110
|
+
});
|
|
111
|
+
return tagged;
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// The root's address as the root actor reports it: root-event capture
|
|
116
|
+
// compares against `target.address`, which percent-encodes each segment.
|
|
117
|
+
const rootAddress = createActor.encodeAddressSegment(createActor.getRootActorId(logic));
|
|
118
|
+
const machineId = logic.id ?? rootAddress;
|
|
119
|
+
const machineVersion = logic.version;
|
|
120
|
+
// One identity object for the whole execution: session numbering continues
|
|
121
|
+
// across this execution's transitions, and a replay (a fresh createDurable
|
|
122
|
+
// with the same executionId) re-numbers identically.
|
|
123
|
+
const executionIdentity = adapter.executionId ? {
|
|
124
|
+
executionId: adapter.executionId,
|
|
125
|
+
nextSessionId: 0
|
|
126
|
+
} : undefined;
|
|
127
|
+
|
|
128
|
+
// The adapter's runtime operations, picked off the flat adapter shape.
|
|
129
|
+
const systemRuntime = {};
|
|
130
|
+
for (const operation of [...createActor.RUNTIME_OPERATIONS, 'sendEvent', 'runStep', 'runLogic']) {
|
|
131
|
+
const impl = adapter[operation];
|
|
132
|
+
if (impl) {
|
|
133
|
+
systemRuntime[operation] = impl.bind(adapter);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const hasSystemRuntime = Object.keys(systemRuntime).length > 0 || !!adapter.enqueueRootEvent;
|
|
137
|
+
|
|
138
|
+
// One batch per `executeEffects` call. The wrapped runtime stays installed
|
|
139
|
+
// on the actor system for the whole execution, so it also sees operations
|
|
140
|
+
// initiated while the loop is parked in `waitForEvent()` (for example a
|
|
141
|
+
// live child reacting to a host-originated delivery). Those belong to the
|
|
142
|
+
// host's domain: they run untracked and uncaptured, so a parked-window
|
|
143
|
+
// failure cannot be attributed to an unrelated later batch. Discarding a
|
|
144
|
+
// failed batch discards its captures and failures with it.
|
|
145
|
+
|
|
146
|
+
let currentBatch;
|
|
147
|
+
|
|
148
|
+
// Root-addressed events captured by settled batches, waiting for the drive
|
|
149
|
+
// loop to take them through `waitForEvent()`.
|
|
150
|
+
const pendingRootEvents = [];
|
|
151
|
+
|
|
152
|
+
// Every inter-actor edge is an async handoff to the runtime, and every
|
|
153
|
+
// handoff queues behind the last one: hosts whose step or activity model
|
|
154
|
+
// forbids concurrent entries depend on that, and so does deterministic
|
|
155
|
+
// replay. An operation must therefore never await another operation of the
|
|
156
|
+
// same execution through the actor system — it would wait behind itself.
|
|
157
|
+
let operationTail = Promise.resolve();
|
|
158
|
+
const track = (batch, operation) => {
|
|
159
|
+
batch.pending.add(operation);
|
|
160
|
+
void operation.catch(error => {
|
|
161
|
+
// Collect the failure so it reaches `executeEffects` even when the
|
|
162
|
+
// operation leaves the pending set before settle() samples it.
|
|
163
|
+
batch.failures.push(error);
|
|
164
|
+
}).then(() => batch.pending.delete(operation));
|
|
165
|
+
return operation;
|
|
166
|
+
};
|
|
167
|
+
const handOff = (batch, run) => {
|
|
168
|
+
const operation = operationTail.then(run).then(() => undefined);
|
|
169
|
+
operationTail = operation.catch(() => {});
|
|
170
|
+
return track(batch, operation);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// Hands an operation over according to where it was initiated: batched
|
|
174
|
+
// during `executeEffects`, immediate while the loop is parked.
|
|
175
|
+
const dispatch = run => currentBatch ? handOff(currentBatch, run) : run();
|
|
176
|
+
const drain = async batch => {
|
|
177
|
+
while (batch.pending.size) {
|
|
178
|
+
await Promise.allSettled([...batch.pending]);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
const settle = async batch => {
|
|
182
|
+
await drain(batch);
|
|
183
|
+
if (batch.failures.length) {
|
|
184
|
+
throw batch.failures[0];
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
function wrapRuntime(runtime, localDeliveryFallback,
|
|
188
|
+
// When set, operations neither this runtime nor the adapter implements
|
|
189
|
+
// keep the behavior they would have had without a per-effect runtime,
|
|
190
|
+
// running against the operation's own actor's system (per-system timer
|
|
191
|
+
// bookkeeping must land on that system, not the root's). Safe from
|
|
192
|
+
// re-entrant dispatch: that system's installed runtime lacks these
|
|
193
|
+
// operations by construction, so the call falls through to local
|
|
194
|
+
// behavior.
|
|
195
|
+
fallbackToActorSystem = false, timerDeadline) {
|
|
196
|
+
const wrapped = {};
|
|
197
|
+
for (const operation of createActor.RUNTIME_OPERATIONS) {
|
|
198
|
+
const impl = runtime[operation] ?? (fallbackToActorSystem ? (...args) => {
|
|
199
|
+
const owner = operation === 'spawnActor' ? args[1] : args[0];
|
|
200
|
+
return owner.system[operation](...args);
|
|
201
|
+
} : undefined);
|
|
202
|
+
if (impl) {
|
|
203
|
+
wrapped[operation] = (...args) => dispatch(() => {
|
|
204
|
+
// Runtime operations can queue behind asynchronous child startup.
|
|
205
|
+
// Calculate the remaining time when dispatching to the adapter.
|
|
206
|
+
if (operation === 'scheduleTimer' && timerDeadline) {
|
|
207
|
+
args[2] = Math.min(timerDeadline.delay, Math.max(0, timerDeadline.deadline - now()));
|
|
208
|
+
}
|
|
209
|
+
if (operation === 'scheduleTimer') {
|
|
210
|
+
const source = args[0];
|
|
211
|
+
const key = args[1];
|
|
212
|
+
const timer = source.getSnapshot()?.timers?.find(pending => createActor.matchesTimerKey(pending, key));
|
|
213
|
+
if (timer) {
|
|
214
|
+
const previousStart = createActor.getTimerStart(timer);
|
|
215
|
+
if (previousStart !== undefined && !timerDeadline) {
|
|
216
|
+
args[2] = Math.min(timer.delay, Math.max(0, previousStart + timer.delay - now()));
|
|
217
|
+
}
|
|
218
|
+
const result = impl(...args);
|
|
219
|
+
if (result) {
|
|
220
|
+
return Promise.resolve(result).then(() => {
|
|
221
|
+
createActor.recordTimerStart(timer, previousStart ?? now());
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
createActor.recordTimerStart(timer, previousStart ?? now());
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return impl(...args);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// A step is an orchestration frame: it may itself await runtime
|
|
233
|
+
// operations of this execution, so it passes through undispatched —
|
|
234
|
+
// queuing it on the operation tail would make it wait behind (and
|
|
235
|
+
// deadlock with) the operations its own body initiates.
|
|
236
|
+
if (runtime.runStep) {
|
|
237
|
+
wrapped.runStep = runtime.runStep;
|
|
238
|
+
}
|
|
239
|
+
if (runtime.runLogic) {
|
|
240
|
+
wrapped.runLogic = runtime.runLogic;
|
|
241
|
+
}
|
|
242
|
+
wrapped.sendEvent = (source, target, event) => {
|
|
243
|
+
const captureBatch = options?.captureRootEvents !== false ? currentBatch : undefined;
|
|
244
|
+
if (!captureBatch && target.address === rootAddress && !runtime.sendEvent && adapter.enqueueRootEvent) {
|
|
245
|
+
return dispatch(() => adapter.enqueueRootEvent(source, event));
|
|
246
|
+
}
|
|
247
|
+
if (!captureBatch && target.address === rootAddress && !runtime.sendEvent) {
|
|
248
|
+
// The root actor is inert; delivering locally would enqueue into a
|
|
249
|
+
// mailbox that never runs, silently losing the event.
|
|
250
|
+
throw new Error(`A root-addressed event ("${event.type}") was produced outside batch capture (for example, while the durable loop was parked), but the adapter has no enqueueRootEvent or sendEvent to receive it. Implement enqueueRootEvent to place root-addressed events in the host's mailbox.`);
|
|
251
|
+
}
|
|
252
|
+
if (captureBatch && target.address === rootAddress) {
|
|
253
|
+
captureBatch.rootEvents.push({
|
|
254
|
+
event,
|
|
255
|
+
source
|
|
256
|
+
});
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const impl = runtime.sendEvent;
|
|
260
|
+
if (impl) {
|
|
261
|
+
return dispatch(() => impl(source, target, event));
|
|
262
|
+
}
|
|
263
|
+
if (localDeliveryFallback) {
|
|
264
|
+
return dispatch(() => createActor.deliverEvent(source, target, event));
|
|
265
|
+
}
|
|
266
|
+
throw new TypeError(`The durable runtime does not support the sendEvent operation (target '${target.address}')`);
|
|
267
|
+
};
|
|
268
|
+
return wrapped;
|
|
269
|
+
}
|
|
270
|
+
const wrappedSystemRuntime = hasSystemRuntime ? wrapRuntime(systemRuntime, true) : undefined;
|
|
271
|
+
|
|
272
|
+
// Depth-first walk of the live actor tree by logical address. Subtrees
|
|
273
|
+
// whose address is not a prefix of the target are pruned.
|
|
274
|
+
function findByAddress(actor, address) {
|
|
275
|
+
if (actor.address === address) {
|
|
276
|
+
return actor;
|
|
277
|
+
}
|
|
278
|
+
if (!address.startsWith(`${actor.address}/`)) {
|
|
279
|
+
return undefined;
|
|
280
|
+
}
|
|
281
|
+
const children = actor.getSnapshot().children;
|
|
282
|
+
for (const child of Object.values(children ?? {})) {
|
|
283
|
+
const found = child && findByAddress(child, address);
|
|
284
|
+
if (found) {
|
|
285
|
+
return found;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return undefined;
|
|
289
|
+
}
|
|
290
|
+
const inspect = options?.inspect;
|
|
291
|
+
|
|
292
|
+
// Attaches the execution's inspector to a system that does not have it
|
|
293
|
+
// yet. Systems constructed inside a transition get it at construction (the
|
|
294
|
+
// ambient inspector); this covers systems materialized outside that window
|
|
295
|
+
// — a snapshot's system first touched here, or a restored child's foreign
|
|
296
|
+
// system. Observer presence doubles as the dedup check: this execution is
|
|
297
|
+
// the only thing attaching observers to its systems.
|
|
298
|
+
function wireInspection(system) {
|
|
299
|
+
if (inspect && !system._hasInspectionObservers?.()) {
|
|
300
|
+
system.inspect(inspect);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function installSystemRuntime(snapshot, recursive = false) {
|
|
304
|
+
if (snapshot.status === 'error') {
|
|
305
|
+
const root = createActor.getSnapshotActorRef(snapshot)?.actor;
|
|
306
|
+
if (root && !observedRoots.has(root)) {
|
|
307
|
+
// The host consumes error snapshots (run() rejects with their error).
|
|
308
|
+
// Observe before termination effects execute, without materializing
|
|
309
|
+
// otherwise lazy roots during successful pure transitions.
|
|
310
|
+
root.subscribe({
|
|
311
|
+
error() {}
|
|
312
|
+
});
|
|
313
|
+
observedRoots.add(root);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (wrappedSystemRuntime || inspect) {
|
|
317
|
+
const ref = createActor.getSnapshotActorRef(snapshot)?.actor;
|
|
318
|
+
const systems = new Set();
|
|
319
|
+
const visit = actor => {
|
|
320
|
+
if (!systems.has(actor.system)) {
|
|
321
|
+
systems.add(actor.system);
|
|
322
|
+
if (wrappedSystemRuntime) {
|
|
323
|
+
actor.system.runtime = wrappedSystemRuntime;
|
|
324
|
+
}
|
|
325
|
+
wireInspection(actor.system);
|
|
326
|
+
}
|
|
327
|
+
if (recursive) {
|
|
328
|
+
const children = actor.getSnapshot().children;
|
|
329
|
+
for (const child of Object.values(children ?? {})) {
|
|
330
|
+
if (child) {
|
|
331
|
+
visit(child);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
if (ref) {
|
|
337
|
+
visit(ref);
|
|
338
|
+
}
|
|
339
|
+
if (!recursive || !ref) {
|
|
340
|
+
const children = snapshot.children;
|
|
341
|
+
for (const child of Object.values(children ?? {})) {
|
|
342
|
+
if (child) {
|
|
343
|
+
visit(child);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return snapshot;
|
|
349
|
+
}
|
|
350
|
+
const execution = {
|
|
351
|
+
rootAddress,
|
|
352
|
+
machineId,
|
|
353
|
+
machineVersion,
|
|
354
|
+
get nextTransitionIndex() {
|
|
355
|
+
return nextTransitionIndex;
|
|
356
|
+
},
|
|
357
|
+
restore(persistedSnapshot) {
|
|
358
|
+
if (restored || nextTransitionIndex !== startingTransitionIndex || currentBatch) {
|
|
359
|
+
throw new Error('restore() requires a fresh durable execution');
|
|
360
|
+
}
|
|
361
|
+
const {
|
|
362
|
+
snapshot,
|
|
363
|
+
scope
|
|
364
|
+
} = createActor.withSystemInspector(inspect, () => createActor.withExecutionIdentity(executionIdentity, () => {
|
|
365
|
+
const scope = createActor.createInertActorScope(logic);
|
|
366
|
+
const snapshot = dist_xstatePersist.restoreLogicSnapshot(logic, persistedSnapshot, scope);
|
|
367
|
+
createActor.setInertActorScopeSnapshot(scope, snapshot, false);
|
|
368
|
+
return {
|
|
369
|
+
snapshot: installSystemRuntime(createActor.attachSnapshotActorRef(scope, snapshot), true),
|
|
370
|
+
scope
|
|
371
|
+
};
|
|
372
|
+
}));
|
|
373
|
+
const effects = [];
|
|
374
|
+
if (snapshot.status === 'active') {
|
|
375
|
+
const {
|
|
376
|
+
children,
|
|
377
|
+
timers
|
|
378
|
+
} = snapshot;
|
|
379
|
+
for (const child of Object.values(children ?? {})) {
|
|
380
|
+
if (child && !createActor.isRemoteActorRef(child) && child.getSnapshot().status === 'active') {
|
|
381
|
+
effects.push(createActor.createStartEffect(child));
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
for (const timer of timers ?? []) {
|
|
385
|
+
const effect = createActor.createTimerEffect(scope, timer, timer.delay);
|
|
386
|
+
if (timer.scheduledAt !== undefined) {
|
|
387
|
+
restoredTimerDeadlines.set(effect, {
|
|
388
|
+
deadline: timer.scheduledAt + timer.delay,
|
|
389
|
+
delay: timer.delay
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
effects.push(effect);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
restored = true;
|
|
396
|
+
return [snapshot, tagEffects(effects, true)];
|
|
397
|
+
},
|
|
398
|
+
initialTransition(...args) {
|
|
399
|
+
if (restored) {
|
|
400
|
+
throw new Error('initialTransition() cannot initialize a restored execution');
|
|
401
|
+
}
|
|
402
|
+
const [snapshot, effects] = createActor.withSystemInspector(inspect, () => createActor.withExecutionIdentity(executionIdentity, () => effectDescriptor.initialTransition(logic, ...args)));
|
|
403
|
+
return [installSystemRuntime(snapshot), tagEffects(effects)];
|
|
404
|
+
},
|
|
405
|
+
transition(snapshot, event) {
|
|
406
|
+
const [nextSnapshot, effects] = createActor.withSystemInspector(inspect, () => createActor.withExecutionIdentity(executionIdentity, () => effectDescriptor.transition(logic, snapshot, event)));
|
|
407
|
+
return [installSystemRuntime(nextSnapshot), tagEffects(effects)];
|
|
408
|
+
},
|
|
409
|
+
getActorRef(snapshot, address) {
|
|
410
|
+
const root = createActor.getSnapshotActorRef(snapshot)?.actor;
|
|
411
|
+
if (!root || address === undefined) {
|
|
412
|
+
return root;
|
|
413
|
+
}
|
|
414
|
+
return findByAddress(root, address);
|
|
415
|
+
},
|
|
416
|
+
async executeEffects(effects) {
|
|
417
|
+
if (currentBatch) {
|
|
418
|
+
throw new Error('executeEffects calls must not overlap: await the previous call before starting the next batch.');
|
|
419
|
+
}
|
|
420
|
+
const batch = {
|
|
421
|
+
rootEvents: [],
|
|
422
|
+
failures: [],
|
|
423
|
+
pending: new Set()
|
|
424
|
+
};
|
|
425
|
+
currentBatch = batch;
|
|
426
|
+
// `undefined` lets the effect's default parameter (the actor's system,
|
|
427
|
+
// and through it the installed `systemRuntime`) apply; without any
|
|
428
|
+
// runtime, the empty object makes unsupported operations throw instead
|
|
429
|
+
// of silently running local behavior on a durable host.
|
|
430
|
+
const fallbackRuntime = hasSystemRuntime ? undefined : {};
|
|
431
|
+
try {
|
|
432
|
+
for (const tagged of effects) {
|
|
433
|
+
const {
|
|
434
|
+
effect
|
|
435
|
+
} = tagged;
|
|
436
|
+
const metadata = {
|
|
437
|
+
id: tagged.id,
|
|
438
|
+
transitionIndex: tagged.transitionIndex,
|
|
439
|
+
effectIndex: tagged.effectIndex
|
|
440
|
+
};
|
|
441
|
+
const perEffectRuntime = adapter.runtime?.(metadata, effect);
|
|
442
|
+
const timerDeadline = restoredTimerDeadlines.get(effect);
|
|
443
|
+
// A per-effect runtime overrides the system runtime
|
|
444
|
+
// operation-by-operation; operations it omits keep the system
|
|
445
|
+
// runtime's behavior.
|
|
446
|
+
const runtime = perEffectRuntime || timerDeadline ? wrapRuntime({
|
|
447
|
+
...systemRuntime,
|
|
448
|
+
...perEffectRuntime
|
|
449
|
+
}, hasSystemRuntime, !!perEffectRuntime || hasSystemRuntime, timerDeadline) : fallbackRuntime;
|
|
450
|
+
if (effect.kind === 'action') {
|
|
451
|
+
// Custom actions have no default-parameter fallback to the actor's
|
|
452
|
+
// system, so hand them the wrapped system runtime directly.
|
|
453
|
+
await adapter.executeAction(effect, metadata, runtime ?? wrappedSystemRuntime ?? {});
|
|
454
|
+
} else {
|
|
455
|
+
await effect.exec(runtime);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
await settle(batch);
|
|
459
|
+
pendingRootEvents.push(...batch.rootEvents);
|
|
460
|
+
} catch (error) {
|
|
461
|
+
// Drain before discarding so batch-initiated operations are not still
|
|
462
|
+
// running when the retrying host re-executes the effects. The failed
|
|
463
|
+
// batch's captures and failures are discarded with it.
|
|
464
|
+
await drain(batch);
|
|
465
|
+
throw error;
|
|
466
|
+
} finally {
|
|
467
|
+
// Runs after `settle()`/`drain()`, so operations the batch initiated
|
|
468
|
+
// are still treated as in-batch while they finish.
|
|
469
|
+
currentBatch = undefined;
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
async waitForEvent() {
|
|
473
|
+
if (lastTransitionIndex === undefined) {
|
|
474
|
+
throw new Error('Cannot wait for an event before the first transition or restore');
|
|
475
|
+
}
|
|
476
|
+
// Root-bound events produced while effects executed are handed out
|
|
477
|
+
// before durably waiting for an external event.
|
|
478
|
+
const queued = pendingRootEvents.shift();
|
|
479
|
+
if (queued) {
|
|
480
|
+
return queued.event;
|
|
481
|
+
}
|
|
482
|
+
return adapter.waitForEvent({
|
|
483
|
+
id: restored && nextTransitionIndex === 0 ? 'event:restore:0' : `event:${lastTransitionIndex}`,
|
|
484
|
+
transitionIndex: lastTransitionIndex
|
|
485
|
+
});
|
|
486
|
+
},
|
|
487
|
+
async run(...args) {
|
|
488
|
+
if (restored || startingTransitionIndex !== 0 || nextTransitionIndex !== startingTransitionIndex) {
|
|
489
|
+
throw new DurableExecutionResumeError();
|
|
490
|
+
}
|
|
491
|
+
let [snapshot, effects] = execution.initialTransition(...args);
|
|
492
|
+
await execution.executeEffects(effects);
|
|
493
|
+
while (snapshot.status === 'active') {
|
|
494
|
+
const event = await execution.waitForEvent();
|
|
495
|
+
[snapshot, effects] = execution.transition(snapshot, event);
|
|
496
|
+
await execution.executeEffects(effects);
|
|
497
|
+
}
|
|
498
|
+
const terminalSnapshot = snapshot;
|
|
499
|
+
if (terminalSnapshot.status === 'done') {
|
|
500
|
+
return terminalSnapshot.output;
|
|
501
|
+
}
|
|
502
|
+
if (terminalSnapshot.status === 'error') {
|
|
503
|
+
throw terminalSnapshot.error;
|
|
504
|
+
}
|
|
505
|
+
throw new DurableExecutionCancelledError();
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
return execution;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
exports.DurableExecutionCancelledError = DurableExecutionCancelledError;
|
|
512
|
+
exports.DurableExecutionResumeError = DurableExecutionResumeError;
|
|
513
|
+
exports.createDurable = createDurable;
|