Skip to content

chore(start): update h3 to 2.0.1 and srvx to 1.0.5 - #8639

Open
skyberd wants to merge 7 commits into
TanStack:mainfrom
skyberd:chore/h3-2.0.1-srvx-1
Open

skyberd wants to merge 7 commits into
TanStack:mainfrom
skyberd:chore/h3-2.0.1-srvx-1

Conversation

@skyberd

@skyberd skyberd commented Oct 8, 2026 •

Copy link
Copy Markdown

srvx has shipped a v1.0! This PR updates all the dependencies required to get Router using the v1.x sensibly; there are a few very minor tweaks and default changes made but the majority of this is just updates to the package logs.

srvx 1.0.0 is a stable re-release of 0.12.8; its breaking changes landed in 0.12.0 (renamed srvx/static and srvx/log exports), which nothing uses in Router.
NodeRequest, sendNodeResponse, toNodeHandler and FastResponse keep their signatures, and the CLI flags used by the e2e apps are unchanged.

AI Disclosure

Claude Code using Opus 5.5 Extra reasoning was used during the creation of this PR.
All code has been manually checked and comments (and this description) reworded for clarity

Updates

Router was stuck on srvx 0.11, because @tanstack/start-server-core pinned h3-v2: npm:[email protected], which depends on srvx ^0.11. h3 2.0.1 is now stable (Oct 3) and depends on srvx ^1.0.5.

A number of other dependencies had transitive dependencies on various versions of srvx so they are also updated to ensure a consistent srvx version is possible.

These could all be raised as separate PRs if wanted - but keeping the change in a single commit seems sensible to me.

Dependency updates

Package Before After Where
h3-v2 (npm:h3) 2.0.1-rc.20 2.0.1 start-server-core
srvx ^0.10 / ^0.11 ^1.0.5 start-plugin-core, e2e apps, examples (early-hints keeps its exact pin, now 1.0.5)
@vitejs/plugin-rsc ^0.5.30 ^0.5.36 react-start-rsc (dev), RSC e2e apps, start-rscs example
@mswjs/interceptors (transitive) 0.41.9 (pinned, same version MSW 2.15 uses) e2e-utils (test-only, see below)

The lockfile now has a single h3, crossws and srvx (1.0.5).

Nitro is no longer updated here: main moved to ^3.0.260903-beta in #7830. The only Nitro-related change left is in the lockfile, where its h3 dependency now resolves to 2.0.1 instead of 2.0.1-rc.32.

@vitejs/plugin-rsc 0.5.36 moved to srvx ^1.0.5 (vitejs/vite-plugin-react#1456).
react-start-rsc keeps its optional @vitejs/plugin-rsc peer range at >=0.5.30.

Required Changes

Malformed paths still respond with 400

h3 2.0.1's H3Event constructor no longer throws URIError for paths like /%80. It now only flags them for h3's own app, which Start doesn't use, so the existing catch (URIError) in requestHandler became unreachable and these requests reached the router as 404s. requestHandler now decodes the pathname itself.

Note - the helper deliberately returns the decoded value: Rolldown treats decodeURI as side-effect free and drops a call whose result is unused, even inside try (Rollup keeps it). A try { decodeURI(p); return false } catch { return true } version passed the unit tests from source but was compiled to return false in dist. Covered by new unit tests in request-response.test.ts and the existing special-characters e2e tests in React, Solid and Vue.

Behaviour changes inherited from h3 2.0.1

These surface through the request/response utilities exported from @tanstack/*-start/server. The PR currently adopts h3's new defaults and these are reflected in the changeset:

  • getRequestProtocol() / getRequestUrl() only read x-forwarded-proto when called with { xForwardedProto: true }. h3 made it opt-in because clients can spoof the header. Start could keep its old default by passing xForwardedProto: true in the wrappers.
  • Session cookies default to SameSite=Lax, which can be overridden with cookie.sameSite.
  • getSession() no longer sets a cookie for a brand-new session until it is updated; useSession() still does. Start could restore the old behaviour by calling useSession() inside its getSession() wrapper.
  • Session sealing uses 8192 PBKDF2 iterations instead of 1. Existing cookies still unseal through h3's legacySealFallback (on by default) and are re-sealed on the next request, so nobody is logged out.

Test harness: MSW preload intercepts only fetch

With h3 2.0.1, the auth-docs login e2e test failed in vite preview only. The MSW 2 preload's @mswjs/interceptors 0.41 replaces the global Headers and rebuilds a copied Headers from an empty raw-header list. h3 2.0.1 copies the response headers when it adds the session Set-Cookie, and the vite preview plugin reads response.headers, so the login response kept only set-cookie and the redirect was never followed. Without the preload, preview login works, so this is not a production issue. It is fixed upstream in @mswjs/interceptors 0.45.6 (mswjs/interceptors#850), first shipped in MSW 3.0.2.

Rather than upgrade MSW, the preload in e2e/e2e-utils/mock-api.mjs now intercepts only fetch:

  • The Headers patch comes from MSW 2's ClientRequest interceptor, which intercepts Node's http/https modules and is installed by setupServer() by default. The fetch interceptor never patches Headers.
  • All 16 e2e apps that load the preload call the mocked API with fetch, directly or through redaxios. The preload now uses MSW 2's exported SetupServerApi with only FetchInterceptor, so the mocks behave as before.
  • @mswjs/interceptors is added as a dev dependency of e2e-utils, pinned to 0.41.9, the version MSW 2.15 already uses, so there is still a single copy. The pin needs to move together with MSW.
  • An app that calls the mocked API through Node's http/https would not be mocked; the comment in mock-api.mjs notes this. When MSW is upgraded to 3, the preload can go back to setupServer().
  • The mock-api unit tests are unchanged, and the auth-docs login test runs in vite preview again.

Test results

Run locally on 878605b5e8 (Node 24.19.0, macOS) with --skip-nx-cache; e2e via nx run-many -t test:e2e --parallel=3, as in CI.

Package checks: all passed

Package Unit Types (TS 5.6–7.0) ESLint Build + publint/attw
start-server-core ✅ 255 ✅ ✅ ✅
start-plugin-core ✅ 580 (+1 existing test.fails) ✅ ✅ ✅
react-start-server no tests ✅ ✅ ✅
solid-start-server no tests ✅ ✅ ✅
vue-start-server no tests ✅ ✅ ✅
react-start-rsc ✅ 61 ✅ ✅ ✅
react-start – – – ✅
solid-start ✅ 4 – – ✅
vue-start – – – ✅
router-e2e-utils (private) ✅ 9 – ✅ ✅ (build)

e2e: every React, Solid and Vue Start e2e app, all modes and shards

Framework Apps Playwright runs Passed Skipped Failed Flaky
React Start 39 98 2,820 66 0 0
Solid Start 21 29 650 12 0 0
Vue Start 18 24 575 9 0 0
Total 78 151 4,045 87 0 0

Skipped tests are existing mode-specific skips. react-start/basic-auth and react-start/clerk-basic have e2e disabled in the repo (exit 0), and react-start/flamegraph-bench has no e2e target. Router-only e2e apps were not run: they do not use the changed server code, and their browser-side MSW fixture is unchanged from main.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested code changes locally with the relevant test commands, or tests do not apply to this pull request.
  • I fully understand the code in this pull request, including any code generated with AI assistance.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.

Summary by CodeRabbit

  • Bug Fixes
    • Malformed percent-encoded request paths now receive a 400 Bad Request response, while valid encoded paths continue to work.
  • New Features
    • Forwarded-protocol handling can be enabled explicitly.
    • Session cookie defaults and creation timing are updated, with improved session-sealing compatibility.
  • Compatibility
    • Updated server handling components to stable releases, including support for the latest h3 and srvx versions.

@changeset-bot

changeset-bot Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 0a8ba16

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@tanstack/start-server-core Patch
@tanstack/start-plugin-core Patch
@tanstack/react-start-server Patch
@tanstack/react-start Patch
@tanstack/solid-start-server Patch
@tanstack/solid-start Patch
@tanstack/vue-start-server Patch
@tanstack/vue-start Patch
@tanstack/react-start-rsc Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: TanStack/router/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 77ea70b9-3dac-4ac6-812a-37634ac86028


📥 Commits

Reviewing files that changed from the base of the PR and between 2dc38e2 and 0a8ba16.



⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml


📒 Files selected for processing (7)
  • e2e/react-start/css-modules/package.json
  • e2e/react-start/dev-ssr-styles/package.json
  • e2e/react-start/flamegraph-bench/package.json
  • e2e/solid-start/dev-ssr-styles/package.json
  • e2e/vue-start/dev-ssr-styles/package.json
  • examples/react/start-rscs/package.json
  • packages/start-server-core/src/request-response.ts


🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/react/start-rscs/package.json


Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.




📝 Walkthrough
📝 Walkthrough

Walkthrough

The pull request updates h3, srvx, and @vitejs/plugin-rsc versions across packages and examples. It adds malformed-path checks to requestHandler and limits the mock API server to fetch interception.

Changes

Server runtime updates

Layer / File(s) Summary
Runtime dependency alignment and release notes
packages/*/package.json, e2e/*-start/*/package.json, examples/react/*/package.json, .changeset/h3-srvx-stable.md
The manifests update h3, srvx, and @vitejs/plugin-rsc versions. The changeset records patch releases and notes about the dependency updates and related behavior.
Malformed request path handling
packages/start-server-core/src/request-response.ts, packages/start-server-core/tests/request-response.test.ts
requestHandler returns an empty 400 response when a percent-containing pathname cannot be decoded, without calling the handler. Tests cover malformed paths and a valid percent-encoded Korean path. The request URL and protocol documentation describes x-forwarded-proto use when xForwardedProto is true.

Mock API fetch interception

Layer / File(s) Summary
Fetch-only mock API setup
e2e/e2e-utils/mock-api.mjs, e2e/e2e-utils/package.json
The mock server uses FetchInterceptor and retains bypass behavior for unhandled requests. The package adds @mswjs/interceptors as a development dependency.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Other

Suggested reviewers: schiller-manuel



Merge Risk: ⚪ Minimal · up to 0a8ba

No actionable merge-blocking risk is established; the change is ready for normal merge checks.

Pre-merge checks | Passed 4 | Failed 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 3 files. (6 skipped: 6… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description check Passed The description clearly explains the dependency updates, code changes, test results, AI disclosure, checklist items, and release impact. It follows the required template and provides sufficient implem…
Title check Passed The title clearly summarizes the primary dependency updates to h3 and srvx. It is concise and directly related to the changeset.

Full details: Docstring Coverage

Explanation

Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 3 files. (6 skipped: 6 unsupported.)


  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR



  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@socket-security

socket-security Bot commented Oct 8, 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
Updatedh3@​2.0.1-rc.32 ⏵ 2.0.19910088 +19680
Updated@​vitejs/​plugin-rsc@​0.5.30 ⏵ 0.5.3699100100 +196100

View full report

@skyberd
skyberd force-pushed the chore/h3-2.0.1-srvx-1 branch from 18a2dc3 to 878605b Compare October 8, 2026 11:10
@skyberd skyberd changed the title chore(start): update h3 to 2.0.1, srvx to 1.0.5, Nitro and MSW 3 chore(start): update h3 to 2.0.1, srvx to 1.0.5 and Nitro Oct 8, 2026
@skyberd
skyberd force-pushed the chore/h3-2.0.1-srvx-1 branch from 228a427 to 878605b Compare October 8, 2026 12:09
@skyberd
skyberd marked this pull request as ready for review October 8, 2026 12:13
skyberd and others added 7 commits October 10, 2026 10:10
…st beta

- Bump h3-v2 to npm:[email protected], srvx to ^1.0.5 and nitro to
  ^3.0.260903-beta across packages, examples and e2e apps. The only
  remaining srvx 0.x copy comes from @vitejs/plugin-rsc.
- h3 2.0.1 no longer throws on malformed percent-encoded paths, so
  requestHandler checks the pathname itself and keeps responding 400.
  The decoded value is used so bundlers cannot drop the decodeURI call.
- Mark the auth-docs login e2e test as fixme under vite preview: the
  MSW 2.x preload drops copied response headers
  (mswjs/interceptors#850, fixed in MSW 3.0.2).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
0.5.36 depends on srvx ^1.0.5 (vitejs/vite-plugin-react#1456), so the
lockfile now resolves a single srvx. react-start-rsc keeps its optional
peer range at >=0.5.30; older versions still work with their own srvx copy.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
… URL helpers

h3 2.0.1 only reads `x-forwarded-proto` when `xForwardedProto: true` is
passed, so the JSDoc for `getRequestUrl()` and `getRequestProtocol()` no
longer describes it as the default. Add the same trusted-proxy note that
`getRequestIP()` has for `xForwardedFor`.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
The MSW 2 preload installs the @mswjs/interceptors ClientRequest
interceptor, which replaces the global `Headers` and rebuilds a copied
`Headers` from an empty raw-header list (mswjs/interceptors#850). h3 2.0.1
copies response headers when it adds pending ones (e.g. a session
`Set-Cookie`), so under vite preview the auth-docs login response kept
only `set-cookie` and the redirect was never followed.

The e2e apps only call the mocked API with `fetch`, so the preload now
uses `SetupServerApi` with just the `FetchInterceptor`, which never
patches `Headers`. `@mswjs/interceptors` is pinned to the version
MSW 2.15 uses. The auth-docs login test runs in vite preview again.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Add JSDoc to the two functions touched by this PR that had none, and
restore the x-forwarded-proto note on getRequestUrl.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@skyberd
skyberd force-pushed the chore/h3-2.0.1-srvx-1 branch from 2dc38e2 to 0a8ba16 Compare October 10, 2026 09:19
@skyberd skyberd changed the title chore(start): update h3 to 2.0.1, srvx to 1.0.5 and Nitro chore(start): update h3 to 2.0.1 and srvx to 1.0.5 Oct 10, 2026

This branch has not been deployed

No deployments
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.

1 participant