Class: TanStackReactRouterBridge
API / @xmachines/play-tanstack-react-router / TanStackReactRouterBridge
Defined in: play-tanstack-react-router/src/tanstack-router-bridge.ts:83
TanStack React Router adapter implementing RouterBridge protocol via RouterBridgeBase
Remarks
Extends RouterBridgeBase to handle all common lifecycle and sync logic. Only 3 TanStack-specific methods are implemented here.
Subscribes to router.history (not router.subscribe(“onBeforeLoad”)) so that
back/forward browser navigation (popstate events) are also captured. The
router.subscribe(“onBeforeLoad”) approach only works when TanStack’s
Transitioner component is mounted (i.e. inside a full router.history.subscribe(router.load).
Architectural Invariants:
- INV-02 (Passive Infrastructure): Router reflects actor state, never decides
- Actor validates all navigation via guards before URL changes
Example
const bridge = new TanStackReactRouterBridge(router, actor, routeMap);bridge.connect();return () => bridge.disconnect();Extends
Constructors
Constructor
new TanStackReactRouterBridge( router, actor, routeMap): TanStackReactRouterBridge;Defined in: play-tanstack-react-router/src/tanstack-router-bridge.ts:93
Create TanStack React Router bridge
Parameters
| Parameter | Type | Description |
|---|---|---|
router | TanStackRouterLike | TanStack React Router instance |
actor | RoutableActor | XMachines actor instance |
routeMap | RouteMap | Bidirectional mapping between state IDs and paths |
Returns
TanStackReactRouterBridge
Overrides
Properties
| Property | Modifier | Type | Default value | Description | Inherited from | Defined in |
|---|---|---|---|---|---|---|
actor | readonly | RoutableActor | undefined | A RoutableActor exposing currentRoute, initialRoute, and send. | RouterBridgeBase.actor | play-router/src/router-bridge-base.ts:125 |
hasConnectedOnce | protected | boolean | false | - | RouterBridgeBase.hasConnectedOnce | play-router/src/router-bridge-base.ts:103 |
isConnected | protected | boolean | false | - | RouterBridgeBase.isConnected | play-router/src/router-bridge-base.ts:102 |
isProcessingNavigation | protected | boolean | false | Guards syncActorFromRouter against re-entrant calls triggered by the actor’s own guard redirects (router→actor send → signal fires → actor→router push → another syncActorFromRouter before the first one returns). NOT used for actor→router echo suppression — that is handled exclusively by lastSyncedPath, which is updated before navigateRouter() is called so any router callback for the same path short-circuits at the sanitized === lastSyncedPath check in syncActorFromRouter. | RouterBridgeBase.isProcessingNavigation | play-router/src/router-bridge-base.ts:115 |
lastSyncedPath | protected | string | null | null | - | RouterBridgeBase.lastSyncedPath | play-router/src/router-bridge-base.ts:104 |
routeMap | readonly | object | undefined | Bidirectional route map for stateId ↔ path resolution. Provide getStateIdByPath and getPathByStateId. Framework adapters typically wrap the result of createRouteMap(machine) or an equivalent. | RouterBridgeBase.routeMap | play-router/src/router-bridge-base.ts:126 |
routeMap.getPathByStateId | public | string | null | undefined | undefined | - | - | play-router/src/router-bridge-base.ts:128 |
routeMap.getStateIdByPath | public | string | null | undefined | undefined | - | - | play-router/src/router-bridge-base.ts:127 |
routeWatcher | protected | | RouteWatcherHandle | null | null | - | RouterBridgeBase.routeWatcher | play-router/src/router-bridge-base.ts:116 |
Methods
connect()
connect(): void;Defined in: play-router/src/router-bridge-base.ts:152
Connect the router bridge to the Actor.
Sets up the TC39 Signal watcher for actor → router direction and starts watching router changes (framework-specific).
Ordering here is part of the bridge contract:
lastSyncedPathis seeded in the constructor fromactor.currentRoute- the actor watcher is installed before adapter router subscriptions
- initial sync then resolves deep-link vs restore using
actor.initialRoute
Adapters that need custom initial-sync behavior should override
getInitialRouterPath() rather than reordering connect() steps.
Returns
void
Inherited from
disconnect()
disconnect(): void;Defined in: play-router/src/router-bridge-base.ts:248
Disconnect the router bridge from the Actor.
Stops signal watching and unregisters framework-specific router listener.
Returns
void
Inherited from
extractParams()
protected extractParams(pathname, stateId): Record<string, string>;Defined in: play-router/src/router-bridge-base.ts:402
Extract path parameters from URL using the URLPattern API.
Accesses globalThis.URLPattern at runtime — no polyfill is imported by this
library. If URLPattern is unavailable and the matched route has parameterized
segments, a URLPatternUnavailableError is thrown — callers must provide a polyfill
for environments without native URLPattern support (Node.js < 24, older browsers).
Parameters
| Parameter | Type | Description |
|---|---|---|
pathname | string | The actual URL path (e.g., ‘/profile/john’) |
stateId | string | The matched state ID for looking up the route pattern |
Returns
Record<string, string>
Extracted path parameters, or empty object if no match
Throws
When URLPattern is absent and the route is parameterized
Inherited from
RouterBridgeBase.extractParams
extractQuery()
protected extractQuery(search): Record<string, string>;Defined in: play-router/src/router-bridge-base.ts:439
Extract query parameters from URL search string.
Parameters
| Parameter | Type | Description |
|---|---|---|
search | string | URL search string (e.g., ‘?tab=security&page=1’) |
Returns
Record<string, string>
Extracted query parameters or empty object
Inherited from
getInitialRouterPath()
protected getInitialRouterPath(): string | null;Defined in: play-tanstack-react-router/src/tanstack-router-bridge.ts:127
Read the router’s current pathname for initial sync.
Called once in connect() to handle cold-load / deep-link scenarios where the URL differs from the actor’s initial state (e.g. user pastes /dashboard while logged out — the actor must be redirected to /login before rendering).
Uses router.history.location.pathname — reflects window.location immediately,
before the router has been loaded or a <RouterProvider> mounted.
router.state.location is only populated after router.load() which may not
have run yet when the bridge first connects in a useEffect.
The base class connect() uses actor.initialRoute to distinguish:
- Deep-link: router URL differs from machine’s initial route → router wins.
- Restore: router at machine’s initial route, actor at a different restored route → actor wins, bridge pushes actor’s restored route to the router.
Returns
string | null
Overrides
RouterBridgeBase.getInitialRouterPath
getInitialRouterSearch()
protected getInitialRouterSearch(): string | undefined;Defined in: play-tanstack-react-router/src/tanstack-router-bridge.ts:143
Return the initial URL search string for query-param forwarding on connect().
Reads router.history.location.search — the same source used by
getInitialRouterPath(), which reflects window.location immediately before
router.load() or <RouterProvider> mounts. An empty string returns undefined
so syncActorFromRouter produces query: {} rather than parsing an empty string.
Returns
string | undefined
Overrides
RouterBridgeBase.getInitialRouterSearch
navigateRouter()
protected navigateRouter(path): void;Defined in: play-tanstack-react-router/src/tanstack-router-bridge.ts:105
Must trigger the framework router’s navigation (e.g., router.navigate(path)).
Parameters
| Parameter | Type |
|---|---|
path | string |
Returns
void
Overrides
RouterBridgeBase.navigateRouter
resolveNavigationPath()
protected resolveNavigationPath(route): string | null;Defined in: play-router/src/router-bridge-base.ts:424
Resolve an actor route value to a concrete URL path for navigation.
Bridges that receive raw actor.currentRoute values in navigateRouter
can call this to normalize stateIds (with or without # prefix) to paths.
Returns null when navigation is not possible:
- unknown stateId with no route map entry
- parameterized pattern (e.g.
/profile/:id) — no concrete values available - non-path string that isn’t a known stateId
Route maps may store stateIds with or without the # prefix; both forms
are tried automatically.
Parameters
| Parameter | Type | Description |
|---|---|---|
route | string | Raw actor route value (stateId, #-stateId, or concrete path) |
Returns
string | null
Concrete URL path, or null if navigation should be skipped
Inherited from
RouterBridgeBase.resolveNavigationPath
sanitizePath()
protected sanitizePath(pathname): string | null;Defined in: play-router/src/router-bridge-base.ts:466
Sanitize and validate a raw URL pathname received from the router.
Applies the path-length cap (2048 chars), strips query strings and fragments that may have been included in the pathname segment, and normalises consecutive slashes.
Implementations that bypass syncActorFromRouter() (e.g. when using
framework-native reactive watchers that receive pre-parsed route objects)
MUST call this method before passing the path to any route-map lookup.
syncActorFromRouter() calls this internally, so bridges that delegate
to it do not need to call sanitizePath themselves.
Parameters
| Parameter | Type | Description |
|---|---|---|
pathname | string | Raw URL pathname from the framework router. |
Returns
string | null
Sanitized pathname, or null if the path is invalid / too long.
Inherited from
syncActorFromRouter()
protected syncActorFromRouter(pathname, search?): void;Defined in: play-router/src/router-bridge-base.ts:324
Sync actor state when router location changes.
Known path: sends a play.route event to the actor with the matched
stateId, params, and query. Prevents circular updates via the
isProcessingNavigation flag.
Unknown/unmapped path: does NOT send a play.route event (actor state
is unchanged). Instead, actively corrects the browser URL by calling
navigateRouter(actor.currentRoute.get()) — keeping the URL in sync with
actor state even when the user types an invalid path into the address bar
or pushes one programmatically mid-session. lastSyncedPath is set to the
resolved concrete path before calling navigateRouter so the router’s own
callback for that navigation short-circuits the echo-suppression guard and
sends no spurious event.
Parameters
| Parameter | Type |
|---|---|
pathname | string |
search? | string |
Returns
void
Inherited from
RouterBridgeBase.syncActorFromRouter
syncRouterFromActor()
protected syncRouterFromActor(route): void;Defined in: play-router/src/router-bridge-base.ts:289
Sync router location when actor route signal changes.
Calls navigateRouter() for framework-specific navigation.
Echo suppression — preventing the router’s own callback from re-driving the
actor — is handled entirely by lastSyncedPath: it is set to route before
navigateRouter() is called, so any syncActorFromRouter invocation for the
same path short-circuits at the sanitized === lastSyncedPath check and sends
no event regardless of whether the callback fires synchronously or asynchronously.
isProcessingNavigation is NOT set here — it is only used inside
syncActorFromRouter to guard against re-entrant guard-redirect loops.
Parameters
| Parameter | Type |
|---|---|
route | unknown |
Returns
void
Inherited from
RouterBridgeBase.syncRouterFromActor
unwatchRouterChanges()
protected unwatchRouterChanges(): void;Defined in: play-tanstack-react-router/src/tanstack-router-bridge.ts:165
Stop watching for router location changes.
Called by disconnect(). Should clean up the framework-specific subscription.
Returns
void
Overrides
RouterBridgeBase.unwatchRouterChanges
watchRouterChanges()
protected watchRouterChanges(): void;Defined in: play-tanstack-react-router/src/tanstack-router-bridge.ts:156
Subscribe to ALL navigation events via router.history.
router.history.subscribe fires for PUSH, POP, BACK, FORWARD, REPLACE, and GO — covering both link clicks and browser back/forward button presses.
The subscriber callback receives { location, action } where location is the new history location with pathname and search already updated.
Returns
void