xstate 6.0.0-beta.0 → 6.0.0-beta.2
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/bin/xstate.js +10 -4
- package/dist/{createActor-551369be.development.esm.js → createActor-0250284a.development.esm.js} +244 -41
- package/dist/{createActor-cbe3abac.esm.js → createActor-20a97166.esm.js} +243 -40
- package/dist/{createActor-a49ae0ce.development.cjs.js → createActor-c029d29f.development.cjs.js} +245 -40
- package/dist/{createActor-25900f76.cjs.js → createActor-c91c9ffe.cjs.js} +244 -39
- package/dist/declarations/src/createActor.d.ts +3 -1
- package/dist/declarations/src/createMachine.d.ts +6 -3
- package/dist/declarations/src/durable/index.d.ts +43 -8
- package/dist/declarations/src/effectDescriptor.d.ts +2 -2
- package/dist/declarations/src/machineVersion.types.d.ts +2 -2
- package/dist/declarations/src/setup.d.ts +5 -5
- package/dist/declarations/src/systemTransition.d.ts +1 -1
- package/dist/declarations/src/types.d.ts +11 -3
- package/dist/declarations/src/types.v6.d.ts +37 -2
- package/dist/{effectDescriptor-f73da4ec.development.cjs.js → effectDescriptor-3fff5c51.development.cjs.js} +5 -5
- package/dist/{effectDescriptor-2fa27c54.cjs.js → effectDescriptor-47f73e7e.cjs.js} +5 -5
- package/dist/{effectDescriptor-321a8ce9.development.esm.js → effectDescriptor-5ac7dccb.development.esm.js} +5 -5
- package/dist/{effectDescriptor-d8b0f749.esm.js → effectDescriptor-e93df910.esm.js} +5 -5
- package/dist/{machineSchemas-88d01821.cjs.js → legacySnapshot-8d595687.cjs.js} +117 -1
- package/dist/{machineSchemas-45c21bc2.esm.js → legacySnapshot-9e06feb4.esm.js} +116 -2
- package/dist/{machineSchemas-b5736804.development.esm.js → legacySnapshot-ae6594a7.development.esm.js} +117 -3
- package/dist/{machineSchemas-6d96bef4.development.cjs.js → legacySnapshot-ebf0b2b8.development.cjs.js} +118 -2
- package/dist/xstate-actors.cjs.js +1 -1
- package/dist/xstate-actors.development.cjs.js +1 -1
- package/dist/xstate-actors.development.esm.js +2 -2
- package/dist/xstate-actors.esm.js +2 -2
- 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 +120 -10
- package/dist/xstate-durable.development.cjs.js +120 -10
- package/dist/xstate-durable.development.esm.js +120 -10
- package/dist/xstate-durable.esm.js +120 -10
- 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 +4 -4
- package/dist/xstate-fsm.development.cjs.js +4 -4
- package/dist/xstate-fsm.development.esm.js +4 -4
- package/dist/xstate-fsm.esm.js +4 -4
- 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-graph.umd.min.js +1 -1
- package/dist/xstate-graph.umd.min.js.map +1 -1
- package/dist/xstate-persist.cjs.js +23 -12
- package/dist/xstate-persist.development.cjs.js +23 -12
- package/dist/xstate-persist.development.esm.js +17 -6
- package/dist/xstate-persist.esm.js +17 -6
- 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 +63 -51
- package/dist/xstate.development.cjs.js +63 -51
- package/dist/xstate.development.esm.js +53 -41
- package/dist/xstate.esm.js +53 -41
- package/dist/xstate.umd.min.js +1 -1
- package/dist/xstate.umd.min.js.map +1 -1
- package/docs/agents.md +9 -0
- package/docs/api-stability.json +273 -249
- package/docs/backend-workflows.md +3 -3
- package/docs/durable-execution.md +72 -48
- package/docs/errors.md +2 -2
- package/docs/examples.md +34 -34
- package/docs/fsm.md +2 -1
- package/docs/guards.md +1 -1
- package/docs/index.md +1 -1
- package/docs/invoke.md +34 -2
- package/docs/persistence.md +16 -10
- package/docs/serialization.md +1 -1
- package/docs/setup-and-provide.md +3 -3
- package/docs/spawn.md +1 -1
- package/docs/system-transitions.md +6 -6
- package/docs/tutorial.md +5 -5
- package/docs/typescript.md +9 -0
- package/docs/xstate-v5-to-v6.md +176 -19
- package/package.json +1 -1
package/docs/serialization.md
CHANGED
|
@@ -85,7 +85,7 @@ const machine = machineFromJSON(definition, {
|
|
|
85
85
|
|
|
86
86
|
The second argument supplies the runtime sources the definition refers to: `actions`, `guards`, `actors`, `delays`, and `evaluators` for code expressions. Invokes keep their string `src` names, so a machine built this way can be cloned with different actors through [`provide()`](setup-and-provide.md), including when restoring its children. Deserialization still requires an implementation for every referenced actor; provide the initial implementations in the second argument, then override them by name.
|
|
87
87
|
|
|
88
|
-
Actions in JSON are objects. The built-in vocabulary is `{ type: '@xstate.raise', event, id?, delay? }`, `{ type: '@xstate.emit', event }`, `{ type: '@xstate.assign', context }`, `{ type: '@xstate.cancel', id }` and `{ type: '@xstate.log', args }`. Any other `{ type, params }` object is a custom action resolved against the `actions` sources. Guards are `{ type, params? }` references resolved against `guards`. Two guard types are built in: `{ type: '@xstate.not', params: { guard } }` negates another guard reference or expression, and `{ type: '@xstate.stateIn', params: { stateId: '#id' } }` is true while the state node with that `id` is active (the same check as `snapshot.matches('#id')`). Source names, and the names of `actions`, `guards` and `delays` defined in the JSON, may not start with `xstate.` or `@xstate.`; those prefixes are reserved for built-in names. Because the runtime invokes these references itself, a JSON-referenced guard receives the transition arguments object first and the declared `params` second
|
|
88
|
+
Actions in JSON are objects. The built-in vocabulary is `{ type: '@xstate.raise', event, id?, delay? }`, `{ type: '@xstate.emit', event }`, `{ type: '@xstate.assign', context }`, `{ type: '@xstate.cancel', id }` and `{ type: '@xstate.log', args }`. Any other `{ type, params }` object is a custom action resolved against the `actions` sources. Guards are `{ type, params? }` references resolved against `guards`. Two guard types are built in: `{ type: '@xstate.not', params: { guard } }` negates another guard reference or expression, and `{ type: '@xstate.stateIn', params: { stateId: '#id' } }` is true while the state node with that `id` is active (the same check as `snapshot.matches('#id')`). Source names, and the names of `actions`, `guards` and `delays` defined in the JSON, may not start with `xstate.` or `@xstate.`; those prefixes are reserved for built-in names. Because the runtime invokes these references itself, a JSON-referenced guard receives the transition arguments object first and the declared `params` second. This differs from code-authored machines, where guards are plain functions called by your own transition code.
|
|
89
89
|
|
|
90
90
|
Machines built from JSON round-trip losslessly. The loader copies the definition, and each serialization returns a fresh copy. Mutating either copy does not change the machine.
|
|
91
91
|
|
|
@@ -140,8 +140,8 @@ Validation can be installed, replaced or disabled by a derived setup. Installing
|
|
|
140
140
|
|
|
141
141
|
Where a validation failure surfaces depends on which side of the delivery boundary produced the invalid value:
|
|
142
142
|
|
|
143
|
-
- **Events arriving from outside the actor**
|
|
144
|
-
- **Values the actor produces itself**
|
|
143
|
+
- **Events arriving from outside the actor** (from `actor.send` or from another actor) are rejected at the boundary when their payload fails its schema, or when the event type is undeclared and `unknownEvents` is `'error'`. The event is never delivered: the actor does not transition, does not error, and no API throws. The rejection is reported to the `onRejectedEvent` dead-letter hook on `createActor` options and as a development-mode console warning. In pure `transition(...)` calls, the snapshot is returned unchanged together with a `@xstate.deadLetter` effect carrying the rejection.
|
|
144
|
+
- **Values the actor produces itself** (input, context, output, emitted events and delayed raised events) error the actor when they fail their schema, and pure `transition(...)`/`initialTransition(...)` throw an `ActorValidationError`. These are machine bugs.
|
|
145
145
|
|
|
146
146
|
## Sources on the machine
|
|
147
147
|
|
|
@@ -175,7 +175,7 @@ idle: {
|
|
|
175
175
|
}
|
|
176
176
|
```
|
|
177
177
|
|
|
178
|
-
Named actions and guards are plain functions called with only their params
|
|
178
|
+
Named actions and guards are plain functions called with only their params. Nothing is injected. Pass values from `context` or the event explicitly. Declare param types on the function itself, or with `schemas.actions` and `schemas.guards` so the params are checked before the implementations exist:
|
|
179
179
|
|
|
180
180
|
```ts
|
|
181
181
|
setup({
|
package/docs/spawn.md
CHANGED
|
@@ -46,7 +46,7 @@ The name is checked against `actors`; its required input and returned actor refe
|
|
|
46
46
|
|
|
47
47
|
Passing the logic value remains convenient: `enq.spawn(actors.upload, options)`. XState recovers its registered name when possible. Inline unregistered logic may run but cannot be durably persisted.
|
|
48
48
|
|
|
49
|
-
Spawning with an `id` that a live child of the same parent already uses throws: an address names at most one live actor. Stop the existing child first
|
|
49
|
+
Spawning with an `id` that a live child of the same parent already uses throws: an address names at most one live actor. Stop the existing child first. An id stopped earlier in the same transition is free to reuse, and a child that completed on its own frees its id for the transition handling its completion. Generate ids from something stable, such as a file or participant id.
|
|
50
50
|
|
|
51
51
|
## Where you can spawn
|
|
52
52
|
|
|
@@ -67,8 +67,8 @@ actor's macrostep. Microsteps are atomic; system snapshots contain no unfinished
|
|
|
67
67
|
microstep or continuation state. A UI presenting individual completed
|
|
68
68
|
microsteps within a macrostep needs a separate tracing interface.
|
|
69
69
|
|
|
70
|
-
Snapshot actor references are data: `{
|
|
71
|
-
as `actorPath`, for example `snapshot.actors[snapshot.root].snapshot.children.worker
|
|
70
|
+
Snapshot actor references are data: `{ '@actor': address, incarnation }`, the same shape as `SerializedActorRef`, with a string `incarnation`. Use `@actor`
|
|
71
|
+
as `actorPath`, for example `snapshot.actors[snapshot.root].snapshot.children.worker["@actor"]`.
|
|
72
72
|
Paths encode IDs; avoid concatenating unescaped IDs. Replacing an actor at the
|
|
73
73
|
same path allocates a fresh incarnation.
|
|
74
74
|
|
|
@@ -101,7 +101,7 @@ Select a pending timer in a simulator with its current occurrence:
|
|
|
101
101
|
|
|
102
102
|
```ts
|
|
103
103
|
const selected = snapshot.timers.find((timer) => timer.dueAt === 6000)!;
|
|
104
|
-
const [next] = systemTransition(systemLogic, snapshot, selected.source
|
|
104
|
+
const [next] = systemTransition(systemLogic, snapshot, selected.source["@actor"], {
|
|
105
105
|
type: 'xstate.timer',
|
|
106
106
|
occurrence: selected.occurrence
|
|
107
107
|
});
|
|
@@ -128,7 +128,7 @@ using the source actor's definition and saved input; the host owns the
|
|
|
128
128
|
external implementation. Its result reenters as a correlated input:
|
|
129
129
|
|
|
130
130
|
```ts
|
|
131
|
-
const [resolved] = systemTransition(systemLogic, pendingSnapshot, effect.source
|
|
131
|
+
const [resolved] = systemTransition(systemLogic, pendingSnapshot, effect.source["@actor"], {
|
|
132
132
|
type: 'xstate.system.effect.result',
|
|
133
133
|
effectId: effect.id,
|
|
134
134
|
event: { type: 'xstate.async.resolve', data: result }
|
|
@@ -150,8 +150,8 @@ input, outputs, events and effect arguments are JSON-compatible. Actor reference
|
|
|
150
150
|
state-node references, errors and named mappers use data markers. Errors retain
|
|
151
151
|
name/message. Undefined properties follow ordinary JSON rules. Cycles,
|
|
152
152
|
unregistered functions, live actors, class instances, symbols, bigint and
|
|
153
|
-
nonfinite numbers are rejected.
|
|
154
|
-
|
|
153
|
+
nonfinite numbers are rejected. `@actor`, `@stateNode`, `@error` and
|
|
154
|
+
`@systemMapper` marker shapes are reserved. Logic versions must match on replay.
|
|
155
155
|
|
|
156
156
|
Transition functions, guards and mappers must be deterministic and pure.
|
|
157
157
|
Read external values from input/events and virtual time from `system._clock.now()`.
|
package/docs/tutorial.md
CHANGED
|
@@ -430,7 +430,7 @@ Nothing about the machine changes. A UI reads snapshots and sends events.
|
|
|
430
430
|
|
|
431
431
|
```html
|
|
432
432
|
<p id="status">stopped</p>
|
|
433
|
-
<p id="title"
|
|
433
|
+
<p id="title"></p>
|
|
434
434
|
<button id="play">Play</button> <button id="pause">Pause</button>
|
|
435
435
|
<button id="stop">Stop</button> <button id="previous">Previous</button>
|
|
436
436
|
<button id="next">Next</button> <button id="mute">Mute</button>
|
|
@@ -475,7 +475,7 @@ Frameworks work the same way, with a hook or store binding instead of manual sub
|
|
|
475
475
|
|
|
476
476
|
You built one machine with context, guards, invoked async logic, hierarchy, parallel regions, delayed events, emitted events and a UI. From here:
|
|
477
477
|
|
|
478
|
-
- [Statecharts](statecharts.md)
|
|
479
|
-
- [Actors](actors.md)
|
|
480
|
-
- [Frameworks](frameworks.md)
|
|
481
|
-
- [Testing](testing.md)
|
|
478
|
+
- [Statecharts](statecharts.md): nested, parallel and history states
|
|
479
|
+
- [Actors](actors.md): spawning, communication and actor systems
|
|
480
|
+
- [Frameworks](frameworks.md): bindings for React, Vue, Svelte and Solid
|
|
481
|
+
- [Testing](testing.md): testing machines and the actors that run them
|
package/docs/typescript.md
CHANGED
|
@@ -49,6 +49,12 @@ adding explicit type annotations.
|
|
|
49
49
|
|
|
50
50
|
For an actor used in one state, `invoke: s.createInvoke({ src, input, onDone })` infers input and completion output from `src`. Keep the helper inline in `s.createMachine(...)` to also infer that state's narrowed context, ancestor context, state input and transition target requirements. The helper works alongside named actor sources. See [typed inline invokes](invoke.md#typed-inline-invokes).
|
|
51
51
|
|
|
52
|
+
A bare inline `invoke: { src: logic, onDone }` cannot correlate its source with
|
|
53
|
+
the output; with no registered actor sources it has `event.output: unknown`.
|
|
54
|
+
Use `s.createInvoke(...)` or a source registered in `setup({ actors })` when
|
|
55
|
+
reading the output. This is especially important for generated machine code:
|
|
56
|
+
the bare form cannot infer the output type from `src`.
|
|
57
|
+
|
|
52
58
|
An async function can be used directly as `src`. Declare `schemas.input`, `schemas.output`, and `schemas.error` on the invoke to type the function and its lifecycle handlers together. Without `schemas.output`, `onDone.event.output` infers from the async return value.
|
|
53
59
|
|
|
54
60
|
Public schema event keys create typed methods on `actor.trigger`; internal
|
|
@@ -84,6 +90,9 @@ When `schemas.events` is declared, each key in an `on` map must match a
|
|
|
84
90
|
declared event type. Matching wildcards (`'*'`, `'user.*'`) and known reserved
|
|
85
91
|
machine descriptors are allowed; misspelled or invented reserved prefixes are rejected. Without `schemas.events`, any key is accepted.
|
|
86
92
|
|
|
93
|
+
An empty `schemas.events: {}` means the machine has no public events. Final
|
|
94
|
+
state output callbacks still receive the declared context and input types.
|
|
95
|
+
|
|
87
96
|
```ts
|
|
88
97
|
on: {
|
|
89
98
|
toggel: { target: 'active' }
|
package/docs/xstate-v5-to-v6.md
CHANGED
|
@@ -79,12 +79,12 @@ Beyond simplifying the action/guard surface, v6 introduces a number of features
|
|
|
79
79
|
|
|
80
80
|
## 1. Inline functions replace action creators
|
|
81
81
|
|
|
82
|
-
This is the largest change. Action creators (`assign`, `raise`, `sendTo`, `emit`, `log`, `cancel`, `enqueueActions`, `spawnChild`, `stopChild`, `forwardTo`, `sendParent`) are
|
|
82
|
+
This is the largest change. Action creators (`assign`, `raise`, `sendTo`, `emit`, `log`, `cancel`, `enqueueActions`, `spawnChild`, `stopChild`, `forwardTo`, `sendParent`) are no longer exported.
|
|
83
83
|
|
|
84
|
-
In v6, every `entry`, `exit`, and transition handler is a **single function** that receives `(args, enq)` where `enq` is a queue of side effects. The function can also
|
|
84
|
+
In v6, every `entry`, `exit`, and transition handler is a **single function** that receives `(args, enq)` where `enq` is a queue of side effects. The function can also return an object that the engine applies after it runs:
|
|
85
85
|
|
|
86
86
|
- **Transition handlers** (`on`, `always`, `after`, `onTimeout`, `onDone`, `onError`) - may return a target, a new `context`, `reenter`, or `meta`.
|
|
87
|
-
- **Entry / exit actions** - may return a new `context` (or `children`). They
|
|
87
|
+
- **Entry / exit actions** - may return a new `context` (or `children`). They cannot return a `target`; entry/exit cannot transition.
|
|
88
88
|
|
|
89
89
|
Returned `context` values are patches. XState merges a patch into the current context at the top level (`{ ...context, ...patch }`): omitted keys keep their current values, and a nested object in the patch replaces the current value of that key. If a transition targets a state with a narrower `schemas.context`, the patch type requires the keys needed to satisfy that state's context.
|
|
90
90
|
|
|
@@ -241,7 +241,7 @@ An **entry / exit action** may return:
|
|
|
241
241
|
| `context` | shallow context patch |
|
|
242
242
|
| `children` | replacement children record |
|
|
243
243
|
|
|
244
|
-
Returning nothing (`undefined`) means "no changes". For transition handlers specifically, returning nothing without calling `enq` also means
|
|
244
|
+
Returning nothing (`undefined`) means "no changes". For transition handlers specifically, returning nothing without calling `enq` also means the event is treated as unhandled at this state - useful for inline guarding. A handler that calls `enq` is taken even when it returns nothing, so check the condition first:
|
|
245
245
|
|
|
246
246
|
```ts
|
|
247
247
|
// v6 - guard inline by returning undefined
|
|
@@ -294,6 +294,26 @@ on: {
|
|
|
294
294
|
}
|
|
295
295
|
```
|
|
296
296
|
|
|
297
|
+
### Transitions inside parallel regions
|
|
298
|
+
|
|
299
|
+
A transition whose targets stay inside one region of a parallel state exits
|
|
300
|
+
and reenters that region only. In v5 the same transition, when it reentered
|
|
301
|
+
its source or targeted a child state, exited the whole parallel state and
|
|
302
|
+
reset every sibling region to its initial state. v6 leaves the siblings where
|
|
303
|
+
they are. A transition declared on a sibling region for the same event still
|
|
304
|
+
runs, because the two exit sets no longer overlap.
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
// Parallel state `p` with regions `a` and `b`.
|
|
308
|
+
// Event `t`: `a` reenters itself; `b.b1` moves to `b.b2`.
|
|
309
|
+
// v5 after `t`: { a: 'a1', b: 'b1' }: `b` was reset when `p` was exited.
|
|
310
|
+
// v6 after `t`: { a: 'a1', b: 'b2' }: only `a` was exited.
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Reset the sibling regions explicitly if the v5 behavior was intended: target
|
|
314
|
+
the parallel state itself, or list a target in every region.
|
|
315
|
+
`@xstate/scxml` keeps the SCXML exit semantics for SCXML sources.
|
|
316
|
+
|
|
297
317
|
---
|
|
298
318
|
|
|
299
319
|
## 2. Guards
|
|
@@ -552,7 +572,7 @@ These inferred typestates work as follows. See [Typestates](typestates.md) for t
|
|
|
552
572
|
|
|
553
573
|
<!-- setup state contracts from SetupStateSchema in packages/core/src/setup.ts -->
|
|
554
574
|
|
|
555
|
-
`setup()` still exists in v6 and still accepts `actions`, `guards`, `actors`, and `delays` (merged into every machine created from it). What changed: `types` is replaced by `schemas`, and `setup()` gains a `states` key for declaring **state contracts**. A contract can provide state-level schemas plus structural metadata and defaults such as `type`, `initial`, `history`, `target`, `id`, and `route`. This types `createMachine` and `createStateConfig`, including the `initial: { target, input }` form and transitions targeting those states. Setups that declare only schemas
|
|
575
|
+
`setup()` still exists in v6 and still accepts `actions`, `guards`, `actors`, and `delays` (merged into every machine created from it). What changed: `types` is replaced by `schemas`, and `setup()` gains a `states` key for declaring **state contracts**. A contract can provide state-level schemas plus structural metadata and defaults such as `type`, `initial`, `history`, `target`, `id`, and `route`. This types `createMachine` and `createStateConfig`, including the `initial: { target, input }` form and transitions targeting those states. Setups that declare only schemas don't require state contracts, but unknown literal transition targets are still type errors.
|
|
556
576
|
|
|
557
577
|
```ts
|
|
558
578
|
// v6 - setup with root schemas and state-level input schemas
|
|
@@ -717,7 +737,7 @@ const fetchUser = createAsyncLogic({
|
|
|
717
737
|
});
|
|
718
738
|
```
|
|
719
739
|
|
|
720
|
-
`enq.step(key, exec)` records each step's outcome on the snapshot under `effects[key]`, so on rehydration the step is
|
|
740
|
+
`enq.step(key, exec)` records each step's outcome on the snapshot under `effects[key]`, so on rehydration the step is not re-executed - the previous result is replayed. This makes async logic durable across restarts.
|
|
721
741
|
|
|
722
742
|
When `timeout` elapses, the logic aborts and rejects with `TimeoutError` (also exported):
|
|
723
743
|
|
|
@@ -922,8 +942,8 @@ on: {
|
|
|
922
942
|
|
|
923
943
|
## 12. Internal events
|
|
924
944
|
|
|
925
|
-
Events declared in `schemas.internalEvents` can be
|
|
926
|
-
are
|
|
945
|
+
Events declared in `schemas.internalEvents` can be raised internally but
|
|
946
|
+
are rejected by the public actor protocol. Wildcard patterns are supported.
|
|
927
947
|
|
|
928
948
|
```ts
|
|
929
949
|
const machine = createMachine({
|
|
@@ -994,7 +1014,7 @@ states: {
|
|
|
994
1014
|
|
|
995
1015
|
The function must resolve to a target - returning `undefined` throws "must resolve to a target".
|
|
996
1016
|
|
|
997
|
-
Choice states are entered automatically by routing
|
|
1017
|
+
Choice states are entered automatically by routing into them. They cannot themselves declare `invoke`, `after`, `on`, or `entry`/`exit` (machine creation rejects these).
|
|
998
1018
|
|
|
999
1019
|
---
|
|
1000
1020
|
|
|
@@ -1026,7 +1046,7 @@ State `timeout` and `createAsyncLogic({ timeout })` accept `number` (ms) or `str
|
|
|
1026
1046
|
| Seconds | `'5s'`, `'1.5s'` | integer or decimal + `s` suffix |
|
|
1027
1047
|
| ISO 8601 duration | `'PT5S'`, `'PT1M30S'`, `'PT2H'`, `'P1D'`, `'P1W'`, `'P1DT12H'` | always starts with `P` |
|
|
1028
1048
|
|
|
1029
|
-
Plain `'5m'`, `'1h'`, `'1d'`, `'1w'` (without the `P`/`PT` prefix) are
|
|
1049
|
+
Plain `'5m'`, `'1h'`, `'1d'`, `'1w'` (without the `P`/`PT` prefix) are not accepted - use the ISO 8601 form for anything beyond seconds and milliseconds.
|
|
1030
1050
|
|
|
1031
1051
|
`after` delays accept the same duration formats. A string delay is resolved against the machine's named `delays` first; only strings that don't match a named delay are parsed as durations.
|
|
1032
1052
|
|
|
@@ -1058,13 +1078,18 @@ Transition arrays are not accepted by the authoring APIs. Use a single
|
|
|
1058
1078
|
transition function to select among targets. Serialized transition arrays are
|
|
1059
1079
|
still accepted by `machineFromJSON(...)`.
|
|
1060
1080
|
|
|
1081
|
+
A chain of eventless transitions that never settles ends the actor in v6. The
|
|
1082
|
+
actor processes at most 1000 microsteps per event and then fails with
|
|
1083
|
+
`InfiniteTransitionError`, so `snapshot.status` is `'error'`. v5 ran such a
|
|
1084
|
+
loop until the process ran out of memory.
|
|
1085
|
+
|
|
1061
1086
|
---
|
|
1062
1087
|
|
|
1063
1088
|
## 16. Removed top-level exports
|
|
1064
1089
|
|
|
1065
1090
|
<!-- exports removed from and added to packages/core/src/index.ts on the v6 branch (relative to main / v5) -->
|
|
1066
1091
|
|
|
1067
|
-
These exports have been
|
|
1092
|
+
These exports have been removed from `xstate`:
|
|
1068
1093
|
|
|
1069
1094
|
- Action creators (entire `actions.ts` module): `assign`, `raise`, `sendTo`, `sendParent`, `forwardTo`, `emit`, `log`, `cancel`, `enqueueActions`, `spawnChild`, `stopChild`, `stop`, plus their `*Action`/`*Params` types
|
|
1070
1095
|
- Guard combinators and helpers: `and`, `or`, `not`, `stateIn`
|
|
@@ -1091,7 +1116,7 @@ These exports have been **removed** from `xstate`:
|
|
|
1091
1116
|
|
|
1092
1117
|
`SetupReturn`, the type returned by `setup(...)`, is still exported, but its type parameters changed, so a v5 `SetupReturn<TContext, TEvent, ...>` annotation no longer type-checks. Use `typeof yourSetup` to name the type of a specific setup.
|
|
1093
1118
|
|
|
1094
|
-
These exports have been
|
|
1119
|
+
These exports have been added:
|
|
1095
1120
|
|
|
1096
1121
|
- `setup` (reshaped - see §4) and `createSystem` for typed system registries
|
|
1097
1122
|
- Setup state contract types: `SetupStateSchema`, `SetupStateSchemas`, `SetupStateType`
|
|
@@ -1250,7 +1275,7 @@ on: {
|
|
|
1250
1275
|
|
|
1251
1276
|
## 20. Persistence / rehydration
|
|
1252
1277
|
|
|
1253
|
-
Persisted snapshots round-trip through `JSON.stringify` and rehydrate via `restoreActor(machine, persisted)` from `xstate/persist`. The internal shape changed, so v5 persisted snapshots are
|
|
1278
|
+
Persisted snapshots round-trip through `JSON.stringify` and rehydrate via `restoreActor(machine, persisted)` from `xstate/persist`. The internal shape changed, so v5 persisted snapshots are not binary-compatible with v6 - drain or migrate stored state during your rollout.
|
|
1254
1279
|
|
|
1255
1280
|
```ts
|
|
1256
1281
|
import { restoreActor } from 'xstate/persist';
|
|
@@ -1271,7 +1296,7 @@ Child actors, async logic with effects, and listener-resume semantics are all pa
|
|
|
1271
1296
|
|
|
1272
1297
|
The host serializes the payload. Development builds warn when `context`, `output`, `error`, or state input holds a value that does not survive a JSON round-trip: functions, symbols, `BigInt`, `Map`, `Set`, cycles, `NaN`, and `Infinity`. Persisting a snapshot whose `context` contains a circular reference throws an error that names the actor and the context path. See [Persistence](persistence.md) for the format rules.
|
|
1273
1298
|
|
|
1274
|
-
Actor refs in persisted `context` are stored as `{ "
|
|
1299
|
+
Actor refs in persisted `context` are stored as `{ "@actor": "<address>" }`. v5 stored them as `{ "xstate$$type": 1, "id": "<id>" }`; v6 does not read that shape, so convert those entries with [`machineVersions`](persistence.md#migrate-machine-versions) before restoring v5 snapshots.
|
|
1275
1300
|
|
|
1276
1301
|
### Snapshot versioning
|
|
1277
1302
|
|
|
@@ -1606,13 +1631,143 @@ It runs these transforms in order. `--transform name,name` selects a subset.
|
|
|
1606
1631
|
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1607
1632
|
| `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. |
|
|
1608
1633
|
| `string-targets` | Wraps bare string transition values under `on`, `after`, `onDone`, `onError`, and `always` in `{ target: '...' }` inside `createMachine` and `createStateConfig` configs. |
|
|
1609
|
-
| `types-to-schemas` | Converts `types: {} as { ... }` to `schemas` with `types<T>()` entries. Events become a map
|
|
1634
|
+
| `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
|
+
| `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. |
|
|
1610
1636
|
| `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. |
|
|
1611
1637
|
| `report-id-path-targets` | Reports, without rewriting, `#a.b` targets and `matches('#a.b')` or `stateIn('#a.b')` arguments that are not whole state ids of the machine config that contains them. References outside a `createMachine` or `createStateConfig` config are always reported. v6 resolves `#` targets by exact id only. |
|
|
1638
|
+
| `suffixed-lifecycle-events` | Rewrites `on` keys that use suffixed v5 lifecycle event types to the category type with `matches`: `'xstate.done.actor.job': { target: 'done' }` becomes `'xstate.done.actor': { matches: { actorId: 'job' }, target: 'done' }`, and the same for `xstate.error.actor.<id>`, `xstate.snapshot.<id>` and `xstate.done.state.<id>` (with `stateId`). A function transition moves under `to`. Reports `xstate.after.<delay>.<id>` keys, keys whose category type is already handled in the same `on`, transitions that are not object or function literals, and suffixed type strings elsewhere in the file, such as `event.type === 'xstate.done.actor.job'`. See [Internal lifecycle events](#internal-lifecycle-events). |
|
|
1639
|
+
| `report-inspection-events` | Reports, without rewriting, string literals naming v5 inspection event types: `@xstate.event`, `@xstate.snapshot`, `@xstate.action`, `@xstate.microstep`, and `@xstate.deadletter`. v6 emits only `@xstate.actor` and `@xstate.transition`, so comparisons against the old types never match; TypeScript reports them only when the handler is typed with `InspectionEvent`. Scans every file, including files that do not import `xstate`. |
|
|
1640
|
+
| `report-action-shapes` | Reports, without rewriting, `entry` and `exit` values that are not functions (strings, arrays, objects, identifiers, or calls such as `assign(...)`), and `actions`, `guard`, and `cond` keys on transition objects under `on`, `after`, `always`, `onDone`, `onError`, `onSnapshot`, or an object `initial`, including each element of a transition array, and the transition arrays themselves. v6 rejects these shapes: `entry` and `exit` take a single function `(args, enq) => { ... }`, and transitions queue effects on `enq` and return `{ target }` or `undefined` instead of listing `actions` and `guard`. |
|
|
1641
|
+
| `report-implementations` | Reports, without rewriting, a second argument to `createMachine(config, implementations)` that `lower-actions` did not move into the config, such as a variable. v6 ignores the second argument. |
|
|
1642
|
+
|
|
1643
|
+
`string-targets` wraps string elements inside transition arrays but keeps the arrays. `lower-actions` rewrites a transition array as one function when any element has `actions` or `guard`; `report-action-shapes` reports the arrays that remain. The v6 `createMachine` types reject transition arrays in `on` and `always` (for example, `on: { X: [ … ] }`); replace each with one transition function (§15, §16).
|
|
1644
|
+
|
|
1645
|
+
`lower-actions` converts the action creators and guard combinators it can resolve in the file. Rewrite the reported ones as inline functions by hand (§1, §2). The transforms read and write imports from `'xstate'` only.
|
|
1646
|
+
|
|
1647
|
+
### Exit codes and JSON output
|
|
1648
|
+
|
|
1649
|
+
`migrate` exits with one of these codes:
|
|
1650
|
+
|
|
1651
|
+
| Code | Meaning |
|
|
1652
|
+
| --- | --- |
|
|
1653
|
+
| `0` | No manual migration is needed. |
|
|
1654
|
+
| `1` | Usage error, or the transformed output failed the syntax check and was not written. |
|
|
1655
|
+
| `2` | Manual migration is needed. At least one transform reported a site. |
|
|
1656
|
+
|
|
1657
|
+
`--json` prints one JSON report to stdout instead of the text summary. `manualSites` lists each reported site:
|
|
1658
|
+
|
|
1659
|
+
```json
|
|
1660
|
+
{
|
|
1661
|
+
"filesChanged": 1,
|
|
1662
|
+
"files": [{ "filePath": "...", "changed": true, "transforms": [{ "name": "...", "changed": true, "notes": [] }] }],
|
|
1663
|
+
"manualSites": [{ "file": "...", "line": 12, "column": 7, "api": "assign", "hint": "...", "transform": "report-removed-apis" }]
|
|
1664
|
+
}
|
|
1665
|
+
```
|
|
1666
|
+
|
|
1667
|
+
### Check behavior with `baseline` and `verify`
|
|
1668
|
+
|
|
1669
|
+
<!-- commands, flags and report fields from packages/xstate-codemod/src/verify/cli.ts, run.ts, diff.ts and deltas.ts -->
|
|
1670
|
+
|
|
1671
|
+
`baseline` and `verify` check that a migrated machine behaves like the v5 original. `baseline` loads the v5 module under XState v5, generates event sequences, and records a trace of each one. `verify` loads the migrated module under XState v6, replays the same sequences, and compares the traces step by step. The codemod package includes both XState versions and resolves `'xstate'` imports in the loaded file to the matching one, so the project can have either version installed.
|
|
1672
|
+
|
|
1673
|
+
Record the baseline before `migrate` rewrites the file:
|
|
1674
|
+
|
|
1675
|
+
```bash
|
|
1676
|
+
npx @xstate/codemod baseline src/checkout.ts --out .xstate-migrate/checkout.json
|
|
1677
|
+
npx @xstate/codemod migrate src/checkout.ts
|
|
1678
|
+
# fix the reported manual sites
|
|
1679
|
+
npx @xstate/codemod verify --baseline .xstate-migrate/checkout.json src/checkout.ts
|
|
1680
|
+
```
|
|
1681
|
+
|
|
1682
|
+
When both versions exist as separate files, `verify v5-file v6-file` records the baseline and replays it in one run.
|
|
1683
|
+
|
|
1684
|
+
The loaded module must export the machine. `--export name` selects an export. Otherwise the commands use the `default` export, then the first export that is actor logic. When the module exports more than one machine and `--export` is not passed, the baseline's `notes` and the text output name the exports and the one used.
|
|
1685
|
+
|
|
1686
|
+
#### Sequences
|
|
1687
|
+
|
|
1688
|
+
Sequences come from the v5 machine's shortest paths, its simple paths, and seeded random walks. Random walks also advance a simulated clock to the next pending timer, so they cover delayed transitions. `--walks` (default `25`), `--steps` (default `12`), and `--seed` (default `1`) control the walks. `--max-sequences` (default `200`) caps the total. Simple paths grow quickly with payload cases and parallel states; when `baseline` fails with `CHILD_TIMEOUT`, pass `--no-simple-paths` to skip them. The baseline stores the setting as `simplePaths: false` in `options`.
|
|
1689
|
+
|
|
1690
|
+
While an actor runs, in both versions, `Date.now()` returns `1700000000000` plus the simulated clock's time, `performance.now()` returns the simulated clock's time, and `Math.random()` returns values from a generator seeded by `--seed` and the sequence index. A machine that stores these values in `context` records the same values under v5 and v6. `new Date()` without arguments still reads the real clock.
|
|
1691
|
+
|
|
1692
|
+
Events are sent as `{ type }` unless an events file supplies payloads. Pass `--events events.json`, an object that maps each event type to a list of payloads:
|
|
1693
|
+
|
|
1694
|
+
```json
|
|
1695
|
+
{ "ADD_ITEM": [{ "type": "ADD_ITEM", "sku": "A1" }, { "type": "ADD_ITEM", "sku": "B2" }] }
|
|
1696
|
+
```
|
|
1697
|
+
|
|
1698
|
+
Event types without cases are listed in the report under `eventsWithoutCases`. When a guard throws because an event has no payload, the graph traversal that hit it is dropped and the event is left out of the random walks that reach it; each such case is listed under `generationErrors`. Add payload cases for those events to cover the transitions behind them. A graph traversal that hits its limit, usually because `context` changes on every step, is also listed there; random walks still cover those paths.
|
|
1699
|
+
|
|
1700
|
+
#### Trace
|
|
1701
|
+
|
|
1702
|
+
The baseline records, for the state after start and after each step:
|
|
1703
|
+
|
|
1704
|
+
- `value`, `context`, `status`, `output`, and `error`
|
|
1705
|
+
- `processed`: every event the root actor processed during the step, in order, including raised, delayed, and done events
|
|
1706
|
+
- `children`: the live child actors, by id and source
|
|
1707
|
+
- `sent`: events sent to other actors, with the target id and delay
|
|
1708
|
+
- `emitted`: events emitted with `emit`
|
|
1709
|
+
- `actions`: custom actions run, by type and params
|
|
1710
|
+
|
|
1711
|
+
Before comparison, events are normalized: suffixed v5 lifecycle event types such as `xstate.done.actor.<id>` become the v6 category types with their `actorId`, `stateId`, or `delay` fields, `xstate.init` is dropped, `sessionId` fields are removed, and generated child ids are replaced by `(anon)`. Functions and symbols in `context` and `output` are replaced by markers and counted under `nonSerializable`.
|
|
1712
|
+
|
|
1713
|
+
`verify` compares every field except `actions` by default. `--compare +actions` adds it. Inline v6 actions have no stable type, so `actions` differ after most migrations. When both versions end a step with `status: 'error'`, only `status` and `error` are compared for that step, because a v6 errored snapshot has no `value`. For each sequence, the first mismatching field at a step is reported as one diff. An unclassified diff ends that sequence. A classified diff is recorded and the comparison continues, so an intentional difference cannot hide a later one.
|
|
1714
|
+
|
|
1715
|
+
#### Stubs
|
|
1716
|
+
|
|
1717
|
+
Invoked and spawned actors that are referenced by name are replaced by stubs. A stub defaults to `"pending"`, a promise that never settles. Pass `--stubs stubs.json` to script outcomes and delays:
|
|
1718
|
+
|
|
1719
|
+
```json
|
|
1720
|
+
{
|
|
1721
|
+
"actors": { "fetchUser": { "done": { "id": 1 } }, "saveOrder": { "error": "boom" }, "poll": "pending" },
|
|
1722
|
+
"delays": { "RETRY": 100 }
|
|
1723
|
+
}
|
|
1724
|
+
```
|
|
1725
|
+
|
|
1726
|
+
`done` resolves with the given output, and `error` rejects with the given value. `{}` resolves with `undefined`, and `{ "done": null }` resolves with `null`. `delays` sets named delays on both versions.
|
|
1727
|
+
|
|
1728
|
+
A baseline records one outcome per actor. To cover both the `onDone` and `onError` paths, record a second baseline with a different `--stubs` file.
|
|
1729
|
+
|
|
1730
|
+
#### Input
|
|
1731
|
+
|
|
1732
|
+
Pass `--input input.json` when the machine reads `input`. The file's JSON value is passed as `createActor(logic, { input })` in both versions. `baseline` stores the input in the baseline file, and `verify --baseline` uses it unless `--input` is passed.
|
|
1733
|
+
|
|
1734
|
+
When the machine errors at start, `baseline` and `verify` print `start: machine errored at start: <error>`, and `baseline --json` reports the message as `startError`. A machine that builds `context` from `input` errors this way when no input is passed.
|
|
1735
|
+
|
|
1736
|
+
#### Results
|
|
1737
|
+
|
|
1738
|
+
`verify` exits with one of these codes:
|
|
1739
|
+
|
|
1740
|
+
| Code | Meaning |
|
|
1741
|
+
| --- | --- |
|
|
1742
|
+
| `0` | Equivalent. Every diff, if any, matched an intentional delta. |
|
|
1743
|
+
| `1` | Usage error. |
|
|
1744
|
+
| `3` | Diverged. At least one diff is `unclassified`. |
|
|
1745
|
+
| `4` | A module failed to load or run. `error` has the phase (`baseline` or `replay`), a code such as `EXPORT_NOT_FOUND`, and the message. |
|
|
1746
|
+
|
|
1747
|
+
The default output is a summary and the first five unclassified diffs. `--json` prints the full report. Each entry in `diffs` has the sequence id, the step, the `field`, the v5 value as `expected`, the v6 value as `actual`, a `witness` (the events and clock advances that reproduce the step), and a `classification`. A `status` diff where either side errored also has a `detail` with the error message of each errored side.
|
|
1748
|
+
|
|
1749
|
+
A diff that matches a known v6 change is classified with a rule instead of `unclassified`:
|
|
1750
|
+
|
|
1751
|
+
| Rule | Diff |
|
|
1752
|
+
| --- | --- |
|
|
1753
|
+
| `anonymous-child-id` | Child or send-target ids that differ only by a generated suffix. |
|
|
1754
|
+
| `error-string-shape` | Error strings with the same message after the prefix is removed. |
|
|
1755
|
+
| `context-reference` | `context` that is equal after removing actor-reference keys (`@actor`). |
|
|
1756
|
+
| `done-event-session` | Processed events that are equal after dropping `sessionId`. |
|
|
1757
|
+
| `final-state-output` | `output` that is undefined in v5 and set in v6, because v6 uses a top-level final state's `output` when the root has none (see [Machine output](#machine-output)). |
|
|
1758
|
+
| `root-send-parent` | `status` and `error` where v5 errored with `Unable to send event to actor '#_parent'` and v6 did not, because v6 makes a send to a missing parent a dead letter (see [Sending to a missing target](#sending-to-a-missing-target)). Later fields of that step, such as `value`, can still differ. |
|
|
1759
|
+
|
|
1760
|
+
Fix the v6 code for each unclassified diff. Do not edit the baseline.
|
|
1612
1761
|
|
|
1613
|
-
|
|
1762
|
+
#### Limits
|
|
1614
1763
|
|
|
1615
|
-
|
|
1764
|
+
- Actor logic written inline in `invoke.src` or `spawn` cannot be stubbed. It runs for real in both versions, and its source is listed under `unstubbed`.
|
|
1765
|
+
- Actions run for real. Side effects inside them, such as network requests or writes, happen during `baseline` and `verify`.
|
|
1766
|
+
- `actions` are not compared unless `--compare +actions` is passed. v6 records an `emit` as an action named after the emitted event, so `+actions` reports a diff on every emitting step.
|
|
1767
|
+
- Random walks advance the simulated clock to the next pending timer only. The v6 clock also fires timers scheduled during a jump and the v5 clock does not, so a longer jump would diverge on clock behavior alone.
|
|
1768
|
+
- An equivalent result covers the generated sequences only. Behavior that needs an event payload or actor outcome missing from the events and stubs files is not exercised.
|
|
1769
|
+
- A transition that reenters its own parallel region reports a `value` diff that is not classified. v5 reset the sibling regions and v6 leaves them in place (see "Transitions inside parallel regions"). Confirm that the v6 value is the intended one, or add explicit targets for the siblings.
|
|
1770
|
+
- A machine whose eventless transitions never settle makes `baseline` fail with `CHILD_CRASH` and an out-of-memory message, because v5 has no microstep limit. v6 ends the actor with `InfiniteTransitionError` instead. Fix the loop in the v5 machine before recording a baseline.
|
|
1616
1771
|
|
|
1617
1772
|
### Running v5 and v6 side by side
|
|
1618
1773
|
|
|
@@ -1629,7 +1784,7 @@ import { createMachine as createV5Machine } from 'xstate';
|
|
|
1629
1784
|
import { createMachine } from 'xstate-v6';
|
|
1630
1785
|
```
|
|
1631
1786
|
|
|
1632
|
-
Migrate one file at a time: run the codemod on it, finish the manual changes, then change its `'xstate'` imports to `'xstate-v6'`. When no v5 imports remain, remove the alias and install `xstate@beta` as `xstate`.
|
|
1787
|
+
Migrate one file at a time: run the codemod on it, finish the manual changes, then change its `'xstate'` imports to `'xstate-v6'`. `verify` resolves `'xstate'`, `'xstate/*'`, `'xstate-v6'`, and `'xstate-v6/*'` imports in the migrated file to its own XState v6, so it works before or after the import change. When no v5 imports remain, remove the alias and install `xstate@beta` as `xstate`.
|
|
1633
1788
|
|
|
1634
1789
|
---
|
|
1635
1790
|
|
|
@@ -1685,7 +1840,7 @@ Code written against a v6 alpha uses names that changed before the beta. The old
|
|
|
1685
1840
|
| `xstate.system.cancelEffect`, `xstate.logic.cleanup` effects | `@xstate.cancelEffect`, `@xstate.cleanup` |
|
|
1686
1841
|
| `xstate.logic.effect`, `xstate.log` system effects | `@xstate.effect`, `@xstate.log` |
|
|
1687
1842
|
| suffixed `xstate.done.actor.<id>` etc. descriptors | category types with `matches` (see [Internal lifecycle events](#internal-lifecycle-events)) |
|
|
1688
|
-
| `{ xstate$type: 'actorRef', id, address, src }` | `{
|
|
1843
|
+
| `{ xstate$type: 'actorRef', id, address, src }` | `{ '@actor': address }` (`SerializedActorRef`; `$actor` in 6.0.0-beta.1) |
|
|
1689
1844
|
| persisted timer `startedAt` | `scheduledAt` |
|
|
1690
1845
|
| `snapshot.timers` record keyed by generated ids (`xstate.after.<delay>.<stateId>`, `xstate.timeout.state.<stateId>`, `xstate.timer.auto.<n>`) | list; built-in timers have no `id`, delayed sends without an `id` carry `seq` |
|
|
1691
1846
|
| `scheduleTimer(source, id, delay)`, `cancelTimer(source, id)`, `{ type: 'xstate.timer', id }` | `scheduleTimer(source, timer, delay)`, `cancelTimer(source, timer)`, `{ type: 'xstate.timer', ...timer }` (`TimerKey`) |
|
|
@@ -1825,7 +1980,9 @@ In v5, an undeclared delay name resolved to `undefined`, and the delayed transit
|
|
|
1825
1980
|
|
|
1826
1981
|
## Migration checklist
|
|
1827
1982
|
|
|
1983
|
+
- [ ] Record a behavior baseline for each machine file with `xstate-codemod baseline` (§27)
|
|
1828
1984
|
- [ ] Run `xstate-codemod migrate --dry`, apply it, and migrate the APIs it reports by hand (§27)
|
|
1985
|
+
- [ ] Run `xstate-codemod verify --baseline` on each migrated file and fix every unclassified diff (§27)
|
|
1829
1986
|
- [ ] Replace every `assign({...})` with an inline function returning a shallow `{ context: {...} }` patch
|
|
1830
1987
|
- [ ] Replace every `raise`, `sendTo`, `sendParent`, `forwardTo`, `emit`, `log`, `cancel`, `spawnChild`, `stopChild` with the corresponding `enq.*` call
|
|
1831
1988
|
- [ ] Replace `enqueueActions(...)` with a regular inline `(args, enq) => { ... }` function
|