@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,604 @@
1
+ [Documentation](../../README.md) / @xmachines/play-vue-router
2
+
3
+ # @xmachines/play-vue-router
4
+
5
+ **Vue Router 4.x adapter for XMachines Universal Player Architecture**
6
+
7
+ Bidirectional sync between Vue Router and XMachines state machines with Composition API integration.
8
+
9
+ ## Overview
10
+
11
+ `@xmachines/play-vue-router` enables Vue.js applications to use XMachines state machines as the source of truth for routing logic. Your state machine controls navigation through Vue Router's reactive primitives.
12
+
13
+ Per [RFC Play v1](https://gitlab.com/xmachin-es/rfc/-/blob/main/src/play-v1.md), this package implements:
14
+
15
+ - **Actor Authority (INV-01):** State machine validates navigation, router reflects decisions
16
+ - **Passive Infrastructure (INV-04):** Router observes `actor.currentRoute` signal
17
+ - **Signal-Only Reactivity (INV-05):** Watcher synchronizes URL with actor state
18
+
19
+ **Key Benefits:**
20
+
21
+ - **Logic-driven navigation:** Business logic in state machines, not components
22
+ - **Protected routes:** Guards live in state machine, not router config
23
+ - **Bidirectional sync:** Actor ↔ Vue Router with circular update prevention
24
+ - **Type-safe parameters:** Route params flow through state machine context
25
+ - **Composition API:** Integrates with `useRouter`, `useRoute`, `onUnmounted`
26
+
27
+ **Framework Compatibility:**
28
+
29
+ - Vue 3.x with Composition API
30
+ - Vue Router 4.x (`^4.0.0`)
31
+ - Named routes pattern (recommended by Vue Router docs)
32
+
33
+ ## Installation
34
+
35
+ ```bash
36
+ npm install vue-router@^4.0.0 vue@^3.5.0 @xmachines/play-vue-router @xmachines/play-vue
37
+ ```
38
+
39
+ **Peer dependencies:**
40
+
41
+ - `vue-router` ^4.0.0 || ^5.0.0 — Vue Router library
42
+ - `vue` ^3.5.0 — Vue runtime
43
+ - `@xmachines/play-vue` — Vue renderer (`PlayRenderer`)
44
+ - `@xmachines/play-actor` — Actor base
45
+ - `@xmachines/play-router` — Route extraction
46
+ - `@xmachines/play-signals` — TC39 Signals primitives
47
+
48
+ ## Quick Start
49
+
50
+ ```typescript
51
+ import { createApp } from "vue";
52
+ import { createRouter, createWebHistory } from "vue-router";
53
+ import { VueRouterBridge, createRouteMap } from "@xmachines/play-vue-router";
54
+ import { extractMachineRoutes, getRoutableRoutes } from "@xmachines/play-router";
55
+ import { definePlayer } from "@xmachines/play-xstate";
56
+ import Home from "./views/Home.vue";
57
+ import Profile from "./views/Profile.vue";
58
+
59
+ // 1. Extract routable states from machine (single source of truth)
60
+ const routeTree = extractMachineRoutes(authMachine);
61
+ const routableRoutes = getRoutableRoutes(routeTree);
62
+ const routeComponents = {
63
+ home: Home,
64
+ profile: Profile,
65
+ } as const;
66
+
67
+ // 2. Define Vue Router routes from extracted machine routes
68
+ const router = createRouter({
69
+ history: createWebHistory(),
70
+ routes: routableRoutes.map((route) => ({
71
+ path: route.fullPath,
72
+ name: route.stateId.replace(/^#/, ""),
73
+ component: routeComponents[route.stateId.replace(/^#/, "") as keyof typeof routeComponents],
74
+ })),
75
+ });
76
+
77
+ // 3. Compute route mapping from machine routes
78
+ const routeMap = createRouteMap(authMachine);
79
+
80
+ // 4. Create actor with state machine
81
+ const createPlayer = definePlayer({
82
+ machine: authMachine,
83
+ catalog: componentCatalog,
84
+ });
85
+ const actor = createPlayer();
86
+ actor.start();
87
+
88
+ // 5. Create bridge to sync actor and router
89
+ const bridge = new VueRouterBridge(router, actor, routeMap);
90
+
91
+ // 6. Connect bridge (required)
92
+ bridge.connect();
93
+
94
+ // 7. Create Vue app
95
+ const app = createApp(App);
96
+ app.use(router);
97
+ app.mount("#app");
98
+
99
+ // 8. Later, when tearing down your app/integration:
100
+ // bridge.disconnect();
101
+ ```
102
+
103
+ ## API Reference
104
+
105
+ ### `VueRouterBridge`
106
+
107
+ Router adapter implementing the `RouterBridge` protocol for Vue Router 4.x.
108
+
109
+ **Type Signature:**
110
+
111
+ ```typescript
112
+ class VueRouterBridge {
113
+ constructor(router: Router, actor: AbstractActor<any>, routeMap: RouteMap);
114
+ connect(): void;
115
+ disconnect(): void;
116
+ dispose(): void;
117
+ }
118
+ ```
119
+
120
+ **Constructor Parameters:**
121
+
122
+ - `router` - Vue Router instance from `createRouter()`
123
+ - `actor` - XMachines actor instance (from `definePlayer().actor`)
124
+ - `routeMap` - Bidirectional state ID ↔ route name mapping
125
+
126
+ **Methods:**
127
+
128
+ - `connect()` - Start bidirectional synchronization.
129
+ - `disconnect()` - Stop synchronization and unhook listeners.
130
+ - `dispose()` - Alias of `disconnect()` for ergonomic teardown.
131
+
132
+ **Internal Behavior:**
133
+
134
+ - Watches `actor.currentRoute` signal via `Signal.subtle.Watcher`
135
+ - Updates Vue Router via `router.push({ name, params })` when actor state changes
136
+ - Listens to router navigation via `router.afterEach()` hook
137
+ - Sends `play.route` events to actor when user navigates
138
+ - Prevents circular updates with multi-layer guards
139
+
140
+ ### `RouteMap`
141
+
142
+ Bidirectional mapping between XMachines state IDs and Vue Router route names.
143
+
144
+ **Type Signature:**
145
+
146
+ ```typescript
147
+ interface RouteMapping {
148
+ stateId: string;
149
+ routeName: string;
150
+ pattern?: string;
151
+ }
152
+
153
+ class RouteMap extends VueBaseRouteMap {
154
+ // Inherits all VueBaseRouteMap methods — no additional API
155
+ }
156
+ ```
157
+
158
+ **Constructor Parameters:**
159
+
160
+ - `mappings` - Array of mapping objects with:
161
+ - `stateId` - State machine state ID (e.g., `'#profile'`)
162
+ - `routeName` - Vue Router route name (e.g., `'profile'`)
163
+ - `pattern` - Optional path pattern for URL resolution (e.g., `'/profile/:userId'`)
164
+
165
+ **Methods (inherited from `VueBaseRouteMap`):**
166
+
167
+ - `getRouteName(stateId)` — Find route name from state ID
168
+ - `getStateId(routeName)` — Find state ID from route name
169
+ - `getPattern(stateId)` — Get URL pattern for state (optional metadata)
170
+ - `getStateIdByPath(path)` — Resolve a URL path to a state ID (from `BaseRouteMap`)
171
+ - `getPathByStateId(stateId)` — Get the URL path pattern for a state ID (from `BaseRouteMap`)
172
+
173
+ ### `VueBaseRouteMap`
174
+
175
+ Intermediate base class for Vue Router adapters. Extends `BaseRouteMap` (bucket-indexed O(k) pattern matching + QuickLRU cache) and adds Vue-specific named-route lookup.
176
+
177
+ Exported for consumers who need to extend or test the Vue routing layer directly. Most consumers use `RouteMap` instead.
178
+
179
+ ```typescript
180
+ class VueBaseRouteMap extends BaseRouteMap {
181
+ constructor(mappings: RouteMapping[]);
182
+ getRouteName(stateId: string): string | undefined;
183
+ getStateId(routeName: string): string | undefined;
184
+ getPattern(stateId: string): string | undefined;
185
+ }
186
+ ```
187
+
188
+ ## Examples
189
+
190
+ ### Basic Usage: Simple 2-3 Route Setup
191
+
192
+ ```typescript
193
+ // State machine with 3 states
194
+ import { defineCatalog } from "@xmachines/play-catalog";
195
+
196
+ const appMachine = setup({
197
+ types: {
198
+ events: {} as PlayRouteEvent,
199
+ },
200
+ }).createMachine({
201
+ id: "app",
202
+ initial: "home",
203
+ states: {
204
+ home: {
205
+ meta: { route: "/", view: { component: "Home" } },
206
+ },
207
+ about: {
208
+ meta: { route: "/about", view: { component: "About" } },
209
+ },
210
+ contact: {
211
+ meta: { route: "/contact", view: { component: "Contact" } },
212
+ },
213
+ },
214
+ });
215
+
216
+ const componentCatalog = defineCatalog({
217
+ Home,
218
+ About,
219
+ Contact,
220
+ });
221
+
222
+ const player = definePlayer({ machine: appMachine, catalog: componentCatalog });
223
+
224
+ // Vue Router configuration
225
+ const routeTree = extractMachineRoutes(appMachine);
226
+ const routableRoutes = getRoutableRoutes(routeTree);
227
+ const routeComponents = {
228
+ home: Home,
229
+ about: About,
230
+ contact: Contact,
231
+ } as const;
232
+
233
+ const router = createRouter({
234
+ history: createWebHistory(),
235
+ routes: routableRoutes.map((route) => ({
236
+ path: route.fullPath,
237
+ name: route.stateId.replace(/^#/, ""),
238
+ component: routeComponents[route.stateId.replace(/^#/, "") as keyof typeof routeComponents],
239
+ })),
240
+ });
241
+
242
+ // Route mapping computed from machine routes
243
+ const routeMap = createRouteMap(appMachine);
244
+ ```
245
+
246
+ ### Parameter Handling: Dynamic Routes with `:param` Syntax
247
+
248
+ ```typescript
249
+ // State machine with parameter routes
250
+ import { formatPlayRouteTransitions } from "@xmachines/play-xstate";
251
+ import { defineCatalog } from "@xmachines/play-catalog";
252
+
253
+ const machineConfig = {
254
+ id: "app",
255
+ context: {},
256
+ states: {
257
+ profile: {
258
+ meta: {
259
+ route: "/profile/:userId",
260
+ view: { component: "Profile" },
261
+ },
262
+ },
263
+ settings: {
264
+ meta: {
265
+ route: "/settings/:section?",
266
+ view: { component: "Settings" },
267
+ },
268
+ },
269
+ },
270
+ };
271
+
272
+ const appMachine = setup({
273
+ types: {
274
+ context: {} as { userId?: string; section?: string },
275
+ events: {} as PlayRouteEvent,
276
+ },
277
+ }).createMachine(formatPlayRouteTransitions(machineConfig));
278
+
279
+ const componentCatalog = defineCatalog({
280
+ Profile,
281
+ Settings,
282
+ });
283
+
284
+ const player = definePlayer({ machine: appMachine, catalog: componentCatalog });
285
+
286
+ // Router with dynamic routes
287
+ const routeTree = extractMachineRoutes(appMachine);
288
+ const routableRoutes = getRoutableRoutes(routeTree);
289
+ const routeComponents = {
290
+ profile: Profile,
291
+ settings: Settings,
292
+ } as const;
293
+
294
+ const router = createRouter({
295
+ routes: routableRoutes.map((route) => ({
296
+ path: route.fullPath,
297
+ name: route.stateId.replace(/^#/, ""),
298
+ component: routeComponents[route.stateId.replace(/^#/, "") as keyof typeof routeComponents],
299
+ })),
300
+ });
301
+
302
+ // Route mapping computed from machine routes
303
+ const routeMap = createRouteMap(appMachine);
304
+ ```
305
+
306
+ **Usage in component:**
307
+
308
+ ```vue
309
+ <script setup>
310
+ import { inject } from "vue";
311
+
312
+ const actor = inject("actor");
313
+
314
+ function viewProfile(userId) {
315
+ actor.send({ type: "play.route", to: "#profile", params: { userId } });
316
+ }
317
+ </script>
318
+
319
+ <template>
320
+ <button @click="viewProfile('123')">View Profile</button>
321
+ </template>
322
+ ```
323
+
324
+ ### Query Parameters: Search/Filters via Query Strings
325
+
326
+ ```typescript
327
+ // State machine with query param handling
328
+ import { formatPlayRouteTransitions } from "@xmachines/play-xstate";
329
+ import { defineCatalog } from "@xmachines/play-catalog";
330
+
331
+ const machineConfig = {
332
+ context: { query: "", filters: {} },
333
+ states: {
334
+ search: {
335
+ meta: {
336
+ route: "/search",
337
+ view: { component: "Search" },
338
+ },
339
+ },
340
+ },
341
+ };
342
+
343
+ const searchMachine = setup({
344
+ types: {
345
+ context: {} as { query: string; filters: Record<string, string> },
346
+ events: {} as PlayRouteEvent,
347
+ },
348
+ }).createMachine(formatPlayRouteTransitions(machineConfig));
349
+
350
+ const componentCatalog = defineCatalog({
351
+ Search,
352
+ });
353
+
354
+ const player = definePlayer({ machine: searchMachine, catalog: componentCatalog });
355
+
356
+ // Component sends query params
357
+ function handleSearch(searchTerm, filters) {
358
+ actor.send({
359
+ type: "play.route",
360
+ to: "#search",
361
+ query: { q: searchTerm, ...filters },
362
+ });
363
+ }
364
+ ```
365
+
366
+ **Vue Router automatically reflects query params in URL:**
367
+
368
+ - `/search?q=xmachines&tag=typescript`
369
+
370
+ ### Protected Routes: Authentication Guards
371
+
372
+ ```typescript
373
+ // State machine with auth guards
374
+ import { defineCatalog } from "@xmachines/play-catalog";
375
+
376
+ const authMachine = setup({
377
+ types: {
378
+ context: {} as { isAuthenticated: boolean },
379
+ events: {} as PlayRouteEvent | { type: "login" } | { type: "logout" },
380
+ },
381
+ }).createMachine({
382
+ context: { isAuthenticated: false },
383
+ initial: "home",
384
+ states: {
385
+ home: {
386
+ meta: { route: "/", view: { component: "Home" } },
387
+ },
388
+ login: {
389
+ meta: { route: "/login", view: { component: "Login" } },
390
+ on: {
391
+ login: {
392
+ target: "dashboard",
393
+ actions: assign({ isAuthenticated: true }),
394
+ },
395
+ },
396
+ },
397
+ dashboard: {
398
+ meta: { route: "/dashboard", view: { component: "Dashboard" } },
399
+ always: {
400
+ guard: ({ context }) => !context.isAuthenticated,
401
+ target: "login",
402
+ },
403
+ },
404
+ },
405
+ });
406
+
407
+ const componentCatalog = defineCatalog({
408
+ Home,
409
+ Login,
410
+ Dashboard,
411
+ });
412
+
413
+ const player = definePlayer({ machine: authMachine, catalog: componentCatalog });
414
+ ```
415
+
416
+ **Guard behavior:**
417
+
418
+ - User navigates to `/dashboard`
419
+ - Bridge sends `play.route` event to actor
420
+ - Actor's `always` guard checks `isAuthenticated`
421
+ - If `false`, actor transitions to `login` state
422
+ - Bridge detects state change, redirects router to `/login`
423
+ - Actor Authority principle enforced
424
+
425
+ ### Cleanup: Proper Disposal on Component Unmount
426
+
427
+ ```vue
428
+ <script setup>
429
+ import { onUnmounted } from "vue";
430
+ import { VueRouterBridge } from "@xmachines/play-vue-router";
431
+
432
+ const router = useRouter();
433
+ const actor = inject("actor");
434
+ const routeMap = inject("routeMap");
435
+
436
+ const bridge = new VueRouterBridge(router, actor, routeMap);
437
+
438
+ // CRITICAL: Cleanup watchers and guards
439
+ onUnmounted(() => {
440
+ bridge.dispose();
441
+ });
442
+ </script>
443
+ ```
444
+
445
+ **Why cleanup matters:**
446
+
447
+ - Navigation guards remain active after unmount (memory leak)
448
+ - Watchers continue observing signals (event listeners pile up)
449
+ - Multiple bridge instances send duplicate events
450
+ - Tests fail with "Cannot send to stopped actor" errors
451
+
452
+ ## Architecture
453
+
454
+ ### Bidirectional Sync (Actor ↔ Router)
455
+
456
+ **Actor → Router (Signal-driven):**
457
+
458
+ 1. Actor transitions to new state with `meta.route`
459
+ 2. `actor.currentRoute` signal updates
460
+ 3. `Signal.subtle.Watcher` detects change in microtask
461
+ 4. Bridge extracts state ID from signal
462
+ 5. Bridge looks up route name via `routeMap.getRouteName()`
463
+ 6. Bridge calls `router.push({ name, params })`
464
+ 7. Vue Router updates URL and renders component
465
+
466
+ **Router → Actor (Navigation guard):**
467
+
468
+ 1. User clicks link or browser back button
469
+ 2. `router.afterEach()` hook fires with `to` route
470
+ 3. Bridge resolves state ID from Vue route `name` via `routeMap.getStateId(...)`
471
+ 4. Bridge extracts params from `to.params` (not `route.params` - see Pitfalls)
472
+ 5. Bridge sends `play.route` event to actor
473
+ 6. Actor validates navigation (guards, transitions)
474
+ 7. If accepted: Actor transitions, signal updates, URL stays
475
+ 8. If rejected: Actor redirects, bridge corrects URL via `router.replace()`
476
+
477
+ ### Circular Update Prevention
478
+
479
+ **Multi-layer guards prevent infinite loops:**
480
+
481
+ 1. **`lastSyncedPath` tracking:** Stores last synchronized path, skips if unchanged
482
+ 2. **`isProcessingNavigation` flag:** Set during router-initiated navigation, prevents actor→router sync
483
+ 3. **Microtask timing:** Actor validation happens asynchronously, bridge checks result after transition completes
484
+
485
+ **Pattern proven in the TanStack Router adapter:**
486
+
487
+ ```typescript
488
+ private syncRouterFromActor(): void {
489
+ if (this.isProcessingNavigation) return; // Guard 1
490
+ const currentRoute = this.actor.currentRoute.get();
491
+ if (currentRoute === this.lastSyncedPath) return; // Guard 2
492
+ this.lastSyncedPath = currentRoute;
493
+ this.router.push(currentRoute);
494
+ }
495
+
496
+ private syncActorFromRouter(to: RouteLocation): void {
497
+ this.isProcessingNavigation = true; // Guard 3
498
+ this.actor.send({ type: 'play.route', to: stateId, params });
499
+ queueMicrotask(() => {
500
+ this.isProcessingNavigation = false; // Guard 4
501
+ });
502
+ }
503
+ ```
504
+
505
+ ### Relationship to Other Packages
506
+
507
+ **Package Dependencies:**
508
+
509
+ - `@xmachines/play` - Protocol interfaces (`PlayRouteEvent`, `RouterBridge`)
510
+ - `@xmachines/play-actor` - Actor base class with signal protocol
511
+ - `@xmachines/play-router` - Route extraction and tree building
512
+ - `@xmachines/play-signals` - TC39 Signals polyfill for reactivity
513
+ - `@xmachines/play-xstate` - XState integration via `definePlayer()`
514
+
515
+ **Architecture Layers:**
516
+
517
+ ```
518
+ ┌─────────────────────────────────────┐
519
+ │ Vue Components (View Layer) │
520
+ │ - Uses inject('actor') │
521
+ │ - Sends play.route events │
522
+ └─────────────────────────────────────┘
523
+
524
+ ┌─────────────────────────────────────┐
525
+ │ VueRouterBridge (Adapter) │
526
+ │ - Watches actor.currentRoute │
527
+ │ - Listens to router.afterEach │
528
+ └─────────────────────────────────────┘
529
+ ↕ ↕
530
+ ┌─────────────┐ ┌──────────────────┐
531
+ │ Vue Router │ │ XMachines Actor │
532
+ │ (Infra) │ │ (Business Logic) │
533
+ └─────────────┘ └──────────────────┘
534
+ ```
535
+
536
+ ### Vue Router Composition API Integration
537
+
538
+ **Recommended patterns:**
539
+
540
+ - **`useRouter()`** - Get router instance for programmatic navigation (avoid in components - use actor)
541
+ - **`useRoute()`** - Access current route params (prefer actor context for state-driven components)
542
+ - **`onUnmounted()`** - Cleanup bridge to prevent leaks
543
+
544
+ **Named routes requirement:**
545
+
546
+ Vue Router adapter uses **named routes** (`router.push({ name: 'profile', params })`) instead of path-based navigation. This provides:
547
+
548
+ - Type safety (TypeScript route names)
549
+ - Cleaner param handling (object-based)
550
+ - Better Vue Router integration (recommended by docs)
551
+
552
+ All routes in your Vue Router config **must have a `name` property** for the bridge to work.
553
+
554
+ ### Pitfall: `to.params` vs `route.params`
555
+
556
+ **⚠️ Common mistake:** Using global `useRoute()` in navigation guards
557
+
558
+ ```typescript
559
+ // ❌ WRONG: route.params is stale during transition
560
+ router.afterEach((to) => {
561
+ const route = useRoute(); // Returns "from" route
562
+ const params = route.params; // STALE
563
+ // ...
564
+ });
565
+
566
+ // ✅ CORRECT: to.params is fresh
567
+ router.afterEach((to) => {
568
+ const params = to.params; // FRESH
569
+ // ...
570
+ });
571
+ ```
572
+
573
+ **Why it happens:** Vue Router's global `route` object updates asynchronously during navigation. The `to` parameter in `afterEach` is the destination route with correct params.
574
+
575
+ ## License
576
+
577
+ Copyright (c) 2016 [Mikael Karon](mailto:mikael@karon.se). All rights reserved.
578
+
579
+ This work is licensed under the terms of the MIT license.
580
+ For a copy, see <https://opensource.org/licenses/MIT>.
581
+
582
+ ## Classes
583
+
584
+ - [RouteMap](classes/RouteMap.md)
585
+ - [VueBaseRouteMap](classes/VueBaseRouteMap.md)
586
+ - [VueRouterBridge](classes/VueRouterBridge.md)
587
+
588
+ ## Interfaces
589
+
590
+ - [PlayRouteEvent](interfaces/PlayRouteEvent.md)
591
+ - [RouteMapping](interfaces/RouteMapping.md)
592
+ - [RouterBridge](interfaces/RouterBridge.md)
593
+
594
+ ## Type Aliases
595
+
596
+ - [RoutableActor](type-aliases/RoutableActor.md)
597
+
598
+ ## Variables
599
+
600
+ - [PlayRouterProvider](variables/PlayRouterProvider.md)
601
+
602
+ ## Functions
603
+
604
+ - [createRouteMap](functions/createRouteMap.md)