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
package/docs/index.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# XState 6.0.0-beta.0
|
|
2
|
+
|
|
3
|
+
These docs match the installed xstate package. Start with the [quick start](quick-start.md) or the [agent guide](agents.md).
|
|
4
|
+
For differences from v5, read the [migration guide](xstate-v5-to-v6.md).
|
|
5
|
+
The [export stability manifest](api-stability.json) classifies the installed source's public, experimental and internal exports.
|
|
6
|
+
|
|
7
|
+
- [Quick start](quick-start.md)
|
|
8
|
+
- [Agent guide](agents.md)
|
|
9
|
+
- [Choose XState](choose-xstate.md)
|
|
10
|
+
- [Use with your framework](frameworks.md)
|
|
11
|
+
- [Examples](examples.md)
|
|
12
|
+
- [Why state machines?](why-state-machines.md)
|
|
13
|
+
- [Your first machine](your-first-machine.md)
|
|
14
|
+
- ['Tutorial: build a media player'](tutorial.md)
|
|
15
|
+
- [States, events and transitions](states-events-transitions.md)
|
|
16
|
+
- [Data and effects](data-and-effects.md)
|
|
17
|
+
- [Async logic](async-logic.md)
|
|
18
|
+
- [Actors](actors.md)
|
|
19
|
+
- [Statecharts](statecharts.md)
|
|
20
|
+
- [How XState runs your machine](how-xstate-runs-machines.md)
|
|
21
|
+
- [Model application behavior](modeling.md)
|
|
22
|
+
- [Handle async requests](async-requests.md)
|
|
23
|
+
- [Add retries and timeouts](retries-and-timeouts.md)
|
|
24
|
+
- [Cancel async work](cancellation.md)
|
|
25
|
+
- [Build forms and wizards](forms-and-wizards.md)
|
|
26
|
+
- [Run backend workflows](backend-workflows.md)
|
|
27
|
+
- [Durable execution](durable-execution.md)
|
|
28
|
+
- [Persist and restore actors](persist-and-restore-actors.md)
|
|
29
|
+
- [Test XState logic](testing.md)
|
|
30
|
+
- [Model-based testing](model-based-testing.md)
|
|
31
|
+
- [Inspect actor systems](inspect-actor-systems.md)
|
|
32
|
+
- [Troubleshooting](troubleshooting.md)
|
|
33
|
+
- [Error codes](errors.md)
|
|
34
|
+
- [Machine configuration](configuration.md)
|
|
35
|
+
- [Compact finite state machines](fsm.md)
|
|
36
|
+
- [Setup and provide](setup-and-provide.md)
|
|
37
|
+
- [States](states.md)
|
|
38
|
+
- [Transitions](transitions.md)
|
|
39
|
+
- [Transition functions and graph analysis](transition-functions.md)
|
|
40
|
+
- [Context](context.md)
|
|
41
|
+
- [Input and output](input-output.md)
|
|
42
|
+
- [State input](state-input.md)
|
|
43
|
+
- [Actions](actions.md)
|
|
44
|
+
- [Guards](guards.md)
|
|
45
|
+
- [Delays](delays.md)
|
|
46
|
+
- [Timeouts](timeouts.md)
|
|
47
|
+
- [Internal events](internal-events.md)
|
|
48
|
+
- [Choice states](choice-states.md)
|
|
49
|
+
- [Route states](route-states.md)
|
|
50
|
+
- [Final states](final-states.md)
|
|
51
|
+
- [History states](history-states.md)
|
|
52
|
+
- [Parallel states](parallel-states.md)
|
|
53
|
+
- [Create actors](create-actor.md)
|
|
54
|
+
- [Actor snapshots](snapshots.md)
|
|
55
|
+
- [Selectors](selectors.md)
|
|
56
|
+
- [Invoke actors](invoke.md)
|
|
57
|
+
- [Spawn actors](spawn.md)
|
|
58
|
+
- [Actor logic](actor-logic.md)
|
|
59
|
+
- [Emitted events](emitted-events.md)
|
|
60
|
+
- [Listen and subscribe to actors](listen-and-subscribe.md)
|
|
61
|
+
- [Actor systems](systems.md)
|
|
62
|
+
- [Pure system transitions](system-transitions.md)
|
|
63
|
+
- [Lifecycle and errors](lifecycle-and-errors.md)
|
|
64
|
+
- [TypeScript](typescript.md)
|
|
65
|
+
- [Typestates](typestates.md)
|
|
66
|
+
- [Persistence](persistence.md)
|
|
67
|
+
- [Serialization](serialization.md)
|
|
68
|
+
- [SCXML](scxml.md)
|
|
69
|
+
- [Inspection](inspection.md)
|
|
70
|
+
- [Utilities](utilities.md)
|
|
71
|
+
- [Cheatsheet](cheatsheet.md)
|
|
72
|
+
- [Frequently asked questions](faq.md)
|
|
73
|
+
- [Glossary](glossary.md)
|
|
74
|
+
- [Migrate from XState v5 to v6](xstate-v5-to-v6.md)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Input and output
|
|
3
|
+
description: Pass input to actors and read output when they complete.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Input provides data when an actor is created.
|
|
7
|
+
|
|
8
|
+
```ts
|
|
9
|
+
const greetingMachine = createMachine({
|
|
10
|
+
context: ({ input }: { input: { name: string } }) => ({ name: input.name })
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const greeting = createActor(greetingMachine, {
|
|
14
|
+
input: { name: 'Ada' }
|
|
15
|
+
}).start();
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
When a machine declares `schemas.input` (directly or through `setup(...)`) and the input type does not accept `undefined`, `createActor` requires the `input` option. Restoring a persisted snapshot with `restoreActor(...)` does not take it.
|
|
19
|
+
|
|
20
|
+
## Final output
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
const machine = createMachine({
|
|
24
|
+
context: { result: 42 },
|
|
25
|
+
initial: 'working',
|
|
26
|
+
states: {
|
|
27
|
+
working: { on: { finish: { target: 'done' } } },
|
|
28
|
+
done: { type: 'final' }
|
|
29
|
+
},
|
|
30
|
+
output: ({ context }) => ({ result: context.result })
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Read output from a completed snapshot or an invocation's done event.
|
|
35
|
+
|
|
36
|
+
Input configures one actor instance. Output reports its final result.
|
|
37
|
+
|
|
38
|
+
- An invoice actor can receive a currency and line items as input, then output the calculated total.
|
|
39
|
+
- A file-processing actor can receive a file key as input, then output the generated asset URL.
|
|
40
|
+
|
|
41
|
+
Actors that run indefinitely may never produce output.
|
|
42
|
+
|
|
43
|
+
## TypeScript
|
|
44
|
+
|
|
45
|
+
Declare input and output schemas when they cross actor boundaries.
|
|
46
|
+
|
|
47
|
+
The output type is inferred from the root `output` when `schemas.output` is not declared. Without a root `output`, the type is the union of the top-level final states' output types. A declared `schemas.output` is authoritative and the root `output` is checked against it.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
const machine = setup({}).createMachine({
|
|
51
|
+
context: { shipped: ['sku-1'] },
|
|
52
|
+
initial: 'done',
|
|
53
|
+
states: { done: { type: 'final' } },
|
|
54
|
+
output: ({ context }) => ({
|
|
55
|
+
status: 'shipped' as const,
|
|
56
|
+
skus: context.shipped
|
|
57
|
+
})
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// OutputFrom<typeof machine> is { status: 'shipped'; skus: string[] }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Input and output cheatsheet
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
context: ({ input }) => ({ value: input.value })
|
|
67
|
+
output: ({ context }) => ({ value: context.value })
|
|
68
|
+
createActor(machine, { input: { value: 1 } });
|
|
69
|
+
```
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Inspect actor systems
|
|
3
|
+
description: Log transitions in development and attach them to error reports.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
An inspector passed to the root actor observes the whole system: the root actor, every invoked or spawned child, and every transition. This guide uses it for a development log and for telemetry.
|
|
7
|
+
|
|
8
|
+
> **Experimental:** the inspection event types (`InspectionEvent`, `ActorInspectionEvent`, `TransitionInspectionEvent`) may change in a minor release.
|
|
9
|
+
|
|
10
|
+
## 1. Attach an inspector in development only
|
|
11
|
+
|
|
12
|
+
Inspection runs on every transition, so keep it out of production builds. Pass `undefined` and `createActor(...)` behaves as if no inspector were given.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { createActor, type InspectionEvent } from 'xstate';
|
|
16
|
+
|
|
17
|
+
const isDev = process.env.NODE_ENV !== 'production';
|
|
18
|
+
|
|
19
|
+
const checkout = createActor(checkoutMachine, {
|
|
20
|
+
inspect: isDev ? inspect : undefined
|
|
21
|
+
}).start();
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 2. Log transitions readably
|
|
25
|
+
|
|
26
|
+
Inspection emits two events: `@xstate.actor` when an actor is created and `@xstate.transition` when one takes a transition. Events that could not be delivered go to the `onRejectedEvent` option instead. Filter to the type you need, then print the event that arrived and the state it produced.
|
|
27
|
+
|
|
28
|
+
Transitions identify their actor by `actorRef.sessionId`, which is unique but not readable. `@xstate.actor` carries the actor's `id`, so keep a map of names as actors appear.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
const names = new Map<string | undefined, string>();
|
|
32
|
+
|
|
33
|
+
function inspect(inspectionEvent: InspectionEvent) {
|
|
34
|
+
if (inspectionEvent.type === '@xstate.actor') {
|
|
35
|
+
names.set(inspectionEvent.actorRef.sessionId, inspectionEvent.id);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const { actorRef, eventType, snapshot } = inspectionEvent;
|
|
40
|
+
const value = 'value' in snapshot ? snapshot.value : snapshot.status;
|
|
41
|
+
|
|
42
|
+
console.log(
|
|
43
|
+
`[${names.get(actorRef.sessionId)}] ${eventType} → ${JSON.stringify(value)}`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The root actor's first transition is `xstate.init`, so the log starts with the initial state. Only machine snapshots have a `value`; a child running async logic reports its `status` instead. A `sessionId` is assigned once an actor starts, which is why the map allows `undefined` keys.
|
|
49
|
+
|
|
50
|
+
Filter further when a system is noisy. An early `if (!eventType.startsWith('payment.')) return;` keeps payment activity and drops everything else.
|
|
51
|
+
|
|
52
|
+
## 3. Inspect the whole tree
|
|
53
|
+
|
|
54
|
+
One inspector on the root covers the system. Every event carries `rootId` for the system and `actorRef.sessionId` for the actor within it, so two children with the same `id` are still distinguishable.
|
|
55
|
+
|
|
56
|
+
`@xstate.actor` announces each actor and its parent before it transitions, which is enough to draw the tree up front:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
function logActors(inspectionEvent: InspectionEvent) {
|
|
60
|
+
if (inspectionEvent.type !== '@xstate.actor') return;
|
|
61
|
+
|
|
62
|
+
const { parentRef, id } = inspectionEvent;
|
|
63
|
+
|
|
64
|
+
console.log(parentRef ? `${names.get(parentRef.sessionId)} → ${id}` : id);
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## 4. Forward transitions to telemetry
|
|
69
|
+
|
|
70
|
+
Keep the last transition per actor and attach it to error reports. The report then says which state the actor was in and which event got it there.
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
const lastTransitions = new Map<
|
|
74
|
+
string | undefined,
|
|
75
|
+
{ event: unknown; value: unknown }
|
|
76
|
+
>();
|
|
77
|
+
|
|
78
|
+
const actor = createActor(checkoutMachine, {
|
|
79
|
+
inspect: (inspectionEvent) => {
|
|
80
|
+
if (inspectionEvent.type !== '@xstate.transition') return;
|
|
81
|
+
|
|
82
|
+
const { actorRef, event, snapshot } = inspectionEvent;
|
|
83
|
+
|
|
84
|
+
lastTransitions.set(actorRef.sessionId, {
|
|
85
|
+
event,
|
|
86
|
+
value: 'value' in snapshot ? snapshot.value : snapshot.status
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}).start();
|
|
90
|
+
|
|
91
|
+
actor.subscribe({
|
|
92
|
+
error: (error) => {
|
|
93
|
+
reportError(error, {
|
|
94
|
+
lastTransition: lastTransitions.get(actor.sessionId)
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Redact before sending. Events and context often carry addresses, card details and tokens.
|
|
101
|
+
|
|
102
|
+
> **Warning:** An inspector observes; it must not change application state. Send events from your machine, not from an inspector.
|
|
103
|
+
|
|
104
|
+
## 5. Use the visual inspector
|
|
105
|
+
|
|
106
|
+
[`@statelyai/inspect`](https://github.com/statelyai/inspect) consumes the same inspection events and draws the running system as a statechart instead of a log.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npm install @statelyai/inspect
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Create its inspector and pass it to the same `inspect` option, in development only.
|
|
113
|
+
|
|
114
|
+
## What next?
|
|
115
|
+
|
|
116
|
+
- [Inspection](inspection.md) for every property on each inspection event type.
|
|
117
|
+
- [Listen and subscribe](listen-and-subscribe.md) for reading actor state in application code.
|
|
118
|
+
- [Systems](systems.md) for how actors are related within a system.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Inspection
|
|
3
|
+
description: Observe actor systems and transitions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Pass an inspector to the root actor with the `inspect` option.
|
|
7
|
+
|
|
8
|
+
> **Experimental:** the inspection event types (`InspectionEvent`, `ActorInspectionEvent`, `TransitionInspectionEvent`) may change in a minor release.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
const actor = createActor(machine, {
|
|
12
|
+
inspect: (inspectionEvent) => {
|
|
13
|
+
console.log(inspectionEvent.type, inspectionEvent);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Inspection emits two event types:
|
|
19
|
+
|
|
20
|
+
| Type | Contains |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| `@xstate.actor` | Actor identity and parent information. |
|
|
23
|
+
| `@xstate.transition` | The event, snapshot, source, target and microsteps. |
|
|
24
|
+
|
|
25
|
+
Both event types carry `rootId`, the session ID of the root actor, and `actorRef`, the actor the event is about. Session IDs are unique across actors, so `rootId` identifies the system and `actorRef.sessionId` identifies an actor within it.
|
|
26
|
+
|
|
27
|
+
`@xstate.actor` announces every created actor: the root actor and each spawned or invoked child. It is the only topology event, so an inspector can draw the actor graph before any transition occurs.
|
|
28
|
+
|
|
29
|
+
| Property | Description |
|
|
30
|
+
| --- | --- |
|
|
31
|
+
| `parentRef` | The parent actor, or `undefined` for the root actor. |
|
|
32
|
+
| `id` | The actor's `id`. |
|
|
33
|
+
| `src` | The source logic, or its referenced string. |
|
|
34
|
+
| `snapshot` | The actor's initial snapshot. |
|
|
35
|
+
|
|
36
|
+
`@xstate.transition` announces a transition. Every property is always present, so an inspector can read each facet without narrowing.
|
|
37
|
+
|
|
38
|
+
| Property | Description |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `eventType` | The event type. |
|
|
41
|
+
| `event` | The event that caused the transition. |
|
|
42
|
+
| `sourceRef` | The actor that sent the event, if any. |
|
|
43
|
+
| `targetRef` | The target actor, usually the same as `actorRef`. |
|
|
44
|
+
| `snapshot` | The resulting snapshot. |
|
|
45
|
+
| `microsteps` | The microstep transition definitions taken. |
|
|
46
|
+
| `actions` | The executed actions, as `{ type, params }`. |
|
|
47
|
+
| `sent` | Events relayed to other actors, as `{ targetRef, targetId, event, delay, id }`. |
|
|
48
|
+
|
|
49
|
+
Each transition retains the source of its own event, including events queued before the actor starts or while another transition runs. Events sent through the public `actor.send(...)` method have an `undefined` source. Child initialization transitions identify the parent as their source.
|
|
50
|
+
|
|
51
|
+
Events that could not be delivered (dead letters) are not inspection events. Observe them with the `onRejectedEvent` option on `createActor`, or subscribe later with `actor.system.onRejectedEvent(listener)`. See [dead letters](systems.md#dead-letters).
|
|
52
|
+
|
|
53
|
+
An event that no transition handled is visible without a separate event type: the `@xstate.transition` event that follows it carries the same `snapshot` reference as the previous transition and an empty `actions` list. Compare references, or use `isUnhandled()` with the pure API.
|
|
54
|
+
|
|
55
|
+
Actor stop is derivable from `snapshot.status` on the actor's final `@xstate.transition` event, so there is no separate stop event. The v5 `@xstate.event`, `@xstate.snapshot`, `@xstate.action` and `@xstate.microstep` events are gone; `@xstate.transition` carries all of them.
|
|
56
|
+
|
|
57
|
+
Use inspection for developer tools, logs and visualizers. Do not change application state from an inspector.
|
|
58
|
+
|
|
59
|
+
If an inspector throws, XState reports the error asynchronously, as it does for snapshot subscriber errors. The actor continues processing, and other inspectors still receive the event.
|
|
60
|
+
|
|
61
|
+
Use inspection to build a statechart visualizer, or to attach actor and transition details to a failed request trace.
|
|
62
|
+
|
|
63
|
+
## Inspection cheatsheet
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
createActor(logic, { inspect });
|
|
67
|
+
createActor(logic, { inspect: (event) => console.log(event) });
|
|
68
|
+
event.rootId; // root actor session ID
|
|
69
|
+
event.actorRef; // '@xstate.actor' and '@xstate.transition'
|
|
70
|
+
event.parentRef, event.id, event.src, event.snapshot; // '@xstate.actor'
|
|
71
|
+
event.event, event.snapshot, event.sourceRef, event.targetRef; // '@xstate.transition'
|
|
72
|
+
event.microsteps, event.actions, event.sent; // '@xstate.transition'
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Microstep transition records contain the targets selected by function transitions. Inspection and `getMicrosteps()` expose resolved copies with a `definition` reference to the shared transition; the machine's shared transition definitions remain reusable.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Internal events
|
|
3
|
+
description: Declare events that the machine may raise but no one may send in.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Declare private event payload schemas in `schemas.internalEvents`. These events
|
|
7
|
+
are part of the machine's internal event union, but are excluded from the
|
|
8
|
+
public `actor.send(...)` and `actor.trigger` protocols.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
const machine = createMachine({
|
|
12
|
+
schemas: {
|
|
13
|
+
events: {
|
|
14
|
+
start: z.object({})
|
|
15
|
+
},
|
|
16
|
+
internalEvents: {
|
|
17
|
+
tick: z.object({ count: z.number() })
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
initial: 'idle',
|
|
21
|
+
states: {
|
|
22
|
+
idle: {
|
|
23
|
+
on: {
|
|
24
|
+
start: (_, enq) => {
|
|
25
|
+
enq.raise({ type: 'tick', count: 1 });
|
|
26
|
+
},
|
|
27
|
+
tick: { target: 'done' }
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
done: {}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Sending `start` raises `tick` internally and the machine transitions to `done`. Sending `tick` directly rejects the event at the delivery boundary:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
const actor = createActor(machine, {
|
|
39
|
+
onRejectedEvent: (rejection) => {
|
|
40
|
+
rejection.event; // { type: 'tick' }
|
|
41
|
+
rejection.reason; // 'internalEvent'
|
|
42
|
+
}
|
|
43
|
+
}).start();
|
|
44
|
+
|
|
45
|
+
actor.send({ type: 'tick' });
|
|
46
|
+
// The event is not delivered. `actor.send` does not throw and the actor
|
|
47
|
+
// does not error; its state is unchanged.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
A rejected event never enters the machine. The rejection is reported two ways:
|
|
51
|
+
|
|
52
|
+
- The `onRejectedEvent` dead-letter hook on `createActor` options receives an `EventRejection` object with the `event`, `targetId`, `sourceRef`, `eventOrigin` (`'external'` or `'actor'`), `reason` and `error`.
|
|
53
|
+
- In development mode, a console warning describes the rejection.
|
|
54
|
+
|
|
55
|
+
Internal events are still ordinary events in every other respect. They appear
|
|
56
|
+
in `on` handlers and are raised with `enq.raise` like any other event. They do
|
|
57
|
+
not need a duplicate entry in `schemas.events`.
|
|
58
|
+
|
|
59
|
+
## Wildcard patterns
|
|
60
|
+
|
|
61
|
+
Entries may use a `.`-segment wildcard, which covers every event type under that prefix.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
schemas: {
|
|
65
|
+
internalEvents: {
|
|
66
|
+
'change.*': z.object({ value: z.string() })
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
With that in place, `change.value`, `change.status` and any other `change.*` event can be raised internally but is rejected from outside.
|
|
72
|
+
|
|
73
|
+
## What counts as "outside"
|
|
74
|
+
|
|
75
|
+
The check compares the sender to the receiver. An internally executed
|
|
76
|
+
self-targeted effect such as `enq.raise(...)` or `enq.sendTo(self, ...)` is
|
|
77
|
+
allowed. Anything else is rejected: `actor.send` from application code, a
|
|
78
|
+
parent sending to a child, or a sibling actor.
|
|
79
|
+
|
|
80
|
+
> **Warning:** a rejection is silent unless you observe it. It does not throw and it does not error the actor. Register `onRejectedEvent` or `actor.system.onRejectedEvent(...)` to detect rejected events. Dead letters are not inspection events. Treat internal events as a private surface, and if application code needs to reach that behavior, expose a public event that raises the internal one.
|
|
81
|
+
|
|
82
|
+
Use internal events for:
|
|
83
|
+
|
|
84
|
+
- a `tick` that only the machine's own timer logic should produce
|
|
85
|
+
- `change.*` events raised by a form's own validation pass, so no caller can fake a field update
|
|
86
|
+
- upload progress events raised by an invoked actor's callbacks, where an outside `progress` event would corrupt the state
|
|
87
|
+
|
|
88
|
+
## TypeScript
|
|
89
|
+
|
|
90
|
+
The keys in `schemas.internalEvents` narrow the actor's public protocol: those
|
|
91
|
+
types, and types matched by a wildcard, are removed from what `actor.send` and
|
|
92
|
+
`actor.trigger` accept, so an invalid send is a type error rather than a
|
|
93
|
+
runtime rejection. They remain fully typed inside the machine for `on`
|
|
94
|
+
handlers, guards, actions, `enq.raise` and [transitions](transitions.md).
|
|
95
|
+
|
|
96
|
+
The top-level `internalEvents: ['tick']` list was removed before 6.0. Move
|
|
97
|
+
each listed event's schema from `schemas.events` to `schemas.internalEvents`.
|
|
98
|
+
A machine config with a top-level `internalEvents` key throws an error naming
|
|
99
|
+
`schemas.internalEvents`.
|
|
100
|
+
|
|
101
|
+
## Internal events cheatsheet
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
createMachine({
|
|
105
|
+
schemas: {
|
|
106
|
+
events: {
|
|
107
|
+
start: z.object({})
|
|
108
|
+
},
|
|
109
|
+
internalEvents: {
|
|
110
|
+
tick: z.object({}),
|
|
111
|
+
'change.*': z.object({ value: z.string() })
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
initial: 'idle',
|
|
115
|
+
states: {
|
|
116
|
+
idle: {
|
|
117
|
+
on: {
|
|
118
|
+
start: (_, enq) => {
|
|
119
|
+
enq.raise({ type: 'tick' });
|
|
120
|
+
},
|
|
121
|
+
tick: { target: 'done' }
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
done: {}
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Validating public input
|
|
130
|
+
|
|
131
|
+
`eventSchema(machine)` is a Standard Schema for complete public input event
|
|
132
|
+
objects. Validate untrusted input (including agent tool arguments) before sending:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
const result = await eventSchema(machine)['~standard'].validate(input);
|
|
136
|
+
if (result.issues) {
|
|
137
|
+
throw new Error(result.issues[0]?.message);
|
|
138
|
+
}
|
|
139
|
+
actor.send(result.value);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The schema validates payloads using `schemas.events`, rejects declared internal
|
|
143
|
+
events (including wildcard descriptors), and rejects `xstate.*` / `@xstate.*`
|
|
144
|
+
runtime events. `xstate.route` is accepted only with a `to` destination identifying
|
|
145
|
+
an explicitly configured route. Route guards and current-state eligibility are
|
|
146
|
+
evaluated during delivery, not schema validation.
|
|
147
|
+
|
|
148
|
+
Without event schemas, application event names remain open. `types<T>()` provides
|
|
149
|
+
type inference only; use a runtime schema such as Zod to validate payloads.
|
|
150
|
+
Validation is not authorization: a well-formed public event may still require
|
|
151
|
+
application permission checks.
|
|
152
|
+
|
|
153
|
+
`actor.send(event)` keeps supporting trusted runtime delivery and replay. It does
|
|
154
|
+
not automatically run `eventSchema(machine)`. For event histories,
|
|
155
|
+
`machineVersions().adaptEvents()` retains historical internal/runtime validation
|
|
156
|
+
when given actual machines.
|