@xmachines/play-xstate 2.2.0 → 4.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 (75) hide show
  1. package/README.md +158 -54
  2. package/dist/capabilities.d.ts +92 -0
  3. package/dist/capabilities.d.ts.map +1 -0
  4. package/dist/capabilities.js +4 -0
  5. package/dist/capabilities.js.map +1 -0
  6. package/dist/define-player.d.ts +7 -1
  7. package/dist/define-player.d.ts.map +1 -1
  8. package/dist/define-player.js +9 -60
  9. package/dist/define-player.js.map +1 -1
  10. package/dist/errors.d.ts +29 -26
  11. package/dist/errors.d.ts.map +1 -1
  12. package/dist/errors.js +53 -35
  13. package/dist/errors.js.map +1 -1
  14. package/dist/index.d.ts +3 -4
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +14 -4
  17. package/dist/index.js.map +1 -1
  18. package/dist/player-actor.d.ts +74 -114
  19. package/dist/player-actor.d.ts.map +1 -1
  20. package/dist/player-actor.js +94 -223
  21. package/dist/player-actor.js.map +1 -1
  22. package/dist/routing/derive-current-route.d.ts +1 -36
  23. package/dist/routing/derive-current-route.d.ts.map +1 -1
  24. package/dist/routing/derive-current-route.js +2 -76
  25. package/dist/routing/derive-current-route.js.map +1 -1
  26. package/dist/routing/derive-initial-route.d.ts.map +1 -1
  27. package/dist/routing/derive-initial-route.js +11 -0
  28. package/dist/routing/derive-initial-route.js.map +1 -1
  29. package/dist/routing/derive-route.d.ts +81 -2
  30. package/dist/routing/derive-route.d.ts.map +1 -1
  31. package/dist/routing/derive-route.js +97 -3
  32. package/dist/routing/derive-route.js.map +1 -1
  33. package/dist/routing/format-play-route-transitions.d.ts +8 -2
  34. package/dist/routing/format-play-route-transitions.d.ts.map +1 -1
  35. package/dist/routing/format-play-route-transitions.js +170 -43
  36. package/dist/routing/format-play-route-transitions.js.map +1 -1
  37. package/dist/routing/index.d.ts +1 -1
  38. package/dist/routing/index.d.ts.map +1 -1
  39. package/dist/routing/types.d.ts +9 -5
  40. package/dist/routing/types.d.ts.map +1 -1
  41. package/dist/state-meta.d.ts +52 -0
  42. package/dist/state-meta.d.ts.map +1 -0
  43. package/dist/state-meta.js +77 -0
  44. package/dist/state-meta.js.map +1 -0
  45. package/dist/types.d.ts +18 -3
  46. package/dist/types.d.ts.map +1 -1
  47. package/dist/view/derive-current-view.d.ts +1 -1
  48. package/dist/view/derive-current-view.d.ts.map +1 -1
  49. package/dist/view/derive-current-view.js +35 -17
  50. package/dist/view/derive-current-view.js.map +1 -1
  51. package/dist/with-routing.d.ts +45 -0
  52. package/dist/with-routing.d.ts.map +1 -0
  53. package/dist/with-routing.js +78 -0
  54. package/dist/with-routing.js.map +1 -0
  55. package/dist/with-view.d.ts +42 -0
  56. package/dist/with-view.d.ts.map +1 -0
  57. package/dist/with-view.js +150 -0
  58. package/dist/with-view.js.map +1 -0
  59. package/package.json +39 -18
  60. package/dist/guards/compose.d.ts +0 -158
  61. package/dist/guards/compose.d.ts.map +0 -1
  62. package/dist/guards/compose.js +0 -188
  63. package/dist/guards/compose.js.map +0 -1
  64. package/dist/guards/helpers.d.ts +0 -62
  65. package/dist/guards/helpers.d.ts.map +0 -1
  66. package/dist/guards/helpers.js +0 -85
  67. package/dist/guards/helpers.js.map +0 -1
  68. package/dist/guards/index.d.ts +0 -20
  69. package/dist/guards/index.d.ts.map +0 -1
  70. package/dist/guards/index.js +0 -18
  71. package/dist/guards/index.js.map +0 -1
  72. package/dist/guards/types.d.ts +0 -22
  73. package/dist/guards/types.d.ts.map +0 -1
  74. package/dist/guards/types.js +0 -2
  75. package/dist/guards/types.js.map +0 -1
@@ -1,8 +1,12 @@
1
- export interface RouteObject {
2
- path: string;
3
- [key: string]: unknown;
4
- }
5
- export type RouteMetadata = string | RouteObject;
1
+ /**
2
+ * `RouteObject` and `RouteMetadata` have ONE definition, and it lives in
3
+ * `@xmachines/play-router`. That package owns the routing protocol, and this package
4
+ * consumes it. A second definition here would be a copy that drifts: a field added to
5
+ * one of them would leave the other behind, and nothing would fail.
6
+ *
7
+ * The re-export keeps the import path of every consumer of this package unchanged.
8
+ */
9
+ export type { RouteObject, RouteMetadata, RouteData, RouteDataResolver, } from "@xmachines/play-router";
6
10
  /**
7
11
  * The context of the route construction, from the machine context.
8
12
  *
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/routing/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,WAAW,CAAC;AAEjD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,YAAY;IAC5B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/routing/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,YAAY,EACX,WAAW,EACX,aAAa,EACb,SAAS,EACT,iBAAiB,GACjB,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,YAAY;IAC5B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The read of the `meta` of the active states, which BOTH capabilities share.
3
+ *
4
+ * `deriveCurrentRoute` folds this record into a URL, and `deriveCurrentView` folds the
5
+ * same record into a view spec. The two therefore cannot move apart on the selection of
6
+ * the branch, and they cannot move apart on their tolerance of a degenerate snapshot.
7
+ *
8
+ * It lives in its own module, and no longer beside the route derivation, because it
9
+ * belongs to neither capability. `@xmachines/play-xstate/view` imported it from
10
+ * `routing/derive-current-route.ts`, and that module reads `deriveRoute`, which names
11
+ * `@xmachines/play-router`. A view-only application therefore loaded the whole route
12
+ * derivation, and the OPTIONAL peer of the routing reached the runtime graph of the view
13
+ * entry point.
14
+ */
15
+ import type { AnyMachineSnapshot } from "xstate";
16
+ /**
17
+ * Collects the `meta` object of the active state nodes of a SINGLE branch, from the
18
+ * root to a leaf. The key of each entry is the state id, and the order is the
19
+ * ancestors first. {@link deriveRoute} folds this shape.
20
+ *
21
+ * `snapshot.getMeta()` returns a FLAT record of the meta object of every active
22
+ * state. For a machine that is not parallel, that record is one chain of ancestors
23
+ * already. For a PARALLEL machine, it mixes the entries of every active region. A
24
+ * blind fold therefore joins a relative route of one region to an absolute route of
25
+ * a sibling region, and the URL belongs to the tree of neither region. The flat
26
+ * record also cannot go back into a hierarchy: when a state declares an explicit
27
+ * `id`, for example a child with `id: "dashboard-overview"` under `id: "dashboard"`,
28
+ * the meta keys are those ids, and they carry no information about the ancestry.
29
+ *
30
+ * Therefore this function walks `snapshot.value`, which holds the real hierarchy of
31
+ * the active states by the state key, against the node tree of the machine. It
32
+ * follows the FIRST active child at each level. This gives one deterministic branch,
33
+ * which matches the historical behavior of "the first that it finds" for a parallel
34
+ * machine. It also works with an explicit id, because each node carries its own `id`
35
+ * and its own `meta`.
36
+ *
37
+ * The function returns `null` when the snapshot exposes no machine and no value to
38
+ * walk. This is a defensive measure, because a real XState snapshot always exposes
39
+ * them. The caller then uses `getMeta()`, as before.
40
+ */
41
+ export declare const firstActiveBranchMeta: (snapshot: AnyMachineSnapshot) => Record<string, unknown> | null;
42
+ /**
43
+ * Resolves the meta record that the route derivation and the view derivation fold:
44
+ * the single active branch that {@link firstActiveBranchMeta} walks, which is
45
+ * correct for a parallel machine and for an explicit id, or the flat `getMeta()`
46
+ * record when the snapshot has no machine tree to walk. `deriveCurrentRoute` and
47
+ * `deriveCurrentView` share this function. Therefore the two sides cannot move apart
48
+ * on the selection of the branch, and they cannot move apart on their tolerance of a
49
+ * degenerate snapshot.
50
+ */
51
+ export declare const activeStateMeta: (snapshot: AnyMachineSnapshot) => Record<string, unknown> | null;
52
+ //# sourceMappingURL=state-meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-meta.d.ts","sourceRoot":"","sources":["../src/state-meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,qBAAqB,GACjC,UAAU,kBAAkB,KAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAqC5B,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,GAAI,UAAU,kBAAkB,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAMxF,CAAC"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Collects the `meta` object of the active state nodes of a SINGLE branch, from the
3
+ * root to a leaf. The key of each entry is the state id, and the order is the
4
+ * ancestors first. {@link deriveRoute} folds this shape.
5
+ *
6
+ * `snapshot.getMeta()` returns a FLAT record of the meta object of every active
7
+ * state. For a machine that is not parallel, that record is one chain of ancestors
8
+ * already. For a PARALLEL machine, it mixes the entries of every active region. A
9
+ * blind fold therefore joins a relative route of one region to an absolute route of
10
+ * a sibling region, and the URL belongs to the tree of neither region. The flat
11
+ * record also cannot go back into a hierarchy: when a state declares an explicit
12
+ * `id`, for example a child with `id: "dashboard-overview"` under `id: "dashboard"`,
13
+ * the meta keys are those ids, and they carry no information about the ancestry.
14
+ *
15
+ * Therefore this function walks `snapshot.value`, which holds the real hierarchy of
16
+ * the active states by the state key, against the node tree of the machine. It
17
+ * follows the FIRST active child at each level. This gives one deterministic branch,
18
+ * which matches the historical behavior of "the first that it finds" for a parallel
19
+ * machine. It also works with an explicit id, because each node carries its own `id`
20
+ * and its own `meta`.
21
+ *
22
+ * The function returns `null` when the snapshot exposes no machine and no value to
23
+ * walk. This is a defensive measure, because a real XState snapshot always exposes
24
+ * them. The caller then uses `getMeta()`, as before.
25
+ */
26
+ export const firstActiveBranchMeta = (snapshot) => {
27
+ const root = snapshot.machine?.root;
28
+ if (!root)
29
+ return null;
30
+ const ordered = {};
31
+ let node = root;
32
+ let value = snapshot.value;
33
+ while (node) {
34
+ if (node.meta && typeof node.meta === "object") {
35
+ ordered[node.id] = node.meta; // nosemgrep: gitlab.eslint.detect-object-injection
36
+ }
37
+ // Find the key of the active child at this level. A string value is the name of an
38
+ // atomic active leaf. An object value is a compound node, with one key, or a
39
+ // parallel node, with many keys: take the first key, for one deterministic
40
+ // branch.
41
+ let key;
42
+ if (typeof value === "string") {
43
+ key = value;
44
+ }
45
+ else if (value && typeof value === "object") {
46
+ key = Object.keys(value)[0];
47
+ }
48
+ if (key === undefined)
49
+ break;
50
+ const child = node.states?.[key]; // nosemgrep: gitlab.eslint.detect-object-injection
51
+ if (!child)
52
+ break;
53
+ value =
54
+ typeof value === "object" && value !== null
55
+ ? value[key] // nosemgrep: gitlab.eslint.detect-object-injection
56
+ : {};
57
+ node = child;
58
+ }
59
+ return ordered;
60
+ };
61
+ /**
62
+ * Resolves the meta record that the route derivation and the view derivation fold:
63
+ * the single active branch that {@link firstActiveBranchMeta} walks, which is
64
+ * correct for a parallel machine and for an explicit id, or the flat `getMeta()`
65
+ * record when the snapshot has no machine tree to walk. `deriveCurrentRoute` and
66
+ * `deriveCurrentView` share this function. Therefore the two sides cannot move apart
67
+ * on the selection of the branch, and they cannot move apart on their tolerance of a
68
+ * degenerate snapshot.
69
+ */
70
+ export const activeStateMeta = (snapshot) => {
71
+ if (!snapshot || typeof snapshot.getMeta !== "function") {
72
+ return null;
73
+ }
74
+ const meta = firstActiveBranchMeta(snapshot) ?? snapshot.getMeta();
75
+ return meta && typeof meta === "object" ? meta : null;
76
+ };
77
+ //# sourceMappingURL=state-meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-meta.js","sourceRoot":"","sources":["../src/state-meta.ts"],"names":[],"mappings":"AAgBA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACpC,QAA4B,EACK,EAAE;IACnC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,IAEnB,CAAC;IACb,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,MAAM,OAAO,GAA4B,EAAE,CAAC;IAC5C,IAAI,IAAI,GAA4B,IAAI,CAAC;IACzC,IAAI,KAAK,GAAY,QAAQ,CAAC,KAAK,CAAC;IAEpC,OAAO,IAAI,EAAE,CAAC;QACb,IAAI,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAChD,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,mDAAmD;QAClF,CAAC;QAED,mFAAmF;QACnF,6EAA6E;QAC7E,2EAA2E;QAC3E,UAAU;QACV,IAAI,GAAuB,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC/B,GAAG,GAAG,KAAK,CAAC;QACb,CAAC;aAAM,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC/C,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QACD,IAAI,GAAG,KAAK,SAAS;YAAE,MAAM;QAE7B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAA4B,CAAC,CAAC,mDAAmD;QAChH,IAAI,CAAC,KAAK;YAAE,MAAM;QAClB,KAAK;YACJ,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;gBAC1C,CAAC,CAAE,KAAiC,CAAC,GAAG,CAAC,CAAC,mDAAmD;gBAC7F,CAAC,CAAC,EAAE,CAAC;QACP,IAAI,GAAG,KAAK,CAAC;IACd,CAAC;IAED,OAAO,OAAO,CAAC;AAChB,CAAC,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAA4B,EAAkC,EAAE;IAC/F,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QACzD,OAAO,IAAI,CAAC;IACb,CAAC;IACD,MAAM,IAAI,GAAG,qBAAqB,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;IACnE,OAAO,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAE,IAAgC,CAAC,CAAC,CAAC,IAAI,CAAC;AACpF,CAAC,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,13 +1,28 @@
1
1
  import type { ActorOptions, AnyStateMachine, InputFrom, SnapshotFrom } from "xstate";
2
2
  import type { PlayerActor as PlayerActorClass } from "./player-actor.js";
3
+ import type { PlayerConstructor } from "./capabilities.js";
3
4
  /**
4
5
  * The configuration of definePlayer()
5
6
  */
6
- export interface PlayerConfig<TMachine extends AnyStateMachine> {
7
+ export interface PlayerConfig<TMachine extends AnyStateMachine, TCapabilities extends object = object> {
7
8
  /** The XState v5 state machine */
8
9
  machine: TMachine;
9
10
  /** The lifecycle hooks and the configuration */
10
11
  options?: PlayerOptions<TMachine>;
12
+ /**
13
+ * The actor class to build, which decides which CAPABILITIES the actor carries.
14
+ *
15
+ * `PlayerActor` is the default, and it holds `state` and `send` alone. Compose a class
16
+ * to add a capability, and the factory then answers an actor with it:
17
+ *
18
+ * ```typescript
19
+ * definePlayer({ machine, actor: compose(PlayerActor, withRouting, withView) });
20
+ * ```
21
+ *
22
+ * An application that declares no route, and renders no view, passes nothing and loads
23
+ * neither body of code.
24
+ */
25
+ actor?: PlayerConstructor<TMachine, TCapabilities>;
11
26
  }
12
27
  /**
13
28
  * The lifecycle hooks of the player — the observability surface around the actor.
@@ -21,7 +36,7 @@ export interface PlayerOptions<TMachine extends AnyStateMachine> {
21
36
  onStart?: (actor: PlayerActorClass<TMachine>) => void;
22
37
  /**
23
38
  * The actor calls it on each real stop, which means only after it tore a running
24
- * actor down. A second `stop()` call, a second `dispose()` call, and a stop of an
39
+ * actor down. A second `stop()` call, and a stop of an
25
40
  * actor that never started fire the hook not.
26
41
  */
27
42
  onStop?: (actor: PlayerActorClass<TMachine>) => void;
@@ -118,5 +133,5 @@ export interface PlayerFactoryResumeOptions<TMachine extends AnyStateMachine> {
118
133
  * An absent input is then a compile error, and not an actor that starts in an error
119
134
  * status with a `null` initial route.
120
135
  */
121
- export type PlayerFactory<TMachine extends AnyStateMachine> = undefined extends InputFrom<TMachine> ? (input?: InputFrom<TMachine>, options?: PlayerFactoryResumeOptions<TMachine>) => PlayerActorClass<TMachine> : (input: InputFrom<TMachine>, options?: PlayerFactoryResumeOptions<TMachine>) => PlayerActorClass<TMachine>;
136
+ export type PlayerFactory<TMachine extends AnyStateMachine, TCapabilities extends object = object> = undefined extends InputFrom<TMachine> ? (input?: InputFrom<TMachine>, options?: PlayerFactoryResumeOptions<TMachine>) => PlayerActorClass<TMachine> & TCapabilities : (input: InputFrom<TMachine>, options?: PlayerFactoryResumeOptions<TMachine>) => PlayerActorClass<TMachine> & TCapabilities;
122
137
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACrF,OAAO,KAAK,EAAE,WAAW,IAAI,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,YAAY,CAAC,QAAQ,SAAS,eAAe;IAC7D,kCAAkC;IAClC,OAAO,EAAE,QAAQ,CAAC;IAElB,gDAAgD;IAChD,OAAO,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,QAAQ,SAAS,eAAe;IAC9D;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAEtD;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAErD;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CACd,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EACjC,SAAS,EAAE,YAAY,CAAC,QAAQ,CAAC,EACjC,SAAS,EAAE,YAAY,CAAC,QAAQ,CAAC,KAC7B,IAAI,CAAC;IAEV,uDAAuD;IACvD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAE3F;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC;CAC5C;AAED;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B,CAAC,QAAQ,SAAS,eAAe;IAC3E;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC;CAC9C;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,CAAC,QAAQ,SAAS,eAAe,IACzD,SAAS,SAAS,SAAS,CAAC,QAAQ,CAAC,GAClC,CACA,KAAK,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,EAC3B,OAAO,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,KAC1C,gBAAgB,CAAC,QAAQ,CAAC,GAC9B,CACA,KAAK,EAAE,SAAS,CAAC,QAAQ,CAAC,EAC1B,OAAO,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,KAC1C,gBAAgB,CAAC,QAAQ,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACrF,OAAO,KAAK,EAAE,WAAW,IAAI,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,YAAY,CAC5B,QAAQ,SAAS,eAAe,EAChC,aAAa,SAAS,MAAM,GAAG,MAAM;IAErC,kCAAkC;IAClC,OAAO,EAAE,QAAQ,CAAC;IAElB,gDAAgD;IAChD,OAAO,CAAC,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAElC;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,EAAE,iBAAiB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;CACnD;AAED;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,QAAQ,SAAS,eAAe;IAC9D;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAEtD;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAErD;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CACd,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EACjC,SAAS,EAAE,YAAY,CAAC,QAAQ,CAAC,EACjC,SAAS,EAAE,YAAY,CAAC,QAAQ,CAAC,KAC7B,IAAI,CAAC;IAEV,uDAAuD;IACvD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAE3F;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,OAAO,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC;CAC5C;AAED;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B,CAAC,QAAQ,SAAS,eAAe;IAC3E;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC;CAC9C;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,CAAC,QAAQ,SAAS,eAAe,EAAE,aAAa,SAAS,MAAM,GAAG,MAAM,IAChG,SAAS,SAAS,SAAS,CAAC,QAAQ,CAAC,GAClC,CACA,KAAK,CAAC,EAAE,SAAS,CAAC,QAAQ,CAAC,EAC3B,OAAO,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,KAC1C,gBAAgB,CAAC,QAAQ,CAAC,GAAG,aAAa,GAC9C,CACA,KAAK,EAAE,SAAS,CAAC,QAAQ,CAAC,EAC1B,OAAO,CAAC,EAAE,0BAA0B,CAAC,QAAQ,CAAC,KAC1C,gBAAgB,CAAC,QAAQ,CAAC,GAAG,aAAa,CAAC"}
@@ -7,7 +7,7 @@
7
7
  * machine always belongs to the region of its URL.
8
8
  */
9
9
  import type { AnyMachineSnapshot } from "xstate";
10
- import { type PlaySpec } from "@xmachines/play-actor";
10
+ import { type PlaySpec } from "@xmachines/play-view";
11
11
  /**
12
12
  * Derives the current view of the actor from the state metadata.
13
13
  *
@@ -1 +1 @@
1
- {"version":3,"file":"derive-current-view.d.ts","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAiC,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAwDrF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,kBAAkB,KAAG,QAAQ,GAAG,IA4C3E,CAAC"}
1
+ {"version":3,"file":"derive-current-view.d.ts","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAiC,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAyEpF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,iBAAiB,GAAI,UAAU,kBAAkB,KAAG,QAAQ,GAAG,IA4C3E,CAAC"}
@@ -1,5 +1,5 @@
1
- import { composePlayState, toAtomState } from "@xmachines/play-actor";
2
- import { activeStateMeta } from "../routing/index.js";
1
+ import { composePlayState, toAtomState } from "@xmachines/play-view";
2
+ import { activeStateMeta } from "../state-meta.js";
3
3
  /**
4
4
  * The migration warning of the `contextProps` field, which 1.x removed. The code
5
5
  * writes it one time for each spec. A meta.view object from a person passes around
@@ -17,22 +17,40 @@ const warnRemovedContextProps = (viewMeta) => {
17
17
  console.warn("[play-xstate] meta.view.contextProps has been removed: the whole machine context " +
18
18
  "is always projected under /context. Delete the field — it no longer filters anything.");
19
19
  };
20
+ /** Reads the `view` of one meta entry, when the entry holds a whole PlaySpec. */
21
+ const viewOfEntry = (stateMeta) => {
22
+ const maybeView = stateMeta && typeof stateMeta === "object"
23
+ ? stateMeta.view
24
+ : undefined;
25
+ return maybeView &&
26
+ typeof maybeView === "object" &&
27
+ "root" in maybeView &&
28
+ "elements" in maybeView
29
+ ? maybeView
30
+ : null;
31
+ };
20
32
  const resolveViewMeta = (meta) => {
21
- // Walk from the last entry to the first: snapshot.getMeta() puts the keys of the
22
- // ancestors first. A scan from the end therefore lets the meta.view of the deepest
23
- // active state win, and an ancestor hides it not.
24
- const entries = Object.entries(meta);
25
- for (let i = entries.length - 1; i >= 0; i--) {
26
- // The array index has the bound of the loop. No user controls this property access.
27
- const [key, stateMeta] = entries[i]; // nosemgrep: gitlab.eslint.detect-object-injection
28
- const maybeView = stateMeta && typeof stateMeta === "object"
29
- ? stateMeta.view
30
- : undefined;
31
- if (maybeView &&
32
- typeof maybeView === "object" &&
33
- "root" in maybeView &&
34
- "elements" in maybeView) {
35
- return { key, view: maybeView };
33
+ // Take the LAST entry that holds a view, and not the first: snapshot.getMeta() puts
34
+ // the keys of the ancestors first, so the last match is the meta.view of the deepest
35
+ // active state. An ancestor hides it not.
36
+ //
37
+ // A walk from the end, and not a findLast or a mapped copy: this runs for each
38
+ // snapshot. The walk stops at the first match, and `viewOfEntry` runs one time for
39
+ // each entry that it visits — a `findLast` would run it a second time on the entry
40
+ // that its own predicate had already resolved, and a `map()` would visit every entry
41
+ // and allocate one object for each match before the search began.
42
+ //
43
+ // `toReversed()`, which copies, and not `reverse()`, which mutates: one spelling for
44
+ // one operation, beside the `toSorted()` that `unicorn/no-array-sort` asks for.
45
+ //
46
+ // The copy costs about 10 ns for the handful of entries that a state path holds, and
47
+ // `Object.entries` above it costs twenty times that. Measured, after a review called
48
+ // this line a cost of a hot path: it is not one, at any rate of snapshots that an
49
+ // actor produces.
50
+ for (const [key, stateMeta] of Object.entries(meta).toReversed()) {
51
+ const view = viewOfEntry(stateMeta);
52
+ if (view) {
53
+ return { key, view };
36
54
  }
37
55
  }
38
56
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"derive-current-view.js","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"derive-current-view.js","sourceRoot":"","sources":["../../src/view/derive-current-view.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The routing capability of an XState actor, as a mixin.
3
+ *
4
+ * `PlayerActor` holds `state` and `send`, and nothing about a route. This module adds
5
+ * `currentRoute` and `initialRoute`, which is what `Routable` of `@xmachines/play-router`
6
+ * asks for and what every router bridge reads.
7
+ *
8
+ * It is a SEPARATE entry point, `@xmachines/play-xstate/routing`, and the core imports it
9
+ * never. `@xmachines/play-router` is an OPTIONAL peer of this package for the same reason:
10
+ * an application that declares no route installs neither that package nor the route map
11
+ * and the bridge that it carries.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { definePlayer, PlayerActor, compose } from "@xmachines/play-xstate";
16
+ * import { withRouting } from "@xmachines/play-xstate/routing";
17
+ *
18
+ * const createPlayer = definePlayer({ machine, actor: compose(PlayerActor, withRouting) });
19
+ * const actor = createPlayer();
20
+ * actor.currentRoute.get(); // "/profile/alice"
21
+ * ```
22
+ *
23
+ * @packageDocumentation
24
+ */
25
+ import type { AnyStateMachine } from "xstate";
26
+ import type { Routable } from "@xmachines/play-router";
27
+ import type { PlayerConstructor } from "./capabilities.js";
28
+ /**
29
+ * Adds the routing capability to an actor class.
30
+ *
31
+ * The result satisfies `Routable`, so a router bridge accepts it. A class without this
32
+ * mixin exposes no `currentRoute`, and a bridge therefore refuses it when it compiles,
33
+ * rather than at the first navigation.
34
+ *
35
+ * The mixin declares NO constructor, and that is deliberate: TypeScript demands the
36
+ * signature `...args: any[]` from a mixin over a generic base (TS2545), and this
37
+ * workspace writes no `any`. A field initializer of a subclass runs after `super()`
38
+ * instead, and it reads the inputs that `PlayerActor` keeps for a capability.
39
+ *
40
+ * @param Base - The actor class to extend, normally `PlayerActor`.
41
+ */
42
+ export declare function withRouting<TMachine extends AnyStateMachine>(Base: PlayerConstructor<TMachine>): PlayerConstructor<TMachine, Routable>;
43
+ export { deriveRoute, isAbsoluteRoute, buildRouteUrl, formatPlayRouteTransitions, } from "./routing/index.js";
44
+ export type { RouteMachineConfig, RouteStateNode, RouteContext, RouteObject, RouteMetadata, RouteData, RouteDataResolver, } from "./routing/index.js";
45
+ //# sourceMappingURL=with-routing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-routing.d.ts","sourceRoot":"","sources":["../src/with-routing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAEvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG3D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,QAAQ,SAAS,eAAe,EAC3D,IAAI,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAC/B,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAoDvC;AAcD,OAAO,EACN,WAAW,EACX,eAAe,EACf,aAAa,EACb,0BAA0B,GAC1B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACX,kBAAkB,EAClB,cAAc,EACd,YAAY,EACZ,WAAW,EACX,aAAa,EACb,SAAS,EACT,iBAAiB,GACjB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,78 @@
1
+ import { Signal } from "@xmachines/play-signals";
2
+ import { deriveCurrentRoute, deriveInitialRoute } from "./routing/index.js";
3
+ /**
4
+ * Adds the routing capability to an actor class.
5
+ *
6
+ * The result satisfies `Routable`, so a router bridge accepts it. A class without this
7
+ * mixin exposes no `currentRoute`, and a bridge therefore refuses it when it compiles,
8
+ * rather than at the first navigation.
9
+ *
10
+ * The mixin declares NO constructor, and that is deliberate: TypeScript demands the
11
+ * signature `...args: any[]` from a mixin over a generic base (TS2545), and this
12
+ * workspace writes no `any`. A field initializer of a subclass runs after `super()`
13
+ * instead, and it reads the inputs that `PlayerActor` keeps for a capability.
14
+ *
15
+ * @param Base - The actor class to extend, normally `PlayerActor`.
16
+ */
17
+ export function withRouting(Base) {
18
+ class RoutableActor extends Base {
19
+ /**
20
+ * A TC39 `Signal.Computed`. It derives the current URL path from the `meta.route`
21
+ * template of the active machine state and from the context of the actor.
22
+ *
23
+ * It returns `null` when the current state has no `meta.route` field, and also when
24
+ * a necessary `:param` has no value in the context. The second case is normally
25
+ * temporary during a transition, and the signal computes the value again on the next
26
+ * snapshot.
27
+ *
28
+ * @example
29
+ * ```typescript
30
+ * // It returns "/profile/alice" when context.params.userId === "alice",
31
+ * // and null while the param is still absent.
32
+ * const route = actor.currentRoute.get();
33
+ * ```
34
+ */
35
+ currentRoute = new Signal.Computed(() => deriveCurrentRoute(this.state.get()));
36
+ /**
37
+ * The route of the initial state of the machine. The construction fixes it, and it
38
+ * never changes, also when the code restores the actor from a snapshot.
39
+ *
40
+ * A router bridge compares it with the browser URL, and it therefore separates a
41
+ * deep link (a URL that is not the initial one → the router wins) from a restore
42
+ * (the initial URL, and the actor at a different route from the restore → the actor
43
+ * wins).
44
+ *
45
+ * `deriveInitialRoute` derives the value statically from the machine definition,
46
+ * with the pure `initialTransition` helper of XState: the chain of the initial states
47
+ * and their `meta.route` templates are fixed at the moment of the machine
48
+ * definition, and the substitution of a `:param` uses the real initial context of
49
+ * the machine for the `input` of this actor. The code makes no second actor, and a
50
+ * snapshot of a restore changes the value never: it is always the **default**
51
+ * initial route of the machine.
52
+ *
53
+ * Without a snapshot of a restore, the pre-start snapshot of this actor IS that
54
+ * default initial state, so the code derives the route from it directly. A restore
55
+ * alone needs `initialTransition`, whose inert actor scope runs the initial
56
+ * transition two more times, one of them with an undefined `input`. That is a quirk
57
+ * of XState, and it costs too much for every other case.
58
+ */
59
+ initialRoute = this.playerRestoredSnapshot === undefined
60
+ ? deriveCurrentRoute(this.getSnapshot())
61
+ : deriveInitialRoute(this.playerMachine, this.playerInput);
62
+ }
63
+ return RoutableActor;
64
+ }
65
+ // The utilities of the route derivation and of the URL construction.
66
+ //
67
+ // They belong HERE, and no longer on the main entry. Each one names
68
+ // `@xmachines/play-router` in its own `.d.ts` — `PlayRouteEvent`, `RouteData`,
69
+ // `RouteObject` and `RouteMetadata` all have their single definition there. That
70
+ // package is an OPTIONAL peer, so a main entry that reached them gave every consumer
71
+ // of `definePlayer` a type graph that names a package their node_modules does not
72
+ // hold. `skipLibCheck` hides the fault and does not remove it: the types resolve to
73
+ // nothing.
74
+ //
75
+ // The view half exposes nothing on the main entry, for the same reason. The two
76
+ // capabilities hold one shape.
77
+ export { deriveRoute, isAbsoluteRoute, buildRouteUrl, formatPlayRouteTransitions, } from "./routing/index.js";
78
+ //# sourceMappingURL=with-routing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-routing.js","sourceRoot":"","sources":["../src/with-routing.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAIjD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAE5E;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CAC1B,IAAiC;IAEjC,MAAM,aAAc,SAAQ,IAAI;QAC/B;;;;;;;;;;;;;;;WAeG;QACa,YAAY,GAAmC,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,CACvF,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CACpC,CAAC;QAEF;;;;;;;;;;;;;;;;;;;;;;WAsBG;QACa,YAAY,GAC3B,IAAI,CAAC,sBAAsB,KAAK,SAAS;YACxC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACxC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;KAC7D;IAED,OAAO,aAAa,CAAC;AACtB,CAAC;AAED,qEAAqE;AACrE,EAAE;AACF,oEAAoE;AACpE,+EAA+E;AAC/E,iFAAiF;AACjF,qFAAqF;AACrF,kFAAkF;AAClF,oFAAoF;AACpF,WAAW;AACX,EAAE;AACF,gFAAgF;AAChF,+BAA+B;AAC/B,OAAO,EACN,WAAW,EACX,eAAe,EACf,aAAa,EACb,0BAA0B,GAC1B,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The view capability of an XState actor, as a mixin.
3
+ *
4
+ * `PlayerActor` holds `state` and `send`, and nothing about a view. This module adds
5
+ * `currentView`, which is what `Viewable` of `@xmachines/play-view` asks for and what
6
+ * every renderer reads.
7
+ *
8
+ * It is a SEPARATE entry point, `@xmachines/play-xstate/view`, and the core imports it
9
+ * never. `@xmachines/play-view` is an OPTIONAL peer of this package for the same reason:
10
+ * an application that renders no view installs neither that package nor the json-render
11
+ * types that it names.
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { definePlayer, PlayerActor, compose } from "@xmachines/play-xstate";
16
+ * import { withRouting } from "@xmachines/play-xstate/routing";
17
+ * import { withView } from "@xmachines/play-xstate/view";
18
+ *
19
+ * const createPlayer = definePlayer({
20
+ * machine,
21
+ * actor: compose(PlayerActor, withRouting, withView),
22
+ * });
23
+ * ```
24
+ *
25
+ * @packageDocumentation
26
+ */
27
+ import type { AnyStateMachine } from "xstate";
28
+ import { type Viewable } from "@xmachines/play-view";
29
+ import type { PlayerConstructor } from "./capabilities.js";
30
+ /**
31
+ * Adds the view capability to an actor class.
32
+ *
33
+ * Compose it AFTER the routing capability. An override calls `super.onSnapshot()` first,
34
+ * so `compose(PlayerActor, withRouting, withView)` gives the route its new value before
35
+ * the view derives from the same transition. A router bridge therefore sees a guard
36
+ * redirect before a renderer sees the view of the state that the guard refused.
37
+ *
38
+ * @param Base - The actor class to extend, normally `PlayerActor` or the result of
39
+ * another capability.
40
+ */
41
+ export declare function withView<TMachine extends AnyStateMachine>(Base: PlayerConstructor<TMachine>): PlayerConstructor<TMachine, Viewable>;
42
+ //# sourceMappingURL=with-view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"with-view.d.ts","sourceRoot":"","sources":["../src/with-view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAsB,eAAe,EAAE,MAAM,QAAQ,CAAC;AAGlE,OAAO,EAAqC,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGxF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAsD3D;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,SAAS,eAAe,EACxD,IAAI,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAC/B,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAgFvC"}