Skip to content

feat(solid): named single-flight source + loadFlightTarget, the cache-agnostic trigger - #8192

Merged
brenelz merged 8 commits into
TanStack:solid-router-v2-prefrom
ryansolid:feat/named-flight-source
Sep 2, 2026
Merged

feat(solid): named single-flight source + loadFlightTarget, the cache-agnostic trigger#8192
brenelz merged 8 commits into
TanStack:solid-router-v2-prefrom
ryansolid:feat/named-flight-source

Conversation

@ryansolid

@ryansolid ryansolid commented Aug 29, 2026

Copy link
Copy Markdown

Requires solid-js / @solidjs/web 2.0.0-rc.6 (released) — the branch bumps the Start packages and e2e apps to rc.6 and floors the peer range there. Stacked on #8193 (merge that first): the retired setupRouterSsrQueryIntegration breaks on rc.6, so the e2e apps must be on the userland glue before this lands.

Summary

Solid's single-flight channel is multi-source: a mutation response carries a keyed envelope of per-cache slices, each routed to the consumer subscribed under its source id. Previously Start claimed the single unnamed slot on both halves — so any other cache wanting mutation-response data (e.g. solid-query, whose provider subscribes under "sq" in TanStack/query#11326) displaced the router's flight data: whichever library registered last silently won.

This PR moves the router's flight data onto its own source id ("tsr"):

  • Server: collectSolidStartFlightData registers additively via registerFlightDataSource(SOLID_START_FLIGHT_SOURCE, ...) instead of claiming the per-handler unnamed slot. A user-supplied collectFlightData option now keeps the unnamed slot to itself — its data folds alongside the router's rather than replacing it.
  • Client: the flight consumer subscribes under the same id and receives exactly the router's slice of the keyed envelope.

Net effect: a Start app using solid-query gets router loader/match refresh and query-cache hydration from one mutation round trip, with no coordination between the libraries.

loadFlightTarget: the trigger as a public primitive

The factoring behind multi-source flight is: the router owns the trigger (running the matched routes' data functions for the URL the client will show after the mutation), each cache owns its slice (what to extract from the loaded state). This PR makes the trigger public — loadFlightTarget in @tanstack/solid-router/ssr/server:

import { registerFlightDataSource } from '@solidjs/web/server-functions/server'
import { loadFlightTarget } from '@tanstack/solid-router/ssr/server'
import { FLIGHT_DATA_SOURCE, dehydrateSettled } from '@tanstack/solid-query'

registerFlightDataSource(FLIGHT_DATA_SOURCE, (event, outcome) => {
  if (!outcome.targetUrl) return undefined
  const queryClient = createQueryClient()
  return loadFlightTarget({
    router: createAppRouter(queryClient),
    event,
    outcome,
    collect: async () => {
      const state = await dehydrateSettled(queryClient)
      return state.queries.length > 0 ? state : undefined
    },
  })
})

It derives the flight request (the outcome's pre-digested targetUrl, the mutation's cookie effects already folded in), points the router at the target through a fresh memory history, runs router.load() inside the flight request-event scope, and hands the loaded router to collect. Errors are contained per Solid Router's own collector convention — flight data is an optimization, so a failure omits the slice rather than surfacing as a mutation error (core also contains per-source: solidjs/solid@ec523607).

Start's tsr collector consumes the same primitive, keeping only its bespoke halves: start-context acquisition, its serialized-redirect target resolution, and match-state extraction.

Known divergence from Solid Router's collector, deliberate for now: outcome.revalidateKeys scoping isn't honored — it comes from Solid's X-Revalidate convention, which TanStack mutations don't produce.

Pre-landing checklist (rc.6 shipped — all done)

  • Delete the feature detection in solid-rpc-flight-client.ts (getFlightDataSourceIds probe) — subscribes directly under SOLID_START_FLIGHT_SOURCE.
  • Delete the legacy fallback in server-functions-handler.ts (the unnamed collectFlightData-slot assignment) — registers via registerFlightDataSource unconditionally.
  • Bump the @solidjs/web peer floor — floored at rc.6 rather than rc.5, since rc.5's settle-walk regression breaks the solid-query pairing this protocol exists for.
  • Bump Start packages and solid-start e2e apps to solid rc.6 (manifests + lockfile; the branch previously had a manifest/lockfile mismatch).

Compatibility

  • The named-source protocol requires @solidjs/web 2.0.0-rc.6+ on both halves; client and server resolve the same install, so the halves cannot disagree.
  • The existing isSolidStartFlightData shape guard stays — redundant-but-harmless under named sources.

Verification

Made with Cursor

@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 1e3920bd-a2b7-42e5-92a9-53bfcde019b7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ryansolid ryansolid changed the title feat(solid-start): named single-flight source for router flight data feat(solid): named single-flight source + loadFlightTarget, the cache-agnostic trigger Aug 29, 2026
…els carry the Router + Query pairing

solid-query v6's QueryClientProvider serializes the request's cache into
Solid's hydration registry during SSR and primes the client cache from
it, so running the ssr-query transport alongside it ships every query
payload twice. The package's two runtime conveniences are each a few
lines of userland composition on public APIs: the provider wrap via the
router's Wrap option, and cache-driven redirect() errors handed to
router.navigate from the caches' config.onError.

Converts the three Solid Start e2e apps to the composition (all suites
green, including the redirect-from-query tests) and marks the package
deprecated for the v2 line.

Co-authored-by: Cursor <cursoragent@cursor.com>
@nx-cloud

nx-cloud Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 6c51a06

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ❌ Failed 10m 15s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 47s View ↗

☁️ Nx Cloud last updated this comment at 2026-09-02 22:52:22 UTC

@pkg-pr-new

pkg-pr-new Bot commented Aug 29, 2026

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/@tanstack/arktype-adapter@8192

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/@tanstack/eslint-plugin-router@8192

@tanstack/eslint-plugin-start

npm i https://pkg.pr.new/@tanstack/eslint-plugin-start@8192

@tanstack/history

npm i https://pkg.pr.new/@tanstack/history@8192

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/@tanstack/nitro-v2-vite-plugin@8192

@tanstack/react-router

npm i https://pkg.pr.new/@tanstack/react-router@8192

@tanstack/react-router-devtools

npm i https://pkg.pr.new/@tanstack/react-router-devtools@8192

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/@tanstack/react-router-ssr-query@8192

@tanstack/react-start

npm i https://pkg.pr.new/@tanstack/react-start@8192

@tanstack/react-start-client

npm i https://pkg.pr.new/@tanstack/react-start-client@8192

@tanstack/react-start-rsc

npm i https://pkg.pr.new/@tanstack/react-start-rsc@8192

@tanstack/react-start-server

npm i https://pkg.pr.new/@tanstack/react-start-server@8192

@tanstack/router-cli

npm i https://pkg.pr.new/@tanstack/router-cli@8192

@tanstack/router-core

npm i https://pkg.pr.new/@tanstack/router-core@8192

@tanstack/router-devtools

npm i https://pkg.pr.new/@tanstack/router-devtools@8192

@tanstack/router-devtools-core

npm i https://pkg.pr.new/@tanstack/router-devtools-core@8192

@tanstack/router-generator

npm i https://pkg.pr.new/@tanstack/router-generator@8192

@tanstack/router-plugin

npm i https://pkg.pr.new/@tanstack/router-plugin@8192

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/@tanstack/router-ssr-query-core@8192

@tanstack/router-utils

npm i https://pkg.pr.new/@tanstack/router-utils@8192

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/@tanstack/router-vite-plugin@8192

@tanstack/solid-router

npm i https://pkg.pr.new/@tanstack/solid-router@8192

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/@tanstack/solid-router-devtools@8192

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/@tanstack/solid-router-ssr-query@8192

@tanstack/solid-start

npm i https://pkg.pr.new/@tanstack/solid-start@8192

@tanstack/solid-start-client

npm i https://pkg.pr.new/@tanstack/solid-start-client@8192

@tanstack/solid-start-server

npm i https://pkg.pr.new/@tanstack/solid-start-server@8192

@tanstack/start-client-core

npm i https://pkg.pr.new/@tanstack/start-client-core@8192

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/@tanstack/start-fn-stubs@8192

@tanstack/start-plugin-core

npm i https://pkg.pr.new/@tanstack/start-plugin-core@8192

@tanstack/start-server-core

npm i https://pkg.pr.new/@tanstack/start-server-core@8192

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/@tanstack/start-static-server-functions@8192

@tanstack/start-storage-context

npm i https://pkg.pr.new/@tanstack/start-storage-context@8192

@tanstack/valibot-adapter

npm i https://pkg.pr.new/@tanstack/valibot-adapter@8192

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/@tanstack/virtual-file-routes@8192

@tanstack/vue-router

npm i https://pkg.pr.new/@tanstack/vue-router@8192

@tanstack/vue-router-devtools

npm i https://pkg.pr.new/@tanstack/vue-router-devtools@8192

@tanstack/vue-router-ssr-query

npm i https://pkg.pr.new/@tanstack/vue-router-ssr-query@8192

@tanstack/vue-start

npm i https://pkg.pr.new/@tanstack/vue-start@8192

@tanstack/vue-start-client

npm i https://pkg.pr.new/@tanstack/vue-start-client@8192

@tanstack/vue-start-server

npm i https://pkg.pr.new/@tanstack/vue-start-server@8192

@tanstack/zod-adapter

npm i https://pkg.pr.new/@tanstack/zod-adapter@8192

commit: 6c51a06

nx-cloud[bot]

This comment was marked as outdated.

@codspeed-hq

codspeed-hq Bot commented Aug 29, 2026

Copy link
Copy Markdown

Hooray! CodSpeed harness just leveled up!

The base and head of this comparison were measured with different runner settings, so their benchmark values are not directly comparable.

What changed between base and head:

Re-run the base with the same settings to get a valid performance comparison.


Comparing ryansolid:feat/named-flight-source (6c51a06) with solid-router-v2-pre (67a9040)1

Open in CodSpeed

Footnotes

  1. No successful run was found on solid-router-v2-pre (5a6935f) during the generation of this report, so 67a9040 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@ryansolid

Copy link
Copy Markdown
Author

Pushed two additions: refactor(solid-start): require named flight sources, drop the pre-rc.5 fallback (the runtime now assumes solid-js 2.0.0-rc.5+, where two-argument subscribeFlightData and registerFlightDataSource exist) and the e2e expectation update for the named X-Single-Flight: tsr header. This PR is the base of a stack: #8213 (native SSR match transfer) and #8214 (Solid-owned transport/payload) build on it.

@ryansolid
ryansolid force-pushed the feat/named-flight-source branch from 356e016 to 6b5dea0 Compare September 2, 2026 20:45
@socket-security

socket-security Bot commented Sep 2, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updated@​solidjs/​web@​2.0.0-rc.4 ⏵ 2.0.0-rc.6100 +110083 +197 +1100
Updatedsolid-js@​2.0.0-rc.4 ⏵ 2.0.0-rc.6100 +110095 +196 +1100

View full report

ryansolid and others added 5 commits September 2, 2026 14:14
Co-authored-by: Cursor <cursoragent@cursor.com>
Solid's single-flight channel is becoming multi-source (solidjs/solid
653dd41e): mutation responses carry a keyed envelope of per-cache
slices, each routed to the consumer subscribed under its source id.
Today Start claims the single unnamed slot on both halves, which means
any other cache wanting mutation-response data (e.g. solid-query, whose
provider subscribes under "sq" in TanStack/query#11326) displaces the
router's — whichever registers last wins, silently.

The router's flight data now rides its own source id ("tsr"): the
server collector registers additively with registerFlightDataSource and
the client subscribes its consumer under the same id, so router
loader/match state and other caches' slices coexist on one round trip.
A user-supplied collectFlightData hook keeps the unnamed slot to itself,
adding data alongside the router's instead of displacing it.

Both halves feature-detect the protocol on the installed @solidjs/web
(it ships in the release after 2.0.0-rc.4) and fall back to the exact
previous unnamed-slot behavior on older versions; since client and
server resolve the same install, the halves cannot disagree.

Co-authored-by: Cursor <cursoragent@cursor.com>
…t trigger

The router's half of flight collection as a public primitive: derive the
flight request for the mutation's target, run the matched routes' data
functions, hand the loaded router to the caller's collect() — any cache
(the router's own state, a query client) composes its extraction on top.
Start's collector now consumes it; errors are contained per Solid
Router's collector convention (flight data is an optimization, never a
mutation error).

Co-authored-by: Cursor <cursoragent@cursor.com>
…5 fallback

@solidjs/web 2.0.0-rc.5 ships the multi-source single-flight protocol, so
the feature detection and cast shims bridging unreleased types come out:
the client subscribes directly under SOLID_START_FLIGHT_SOURCE, the server
registers its collector via registerFlightDataSource unconditionally (the
unnamed collectFlightData slot now always belongs to the user), and the
@solidjs/web peer floor moves to rc.5.

Co-authored-by: Cursor <cursoragent@cursor.com>
With the pre-rc.5 fallback stripped, the client advertises its named
source and the server echoes what it folded: X-Single-Flight is "tsr" on
both sides, not the legacy "true".

Co-authored-by: Cursor <cursoragent@cursor.com>
@ryansolid
ryansolid force-pushed the feat/named-flight-source branch 2 times, most recently from 62c7702 to 1f6e3d9 Compare September 2, 2026 21:23
@ryansolid
ryansolid marked this pull request as ready for review September 2, 2026 21:24
@brenelz

brenelz commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Benchmarks are failing with

 TypeError: registerFlightDataSource is not a function
     ❯ dist/server/server.js:6938:25
        6936|  endpoint: "/_serverFn/"
        6937| });
        6938| registerFlightDataSource("tsr", collectSolidStartFlightData);
           |                         ^
        6939| var solidNoJSHandler = createNoJSHandler();
        6940| async function handleSolidServerFunctionRequest(request, options = {})…
        ````

@brenelz

brenelz commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

And some e2e with

[MISSING_EXPORT] "registerFlightDataSource" is not exported by "../../../node_modules/.pnpm/@solidjs+web@2.0.0-rc.4_solid-js@2.0.0-rc.4/node_modules/@solidjs/web/server-functions/dist/server.js".
╭─[ node_modules/.nitro/vite/services/ssr/index.js:8:114 ]

…rc.6

Repo-wide (packages, examples, e2e apps, benchmarks) — a scoped bump
leaves the workspace mixed, and examples/benchmarks then build workspace
solid-start dists (which import registerFlightDataSource, rc.5+) against
their own @solidjs/web rc.4 resolution. rc.6 ships the named flight-data
source API this branch requires plus the settle-walk fix that unblocks
the Solid Query pairing. @tanstack/solid-start's peer floor moves to
rc.6.

The SSR bench helpers move onto rc.6's wire shape: scripted callers use
the data address (`<endpoint>/data/<id>`) — the bare address now answers
document traffic with the no-JS convention.

Co-authored-by: Cursor <cursoragent@cursor.com>
@ryansolid
ryansolid force-pushed the feat/named-flight-source branch from 1f6e3d9 to 21b2fc6 Compare September 2, 2026 22:15

@nx-cloud nx-cloud Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nx Cloud is proposing a fix for your failed CI:

We updated all createEffect usages in the solid example apps to match the breaking API change introduced in solid-js rc.6, where the function now requires two mandatory arguments (a reactive compute phase and a separate effectFn phase) instead of the previous single-callback form. These changes fix the TS2554: Expected 2-3 arguments, but got 1 TypeScript errors that caused four example build tasks to fail after the PR bumped solid-js from rc.4 to rc.6 without updating the call sites.

Tip

We verified this fix by re-running tanstack-router-solid-example-kitchen-sink-solid-query:build, tanstack-router-solid-example-basic-solid-query:build, tanstack-router-solid-example-basic-solid-query-file-based:build and 2 more.

Warning

The suggested diff is too large to display here, but you can view it on Nx Cloud ↗


Because this branch comes from a fork, it is not possible for us to apply fixes directly, but you can apply the changes locally using the available options below.

Apply changes locally with:

npx nx-cloud apply-locally 4KrC-XYcS

Apply fix locally with your editor ↗   View interactive diff ↗



🎓 Learn more about Self-Healing CI on nx.dev

@brenelz
brenelz merged commit 96f50d9 into TanStack:solid-router-v2-pre Sep 2, 2026
23 of 26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants