@bgub/fig-tanstack-router 0.0.0-tegami-trusted-publish-setup → 0.1.0-alpha.2

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/CHANGELOG.md ADDED
@@ -0,0 +1,183 @@
1
+ ## @bgub/fig-tanstack-router@0.1.0-alpha.1
2
+
3
+ ### Add the TanStack Router adapter for Fig
4
+
5
+ `@bgub/fig-tanstack-router` now supplies code-route creation, a Fig router
6
+ provider and outlet, router hooks, native anchor links, route preloading, and a
7
+ private reactive-store bridge for `@tanstack/router-core` 1.171.15.
8
+
9
+ ### Prioritize render-blocking document assets
10
+
11
+ Full-document rendering now emits parser- and security-sensitive metadata,
12
+ connection hints, critical font and image preloads, and stylesheets before
13
+ ordinary metadata and lower-priority JavaScript hints. TanStack Router matches
14
+ also register authored links and manifest stylesheets before their generated
15
+ module preloads, so render-blocking CSS begins loading earlier without changing
16
+ stylesheet order.
17
+
18
+ ### Remove `useLoaderData`; enforce void loaders for data-backed routers
19
+
20
+ The adapter no longer exposes `useLoaderData` (standalone, route-bound, or via
21
+ `getRouteApi`): the Fig data store is the single route-data cache, so loader
22
+ values are read with `readData` against the same resource the loader ensured.
23
+ `useLoaderDeps` remains — deps are loader orchestration, not a cache.
24
+
25
+ In dev builds, a match that commits with `loaderData` set while
26
+ `router.context.data` is configured now throws a diagnostic naming the route.
27
+ Derive navigation-scoped values from `useLoaderDeps`, search params, or
28
+ `beforeLoad`-returned route context. Routers created without `context.data`
29
+ keep Router Core's native loader semantics untouched.
30
+
31
+ ### Build generated TanStack Start file routes with Fig
32
+
33
+ `@bgub/fig-tanstack-router` now implements generated file routes, lazy route
34
+ records, lazy components, and lazy loader functions. TanStack Start builds and
35
+ reloads those routes in development through its existing generator and code
36
+ splitter.
37
+
38
+ `@bgub/fig-tanstack-start` now exposes Start configuration and middleware
39
+ factories. Its demo covers request-isolated middleware context, server and
40
+ client redirects, generated error and not-found routes, split chunks, SSR,
41
+ hydration, and server-function mutations.
42
+
43
+ ### Add canonical bound route APIs
44
+
45
+ Fig routes and `getRouteApi` now provide bound match, params, search,
46
+ loader-deps, loader-data, context, navigation, link, and not-found helpers. The
47
+ adapter also adds active-match selection, reactive route matching,
48
+ `MatchRoute`, and declarative `Navigate` APIs.
49
+
50
+ ### Expand TanStack Router hook and link parity
51
+
52
+ Router selectors now honor structural sharing, including the router-wide
53
+ default, and support selected locations plus loose or optional match reads.
54
+ Links gain composable active and inactive props and render-function children
55
+ with active and transitioning state. `linkOptions` and `createRouteMask` add
56
+ zero-wrapper helpers for reusable, type-checked navigation options. A
57
+ published compatibility matrix now distinguishes the guaranteed Start surface
58
+ from compatibility, deferred, and deliberately omitted APIs.
59
+
60
+ ### Complete Fig-native data and navigation patterns
61
+
62
+ TanStack Start routes can now preload Payload data and return immediately,
63
+ letting Fig Suspense stream the result and its asset resources without copying
64
+ values into Router loader data. Initial Payload responses registered after the
65
+ document shell starts are embedded before hydration, preventing a duplicate
66
+ client request.
67
+
68
+ The Router adapter adds modern object-only `useBlocker` and reactive
69
+ `useCanGoBack` hooks, makes the concrete Router and RouteApi constructors
70
+ internal, and rejects unsupported proximity preloading in `LinkProps`.
71
+ Fig's structural `ViewTransition` remains the sole document-transition owner,
72
+ even when a TanStack navigation carries its `viewTransition` option.
73
+
74
+ ### Make data resources the router's default external cache
75
+
76
+ Put `root.data` in router context, return `ensureRouteData` from loaders, and
77
+ read the same resource with `readData` in components. Data-backed routers now
78
+ default `defaultPreloadStaleTime` to `0`, the loader helper resolves to `void`
79
+ so the value is not duplicated in `loaderData`, and route reset invalidates
80
+ attributed Fig data errors before re-running the router. The adapter also
81
+ renders Router Core's global not-found state through the root outlet.
82
+
83
+ ### Complete route match rendering semantics
84
+
85
+ Route matches now honor pending delay and minimum duration, route and default
86
+ remount dependencies, explicit Suspense wrapping, client-only and data-only SSR
87
+ policies, redirects, and router-level error reporting. Scroll restoration is
88
+ installed idempotently and emits its Start SSR bootstrap once.
89
+
90
+ ### Keep outgoing route hooks valid through unmount
91
+
92
+ Route-scoped hooks now retain their mounted match while navigation replaces the
93
+ active match list. Outgoing routes can subscribe to router state without
94
+ throwing during browser back navigation and clearing the rendered page.
95
+
96
+ ### Settle Router navigation through Fig transitions
97
+
98
+ `RouterProvider` now merges partial options and route context before the first
99
+ loader runs. Browser navigation uses Fig transitions, publishes Router's load,
100
+ mount, resolved, and rendered lifecycle events in order, ignores superseded
101
+ navigation completions, and keeps `isTransitioning` accurate while an
102
+ asynchronous navigation settles.
103
+
104
+ Hydration skips duplicate initial loads, canonical validated locations replace
105
+ the browser URL, and provider unmounts release history and transition bindings.
106
+
107
+ ### Give each matched route ownership of its Fig assets
108
+
109
+ Route stylesheets, preload hints, preconnects, font preloads, and async scripts
110
+ now enter Fig's shared asset registry at the matched subtree. This gives Start
111
+ streaming, client navigation, and Payload assets one deduplicating ownership
112
+ model while title, meta, inline styles, JSON-LD, and synchronous scripts retain
113
+ their declared document positions.
114
+
115
+ Manifest `assetCrossOrigin` configuration now belongs to `createRouter`
116
+ options, where it is available before the root match renders.
117
+
118
+ ### Define the Start-first Router support contract
119
+
120
+ The Router adapter now documents generated TanStack Start file routes as its
121
+ primary interface, distinguishes supported code-created routes from deferred
122
+ or deliberately omitted adapter conveniences, and clarifies when route data
123
+ belongs in Fig data resources versus Router `loaderData`. The package also
124
+ declares itself side-effect-free and guards the production Start-oriented
125
+ surface with a bundle-size limit.
126
+
127
+ ### Preserve framework-managed asset placement
128
+
129
+ Framework adapters can now keep externally managed head and body tags in their
130
+ declared positions without exposing a DOM prop. TanStack Router uses this for
131
+ route-managed links, styles, and scripts while continuing to map title and meta
132
+ entries through Fig asset resources. Full-document hydration now ignores the
133
+ doctype and one shared marker identifies every server-owned node without a
134
+ client fiber. Declarative asset lists also gain a client commit lifecycle, so
135
+ route titles and metadata update during navigation.
136
+
137
+ ### Add Payload routes to the TanStack Start adapter
138
+
139
+ `@bgub/fig-tanstack-start/payload` now exposes `payloadResource`, which compiles
140
+ an inline render callback into a private server function and Fig-owned route
141
+ data resource. Applications supply the cache key and component tree without
142
+ authoring transport plumbing. The shared declaration can stay in one
143
+ `.payload.tsx` module; its render callback and render-only imports are omitted
144
+ from the browser build. The initial SSR response is embedded into the document
145
+ and adopted without refetching; client navigation and refresh use the same
146
+ resource request path. Payload data rows
147
+ hydrate the shared store, asset resources are retained on their owning server
148
+ segments or inserted through the browser registry, and client references retain
149
+ their resolver-defined identity. `decodePayloadStream` and `payloadDataLoader`
150
+ now expose `retainAssets` for server document renderers that need this delivery
151
+ path.
152
+
153
+ `@bgub/fig-tanstack-start/server` exposes the lower-level
154
+ `renderPayloadResponse` used by the generated TanStack server function; it
155
+ defaults its render abort signal to the incoming request, so a disconnected
156
+ client cancels the Payload render. Shell
157
+ HTML streams while outlined Suspense holes settle, and the completed initial
158
+ responses are embedded before TanStack starts full-document hydration. The Vite
159
+ adapter also publishes assets imported only by server modules into the client
160
+ build output. Fig Router links also consume TanStack's `viewTransition`
161
+ navigation option without forwarding it as an invalid attribute to the rendered
162
+ anchor, and derive active state from the resolved route instead of an in-flight
163
+ location.
164
+
165
+ ### Add the TanStack Start runtime adapter
166
+
167
+ `createDataStore` now creates a root-neutral Fig store that route loaders can
168
+ populate before a renderer exists. Server and client renderers adopt that exact
169
+ store, preserving one cache while attaching their lifecycle and scheduling.
170
+
171
+ The new TanStack Start runtime uses the store for route loading, server
172
+ rendering, Fig-owned document serialization, client deserialization, and
173
+ hydration. Route-managed head and script output maps through the Router adapter,
174
+ including Fig asset resources. The end-to-end contract verifies no initial
175
+ client refetch and exactly one reload after invalidation.
176
+
177
+ ## @bgub/fig-tanstack-router@0.1.0-alpha.0 (alpha)
178
+
179
+ ### Initial alpha release
180
+
181
+ First public alpha release of the TanStack Router adapter for Fig.
182
+
183
+ # Changelog
@@ -0,0 +1,65 @@
1
+ # TanStack Router compatibility
2
+
3
+ `@bgub/fig-tanstack-router` targets the APIs used by generated TanStack Start
4
+ applications. It is not intended to reproduce every convenience or deprecated
5
+ alias from another framework adapter.
6
+
7
+ The conformance target is `@tanstack/router-core@1.171.15`. The owning
8
+ [concept document](https://github.com/bgub/fig/blob/main/docs/concepts/tanstack-router.md)
9
+ defines the detailed contracts and rationale; this page is the quick
10
+ compatibility reference.
11
+
12
+ ## Support levels
13
+
14
+ - **Guaranteed** — part of the adapter's supported Start-first interface and
15
+ covered by its conformance tests.
16
+ - **Compatibility** — supported, but not the recommended authoring path for a
17
+ new TanStack Start application.
18
+ - **Deferred** — useful framework-adapter convenience that may be added later.
19
+ - **Omitted** — intentionally replaced by a Fig primitive or excluded from the
20
+ adapter's contract.
21
+
22
+ ## Compatibility matrix
23
+
24
+ | Area | Level | Support |
25
+ | ---------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
26
+ | Generated routes | Guaranteed | `createFileRoute`, `createLazyFileRoute`, generated-tree mutation and type registration, `lazyRouteComponent`, and `lazyFn` |
27
+ | Code-created routes | Compatibility | `createRootRoute`, `createRootRouteWithContext`, `createRoute`, and `addChildren`; generated file routes remain recommended |
28
+ | Router setup | Guaranteed | `createRouter`, `RouterProvider`, route context, router option updates, browser/memory/hash history, and hydration-aware initial loading |
29
+ | Route APIs | Guaranteed | Route-bound hooks, `Link`, `notFound`, and `getRouteApi` |
30
+ | State and match hooks | Guaranteed | Router state, location, matches, match testing, match values, params, search, loader data/deps, route context, and navigation |
31
+ | Hook options | Guaranteed | Selectors, structural sharing, router-wide default structural sharing, `strict: false`, and optional match/params/search reads with `shouldThrow: false` |
32
+ | Navigation | Guaranteed | Imperative and declarative navigation, redirects, route masks, navigation blocking, back-history state, and Router Core lifecycle events |
33
+ | Links | Guaranteed | Native anchors, active/inactive props, render-function children, per-link transition state, disabled links, and native click semantics |
34
+ | Link preloading | Guaranteed | Intent, render, and viewport preloading |
35
+ | Proximity preloading | Deferred | `preloadIntentProximity` is rejected by `LinkProps` rather than silently ignored |
36
+ | Pending and errors | Guaranteed | Pending timing, minimum pending duration, Suspense boundaries, remount dependencies, route errors, reset, and not-found handling |
37
+ | Start SSR | Guaranteed | Route-level `ssr` policies, hydration, head output, scripts, nonce propagation, and the Start data snapshot |
38
+ | Asset resources | Guaranteed | Matched-route stylesheets, preloads, module preloads, preconnects, font preloads, and external async scripts |
39
+ | Data resources | Guaranteed | `ensureRouteData` and Start context integration for Fig-owned caching, hydration, invalidation, and streaming |
40
+ | Scroll restoration | Guaranteed | Router-level document scroll restoration and its Start SSR bootstrap |
41
+ | Element scroll restoration | Deferred | `useElementScrollRestoration` is not exported |
42
+ | Parent/child match selectors | Deferred | `useParentMatches` and `useChildMatches` are not exported; use `useMatches({ select })` when practical |
43
+ | Custom link construction | Deferred | `useLinkProps` and `createLink` are not exported; use the native `Link` interface |
44
+ | View transitions | Guaranteed | Fig `<ViewTransition>` boundaries own structural animation; Router Core's document-level wrapper is disabled to prevent nesting |
45
+ | Activity keep-alive | Omitted | Navigation transitions preserve the visible tree while loading, but resolved navigation replaces it instead of retaining inactive routes |
46
+ | Deprecated APIs | Omitted | Deprecated blocker overloads, compatibility classes, and aliases are not part of the adapter interface |
47
+
48
+ ## Fig-owned equivalents
49
+
50
+ Some framework-adapter components would duplicate existing Fig behavior, so
51
+ they are deliberately not exported:
52
+
53
+ | TanStack adapter convenience | Fig contract |
54
+ | ------------------------------ | -------------------------------------------------------------------------------------------------- |
55
+ | `Await` | `readPromise` inside `Suspense` |
56
+ | `CatchBoundary` | Fig `ErrorBoundary` plus route error/reset integration |
57
+ | `ClientOnly` | The adapter's internal hydration gate for route SSR policies |
58
+ | `ScrollRestoration` | Automatic router-level setup through `createRouter` or `RouterProvider` |
59
+ | Activity-based inactive routes | No equivalent yet; this requires an explicit keep-alive state, effect, and data-ownership contract |
60
+
61
+ ## Version upgrades
62
+
63
+ Upgrading the Router Core pin is a conformance change. Generated-route,
64
+ navigation, SSR, data, asset, and document tests must pass against the new
65
+ version before the supported target moves.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Ben Gubler
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,6 +1,289 @@
1
- # Placeholder package
2
-
3
- This empty package was published by [Tegami](https://tegami.fuma-nama.dev) to configure npm trusted publishing.
4
-
5
- The real package contents will be published via CI with OIDC.
6
-
1
+ # @bgub/fig-tanstack-router
2
+
3
+ The Fig framework adapter for TanStack Router. Route matching, loaders,
4
+ navigation, and history come from `@tanstack/router-core`; this package adds
5
+ the Fig components, hooks, native links, asset mapping, and reactive store
6
+ bridge used by TanStack Start.
7
+
8
+ Generated file routes are the recommended interface. Code-created route trees
9
+ remain supported for standalone use, but they are not the design center.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pnpm add @bgub/fig-tanstack-router @bgub/fig @bgub/fig-dom @tanstack/router-core
15
+ ```
16
+
17
+ For TanStack Start, also install `@bgub/fig-tanstack-start` and use its Vite
18
+ plugin and default entries. See the
19
+ [`@bgub/fig-tanstack-start` guide](../fig-tanstack-start/README.md) for the
20
+ complete build and hydration setup.
21
+
22
+ ## Recommended: generated file routes
23
+
24
+ TanStack Start generates `routeTree.gen.ts` from the files under `src/routes`.
25
+ Create one router and one root-neutral Fig data store around that generated
26
+ tree:
27
+
28
+ ```tsx
29
+ // src/router.tsx
30
+ import { createStartDataContext } from "@bgub/fig-tanstack-start";
31
+ import { createRouter } from "@bgub/fig-tanstack-router";
32
+ import { routeTree } from "./routeTree.gen.ts";
33
+
34
+ export function getRouter() {
35
+ return createRouter({
36
+ ...createStartDataContext(),
37
+ isServer: typeof document === "undefined",
38
+ routeTree,
39
+ });
40
+ }
41
+
42
+ export type AppRouter = ReturnType<typeof getRouter>;
43
+
44
+ declare module "@tanstack/router-core" {
45
+ interface Register {
46
+ router: AppRouter;
47
+ }
48
+ }
49
+ ```
50
+
51
+ A route file exports the generated route's configuration and receives bound,
52
+ fully typed hooks from that route:
53
+
54
+ ```tsx
55
+ // src/routes/users.$id.tsx
56
+ import { on } from "@bgub/fig-dom";
57
+ import { createFileRoute } from "@tanstack/solid-router";
58
+
59
+ export const Route = createFileRoute("/users/$id")({
60
+ validateSearch: (search): { preview?: boolean } => ({
61
+ preview: search.preview === true,
62
+ }),
63
+ loaderDeps: ({ search }) => ({ preview: search.preview === true }),
64
+ component: User,
65
+ });
66
+
67
+ function User() {
68
+ const { id } = Route.useParams();
69
+ const { preview } = Route.useLoaderDeps();
70
+ const navigate = Route.useNavigate();
71
+
72
+ return (
73
+ <article>
74
+ <Route.Link to="/">Home</Route.Link>
75
+ <button mix={on("click", () => navigate({ to: "/" }))} type="button">
76
+ Done
77
+ </button>
78
+ <p>{preview ? `Previewing ${id}` : `User ${id}`}</p>
79
+ </article>
80
+ );
81
+ }
82
+ ```
83
+
84
+ `@tanstack/solid-router` is currently a compiler-only compatibility ID. The
85
+ Start plugin maps it directly to this package; no Solid Router adapter runtime
86
+ is installed or bundled. TypeScript needs the equivalent path mapping:
87
+
88
+ ```json
89
+ {
90
+ "compilerOptions": {
91
+ "paths": {
92
+ "@tanstack/solid-router": ["./node_modules/@bgub/fig-tanstack-router"]
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ The root route normally renders Router-managed document state and Start's Fig
99
+ data snapshot before the bootstrap scripts:
100
+
101
+ ```tsx
102
+ import { StartScripts, type StartDataContext } from "@bgub/fig-tanstack-start";
103
+ import {
104
+ createRootRouteWithContext,
105
+ HeadContent,
106
+ Outlet,
107
+ } from "@bgub/fig-tanstack-router";
108
+
109
+ export const Route = createRootRouteWithContext<StartDataContext>()({
110
+ component: Document,
111
+ });
112
+
113
+ function Document() {
114
+ return (
115
+ <html lang="en">
116
+ <head>
117
+ <HeadContent />
118
+ </head>
119
+ <body>
120
+ <Outlet />
121
+ <StartScripts />
122
+ </body>
123
+ </html>
124
+ );
125
+ }
126
+ ```
127
+
128
+ Route stylesheets, preload hints, preconnects, font preloads, and async scripts
129
+ are translated into Fig asset resources owned by the matched route. Title,
130
+ meta, inline styles, JSON-LD, and synchronous scripts retain their document
131
+ position. Configure manifest cross-origin behavior on the router so it is
132
+ available before the root document renders:
133
+
134
+ ```tsx
135
+ const router = createRouter({
136
+ assetCrossOrigin: { script: "anonymous", stylesheet: "use-credentials" },
137
+ routeTree,
138
+ });
139
+ ```
140
+
141
+ `getRouteApi(routeId)` provides a route-bound interface outside the route's
142
+ own module. `useMatches` reads or selects the active match list;
143
+ `useMatchRoute` and `MatchRoute` test locations reactively; `Navigate`
144
+ performs declarative post-commit navigation. Selector hooks accept
145
+ `structuralSharing`, falling back to the router's `defaultStructuralSharing`;
146
+ location hooks accept selectors, loose hooks accept `strict: false`, and
147
+ match, params, and search reads can return `undefined` with
148
+ `shouldThrow: false`.
149
+
150
+ ## Provider and navigation lifecycle
151
+
152
+ `RouterProvider` can merge partial router options and route context into an
153
+ existing router. Initial loaders see these values on their first run, and
154
+ later provider renders preserve context fields they do not replace:
155
+
156
+ ```tsx
157
+ <RouterProvider context={{ session }} defaultPreload="intent" router={router} />
158
+ ```
159
+
160
+ Browser navigation runs in a Fig transition, keeping the previously resolved
161
+ match tree visible until loading settles. Router lifecycle subscriptions fire
162
+ in commit order: `onLoad`, `onBeforeRouteMount`, `onResolved`, then
163
+ `onRendered`. The provider skips a duplicate initial load during hydration,
164
+ normalizes validated locations in browser history, and cleans up its history
165
+ and transition bindings on unmount. A superseded navigation cannot publish a
166
+ late resolved state.
167
+
168
+ Fig structural `<ViewTransition>` boundaries own route animations. The adapter
169
+ suppresses Router Core's document wrapper, so a `viewTransition` navigation
170
+ option cannot create a second nested browser transition.
171
+
172
+ Ordinary route changes do not use `Activity`: the previous tree is replaced
173
+ after the transition. Retaining inactive route trees would require a separate
174
+ keep-alive contract for their state, effects, and data ownership.
175
+
176
+ ## Navigation blocking
177
+
178
+ `useBlocker` supports TanStack's modern object contract without its deprecated
179
+ positional overloads. Set `withResolver: true` to render explicit proceed/reset
180
+ controls; `useCanGoBack` reacts to the current history index:
181
+
182
+ ```tsx
183
+ const blocker = useBlocker({
184
+ shouldBlockFn: () => formIsDirty,
185
+ withResolver: true,
186
+ });
187
+ const canGoBack = useCanGoBack();
188
+
189
+ return blocker.status === "blocked" ? (
190
+ <nav>
191
+ <button mix={on("click", blocker.proceed)}>Discard and leave</button>
192
+ <button mix={on("click", blocker.reset)}>Stay</button>
193
+ </nav>
194
+ ) : (
195
+ <button disabled={!canGoBack} mix={on("click", () => history.back())}>
196
+ Back
197
+ </button>
198
+ );
199
+ ```
200
+
201
+ ## Route data: delegate keyed values to Fig
202
+
203
+ Fig data resources are the external cache for keyed route data — TanStack's
204
+ ["pass all loader events to an external cache"](https://tanstack.com/router/latest/docs/guide/data-loading#passing-all-loader-events-to-an-external-cache)
205
+ pattern. Router Core decides _when_ loaders run; the Fig store owns value
206
+ identity, deduplication, freshness, hydration, errors, and render-time reads.
207
+
208
+ `createStartDataContext()` places the Fig data handle at
209
+ `router.context.data`. A blocking route loader calls `ensureRouteData`, while
210
+ the component reads the same entry with `readData`:
211
+
212
+ ```tsx
213
+ import { dataResource, readData } from "@bgub/fig";
214
+ import { ensureRouteData } from "@bgub/fig-tanstack-router";
215
+ import { createFileRoute } from "@tanstack/solid-router";
216
+
217
+ const userResource = dataResource({
218
+ key: (id: string) => ["user", id],
219
+ load: async (id, { signal }) => fetchUser(id, signal),
220
+ });
221
+
222
+ export const Route = createFileRoute("/users/$id")({
223
+ loader: ({ context, params }) =>
224
+ ensureRouteData(context, userResource, params.id),
225
+ component: User,
226
+ });
227
+
228
+ function User() {
229
+ const { id } = Route.useParams();
230
+ const user = readData(userResource, id);
231
+ return <h1>{user.name}</h1>;
232
+ }
233
+ ```
234
+
235
+ `ensureRouteData` deliberately resolves to `void`, so Router Core does not
236
+ retain a second copy in `loaderData`. For non-blocking streaming, call
237
+ `context.data.preloadData(resource, ...args)` and return; the component's
238
+ `readData` suspends through Fig until the entry settles. Returning `void` lets
239
+ the route commit its Suspense fallback independently and keeps resource values
240
+ out of Router dehydration.
241
+
242
+ Loaders return `void`, and the adapter exposes no `useLoaderData`: a loader
243
+ value would be a second cache with a second wire format (Router Core retains
244
+ it per match; TanStack Start dehydrates it through its own transport). In dev
245
+ builds, a match that commits with `loaderData` set while `router.context.data`
246
+ is configured throws a diagnostic naming the route. Derive navigation-scoped
247
+ values from `useLoaderDeps`, search params, or `beforeLoad`-returned route
248
+ context; use a data resource when a value is keyed, shared, hydrated,
249
+ independently invalidated, refreshed, or streamed. Routers created without
250
+ `context.data` keep Router Core's native loader semantics untouched.
251
+
252
+ ## Support policy
253
+
254
+ See [TanStack Router compatibility](./COMPATIBILITY.md) for the feature-level
255
+ matrix and Fig equivalents for intentionally omitted adapter conveniences.
256
+
257
+ | Tier | Contract |
258
+ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
259
+ | Guaranteed | Generated file and lazy routes; typed route APIs and structural-sharing selectors; Router creation/provider; native links with active/inactive props and render-function children; navigation blocking and back-history state; loaders, redirects, route masks, not-found and route errors; pending timing and remount dependencies; route-level Start SSR policies/hydration; scroll restoration; head and script output; search/history helpers; Fig data-resource delegation. |
260
+ | Compatibility | `createRootRoute` and `createRoute` for code-created route trees. These use the same Router Core machinery but are not the recommended Start authoring path. |
261
+ | Deferred | `useElementScrollRestoration`, parent/child match selectors, custom-link construction through `useLinkProps` or `createLink`, and proximity preloading. |
262
+ | Deliberately omitted | Additional deprecated compatibility classes and aliases; public `Await`, `ClientOnly`, `CatchBoundary`, and `ScrollRestoration` clones; Activity-based keep-alive routing; `useLoaderData` (the Fig data store is the single route-data cache — read with `readData`). Fig primitives or internal adapter behavior cover these concerns. |
263
+
264
+ The adapter is pinned and tested against `@tanstack/router-core@1.171.15`.
265
+ Upgrades are conformance changes: generated-route, navigation, SSR, data, and
266
+ document tests must pass against the new version before the pin moves.
267
+
268
+ ## Native link contract
269
+
270
+ `Link` renders a native anchor. It intercepts only unmodified primary clicks;
271
+ downloads, external URLs, modifier keys, and non-`_self` targets retain native
272
+ browser behavior. Disabled links omit `href` and expose `aria-disabled`.
273
+ Preloading supports `intent`, `render`, and `viewport`, and active links expose
274
+ `aria-current="page"` plus `data-status="active"`. `activeProps` and
275
+ `inactiveProps` compose native anchor state, while render-function children
276
+ receive `isActive` and `isTransitioning`. `linkOptions` and `createRouteMask`
277
+ provide reusable typed options without runtime wrappers. Unsupported
278
+ `preloadIntentProximity` is rejected by `LinkProps` rather than silently ignored.
279
+
280
+ ## Code-created route trees
281
+
282
+ Standalone applications may still assemble a tree with `createRootRoute`,
283
+ `createRoute`, and `route.addChildren`. This compatibility surface remains
284
+ tested because it is useful for small routers and focused adapter tests. New
285
+ TanStack Start applications should use generated file routes so the generator
286
+ can provide route typing and automatic code splitting.
287
+
288
+ Construct routers and standalone route APIs with `createRouter` and
289
+ `getRouteApi`; their concrete classes are adapter internals.