@xmachines/docs 1.0.0-beta.10

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 (197) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -0
  3. package/api/@xmachines/play/README.md +130 -0
  4. package/api/@xmachines/play/type-aliases/PlayEvent.md +81 -0
  5. package/api/@xmachines/play-actor/README.md +247 -0
  6. package/api/@xmachines/play-actor/classes/AbstractActor.md +520 -0
  7. package/api/@xmachines/play-actor/interfaces/Routable.md +29 -0
  8. package/api/@xmachines/play-actor/interfaces/ViewMetadata.md +17 -0
  9. package/api/@xmachines/play-actor/interfaces/Viewable.md +12 -0
  10. package/api/@xmachines/play-catalog/README.md +331 -0
  11. package/api/@xmachines/play-catalog/functions/defineCatalog.md +98 -0
  12. package/api/@xmachines/play-catalog/functions/defineComponents.md +134 -0
  13. package/api/@xmachines/play-catalog/type-aliases/Catalog.md +48 -0
  14. package/api/@xmachines/play-catalog/type-aliases/ComponentsFor.md +20 -0
  15. package/api/@xmachines/play-catalog/type-aliases/InferComponentProps.md +65 -0
  16. package/api/@xmachines/play-catalog/type-aliases/NoExtraKeys.md +17 -0
  17. package/api/@xmachines/play-react/README.md +423 -0
  18. package/api/@xmachines/play-react/classes/PlayErrorBoundary.md +613 -0
  19. package/api/@xmachines/play-react/functions/useSignalEffect.md +68 -0
  20. package/api/@xmachines/play-react/interfaces/PlayErrorBoundaryProps.md +15 -0
  21. package/api/@xmachines/play-react/interfaces/PlayErrorBoundaryState.md +14 -0
  22. package/api/@xmachines/play-react/interfaces/PlayRendererProps.md +15 -0
  23. package/api/@xmachines/play-react/variables/PlayRenderer.md +64 -0
  24. package/api/@xmachines/play-react-router/README.md +198 -0
  25. package/api/@xmachines/play-react-router/classes/ReactRouterBridge.md +321 -0
  26. package/api/@xmachines/play-react-router/classes/RouteMap.md +137 -0
  27. package/api/@xmachines/play-react-router/functions/PlayRouterProvider.md +19 -0
  28. package/api/@xmachines/play-react-router/functions/createRouteMapFromTree.md +35 -0
  29. package/api/@xmachines/play-react-router/interfaces/PlayRouteEvent.md +119 -0
  30. package/api/@xmachines/play-react-router/interfaces/PlayRouterProviderProps.md +14 -0
  31. package/api/@xmachines/play-react-router/interfaces/RouteMapping.md +17 -0
  32. package/api/@xmachines/play-react-router/interfaces/RouterBridge.md +104 -0
  33. package/api/@xmachines/play-react-router-demo/README.md +137 -0
  34. package/api/@xmachines/play-router/README.md +502 -0
  35. package/api/@xmachines/play-router/classes/BaseRouteMap.md +142 -0
  36. package/api/@xmachines/play-router/classes/RouterBridgeBase.md +300 -0
  37. package/api/@xmachines/play-router/functions/buildRouteTree.md +27 -0
  38. package/api/@xmachines/play-router/functions/connectRouter.md +67 -0
  39. package/api/@xmachines/play-router/functions/crawlMachine.md +92 -0
  40. package/api/@xmachines/play-router/functions/createBrowserHistory.md +47 -0
  41. package/api/@xmachines/play-router/functions/createRouteMap.md +53 -0
  42. package/api/@xmachines/play-router/functions/createRouter.md +76 -0
  43. package/api/@xmachines/play-router/functions/detectDuplicateRoutes.md +32 -0
  44. package/api/@xmachines/play-router/functions/extractMachineRoutes.md +64 -0
  45. package/api/@xmachines/play-router/functions/extractRoute.md +45 -0
  46. package/api/@xmachines/play-router/functions/findRouteById.md +37 -0
  47. package/api/@xmachines/play-router/functions/findRouteByPath.md +39 -0
  48. package/api/@xmachines/play-router/functions/getNavigableRoutes.md +35 -0
  49. package/api/@xmachines/play-router/functions/getRoutableRoutes.md +39 -0
  50. package/api/@xmachines/play-router/functions/routeExists.md +26 -0
  51. package/api/@xmachines/play-router/functions/validateRouteFormat.md +29 -0
  52. package/api/@xmachines/play-router/functions/validateStateExists.md +29 -0
  53. package/api/@xmachines/play-router/interfaces/BaseRouteMapping.md +27 -0
  54. package/api/@xmachines/play-router/interfaces/BrowserHistory.md +172 -0
  55. package/api/@xmachines/play-router/interfaces/BrowserWindow.md +69 -0
  56. package/api/@xmachines/play-router/interfaces/ConnectRouterOptions.md +13 -0
  57. package/api/@xmachines/play-router/interfaces/PlayRouteEvent.md +119 -0
  58. package/api/@xmachines/play-router/interfaces/RouteInfo.md +19 -0
  59. package/api/@xmachines/play-router/interfaces/RouteMap.md +56 -0
  60. package/api/@xmachines/play-router/interfaces/RouteNode.md +21 -0
  61. package/api/@xmachines/play-router/interfaces/RouteObject.md +21 -0
  62. package/api/@xmachines/play-router/interfaces/RouteTree.md +20 -0
  63. package/api/@xmachines/play-router/interfaces/RouterBridge.md +104 -0
  64. package/api/@xmachines/play-router/interfaces/StateVisit.md +15 -0
  65. package/api/@xmachines/play-router/interfaces/VanillaRouter.md +28 -0
  66. package/api/@xmachines/play-router/type-aliases/RouteMetadata.md +11 -0
  67. package/api/@xmachines/play-router-demo/README.md +137 -0
  68. package/api/@xmachines/play-signals/README.md +176 -0
  69. package/api/@xmachines/play-signals/interfaces/ComputedOptions.md +34 -0
  70. package/api/@xmachines/play-signals/interfaces/SignalComputed.md +49 -0
  71. package/api/@xmachines/play-signals/interfaces/SignalOptions.md +35 -0
  72. package/api/@xmachines/play-signals/interfaces/SignalState.md +68 -0
  73. package/api/@xmachines/play-signals/interfaces/SignalWatcher.md +97 -0
  74. package/api/@xmachines/play-signals/namespaces/Signal/README.md +22 -0
  75. package/api/@xmachines/play-signals/namespaces/Signal/classes/Computed.md +52 -0
  76. package/api/@xmachines/play-signals/namespaces/Signal/classes/State.md +72 -0
  77. package/api/@xmachines/play-signals/namespaces/Signal/interfaces/Options.md +19 -0
  78. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/README.md +21 -0
  79. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/classes/Watcher.md +85 -0
  80. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/currentComputed.md +13 -0
  81. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/hasSinks.md +19 -0
  82. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/hasSources.md +19 -0
  83. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/introspectSinks.md +19 -0
  84. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/introspectSources.md +19 -0
  85. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/functions/untrack.md +25 -0
  86. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/variables/unwatched.md +9 -0
  87. package/api/@xmachines/play-signals/namespaces/Signal/namespaces/subtle/variables/watched.md +9 -0
  88. package/api/@xmachines/play-signals/namespaces/Signal/variables/isComputed.md +19 -0
  89. package/api/@xmachines/play-signals/namespaces/Signal/variables/isState.md +19 -0
  90. package/api/@xmachines/play-signals/namespaces/Signal/variables/isWatcher.md +19 -0
  91. package/api/@xmachines/play-signals/type-aliases/WatcherNotify.md +32 -0
  92. package/api/@xmachines/play-solid/README.md +311 -0
  93. package/api/@xmachines/play-solid/interfaces/PlayRendererProps.md +15 -0
  94. package/api/@xmachines/play-solid/variables/PlayRenderer.md +70 -0
  95. package/api/@xmachines/play-solid-router/README.md +666 -0
  96. package/api/@xmachines/play-solid-router/classes/RouteMap.md +150 -0
  97. package/api/@xmachines/play-solid-router/classes/SolidRouterBridge.md +347 -0
  98. package/api/@xmachines/play-solid-router/functions/PlayRouterProvider.md +19 -0
  99. package/api/@xmachines/play-solid-router/functions/createRouteMap.md +32 -0
  100. package/api/@xmachines/play-solid-router/interfaces/AbstractActor.md +486 -0
  101. package/api/@xmachines/play-solid-router/interfaces/PlayRouteEvent.md +119 -0
  102. package/api/@xmachines/play-solid-router/interfaces/PlayRouterProviderProps.md +14 -0
  103. package/api/@xmachines/play-solid-router/interfaces/RouteMapping.md +14 -0
  104. package/api/@xmachines/play-solid-router/interfaces/RouterBridge.md +104 -0
  105. package/api/@xmachines/play-solid-router/type-aliases/RoutableActor.md +9 -0
  106. package/api/@xmachines/play-solid-router/type-aliases/SolidRouterHooks.md +51 -0
  107. package/api/@xmachines/play-solid-router-demo/README.md +127 -0
  108. package/api/@xmachines/play-tanstack-react-router/README.md +226 -0
  109. package/api/@xmachines/play-tanstack-react-router/classes/RouteMap.md +137 -0
  110. package/api/@xmachines/play-tanstack-react-router/classes/TanStackReactRouterBridge.md +348 -0
  111. package/api/@xmachines/play-tanstack-react-router/functions/PlayRouterProvider.md +19 -0
  112. package/api/@xmachines/play-tanstack-react-router/functions/createRouteMap.md +53 -0
  113. package/api/@xmachines/play-tanstack-react-router/functions/createRouteMapFromTree.md +35 -0
  114. package/api/@xmachines/play-tanstack-react-router/functions/extractParams.md +38 -0
  115. package/api/@xmachines/play-tanstack-react-router/functions/extractQueryParams.md +33 -0
  116. package/api/@xmachines/play-tanstack-react-router/interfaces/PlayRouteEvent.md +119 -0
  117. package/api/@xmachines/play-tanstack-react-router/interfaces/PlayRouterProviderProps.md +14 -0
  118. package/api/@xmachines/play-tanstack-react-router/interfaces/RouteMapping.md +17 -0
  119. package/api/@xmachines/play-tanstack-react-router/interfaces/RouteNavigateEvent.md +26 -0
  120. package/api/@xmachines/play-tanstack-react-router/interfaces/RouterBridge.md +104 -0
  121. package/api/@xmachines/play-tanstack-react-router/type-aliases/TanStackRouterInstance.md +9 -0
  122. package/api/@xmachines/play-tanstack-react-router/type-aliases/TanStackRouterLike.md +78 -0
  123. package/api/@xmachines/play-tanstack-react-router/variables/extractMachineRoutes.md +64 -0
  124. package/api/@xmachines/play-tanstack-react-router-demo/README.md +126 -0
  125. package/api/@xmachines/play-tanstack-solid-router/README.md +285 -0
  126. package/api/@xmachines/play-tanstack-solid-router/classes/RouteMap.md +150 -0
  127. package/api/@xmachines/play-tanstack-solid-router/classes/SolidRouterBridge.md +343 -0
  128. package/api/@xmachines/play-tanstack-solid-router/functions/PlayRouterProvider.md +19 -0
  129. package/api/@xmachines/play-tanstack-solid-router/functions/createRouteMap.md +32 -0
  130. package/api/@xmachines/play-tanstack-solid-router/interfaces/PlayRouteEvent.md +119 -0
  131. package/api/@xmachines/play-tanstack-solid-router/interfaces/PlayRouterProviderProps.md +14 -0
  132. package/api/@xmachines/play-tanstack-solid-router/interfaces/RouteMapping.md +23 -0
  133. package/api/@xmachines/play-tanstack-solid-router/interfaces/RouterBridge.md +104 -0
  134. package/api/@xmachines/play-tanstack-solid-router/type-aliases/RoutableActor.md +9 -0
  135. package/api/@xmachines/play-tanstack-solid-router/type-aliases/TanStackRouterInstance.md +9 -0
  136. package/api/@xmachines/play-tanstack-solid-router/type-aliases/TanStackRouterLike.md +78 -0
  137. package/api/@xmachines/play-tanstack-solid-router-demo/README.md +126 -0
  138. package/api/@xmachines/play-vue/README.md +292 -0
  139. package/api/@xmachines/play-vue/interfaces/PlayRendererProps.md +14 -0
  140. package/api/@xmachines/play-vue/variables/PlayRenderer.md +9 -0
  141. package/api/@xmachines/play-vue-router/README.md +604 -0
  142. package/api/@xmachines/play-vue-router/classes/RouteMap.md +209 -0
  143. package/api/@xmachines/play-vue-router/classes/VueBaseRouteMap.md +201 -0
  144. package/api/@xmachines/play-vue-router/classes/VueRouterBridge.md +360 -0
  145. package/api/@xmachines/play-vue-router/functions/createRouteMap.md +19 -0
  146. package/api/@xmachines/play-vue-router/interfaces/PlayRouteEvent.md +119 -0
  147. package/api/@xmachines/play-vue-router/interfaces/RouteMapping.md +15 -0
  148. package/api/@xmachines/play-vue-router/interfaces/RouterBridge.md +104 -0
  149. package/api/@xmachines/play-vue-router/type-aliases/RoutableActor.md +9 -0
  150. package/api/@xmachines/play-vue-router/variables/PlayRouterProvider.md +67 -0
  151. package/api/@xmachines/play-vue-router-demo/README.md +133 -0
  152. package/api/@xmachines/play-xstate/README.md +512 -0
  153. package/api/@xmachines/play-xstate/classes/PlayerActor.md +527 -0
  154. package/api/@xmachines/play-xstate/functions/buildRouteUrl.md +43 -0
  155. package/api/@xmachines/play-xstate/functions/composeGuards.md +79 -0
  156. package/api/@xmachines/play-xstate/functions/composeGuardsOr.md +67 -0
  157. package/api/@xmachines/play-xstate/functions/definePlayer.md +127 -0
  158. package/api/@xmachines/play-xstate/functions/deriveRoute.md +109 -0
  159. package/api/@xmachines/play-xstate/functions/eventMatches.md +40 -0
  160. package/api/@xmachines/play-xstate/functions/formatPlayRouteTransitions.md +54 -0
  161. package/api/@xmachines/play-xstate/functions/hasContext.md +42 -0
  162. package/api/@xmachines/play-xstate/functions/isAbsoluteRoute.md +41 -0
  163. package/api/@xmachines/play-xstate/functions/mergeViewProps.md +26 -0
  164. package/api/@xmachines/play-xstate/functions/negateGuard.md +61 -0
  165. package/api/@xmachines/play-xstate/functions/stateMatches.md +25 -0
  166. package/api/@xmachines/play-xstate/functions/validateComponentBinding.md +39 -0
  167. package/api/@xmachines/play-xstate/functions/validateViewProps.md +80 -0
  168. package/api/@xmachines/play-xstate/interfaces/CatalogEntry.md +16 -0
  169. package/api/@xmachines/play-xstate/interfaces/PlayerConfig.md +24 -0
  170. package/api/@xmachines/play-xstate/interfaces/PlayerOptions.md +26 -0
  171. package/api/@xmachines/play-xstate/interfaces/RouteContext.md +22 -0
  172. package/api/@xmachines/play-xstate/type-aliases/Catalog.md +21 -0
  173. package/api/@xmachines/play-xstate/type-aliases/ComposedGuard.md +14 -0
  174. package/api/@xmachines/play-xstate/type-aliases/Guard.md +34 -0
  175. package/api/@xmachines/play-xstate/type-aliases/GuardArray.md +20 -0
  176. package/api/@xmachines/play-xstate/type-aliases/PlayerFactory.md +29 -0
  177. package/api/@xmachines/play-xstate/type-aliases/RouteMachineConfig.md +45 -0
  178. package/api/@xmachines/play-xstate/type-aliases/RouteStateNode.md +51 -0
  179. package/api/@xmachines/play-xstate/type-aliases/ValidationResult.md +17 -0
  180. package/api/@xmachines/play-xstate/type-aliases/ViewMergeContext.md +35 -0
  181. package/api/@xmachines/shared/README.md +379 -0
  182. package/api/@xmachines/shared/functions/defineXmVitestConfig.md +29 -0
  183. package/api/@xmachines/shared/functions/xmAliases.md +24 -0
  184. package/api/README.md +25 -0
  185. package/api/llms.txt +26 -0
  186. package/examples/README.md +63 -0
  187. package/examples/basic-state-machine.md +70 -0
  188. package/examples/form-validation.md +167 -0
  189. package/examples/multi-router-integration.md +277 -0
  190. package/examples/routing-patterns.md +260 -0
  191. package/examples/traffic-light.md +99 -0
  192. package/guides/README.md +29 -0
  193. package/guides/getting-started.md +223 -0
  194. package/guides/installation.md +323 -0
  195. package/index.d.ts +3 -0
  196. package/index.js +4 -0
  197. package/package.json +54 -0
@@ -0,0 +1,502 @@
1
+ [Documentation](../../README.md) / @xmachines/play-router
2
+
3
+ # @xmachines/play-router
4
+
5
+ **Route tree extraction from XState v5 state machines with routing patterns**
6
+
7
+ BFS graph crawling and bidirectional route lookup enabling Actor Authority over navigation.
8
+
9
+ ## Overview
10
+
11
+ `@xmachines/play-router` extracts route trees from XState state machines by crawling the state graph using breadth-first traversal. It extracts `meta.route` paths from state machines and builds hierarchical route trees with bidirectional state ID ↔ path mapping.
12
+
13
+ It also exports `RouterBridgeBase`, the shared base class used by framework adapters to implement `RouterBridge` with consistent actor↔router synchronization behavior.
14
+
15
+ `RouterBridgeBase` is the policy point; framework adapters are thin ports that implement only framework-specific navigate/subscribe/unsubscribe behavior.
16
+
17
+ Per [RFC Play v1](https://gitlab.com/xmachin-es/rfc/-/blob/main/src/play-v1.md), this package implements:
18
+
19
+ - **Actor Authority (INV-01):** Routes derive from machine definitions, not external configuration
20
+
21
+ **Routing:** Supports `meta.route` detection, `play.route` event routing, and pattern matching for dynamic parameters.
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install xstate@^5.0.0
27
+ npm install @xmachines/play-router
28
+ ```
29
+
30
+ **Peer dependencies:**
31
+
32
+ - `xstate` ^5.0.0 — State machine runtime
33
+
34
+ **URLPattern polyfill (Node.js < 24 / older browsers):**
35
+
36
+ `@xmachines/play-router` uses the [URLPattern API](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern) for dynamic route matching. URLPattern is available natively on Node.js 24+ and modern browsers (Chrome 95+, Firefox 117+, Safari 16.4+).
37
+
38
+ On environments without native support, load a polyfill **before** importing this package:
39
+
40
+ ```typescript
41
+ // Entry point — must run before any @xmachines/play-router import
42
+ import "urlpattern-polyfill";
43
+ ```
44
+
45
+ Install the polyfill:
46
+
47
+ ```bash
48
+ npm install urlpattern-polyfill
49
+ ```
50
+
51
+ `urlpattern-polyfill` is declared as an optional peer dependency. Package managers will not install it automatically — it is the consumer's responsibility to load it when needed.
52
+
53
+ ## Quick Start
54
+
55
+ ```typescript
56
+ import { createMachine } from "xstate";
57
+ import { extractMachineRoutes } from "@xmachines/play-router";
58
+
59
+ // Route pattern (recommended)
60
+ const machine = createMachine({
61
+ id: "app",
62
+ initial: "home",
63
+ states: {
64
+ home: {
65
+ id: "home",
66
+ meta: { route: "/", view: { component: "Home" } },
67
+ },
68
+ dashboard: {
69
+ id: "dashboard",
70
+ meta: { route: "/dashboard", view: { component: "Dashboard" } },
71
+ initial: "overview",
72
+ states: {
73
+ overview: {
74
+ id: "overview",
75
+ meta: { route: "/overview", view: { component: "Overview" } },
76
+ },
77
+ settings: {
78
+ id: "settings",
79
+ meta: { route: "/settings/:section?", view: { component: "Settings" } }, // Optional parameter
80
+ },
81
+ },
82
+ },
83
+ },
84
+ });
85
+
86
+ const tree = extractMachineRoutes(machine);
87
+
88
+ // Bidirectional lookup
89
+ console.log(tree.byPath.get("/dashboard/overview")); // RouteNode
90
+ console.log(tree.byId.get("overview")); // RouteNode
91
+
92
+ // Pattern matching for dynamic routes
93
+ const settingsRoute = tree.byPath.get("/settings/profile");
94
+ console.log(settingsRoute?.id); // "settings"
95
+ ```
96
+
97
+ ## Vanilla Browser Example
98
+
99
+ See `examples/vanilla-demo/` for a complete example using vanilla TypeScript with the browser History API.
100
+
101
+ The demo demonstrates:
102
+
103
+ - **RouteTree extraction** from XState machine meta.route
104
+ - **History API integration** (pushState, popstate)
105
+ - **Bidirectional synchronization** (actor ↔ URL)
106
+ - **Protected route guards** (authentication redirects)
107
+ - **Dynamic route parameters** (/profile/:userId)
108
+
109
+ **Run the demo:**
110
+
111
+ ```bash
112
+ cd packages/play-router/examples/demo
113
+ npm install
114
+ npm run dev
115
+ ```
116
+
117
+ Open http://localhost:5174/ and explore:
118
+
119
+ 1. Login with any username
120
+ 2. Navigate between home and profile
121
+ 3. Use browser back/forward buttons
122
+ 4. Try accessing protected routes directly
123
+
124
+ **Key implementation patterns:**
125
+
126
+ ```typescript
127
+ // Extract routes from machine
128
+ const routeTree = extractMachineRoutes(authMachine);
129
+ const routeMap = createRouteMap(routeTree);
130
+
131
+ // Actor → URL sync
132
+ const watcher = new Signal.subtle.Watcher(() => {
133
+ queueMicrotask(() => {
134
+ watcher.getPending();
135
+ const route = actor.currentRoute.get();
136
+ if (route) {
137
+ window.history.pushState({}, "", route);
138
+ }
139
+ watcher.watch(actor.currentRoute);
140
+ });
141
+ });
142
+
143
+ // URL → Actor sync (with pattern matching)
144
+ window.addEventListener("popstate", () => {
145
+ const path = window.location.pathname;
146
+ const { to, params } = routeMap.resolve(path);
147
+ if (to) {
148
+ actor.send({ type: "play.route", to, params });
149
+ }
150
+ });
151
+
152
+ // Initial URL handling
153
+ const initialPath = window.location.pathname;
154
+ if (initialPath !== "/") {
155
+ const { to, params } = routeMap.resolve(initialPath);
156
+ if (to) {
157
+ actor.send({ type: "play.route", to, params });
158
+ }
159
+ }
160
+ ```
161
+
162
+ This example shows the core routing concepts without framework dependencies, making it ideal for understanding how @xmachines/play-router integrates with browser History API.
163
+
164
+ ## Canonical Watcher Lifecycle
165
+
166
+ Bridge implementations should use one watcher flow:
167
+
168
+ 1. `notify`
169
+ 2. `queueMicrotask`
170
+ 3. `getPending()`
171
+ 4. read actor route and sync infrastructure state
172
+ 5. re-arm with `watch(...)` or `watch()`
173
+
174
+ Watcher notification is one-shot; re-arm is required.
175
+
176
+ ## Bridge Cleanup Contract
177
+
178
+ Bridge teardown must be explicit and deterministic:
179
+
180
+ - `disconnect`/`dispose` must unwatch signal subscriptions and unhook router listeners.
181
+ - Do not rely on GC-only cleanup guidance.
182
+ - Infrastructure remains passive: bridges observe and forward intents, actors decide validity.
183
+
184
+ ## API Reference
185
+
186
+ ### extractMachineRoutes()
187
+
188
+ Main entry point — crawls state machine, extracts routes, builds tree:
189
+
190
+ ```typescript
191
+ const tree = extractMachineRoutes(machine: AnyStateMachine): RouteTree;
192
+ ```
193
+
194
+ **Detection:**
195
+
196
+ - States with `meta.route` in meta object
197
+
198
+ **Returns:** `RouteTree` with:
199
+
200
+ - `routes: RouteNode[]` - Array of route nodes
201
+ - `byPath: Map<string, RouteNode>` - URL path → route node
202
+ - `byId: Map<string, RouteNode>` - State ID → route node
203
+
204
+ **Throws:** Error if routes are invalid (malformed paths, missing state IDs, duplicates)
205
+
206
+ **Example:**
207
+
208
+ ```typescript
209
+ import { extractMachineRoutes } from "@xmachines/play-router";
210
+
211
+ const tree = extractMachineRoutes(authMachine);
212
+
213
+ // Query routes
214
+ const loginRoute = tree.byId.get("login");
215
+ console.log(loginRoute?.path); // "/login"
216
+
217
+ const dashboardRoute = tree.byPath.get("/dashboard");
218
+ console.log(dashboardRoute?.id); // "dashboard"
219
+ ```
220
+
221
+ ### crawlMachine()
222
+
223
+ Low-level BFS traversal of state machine graph:
224
+
225
+ ```typescript
226
+ const visits = crawlMachine(machine: AnyStateMachine): StateVisit[];
227
+ ```
228
+
229
+ **Returns:** Array of state visits in breadth-first order with:
230
+
231
+ - `path: string[]` - State path (e.g., ["dashboard", "settings"])
232
+ - `parent: StateNode | null` - Parent state node
233
+ - `node: StateNode` - Current state node
234
+
235
+ **Example:**
236
+
237
+ ```typescript
238
+ import { crawlMachine } from "@xmachines/play-router";
239
+
240
+ const visits = crawlMachine(machine);
241
+ visits.forEach((visit) => {
242
+ console.log("State:", visit.path.join("."));
243
+ console.log("Parent:", visit.parent?.id ?? "root");
244
+ });
245
+ ```
246
+
247
+ ### Query Utilities
248
+
249
+ ```typescript
250
+ // Get child routes from state
251
+ const children = getNavigableRoutes(tree, "dashboard");
252
+
253
+ // Check if route exists
254
+ const exists = routeExists(tree, "/profile/:userId");
255
+ ```
256
+
257
+ ## Examples
258
+
259
+ ### Route Detection
260
+
261
+ ```typescript
262
+ import { extractMachineRoutes } from "@xmachines/play-router";
263
+ import { createMachine } from "xstate";
264
+
265
+ const machine = createMachine({
266
+ initial: "home",
267
+ states: {
268
+ home: {
269
+ id: "home",
270
+ meta: { route: "/", view: { component: "Home" } },
271
+ },
272
+ profile: {
273
+ id: "profile",
274
+ meta: { route: "/profile/:userId", view: { component: "Profile" } }, // Parameter pattern
275
+ },
276
+ settings: {
277
+ id: "settings",
278
+ meta: { route: "/settings/:section?", view: { component: "Settings" } }, // Optional parameter
279
+ },
280
+ },
281
+ });
282
+
283
+ const tree = extractMachineRoutes(machine);
284
+
285
+ // Bidirectional mapping
286
+ const profileById = tree.byId.get("profile");
287
+ console.log(profileById?.path); // "/profile/:userId"
288
+
289
+ const profileByPath = tree.byPath.get("/profile/user123");
290
+ console.log(profileByPath?.id); // "profile"
291
+ ```
292
+
293
+ ### Hierarchical Route Tree
294
+
295
+ ```typescript
296
+ import { extractMachineRoutes, getNavigableRoutes } from "@xmachines/play-router";
297
+
298
+ const machine = createMachine({
299
+ initial: "app",
300
+ states: {
301
+ app: {
302
+ id: "app",
303
+ meta: { route: "/", view: { component: "AppShell" } },
304
+ initial: "dashboard",
305
+ states: {
306
+ dashboard: {
307
+ id: "dashboard",
308
+ meta: { route: "/dashboard", view: { component: "Dashboard" } },
309
+ initial: "overview",
310
+ states: {
311
+ overview: {
312
+ id: "overview",
313
+ meta: { route: "/overview", view: { component: "Overview" } },
314
+ },
315
+ analytics: {
316
+ id: "analytics",
317
+ meta: { route: "/analytics", view: { component: "Analytics" } },
318
+ },
319
+ },
320
+ },
321
+ },
322
+ },
323
+ },
324
+ });
325
+
326
+ const tree = extractMachineRoutes(machine);
327
+
328
+ // Get child routes
329
+ const dashboardChildren = getNavigableRoutes(tree, "dashboard");
330
+ console.log(dashboardChildren.map((r) => r.id)); // ["overview", "analytics"]
331
+
332
+ // Route inheritance
333
+ const analyticsRoute = tree.byId.get("analytics");
334
+ console.log(analyticsRoute?.path); // "/dashboard/analytics" (inherited parent path)
335
+ ```
336
+
337
+ ### Pattern Matching
338
+
339
+ ```typescript
340
+ import { extractMachineRoutes } from "@xmachines/play-router";
341
+
342
+ const machine = createMachine({
343
+ states: {
344
+ user: {
345
+ id: "user",
346
+ meta: { route: "/user/:userId", view: { component: "User" } }, // Required parameter
347
+ },
348
+ settings: {
349
+ id: "settings",
350
+ meta: { route: "/settings/:section?", view: { component: "Settings" } }, // Optional parameter
351
+ },
352
+ },
353
+ });
354
+
355
+ const tree = extractMachineRoutes(machine);
356
+
357
+ // Pattern matching for actual URLs
358
+ const userRoute = tree.byPath.get("/user/user123");
359
+ console.log(userRoute?.id); // "user"
360
+
361
+ const settingsDefault = tree.byPath.get("/settings");
362
+ console.log(settingsDefault?.id); // "settings" (optional param)
363
+
364
+ const settingsProfile = tree.byPath.get("/settings/profile");
365
+ console.log(settingsProfile?.id); // "settings" (with param)
366
+ ```
367
+
368
+ ## Route Configuration
369
+
370
+ ### Route Pattern (Recommended)
371
+
372
+ ```typescript
373
+ states: {
374
+ dashboard: {
375
+ id: "dashboard", // Required for bidirectional lookup
376
+ meta: {
377
+ route: "/dashboard", // URL path - marks state as routable
378
+ },
379
+ },
380
+ }
381
+ ```
382
+
383
+ ### Alternative Pattern
384
+
385
+ ```typescript
386
+ states: {
387
+ dashboard: {
388
+ id: "dashboard",
389
+ meta: {
390
+ route: "/dashboard",
391
+ },
392
+ },
393
+ }
394
+ ```
395
+
396
+ ### Route Inheritance
397
+
398
+ ```typescript
399
+ states: {
400
+ parent: {
401
+ id: "parent",
402
+ meta: { route: "/parent", view: { component: "Parent" } },
403
+ states: {
404
+ absolute: {
405
+ id: "absolute",
406
+ meta: { route: "/absolute", view: { component: "Absolute" } }, // Starts with / → doesn't inherit
407
+ },
408
+ relative: {
409
+ id: "relative",
410
+ meta: { route: "relative", view: { component: "Relative" } }, // No leading / → inherits parent
411
+ // Final path: "/parent/relative"
412
+ },
413
+ },
414
+ },
415
+ }
416
+ ```
417
+
418
+ ### Dynamic Parameters
419
+
420
+ ```typescript
421
+ meta: {
422
+ route: "/profile/:userId", // Required parameter
423
+ route: "/settings/:section?", // Optional parameter
424
+ route: "/docs/:category/:page", // Multiple parameters
425
+ view: { component: "AnyView" },
426
+ }
427
+ ```
428
+
429
+ **Parameter substitution:** Values extracted from context or event params (handled by play-xstate adapter).
430
+
431
+ ## Architecture
432
+
433
+ This package enables **Actor Authority (INV-01)**:
434
+
435
+ 1. **Routes derive from machine:** Business logic defines routes in state machine, not external config
436
+ 2. **BFS traversal:** Systematic state discovery ensures all nested states visited
437
+ 3. **Bidirectional mapping:** Fast lookup by path (browser URL) or by ID (state machine)
438
+ 4. **Build-time validation:** Invalid routes throw errors during extraction, not runtime
439
+
440
+ **Enhancements:**
441
+
442
+ - `meta.route` detection via state metadata
443
+ - Pattern matching for dynamic routes (`:param` and `:param?`)
444
+ - State ID ↔ path bidirectional maps for `play.route` events
445
+
446
+ ## Related Packages
447
+
448
+ - **[@xmachines/play-xstate](../play-xstate/README.md)** - XState adapter using route extraction
449
+ - **[@xmachines/play-tanstack-react-router](../play-tanstack-react-router/README.md)** - TanStack Router adapter using route trees
450
+ - **[@xmachines/play-react-router](../play-react-router/README.md)** - React Router v7 adapter using RouterBridgeBase
451
+ - **[@xmachines/play](../play/README.md)** - Protocol types
452
+
453
+ ## License
454
+
455
+ Copyright (c) 2016 [Mikael Karon](mailto:mikael@karon.se). All rights reserved.
456
+
457
+ This work is licensed under the terms of the MIT license.
458
+ For a copy, see <https://opensource.org/licenses/MIT>.
459
+
460
+ ## Classes
461
+
462
+ - [BaseRouteMap](classes/BaseRouteMap.md)
463
+ - [RouterBridgeBase](classes/RouterBridgeBase.md)
464
+
465
+ ## Interfaces
466
+
467
+ - [BaseRouteMapping](interfaces/BaseRouteMapping.md)
468
+ - [BrowserHistory](interfaces/BrowserHistory.md)
469
+ - [BrowserWindow](interfaces/BrowserWindow.md)
470
+ - [ConnectRouterOptions](interfaces/ConnectRouterOptions.md)
471
+ - [PlayRouteEvent](interfaces/PlayRouteEvent.md)
472
+ - [RouteInfo](interfaces/RouteInfo.md)
473
+ - [RouteMap](interfaces/RouteMap.md)
474
+ - [RouteNode](interfaces/RouteNode.md)
475
+ - [RouteObject](interfaces/RouteObject.md)
476
+ - [RouterBridge](interfaces/RouterBridge.md)
477
+ - [RouteTree](interfaces/RouteTree.md)
478
+ - [StateVisit](interfaces/StateVisit.md)
479
+ - [VanillaRouter](interfaces/VanillaRouter.md)
480
+
481
+ ## Type Aliases
482
+
483
+ - [RouteMetadata](type-aliases/RouteMetadata.md)
484
+
485
+ ## Functions
486
+
487
+ - [buildRouteTree](functions/buildRouteTree.md)
488
+ - [connectRouter](functions/connectRouter.md)
489
+ - [crawlMachine](functions/crawlMachine.md)
490
+ - [createBrowserHistory](functions/createBrowserHistory.md)
491
+ - [createRouteMap](functions/createRouteMap.md)
492
+ - [createRouter](functions/createRouter.md)
493
+ - [detectDuplicateRoutes](functions/detectDuplicateRoutes.md)
494
+ - [extractMachineRoutes](functions/extractMachineRoutes.md)
495
+ - [extractRoute](functions/extractRoute.md)
496
+ - [findRouteById](functions/findRouteById.md)
497
+ - [findRouteByPath](functions/findRouteByPath.md)
498
+ - [getNavigableRoutes](functions/getNavigableRoutes.md)
499
+ - [getRoutableRoutes](functions/getRoutableRoutes.md)
500
+ - [routeExists](functions/routeExists.md)
501
+ - [validateRouteFormat](functions/validateRouteFormat.md)
502
+ - [validateStateExists](functions/validateStateExists.md)
@@ -0,0 +1,142 @@
1
+ [Documentation](../../../README.md) / [@xmachines/play-router](../README.md) / BaseRouteMap
2
+
3
+ # Class: BaseRouteMap
4
+
5
+ Defined in: [base-route-map.ts:70](https://gitlab.com/xmachin-es/xmachines-js/-/blob/00a28432ed57807112288436d1ae4387d9f06919/packages/play-router/src/base-route-map.ts#L70)
6
+
7
+ Shared bidirectional route map base class.
8
+
9
+ All framework adapter `RouteMap` classes extend this — they add no logic of their
10
+ own and inherit the full public API from here.
11
+
12
+ **Lookup strategy:**
13
+
14
+ - Static paths (no `:param`) → O(1) `Map` lookup
15
+ - Dynamic paths → O(k) bucket-indexed scan using `RegExp`, where `k` is the number
16
+ of routes sharing the same first path segment
17
+ - Results are cached after the first match
18
+
19
+ **Pattern syntax** (`:param` / `:param?`):
20
+
21
+ - `:param` — required segment, matches exactly one non-`/` segment
22
+ - `:param?` — optional segment, matches zero or one non-`/` segment
23
+
24
+ ## Example
25
+
26
+ ```typescript
27
+ import { BaseRouteMap } from "@xmachines/play-router";
28
+
29
+ const map = new BaseRouteMap([
30
+ { stateId: "home", path: "/" },
31
+ { stateId: "profile", path: "/profile/:userId" },
32
+ { stateId: "settings", path: "/settings/:section?" },
33
+ ]);
34
+
35
+ map.getStateIdByPath("/"); // "home"
36
+ map.getStateIdByPath("/profile/123"); // "profile"
37
+ map.getStateIdByPath("/settings"); // "settings"
38
+ map.getStateIdByPath("/unknown"); // null
39
+
40
+ map.getPathByStateId("profile"); // "/profile/:userId"
41
+ map.getPathByStateId("missing"); // null
42
+ ```
43
+
44
+ ## Extended by
45
+
46
+ - [`RouteMap`](../../play-react-router/classes/RouteMap.md)
47
+ - [`RouteMap`](../../play-solid-router/classes/RouteMap.md)
48
+ - [`RouteMap`](../../play-tanstack-react-router/classes/RouteMap.md)
49
+ - [`RouteMap`](../../play-tanstack-solid-router/classes/RouteMap.md)
50
+ - [`VueBaseRouteMap`](../../play-vue-router/classes/VueBaseRouteMap.md)
51
+
52
+ ## Constructors
53
+
54
+ ### Constructor
55
+
56
+ ```ts
57
+ new BaseRouteMap(mappings): BaseRouteMap;
58
+ ```
59
+
60
+ Defined in: [base-route-map.ts:86](https://gitlab.com/xmachin-es/xmachines-js/-/blob/00a28432ed57807112288436d1ae4387d9f06919/packages/play-router/src/base-route-map.ts#L86)
61
+
62
+ Build a route map from an array of state ID ↔ path mappings.
63
+
64
+ Static paths (no `:param`) are indexed in an O(1) `Map`.
65
+ Parameterized paths are compiled to `RegExp` and grouped into first-segment
66
+ buckets for efficient candidate selection.
67
+
68
+ #### Parameters
69
+
70
+ | Parameter | Type | Description |
71
+ | ---------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
72
+ | `mappings` | [`BaseRouteMapping`](../interfaces/BaseRouteMapping.md)[] | Array of `{ stateId, path }` entries. Order determines priority when multiple patterns could match the same path. |
73
+
74
+ #### Returns
75
+
76
+ `BaseRouteMap`
77
+
78
+ ## Methods
79
+
80
+ ### getPathByStateId()
81
+
82
+ ```ts
83
+ getPathByStateId(stateId): string | null;
84
+ ```
85
+
86
+ Defined in: [base-route-map.ts:164](https://gitlab.com/xmachin-es/xmachines-js/-/blob/00a28432ed57807112288436d1ae4387d9f06919/packages/play-router/src/base-route-map.ts#L164)
87
+
88
+ Look up the path pattern registered for a state ID.
89
+
90
+ #### Parameters
91
+
92
+ | Parameter | Type | Description |
93
+ | --------- | -------- | --------------------------------------------------------- |
94
+ | `stateId` | `string` | State machine state ID (e.g., `"profile"`, `"#settings"`) |
95
+
96
+ #### Returns
97
+
98
+ `string` \| `null`
99
+
100
+ The registered path pattern, or `null` if the state ID is unknown
101
+
102
+ #### Example
103
+
104
+ ```typescript
105
+ map.getPathByStateId("profile"); // "/profile/:userId"
106
+ map.getPathByStateId("missing"); // null
107
+ ```
108
+
109
+ ---
110
+
111
+ ### getStateIdByPath()
112
+
113
+ ```ts
114
+ getStateIdByPath(path): string | null;
115
+ ```
116
+
117
+ Defined in: [base-route-map.ts:130](https://gitlab.com/xmachin-es/xmachines-js/-/blob/00a28432ed57807112288436d1ae4387d9f06919/packages/play-router/src/base-route-map.ts#L130)
118
+
119
+ Resolve a URL path to its mapped state ID.
120
+
121
+ Strips query strings and hash fragments before matching. Tries an O(1) exact
122
+ lookup first, then falls back to bucket-indexed pattern matching. Results are
123
+ cached after the first pattern match.
124
+
125
+ #### Parameters
126
+
127
+ | Parameter | Type | Description |
128
+ | --------- | -------- | ------------------------------------------------------------------------------ |
129
+ | `path` | `string` | URL pathname, optionally including query/hash (e.g., `"/profile/123?ref=nav"`) |
130
+
131
+ #### Returns
132
+
133
+ `string` \| `null`
134
+
135
+ The mapped state ID, or `null` if no route matches
136
+
137
+ #### Example
138
+
139
+ ```typescript
140
+ map.getStateIdByPath("/profile/123"); // "profile"
141
+ map.getStateIdByPath("/unknown"); // null
142
+ ```