@xmachines/play-xstate 6.0.0 → 7.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.
Files changed (45) hide show
  1. package/README.md +87 -28
  2. package/dist/capabilities.d.ts +2 -2
  3. package/dist/capabilities.js +6 -2
  4. package/dist/capabilities.js.map +1 -1
  5. package/dist/define-player.js +8 -8
  6. package/dist/define-player.js.map +1 -1
  7. package/dist/errors.js +262 -259
  8. package/dist/errors.js.map +1 -1
  9. package/dist/index.js +4 -25
  10. package/dist/player-actor.js +318 -448
  11. package/dist/player-actor.js.map +1 -1
  12. package/dist/routing/build-url.js +74 -108
  13. package/dist/routing/build-url.js.map +1 -1
  14. package/dist/routing/derive-current-route.d.ts.map +1 -1
  15. package/dist/routing/derive-current-route.js +46 -67
  16. package/dist/routing/derive-current-route.js.map +1 -1
  17. package/dist/routing/derive-initial-route.js +53 -64
  18. package/dist/routing/derive-initial-route.js.map +1 -1
  19. package/dist/routing/derive-route.js +225 -242
  20. package/dist/routing/derive-route.js.map +1 -1
  21. package/dist/routing/format-play-route-transitions.d.ts.map +1 -1
  22. package/dist/routing/format-play-route-transitions.js +192 -257
  23. package/dist/routing/format-play-route-transitions.js.map +1 -1
  24. package/dist/state-meta.d.ts +84 -28
  25. package/dist/state-meta.d.ts.map +1 -1
  26. package/dist/state-meta.js +170 -72
  27. package/dist/state-meta.js.map +1 -1
  28. package/dist/view/derive-current-view.d.ts +18 -10
  29. package/dist/view/derive-current-view.d.ts.map +1 -1
  30. package/dist/view/derive-current-view.js +249 -128
  31. package/dist/view/derive-current-view.js.map +1 -1
  32. package/dist/with-routing.js +94 -136
  33. package/dist/with-routing.js.map +1 -1
  34. package/dist/with-view.d.ts +1 -3
  35. package/dist/with-view.d.ts.map +1 -1
  36. package/dist/with-view.js +82 -152
  37. package/dist/with-view.js.map +1 -1
  38. package/package.json +19 -19
  39. package/dist/index.js.map +0 -1
  40. package/dist/routing/index.js +0 -14
  41. package/dist/routing/index.js.map +0 -1
  42. package/dist/routing/types.js +0 -2
  43. package/dist/routing/types.js.map +0 -1
  44. package/dist/types.js +0 -2
  45. package/dist/types.js.map +0 -1
package/README.md CHANGED
@@ -2,13 +2,14 @@
2
2
 
3
3
  > XState v5 adapter for the XMachines Play Architecture. It binds a state machine to the actor base, with atom-driven reactivity and a router integration.
4
4
 
5
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Version](https://img.shields.io/badge/version-6.0.0-blue)](https://www.npmjs.com/package/@xmachines/play-xstate)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Version](https://img.shields.io/badge/version-7.0.0-blue)](https://www.npmjs.com/package/@xmachines/play-xstate)
6
6
 
7
7
  ---
8
8
 
9
- > **Browser floor: Chrome 110, Firefox 115, Safari 16.4.** This package calls the ES2023
10
- > change-by-copy array methods, so a browser below that floor throws
11
- > `TypeError: ... is not a function`. The root README carries the table.
9
+ > **Browser floor:** the table of the root README covers this package. Its own code calls
10
+ > no ES2023 change-by-copy array method, and its routing capability imports only types from
11
+ > [`@xmachines/play-router`](../play-router/README.md). A router bridge of play-router sets
12
+ > the floor of the table.
12
13
 
13
14
  ## Installation
14
15
 
@@ -115,21 +116,36 @@ machine cannot be `undefined`, the first argument of the factory is necessary. A
115
116
  input is then a compile error, not an actor that stops in an error status.
116
117
 
117
118
  ```typescript
118
- type PlayerFactory<TMachine> =
119
+ import type { AnyStateMachine, InputFrom } from "xstate";
120
+ import type { PlayerActor, PlayerFactoryResumeOptions } from "@xmachines/play-xstate";
121
+
122
+ type PlayerFactory<TMachine extends AnyStateMachine, TCapabilities extends object = object> =
119
123
  undefined extends InputFrom<TMachine>
120
124
  ? (
121
125
  input?: InputFrom<TMachine>,
122
126
  options?: PlayerFactoryResumeOptions<TMachine>,
123
- ) => PlayerActor<TMachine>
127
+ ) => PlayerActor<TMachine> & TCapabilities
124
128
  : (
125
129
  input: InputFrom<TMachine>,
126
130
  options?: PlayerFactoryResumeOptions<TMachine>,
127
- ) => PlayerActor<TMachine>;
131
+ ) => PlayerActor<TMachine> & TCapabilities;
128
132
  ```
129
133
 
134
+ `TCapabilities` is what `compose` adds, for example `Routable` of [`@xmachines/play-router`](../play-router/README.md).
135
+
130
136
  #### Restoring from a snapshot
131
137
 
132
138
  ```typescript
139
+ import { definePlayer, compose, PlayerActor } from "@xmachines/play-xstate";
140
+ import { withRouting } from "@xmachines/play-xstate/routing";
141
+ import type { AnyStateMachine } from "xstate";
142
+
143
+ declare const machine: AnyStateMachine; // your machine, with an input and routed states
144
+
145
+ const createPlayer = definePlayer({ machine, actor: compose(PlayerActor, withRouting) });
146
+ const actor = createPlayer({ userId: "alice" });
147
+ actor.start();
148
+
133
149
  const snapshot = actor.getPersistedSnapshot();
134
150
  actor.stop();
135
151
 
@@ -182,6 +198,9 @@ carries the route utilities — `deriveRoute`, `isAbsoluteRoute`, `buildRouteUrl
182
198
  import { definePlayer, PlayerActor, compose } from "@xmachines/play-xstate";
183
199
  import { withRouting } from "@xmachines/play-xstate/routing";
184
200
  import { withView } from "@xmachines/play-xstate/view";
201
+ import type { AnyStateMachine } from "xstate";
202
+
203
+ declare const machine: AnyStateMachine; // your machine
185
204
 
186
205
  // Both capabilities
187
206
  const createPlayer = definePlayer({
@@ -196,11 +215,20 @@ const createRouted = definePlayer({ machine, actor: compose(PlayerActor, withRou
196
215
  const createBare = definePlayer({ machine });
197
216
  ```
198
217
 
199
- **The composition ORDER decides nothing.** `currentRoute` and `currentView` are computed atoms over `state`, and neither reads the other, so one write for each transition reaches both and the engine evaluates them in topological order. A router bridge therefore sees a guard redirect and a renderer sees the view of the same snapshot, whatever order `compose` applied. A release before this one wrote `currentView` from an `onSnapshot` override, and the order was load-bearing there.
218
+ **The composition ORDER decides nothing.** `currentRoute` and `currentView` are computed atoms over `state`, and neither reads the other, so one write for each transition reaches both and the engine evaluates them in topological order. A router bridge therefore sees a guard redirect and a renderer sees the view of the same snapshot, whatever order `compose` applied.
200
219
 
201
220
  **A lifecycle hook receives the bare actor.** `PlayerOptions` is typed before the class is composed, so it cannot name the capabilities, and a narrower hook parameter is refused under `strictFunctionTypes`. A hook that reads `currentRoute` or `currentView` reads them through a binding of the composed type:
202
221
 
203
222
  ```typescript
223
+ import { definePlayer, PlayerActor, compose } from "@xmachines/play-xstate";
224
+ import { withRouting } from "@xmachines/play-xstate/routing";
225
+ import { withView } from "@xmachines/play-xstate/view";
226
+ import type { Routable } from "@xmachines/play-router";
227
+ import type { Viewable } from "@xmachines/play-view";
228
+ import type { AnyStateMachine } from "xstate";
229
+
230
+ declare const machine: AnyStateMachine; // your machine
231
+
204
232
  let composed: PlayerActor<typeof machine> & Routable & Viewable;
205
233
 
206
234
  const actor = definePlayer({
@@ -213,9 +241,9 @@ composed = actor;
213
241
 
214
242
  | Atom | Type | Capability | Description |
215
243
  | -------------- | -------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
216
- | `currentRoute` | `ReadonlyAtom<string \| null>` | routing | The URL that comes from the `meta.route` template of the active state and from the context |
244
+ | `currentRoute` | `ReadonlyAtom<string \| null>` | routing | The URL from the `meta.route` template of the active state and from the context. A parallel machine uses its first routed region |
217
245
  | `initialRoute` | `readonly string \| null` | routing | The route of the initial state of the machine. The construction fixes it, and a router bridge uses it to detect a deep link or a restore |
218
- | `currentView` | `ReadonlyAtom<PlaySpec \| null>` | view | The view spec from the `meta.view` metadata of the active state, with the context params added |
246
+ | `currentView` | `ReadonlyAtom<PlaySpec \| null>` | view | The `meta.view` of the deepest active state, or the composed view of a state that declares `outlets`, with the context under `/context` |
219
247
 
220
248
  `state` is the ONE atom that the actor writes. `currentRoute` and `currentView` are
221
249
  COMPUTED over it, so one write for each transition reaches both in one propagation and no
@@ -223,6 +251,13 @@ observer reads the new state beside an old derivation. Each derivation reports a
223
251
  through the `onError` option and keeps its last good value; it throws never, because it
224
252
  runs inside the write.
225
253
 
254
+ **A parent view with `outlets` shares the screen with its substates.** The derivation then
255
+ walks the active states from the root, puts the view of each active child into its outlet,
256
+ and keeps the `viewKey` of the outermost composing view, so a change of the page keeps the
257
+ store of the layout. A machine that declares no `outlets` keeps the rule that the deepest
258
+ view wins. The [State Machines guide](../docs/guides/state-machines.md#a-layout-and-its-pages-outlets)
259
+ shows a complete machine.
260
+
226
261
  **`currentRoute` notifies on every transition, and `currentView` notifies on a change of
227
262
  the view alone.** The two atoms answer two different questions. A router bridge needs the
228
263
  answer of the actor to each event that it proposed, and a guard that refuses an inbound
@@ -247,6 +282,11 @@ the path yourself, when you run work that belongs to a change of the route alone
247
282
 
248
283
  ```typescript
249
284
  import { watchAtom } from "@xmachines/play-atom";
285
+ import type { PlayerActor } from "@xmachines/play-xstate";
286
+ import type { Routable } from "@xmachines/play-router";
287
+ import type { AnyStateMachine } from "xstate";
288
+
289
+ declare const actor: PlayerActor<AnyStateMachine> & Routable; // composed with withRouting
250
290
 
251
291
  const stop = watchAtom(actor.currentRoute, (route) => {
252
292
  console.log("Route changed:", route);
@@ -268,22 +308,32 @@ This package gives no guard utility. Compose a guard with the `and()`, `or()` an
268
308
  import { and, not, setup } from "xstate";
269
309
 
270
310
  const machine = setup({
311
+ types: {
312
+ context: {} as { userId: string; role: string },
313
+ events: {} as { type: "accessAdmin" } | { type: "accessLogin" },
314
+ },
271
315
  guards: {
272
316
  isLoggedIn: ({ context }) => context.userId !== "",
273
317
  hasAdminRole: ({ context }) => context.role === "admin",
274
318
  },
275
319
  }).createMachine({
320
+ context: { userId: "", role: "guest" },
321
+ initial: "home",
276
322
  on: {
277
323
  accessAdmin: {
278
324
  guard: and(["isLoggedIn", "hasAdminRole"]),
279
- target: "adminPanel",
325
+ target: ".adminPanel",
280
326
  },
281
327
  accessLogin: {
282
328
  guard: not("isLoggedIn"),
283
- target: "login",
329
+ target: ".login",
284
330
  },
285
331
  },
286
- // ...
332
+ states: {
333
+ home: {},
334
+ adminPanel: {},
335
+ login: {},
336
+ },
287
337
  });
288
338
  ```
289
339
 
@@ -307,6 +357,7 @@ import { formatPlayRouteTransitions } from "@xmachines/play-xstate/routing";
307
357
 
308
358
  const config = formatPlayRouteTransitions({
309
359
  id: "app",
360
+ initial: "home",
310
361
  states: {
311
362
  home: {
312
363
  id: "home",
@@ -341,6 +392,10 @@ with `asDisposable` of [`@xmachines/core/utils`](../core/README.md):
341
392
 
342
393
  ```typescript
343
394
  import { asDisposable } from "@xmachines/core/utils";
395
+ import { definePlayer } from "@xmachines/play-xstate";
396
+ import type { AnyStateMachine } from "xstate";
397
+
398
+ declare const machine: AnyStateMachine; // your machine
344
399
 
345
400
  {
346
401
  const actor = definePlayer({ machine })();
@@ -361,6 +416,10 @@ includes [`@statelyai/inspect`](https://stately.ai/docs/inspector):
361
416
 
362
417
  ```typescript
363
418
  import { createBrowserInspector } from "@statelyai/inspect";
419
+ import { definePlayer } from "@xmachines/play-xstate";
420
+ import type { AnyStateMachine } from "xstate";
421
+
422
+ declare const machine: AnyStateMachine; // your machine
364
423
 
365
424
  const { inspect } = createBrowserInspector();
366
425
  const createPlayer = definePlayer({ machine, options: { inspect } });
@@ -414,7 +473,7 @@ import type {
414
473
  `RouteObject`, `RouteMetadata`, `RouteData`, and `RouteDataResolver` have one
415
474
  definition, and it lives in [`@xmachines/play-router`](../play-router/README.md). `@xmachines/play-xstate/routing`
416
475
  re-exports them, so either import path gives you the same type. The MAIN entry point of
417
- this package re-exports them no longer: it would name an optional peer in the types of
476
+ this package does not re-export them: it would name an optional peer in the types of
418
477
  every consumer, including one that composes no routing.
419
478
 
420
479
  ### The object form of `meta.route`
@@ -422,19 +481,20 @@ every consumer, including one that composes no routing.
422
481
  The string form declares the path only. The object form declares the path and the
423
482
  behaviour of the generated `play.route` transition:
424
483
 
425
- ```typescript
484
+ ```typescript fragment
426
485
  meta: {
427
486
  route: {
428
487
  path: "/doc/:docId",
429
488
  // Where the generated transition sits. The default is "root", which is what
430
489
  // XState does: every route transition sits on the root of the machine.
431
490
  // "root" — one transition on the root. A route from any state arrives.
432
- // "local" — one transition on the PARENT. The parent keeps its entry action,
433
- // and a route from outside the parent arrives NOWHERE.
434
- // "both" — one in each place. The parent keeps its entry action, and a route
435
- // from outside the parent still arrives.
491
+ // "local" — one transition on the PARENT. The parent keeps its entry action
492
+ // under `reenter: false`, and a route from outside the parent
493
+ // arrives NOWHERE.
494
+ // "both" — one in each place. The parent keeps its entry action under
495
+ // `reenter: false`, and a route from outside the parent still arrives.
436
496
  handler: "both",
437
- // Whether the transition re-enters its OWN DOMAIN. The default is false, which
497
+ // Whether the transition re-enters its DOMAIN. The default is false, which
438
498
  // is the default of XState. Under `handler: "root"` the domain is the root of
439
499
  // the machine, so `false` spares the root alone: each ancestor between the root
440
500
  // and the target still runs its exit and its entry actions. `handler` is the
@@ -449,18 +509,17 @@ meta: {
449
509
 
450
510
  An unknown `handler` value throws `InvalidRouteHandlerError` at the format time.
451
511
 
452
- > **Upgrading from 3.x: the `reenter` default changed, and a machine that relies on it
453
- > goes quiet.** An earlier release wrote `reenter: true` on EVERY generated transition,
454
- > so every routed state re-entered its own domain on each navigation and ran its `entry`
455
- > actions again. The flag is now what `meta.route` declares, and the default is `false` —
456
- > which is the default of XState. A state whose `entry` action must run on each
457
- > navigation has to declare `reenter: true` for itself. Nothing throws, and the action
458
- > simply stops running.
512
+ > **The `reenter` flag re-enters the domain, and not the target.** The target state runs
513
+ > its own `exit` and `entry` actions on each navigation to it, under both values. A state
514
+ > that declares `reenter: true` also re-enters the domain of its transition: the root
515
+ > under `handler: "root"`, and the parent under `"local"` and `"both"` while the parent is
516
+ > active. A route to the ROOT of the machine is the one exception: the root is then the
517
+ > target and the domain, so the root runs those actions only under `reenter: true`.
459
518
 
460
519
  The `data` field follows the `WithDynamicParams` shape of XState, so the function form
461
520
  reads the context and the event:
462
521
 
463
- ```typescript
522
+ ```typescript fragment
464
523
  data: ({ context, event }) => ({ title: `Document ${event.params?.docId}` });
465
524
  ```
466
525
 
@@ -9,8 +9,8 @@
9
9
  * {@link compose} applies each capability from left to right, so the LAST one is the
10
10
  * outermost class. The ORDER decides no value: a capability that publishes one derives it
11
11
  * with a computed atom over `state`, and the engine evaluates every derivation from the
12
- * one write of a transition, in topological order. `onSnapshot` remains for a capability
13
- * that must run an EFFECT, and an override of it still calls `super.onSnapshot()` first.
12
+ * one write of a transition, in topological order. A capability that must run an EFFECT
13
+ * overrides `onSnapshot`, and the override calls `super.onSnapshot()` first.
14
14
  *
15
15
  * ## Why the types read this way
16
16
  *
@@ -1,4 +1,8 @@
1
- export function compose(Base, ...capabilities) {
2
- return capabilities.reduce((actor, capability) => capability(actor), Base);
1
+ //#region packages/play-xstate/src/capabilities.ts
2
+ function compose(Base, ...capabilities) {
3
+ return capabilities.reduce((actor, capability) => capability(actor), Base);
3
4
  }
5
+ //#endregion
6
+ export { compose };
7
+
4
8
  //# sourceMappingURL=capabilities.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AA6HA,MAAM,UAAU,OAAO,CACtB,IAAiC,EACjC,GAAG,YAEF;IAED,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC;AAC5E,CAAC"}
1
+ {"version":3,"file":"capabilities.js","names":[],"sources":["../src/capabilities.ts"],"sourcesContent":["/**\n * The composition of the optional capabilities of an actor.\n *\n * `PlayerActor` gives the protocol of `PlayActor` and nothing else: `state` and\n * `send`. Routing and the view are capabilities, each one a MIXIN in a module that the\n * core imports never. An application that renders no view therefore loads no view code,\n * and an application that declares no route loads no routing code.\n *\n * {@link compose} applies each capability from left to right, so the LAST one is the\n * outermost class. The ORDER decides no value: a capability that publishes one derives it\n * with a computed atom over `state`, and the engine evaluates every derivation from the\n * one write of a transition, in topological order. A capability that must run an EFFECT\n * overrides `onSnapshot`, and the override calls `super.onSnapshot()` first.\n *\n * ## Why the types read this way\n *\n * A capability is typed by the INSTANCE that it extends, and not by a type parameter for\n * the class. That one decision removes three problems at once:\n *\n * - A class that extends a TYPE PARAMETER must constrain it to `new (...args: any[])`, and\n * TypeScript reports TS2545 for every other spelling. A concrete constructor type needs\n * no `any`.\n * - A mixin that INFERS its return type emits no declaration: `Actor` of XState carries\n * private members such as `_actorScope`, and an anonymous class that holds one is not\n * nameable (TS4094).\n * - A conditional return type cannot be checked against the class that a mixin builds, so\n * it forces `as unknown as` at the return. Nothing here asserts anything.\n *\n * `TCapabilities` carries what the base already added, so a composed constructor names\n * every capability on its instance. {@link compose} is what accumulates them:\n * `compose(PlayerActor, withRouting, withView)` answers an actor that is `Routable` AND\n * `Viewable`. Each capability declares a FIXED return type, so the nested form\n * `withView(withRouting(PlayerActor))` answers `Viewable` alone.\n */\nimport type { ActorOptions, AnyStateMachine, InputFrom } from \"xstate\";\n\nimport type { PlayerActor } from \"./player-actor.js\";\nimport type { PlayerOptions } from \"./types.js\";\n\n/**\n * The constructor of a `PlayerActor`, with every capability that it carries already.\n *\n * The argument list is the one that `PlayerActor` declares, so `definePlayer` builds an\n * actor with the arguments checked, whatever the composition added to the instance.\n *\n * @typeParam TMachine - The machine of the actor.\n * @typeParam TCapabilities - What the capabilities added, for example `Routable & Viewable`.\n */\nexport type PlayerConstructor<\n\tTMachine extends AnyStateMachine,\n\tTCapabilities extends object = object,\n> = new (\n\tmachine: TMachine,\n\toptions: PlayerOptions<TMachine>,\n\tinput?: InputFrom<TMachine>,\n\trestoredSnapshot?: ActorOptions<TMachine>[\"snapshot\"],\n) => PlayerActor<TMachine> & TCapabilities;\n\n/**\n * One capability of an actor: a function that takes an actor class and answers the same\n * class with `TAdded` on the instance.\n *\n * `withRouting` of `@xmachines/play-xstate/routing` and `withView` of\n * `@xmachines/play-xstate/view` are the two that this package ships. Write your own with\n * the same shape, and {@link compose} takes it beside them.\n *\n * @typeParam TMachine - The machine of the actor.\n * @typeParam TAdded - What the capability adds to the instance, for example `Routable`.\n */\nexport type Capability<TMachine extends AnyStateMachine, TAdded extends object> = (\n\tBase: PlayerConstructor<TMachine>,\n) => PlayerConstructor<TMachine, TAdded>;\n\n/**\n * Builds an actor class from a base and a list of capabilities.\n *\n * It applies each capability from left to right, so the LAST one is the outermost class,\n * and the return type accumulates what each one adds:\n * `compose(PlayerActor, withRouting, withView)` is `Routable` AND `Viewable`.\n *\n * Use this form, and not the nested one. Each capability declares a FIXED return type, so\n * `withView(withRouting(PlayerActor))` builds the same class at run time and answers\n * `Viewable` alone at the type level — a router bridge then refuses the actor with\n * TS2739. The overloads below are what carries `Routable` through.\n *\n * @example\n * ```typescript\n * import { definePlayer, PlayerActor, compose } from \"@xmachines/play-xstate\";\n * import { withRouting } from \"@xmachines/play-xstate/routing\";\n * import { withView } from \"@xmachines/play-xstate/view\";\n *\n * const createPlayer = definePlayer({\n * machine,\n * actor: compose(PlayerActor, withRouting, withView),\n * });\n * ```\n *\n * Each overload takes the capabilities as separate arguments, `c1` to `c3`, and it\n * applies them from left to right.\n *\n * @param Base - The actor class to build on, normally `PlayerActor`.\n */\nexport function compose<TMachine extends AnyStateMachine>(\n\tBase: PlayerConstructor<TMachine>,\n): PlayerConstructor<TMachine>;\nexport function compose<TMachine extends AnyStateMachine, TC1 extends object>(\n\tBase: PlayerConstructor<TMachine>,\n\tc1: Capability<TMachine, TC1>,\n): PlayerConstructor<TMachine, TC1>;\nexport function compose<TMachine extends AnyStateMachine, TC1 extends object, TC2 extends object>(\n\tBase: PlayerConstructor<TMachine>,\n\tc1: Capability<TMachine, TC1>,\n\tc2: Capability<TMachine, TC2>,\n): PlayerConstructor<TMachine, TC1 & TC2>;\nexport function compose<\n\tTMachine extends AnyStateMachine,\n\tTC1 extends object,\n\tTC2 extends object,\n\tTC3 extends object,\n>(\n\tBase: PlayerConstructor<TMachine>,\n\tc1: Capability<TMachine, TC1>,\n\tc2: Capability<TMachine, TC2>,\n\tc3: Capability<TMachine, TC3>,\n): PlayerConstructor<TMachine, TC1 & TC2 & TC3>;\nexport function compose<TMachine extends AnyStateMachine>(\n\tBase: PlayerConstructor<TMachine>,\n\t...capabilities: ReadonlyArray<\n\t\t(Base: PlayerConstructor<TMachine>) => PlayerConstructor<TMachine>\n\t>\n): PlayerConstructor<TMachine> {\n\treturn capabilities.reduce((actor, capability) => capability(actor), Base);\n}\n"],"mappings":";AA6HA,SAAgB,QACf,MACA,GAAG,cAG2B;CAC9B,OAAO,aAAa,QAAQ,OAAO,eAAe,WAAW,KAAK,GAAG,IAAI;AAC1E"}
@@ -1,11 +1,11 @@
1
1
  import { PlayerActor } from "./player-actor.js";
2
- export function definePlayer(config) {
3
- const { machine, options, actor } = config;
4
- // `PlayerActor` is the default, and it carries no capability. A consumer that routes or
5
- // renders passes a composed class, and this module imports neither capability. The two
6
- // overloads above are what keeps the answer exact: the default one answers a bare
7
- // player, and the other answers the player with everything that the composition added.
8
- const ActorClass = actor ?? PlayerActor;
9
- return (input, restore) => new ActorClass(machine, options ?? {}, input, restore?.snapshot);
2
+ //#region packages/play-xstate/src/define-player.ts
3
+ function definePlayer(config) {
4
+ const { machine, options, actor } = config;
5
+ const ActorClass = actor ?? PlayerActor;
6
+ return (input, restore) => new ActorClass(machine, options ?? {}, input, restore?.snapshot);
10
7
  }
8
+ //#endregion
9
+ export { definePlayer };
10
+
11
11
  //# sourceMappingURL=define-player.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"define-player.js","sourceRoot":"","sources":["../src/define-player.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAkEhD,MAAM,UAAU,YAAY,CAC3B,MAA6C;IAE7C,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;IAC3C,wFAAwF;IACxF,uFAAuF;IACvF,kFAAkF;IAClF,uFAAuF;IACvF,MAAM,UAAU,GAAG,KAAK,IAAI,WAAW,CAAC;IAExC,OAAO,CAAC,KAA2B,EAAE,OAA8C,EAAE,EAAE,CACtF,IAAI,UAAU,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;AACnE,CAAC"}
1
+ {"version":3,"file":"define-player.js","names":[],"sources":["../src/define-player.ts"],"sourcesContent":["import type { AnyStateMachine, InputFrom } from \"xstate\";\nimport type { PlayerConfig, PlayerFactory, PlayerFactoryResumeOptions } from \"./types.js\";\nimport type { PlayerConstructor } from \"./capabilities.js\";\nimport { PlayerActor } from \"./player-actor.js\";\n\n/**\n * Creates a player factory from an XState machine\n *\n * This factory function accepts an XState v5 machine. It returns a function that\n * makes {@link PlayerActor} instances. One configuration can therefore make more\n * than one actor instance, and this helps with a test, with an application of\n * several instances, and with a render on the server.\n *\n * @typeParam TMachine - The type of the XState v5 state machine\n *\n * @param config - The configuration object of the player\n * @param config.machine - The XState v5 state machine\n * @param config.options - The optional lifecycle hooks: onStart, onTransition, and the others\n *\n * @returns The factory function. It makes an actor instance, with an optional input context\n *\n * @example\n * A basic player factory\n * ```typescript\n * import { setup } from \"xstate\";\n * import { definePlayer } from \"@xmachines/play-xstate\";\n *\n * const machine = setup({}).createMachine({\n * initial: 'idle',\n * states: {\n * idle: { meta: { route: '/' } },\n * active: { meta: { route: '/active' } }\n * }\n * });\n *\n * const createPlayer = definePlayer({ machine });\n * const actor = createPlayer();\n * actor.start();\n * ```\n *\n * @example\n * More than one actor instance from one factory\n * ```typescript\n * const createPlayer = definePlayer({ machine });\n *\n * // Create an actor for each user\n * const alice = createPlayer({ userId: 'alice' });\n * const bob = createPlayer({ userId: 'bob' });\n *\n * alice.start();\n * bob.start();\n *\n * // The two state machines are independent\n * console.log(alice.state.get() !== bob.state.get());\n * ```\n *\n * @see [Play RFC](../../docs/rfc/play.md)\n * @see {@link PlayerActor} for the concrete actor implementation\n * @see {@link PlayerConfig} for the configuration options\n * @see {@link PlayerFactory} for the signature of the factory function\n */\nexport function definePlayer<TMachine extends AnyStateMachine>(\n\tconfig: PlayerConfig<TMachine> & { actor?: undefined },\n): PlayerFactory<TMachine>;\nexport function definePlayer<TMachine extends AnyStateMachine, TCapabilities extends object>(\n\tconfig: PlayerConfig<TMachine, TCapabilities> & {\n\t\tactor: PlayerConstructor<TMachine, TCapabilities>;\n\t},\n): PlayerFactory<TMachine, TCapabilities>;\nexport function definePlayer<TMachine extends AnyStateMachine, TCapabilities extends object>(\n\tconfig: PlayerConfig<TMachine, TCapabilities>,\n): PlayerFactory<TMachine, TCapabilities> | PlayerFactory<TMachine> {\n\tconst { machine, options, actor } = config;\n\t// `PlayerActor` is the default, and it carries no capability. A consumer that routes or\n\t// renders passes a composed class, and this module imports neither capability. The two\n\t// overloads above are what keeps the answer exact: the default one answers a bare\n\t// player, and the other answers the player with everything that the composition added.\n\tconst ActorClass = actor ?? PlayerActor;\n\n\treturn (input?: InputFrom<TMachine>, restore?: PlayerFactoryResumeOptions<TMachine>) =>\n\t\tnew ActorClass(machine, options ?? {}, input, restore?.snapshot);\n}\n"],"mappings":";;AAqEA,SAAgB,aACf,QACmE;CACnE,MAAM,EAAE,SAAS,SAAS,UAAU;CAKpC,MAAM,aAAa,SAAS;CAE5B,QAAQ,OAA6B,YACpC,IAAI,WAAW,SAAS,WAAW,CAAC,GAAG,OAAO,SAAS,QAAQ;AACjE"}