@xmachines/play-tanstack-solid-router 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,428 @@
1
+ # @xmachines/play-tanstack-solid-router
2
+
3
+ **TanStack Solid Router adapter for XMachines Universal Player Architecture**
4
+
5
+ Signals-native integration with TanStack Solid Router enabling logic-driven navigation through Solid.js reactivity.
6
+
7
+ ## Overview
8
+
9
+ `@xmachines/play-tanstack-solid-router` provides seamless integration between TanStack Solid Router and XMachines state machines. Built on Solid's reactive primitives (`createEffect`), it implements the RouterBridge protocol for bidirectional synchronization.
10
+
11
+ Per [RFC Play v1](https://gitlab.com/xmachin-es/rfc/-/blob/main/src/play-v1.md), this package implements:
12
+
13
+ - **Actor Authority (INV-01):** State machine controls navigation, router reflects decisions
14
+ - **Passive Infrastructure (INV-04):** Router observes `actor.currentRoute` signal
15
+ - **Signal-Only Reactivity (INV-05):** `createEffect` synchronizes URL with actor state
16
+
17
+ **Key Benefits:**
18
+
19
+ - **Signals-native:** Zero adaptation layer between Solid signals and TC39 Signals
20
+ - **RouterBridge pattern:** ~220 lines, 2 flags (consistent with Vue/Solid Router adapters)
21
+ - **Automatic tracking:** `createEffect` handles dependency tracking (no manual Watcher)
22
+ - **Logic-driven navigation:** Business logic in state machines, not components
23
+ - **Type-safe parameters:** Route params flow through state machine context
24
+
25
+ **Framework Compatibility:**
26
+
27
+ - TanStack Solid Router 1.0.0+
28
+ - SolidJS 1.8.0+
29
+ - TC39 Signals polyfill integration
30
+
31
+ ## Installation
32
+
33
+ ```bash
34
+ npm install @tanstack/solid-router@^1.0.0 solid-js@^1.8.0 @xmachines/play-tanstack-solid-router @xmachines/play-solid
35
+ ```
36
+
37
+ **Peer dependencies:**
38
+
39
+ - `@tanstack/solid-router` ^1.0.0 - TanStack Solid Router library
40
+ - `solid-js` ^1.8.0 - SolidJS runtime
41
+ - `@xmachines/play-solid` - Solid renderer (`PlayRenderer`)
42
+ - `@xmachines/play-actor` - Actor base
43
+ - `@xmachines/play-router` - Route extraction
44
+ - `@xmachines/play-signals` - TC39 Signals polyfill
45
+
46
+ ## Quick Start
47
+
48
+ ```typescript
49
+ import { createRouter } from '@tanstack/solid-router';
50
+ import { onCleanup } from 'solid-js';
51
+ import { PlayRenderer } from '@xmachines/play-solid';
52
+ import { definePlayer } from '@xmachines/play-xstate';
53
+ import { extractMachineRoutes } from '@xmachines/play-router';
54
+ import { SolidRouterBridge, createRouteMapFromTree } from '@xmachines/play-tanstack-solid-router';
55
+
56
+ function App() {
57
+ // 1. Create actor
58
+ const actor = definePlayer({ machine, catalog })();
59
+
60
+ // 2. Create router
61
+ const router = createRouter({
62
+ routes: /* ... TanStack route config ... */
63
+ });
64
+
65
+ // 3. Extract routes from machine and create RouteMap
66
+ const routeTree = extractMachineRoutes(machine);
67
+ const routeMap = createRouteMapFromTree(routeTree);
68
+
69
+ // 4. Create and connect bridge (inside component with Solid ownership context)
70
+ const bridge = new SolidRouterBridge(router, actor, routeMap);
71
+ bridge.connect();
72
+
73
+ onCleanup(() => bridge.disconnect());
74
+
75
+ return (
76
+ <Router>
77
+ <PlayRenderer actor={actor} components={components} />
78
+ </Router>
79
+ );
80
+ }
81
+ ```
82
+
83
+ **Important:** The bridge must be created inside a component where Solid hooks (`createEffect`, `onCleanup`) are available. TanStack Solid Router requires Solid's ownership context for reactivity to work correctly.
84
+
85
+ ## API Reference
86
+
87
+ ### `SolidRouterBridge`
88
+
89
+ Router adapter implementing the `RouterBridge` protocol for TanStack Solid Router.
90
+
91
+ **Constructor:**
92
+
93
+ ```typescript
94
+ new SolidRouterBridge(
95
+ router: Router,
96
+ actor: AbstractActor<any>,
97
+ routeMap: RouteMap
98
+ )
99
+ ```
100
+
101
+ **Parameters:**
102
+
103
+ - `router`: TanStack Solid Router instance (from `createRouter()`)
104
+ - `actor`: XMachines player actor implementing signal protocol
105
+ - `routeMap`: Bidirectional state ID ↔ path mapping
106
+
107
+ **Methods:**
108
+
109
+ - `connect(): void` - Start bidirectional synchronization (actor ↔ router)
110
+ - `disconnect(): void` - Stop synchronization and cleanup subscriptions
111
+
112
+ **Important:** Must be created inside component where Solid hooks (`createEffect`, `onCleanup`) are available. Creating outside ownership context will cause reactivity to fail.
113
+
114
+ ### `RouteMap`
115
+
116
+ Bidirectional mapping between XMachines state IDs and URL paths with pattern matching support.
117
+
118
+ **Constructor:**
119
+
120
+ ```typescript
121
+ new RouteMap(routes: RouteMapping[])
122
+ ```
123
+
124
+ **Interface:**
125
+
126
+ ```typescript
127
+ interface RouteMapping {
128
+ stateId: string; // XMachines state ID (e.g., '#home', '#profile')
129
+ path: string; // URL path pattern (e.g., '/', '/profile/:userId')
130
+ }
131
+ ```
132
+
133
+ **Methods:**
134
+
135
+ - `getStateIdByPath(path: string): string | null` - Lookup state ID by path (with URLPattern matching)
136
+ - `getPathByStateId(stateId: string): string | null` - Lookup path by state ID
137
+
138
+ ### `createRouteMapFromTree()`
139
+
140
+ Helper to create RouteMap from RouteTree extracted from state machine.
141
+
142
+ **Signature:**
143
+
144
+ ```typescript
145
+ function createRouteMapFromTree(routeTree: RouteTree): RouteMap;
146
+ ```
147
+
148
+ **Usage:**
149
+
150
+ ```typescript
151
+ import { extractMachineRoutes } from "@xmachines/play-router";
152
+ import { createRouteMapFromTree } from "@xmachines/play-tanstack-solid-router";
153
+
154
+ const routeTree = extractMachineRoutes(machine);
155
+ const routeMap = createRouteMapFromTree(routeTree);
156
+ ```
157
+
158
+ This helper traverses the route tree and creates RouteMapping entries for all routable states.
159
+
160
+ ## Usage Patterns
161
+
162
+ ### Creating RouteMap from Machine
163
+
164
+ **Recommended:** Extract routes from state machine automatically:
165
+
166
+ ```typescript
167
+ import { extractMachineRoutes } from "@xmachines/play-router";
168
+ import { createRouteMapFromTree } from "@xmachines/play-tanstack-solid-router";
169
+
170
+ const routeTree = extractMachineRoutes(machine);
171
+ const routeMap = createRouteMapFromTree(routeTree);
172
+ ```
173
+
174
+ **Manual:** Define routes explicitly:
175
+
176
+ ```typescript
177
+ const routeMap = new RouteMap([
178
+ { stateId: "#home", path: "/" },
179
+ { stateId: "#profile", path: "/profile/:userId" },
180
+ ]);
181
+ ```
182
+
183
+ ### Dynamic Routes with Parameters
184
+
185
+ **Path parameters:**
186
+
187
+ ```typescript
188
+ const routeMap = new RouteMap([
189
+ { stateId: "#home", path: "/" },
190
+ { stateId: "#settings", path: "/settings/:section?" }, // Optional param
191
+ { stateId: "#profile", path: "/profile/:userId" }, // Required param
192
+ ]);
193
+ ```
194
+
195
+ **Pattern matching examples:**
196
+
197
+ ```typescript
198
+ routeMap.getStateIdByPath("/profile/123"); // → '#profile'
199
+ routeMap.getStateIdByPath("/settings"); // → '#settings'
200
+ routeMap.getStateIdByPath("/settings/privacy"); // → '#settings'
201
+ ```
202
+
203
+ ### Cleanup on Component Unmount
204
+
205
+ **Always cleanup when component unmounts:**
206
+
207
+ ```typescript
208
+ function MyApp() {
209
+ const bridge = new SolidRouterBridge(router, actor, routeMap);
210
+ bridge.connect();
211
+
212
+ onCleanup(() => {
213
+ bridge.disconnect(); // Stop synchronization
214
+ actor.stop(); // Stop actor if needed
215
+ });
216
+
217
+ return <Router>...</Router>;
218
+ }
219
+ ```
220
+
221
+ ## Circular Update Prevention
222
+
223
+ SolidRouterBridge uses a **2-flag pattern** to prevent infinite loops:
224
+
225
+ 1. **lastSyncedPath** - Skips redundant updates when path unchanged
226
+ 2. **isProcessingNavigation** - Prevents actor → router → actor loops
227
+
228
+ **How it works:**
229
+
230
+ ```typescript
231
+ // Actor state change → Router navigation
232
+ private syncRouterFromActor(route: string | null): void {
233
+ if (this.isProcessingNavigation) return; // Skip if processing router event
234
+ if (route === this.lastSyncedPath) return; // Skip if path unchanged
235
+
236
+ this.lastSyncedPath = route || '/';
237
+ this.router.navigate({ to: this.lastSyncedPath });
238
+ }
239
+
240
+ // Router navigation → Actor event
241
+ private syncActorFromRouter(location: RouterLocation): void {
242
+ this.isProcessingNavigation = true; // Set flag
243
+
244
+ // Send event to actor...
245
+
246
+ queueMicrotask(() => {
247
+ this.isProcessingNavigation = false; // Clear flag in microtask
248
+ });
249
+ }
250
+ ```
251
+
252
+ **Microtask timing:** The `isProcessingNavigation` flag is cleared in a microtask (via `queueMicrotask()`) to ensure the actor has processed the event before allowing router-initiated syncs again.
253
+
254
+ ## Comparison with @solidjs/router Adapter
255
+
256
+ | Aspect | @solidjs/router | @tanstack/solid-router |
257
+ | -------------- | ----------------- | ---------------------------- |
258
+ | **Router API** | router.push() | router.navigate({ to }) |
259
+ | **Location** | router.location | router.state.location |
260
+ | **Guards** | router.beforeEach | No guards (use createEffect) |
261
+ | **Reactivity** | createEffect | createEffect |
262
+
263
+ **Key Differences:**
264
+
265
+ - **TanStack Solid Router:** Uses `router.navigate({ to })` API (object-based navigation)
266
+ - **SolidJS Router:** Uses `navigate(path)` function (string-based navigation)
267
+ - **TanStack:** Router instance contains state, no separate hooks needed
268
+ - **SolidJS:** Requires hooks (`useNavigate`, `useLocation`) for navigation primitives
269
+
270
+ ## Limitations
271
+
272
+ ### Solid Ownership Context Required
273
+
274
+ The bridge must be created inside a component where Solid hooks are available:
275
+
276
+ ```typescript
277
+ // ✅ CORRECT: Inside component
278
+ function App() {
279
+ const bridge = new SolidRouterBridge(router, actor, routeMap);
280
+ bridge.connect();
281
+ onCleanup(() => bridge.disconnect());
282
+ }
283
+
284
+ // ❌ WRONG: Outside component (no ownership context)
285
+ const bridge = new SolidRouterBridge(router, actor, routeMap);
286
+ bridge.connect(); // Will fail - no owner for createEffect
287
+ ```
288
+
289
+ **Error message:**
290
+
291
+ ```
292
+ Error: createEffect can only be used within a component
293
+ ```
294
+
295
+ ### Router Creation
296
+
297
+ Router must be created with TanStack's `createRouter()`:
298
+
299
+ ```typescript
300
+ import { createRouter } from "@tanstack/solid-router";
301
+
302
+ const router = createRouter({
303
+ routes: [
304
+ /* route config */
305
+ ],
306
+ });
307
+ ```
308
+
309
+ ### Pattern Matching Requirements
310
+
311
+ Route patterns with parameters require URLPattern support:
312
+
313
+ - **Modern browsers:** Safari 17.4+, Chrome 95+, Firefox 106+
314
+ - **Node.js:** Requires `urlpattern-polyfill` for tests
315
+
316
+ **Polyfill setup:**
317
+
318
+ ```typescript
319
+ // Top of app entry point
320
+ if (!globalThis.URLPattern) {
321
+ await import("urlpattern-polyfill");
322
+ }
323
+ ```
324
+
325
+ ## Architecture
326
+
327
+ SolidRouterBridge follows XMachines Play architectural invariants:
328
+
329
+ ### INV-01: Actor Authority
330
+
331
+ **Principle:** State machine has final authority over all transitions.
332
+
333
+ **Implementation:** Router navigation triggers actor events, but actor guards decide validity:
334
+
335
+ ```typescript
336
+ // Router navigation → Actor event
337
+ syncActorFromRouter(location: RouterLocation): void {
338
+ const stateId = this.routeMap.getStateIdByPath(location.pathname);
339
+ this.actor.send({
340
+ type: 'play.route',
341
+ to: stateId,
342
+ params: extractParams(location)
343
+ });
344
+ // Actor guards validate - if rejected, URL reverts to actor's current route
345
+ }
346
+ ```
347
+
348
+ ### INV-02: Passive Infrastructure
349
+
350
+ **Principle:** Infrastructure reflects actor state, never decides navigation.
351
+
352
+ **Implementation:** Router observes `actor.currentRoute` signal and updates URL:
353
+
354
+ ```typescript
355
+ // Actor state change → Router navigation
356
+ const actorEffect = createEffect(
357
+ on(
358
+ () => this.actor.currentRoute.get(),
359
+ (route) => this.syncRouterFromActor(route),
360
+ ),
361
+ );
362
+ ```
363
+
364
+ ### INV-05: Signal-Only Reactivity
365
+
366
+ **Principle:** All reactivity through signals, never callbacks or promises.
367
+
368
+ **Implementation:** Solid's `createEffect` watches actor signals automatically:
369
+
370
+ ```typescript
371
+ // Automatic dependency tracking
372
+ createEffect(
373
+ on(
374
+ () => this.actor.currentRoute.get(), // Signal read
375
+ (route) => {
376
+ // Effect runs when signal changes
377
+ },
378
+ ),
379
+ );
380
+ ```
381
+
382
+ ## Browser Support
383
+
384
+ This package uses the [URLPattern API](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern) for route pattern matching.
385
+
386
+ **Native Support:**
387
+
388
+ - Safari 17.4+ (Sept 2024)
389
+ - Chrome 95+ (Oct 2021)
390
+ - Firefox 106+ (Oct 2022)
391
+ - **Baseline 2025** status (newly available)
392
+
393
+ **Polyfill Required:**
394
+
395
+ - Node.js (all versions) - required for tests
396
+ - Safari < 17.4
397
+ - Older browsers
398
+
399
+ **Polyfill Installation:**
400
+
401
+ ```bash
402
+ npm install urlpattern-polyfill
403
+ ```
404
+
405
+ **Usage:**
406
+
407
+ ```typescript
408
+ // Top of your app entry point (e.g., main.tsx)
409
+ if (!globalThis.URLPattern) {
410
+ await import("urlpattern-polyfill");
411
+ }
412
+ ```
413
+
414
+ **Bundle Size:** ~4KB gzipped (zero impact if URLPattern is native)
415
+
416
+ ## Examples
417
+
418
+ See `examples/demo/` for the maintained integration example and tests.
419
+
420
+ ## License
421
+
422
+ MIT
423
+
424
+ ---
425
+
426
+ **Package:** @xmachines/play-tanstack-solid-router
427
+ **Pattern:** RouterBridge (~220 lines, 2 flags)
428
+ **Framework:** TanStack Solid Router 1.0+ with SolidJS 1.8+
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Create RouteMap helper for TanStack Solid Router adapter
3
+ *
4
+ * Simplifies demo code by hiding route extraction complexity.
5
+ * Internally calls extractMachineRoutes() and getRoutableRoutes(),
6
+ * then constructs RouteMap with proper state ID ↔ path mappings.
7
+ */
8
+ import type { AnyStateMachine } from "xstate";
9
+ import { RouteMap } from "./route-map.js";
10
+ /**
11
+ * Create a RouteMap from an XState machine
12
+ *
13
+ * @param machine - XState machine with route: {} config on states
14
+ * @returns RouteMap for bidirectional state ID ↔ path resolution
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { createRouteMap } from '@xmachines/play-tanstack-solid-router';
19
+ * import { authMachine } from './machine.js';
20
+ *
21
+ * const routeMap = createRouteMap(authMachine);
22
+ * ```
23
+ */
24
+ export declare function createRouteMap(machine: AnyStateMachine): RouteMap;
25
+ //# sourceMappingURL=create-route-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-route-map.d.ts","sourceRoot":"","sources":["../src/create-route-map.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,QAAQ,CAcjE"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Create RouteMap helper for TanStack Solid Router adapter
3
+ *
4
+ * Simplifies demo code by hiding route extraction complexity.
5
+ * Internally calls extractMachineRoutes() and getRoutableRoutes(),
6
+ * then constructs RouteMap with proper state ID ↔ path mappings.
7
+ */
8
+ import { extractMachineRoutes, getRoutableRoutes } from "@xmachines/play-router";
9
+ import { RouteMap } from "./route-map.js";
10
+ /**
11
+ * Create a RouteMap from an XState machine
12
+ *
13
+ * @param machine - XState machine with route: {} config on states
14
+ * @returns RouteMap for bidirectional state ID ↔ path resolution
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import { createRouteMap } from '@xmachines/play-tanstack-solid-router';
19
+ * import { authMachine } from './machine.js';
20
+ *
21
+ * const routeMap = createRouteMap(authMachine);
22
+ * ```
23
+ */
24
+ export function createRouteMap(machine) {
25
+ // Extract route tree from machine
26
+ const routeTree = extractMachineRoutes(machine);
27
+ // Get only routable nodes (states with route: {} config)
28
+ const routes = getRoutableRoutes(routeTree);
29
+ // Map to RouteMapping format expected by RouteMap constructor
30
+ const mappings = routes.map((node) => ({
31
+ stateId: node.stateId,
32
+ path: node.fullPath,
33
+ }));
34
+ return new RouteMap(mappings);
35
+ }
36
+ //# sourceMappingURL=create-route-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-route-map.js","sourceRoot":"","sources":["../src/create-route-map.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AACjF,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,OAAwB;IACtD,kCAAkC;IAClC,MAAM,SAAS,GAAG,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAEhD,yDAAyD;IACzD,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;IAE5C,8DAA8D;IAC9D,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACtC,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,IAAI,EAAE,IAAI,CAAC,QAAQ;KACnB,CAAC,CAAC,CAAC;IAEJ,OAAO,IAAI,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @xmachines/play-tanstack-solid-router
3
+ *
4
+ * TanStack Solid Router adapter for XMachines Universal Player Architecture
5
+ */
6
+ export { SolidRouterBridge } from "./solid-router-bridge.js";
7
+ export { PlayRouterProvider } from "./play-router-provider.js";
8
+ export type { PlayRouterProviderProps, RoutableActor, TanStackRouterInstance, } from "./play-router-provider.js";
9
+ export { RouteMap } from "./route-map.js";
10
+ export { createRouteMap } from "./create-route-map.js";
11
+ export type { TanStackRouterLike } from "./solid-router-bridge.js";
12
+ export type { RouteMapping, RouterBridge, PlayRouteEvent } from "./types.js";
13
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,YAAY,EACX,uBAAuB,EACvB,aAAa,EACb,sBAAsB,GACtB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,YAAY,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @xmachines/play-tanstack-solid-router
3
+ *
4
+ * TanStack Solid Router adapter for XMachines Universal Player Architecture
5
+ */
6
+ export { SolidRouterBridge } from "./solid-router-bridge.js";
7
+ export { PlayRouterProvider } from "./play-router-provider.js";
8
+ export { RouteMap } from "./route-map.js";
9
+ export { createRouteMap } from "./create-route-map.js";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAM/D,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { type JSX } from "solid-js";
2
+ import type { AbstractActor, Routable, Viewable } from "@xmachines/play-actor";
3
+ import type { AnyActorLogic } from "xstate";
4
+ import { SolidRouterBridge } from "./solid-router-bridge.js";
5
+ import type { RouteMap } from "./route-map.js";
6
+ export type RoutableActor = AbstractActor<AnyActorLogic> & Routable & Viewable;
7
+ export type TanStackRouterInstance = ConstructorParameters<typeof SolidRouterBridge>[0];
8
+ export interface PlayRouterProviderProps {
9
+ actor: RoutableActor;
10
+ router: TanStackRouterInstance;
11
+ routeMap: RouteMap;
12
+ renderer: (actor: RoutableActor, router: TanStackRouterInstance) => JSX.Element;
13
+ }
14
+ export declare function PlayRouterProvider(props: PlayRouterProviderProps): any;
15
+ //# sourceMappingURL=play-router-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"play-router-provider.d.ts","sourceRoot":"","sources":["../src/play-router-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,MAAM,aAAa,GAAG,aAAa,CAAC,aAAa,CAAC,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAC/E,MAAM,MAAM,sBAAsB,GAAG,qBAAqB,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;AAExF,MAAM,WAAW,uBAAuB;IACvC,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,sBAAsB,KAAK,GAAG,CAAC,OAAO,CAAC;CAChF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,OAShE"}
@@ -0,0 +1,11 @@
1
+ import { onCleanup } from "solid-js";
2
+ import { SolidRouterBridge } from "./solid-router-bridge.js";
3
+ export function PlayRouterProvider(props) {
4
+ const bridge = new SolidRouterBridge(props.router, props.actor, props.routeMap);
5
+ bridge.connect();
6
+ onCleanup(() => {
7
+ bridge.disconnect();
8
+ });
9
+ return <>{props.renderer(props.actor, props.router)}</>;
10
+ }
11
+ //# sourceMappingURL=play-router-provider.jsx.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"play-router-provider.jsx","sourceRoot":"","sources":["../src/play-router-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAY,MAAM,UAAU,CAAC;AAG/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAa7D,MAAM,UAAU,kBAAkB,CAAC,KAA8B;IAChE,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChF,MAAM,CAAC,OAAO,EAAE,CAAC;IAEjB,SAAS,CAAC,GAAG,EAAE;QACd,MAAM,CAAC,UAAU,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC;AACzD,CAAC"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * RouteMap for bidirectional state ID ↔ path mapping
3
+ *
4
+ * Provides efficient lookup between XMachines state IDs and TanStack Router paths.
5
+ * Supports pattern matching for dynamic routes with parameters.
6
+ */
7
+ import type { RouteMapping } from "./types.js";
8
+ export declare class RouteMap {
9
+ private stateToPath;
10
+ private pathToState;
11
+ /**
12
+ * Create a RouteMap with bidirectional mappings
13
+ *
14
+ * @param mappings - Array of state ID to path mappings
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const routeMap = new RouteMap([
19
+ * { stateId: '#home', path: '/' },
20
+ * { stateId: '#profile', path: '/profile/:userId' },
21
+ * { stateId: '#settings', path: '/settings/:section?' }
22
+ * ]);
23
+ * ```
24
+ */
25
+ constructor(mappings: RouteMapping[]);
26
+ /**
27
+ * Get path pattern for a state ID
28
+ *
29
+ * @param stateId - XMachines state ID (e.g., '#profile')
30
+ * @returns Path pattern or null if not found
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * routeMap.getPathByStateId('#profile'); // '/profile/:userId'
35
+ * ```
36
+ */
37
+ getPathByStateId(stateId: string): string | null;
38
+ /**
39
+ * Get state ID for a path, with pattern matching support
40
+ *
41
+ * Performs exact match first, then fuzzy pattern matching for dynamic routes.
42
+ * Supports both required (:param) and optional (:param?) parameters.
43
+ *
44
+ * @param path - Actual URL path (e.g., '/profile/123')
45
+ * @returns State ID or null if no match found
46
+ *
47
+ * @example
48
+ * ```typescript
49
+ * routeMap.getStateIdByPath('/profile/123'); // '#profile'
50
+ * routeMap.getStateIdByPath('/settings'); // '#settings'
51
+ * routeMap.getStateIdByPath('/settings/account'); // '#settings'
52
+ * ```
53
+ */
54
+ getStateIdByPath(path: string): string | null;
55
+ /**
56
+ * Check if a path matches a pattern
57
+ *
58
+ * Supports:
59
+ * - Required parameters: :param
60
+ * - Optional parameters: :param?
61
+ *
62
+ * @param path - Actual URL path
63
+ * @param pattern - Route pattern with :param syntax
64
+ * @returns true if path matches pattern
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * matchesPattern('/profile/123', '/profile/:userId'); // true
69
+ * matchesPattern('/settings', '/settings/:section?'); // true
70
+ * matchesPattern('/settings/account', '/settings/:section?'); // true
71
+ * ```
72
+ */
73
+ private matchesPattern;
74
+ }
75
+ //# sourceMappingURL=route-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-map.d.ts","sourceRoot":"","sources":["../src/route-map.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,qBAAa,QAAQ;IACpB,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,WAAW,CAA6B;IAEhD;;;;;;;;;;;;;OAaG;gBACS,QAAQ,EAAE,YAAY,EAAE;IAOpC;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAIhD;;;;;;;;;;;;;;;OAeG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAmB7C;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,cAAc;CAetB"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * RouteMap for bidirectional state ID ↔ path mapping
3
+ *
4
+ * Provides efficient lookup between XMachines state IDs and TanStack Router paths.
5
+ * Supports pattern matching for dynamic routes with parameters.
6
+ */
7
+ export class RouteMap {
8
+ stateToPath = new Map();
9
+ pathToState = new Map();
10
+ /**
11
+ * Create a RouteMap with bidirectional mappings
12
+ *
13
+ * @param mappings - Array of state ID to path mappings
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const routeMap = new RouteMap([
18
+ * { stateId: '#home', path: '/' },
19
+ * { stateId: '#profile', path: '/profile/:userId' },
20
+ * { stateId: '#settings', path: '/settings/:section?' }
21
+ * ]);
22
+ * ```
23
+ */
24
+ constructor(mappings) {
25
+ mappings.forEach(({ stateId, path }) => {
26
+ this.stateToPath.set(stateId, path);
27
+ this.pathToState.set(path, stateId);
28
+ });
29
+ }
30
+ /**
31
+ * Get path pattern for a state ID
32
+ *
33
+ * @param stateId - XMachines state ID (e.g., '#profile')
34
+ * @returns Path pattern or null if not found
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * routeMap.getPathByStateId('#profile'); // '/profile/:userId'
39
+ * ```
40
+ */
41
+ getPathByStateId(stateId) {
42
+ return this.stateToPath.get(stateId) ?? null;
43
+ }
44
+ /**
45
+ * Get state ID for a path, with pattern matching support
46
+ *
47
+ * Performs exact match first, then fuzzy pattern matching for dynamic routes.
48
+ * Supports both required (:param) and optional (:param?) parameters.
49
+ *
50
+ * @param path - Actual URL path (e.g., '/profile/123')
51
+ * @returns State ID or null if no match found
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * routeMap.getStateIdByPath('/profile/123'); // '#profile'
56
+ * routeMap.getStateIdByPath('/settings'); // '#settings'
57
+ * routeMap.getStateIdByPath('/settings/account'); // '#settings'
58
+ * ```
59
+ */
60
+ getStateIdByPath(path) {
61
+ // Strip query string and hash fragment for matching
62
+ const cleanPath = path.split("?")[0].split("#")[0];
63
+ // Direct lookup first (exact match)
64
+ if (this.pathToState.has(cleanPath)) {
65
+ return this.pathToState.get(cleanPath);
66
+ }
67
+ // Fuzzy match for dynamic routes
68
+ for (const [pattern, stateId] of this.pathToState) {
69
+ if (this.matchesPattern(cleanPath, pattern)) {
70
+ return stateId;
71
+ }
72
+ }
73
+ return null;
74
+ }
75
+ /**
76
+ * Check if a path matches a pattern
77
+ *
78
+ * Supports:
79
+ * - Required parameters: :param
80
+ * - Optional parameters: :param?
81
+ *
82
+ * @param path - Actual URL path
83
+ * @param pattern - Route pattern with :param syntax
84
+ * @returns true if path matches pattern
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * matchesPattern('/profile/123', '/profile/:userId'); // true
89
+ * matchesPattern('/settings', '/settings/:section?'); // true
90
+ * matchesPattern('/settings/account', '/settings/:section?'); // true
91
+ * ```
92
+ */
93
+ matchesPattern(path, pattern) {
94
+ // Convert route pattern to regex
95
+ // Process replacements in correct order: optional params first, then required
96
+ let regexPattern = pattern
97
+ // Replace /:param? with optional segment (matches both /value and nothing)
98
+ .replace(/\/:(\w+)\?/g, "(?:/([^/]+))?")
99
+ // Replace /:param with required segment
100
+ .replace(/\/:(\w+)/g, "/([^/]+)");
101
+ // Add anchors for exact match
102
+ regexPattern = "^" + regexPattern + "$";
103
+ const regex = new RegExp(regexPattern);
104
+ return regex.test(path);
105
+ }
106
+ }
107
+ //# sourceMappingURL=route-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-map.js","sourceRoot":"","sources":["../src/route-map.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,OAAO,QAAQ;IACZ,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IACxC,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEhD;;;;;;;;;;;;;OAaG;IACH,YAAY,QAAwB;QACnC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;YACtC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;IACJ,CAAC;IAED;;;;;;;;;;OAUG;IACH,gBAAgB,CAAC,OAAe;QAC/B,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;IAC9C,CAAC;IAED;;;;;;;;;;;;;;;OAeG;IACH,gBAAgB,CAAC,IAAY;QAC5B,oDAAoD;QACpD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAEnD,oCAAoC;QACpC,IAAI,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACrC,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAE,CAAC;QACzC,CAAC;QAED,iCAAiC;QACjC,KAAK,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;YACnD,IAAI,IAAI,CAAC,cAAc,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC;gBAC7C,OAAO,OAAO,CAAC;YAChB,CAAC;QACF,CAAC;QAED,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACK,cAAc,CAAC,IAAY,EAAE,OAAe;QACnD,iCAAiC;QACjC,8EAA8E;QAC9E,IAAI,YAAY,GAAG,OAAO;YACzB,2EAA2E;aAC1E,OAAO,CAAC,aAAa,EAAE,eAAe,CAAC;YACxC,wCAAwC;aACvC,OAAO,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QAEnC,8BAA8B;QAC9B,YAAY,GAAG,GAAG,GAAG,YAAY,GAAG,GAAG,CAAC;QAExC,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC;QACvC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;CACD"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * TanStack Solid Router bridge implementing RouterBridge protocol via RouterBridgeBase
3
+ *
4
+ * Extends RouterBridgeBase to handle all common lifecycle and sync logic.
5
+ *
6
+ * @example
7
+ * \`\`\`tsx
8
+ * import { createRouter } from '@tanstack/solid-router';
9
+ * import { onCleanup } from 'solid-js';
10
+ * import { SolidRouterBridge, RouteMap } from '@xmachines/play-tanstack-solid-router';
11
+ *
12
+ * function App() {
13
+ * const routeMap = new RouteMap([...]);
14
+ * const bridge = new SolidRouterBridge(router, actor, routeMap);
15
+ * bridge.connect();
16
+ * onCleanup(() => bridge.disconnect());
17
+ * return <div>...</div>;
18
+ * }
19
+ * \`\`\`
20
+ */
21
+ import { RouterBridgeBase } from "@xmachines/play-router";
22
+ import type { AbstractActor, Routable } from "@xmachines/play-actor";
23
+ import type { AnyActorLogic } from "xstate";
24
+ import type { RouteMap } from "./route-map.js";
25
+ export type TanStackRouterLike = {
26
+ navigate(args: {
27
+ to: string;
28
+ }): void;
29
+ state?: {
30
+ location?: {
31
+ pathname?: string;
32
+ };
33
+ };
34
+ history: {
35
+ subscribe(handler: (event: {
36
+ location: {
37
+ pathname: string;
38
+ search?: string;
39
+ };
40
+ }) => void): () => void;
41
+ };
42
+ };
43
+ /**
44
+ * TanStack Solid Router integration bridge extending RouterBridgeBase
45
+ *
46
+ * Uses router.subscribe("onBeforeLoad", fn) for router→actor sync.
47
+ * This mirrors the TanStack React Router bridge pattern and uses the
48
+ * public router events API instead of the internal __store.
49
+ */
50
+ export declare class SolidRouterBridge extends RouterBridgeBase {
51
+ private readonly router;
52
+ private _unsubscribeRouter;
53
+ /**
54
+ * Create a TanStack Solid Router bridge
55
+ *
56
+ * @param router - TanStack Router instance (from createRouter)
57
+ * @param actor - XMachines actor instance
58
+ * @param routeMap - Bidirectional state ID ↔ path mapping
59
+ */
60
+ constructor(router: TanStackRouterLike, actor: AbstractActor<AnyActorLogic> & Routable, routeMap: RouteMap);
61
+ /**
62
+ * Navigate TanStack Solid Router to the given path.
63
+ */
64
+ protected navigateRouter(path: string): void;
65
+ /**
66
+ * Get the router's current path at connect() time for initial sync.
67
+ *
68
+ * TanStack Router exposes router.state.location.pathname synchronously,
69
+ * so we can read it here to drive the actor to the correct initial state
70
+ * when the user cold-loads on a deep-link URL.
71
+ */
72
+ protected getInitialRouterPath(): string | null;
73
+ /**
74
+ * Subscribe to ALL navigation events via router.history.
75
+ *
76
+ * router.history.subscribe fires for PUSH, POP, BACK, FORWARD, REPLACE, and GO —
77
+ * covering both link clicks and browser back/forward button presses.
78
+ *
79
+ * The subscriber callback receives { location, action } where location is the
80
+ * new history location with pathname and search already updated.
81
+ *
82
+ * Using router.history rather than router.subscribe("onBeforeLoad") ensures
83
+ * back/forward works regardless of whether <RouterProvider> is mounted.
84
+ *
85
+ * Also registers onCleanup() so Solid automatically disconnects on unmount.
86
+ */
87
+ protected watchRouterChanges(): void;
88
+ /**
89
+ * Stop watching TanStack Router changes.
90
+ */
91
+ protected unwatchRouterChanges(): void;
92
+ /**
93
+ * Dispose the bridge (alias for disconnect).
94
+ */
95
+ dispose(): void;
96
+ }
97
+ //# sourceMappingURL=solid-router-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solid-router-bridge.d.ts","sourceRoot":"","sources":["../src/solid-router-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,MAAM,kBAAkB,GAAG;IAChC,QAAQ,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACrC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IAC7C,OAAO,EAAE;QACR,SAAS,CACR,OAAO,EAAE,CAAC,KAAK,EAAE;YAAE,QAAQ,EAAE;gBAAE,QAAQ,EAAE,MAAM,CAAC;gBAAC,MAAM,CAAC,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,KAAK,IAAI,GAC3E,MAAM,IAAI,CAAC;KACd,CAAC;CACF,CAAC;AAEF;;;;;;GAMG;AACH,qBAAa,iBAAkB,SAAQ,gBAAgB;IAWrD,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVxB,OAAO,CAAC,kBAAkB,CAA6B;IAEvD;;;;;;OAMG;gBAEe,MAAM,EAAE,kBAAkB,EAC3C,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,GAAG,QAAQ,EAC9C,QAAQ,EAAE,QAAQ;IAQnB;;OAEG;IACH,SAAS,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI5C;;;;;;OAMG;cACgB,oBAAoB,IAAI,MAAM,GAAG,IAAI;IAIxD;;;;;;;;;;;;;OAaG;IACH,SAAS,CAAC,kBAAkB,IAAI,IAAI;IAWpC;;OAEG;IACH,SAAS,CAAC,oBAAoB,IAAI,IAAI;IAKtC;;OAEG;IACH,OAAO,IAAI,IAAI;CAGf"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * TanStack Solid Router bridge implementing RouterBridge protocol via RouterBridgeBase
3
+ *
4
+ * Extends RouterBridgeBase to handle all common lifecycle and sync logic.
5
+ *
6
+ * @example
7
+ * \`\`\`tsx
8
+ * import { createRouter } from '@tanstack/solid-router';
9
+ * import { onCleanup } from 'solid-js';
10
+ * import { SolidRouterBridge, RouteMap } from '@xmachines/play-tanstack-solid-router';
11
+ *
12
+ * function App() {
13
+ * const routeMap = new RouteMap([...]);
14
+ * const bridge = new SolidRouterBridge(router, actor, routeMap);
15
+ * bridge.connect();
16
+ * onCleanup(() => bridge.disconnect());
17
+ * return <div>...</div>;
18
+ * }
19
+ * \`\`\`
20
+ */
21
+ import { onCleanup } from "solid-js";
22
+ import { RouterBridgeBase } from "@xmachines/play-router";
23
+ /**
24
+ * TanStack Solid Router integration bridge extending RouterBridgeBase
25
+ *
26
+ * Uses router.subscribe("onBeforeLoad", fn) for router→actor sync.
27
+ * This mirrors the TanStack React Router bridge pattern and uses the
28
+ * public router events API instead of the internal __store.
29
+ */
30
+ export class SolidRouterBridge extends RouterBridgeBase {
31
+ router;
32
+ _unsubscribeRouter = null;
33
+ /**
34
+ * Create a TanStack Solid Router bridge
35
+ *
36
+ * @param router - TanStack Router instance (from createRouter)
37
+ * @param actor - XMachines actor instance
38
+ * @param routeMap - Bidirectional state ID ↔ path mapping
39
+ */
40
+ constructor(router, actor, routeMap) {
41
+ super(actor, {
42
+ getStateIdByPath: (path) => routeMap.getStateIdByPath(path) ?? undefined,
43
+ getPathByStateId: (id) => routeMap.getPathByStateId(id) ?? undefined,
44
+ });
45
+ this.router = router;
46
+ }
47
+ /**
48
+ * Navigate TanStack Solid Router to the given path.
49
+ */
50
+ navigateRouter(path) {
51
+ this.router.navigate({ to: path });
52
+ }
53
+ /**
54
+ * Get the router's current path at connect() time for initial sync.
55
+ *
56
+ * TanStack Router exposes router.state.location.pathname synchronously,
57
+ * so we can read it here to drive the actor to the correct initial state
58
+ * when the user cold-loads on a deep-link URL.
59
+ */
60
+ getInitialRouterPath() {
61
+ return this.router.state?.location?.pathname ?? null;
62
+ }
63
+ /**
64
+ * Subscribe to ALL navigation events via router.history.
65
+ *
66
+ * router.history.subscribe fires for PUSH, POP, BACK, FORWARD, REPLACE, and GO —
67
+ * covering both link clicks and browser back/forward button presses.
68
+ *
69
+ * The subscriber callback receives { location, action } where location is the
70
+ * new history location with pathname and search already updated.
71
+ *
72
+ * Using router.history rather than router.subscribe("onBeforeLoad") ensures
73
+ * back/forward works regardless of whether <RouterProvider> is mounted.
74
+ *
75
+ * Also registers onCleanup() so Solid automatically disconnects on unmount.
76
+ */
77
+ watchRouterChanges() {
78
+ this._unsubscribeRouter = this.router.history.subscribe(({ location }) => {
79
+ this.syncActorFromRouter(location.pathname, location.search ?? "");
80
+ });
81
+ // Solid's onCleanup — automatically disconnects when component unmounts
82
+ onCleanup(() => this.disconnect());
83
+ }
84
+ /**
85
+ * Stop watching TanStack Router changes.
86
+ */
87
+ unwatchRouterChanges() {
88
+ this._unsubscribeRouter?.();
89
+ this._unsubscribeRouter = null;
90
+ }
91
+ /**
92
+ * Dispose the bridge (alias for disconnect).
93
+ */
94
+ dispose() {
95
+ this.disconnect();
96
+ }
97
+ }
98
+ //# sourceMappingURL=solid-router-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solid-router-bridge.js","sourceRoot":"","sources":["../src/solid-router-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAe1D;;;;;;GAMG;AACH,MAAM,OAAO,iBAAkB,SAAQ,gBAAgB;IAWpC;IAVV,kBAAkB,GAAwB,IAAI,CAAC;IAEvD;;;;;;OAMG;IACH,YACkB,MAA0B,EAC3C,KAA8C,EAC9C,QAAkB;QAElB,KAAK,CAAC,KAAK,EAAE;YACZ,gBAAgB,EAAE,CAAC,IAAY,EAAE,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,SAAS;YAChF,gBAAgB,EAAE,CAAC,EAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,IAAI,SAAS;SAC5E,CAAC,CAAC;QAPc,WAAM,GAAN,MAAM,CAAoB;IAQ5C,CAAC;IAED;;OAEG;IACO,cAAc,CAAC,IAAY;QACpC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACpC,CAAC;IAED;;;;;;OAMG;IACgB,oBAAoB;QACtC,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,IAAI,IAAI,CAAC;IACtD,CAAC;IAED;;;;;;;;;;;;;OAaG;IACO,kBAAkB;QAC3B,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CACtD,CAAC,EAAE,QAAQ,EAAuD,EAAE,EAAE;YACrE,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;QACpE,CAAC,CACD,CAAC;QAEF,wEAAwE;QACxE,SAAS,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;IACpC,CAAC;IAED;;OAEG;IACO,oBAAoB;QAC7B,IAAI,CAAC,kBAAkB,EAAE,EAAE,CAAC;QAC5B,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,OAAO;QACN,IAAI,CAAC,UAAU,EAAE,CAAC;IACnB,CAAC;CACD"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Type definitions for TanStack Solid Router adapter
3
+ */
4
+ export type { RouterBridge, PlayRouteEvent } from "@xmachines/play-router";
5
+ export type { AbstractActor } from "@xmachines/play-actor";
6
+ export interface RouteMapping {
7
+ stateId: string;
8
+ path: string;
9
+ }
10
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC3E,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACb"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Type definitions for TanStack Solid Router adapter
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@xmachines/play-tanstack-solid-router",
3
+ "version": "1.0.0-beta.1",
4
+ "description": "TanStack Solid Router adapter for XMachines Universal Player Architecture",
5
+ "license": "MIT",
6
+ "author": "XMachines Contributors",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git@gitlab.com:xmachin-es/xmachines-js.git",
10
+ "directory": "packages/play-tanstack-solid-router"
11
+ },
12
+ "files": [
13
+ "dist",
14
+ "README.md"
15
+ ],
16
+ "type": "module",
17
+ "main": "./dist/index.js",
18
+ "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ }
24
+ },
25
+ "scripts": {
26
+ "build": "tsc --build",
27
+ "test": "vitest run",
28
+ "test:watch": "vitest",
29
+ "typecheck": "tsc --noEmit",
30
+ "clean": "rm -rf dist *.tsbuildinfo",
31
+ "prepublishOnly": "npm run build"
32
+ },
33
+ "dependencies": {
34
+ "@xmachines/play": "1.0.0-beta.1",
35
+ "@xmachines/play-actor": "1.0.0-beta.1",
36
+ "@xmachines/play-router": "1.0.0-beta.1",
37
+ "@xmachines/play-signals": "1.0.0-beta.1"
38
+ },
39
+ "devDependencies": {
40
+ "@solidjs/testing-library": "^0.8.0",
41
+ "@tanstack/solid-router": "^1.166.7",
42
+ "solid-js": "^1.8.0"
43
+ },
44
+ "peerDependencies": {
45
+ "@tanstack/solid-router": "^1.166.7",
46
+ "solid-js": "^1.8.0"
47
+ },
48
+ "publishConfig": {
49
+ "access": "public"
50
+ }
51
+ }