xstate 6.0.0-beta.2 → 6.0.0-beta.3
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 +4 -2
- package/dist/{createActor-20a97166.esm.js → createActor-49ea55ba.esm.js} +17 -8
- package/dist/{createActor-c91c9ffe.cjs.js → createActor-73aa92ba.cjs.js} +17 -7
- package/dist/{createActor-0250284a.development.esm.js → createActor-a085b20b.development.esm.js} +17 -8
- package/dist/{createActor-c029d29f.development.cjs.js → createActor-dfb6b790.development.cjs.js} +17 -7
- package/dist/declarations/src/fsm.d.ts +7 -7
- package/dist/{effectDescriptor-47f73e7e.cjs.js → effectDescriptor-3402f63e.cjs.js} +1 -1
- package/dist/{effectDescriptor-e93df910.esm.js → effectDescriptor-65821048.development.esm.js} +1 -1
- package/dist/{effectDescriptor-5ac7dccb.development.esm.js → effectDescriptor-72c62058.esm.js} +1 -1
- package/dist/{effectDescriptor-3fff5c51.development.cjs.js → effectDescriptor-d0ea44ad.development.cjs.js} +1 -1
- package/dist/{legacySnapshot-ae6594a7.development.esm.js → legacySnapshot-11aba2d2.development.esm.js} +1 -1
- package/dist/{legacySnapshot-ebf0b2b8.development.cjs.js → legacySnapshot-2e2c1d3b.development.cjs.js} +1 -1
- package/dist/{legacySnapshot-8d595687.cjs.js → legacySnapshot-a85dfbe2.cjs.js} +1 -1
- package/dist/{legacySnapshot-9e06feb4.esm.js → legacySnapshot-fffe81a0.esm.js} +1 -1
- package/dist/xstate-actors.cjs.js +30 -5
- package/dist/xstate-actors.development.cjs.js +30 -5
- package/dist/xstate-actors.development.esm.js +31 -6
- package/dist/xstate-actors.esm.js +31 -6
- package/dist/xstate-actors.umd.min.js +1 -1
- package/dist/xstate-actors.umd.min.js.map +1 -1
- package/dist/xstate-durable.cjs.js +3 -3
- package/dist/xstate-durable.development.cjs.js +3 -3
- package/dist/xstate-durable.development.esm.js +3 -3
- package/dist/xstate-durable.esm.js +3 -3
- package/dist/xstate-durable.umd.min.js +1 -1
- package/dist/xstate-durable.umd.min.js.map +1 -1
- package/dist/xstate-fsm.cjs.js +61 -31
- package/dist/xstate-fsm.development.cjs.js +61 -31
- package/dist/xstate-fsm.development.esm.js +61 -31
- package/dist/xstate-fsm.esm.js +61 -31
- package/dist/xstate-fsm.umd.min.js +1 -1
- package/dist/xstate-fsm.umd.min.js.map +1 -1
- package/dist/xstate-graph.cjs.js +1 -1
- package/dist/xstate-graph.development.cjs.js +1 -1
- package/dist/xstate-graph.development.esm.js +2 -2
- package/dist/xstate-graph.esm.js +2 -2
- package/dist/xstate-persist.cjs.js +2 -2
- package/dist/xstate-persist.development.cjs.js +2 -2
- package/dist/xstate-persist.development.esm.js +3 -3
- package/dist/xstate-persist.esm.js +3 -3
- package/dist/xstate-persist.umd.min.js +1 -1
- package/dist/xstate-persist.umd.min.js.map +1 -1
- package/dist/xstate-validation.cjs.js +1 -1
- package/dist/xstate-validation.development.cjs.js +1 -1
- package/dist/xstate-validation.development.esm.js +1 -1
- package/dist/xstate-validation.esm.js +1 -1
- package/dist/xstate.cjs.js +26 -8
- package/dist/xstate.development.cjs.js +26 -8
- package/dist/xstate.development.esm.js +28 -10
- package/dist/xstate.esm.js +28 -10
- package/dist/xstate.umd.min.js +1 -1
- package/dist/xstate.umd.min.js.map +1 -1
- package/docs/actor-logic.md +1 -1
- package/docs/api-stability.json +93 -81
- package/docs/faq.md +1 -1
- package/docs/fsm.md +53 -10
- package/docs/index.md +2 -1
- package/docs/inspect-actor-systems.md +20 -3
- package/docs/inspection.md +5 -1
- package/docs/invoke.md +2 -2
- package/docs/migrate-inspector.md +141 -0
- package/docs/system-transitions.md +2 -0
- package/docs/transitions.md +5 -1
- package/docs/xstate-v5-to-v6.md +6 -4
- package/package.json +1 -1
package/docs/faq.md
CHANGED
|
@@ -25,7 +25,7 @@ No typegen step is needed. Types come from `schemas`: declare `context`, `events
|
|
|
25
25
|
|
|
26
26
|
## What happened to `@xstate/immer` and `@xstate/inspect`?
|
|
27
27
|
|
|
28
|
-
Both packages were removed. Instead of `@xstate/immer`, return an updated `context` patch directly from the transition function; if you want Immer drafts, call Immer's `produce` yourself inside that function. Instead of `@xstate/inspect`, use `actor.subscribe(...)` or the `inspect` option on `createActor(...)`, and use [`@statelyai/inspect`](
|
|
28
|
+
Both packages were removed. Instead of `@xstate/immer`, return an updated `context` patch directly from the transition function; if you want Immer drafts, call Immer's `produce` yourself inside that function. Instead of `@xstate/inspect`, use `actor.subscribe(...)` or the `inspect` option on `createActor(...)`, and use [`@statelyai/sdk/inspect`](migrate-inspector.md) for a visual inspector. See [inspection](inspection.md) and [inspect actor systems](inspect-actor-systems.md).
|
|
29
29
|
|
|
30
30
|
## Can I run v5 and v6 side by side?
|
|
31
31
|
|
package/docs/fsm.md
CHANGED
|
@@ -17,8 +17,8 @@ import { createFSM } from 'xstate/fsm';
|
|
|
17
17
|
const machine = createFSM({
|
|
18
18
|
initial: 'inactive',
|
|
19
19
|
states: {
|
|
20
|
-
inactive: { on: { toggle: 'active' } },
|
|
21
|
-
active: { on: { toggle: 'inactive' } }
|
|
20
|
+
inactive: { on: { toggle: { target: 'active' } } },
|
|
21
|
+
active: { on: { toggle: { target: 'inactive' } } }
|
|
22
22
|
}
|
|
23
23
|
});
|
|
24
24
|
|
|
@@ -121,8 +121,8 @@ import { createFSM } from 'xstate/fsm';
|
|
|
121
121
|
const machine = createFSM({
|
|
122
122
|
initial: 'inactive',
|
|
123
123
|
states: {
|
|
124
|
-
inactive: { on: { toggle: 'active' } },
|
|
125
|
-
active: { on: { toggle: 'inactive' } }
|
|
124
|
+
inactive: { on: { toggle: { target: 'active' } } },
|
|
125
|
+
active: { on: { toggle: { target: 'inactive' } } }
|
|
126
126
|
}
|
|
127
127
|
});
|
|
128
128
|
|
|
@@ -143,23 +143,66 @@ from `xstate` adds the runtime to your bundle.
|
|
|
143
143
|
|
|
144
144
|
`createFSM` is pure. It does not create or run actors:
|
|
145
145
|
|
|
146
|
-
- `machine.initialState` is the initial
|
|
147
|
-
|
|
148
|
-
|
|
146
|
+
- `machine.initialState` is the settled initial
|
|
147
|
+
`{ status: 'active', value, context }` snapshot. FSM snapshots are always
|
|
148
|
+
`'active'`. The `output` and `error` fields are always `undefined`.
|
|
149
149
|
- `machine.getInitialSnapshot()` returns `machine.initialState`.
|
|
150
150
|
- `machine.transition(state, event)` returns `[nextState, effects]`. `effects`
|
|
151
151
|
is always empty.
|
|
152
152
|
- Missing transitions return the current state unchanged.
|
|
153
|
-
- A transition can be
|
|
153
|
+
- A transition can be `{ target, context }` or a function that
|
|
154
154
|
receives `{ context, event }` and returns `{ target, context }`. Return
|
|
155
155
|
`undefined` from a function for no transition.
|
|
156
|
-
- Only own entries in `states` and `on` define transitions. A state inherited from the `states` prototype has no outgoing transitions, like an undeclared state.
|
|
156
|
+
- Only own entries in `states` and `on` define transitions. A state inherited from the `states` prototype has no outgoing transitions, like an undeclared state. Target state names are not validated at runtime. Bare string transitions are rejected.
|
|
157
157
|
- Context updates are shallow patches. A patch adds its own enumerable string and symbol keys even when a new value is `undefined` or matches an inherited value. If the target is unchanged, a patch whose keys already exist with `Object.is`-equal values keeps the current snapshot.
|
|
158
158
|
- `types<T>()` adds types without runtime validation. Setup schema values are
|
|
159
159
|
ignored by the FSM runtime; state `schemas.input` is accepted for upgrade
|
|
160
160
|
compatibility but no input is consumed by this pure API.
|
|
161
161
|
|
|
162
|
+
## Eventless transitions
|
|
163
|
+
|
|
164
|
+
A state can declare `always` with the same object or function form as
|
|
165
|
+
an event transition. Return `undefined` from a function when no transition
|
|
166
|
+
is enabled:
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
const machine = createFSM<{ attempts: number }>({
|
|
170
|
+
initial: 'checking',
|
|
171
|
+
context: { attempts: 0 },
|
|
172
|
+
states: {
|
|
173
|
+
checking: {
|
|
174
|
+
always: ({ context }) =>
|
|
175
|
+
context.attempts < 3
|
|
176
|
+
? { context: { attempts: context.attempts + 1 } }
|
|
177
|
+
: { target: 'ready' }
|
|
178
|
+
},
|
|
179
|
+
ready: {}
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
machine.initialState.value; // 'ready'
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The presence of `always` transitions is detected once during construction.
|
|
187
|
+
Define all `always` transitions before calling `createFSM`.
|
|
188
|
+
|
|
189
|
+
The machine follows enabled `always` transitions during construction and after
|
|
190
|
+
each handled event until none is enabled. Ignored events and callbacks that
|
|
191
|
+
return `undefined` do not start another eventless chain. Subscribers receive
|
|
192
|
+
only the settled snapshot. During construction, callbacks receive
|
|
193
|
+
`{ type: 'xstate.init' }`; afterward, they receive the triggering event.
|
|
194
|
+
|
|
195
|
+
There is no transition-count limit. An unconditional cycle does not terminate.
|
|
196
|
+
Each state supports one `always` transition. Transition arrays and a separate
|
|
197
|
+
guard API are not supported.
|
|
198
|
+
|
|
162
199
|
The package intentionally has no actions, guards, effects, timers, child
|
|
163
|
-
actors, hierarchical or parallel states
|
|
200
|
+
actors, hierarchical or parallel states. Use
|
|
164
201
|
`createMachine` and `createActor` from `xstate` when the state machine needs
|
|
165
202
|
those statechart or runtime features.
|
|
203
|
+
|
|
204
|
+
## Transition target migration
|
|
205
|
+
|
|
206
|
+
`on` and `always` require transition objects or functions returning transition objects. Replace `on: { GO: 'ready' }` with `on: { GO: { target: 'ready' } }` and `always: 'ready'` with `always: { target: 'ready' }`. `initial: 'idle'` stays a string. Invalid string transitions throw a `TypeError`.
|
|
207
|
+
|
|
208
|
+
The `@xstate/codemod` `string-targets` transform updates inline `createFSM` and `setup(...).createFSM` configurations, including aliased `createFSM` imports. Review configurations stored separately and functions returning strings manually.
|
package/docs/index.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# XState 6.0.0-beta.
|
|
1
|
+
# XState 6.0.0-beta.3
|
|
2
2
|
|
|
3
3
|
These docs match the installed xstate package. Start with the [quick start](quick-start.md) or the [agent guide](agents.md).
|
|
4
4
|
For differences from v5, read the [migration guide](xstate-v5-to-v6.md).
|
|
@@ -29,6 +29,7 @@ The [export stability manifest](api-stability.json) classifies the installed sou
|
|
|
29
29
|
- [Test XState logic](testing.md)
|
|
30
30
|
- [Model-based testing](model-based-testing.md)
|
|
31
31
|
- [Inspect actor systems](inspect-actor-systems.md)
|
|
32
|
+
- [Migrate to SDK inspection](migrate-inspector.md)
|
|
32
33
|
- [Troubleshooting](troubleshooting.md)
|
|
33
34
|
- [Error codes](errors.md)
|
|
34
35
|
- [Machine configuration](configuration.md)
|
|
@@ -103,13 +103,30 @@ Redact before sending. Events and context often carry addresses, card details an
|
|
|
103
103
|
|
|
104
104
|
## 5. Use the visual inspector
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
Use `createInspector` from `@statelyai/sdk/inspect` to visualize the running actor system.
|
|
107
107
|
|
|
108
108
|
```bash
|
|
109
|
-
npm install @statelyai/
|
|
109
|
+
npm install @statelyai/sdk
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
```ts
|
|
113
|
+
import { createActor } from 'xstate';
|
|
114
|
+
import { createInspector } from '@statelyai/sdk/inspect';
|
|
115
|
+
import { checkoutMachine } from './checkoutMachine';
|
|
116
|
+
|
|
117
|
+
const inspector = createInspector();
|
|
118
|
+
const actor = createActor(checkoutMachine, { inspect: inspector.inspect });
|
|
119
|
+
actor.start();
|
|
120
|
+
|
|
121
|
+
await inspector.ready;
|
|
122
|
+
console.log(inspector.inspectorUrl);
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Open the logged URL to view the system. The SDK connects to the hosted relay without an API key and does not open a browser by default. In Node, pass `launch: 'browser'` to open the viewer automatically. In a browser, expose the URL as a link after `inspector.ready` resolves and let the user open it.
|
|
126
|
+
|
|
127
|
+
Snapshot context is omitted by default. Use `serializeSnapshot` to include selected context fields. Call `inspector.destroy()` when inspection ends; this disconnects inspection without stopping your actors. Configure inspection in development only.
|
|
128
|
+
|
|
129
|
+
If you use `@statelyai/inspect`, follow [Migrate to SDK inspection](migrate-inspector.md). The SDK has a different API and transport protocol.
|
|
113
130
|
|
|
114
131
|
## What next?
|
|
115
132
|
|
package/docs/inspection.md
CHANGED
|
@@ -44,7 +44,9 @@ Both event types carry `rootId`, the session ID of the root actor, and `actorRef
|
|
|
44
44
|
| `snapshot` | The resulting snapshot. |
|
|
45
45
|
| `microsteps` | The microstep transition definitions taken. |
|
|
46
46
|
| `actions` | The executed actions, as `{ type, params }`. |
|
|
47
|
-
| `sent` | Events
|
|
47
|
+
| `sent` | Events sent by the actor, including events sent to itself, as `{ targetRef, targetId, event, delay, id }`. |
|
|
48
|
+
|
|
49
|
+
Callback `sendBack`, event observable values, and events mapped by `enq.listen()` or `enq.subscribeTo()` enter the source actor's mailbox before reaching the parent. The source reports a transition with the parent event in `sent`. A `createEffectEventStreamLogic` actor reports its stream items the same way.
|
|
48
50
|
|
|
49
51
|
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
52
|
|
|
@@ -73,3 +75,5 @@ event.microsteps, event.actions, event.sent; // '@xstate.transition'
|
|
|
73
75
|
```
|
|
74
76
|
|
|
75
77
|
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.
|
|
78
|
+
|
|
79
|
+
For visual inspection, use [`@statelyai/sdk/inspect`](inspect-actor-systems.md#5-use-the-visual-inspector). See [Migrate to SDK inspection](migrate-inspector.md) if you use the legacy `@statelyai/inspect` package.
|
package/docs/invoke.md
CHANGED
|
@@ -154,9 +154,9 @@ Invoked actors belong to the state that starts them:
|
|
|
154
154
|
- leaving the state stops it
|
|
155
155
|
- re-entering the state stops the old actor and starts a new one
|
|
156
156
|
|
|
157
|
-
A state is re-entered by an external transition back to itself, or by a transition with `reenter: true`. A transition that stays inside the invoking state does not restart the child.
|
|
157
|
+
A state is re-entered by an external transition back to itself, or by a targeted transition with `reenter: true`. A transition that stays inside the invoking state does not restart the child. Targetless transitions do not restart the child, even with `reenter: true`.
|
|
158
158
|
|
|
159
|
-
Invoke on the machine root runs for the whole lifetime of the actor. Root invocations survive ordinary transitions between top-level states, and restart only on a root [transition](transitions.md) with `reenter: true`.
|
|
159
|
+
Invoke on the machine root runs for the whole lifetime of the actor. Root invocations survive ordinary transitions between top-level states, and restart only on a root [transition](transitions.md) with an explicit target and `reenter: true`.
|
|
160
160
|
|
|
161
161
|
```ts
|
|
162
162
|
const machine = createMachine({
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Migrate to SDK inspection
|
|
3
|
+
description: Replace legacy Stately Inspect integrations with the Stately SDK.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use `@statelyai/sdk/inspect` for visual inspection with XState v6. The SDK accepts XState v5 and v6 inspection events. The legacy `@statelyai/inspect` package remains available for existing XState v5 integrations.
|
|
7
|
+
|
|
8
|
+
The SDK is not a drop-in replacement. Check the options and transport changes below before removing the legacy package. This guide describes `@statelyai/sdk` 0.48.0.
|
|
9
|
+
|
|
10
|
+
## Install and connect
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @statelyai/sdk
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Replace the browser factory with the SDK factory:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
// Before: XState v5
|
|
20
|
+
import { createBrowserInspector } from '@statelyai/inspect';
|
|
21
|
+
|
|
22
|
+
const inspector = createBrowserInspector();
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
// After: XState v6
|
|
27
|
+
import { createActor } from 'xstate';
|
|
28
|
+
import { createInspector } from '@statelyai/sdk/inspect';
|
|
29
|
+
import { machine } from './machine';
|
|
30
|
+
|
|
31
|
+
const inspector = createInspector();
|
|
32
|
+
const actor = createActor(machine, { inspect: inspector.inspect });
|
|
33
|
+
actor.start();
|
|
34
|
+
|
|
35
|
+
await inspector.ready;
|
|
36
|
+
console.log(inspector.inspectorUrl);
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The SDK connects to the hosted relay without an API key. `inspector.ready` resolves after relay registration and the initial-state flush. Open `inspector.inspectorUrl` after it resolves. If you supply a custom transport, the URL is `null` and your transport controls the viewer connection.
|
|
40
|
+
|
|
41
|
+
The SDK's `inspect` property is a callback. Pass it directly to `createActor` instead of calling the legacy observer's `inspect.next(...)` method. To inspect an actor that already exists, call `inspector.attach(actor)`.
|
|
42
|
+
|
|
43
|
+
The SDK has no XState peer dependency restriction, but currently depends on XState v5 internally. An application using XState v6 can have both versions installed.
|
|
44
|
+
|
|
45
|
+
## Open the viewer
|
|
46
|
+
|
|
47
|
+
The SDK does not open a popup automatically. In a browser, expose `inspector.inspectorUrl` as a link after `inspector.ready` resolves. Let the user open it from a click or another user gesture.
|
|
48
|
+
|
|
49
|
+
In Node, request automatic browser launch:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import { createInspector } from '@statelyai/sdk/inspect';
|
|
53
|
+
|
|
54
|
+
const inspector = createInspector({ launch: 'browser' });
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`launch: 'browser'` is supported from Node, not from a browser runtime.
|
|
58
|
+
|
|
59
|
+
## Include selected context
|
|
60
|
+
|
|
61
|
+
The default snapshot serializer sends `value`, `status`, and available tags. It omits context. Use `serializeSnapshot` to include fields that your viewer needs:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { createInspector } from '@statelyai/sdk/inspect';
|
|
65
|
+
|
|
66
|
+
const inspector = createInspector({
|
|
67
|
+
serializeSnapshot: (snapshot) => {
|
|
68
|
+
const context = snapshot.context;
|
|
69
|
+
const orderId =
|
|
70
|
+
context !== null &&
|
|
71
|
+
typeof context === 'object' &&
|
|
72
|
+
'orderId' in context &&
|
|
73
|
+
typeof context.orderId === 'string'
|
|
74
|
+
? context.orderId
|
|
75
|
+
: undefined;
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
value: snapshot.value,
|
|
79
|
+
status: snapshot.status,
|
|
80
|
+
tags: snapshot.tags ? Array.from(snapshot.tags) : [],
|
|
81
|
+
context: { orderId }
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Return JSON-serializable data. Avoid sending actor references, DOM nodes, credentials, or personal data. This serializer controls snapshots only; it does not redact event payloads or machine definitions.
|
|
88
|
+
|
|
89
|
+
## Disconnect inspection
|
|
90
|
+
|
|
91
|
+
Replace the legacy `inspector.stop()` teardown call with:
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
inspector.destroy();
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
This closes inspection and its subscriptions. It does not stop the application actors. The SDK's `stop(actorId)` method marks a manually inspected actor as stopped; it is not a teardown method. The SDK has no equivalent of the legacy `autoStart: false` and `start()` lifecycle.
|
|
98
|
+
|
|
99
|
+
## Migrate manual inspection
|
|
100
|
+
|
|
101
|
+
Both packages support manual actors, events, and snapshots, but actor registration has a different shape:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
// Before
|
|
105
|
+
inspector.actor('request', { status: 'active' }, { parentId: 'server' });
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
// After
|
|
110
|
+
inspector.actor('request', {
|
|
111
|
+
snapshot: { status: 'active' },
|
|
112
|
+
parent: 'server'
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Pass actor IDs as strings. Replace actor-reference arguments with their corresponding manual IDs. Map a legacy `definition` to the SDK's `machine` option, and provide a machine config or source string rather than assuming the old serialized definition is accepted.
|
|
117
|
+
|
|
118
|
+
`inspector.snapshot(id, snapshot, event)` takes the triggering event directly as its third argument. The legacy API takes `{ event }` there. `inspector.event(id, event, { source })` continues to accept a source, but the SDK expects the source actor's ID as a string.
|
|
119
|
+
|
|
120
|
+
## Check unsupported options and transports
|
|
121
|
+
|
|
122
|
+
| Legacy API | SDK migration |
|
|
123
|
+
| --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
124
|
+
| `createInspector(adapter, options)` | `createInspector(options)` has a different signature. A custom SDK `transport` must implement the SDK transport interface. |
|
|
125
|
+
| `createWebSocketInspector({ url })` | Use `createInspector({ url })` with a compatible SDK relay. The SDK `url` is a relay URL, not a viewer URL. |
|
|
126
|
+
| `createInspectorServer` from `@statelyai/inspect/server` | For local inspection, use `createNodeInspectionRelay` from `@statelyai/sdk/node-relay`. Install its `ws` peer dependency and start the relay before connecting. |
|
|
127
|
+
| `createBrowserReceiver`, `createWebSocketReceiver` | There are no matching SDK exports. Keep the legacy receiver until its integration supports the SDK protocol. |
|
|
128
|
+
| `iframe`, custom `window`, browser `send` override | There is no equivalent option on the SDK inspector factory. Keep the legacy integration until the viewer integration is migrated. |
|
|
129
|
+
| `filter`, `serialize`, `sanitizeEvent`, `sanitizeContext` | There are no matching SDK options. `serializeSnapshot` only controls snapshots. Keep the legacy integration if it requires event filtering or sanitization that has not been replaced. |
|
|
130
|
+
| `maxDeferredEvents`, `serializationDepthLimit` | There are no matching SDK options. Do not pass them and assume they take effect. |
|
|
131
|
+
| `createSkyInspector({ apiKey })` | The SDK has an `apiKey` option for hosted session ownership, but it uses a different session and transport protocol. Migrate the hosted integration explicitly. |
|
|
132
|
+
|
|
133
|
+
The legacy popup, WebSocket receiver, and local bridge exchange legacy inspection messages. SDK relays exchange room and producer messages. Changing the package name or server URL does not make these protocols compatible.
|
|
134
|
+
|
|
135
|
+
After migrating and verifying your integration, remove `@statelyai/inspect` if no other code uses it:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
npm uninstall @statelyai/inspect
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
See [Inspect actor systems](inspect-actor-systems.md) for the v6 inspection workflow and [Inspection](inspection.md) for XState's event types.
|
|
@@ -79,6 +79,8 @@ such as `actor.send`, `actor.start`, `actor.on` and `actor.subscribe` throw.
|
|
|
79
79
|
For `enq.listen`/`enq.subscribeTo`, register named pure mapper functions in
|
|
80
80
|
`systemLogic.mappers`; mapped communication and attachment lifetimes belong
|
|
81
81
|
to the snapshot too.
|
|
82
|
+
Mapped events transition through their listener or subscription actor before
|
|
83
|
+
reaching the owner.
|
|
82
84
|
Subscription `done`/`error` mappings enter the owner's message queue before
|
|
83
85
|
the native child completion/error notification, matching live actor ordering.
|
|
84
86
|
|
package/docs/transitions.md
CHANGED
|
@@ -35,7 +35,7 @@ schemas: {
|
|
|
35
35
|
|
|
36
36
|
There is no `guard` property. Conditions live inside the transition function, which returns `undefined` to reject the event. Check the condition before calling `enq`: a function that calls `enq` is taken even if it returns `undefined`. See [guards](guards.md).
|
|
37
37
|
|
|
38
|
-
A targetless transition can update context and run effects without leaving the current state.
|
|
38
|
+
A targetless transition can update context and run effects without leaving the current state. It does not run exit or entry behavior, even with `reenter: true`. Specify a target and set `reenter: true` when a self-transition should run exit and entry behavior again.
|
|
39
39
|
|
|
40
40
|
```ts
|
|
41
41
|
on: {
|
|
@@ -101,6 +101,10 @@ Transition functions must be synchronous. A transition function that returns a p
|
|
|
101
101
|
|
|
102
102
|
`always` runs without an external event. `after` runs after a delay. `onDone`, `onError` and `onTimeout` handle actor outcomes.
|
|
103
103
|
|
|
104
|
+
When an `after` timer, state timeout, or delayed `enq.raise(...)` becomes due, the delayed event is processed before `always` is reevaluated. Eventless transitions then settle before immediately raised events are processed. Timer bookkeeping does not itself run `always`: a delayed `enq.sendTo(...)` delivers its event without reevaluating eventless transitions in the sender. If the sender is also the recipient, it processes the delivered event and then reevaluates `always`.
|
|
105
|
+
|
|
106
|
+
If an `always` condition depends only on context updated through transitions, it is reevaluated during those updates and cannot become enabled silently while the machine waits. This also applies to observable values whose updates reach the machine as events and update context. The timer ordering issue concerns conditions that read outside mutable values or depend on the current event. `always` does not poll outside values for changes.
|
|
107
|
+
|
|
104
108
|
Use targetless transitions for edits that keep a form on the same step. Use re-entering transitions to restart a timer, subscription or invoked request.
|
|
105
109
|
|
|
106
110
|
Put shared transitions on a parent state. A child can set an event to `undefined` to forbid that parent transition. Wildcards such as `pointer.*` match an event family when no exact transition matches.
|
package/docs/xstate-v5-to-v6.md
CHANGED
|
@@ -34,7 +34,7 @@ This guide is organized by area. Skim the **Quick reference** below and read [§
|
|
|
34
34
|
| `types: {} as { context: ..., events: ...}` | `schemas: { context, events, ... }` (Zod / Standard Schema, or `types<T>()` for type-only) |
|
|
35
35
|
| `actor.send({ type: 'INC' })` | `actor.send(...)` keeps working; new typed `actor.trigger.INC()` |
|
|
36
36
|
| `@xstate/immer` | removed - return updated `context` patches directly |
|
|
37
|
-
| `@xstate/inspect` | removed - use `inspect` option on `createActor`, `actor.subscribe`, or [`@statelyai/inspect`](
|
|
37
|
+
| `@xstate/inspect` | removed - use `inspect` option on `createActor`, `actor.subscribe`, or [`@statelyai/sdk/inspect`](migrate-inspector.md) |
|
|
38
38
|
| `sendTo('child', ev)` with no running `child` | dead letter with reason `'missingTarget'`; the sender stays `active` (§26) |
|
|
39
39
|
| `tsTypes` (typegen) | removed; declare types with `schemas` (§3) |
|
|
40
40
|
| `machine.implementations` | `machine.sources` |
|
|
@@ -1146,7 +1146,7 @@ See [compact finite state machines](fsm.md) for its exact supported surface.
|
|
|
1146
1146
|
- The executable action types are now executable effect types: `ExecutableActionObject` is `ExecutableEffect`, `ExecutableActionsFrom` is `ExecutableEffectFrom`, `SpecialExecutableAction` is `SpecialExecutableEffect`, `ExecutableSpawnAction` is `SpawnExecutableEffect`, and `ToExecutableAction` is `ToExecutableEffect`. The new v6 types and helpers use the same naming, for example `BuiltInExecutableEffect` and `isBuiltInExecutableEffect`.
|
|
1147
1147
|
- `snapshot._nodes` is now `snapshot.nodes`. It lists the active state nodes.
|
|
1148
1148
|
- Implicit state ids no longer use the `(machine)` placeholder. A state's implicit id is its path from the root joined by `.`, prefixed by the machine `id` when the machine has one: `shop.checkout` for `id: 'shop'`, and `checkout` without an id (v5: `(machine).checkout`). `machine.id` and the root's id are `''` for a machine without an `id`, so `#` cannot reference that root; give the machine an `id` to target it. An explicit state `id` that equals another state's id throws.
|
|
1149
|
-
- Bare string transition values (`on: { GO: 'next' }`, `after: { 1000: 'idle' }`, `always: 'ready'`, `onDone: 'done'`) throw when the machine is created: `Transition for "GO" in state "idle" is the string "next". Use { target: 'next' }.` Write `{ target: 'next' }`; the `string-targets` codemod transform rewrites them. `initial` keeps its string form
|
|
1149
|
+
- Bare string transition values (`on: { GO: 'next' }`, `after: { 1000: 'idle' }`, `always: 'ready'`, `onDone: 'done'`) throw when the machine is created: `Transition for "GO" in state "idle" is the string "next". Use { target: 'next' }.` Write `{ target: 'next' }`; the `string-targets` codemod transform rewrites them. `initial` keeps its string form. `xstate/fsm` also requires object targets for `on` and `always`.
|
|
1150
1150
|
- `#` targets and `matches('#…')` resolve by exact id. v5 split the text after `#` at the first `.` and resolved the rest as a path below that id, so `#flow.review` meant "child `review` of the state with id `flow`". In v6, the whole string after `#` is the id: use the target state's own explicit `id`, or its full implicit id. This also applies to `@xstate.stateIn` guards in JSON. Dots in an explicit id are matched literally (`#checkout.v2` for `id: 'checkout.v2'`); v5 required `#checkout\\.v2`. An unresolvable target throws when the machine is created, and suggests the target's id when the old form resolves:
|
|
1151
1151
|
|
|
1152
1152
|
```ts
|
|
@@ -1204,6 +1204,8 @@ If you want Immer-style drafts, call Immer's `produce` yourself inside the inlin
|
|
|
1204
1204
|
|
|
1205
1205
|
### `@xstate/inspect` - removed
|
|
1206
1206
|
|
|
1207
|
+
For a visual inspector, use `createInspector` from `@statelyai/sdk/inspect`. See [Migrate to SDK inspection](migrate-inspector.md) for installation and changes from `@statelyai/inspect`.
|
|
1208
|
+
|
|
1207
1209
|
The standalone inspector package and its `inspect()` entry point are gone. Inspection now flows through:
|
|
1208
1210
|
|
|
1209
1211
|
- `actor.subscribe(observer)` - the snapshot stream
|
|
@@ -1630,7 +1632,7 @@ It runs these transforms in order. `--transform name,name` selects a subset.
|
|
|
1630
1632
|
| Transform | Effect |
|
|
1631
1633
|
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1632
1634
|
| `rename-imports` | Renames `interpret` to `createActor`, `Interpreter` to `Actor`, and `fromCallback`, `fromObservable`, and `fromEventObservable` to their `create*Logic` names, and the executable action types to their executable effect names, including usages. Import aliases are kept. |
|
|
1633
|
-
| `string-targets` | Wraps bare string transition values under `on`, `after`, `onDone`, `onError`, and `always` in `{ target: '...' }` inside `createMachine` and `
|
|
1635
|
+
| `string-targets` | Wraps bare string transition values under `on`, `after`, `onDone`, `onError`, and `always` in `{ target: '...' }` inside `createMachine`, `createStateConfig`, and `createFSM` configs. |
|
|
1634
1636
|
| `types-to-schemas` | Converts `types: {} as { ... }` and the per-key form `types: { context: {} as C, events: {} as E }` to `schemas` with `types<T>()` entries. Events become a map when they are written as a union of object literals with a string-literal `type`, inline or through type aliases declared in the same file. Other event types become `events: types<E>()`, which loads but does not type-check as a v6 event map, so the entry is reported as a manual site to rewrite as a map by hand. A `types` value in any other shape, such as a variable, is reported as a manual site. |
|
|
1635
1637
|
| `lower-actions` | Rewrites transition objects that have `actions` or `guard`, and transition arrays, as one transition function `(args, enq) => { ... }`; non-function `entry` and `exit` values as one function; and the action creators and guard combinators inside them (`assign`, `enqueueActions`, `raise`, `sendTo`, `sendParent`, `forwardTo`, `emit`, `log`, `cancel`, `stopChild`, `spawnChild`, `and`, `or`, `not`, `stateIn`) as `enq` calls, context patches and boolean expressions, following named implementations and module-level constants defined in the same file. Named actions and guards keep their v5 signatures; the generated code calls them as `enq(args.actions.name, args, params)` and `args.guards.name(args, params)`. A named `assign` action becomes a function that returns a context patch. Moves an object-literal second `createMachine` argument into the config, and rewrites `fromPromise(fn)` as `createAsyncLogic({ run: fn })` when `fn` does not read `system` or `emit`. Removes the `'xstate'` imports it leaves unused. A transition, `entry`, or `exit` value that contains anything it cannot rewrite, such as an `enqueueActions` callback that passes `enqueue` as a value or returns early, a guard or action defined in another file, or a named `assign` that `provide()` overrides, is left unchanged and reported by the transforms below. |
|
|
1636
1638
|
| `report-removed-apis` | Reports, without rewriting, uses of `assign`, `raise`, `sendTo`, `sendParent`, `forwardTo`, `emit`, `log`, `cancel`, `spawnChild`, `stop`, `stopChild`, `enqueueActions`, `and`, `or`, `not`, `stateIn`, `fromPromise`, `fromTransition`, `toObserver`, `pathToStateValue`, and `SpecialTargets`, with a suggested replacement. |
|
|
@@ -1994,7 +1996,7 @@ In v5, an undeclared delay name resolved to `undefined`, and the delayed transit
|
|
|
1994
1996
|
- [ ] If you used `events` as a **union**, restructure to a **map keyed by type**
|
|
1995
1997
|
- [ ] Move implementations passed as the second argument of `createMachine(config, implementations)` (deprecated in v5) into `setup({ ... })`, the `createMachine({ ... })` config, or `machine.provide({ ... })` (§4). v6's `createMachine` takes one argument and throws when it receives a second one
|
|
1996
1998
|
- [ ] Audit `invoke.src` references - `src` may be a logic object, a registered name, or a resolver function
|
|
1997
|
-
- [ ] Drop dependencies on `@xstate/immer` and `@xstate/inspect`; update inspection to `actor.subscribe`, the `inspect` option, or `@statelyai/inspect`
|
|
1999
|
+
- [ ] Drop dependencies on `@xstate/immer` and `@xstate/inspect`; update inspection to `actor.subscribe`, the `inspect` option, or `@statelyai/sdk/inspect`
|
|
1998
2000
|
- [ ] Remove imports of `GuardArgs`, `GuardPredicate`, `Inspected*Event`, `PromiseActorLogic`, and `fromPromise` (use `createAsyncLogic`), and update the type arguments of any `SetupReturn<...>` annotation (§16)
|
|
1999
2001
|
- [ ] Drain/migrate any v5 persisted snapshots - the v6 snapshot shape is not binary-compatible
|
|
2000
2002
|
- [ ] Check that persisted `context` holds only JSON values; development builds warn on functions, symbols, `BigInt`, `Map`, `Set`, cycles, `NaN`, and `Infinity`
|