@xmachines/play-xstate 1.0.0 → 2.0.0-alpha.1

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.
Files changed (55) hide show
  1. package/README.md +77 -24
  2. package/dist/define-player.d.ts +3 -3
  3. package/dist/define-player.js +3 -3
  4. package/dist/define-player.typecheck.js +10 -10
  5. package/dist/define-player.typecheck.js.map +1 -1
  6. package/dist/errors.d.ts +38 -0
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +45 -0
  9. package/dist/errors.js.map +1 -1
  10. package/dist/guards/compose.d.ts +59 -41
  11. package/dist/guards/compose.d.ts.map +1 -1
  12. package/dist/guards/compose.js +97 -69
  13. package/dist/guards/compose.js.map +1 -1
  14. package/dist/guards/compose.typecheck.d.ts +2 -0
  15. package/dist/guards/compose.typecheck.d.ts.map +1 -0
  16. package/dist/guards/compose.typecheck.js +22 -0
  17. package/dist/guards/compose.typecheck.js.map +1 -0
  18. package/dist/index.d.ts +4 -3
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +4 -2
  21. package/dist/index.js.map +1 -1
  22. package/dist/player-actor.d.ts +3 -3
  23. package/dist/player-actor.d.ts.map +1 -1
  24. package/dist/player-actor.js +15 -9
  25. package/dist/player-actor.js.map +1 -1
  26. package/dist/player-actor.typecheck.js +8 -5
  27. package/dist/player-actor.typecheck.js.map +1 -1
  28. package/dist/routing/create-routed-machine.d.ts +71 -0
  29. package/dist/routing/create-routed-machine.d.ts.map +1 -0
  30. package/dist/routing/create-routed-machine.js +71 -0
  31. package/dist/routing/create-routed-machine.js.map +1 -0
  32. package/dist/routing/derive-initial-route.d.ts +1 -1
  33. package/dist/routing/derive-initial-route.js +1 -1
  34. package/dist/routing/format-play-route-transitions.d.ts +54 -11
  35. package/dist/routing/format-play-route-transitions.d.ts.map +1 -1
  36. package/dist/routing/format-play-route-transitions.js +125 -52
  37. package/dist/routing/format-play-route-transitions.js.map +1 -1
  38. package/dist/routing/index.d.ts +4 -0
  39. package/dist/routing/index.d.ts.map +1 -1
  40. package/dist/routing/index.js +2 -0
  41. package/dist/routing/index.js.map +1 -1
  42. package/dist/routing/play-route-event.typecheck.d.ts +2 -0
  43. package/dist/routing/play-route-event.typecheck.d.ts.map +1 -0
  44. package/dist/routing/play-route-event.typecheck.js +43 -0
  45. package/dist/routing/play-route-event.typecheck.js.map +1 -0
  46. package/dist/routing/schemas.d.ts +99 -0
  47. package/dist/routing/schemas.d.ts.map +1 -0
  48. package/dist/routing/schemas.js +30 -0
  49. package/dist/routing/schemas.js.map +1 -0
  50. package/dist/schemas.d.ts +28 -0
  51. package/dist/schemas.d.ts.map +1 -0
  52. package/dist/schemas.js +29 -0
  53. package/dist/schemas.js.map +1 -0
  54. package/dist/types.d.ts +1 -1
  55. package/package.json +9 -9
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # @xmachines/play-xstate
4
4
 
5
- > XState v5 adapter for the XMachines Play Architecture — bind state machines to the actor base with signal-driven reactivity and router integration.
5
+ > XState v6 adapter for the XMachines Play Architecture — bind state machines to the actor base with signal-driven reactivity and router integration.
6
6
 
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
8
  [![Version](https://img.shields.io/badge/version-1.0.0--beta.51-blue)](https://www.npmjs.com/package/@xmachines/play-xstate)
@@ -17,7 +17,7 @@ Part of the [XMachines Play](../../README.md) monorepo.
17
17
  pnpm add @xmachines/play-xstate xstate
18
18
  ```
19
19
 
20
- `xstate ^5.31.0` is a peer dependency and must be installed alongside this package.
20
+ `xstate ^6.0.0-alpha.19` is a peer dependency and must be installed alongside this package.
21
21
 
22
22
  ---
23
23
 
@@ -25,13 +25,18 @@ pnpm add @xmachines/play-xstate xstate
25
25
 
26
26
  ```typescript
27
27
  import { setup } from "xstate";
28
- import { definePlayer } from "@xmachines/play-xstate";
28
+ import { definePlayer, emptyEventSchema, playMetaSchema } from "@xmachines/play-xstate";
29
29
 
30
- // 1. Define your XState v5 machine
31
- const machine = setup({}).createMachine({
30
+ // 1. Define your XState v6 machine
31
+ const machine = setup({
32
+ schemas: {
33
+ events: { activate: emptyEventSchema },
34
+ meta: playMetaSchema, // types meta.route / meta.view on state nodes
35
+ },
36
+ }).createMachine({
32
37
  initial: "idle",
33
38
  states: {
34
- idle: { meta: { route: "/" } },
39
+ idle: { meta: { route: "/" }, on: { activate: { target: "active" } } },
35
40
  active: { meta: { route: "/active" } },
36
41
  },
37
42
  });
@@ -59,16 +64,16 @@ actor.stop();
59
64
 
60
65
  ### `definePlayer(config)`
61
66
 
62
- 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.
67
+ Creates a `PlayerFactory` from an XState v6 machine. The factory pattern enables multiple independent actor instances from a single configuration — useful for multi-user scenarios, SSR, or testing.
63
68
 
64
69
  ```typescript
65
- import { setup } from "xstate";
70
+ import { setup, types } from "xstate";
66
71
  import { definePlayer } from "@xmachines/play-xstate";
67
72
 
68
73
  const machine = setup({
69
- types: {
70
- context: {} as { userId: string },
71
- input: {} as { userId: string },
74
+ schemas: {
75
+ context: types<{ userId: string }>(),
76
+ input: types<{ userId: string }>(),
72
77
  },
73
78
  }).createMachine({
74
79
  context: ({ input }) => ({ userId: input.userId }),
@@ -117,7 +122,7 @@ console.log(restored.currentRoute.get()); // same route as when saved
117
122
 
118
123
  ### `PlayerActor<TMachine>`
119
124
 
120
- Concrete actor class that wraps an XState v5 actor and exposes TC39 Signal-based reactive signals. Implements both `Routable` and `Viewable` interfaces from `@xmachines/play-actor`.
125
+ Concrete actor class that wraps an XState v6 actor and exposes TC39 Signal-based reactive signals. Implements both `Routable` and `Viewable` interfaces from `@xmachines/play-actor`.
121
126
 
122
127
  #### Signals
123
128
 
@@ -158,7 +163,7 @@ actor.start();
158
163
 
159
164
  ### Guard utilities
160
165
 
161
- Composable guard helpers that wrap XState's built-in `and()`, `or()`, and `not()` for use in machine `setup({ guards })` definitions.
166
+ Composable guard helpers that combine predicates with AND, OR, and NOT logic. Each helper returns a plain predicate — call it inside a transition function with the transition arguments and return early to block the transition. String guard names are resolved against the named guards declared in `setup({ guards })`.
162
167
 
163
168
  ```typescript
164
169
  import { setup } from "xstate";
@@ -171,20 +176,24 @@ import {
171
176
  contextFieldMatches, // guard: context field equals a value
172
177
  } from "@xmachines/play-xstate";
173
178
 
179
+ const canAccessAdmin = composeGuards(["isLoggedIn", "hasAdminRole"]);
180
+ const isAuthenticated = negateGuard("isGuest");
181
+
174
182
  const machine = setup({
175
183
  guards: {
176
184
  isLoggedIn: ({ context }) => !!context.userId,
177
185
  hasAdminRole: ({ context }) => context.role === "admin",
186
+ isGuest: ({ context }) => !context.userId,
178
187
  },
179
188
  }).createMachine({
180
189
  on: {
181
- accessAdmin: {
182
- guard: composeGuards(["isLoggedIn", "hasAdminRole"]),
183
- target: "adminPanel",
190
+ accessAdmin: (args) => {
191
+ if (!canAccessAdmin(args)) return;
192
+ return { target: "adminPanel" };
184
193
  },
185
- accessDashboard: {
186
- guard: negateGuard("isGuest"),
187
- target: "dashboard",
194
+ accessDashboard: (args) => {
195
+ if (!isAuthenticated(args)) return;
196
+ return { target: "dashboard" };
188
197
  },
189
198
  },
190
199
  // ...
@@ -197,13 +206,42 @@ const machine = setup({
197
206
 
198
207
  Helper functions for declarative route configuration in XState machines.
199
208
 
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
+
200
234
  #### `formatPlayRouteTransitions(machineConfig)`
201
235
 
202
- Crawls machine states with `meta.route` and auto-generates `play.route` event handlers at the root leveleliminating boilerplate routing transitions.
236
+ The underlying transform. Crawls machine states with `meta.route` and wires them to XState v6's native routing: each routed state gets a native `route: {}` config (targetable via the built-in `xstate.route` event and visible to graph tooling), and one root `play.route` forwarder navigates those targets in a single atomic transition patching `params`/`query` into context — while re-raising `xstate.route` only for states that declare their own `route` config. Unknown targets fall through to user-defined `play.route` fallbacks (e.g. a 404 route); one `play.route` send is one atomic transition, so exit actions see the old `params` and entry actions the new ones.
203
237
 
204
238
  ```typescript
205
239
  import { setup } from "xstate";
206
- import { formatPlayRouteTransitions } from "@xmachines/play-xstate";
240
+ import {
241
+ formatPlayRouteTransitions,
242
+ playMetaSchema,
243
+ playRouteEventSchema,
244
+ } from "@xmachines/play-xstate";
207
245
 
208
246
  const config = formatPlayRouteTransitions({
209
247
  id: "app",
@@ -219,17 +257,30 @@ const config = formatPlayRouteTransitions({
219
257
  },
220
258
  });
221
259
 
222
- // config now includes auto-generated play.route handlers:
223
- // on: { "play.route": [ { target: ".home", guard: e => e.to === "#home" }, ... ] }
224
- const machine = setup({}).createMachine(config);
260
+ // config now carries native route configs plus the play.route forwarder:
261
+ // states: { home: { ..., route: {} }, profile: { ..., route: {} } }
262
+ // on: { "play.route": [forwarder, ...userFallbacks] }
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);
225
271
  ```
226
272
 
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
+
227
275
  > **Note:** Every state with `meta.route` must also have an explicit `id` field; omitting it throws `MissingStateIdError` at machine-definition time.
228
276
 
229
277
  #### Other routing exports
230
278
 
231
279
  | Export | Description |
232
280
  | ---------------------------------- | ------------------------------------------------------------------------- |
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 |
233
284
  | `deriveRoute(meta)` | Extract the route template string from a state's metadata object |
234
285
  | `isAbsoluteRoute(route)` | Returns `true` if the route string is an absolute URL path |
235
286
  | `buildRouteUrl(template, context)` | Substitute `:param` placeholders in a route template using context values |
@@ -270,6 +321,8 @@ import {
270
321
  InvalidEventError, // actor.send() called with null/undefined/non-object
271
322
  InvalidRouteMetadataError, // meta.route is neither a string nor { path: string }
272
323
  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)
273
326
  } from "@xmachines/play-xstate/errors";
274
327
  ```
275
328
 
@@ -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 v5 machine,
6
+ * Factory pattern that accepts an XState v6 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 v5 state machine type
11
+ * @typeParam TMachine - XState v6 state machine type
12
12
  *
13
13
  * @param config - Player configuration object
14
- * @param config.machine - XState v5 state machine
14
+ * @param config.machine - XState v6 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
@@ -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 v5 machine,
5
+ * Factory pattern that accepts an XState v6 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 v5 state machine type
10
+ * @typeParam TMachine - XState v6 state machine type
11
11
  *
12
12
  * @param config - Player configuration object
13
- * @param config.machine - XState v5 state machine
13
+ * @param config.machine - XState v6 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
@@ -1,10 +1,13 @@
1
- import { setup } from "xstate";
1
+ import { setup, types } from "xstate";
2
+ import { emptyEventSchema } from "./schemas.js";
2
3
  import { definePlayer } from "./define-player.js";
3
4
  const machine = setup({
4
- types: {
5
- context: {},
6
- input: {},
7
- events: {},
5
+ schemas: {
6
+ context: types(),
7
+ input: types(),
8
+ events: {
9
+ inc: emptyEventSchema,
10
+ },
8
11
  },
9
12
  }).createMachine({
10
13
  context: ({ input }) => ({ count: input.count }),
@@ -12,11 +15,8 @@ const machine = setup({
12
15
  states: {
13
16
  active: {
14
17
  on: {
15
- inc: {
16
- actions: ({ context }) => {
17
- context.count += 1;
18
- },
19
- },
18
+ // XState v6: transitions are functions returning a context patch.
19
+ inc: ({ context }) => ({ context: { count: context.count + 1 } }),
20
20
  },
21
21
  },
22
22
  },
@@ -1 +1 @@
1
- {"version":3,"file":"define-player.typecheck.js","sourceRoot":"","sources":["../src/define-player.typecheck.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKlD,MAAM,OAAO,GAAG,KAAK,CAAC;IACrB,KAAK,EAAE;QACN,OAAO,EAAE,EAAuB;QAChC,KAAK,EAAE,EAAuB;QAC9B,MAAM,EAAE,EAAqB;KAC7B;CACD,CAAC,CAAC,aAAa,CAAC;IAChB,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IAChD,OAAO,EAAE,QAAQ;IACjB,MAAM,EAAE;QACP,MAAM,EAAE;YACP,EAAE,EAAE;gBACH,GAAG,EAAE;oBACJ,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;wBACxB,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC;oBACpB,CAAC;iBACD;aACD;SACD;KACD;CACD,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,YAAY,CAAC;IACjC,OAAO;IACP,OAAO,EAAE;QACR,YAAY,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE;YAK7C,MAAM,WAAW,GAA4B,KAAK,CAAC;YACnD,MAAM,UAAU,GAA2B,KAAK,CAAC;YACjD,MAAM,UAAU,GAA2B,KAAK,CAAC;YAEjD,KAAK,WAAW,CAAC;YACjB,KAAK,UAAU,CAAC;YAChB,KAAK,UAAU,CAAC;QACjB,CAAC;KACD;CACD,CAAC,CAAC;AAEH,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AACzC,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;AACrC,MAAM,aAAa,GAAG,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;AAI/D,MAAM,YAAY,GAA6B,KAAK,CAAC;AACrD,MAAM,oBAAoB,GAAqC,KAAK,CAAC;AACrE,KAAK,YAAY,CAAC;AAClB,KAAK,oBAAoB,CAAC;AAE1B,gEAAgE;AAChE,YAAY,CAAC,SAAS,CAAC,CAAC;AAExB,oEAAoE;AACpE,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC"}
1
+ {"version":3,"file":"define-player.typecheck.js","sourceRoot":"","sources":["../src/define-player.typecheck.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKlD,MAAM,OAAO,GAAG,KAAK,CAAC;IACrB,OAAO,EAAE;QACR,OAAO,EAAE,KAAK,EAAqB;QACnC,KAAK,EAAE,KAAK,EAAqB;QACjC,MAAM,EAAE;YACP,GAAG,EAAE,gBAAgB;SACrB;KACD;CACD,CAAC,CAAC,aAAa,CAAC;IAChB,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;IAChD,OAAO,EAAE,QAAQ;IACjB,MAAM,EAAE;QACP,MAAM,EAAE;YACP,EAAE,EAAE;gBACH,kEAAkE;gBAClE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC;aACjE;SACD;KACD;CACD,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,YAAY,CAAC;IACjC,OAAO;IACP,OAAO,EAAE;QACR,YAAY,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE;YAK7C,MAAM,WAAW,GAA4B,KAAK,CAAC;YACnD,MAAM,UAAU,GAA2B,KAAK,CAAC;YACjD,MAAM,UAAU,GAA2B,KAAK,CAAC;YAEjD,KAAK,WAAW,CAAC;YACjB,KAAK,UAAU,CAAC;YAChB,KAAK,UAAU,CAAC;QACjB,CAAC;KACD;CACD,CAAC,CAAC;AAEH,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AACzC,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;AACrC,MAAM,aAAa,GAAG,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;AAI/D,MAAM,YAAY,GAA6B,KAAK,CAAC;AACrD,MAAM,oBAAoB,GAAqC,KAAK,CAAC;AACrE,KAAK,YAAY,CAAC;AAClB,KAAK,oBAAoB,CAAC;AAE1B,gEAAgE;AAChE,YAAY,CAAC,SAAS,CAAC,CAAC;AAExB,oEAAoE;AACpE,YAAY,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC"}
package/dist/errors.d.ts CHANGED
@@ -137,6 +137,44 @@ export declare class EmptyGuardArrayError extends PlayError {
137
137
  readonly combinator: "and" | "or";
138
138
  constructor(combinator: "and" | "or");
139
139
  }
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
+ }
140
178
  /**
141
179
  * Thrown by `PlayerActor.send()` when the event argument is not a plain object.
142
180
  *
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;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"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;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;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,iBAAiB,GAAG,aAAa,CAAC;AAElF;;;;;;;;;;;GAWG;AACH,qBAAa,0BAA2B,SAAQ,SAAS;IACxD,iDAAiD;IACjD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe;CAWtD;AAED;;;;;;;;;;GAUG;AACH,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,+EAA+E;IAC/E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe;CAWtD;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,iBAAkB,SAAQ,SAAS;IAC/C,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;gBAEb,MAAM,EAAE,OAAO;CAS3B"}
package/dist/errors.js CHANGED
@@ -165,6 +165,51 @@ export class EmptyGuardArrayError extends PlayError {
165
165
  this.combinator = combinator;
166
166
  }
167
167
  }
168
+ /**
169
+ * Thrown when a composed guard cannot resolve a string guard name at call time.
170
+ *
171
+ * String names in `composeGuards`/`composeGuardsOr`/`negateGuard` resolve
172
+ * against `args.guards` — the named guards from `setup({ guards })` that
173
+ * XState v6 provides to transition functions, `always`, entry/exit actions
174
+ * (since 6.0.0-alpha.20), and function-form route resolvers. Resolution fails
175
+ * when the name was never declared or when the composed guard is called
176
+ * without transition arguments.
177
+ *
178
+ * **Error code:** `PLAY_XSTATE_UNRESOLVABLE_GUARD_NAME`
179
+ */
180
+ export class UnresolvableGuardNameError extends PlayError {
181
+ /** The guard name that could not be resolved. */
182
+ guardName;
183
+ constructor(guardName, origin) {
184
+ super(origin, "PLAY_XSTATE_UNRESOLVABLE_GUARD_NAME", `Guard "${guardName}" is not a function. Either the name was never declared ` +
185
+ `in setup({ guards }) or the composed guard was called without ` +
186
+ `transition arguments.`);
187
+ this.name = "UnresolvableGuardNameError";
188
+ this.guardName = guardName;
189
+ }
190
+ }
191
+ /**
192
+ * Thrown when a composed guard evaluates an entry that is neither a predicate
193
+ * function nor a guard name — typically `null`/`undefined` from a typo'd
194
+ * import or an optional lookup.
195
+ *
196
+ * XState v5 failed loudly when evaluating such entries; silently treating them
197
+ * as never-passing would turn `negateGuard(undefined)` into an always-allow.
198
+ * Composition stays lazy (no throw at compose time); evaluation throws.
199
+ *
200
+ * **Error code:** `PLAY_XSTATE_INVALID_GUARD_ENTRY`
201
+ */
202
+ export class InvalidGuardEntryError extends PlayError {
203
+ /** `typeof` of the invalid entry (e.g. `"undefined"`, `"object"` for null). */
204
+ entryType;
205
+ constructor(entryType, origin) {
206
+ super(origin, "PLAY_XSTATE_INVALID_GUARD_ENTRY", `Guard entry of type "${entryType}" is neither a predicate function nor a ` +
207
+ `guard name. Check for typo'd imports or optional lookups that resolved ` +
208
+ `to null/undefined.`);
209
+ this.name = "InvalidGuardEntryError";
210
+ this.entryType = entryType;
211
+ }
212
+ }
168
213
  /**
169
214
  * Thrown by `PlayerActor.send()` when the event argument is not a plain object.
170
215
  *
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
@@ -1,33 +1,50 @@
1
- import type { GuardPredicate } from "xstate";
2
1
  import type { Guard, GuardArray } from "./types.js";
3
- import type { MachineContext, EventObject, ParameterizedObject } from "xstate";
4
2
  /**
5
- * Narrowest public return type for guard composition helpers.
3
+ * Composed guard: a plain predicate over transition arguments.
6
4
  *
7
- * `GuardPredicate<MachineContext, EventObject, unknown, ParameterizedObject>` is the
8
- * widest-compatible concrete XState guard type that does not use `any`.
5
+ * XState v6 removed guard objects and the `and()`/`or()`/`not()` creators —
6
+ * guards are now plain functions evaluated inside transition functions. A
7
+ * composed guard is therefore just another predicate with the same shape as
8
+ * {@link Guard}, callable anywhere transition args are available.
9
+ *
10
+ * String guard names are resolved against `args.guards` (the named guards
11
+ * declared in `setup({ guards })`, which XState v6 passes to every transition
12
+ * function). Resolving a name outside a transition function — or a name that
13
+ * was never declared — throws `UnresolvableGuardNameError` immediately.
14
+ *
15
+ * String names work in `on` transitions, `always`, entry/exit actions (since
16
+ * xstate 6.0.0-alpha.20 populates `guards` there), and function-form route
17
+ * resolvers.
9
18
  *
10
19
  * @public
11
20
  */
12
- export type ComposedGuard = GuardPredicate<MachineContext, EventObject, unknown, ParameterizedObject>;
21
+ export type ComposedGuard = (args: unknown) => boolean;
13
22
  /**
14
- * Compose guards with AND logic using XState's and() helper
23
+ * Compose guards with AND logic.
15
24
  *
16
25
  * Combines multiple guard predicates using AND semantics—all guards must pass for
17
- * the composition to succeed. Uses XState's built-in `and()` helper to ensure proper
18
- * type inference and machine serialization.
26
+ * the composition to succeed. Evaluation is short-circuiting, left to right.
19
27
  *
20
28
  * **Architectural Context:** Supports **Actor Authority (INV-01)** by enabling
21
29
  * declarative guard composition in state machine transitions. Guards enforce business
22
30
  * logic rules that determine whether navigation or actions are valid.
23
31
  *
24
- * @typeParam TContext - State machine context type
32
+ * **XState v6:** the composed value is a plain predicate. Call it inside a
33
+ * transition function and return early to block the transition:
34
+ *
35
+ * @typeParam TContext - State machine context type (defaults to `any` so the
36
+ * documented inline-predicate examples compile without annotations)
37
+ * @typeParam TEvent - Event type
38
+ *
39
+ * @typeParam TContext - State machine context type (defaults to `any` so the
40
+ * documented inline-predicate examples compile without annotations)
25
41
  * @typeParam TEvent - Event type
26
42
  *
27
- * @param guards - Array of guard predicates or guard names (string references)
28
- * @returns XState and() guard composition
43
+ * @param guards - Array of guard predicates or guard names (string references
44
+ * resolved against `args.guards` from `setup({ guards })`)
45
+ * @returns Predicate returning `true` only when every guard passes
29
46
  *
30
- * @throws {Error} If guards array is empty
47
+ * @throws {EmptyGuardArrayError} If guards array is empty
31
48
  *
32
49
  * @example
33
50
  * AND composition with named guards
@@ -35,6 +52,8 @@ export type ComposedGuard = GuardPredicate<MachineContext, EventObject, unknown,
35
52
  * import { setup } from "xstate";
36
53
  * import { composeGuards } from "@xmachines/play-xstate";
37
54
  *
55
+ * const canAccessAdmin = composeGuards(['isLoggedIn', 'hasPermission']);
56
+ *
38
57
  * const machine = setup({
39
58
  * guards: {
40
59
  * isLoggedIn: ({ context }) => !!context.userId,
@@ -42,10 +61,9 @@ export type ComposedGuard = GuardPredicate<MachineContext, EventObject, unknown,
42
61
  * }
43
62
  * }).createMachine({
44
63
  * on: {
45
- * accessAdmin: {
46
- * // Both guards must pass
47
- * guard: composeGuards(['isLoggedIn', 'hasPermission']),
48
- * target: 'adminPanel'
64
+ * accessAdmin: (args) => {
65
+ * if (!canAccessAdmin(args)) return;
66
+ * return { target: 'adminPanel' };
49
67
  * }
50
68
  * }
51
69
  * });
@@ -56,10 +74,10 @@ export type ComposedGuard = GuardPredicate<MachineContext, EventObject, unknown,
56
74
  * ```typescript
57
75
  * import { composeGuards } from "@xmachines/play-xstate";
58
76
  *
59
- * guard: composeGuards([
77
+ * const isEligible = composeGuards([
60
78
  * ({ context }) => context.age >= 18,
61
79
  * ({ context }) => context.verified
62
- * ])
80
+ * ]);
63
81
  * ```
64
82
  *
65
83
  * @see {@link composeGuardsOr} for OR composition
@@ -67,19 +85,16 @@ export type ComposedGuard = GuardPredicate<MachineContext, EventObject, unknown,
67
85
  */
68
86
  export declare const composeGuards: <TContext = any, TEvent = any>(guards: GuardArray<TContext, TEvent>) => ComposedGuard;
69
87
  /**
70
- * Compose guards with OR logic using XState's or() helper
88
+ * Compose guards with OR logic.
71
89
  *
72
90
  * Combines multiple guard predicates using OR semantics—at least one guard must pass
73
- * for the composition to succeed. Uses XState's built-in `or()` helper for proper
74
- * type inference.
75
- *
76
- * @typeParam TContext - State machine context type
77
- * @typeParam TEvent - Event type
91
+ * for the composition to succeed. Evaluation is short-circuiting, left to right.
78
92
  *
79
- * @param guards - Array of guard predicates or guard names
80
- * @returns XState or() guard composition
93
+ * @param guards - Array of guard predicates or guard names (string references
94
+ * resolved against `args.guards` from `setup({ guards })`)
95
+ * @returns Predicate returning `true` when any guard passes
81
96
  *
82
- * @throws {Error} If guards array is empty
97
+ * @throws {EmptyGuardArrayError} If guards array is empty
83
98
  *
84
99
  * @example
85
100
  * OR composition with named guards
@@ -87,6 +102,8 @@ export declare const composeGuards: <TContext = any, TEvent = any>(guards: Guard
87
102
  * import { setup } from "xstate";
88
103
  * import { composeGuardsOr } from "@xmachines/play-xstate";
89
104
  *
105
+ * const canDelete = composeGuardsOr(['isOwner', 'isAdmin']);
106
+ *
90
107
  * const machine = setup({
91
108
  * guards: {
92
109
  * isOwner: ({ context }) => context.role === 'owner',
@@ -94,10 +111,9 @@ export declare const composeGuards: <TContext = any, TEvent = any>(guards: Guard
94
111
  * }
95
112
  * }).createMachine({
96
113
  * on: {
97
- * deleteResource: {
98
- * // Either guard can pass
99
- * guard: composeGuardsOr(['isOwner', 'isAdmin']),
100
- * actions: 'delete'
114
+ * deleteResource: (args, enq) => {
115
+ * if (!canDelete(args)) return;
116
+ * enq(() => deleteIt());
101
117
  * }
102
118
  * }
103
119
  * });
@@ -108,16 +124,17 @@ export declare const composeGuards: <TContext = any, TEvent = any>(guards: Guard
108
124
  */
109
125
  export declare const composeGuardsOr: <TContext = any, TEvent = any>(guards: GuardArray<TContext, TEvent>) => ComposedGuard;
110
126
  /**
111
- * Negate a guard using XState's not() helper
127
+ * Negate a guard.
112
128
  *
113
129
  * Inverts a guard's result—if the guard passes, NOT fails; if guard fails, NOT passes.
114
- * Uses XState's built-in `not()` helper for proper serialization.
115
130
  *
116
- * @typeParam TContext - State machine context type
131
+ * @typeParam TContext - State machine context type (defaults to `any` so
132
+ * inline predicates compile without annotations)
117
133
  * @typeParam TEvent - Event type
118
134
  *
119
- * @param guard - Guard predicate or guard name to negate
120
- * @returns XState not() guard negation
135
+ * @param guard - Guard predicate or guard name (resolved against `args.guards`
136
+ * from `setup({ guards })`) to negate
137
+ * @returns Predicate returning the inverted guard result
121
138
  *
122
139
  * @example
123
140
  * NOT composition with named guard
@@ -125,16 +142,17 @@ export declare const composeGuardsOr: <TContext = any, TEvent = any>(guards: Gua
125
142
  * import { setup } from "xstate";
126
143
  * import { negateGuard } from "@xmachines/play-xstate";
127
144
  *
145
+ * const isAuthenticated = negateGuard('isGuest');
146
+ *
128
147
  * const machine = setup({
129
148
  * guards: {
130
149
  * isGuest: ({ context }) => !context.userId
131
150
  * }
132
151
  * }).createMachine({
133
152
  * on: {
134
- * accessDashboard: {
135
- * // Allow if NOT a guest (i.e., authenticated)
136
- * guard: negateGuard('isGuest'),
137
- * target: 'dashboard'
153
+ * accessDashboard: (args) => {
154
+ * if (!isAuthenticated(args)) return;
155
+ * return { target: 'dashboard' };
138
156
  * }
139
157
  * }
140
158
  * });
@@ -1 +1 @@
1
- {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/guards/compose.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAG/E;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,cAAc,CACzC,cAAc,EACd,WAAW,EACX,OAAO,EACP,mBAAmB,CACnB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH,eAAO,MAAM,aAAa,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EACzD,QAAQ,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,KAClC,aAqBF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,eAAO,MAAM,eAAe,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EAC3D,QAAQ,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,KAClC,aAmBF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,eAAO,MAAM,WAAW,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EACvD,OAAO,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,KACrC,aAOF,CAAC"}
1
+ {"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/guards/compose.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAQpD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;AAqCvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AAEH,eAAO,MAAM,aAAa,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EACzD,QAAQ,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,KAClC,aAgBF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,eAAO,MAAM,eAAe,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EAC3D,QAAQ,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,KAClC,aAgBF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,eAAO,MAAM,WAAW,GAAI,QAAQ,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EACvD,OAAO,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,MAAM,KACrC,aAGF,CAAC"}