@xmachines/play-xstate 2.0.0-alpha.1 → 2.0.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 +90 -91
- package/dist/define-player.d.ts +3 -3
- package/dist/define-player.js +3 -3
- package/dist/errors.d.ts +46 -70
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +69 -77
- package/dist/errors.js.map +1 -1
- package/dist/guards/compose.d.ts +49 -59
- package/dist/guards/compose.d.ts.map +1 -1
- package/dist/guards/compose.js +68 -95
- package/dist/guards/compose.js.map +1 -1
- package/dist/guards/helpers.d.ts +6 -2
- package/dist/guards/helpers.d.ts.map +1 -1
- package/dist/guards/helpers.js +6 -2
- package/dist/guards/helpers.js.map +1 -1
- package/dist/guards/index.d.ts +7 -0
- package/dist/guards/index.d.ts.map +1 -1
- package/dist/guards/index.js +7 -0
- package/dist/guards/index.js.map +1 -1
- package/dist/guards/types.d.ts +4 -5
- package/dist/guards/types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -4
- package/dist/index.js.map +1 -1
- package/dist/player-actor.d.ts +112 -44
- package/dist/player-actor.d.ts.map +1 -1
- package/dist/player-actor.js +311 -327
- package/dist/player-actor.js.map +1 -1
- package/dist/routing/build-url.d.ts +2 -7
- package/dist/routing/build-url.d.ts.map +1 -1
- package/dist/routing/build-url.js +21 -25
- package/dist/routing/build-url.js.map +1 -1
- package/dist/routing/derive-current-route.d.ts +32 -0
- package/dist/routing/derive-current-route.d.ts.map +1 -1
- package/dist/routing/derive-current-route.js +20 -19
- package/dist/routing/derive-current-route.js.map +1 -1
- package/dist/routing/derive-initial-route.d.ts +1 -4
- package/dist/routing/derive-initial-route.d.ts.map +1 -1
- package/dist/routing/derive-initial-route.js +1 -4
- package/dist/routing/derive-initial-route.js.map +1 -1
- package/dist/routing/format-play-route-transitions.d.ts +11 -54
- package/dist/routing/format-play-route-transitions.d.ts.map +1 -1
- package/dist/routing/format-play-route-transitions.js +65 -125
- package/dist/routing/format-play-route-transitions.js.map +1 -1
- package/dist/routing/index.d.ts +1 -5
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +1 -3
- package/dist/routing/index.js.map +1 -1
- package/dist/types.d.ts +87 -14
- package/dist/types.d.ts.map +1 -1
- package/dist/view/derive-current-view.d.ts +49 -0
- package/dist/view/derive-current-view.d.ts.map +1 -0
- package/dist/view/derive-current-view.js +115 -0
- package/dist/view/derive-current-view.js.map +1 -0
- package/package.json +22 -22
- package/dist/define-player.typecheck.d.ts +0 -2
- package/dist/define-player.typecheck.d.ts.map +0 -1
- package/dist/define-player.typecheck.js +0 -48
- package/dist/define-player.typecheck.js.map +0 -1
- package/dist/guards/compose.typecheck.d.ts +0 -2
- package/dist/guards/compose.typecheck.d.ts.map +0 -1
- package/dist/guards/compose.typecheck.js +0 -22
- package/dist/guards/compose.typecheck.js.map +0 -1
- package/dist/player-actor.typecheck.d.ts +0 -2
- package/dist/player-actor.typecheck.d.ts.map +0 -1
- package/dist/player-actor.typecheck.js +0 -30
- package/dist/player-actor.typecheck.js.map +0 -1
- package/dist/routing/create-routed-machine.d.ts +0 -71
- package/dist/routing/create-routed-machine.d.ts.map +0 -1
- package/dist/routing/create-routed-machine.js +0 -71
- package/dist/routing/create-routed-machine.js.map +0 -1
- package/dist/routing/play-route-event.typecheck.d.ts +0 -2
- package/dist/routing/play-route-event.typecheck.d.ts.map +0 -1
- package/dist/routing/play-route-event.typecheck.js +0 -43
- package/dist/routing/play-route-event.typecheck.js.map +0 -1
- package/dist/routing/schemas.d.ts +0 -99
- package/dist/routing/schemas.d.ts.map +0 -1
- package/dist/routing/schemas.js +0 -30
- package/dist/routing/schemas.js.map +0 -1
- package/dist/schemas.d.ts +0 -28
- package/dist/schemas.d.ts.map +0 -1
- package/dist/schemas.js +0 -29
- package/dist/schemas.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
<!-- generated-by: gsd-doc-writer -->
|
|
2
|
-
|
|
3
1
|
# @xmachines/play-xstate
|
|
4
2
|
|
|
5
|
-
> XState
|
|
3
|
+
> XState v5 adapter for the XMachines Play Architecture — bind state machines to the actor base with signal-driven reactivity and router integration.
|
|
6
4
|
|
|
7
|
-
[](https://opensource.org/licenses/MIT)
|
|
8
|
-
[](https://www.npmjs.com/package/@xmachines/play-xstate)
|
|
5
|
+
[](https://opensource.org/licenses/MIT) [](https://www.npmjs.com/package/@xmachines/play-xstate)
|
|
9
6
|
|
|
10
7
|
Part of the [XMachines Play](../../README.md) monorepo.
|
|
11
8
|
|
|
@@ -17,7 +14,7 @@ Part of the [XMachines Play](../../README.md) monorepo.
|
|
|
17
14
|
pnpm add @xmachines/play-xstate xstate
|
|
18
15
|
```
|
|
19
16
|
|
|
20
|
-
`xstate ^
|
|
17
|
+
`xstate ^5.31.0` is a peer dependency and must be installed alongside this package.
|
|
21
18
|
|
|
22
19
|
---
|
|
23
20
|
|
|
@@ -25,18 +22,13 @@ pnpm add @xmachines/play-xstate xstate
|
|
|
25
22
|
|
|
26
23
|
```typescript
|
|
27
24
|
import { setup } from "xstate";
|
|
28
|
-
import { definePlayer
|
|
25
|
+
import { definePlayer } from "@xmachines/play-xstate";
|
|
29
26
|
|
|
30
|
-
// 1. Define your XState
|
|
31
|
-
const machine = setup({
|
|
32
|
-
schemas: {
|
|
33
|
-
events: { activate: emptyEventSchema },
|
|
34
|
-
meta: playMetaSchema, // types meta.route / meta.view on state nodes
|
|
35
|
-
},
|
|
36
|
-
}).createMachine({
|
|
27
|
+
// 1. Define your XState v5 machine
|
|
28
|
+
const machine = setup({}).createMachine({
|
|
37
29
|
initial: "idle",
|
|
38
30
|
states: {
|
|
39
|
-
idle: { meta: { route: "/" }
|
|
31
|
+
idle: { meta: { route: "/" } },
|
|
40
32
|
active: { meta: { route: "/active" } },
|
|
41
33
|
},
|
|
42
34
|
});
|
|
@@ -64,16 +56,16 @@ actor.stop();
|
|
|
64
56
|
|
|
65
57
|
### `definePlayer(config)`
|
|
66
58
|
|
|
67
|
-
Creates a `PlayerFactory` from an XState
|
|
59
|
+
Creates a `PlayerFactory` from an XState v5 machine. The factory pattern enables multiple independent actor instances from a single configuration — useful for multi-user scenarios, SSR, or testing.
|
|
68
60
|
|
|
69
61
|
```typescript
|
|
70
|
-
import { setup
|
|
62
|
+
import { setup } from "xstate";
|
|
71
63
|
import { definePlayer } from "@xmachines/play-xstate";
|
|
72
64
|
|
|
73
65
|
const machine = setup({
|
|
74
|
-
|
|
75
|
-
context:
|
|
76
|
-
input:
|
|
66
|
+
types: {
|
|
67
|
+
context: {} as { userId: string },
|
|
68
|
+
input: {} as { userId: string },
|
|
77
69
|
},
|
|
78
70
|
}).createMachine({
|
|
79
71
|
context: ({ input }) => ({ userId: input.userId }),
|
|
@@ -89,6 +81,7 @@ const createPlayer = definePlayer({
|
|
|
89
81
|
onTransition: (actor, prev, next) => console.log("transitioned"),
|
|
90
82
|
onStateChange: (actor, state) => console.log("state changed"),
|
|
91
83
|
onError: (actor, err) => console.error(err),
|
|
84
|
+
inspect: (event) => console.log(event.type), // handed to XState's actor constructor — enables @statelyai/inspect
|
|
92
85
|
},
|
|
93
86
|
});
|
|
94
87
|
|
|
@@ -99,17 +92,27 @@ const bob = createPlayer({ userId: "bob" });
|
|
|
99
92
|
|
|
100
93
|
#### `PlayerFactory` signature
|
|
101
94
|
|
|
95
|
+
`input` requiredness mirrors XState's `createActor`: a machine whose input type
|
|
96
|
+
cannot be `undefined` makes the factory's first argument required, so forgetting
|
|
97
|
+
it is a compile error instead of an actor stuck in an error status.
|
|
98
|
+
|
|
102
99
|
```typescript
|
|
103
|
-
type PlayerFactory<TMachine> =
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
100
|
+
type PlayerFactory<TMachine> =
|
|
101
|
+
undefined extends InputFrom<TMachine>
|
|
102
|
+
? (
|
|
103
|
+
input?: InputFrom<TMachine>,
|
|
104
|
+
options?: PlayerFactoryResumeOptions<TMachine>,
|
|
105
|
+
) => PlayerActor<TMachine>
|
|
106
|
+
: (
|
|
107
|
+
input: InputFrom<TMachine>,
|
|
108
|
+
options?: PlayerFactoryResumeOptions<TMachine>,
|
|
109
|
+
) => PlayerActor<TMachine>;
|
|
107
110
|
```
|
|
108
111
|
|
|
109
112
|
#### Restoring from a snapshot
|
|
110
113
|
|
|
111
114
|
```typescript
|
|
112
|
-
const snapshot = actor.
|
|
115
|
+
const snapshot = actor.getPersistedSnapshot();
|
|
113
116
|
actor.stop();
|
|
114
117
|
|
|
115
118
|
// Restore to the exact saved state
|
|
@@ -118,11 +121,15 @@ restored.start();
|
|
|
118
121
|
console.log(restored.currentRoute.get()); // same route as when saved
|
|
119
122
|
```
|
|
120
123
|
|
|
124
|
+
> **Note:** Persist with `getPersistedSnapshot()`, not `getSnapshot()` — it is
|
|
125
|
+
> the form `createActor` accepts, and the only one that round-trips machines
|
|
126
|
+
> with invoked or spawned children.
|
|
127
|
+
|
|
121
128
|
---
|
|
122
129
|
|
|
123
130
|
### `PlayerActor<TMachine>`
|
|
124
131
|
|
|
125
|
-
Concrete actor class
|
|
132
|
+
Concrete actor class: an XState v5 actor that also exposes TC39 Signal-based reactive signals. Implements both `Routable` and `Viewable` interfaces from `@xmachines/play-actor`.
|
|
126
133
|
|
|
127
134
|
#### Signals
|
|
128
135
|
|
|
@@ -163,7 +170,11 @@ actor.start();
|
|
|
163
170
|
|
|
164
171
|
### Guard utilities
|
|
165
172
|
|
|
166
|
-
|
|
173
|
+
> **Deprecated:** the guard helpers wrap XState's own `and()` / `or()` / `not()`
|
|
174
|
+
> combinators without composing with `setup()`-typed guard slots. Use XState's
|
|
175
|
+
> combinators directly; this module will be removed in the next major.
|
|
176
|
+
|
|
177
|
+
Composable guard helpers that wrap XState's built-in `and()`, `or()`, and `not()` for use in machine `setup({ guards })` definitions.
|
|
167
178
|
|
|
168
179
|
```typescript
|
|
169
180
|
import { setup } from "xstate";
|
|
@@ -176,24 +187,20 @@ import {
|
|
|
176
187
|
contextFieldMatches, // guard: context field equals a value
|
|
177
188
|
} from "@xmachines/play-xstate";
|
|
178
189
|
|
|
179
|
-
const canAccessAdmin = composeGuards(["isLoggedIn", "hasAdminRole"]);
|
|
180
|
-
const isAuthenticated = negateGuard("isGuest");
|
|
181
|
-
|
|
182
190
|
const machine = setup({
|
|
183
191
|
guards: {
|
|
184
192
|
isLoggedIn: ({ context }) => !!context.userId,
|
|
185
193
|
hasAdminRole: ({ context }) => context.role === "admin",
|
|
186
|
-
isGuest: ({ context }) => !context.userId,
|
|
187
194
|
},
|
|
188
195
|
}).createMachine({
|
|
189
196
|
on: {
|
|
190
|
-
accessAdmin:
|
|
191
|
-
|
|
192
|
-
|
|
197
|
+
accessAdmin: {
|
|
198
|
+
guard: composeGuards(["isLoggedIn", "hasAdminRole"]),
|
|
199
|
+
target: "adminPanel",
|
|
193
200
|
},
|
|
194
|
-
accessDashboard:
|
|
195
|
-
|
|
196
|
-
|
|
201
|
+
accessDashboard: {
|
|
202
|
+
guard: negateGuard("isGuest"),
|
|
203
|
+
target: "dashboard",
|
|
197
204
|
},
|
|
198
205
|
},
|
|
199
206
|
// ...
|
|
@@ -206,42 +213,13 @@ const machine = setup({
|
|
|
206
213
|
|
|
207
214
|
Helper functions for declarative route configuration in XState machines.
|
|
208
215
|
|
|
209
|
-
#### `createRoutedMachine(setup)`
|
|
210
|
-
|
|
211
|
-
The recommended entry point: returns a `createMachine` with the same signature as the setup's own — full contextual typing for the config — that wires routing up at runtime.
|
|
212
|
-
|
|
213
|
-
```typescript
|
|
214
|
-
import { setup } from "xstate";
|
|
215
|
-
import { createRoutedMachine } from "@xmachines/play-xstate";
|
|
216
|
-
|
|
217
|
-
const appSetup = setup({/* schemas, guards, ... */});
|
|
218
|
-
|
|
219
|
-
const machine = createRoutedMachine(appSetup)({
|
|
220
|
-
id: "app",
|
|
221
|
-
states: {
|
|
222
|
-
home: {
|
|
223
|
-
id: "home",
|
|
224
|
-
meta: { route: "/home" },
|
|
225
|
-
},
|
|
226
|
-
profile: {
|
|
227
|
-
id: "profile",
|
|
228
|
-
meta: { route: "/users/:userId" },
|
|
229
|
-
},
|
|
230
|
-
},
|
|
231
|
-
});
|
|
232
|
-
```
|
|
233
|
-
|
|
234
216
|
#### `formatPlayRouteTransitions(machineConfig)`
|
|
235
217
|
|
|
236
|
-
|
|
218
|
+
Crawls machine states with `meta.route` and auto-generates `play.route` event handlers at the root level — eliminating boilerplate routing transitions.
|
|
237
219
|
|
|
238
220
|
```typescript
|
|
239
221
|
import { setup } from "xstate";
|
|
240
|
-
import {
|
|
241
|
-
formatPlayRouteTransitions,
|
|
242
|
-
playMetaSchema,
|
|
243
|
-
playRouteEventSchema,
|
|
244
|
-
} from "@xmachines/play-xstate";
|
|
222
|
+
import { formatPlayRouteTransitions } from "@xmachines/play-xstate";
|
|
245
223
|
|
|
246
224
|
const config = formatPlayRouteTransitions({
|
|
247
225
|
id: "app",
|
|
@@ -257,47 +235,69 @@ const config = formatPlayRouteTransitions({
|
|
|
257
235
|
},
|
|
258
236
|
});
|
|
259
237
|
|
|
260
|
-
// config now
|
|
261
|
-
//
|
|
262
|
-
|
|
263
|
-
// The forwarder navigates injected-route targets directly (atomically);
|
|
264
|
-
// xstate.route is raised only for states declaring their own route config.
|
|
265
|
-
const machine = setup({
|
|
266
|
-
schemas: {
|
|
267
|
-
events: { "play.route": playRouteEventSchema },
|
|
268
|
-
meta: playMetaSchema,
|
|
269
|
-
},
|
|
270
|
-
}).createMachine(config);
|
|
238
|
+
// config now includes auto-generated play.route handlers:
|
|
239
|
+
// on: { "play.route": [ { target: ".home", guard: e => e.to === "#home" }, ... ] }
|
|
240
|
+
const machine = setup({}).createMachine(config);
|
|
271
241
|
```
|
|
272
242
|
|
|
273
|
-
Because the injected `route` configs are static, route transitions keep statically-known targets — `machineToGraph()` sees real edges to every routed state, so reachability queries work.
|
|
274
|
-
|
|
275
243
|
> **Note:** Every state with `meta.route` must also have an explicit `id` field; omitting it throws `MissingStateIdError` at machine-definition time.
|
|
276
244
|
|
|
277
245
|
#### Other routing exports
|
|
278
246
|
|
|
279
247
|
| Export | Description |
|
|
280
248
|
| ---------------------------------- | ------------------------------------------------------------------------- |
|
|
281
|
-
| `playMetaSchema` | Shared `schemas.meta` declaration for `meta.route` / `meta.view` metadata |
|
|
282
|
-
| `playRouteEventSchema` | Shared `schemas.events` entry for the `play.route` event payload |
|
|
283
|
-
| `emptyEventSchema` | Shared `schemas.events` entry for events that carry no payload |
|
|
284
249
|
| `deriveRoute(meta)` | Extract the route template string from a state's metadata object |
|
|
285
250
|
| `isAbsoluteRoute(route)` | Returns `true` if the route string is an absolute URL path |
|
|
286
251
|
| `buildRouteUrl(template, context)` | Substitute `:param` placeholders in a route template using context values |
|
|
287
252
|
|
|
288
253
|
---
|
|
289
254
|
|
|
255
|
+
## Inspection
|
|
256
|
+
|
|
257
|
+
`options.inspect` is forwarded verbatim to XState's `createActor`, so every XState
|
|
258
|
+
inspection tool — [`@statelyai/inspect`](https://stately.ai/docs/inspector)
|
|
259
|
+
included — works against a `PlayerActor` unchanged:
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
import { createBrowserInspector } from "@statelyai/inspect";
|
|
263
|
+
|
|
264
|
+
const { inspect } = createBrowserInspector();
|
|
265
|
+
const createPlayer = definePlayer({ machine, options: { inspect } });
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Three things are worth knowing:
|
|
269
|
+
|
|
270
|
+
- **It is a factory option, not a per-instance one.** Every actor a factory creates
|
|
271
|
+
reports to the same observer. Demultiplex by root: `event.rootId === actor.sessionId`
|
|
272
|
+
covers an actor's whole tree, children included.
|
|
273
|
+
- **It is the only route that sees construction.** `actor.system.inspect(fn)` attaches
|
|
274
|
+
later and only sees events from that point on — including missing the `@xstate.actor`
|
|
275
|
+
registration an inspector needs in order to draw the machine at all.
|
|
276
|
+
- **A `PlayerActor` is the actor.** Its own events carry `actorRef === playerActor`, so a
|
|
277
|
+
player can be recognised by identity. The one caveat: `@xstate.actor` fires from inside
|
|
278
|
+
the constructor, where `state`, `currentRoute`, `currentView` and `initialRoute` do not
|
|
279
|
+
exist yet — reading them there throws.
|
|
280
|
+
|
|
281
|
+
For an inspector created after the factory (a dev-tools toggle, say), pass a forwarding
|
|
282
|
+
function: `inspect: (event) => currentInspector?.(event)`.
|
|
283
|
+
|
|
284
|
+
See the [inspector guide](../docs/guides/inspector.md) for the full walkthrough —
|
|
285
|
+
late attachment with replay, browser-free WebSocket inspection, and production
|
|
286
|
+
considerations.
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
290
|
## Exported Types
|
|
291
291
|
|
|
292
292
|
```typescript
|
|
293
293
|
import type {
|
|
294
294
|
PlayerConfig, // definePlayer() config argument shape
|
|
295
|
-
PlayerOptions, // Lifecycle hooks (onStart, onStop, onTransition, onStateChange, onError)
|
|
295
|
+
PlayerOptions, // Lifecycle hooks (onStart, onStop, onTransition, onStateChange, onError) + inspect
|
|
296
296
|
PlayerFactory, // Factory function returned by definePlayer()
|
|
297
297
|
PlayerFactoryResumeOptions, // { snapshot? } for restoring actor state
|
|
298
|
-
Guard, //
|
|
299
|
-
GuardArray, //
|
|
300
|
-
ComposedGuard, //
|
|
298
|
+
Guard, // deprecated with the guard utilities — removed in the next major
|
|
299
|
+
GuardArray, // deprecated with the guard utilities — removed in the next major
|
|
300
|
+
ComposedGuard, // deprecated with the guard utilities — removed in the next major
|
|
301
301
|
RouteMachineConfig, // Minimal machine config accepted by formatPlayRouteTransitions
|
|
302
302
|
RouteStateNode, // Single state node shape used during route crawling
|
|
303
303
|
RouteContext, // Context shape expected by buildRouteUrl ({ params?, query?, basePath?, hash? })
|
|
@@ -315,14 +315,13 @@ Error classes are exported from the `@xmachines/play-xstate/errors` sub-path to
|
|
|
315
315
|
```typescript
|
|
316
316
|
import {
|
|
317
317
|
MissingRouteParamError, // Required :param absent from context when resolving currentRoute
|
|
318
|
-
MissingQueryContextError, //
|
|
318
|
+
MissingQueryContextError, // deprecated: no longer thrown
|
|
319
319
|
MissingStateIdError, // meta.route declared without a state id field
|
|
320
320
|
InvalidMachineError, // PlayerActor constructed with a non-object machine
|
|
321
321
|
InvalidEventError, // actor.send() called with null/undefined/non-object
|
|
322
|
+
ActorThrewNonErrorError, // actor failed with a thrown value that is not an Error
|
|
322
323
|
InvalidRouteMetadataError, // meta.route is neither a string nor { path: string }
|
|
323
324
|
EmptyGuardArrayError, // composeGuards/composeGuardsOr called with empty array
|
|
324
|
-
UnresolvableGuardNameError, // string guard name could not be resolved at call time
|
|
325
|
-
InvalidGuardEntryError, // guard entry was neither a predicate nor a name (e.g. undefined)
|
|
326
325
|
} from "@xmachines/play-xstate/errors";
|
|
327
326
|
```
|
|
328
327
|
|
package/dist/define-player.d.ts
CHANGED
|
@@ -3,15 +3,15 @@ import type { PlayerConfig, PlayerFactory } from "./types.js";
|
|
|
3
3
|
/**
|
|
4
4
|
* Create a player factory from an XState machine
|
|
5
5
|
*
|
|
6
|
-
* Factory pattern that accepts an XState
|
|
6
|
+
* Factory pattern that accepts an XState v5 machine,
|
|
7
7
|
* returning a function that creates {@link PlayerActor} instances. This enables
|
|
8
8
|
* creating multiple actor instances from a single configuration, useful for
|
|
9
9
|
* testing, multi-instance scenarios, or server-side rendering.
|
|
10
10
|
*
|
|
11
|
-
* @typeParam TMachine - XState
|
|
11
|
+
* @typeParam TMachine - XState v5 state machine type
|
|
12
12
|
*
|
|
13
13
|
* @param config - Player configuration object
|
|
14
|
-
* @param config.machine - XState
|
|
14
|
+
* @param config.machine - XState v5 state machine
|
|
15
15
|
* @param config.options - Optional lifecycle hooks (onStart, onTransition, etc.)
|
|
16
16
|
*
|
|
17
17
|
* @returns Factory function that creates actor instances with optional input context
|
package/dist/define-player.js
CHANGED
|
@@ -2,15 +2,15 @@ import { PlayerActor } from "./player-actor.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Create a player factory from an XState machine
|
|
4
4
|
*
|
|
5
|
-
* Factory pattern that accepts an XState
|
|
5
|
+
* Factory pattern that accepts an XState v5 machine,
|
|
6
6
|
* returning a function that creates {@link PlayerActor} instances. This enables
|
|
7
7
|
* creating multiple actor instances from a single configuration, useful for
|
|
8
8
|
* testing, multi-instance scenarios, or server-side rendering.
|
|
9
9
|
*
|
|
10
|
-
* @typeParam TMachine - XState
|
|
10
|
+
* @typeParam TMachine - XState v5 state machine type
|
|
11
11
|
*
|
|
12
12
|
* @param config - Player configuration object
|
|
13
|
-
* @param config.machine - XState
|
|
13
|
+
* @param config.machine - XState v5 state machine
|
|
14
14
|
* @param config.options - Optional lifecycle hooks (onStart, onTransition, etc.)
|
|
15
15
|
*
|
|
16
16
|
* @returns Factory function that creates actor instances with optional input context
|
package/dist/errors.d.ts
CHANGED
|
@@ -8,16 +8,17 @@ import { PlayError } from "@xmachines/play";
|
|
|
8
8
|
*
|
|
9
9
|
* **Error code:** `PLAY_XSTATE_ROUTE_PARAM_MISSING`
|
|
10
10
|
*
|
|
11
|
+
* Note: `actor.currentRoute.get()` never surfaces this error — route
|
|
12
|
+
* derivation catches it and returns `null` for the transient mid-transition
|
|
13
|
+
* case. It only escapes direct `buildRouteUrl()` calls.
|
|
14
|
+
*
|
|
11
15
|
* @example
|
|
12
16
|
* ```typescript
|
|
17
|
+
* import { buildRouteUrl } from "@xmachines/play-xstate";
|
|
13
18
|
* import { MissingRouteParamError } from "@xmachines/play-xstate/errors";
|
|
14
19
|
*
|
|
15
|
-
* // The route template "/profile/:userId" requires "userId" in context.
|
|
16
|
-
* // If userId is absent, MissingRouteParamError is thrown when the
|
|
17
|
-
* // actor.currentRoute signal is read.
|
|
18
|
-
*
|
|
19
20
|
* try {
|
|
20
|
-
*
|
|
21
|
+
* buildRouteUrl("/profile/:userId", { params: {}, query: {} });
|
|
21
22
|
* } catch (err) {
|
|
22
23
|
* if (err instanceof MissingRouteParamError) {
|
|
23
24
|
* console.error(
|
|
@@ -35,36 +36,18 @@ export declare class MissingRouteParamError extends PlayError {
|
|
|
35
36
|
constructor(param: string, template: string);
|
|
36
37
|
}
|
|
37
38
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
39
|
+
* @deprecated Never thrown any more. `buildRouteUrl` treats a missing `query`
|
|
40
|
+
* field as `query: {}` — the generated `play.route` transitions assign
|
|
41
|
+
* `query` on every navigation, so the loss this error guarded against cannot
|
|
42
|
+
* occur through route derivation. Machines that handle `play.route` by hand
|
|
43
|
+
* and want query forwarding must assign `event.query` to context themselves.
|
|
44
|
+
* Kept exported so existing `instanceof` handlers keep compiling; remove them
|
|
45
|
+
* at leisure.
|
|
44
46
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* If using `formatPlayRouteTransitions`, the field is assigned automatically on each
|
|
48
|
-
* `play.route` event — but the machine's initial context must still declare it.
|
|
47
|
+
* Formerly thrown by `buildRouteUrl()` when the context had a `params` field
|
|
48
|
+
* (a routing-aware machine context) but no `query` field.
|
|
49
49
|
*
|
|
50
50
|
* **Error code:** `PLAY_XSTATE_MISSING_QUERY_CONTEXT`
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
* ```typescript
|
|
54
|
-
* import { MissingQueryContextError } from "@xmachines/play-xstate/errors";
|
|
55
|
-
*
|
|
56
|
-
* try {
|
|
57
|
-
* // params present but no query field — throws
|
|
58
|
-
* buildRouteUrl("/profile/:userId", { params: { userId: "42" } });
|
|
59
|
-
* } catch (err) {
|
|
60
|
-
* if (err instanceof MissingQueryContextError) {
|
|
61
|
-
* console.error("Machine context missing query field");
|
|
62
|
-
* }
|
|
63
|
-
* }
|
|
64
|
-
*
|
|
65
|
-
* // Correct — both params and query declared
|
|
66
|
-
* buildRouteUrl("/profile/:userId", { params: { userId: "42" }, query: {} });
|
|
67
|
-
* ```
|
|
68
51
|
*/
|
|
69
52
|
export declare class MissingQueryContextError extends PlayError {
|
|
70
53
|
constructor();
|
|
@@ -137,44 +120,6 @@ export declare class EmptyGuardArrayError extends PlayError {
|
|
|
137
120
|
readonly combinator: "and" | "or";
|
|
138
121
|
constructor(combinator: "and" | "or");
|
|
139
122
|
}
|
|
140
|
-
/**
|
|
141
|
-
* The guard-composition helper a composed guard was built by. Threaded into
|
|
142
|
-
* guard errors so `PlayError.scope` names the actual origin.
|
|
143
|
-
*/
|
|
144
|
-
export type GuardCombinator = "composeGuards" | "composeGuardsOr" | "negateGuard";
|
|
145
|
-
/**
|
|
146
|
-
* Thrown when a composed guard cannot resolve a string guard name at call time.
|
|
147
|
-
*
|
|
148
|
-
* String names in `composeGuards`/`composeGuardsOr`/`negateGuard` resolve
|
|
149
|
-
* against `args.guards` — the named guards from `setup({ guards })` that
|
|
150
|
-
* XState v6 provides to transition functions, `always`, entry/exit actions
|
|
151
|
-
* (since 6.0.0-alpha.20), and function-form route resolvers. Resolution fails
|
|
152
|
-
* when the name was never declared or when the composed guard is called
|
|
153
|
-
* without transition arguments.
|
|
154
|
-
*
|
|
155
|
-
* **Error code:** `PLAY_XSTATE_UNRESOLVABLE_GUARD_NAME`
|
|
156
|
-
*/
|
|
157
|
-
export declare class UnresolvableGuardNameError extends PlayError {
|
|
158
|
-
/** The guard name that could not be resolved. */
|
|
159
|
-
readonly guardName: string;
|
|
160
|
-
constructor(guardName: string, origin: GuardCombinator);
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Thrown when a composed guard evaluates an entry that is neither a predicate
|
|
164
|
-
* function nor a guard name — typically `null`/`undefined` from a typo'd
|
|
165
|
-
* import or an optional lookup.
|
|
166
|
-
*
|
|
167
|
-
* XState v5 failed loudly when evaluating such entries; silently treating them
|
|
168
|
-
* as never-passing would turn `negateGuard(undefined)` into an always-allow.
|
|
169
|
-
* Composition stays lazy (no throw at compose time); evaluation throws.
|
|
170
|
-
*
|
|
171
|
-
* **Error code:** `PLAY_XSTATE_INVALID_GUARD_ENTRY`
|
|
172
|
-
*/
|
|
173
|
-
export declare class InvalidGuardEntryError extends PlayError {
|
|
174
|
-
/** `typeof` of the invalid entry (e.g. `"undefined"`, `"object"` for null). */
|
|
175
|
-
readonly entryType: string;
|
|
176
|
-
constructor(entryType: string, origin: GuardCombinator);
|
|
177
|
-
}
|
|
178
123
|
/**
|
|
179
124
|
* Thrown by `PlayerActor.send()` when the event argument is not a plain object.
|
|
180
125
|
*
|
|
@@ -205,4 +150,35 @@ export declare class InvalidEventError extends PlayError {
|
|
|
205
150
|
readonly detail: unknown;
|
|
206
151
|
constructor(detail: unknown);
|
|
207
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Passed to `PlayerOptions.onError` when the actor failed with a value that is
|
|
155
|
+
* not an `Error` — e.g. a machine action ran `throw { code: 42 }`.
|
|
156
|
+
*
|
|
157
|
+
* An actor error that *is* an `Error` reaches `onError` untouched, keeping the
|
|
158
|
+
* identity the machine gave it. Only this case constructs a new error, so it
|
|
159
|
+
* carries a matchable code instead of a `String(value)` message such as
|
|
160
|
+
* `"[object Object]"`. The thrown value is preserved on `cause`.
|
|
161
|
+
*
|
|
162
|
+
* **Error code:** `PLAY_XSTATE_NON_ERROR_THROWN`
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* import { ActorThrewNonErrorError } from "@xmachines/play-xstate/errors";
|
|
167
|
+
*
|
|
168
|
+
* definePlayer({
|
|
169
|
+
* machine,
|
|
170
|
+
* options: {
|
|
171
|
+
* onError: (actor, err) => {
|
|
172
|
+
* if (err instanceof ActorThrewNonErrorError) {
|
|
173
|
+
* // err.cause is the value the machine actually threw
|
|
174
|
+
* console.error("Machine threw a non-Error:", err.cause);
|
|
175
|
+
* }
|
|
176
|
+
* },
|
|
177
|
+
* },
|
|
178
|
+
* });
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
export declare class ActorThrewNonErrorError extends PlayError {
|
|
182
|
+
constructor(value: unknown);
|
|
183
|
+
}
|
|
208
184
|
//# sourceMappingURL=errors.d.ts.map
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAqB5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,0FAA0F;IAC1F,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAU3C;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,wBAAyB,SAAQ,SAAS;;CAWtD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;IACjD,oFAAoF;IACpF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8EAA8E;IAC9E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAW3C;AAED;;;;;GAKG;AACH,qBAAa,mBAAoB,SAAQ,SAAS;;CASjD;AAED;;;;;GAKG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,oEAAoE;IACpE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,KAAK,EAAE,OAAO,EAAE,MAAM,SAAgB;CAUlD;AAED;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,SAAS;IAClD,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,KAAK,GAAG,IAAI,CAAC;gBAEtB,UAAU,EAAE,KAAK,GAAG,IAAI;CASpC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,iBAAkB,SAAQ,SAAS;IAC/C,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;gBAEb,MAAM,EAAE,OAAO;CAS3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,uBAAwB,SAAQ,SAAS;gBACzC,KAAK,EAAE,OAAO;CAS1B"}
|