From 4680094a4baba4bc704c5bf34eb08f182f468f7b Mon Sep 17 00:00:00 2001 From: Avi Vahl Date: Wed, 22 Jul 2026 17:09:32 +0300 Subject: [PATCH 1/5] feat: allow typescript@7 to be used with react-router (#15317) extend the peer dep range to allow typescript v7 repository itself wasn't upgraded to the new version, as it uses typescript-eslint and the programmatic api in dev time (`scripts/docs.ts` and `packages/react-router-dev/__tests__/rsc-virtual-route-modules-test.ts`) --- .../.changes/patch.allow-typescript7-used.md | 1 + packages/react-router-architect/package.json | 2 +- .../.changes/patch.allow-typescript7-used.md | 1 + packages/react-router-cloudflare/package.json | 2 +- .../react-router-dev/.changes/patch.allow-typescript7-used.md | 1 + packages/react-router-dev/package.json | 2 +- .../.changes/patch.allow-typescript7-used.md | 1 + packages/react-router-express/package.json | 2 +- .../.changes/patch.allow-typescript7-used.md | 1 + packages/react-router-fs-routes/package.json | 2 +- .../react-router-node/.changes/patch.allow-typescript7-used.md | 1 + packages/react-router-node/package.json | 2 +- .../.changes/patch.allow-typescript7-used.md | 1 + packages/react-router-remix-routes-option-adapter/package.json | 2 +- 14 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 packages/react-router-architect/.changes/patch.allow-typescript7-used.md create mode 100644 packages/react-router-cloudflare/.changes/patch.allow-typescript7-used.md create mode 100644 packages/react-router-dev/.changes/patch.allow-typescript7-used.md create mode 100644 packages/react-router-express/.changes/patch.allow-typescript7-used.md create mode 100644 packages/react-router-fs-routes/.changes/patch.allow-typescript7-used.md create mode 100644 packages/react-router-node/.changes/patch.allow-typescript7-used.md create mode 100644 packages/react-router-remix-routes-option-adapter/.changes/patch.allow-typescript7-used.md diff --git a/packages/react-router-architect/.changes/patch.allow-typescript7-used.md b/packages/react-router-architect/.changes/patch.allow-typescript7-used.md new file mode 100644 index 0000000000..5cfef3ce2d --- /dev/null +++ b/packages/react-router-architect/.changes/patch.allow-typescript7-used.md @@ -0,0 +1 @@ +allow typescript@7 to be used diff --git a/packages/react-router-architect/package.json b/packages/react-router-architect/package.json index 0cc770f96b..314028e174 100644 --- a/packages/react-router-architect/package.json +++ b/packages/react-router-architect/package.json @@ -61,7 +61,7 @@ "peerDependencies": { "@react-router/node": "workspace:^", "react-router": "workspace:^", - "typescript": "^5.1.0 || ^6.0.0" + "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0" }, "peerDependenciesMeta": { "typescript": { diff --git a/packages/react-router-cloudflare/.changes/patch.allow-typescript7-used.md b/packages/react-router-cloudflare/.changes/patch.allow-typescript7-used.md new file mode 100644 index 0000000000..5cfef3ce2d --- /dev/null +++ b/packages/react-router-cloudflare/.changes/patch.allow-typescript7-used.md @@ -0,0 +1 @@ +allow typescript@7 to be used diff --git a/packages/react-router-cloudflare/package.json b/packages/react-router-cloudflare/package.json index 44b10eb9c3..338e249950 100644 --- a/packages/react-router-cloudflare/package.json +++ b/packages/react-router-cloudflare/package.json @@ -50,7 +50,7 @@ "peerDependencies": { "@cloudflare/workers-types": "^4.0.0", "react-router": "workspace:^", - "typescript": "^5.1.0 || ^6.0.0" + "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0" }, "peerDependenciesMeta": { "typescript": { diff --git a/packages/react-router-dev/.changes/patch.allow-typescript7-used.md b/packages/react-router-dev/.changes/patch.allow-typescript7-used.md new file mode 100644 index 0000000000..5cfef3ce2d --- /dev/null +++ b/packages/react-router-dev/.changes/patch.allow-typescript7-used.md @@ -0,0 +1 @@ +allow typescript@7 to be used diff --git a/packages/react-router-dev/package.json b/packages/react-router-dev/package.json index 68460fe48f..b17fcab9b9 100644 --- a/packages/react-router-dev/package.json +++ b/packages/react-router-dev/package.json @@ -144,7 +144,7 @@ "@vitejs/plugin-rsc": "catalog:", "react-router": "workspace:^", "react-server-dom-webpack": "catalog:", - "typescript": "^5.1.0 || ^6.0.0", + "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0", "vite": "^7.0.0 || ^8.0.0", "wrangler": "^4.0.0" }, diff --git a/packages/react-router-express/.changes/patch.allow-typescript7-used.md b/packages/react-router-express/.changes/patch.allow-typescript7-used.md new file mode 100644 index 0000000000..5cfef3ce2d --- /dev/null +++ b/packages/react-router-express/.changes/patch.allow-typescript7-used.md @@ -0,0 +1 @@ +allow typescript@7 to be used diff --git a/packages/react-router-express/package.json b/packages/react-router-express/package.json index 92d36d8ece..c48130c2d9 100644 --- a/packages/react-router-express/package.json +++ b/packages/react-router-express/package.json @@ -57,7 +57,7 @@ "peerDependencies": { "express": "^4.22.2 || ^5", "react-router": "workspace:*", - "typescript": "^5.1.0 || ^6.0.0" + "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0" }, "peerDependenciesMeta": { "typescript": { diff --git a/packages/react-router-fs-routes/.changes/patch.allow-typescript7-used.md b/packages/react-router-fs-routes/.changes/patch.allow-typescript7-used.md new file mode 100644 index 0000000000..5cfef3ce2d --- /dev/null +++ b/packages/react-router-fs-routes/.changes/patch.allow-typescript7-used.md @@ -0,0 +1 @@ +allow typescript@7 to be used diff --git a/packages/react-router-fs-routes/package.json b/packages/react-router-fs-routes/package.json index d220813406..cb9ecbd4df 100644 --- a/packages/react-router-fs-routes/package.json +++ b/packages/react-router-fs-routes/package.json @@ -51,7 +51,7 @@ }, "peerDependencies": { "@react-router/dev": "workspace:^", - "typescript": "^5.1.0 || ^6.0.0" + "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0" }, "peerDependenciesMeta": { "typescript": { diff --git a/packages/react-router-node/.changes/patch.allow-typescript7-used.md b/packages/react-router-node/.changes/patch.allow-typescript7-used.md new file mode 100644 index 0000000000..5cfef3ce2d --- /dev/null +++ b/packages/react-router-node/.changes/patch.allow-typescript7-used.md @@ -0,0 +1 @@ +allow typescript@7 to be used diff --git a/packages/react-router-node/package.json b/packages/react-router-node/package.json index 27f09bfe2a..1cf18672dd 100644 --- a/packages/react-router-node/package.json +++ b/packages/react-router-node/package.json @@ -53,7 +53,7 @@ }, "peerDependencies": { "react-router": "workspace:*", - "typescript": "^5.1.0 || ^6.0.0" + "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0" }, "peerDependenciesMeta": { "typescript": { diff --git a/packages/react-router-remix-routes-option-adapter/.changes/patch.allow-typescript7-used.md b/packages/react-router-remix-routes-option-adapter/.changes/patch.allow-typescript7-used.md new file mode 100644 index 0000000000..5cfef3ce2d --- /dev/null +++ b/packages/react-router-remix-routes-option-adapter/.changes/patch.allow-typescript7-used.md @@ -0,0 +1 @@ +allow typescript@7 to be used diff --git a/packages/react-router-remix-routes-option-adapter/package.json b/packages/react-router-remix-routes-option-adapter/package.json index bad639636c..33625163b4 100644 --- a/packages/react-router-remix-routes-option-adapter/package.json +++ b/packages/react-router-remix-routes-option-adapter/package.json @@ -47,7 +47,7 @@ }, "peerDependencies": { "@react-router/dev": "workspace:^", - "typescript": "^5.1.0 || ^6.0.0" + "typescript": "^5.1.0 || ^6.0.0 || ^7.0.0" }, "peerDependenciesMeta": { "typescript": { From 687ab72dddcc19d2fc749f992fe29789ba13daad Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Wed, 22 Jul 2026 11:00:13 -0400 Subject: [PATCH 2/5] Prep release notes --- .../.changes/patch.allow-typescript7-used.md | 2 +- .../.changes/patch.allow-typescript7-used.md | 2 +- .../.changes/patch.allow-typescript7-used.md | 2 +- .../.changes/patch.allow-typescript7-used.md | 2 +- .../.changes/patch.allow-typescript7-used.md | 2 +- .../.changes/patch.allow-typescript7-used.md | 2 +- .../.changes/patch.allow-typescript7-used.md | 2 +- .../.changes/patch.rsc-client-loader-revalidation.md | 2 +- packages/react-router/.changes/patch.rsc-csrf.md | 2 +- .../react-router/.changes/patch.rsc-html-stream-cancel.md | 4 +++- scripts/changes/whats-changed.md | 5 +++++ 11 files changed, 17 insertions(+), 10 deletions(-) create mode 100644 scripts/changes/whats-changed.md diff --git a/packages/react-router-architect/.changes/patch.allow-typescript7-used.md b/packages/react-router-architect/.changes/patch.allow-typescript7-used.md index 5cfef3ce2d..104eae9eaa 100644 --- a/packages/react-router-architect/.changes/patch.allow-typescript7-used.md +++ b/packages/react-router-architect/.changes/patch.allow-typescript7-used.md @@ -1 +1 @@ -allow typescript@7 to be used +Allow `typescript@7` to be used diff --git a/packages/react-router-cloudflare/.changes/patch.allow-typescript7-used.md b/packages/react-router-cloudflare/.changes/patch.allow-typescript7-used.md index 5cfef3ce2d..104eae9eaa 100644 --- a/packages/react-router-cloudflare/.changes/patch.allow-typescript7-used.md +++ b/packages/react-router-cloudflare/.changes/patch.allow-typescript7-used.md @@ -1 +1 @@ -allow typescript@7 to be used +Allow `typescript@7` to be used diff --git a/packages/react-router-dev/.changes/patch.allow-typescript7-used.md b/packages/react-router-dev/.changes/patch.allow-typescript7-used.md index 5cfef3ce2d..104eae9eaa 100644 --- a/packages/react-router-dev/.changes/patch.allow-typescript7-used.md +++ b/packages/react-router-dev/.changes/patch.allow-typescript7-used.md @@ -1 +1 @@ -allow typescript@7 to be used +Allow `typescript@7` to be used diff --git a/packages/react-router-express/.changes/patch.allow-typescript7-used.md b/packages/react-router-express/.changes/patch.allow-typescript7-used.md index 5cfef3ce2d..104eae9eaa 100644 --- a/packages/react-router-express/.changes/patch.allow-typescript7-used.md +++ b/packages/react-router-express/.changes/patch.allow-typescript7-used.md @@ -1 +1 @@ -allow typescript@7 to be used +Allow `typescript@7` to be used diff --git a/packages/react-router-fs-routes/.changes/patch.allow-typescript7-used.md b/packages/react-router-fs-routes/.changes/patch.allow-typescript7-used.md index 5cfef3ce2d..104eae9eaa 100644 --- a/packages/react-router-fs-routes/.changes/patch.allow-typescript7-used.md +++ b/packages/react-router-fs-routes/.changes/patch.allow-typescript7-used.md @@ -1 +1 @@ -allow typescript@7 to be used +Allow `typescript@7` to be used diff --git a/packages/react-router-node/.changes/patch.allow-typescript7-used.md b/packages/react-router-node/.changes/patch.allow-typescript7-used.md index 5cfef3ce2d..104eae9eaa 100644 --- a/packages/react-router-node/.changes/patch.allow-typescript7-used.md +++ b/packages/react-router-node/.changes/patch.allow-typescript7-used.md @@ -1 +1 @@ -allow typescript@7 to be used +Allow `typescript@7` to be used diff --git a/packages/react-router-remix-routes-option-adapter/.changes/patch.allow-typescript7-used.md b/packages/react-router-remix-routes-option-adapter/.changes/patch.allow-typescript7-used.md index 5cfef3ce2d..104eae9eaa 100644 --- a/packages/react-router-remix-routes-option-adapter/.changes/patch.allow-typescript7-used.md +++ b/packages/react-router-remix-routes-option-adapter/.changes/patch.allow-typescript7-used.md @@ -1 +1 @@ -allow typescript@7 to be used +Allow `typescript@7` to be used diff --git a/packages/react-router/.changes/patch.rsc-client-loader-revalidation.md b/packages/react-router/.changes/patch.rsc-client-loader-revalidation.md index f3df2a93aa..64eff1648b 100644 --- a/packages/react-router/.changes/patch.rsc-client-loader-revalidation.md +++ b/packages/react-router/.changes/patch.rsc-client-loader-revalidation.md @@ -1 +1 @@ -Preserve RSC route component metadata so routes with a `clientLoader` can skip unnecessary server requests once their components have rendered while still fetching missing server-rendered elements. +Preserve RSC route component metadata so routes with a `clientLoader` can skip unnecessary server requests once their components have rendered while still fetching missing server-rendered elements diff --git a/packages/react-router/.changes/patch.rsc-csrf.md b/packages/react-router/.changes/patch.rsc-csrf.md index f778a415cf..5855da9cfc 100644 --- a/packages/react-router/.changes/patch.rsc-csrf.md +++ b/packages/react-router/.changes/patch.rsc-csrf.md @@ -1 +1 @@ -Harden RSC CSRF codepaths. +Harden RSC CSRF code paths diff --git a/packages/react-router/.changes/patch.rsc-html-stream-cancel.md b/packages/react-router/.changes/patch.rsc-html-stream-cancel.md index 322d3e5488..62b6bdadf4 100644 --- a/packages/react-router/.changes/patch.rsc-html-stream-cancel.md +++ b/packages/react-router/.changes/patch.rsc-html-stream-cancel.md @@ -1 +1,3 @@ -Fix server crash (`TypeError: Invalid state: Unable to enqueue`) when a request is aborted while the RSC HTML stream has a pending flush — `injectRSCPayload` now handles cancellation of its readable side, clears the pending flush, and cancels the underlying RSC payload stream +Fix server crash (`TypeError: Invalid state: Unable to enqueue`) when a request is aborted while the RSC HTML stream has a pending flush + +- Handle cancellation of the `injectRSCPayload` readable side, clear the pending flush, and cancel the underlying RSC payload stream diff --git a/scripts/changes/whats-changed.md b/scripts/changes/whats-changed.md new file mode 100644 index 0000000000..74473eb724 --- /dev/null +++ b/scripts/changes/whats-changed.md @@ -0,0 +1,5 @@ +#### RSC Entry Updates + +This release includes several updates for unstable RSC apps that use custom entry files. Apps using the default RSC Framework entries do not need any changes. + +If you maintain custom RSC entries, review the generated unstable change notes for the new client version, subresource integrity, and CSP nonce wiring. Custom `entry.rsc.tsx` files should pass the generated client version to `unstable_matchRSCServerRequest`, and custom `entry.ssr.tsx` files may need to pass the generated import map integrity data and request nonce through React's HTML renderer. From 2edaca7a4f12a50cad002d55d84f73b0cdd462b6 Mon Sep 17 00:00:00 2001 From: Ryan Florence Date: Wed, 22 Jul 2026 09:03:26 -0600 Subject: [PATCH 3/5] Release v8.3.0 (#15294) Co-authored-by: Remix Run Bot --- CHANGELOG.md | 114 ++++++++++++++++++ packages/create-react-router/CHANGELOG.md | 6 + packages/create-react-router/package.json | 2 +- .../.changes/patch.allow-typescript7-used.md | 1 - packages/react-router-architect/CHANGELOG.md | 9 ++ packages/react-router-architect/package.json | 2 +- .../.changes/patch.allow-typescript7-used.md | 1 - packages/react-router-cloudflare/CHANGELOG.md | 8 ++ packages/react-router-cloudflare/package.json | 2 +- .../.changes/minor.development-conditions.md | 1 - .../.changes/patch.allow-typescript7-used.md | 1 - .../.changes/unstable.rsc-client-version.md | 1 - .../unstable.rsc-subresource-integrity.md | 19 --- packages/react-router-dev/CHANGELOG.md | 40 ++++++ packages/react-router-dev/package.json | 2 +- .../.changes/patch.allow-typescript7-used.md | 1 - packages/react-router-express/CHANGELOG.md | 9 ++ packages/react-router-express/package.json | 2 +- .../.changes/patch.allow-typescript7-used.md | 1 - packages/react-router-fs-routes/CHANGELOG.md | 8 ++ packages/react-router-fs-routes/package.json | 2 +- .../.changes/patch.allow-typescript7-used.md | 1 - packages/react-router-node/CHANGELOG.md | 8 ++ packages/react-router-node/package.json | 2 +- .../.changes/patch.allow-typescript7-used.md | 1 - .../CHANGELOG.md | 8 ++ .../package.json | 2 +- packages/react-router-serve/CHANGELOG.md | 9 ++ packages/react-router-serve/package.json | 2 +- .../patch.encode-path-params-pchar.md | 4 - .../patch.memory-session-random-uuid.md | 3 - .../patch.navlink-pending-trailing-slash.md | 1 - .../patch.rsc-client-loader-revalidation.md | 1 - .../react-router/.changes/patch.rsc-csrf.md | 1 - .../.changes/patch.rsc-html-stream-cancel.md | 3 - .../.changes/unstable.rsc-client-version.md | 14 --- .../.changes/unstable.rsc-nonce.md | 32 ----- packages/react-router/CHANGELOG.md | 67 ++++++++++ packages/react-router/package.json | 2 +- scripts/changes/whats-changed.md | 5 - 40 files changed, 296 insertions(+), 102 deletions(-) delete mode 100644 packages/react-router-architect/.changes/patch.allow-typescript7-used.md delete mode 100644 packages/react-router-cloudflare/.changes/patch.allow-typescript7-used.md delete mode 100644 packages/react-router-dev/.changes/minor.development-conditions.md delete mode 100644 packages/react-router-dev/.changes/patch.allow-typescript7-used.md delete mode 100644 packages/react-router-dev/.changes/unstable.rsc-client-version.md delete mode 100644 packages/react-router-dev/.changes/unstable.rsc-subresource-integrity.md delete mode 100644 packages/react-router-express/.changes/patch.allow-typescript7-used.md delete mode 100644 packages/react-router-fs-routes/.changes/patch.allow-typescript7-used.md delete mode 100644 packages/react-router-node/.changes/patch.allow-typescript7-used.md delete mode 100644 packages/react-router-remix-routes-option-adapter/.changes/patch.allow-typescript7-used.md delete mode 100644 packages/react-router/.changes/patch.encode-path-params-pchar.md delete mode 100644 packages/react-router/.changes/patch.memory-session-random-uuid.md delete mode 100644 packages/react-router/.changes/patch.navlink-pending-trailing-slash.md delete mode 100644 packages/react-router/.changes/patch.rsc-client-loader-revalidation.md delete mode 100644 packages/react-router/.changes/patch.rsc-csrf.md delete mode 100644 packages/react-router/.changes/patch.rsc-html-stream-cancel.md delete mode 100644 packages/react-router/.changes/unstable.rsc-client-version.md delete mode 100644 packages/react-router/.changes/unstable.rsc-nonce.md delete mode 100644 scripts/changes/whats-changed.md diff --git a/CHANGELOG.md b/CHANGELOG.md index b935013783..6260d84232 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ We manage release notes in this file instead of the paginated Github Releases Pa Table of Contents - [React Router Releases](#react-router-releases) + - [v8.3.0](#v830) + - [RSC Entry Updates](#rsc-entry-updates) - [v8.2.0](#v820) - [Web Streams Default Server Entry](#web-streams-default-server-entry) - [v8.1.0](#v810) @@ -109,6 +111,118 @@ We manage release notes in this file instead of the paginated Github Releases Pa +## v8.3.0 + +Date: 2026-07-22 + +### What's Changed + +#### RSC Entry Updates + +This release includes several updates for unstable RSC apps that use custom entry files. Apps using the default RSC Framework entries do not need any changes. + +If you maintain custom RSC entries, review the generated unstable change notes for the new client version, subresource integrity, and CSP nonce wiring. Custom `entry.rsc.tsx` files should pass the generated client version to `unstable_matchRSCServerRequest`, and custom `entry.ssr.tsx` files may need to pass the generated import map integrity data and request nonce through React's HTML renderer. + +### Minor Changes + +- `@react-router/dev` - Restart `react-router dev` with `--conditions=development` when not already configured ([#15291](https://github.com/remix-run/react-router/pull/15291)) + +### Patch Changes + +- `react-router` - Encode path params in `href`/`generatePath` per RFC 3986 path-segment rules instead of `encodeURIComponent` ([#15310](https://github.com/remix-run/react-router/pull/15310)) + - Characters that are valid literally in a path segment (`$ & + , ; = : @` — RFC 3986 `pchar`) are no longer percent-encoded, so values like a semver build `1.0.0+1` interpolate unchanged instead of becoming `1.0.0%2B1` + - Structural/unsafe characters (`/ ? # %`, whitespace, non-ASCII) are still escaped exactly as before +- `react-router` - Use `crypto.randomUUID()` for `createMemorySessionStorage` session ids ([#15302](https://github.com/remix-run/react-router/pull/15302)) + - `createMemorySessionStorage` is only intended for local development and testing - sessions are lost when the server restarts +- `react-router` - Fix `NavLink` not applying its `pending` state when `to` has a trailing slash ([#15300](https://github.com/remix-run/react-router/pull/15300)) +- `react-router` - Preserve RSC route component metadata so routes with a `clientLoader` can skip unnecessary server requests once their components have rendered while still fetching missing server-rendered elements ([#15323](https://github.com/remix-run/react-router/pull/15323)) +- `react-router` - Harden RSC CSRF code paths ([#15311](https://github.com/remix-run/react-router/pull/15311)) +- `react-router` - Fix server crash (`TypeError: Invalid state: Unable to enqueue`) when a request is aborted while the RSC HTML stream has a pending flush ([#15286](https://github.com/remix-run/react-router/pull/15286)) + - Handle cancellation of the `injectRSCPayload` readable side, clear the pending flush, and cancel the underlying RSC payload stream +- `@react-router/architect` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) +- `@react-router/cloudflare` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) +- `@react-router/dev` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) +- `@react-router/express` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) +- `@react-router/fs-routes` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) +- `@react-router/node` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) +- `@react-router/remix-routes-option-adapter` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) + +### Unstable Changes + +⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_ + +- `react-router` - Detect stale RSC clients during lazy route discovery and reload the destination document ([#15318](https://github.com/remix-run/react-router/pull/15318)) + + #### Migration + + Apps using the default RSC Framework entry do not need to make any changes. Apps with a custom `entry.rsc.tsx` should import the generated client version and pass it to `unstable_matchRSCServerRequest`: + + ```tsx + import clientVersion from "virtual:react-router/unstable_rsc/client-version"; + + return unstable_matchRSCServerRequest({ + // ... + clientVersion, + }); + ``` + +- `react-router` - Add CSP nonce support to RSC document rendering ([#15320](https://github.com/remix-run/react-router/pull/15320)) + + - Add `nonce` options to `unstable_routeRSCServerRequest` and `unstable_RSCStaticRouter` + - Forward the nonce to the HTML renderer and apply it to injected RSC payload scripts and nonce-aware framework components + + To adopt nonce-based CSP, update your `entry.ssr.tsx` (run `react-router reveal entry.ssr` first in RSC Framework Mode) to generate a fresh nonce for each request. Pass it to `routeRSCServerRequest`, spread the `renderHTML` options into React's HTML renderer, pass `options.nonce` to `RSCStaticRouter`, and use the same nonce in the `Content-Security-Policy` response header: + + ```tsx + const nonce = crypto.randomUUID(); + const response = await routeRSCServerRequest({ + request, + serverResponse, + createFromReadableStream, + nonce, + async renderHTML(getPayload, options) { + const payload = getPayload(); + return renderHTMLToReadableStream( + , + { + ...options, + bootstrapScriptContent, + formState: await payload.formState, + signal: request.signal, + }, + ); + }, + }); + response.headers.set( + "Content-Security-Policy", + `script-src 'self' 'nonce-${nonce}'`, + ); + ``` + +- `@react-router/dev` - Add `unstable_rsc/client-version` client build version virtual module ([#15318](https://github.com/remix-run/react-router/pull/15318)) + +- `@react-router/dev` - Support the `subResourceIntegrity` config option in RSC Framework Mode ([#15321](https://github.com/remix-run/react-router/pull/15321)) + + #### Migration guide + + No changes are required when using the default RSC SSR entry. If you maintain a custom `app/entry.ssr.tsx`, import the new virtual module and pass its hashes to React's `importMap` render option: + + ```diff + +import subResourceIntegrity from "virtual:react-router/unstable_rsc/subresource-integrity"; + + return renderToReadableStream(, { + ...options, + bootstrapScriptContent, + formState, + + importMap: subResourceIntegrity + + ? { integrity: subResourceIntegrity } + + : undefined, + signal: request.signal, + }); + ``` + +**Full Changelog**: [`v8.2.0...v8.3.0`](https://github.com/remix-run/react-router/compare/react-router@8.2.0...react-router@8.3.0) + ## v8.2.0 Date: 2026-07-08 diff --git a/packages/create-react-router/CHANGELOG.md b/packages/create-react-router/CHANGELOG.md index ac095d86de..8f76964af6 100644 --- a/packages/create-react-router/CHANGELOG.md +++ b/packages/create-react-router/CHANGELOG.md @@ -1,5 +1,11 @@ # `create-react-router` +## v8.3.0 + +### Patch Changes + +- _No changes_ + ## v8.2.0 ### Minor Changes diff --git a/packages/create-react-router/package.json b/packages/create-react-router/package.json index ca37d076e5..591f0198ff 100644 --- a/packages/create-react-router/package.json +++ b/packages/create-react-router/package.json @@ -1,7 +1,7 @@ { "name": "create-react-router", "type": "module", - "version": "8.2.0", + "version": "8.3.0", "description": "Create a new React Router app", "homepage": "https://reactrouter.com", "bugs": { diff --git a/packages/react-router-architect/.changes/patch.allow-typescript7-used.md b/packages/react-router-architect/.changes/patch.allow-typescript7-used.md deleted file mode 100644 index 104eae9eaa..0000000000 --- a/packages/react-router-architect/.changes/patch.allow-typescript7-used.md +++ /dev/null @@ -1 +0,0 @@ -Allow `typescript@7` to be used diff --git a/packages/react-router-architect/CHANGELOG.md b/packages/react-router-architect/CHANGELOG.md index 9801e8cae5..b00158fb5b 100644 --- a/packages/react-router-architect/CHANGELOG.md +++ b/packages/react-router-architect/CHANGELOG.md @@ -1,5 +1,14 @@ # `@react-router/architect` +## v8.3.0 + +### Patch Changes + +- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) +- Updated dependencies: + - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0) + - [`@react-router/node@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@8.3.0) + ## v8.2.0 ### Patch Changes diff --git a/packages/react-router-architect/package.json b/packages/react-router-architect/package.json index 314028e174..9f34612754 100644 --- a/packages/react-router-architect/package.json +++ b/packages/react-router-architect/package.json @@ -1,7 +1,7 @@ { "name": "@react-router/architect", "type": "module", - "version": "8.2.0", + "version": "8.3.0", "description": "Architect server request handler for React Router", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router-cloudflare/.changes/patch.allow-typescript7-used.md b/packages/react-router-cloudflare/.changes/patch.allow-typescript7-used.md deleted file mode 100644 index 104eae9eaa..0000000000 --- a/packages/react-router-cloudflare/.changes/patch.allow-typescript7-used.md +++ /dev/null @@ -1 +0,0 @@ -Allow `typescript@7` to be used diff --git a/packages/react-router-cloudflare/CHANGELOG.md b/packages/react-router-cloudflare/CHANGELOG.md index 40637211dc..e8d293c861 100644 --- a/packages/react-router-cloudflare/CHANGELOG.md +++ b/packages/react-router-cloudflare/CHANGELOG.md @@ -1,5 +1,13 @@ # `@react-router/cloudflare` +## v8.3.0 + +### Patch Changes + +- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) +- Updated dependencies: + - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0) + ## v8.2.0 ### Patch Changes diff --git a/packages/react-router-cloudflare/package.json b/packages/react-router-cloudflare/package.json index 338e249950..54c3e287e2 100644 --- a/packages/react-router-cloudflare/package.json +++ b/packages/react-router-cloudflare/package.json @@ -1,7 +1,7 @@ { "name": "@react-router/cloudflare", "type": "module", - "version": "8.2.0", + "version": "8.3.0", "description": "Cloudflare platform abstractions for React Router", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router-dev/.changes/minor.development-conditions.md b/packages/react-router-dev/.changes/minor.development-conditions.md deleted file mode 100644 index 423b22f725..0000000000 --- a/packages/react-router-dev/.changes/minor.development-conditions.md +++ /dev/null @@ -1 +0,0 @@ -Restart `react-router dev` with `--conditions=development` when not already configured diff --git a/packages/react-router-dev/.changes/patch.allow-typescript7-used.md b/packages/react-router-dev/.changes/patch.allow-typescript7-used.md deleted file mode 100644 index 104eae9eaa..0000000000 --- a/packages/react-router-dev/.changes/patch.allow-typescript7-used.md +++ /dev/null @@ -1 +0,0 @@ -Allow `typescript@7` to be used diff --git a/packages/react-router-dev/.changes/unstable.rsc-client-version.md b/packages/react-router-dev/.changes/unstable.rsc-client-version.md deleted file mode 100644 index 001cc296b0..0000000000 --- a/packages/react-router-dev/.changes/unstable.rsc-client-version.md +++ /dev/null @@ -1 +0,0 @@ -Add `unstable_rsc/client-version` client build version virtual module diff --git a/packages/react-router-dev/.changes/unstable.rsc-subresource-integrity.md b/packages/react-router-dev/.changes/unstable.rsc-subresource-integrity.md deleted file mode 100644 index 01a1047593..0000000000 --- a/packages/react-router-dev/.changes/unstable.rsc-subresource-integrity.md +++ /dev/null @@ -1,19 +0,0 @@ -Support the `subResourceIntegrity` config option in RSC Framework Mode - -#### Migration guide - -No changes are required when using the default RSC SSR entry. If you maintain a custom `app/entry.ssr.tsx`, import the new virtual module and pass its hashes to React's `importMap` render option: - -```diff -+import subResourceIntegrity from "virtual:react-router/unstable_rsc/subresource-integrity"; - -return renderToReadableStream(, { - ...options, - bootstrapScriptContent, - formState, -+ importMap: subResourceIntegrity -+ ? { integrity: subResourceIntegrity } -+ : undefined, - signal: request.signal, -}); -``` diff --git a/packages/react-router-dev/CHANGELOG.md b/packages/react-router-dev/CHANGELOG.md index 886f5ded0c..162209de91 100644 --- a/packages/react-router-dev/CHANGELOG.md +++ b/packages/react-router-dev/CHANGELOG.md @@ -1,5 +1,45 @@ # `@react-router/dev` +## v8.3.0 + +### Minor Changes + +- Restart `react-router dev` with `--conditions=development` when not already configured ([#15291](https://github.com/remix-run/react-router/pull/15291)) + +### Patch Changes + +- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) + +### Unstable Changes + +⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_ + +- Add `unstable_rsc/client-version` client build version virtual module ([#15318](https://github.com/remix-run/react-router/pull/15318)) + +- Support the `subResourceIntegrity` config option in RSC Framework Mode ([#15321](https://github.com/remix-run/react-router/pull/15321)) + + #### Migration guide + + No changes are required when using the default RSC SSR entry. If you maintain a custom `app/entry.ssr.tsx`, import the new virtual module and pass its hashes to React's `importMap` render option: + + ```diff + +import subResourceIntegrity from "virtual:react-router/unstable_rsc/subresource-integrity"; + + return renderToReadableStream(, { + ...options, + bootstrapScriptContent, + formState, + + importMap: subResourceIntegrity + + ? { integrity: subResourceIntegrity } + + : undefined, + signal: request.signal, + }); + ``` +- Updated dependencies: + - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0) + - [`@react-router/node@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@8.3.0) + - [`@react-router/serve@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/serve@8.3.0) + ## v8.2.0 ### Minor Changes diff --git a/packages/react-router-dev/package.json b/packages/react-router-dev/package.json index b17fcab9b9..7f25d822c1 100644 --- a/packages/react-router-dev/package.json +++ b/packages/react-router-dev/package.json @@ -1,7 +1,7 @@ { "name": "@react-router/dev", "type": "module", - "version": "8.2.0", + "version": "8.3.0", "description": "Dev tools and CLI for React Router", "keywords": [ "react", diff --git a/packages/react-router-express/.changes/patch.allow-typescript7-used.md b/packages/react-router-express/.changes/patch.allow-typescript7-used.md deleted file mode 100644 index 104eae9eaa..0000000000 --- a/packages/react-router-express/.changes/patch.allow-typescript7-used.md +++ /dev/null @@ -1 +0,0 @@ -Allow `typescript@7` to be used diff --git a/packages/react-router-express/CHANGELOG.md b/packages/react-router-express/CHANGELOG.md index 9140efdf0b..8971e53f07 100644 --- a/packages/react-router-express/CHANGELOG.md +++ b/packages/react-router-express/CHANGELOG.md @@ -1,5 +1,14 @@ # `@react-router/express` +## v8.3.0 + +### Patch Changes + +- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) +- Updated dependencies: + - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0) + - [`@react-router/node@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@8.3.0) + ## v8.2.0 ### Patch Changes diff --git a/packages/react-router-express/package.json b/packages/react-router-express/package.json index c48130c2d9..a021fca8d8 100644 --- a/packages/react-router-express/package.json +++ b/packages/react-router-express/package.json @@ -1,7 +1,7 @@ { "name": "@react-router/express", "type": "module", - "version": "8.2.0", + "version": "8.3.0", "description": "Express server request handler for React Router", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router-fs-routes/.changes/patch.allow-typescript7-used.md b/packages/react-router-fs-routes/.changes/patch.allow-typescript7-used.md deleted file mode 100644 index 104eae9eaa..0000000000 --- a/packages/react-router-fs-routes/.changes/patch.allow-typescript7-used.md +++ /dev/null @@ -1 +0,0 @@ -Allow `typescript@7` to be used diff --git a/packages/react-router-fs-routes/CHANGELOG.md b/packages/react-router-fs-routes/CHANGELOG.md index c5a54a047d..23841a9f84 100644 --- a/packages/react-router-fs-routes/CHANGELOG.md +++ b/packages/react-router-fs-routes/CHANGELOG.md @@ -1,5 +1,13 @@ # `@react-router/fs-routes` +## v8.3.0 + +### Patch Changes + +- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) +- Updated dependencies: + - [`@react-router/dev@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/dev@8.3.0) + ## v8.2.0 ### Patch Changes diff --git a/packages/react-router-fs-routes/package.json b/packages/react-router-fs-routes/package.json index cb9ecbd4df..4ff1b3269f 100644 --- a/packages/react-router-fs-routes/package.json +++ b/packages/react-router-fs-routes/package.json @@ -1,7 +1,7 @@ { "name": "@react-router/fs-routes", "type": "module", - "version": "8.2.0", + "version": "8.3.0", "description": "File system routing conventions for React Router, for use within routes.ts", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router-node/.changes/patch.allow-typescript7-used.md b/packages/react-router-node/.changes/patch.allow-typescript7-used.md deleted file mode 100644 index 104eae9eaa..0000000000 --- a/packages/react-router-node/.changes/patch.allow-typescript7-used.md +++ /dev/null @@ -1 +0,0 @@ -Allow `typescript@7` to be used diff --git a/packages/react-router-node/CHANGELOG.md b/packages/react-router-node/CHANGELOG.md index efe82bbc88..82fd7243bc 100644 --- a/packages/react-router-node/CHANGELOG.md +++ b/packages/react-router-node/CHANGELOG.md @@ -1,5 +1,13 @@ # `@react-router/node` +## v8.3.0 + +### Patch Changes + +- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) +- Updated dependencies: + - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0) + ## v8.2.0 ### Patch Changes diff --git a/packages/react-router-node/package.json b/packages/react-router-node/package.json index 1cf18672dd..c030b65222 100644 --- a/packages/react-router-node/package.json +++ b/packages/react-router-node/package.json @@ -1,7 +1,7 @@ { "name": "@react-router/node", "type": "module", - "version": "8.2.0", + "version": "8.3.0", "description": "Node.js platform abstractions for React Router", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router-remix-routes-option-adapter/.changes/patch.allow-typescript7-used.md b/packages/react-router-remix-routes-option-adapter/.changes/patch.allow-typescript7-used.md deleted file mode 100644 index 104eae9eaa..0000000000 --- a/packages/react-router-remix-routes-option-adapter/.changes/patch.allow-typescript7-used.md +++ /dev/null @@ -1 +0,0 @@ -Allow `typescript@7` to be used diff --git a/packages/react-router-remix-routes-option-adapter/CHANGELOG.md b/packages/react-router-remix-routes-option-adapter/CHANGELOG.md index f1dcea567c..0f2d219194 100644 --- a/packages/react-router-remix-routes-option-adapter/CHANGELOG.md +++ b/packages/react-router-remix-routes-option-adapter/CHANGELOG.md @@ -1,5 +1,13 @@ # `@react-router/remix-config-routes-adapter` +## v8.3.0 + +### Patch Changes + +- Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) +- Updated dependencies: + - [`@react-router/dev@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/dev@8.3.0) + ## v8.2.0 ### Patch Changes diff --git a/packages/react-router-remix-routes-option-adapter/package.json b/packages/react-router-remix-routes-option-adapter/package.json index 33625163b4..1c5eb57da4 100644 --- a/packages/react-router-remix-routes-option-adapter/package.json +++ b/packages/react-router-remix-routes-option-adapter/package.json @@ -1,7 +1,7 @@ { "name": "@react-router/remix-routes-option-adapter", "type": "module", - "version": "8.2.0", + "version": "8.3.0", "description": "Adapter for Remix's \"routes\" config option, for use within routes.ts", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router-serve/CHANGELOG.md b/packages/react-router-serve/CHANGELOG.md index 446ea33f1e..4466b07bf9 100644 --- a/packages/react-router-serve/CHANGELOG.md +++ b/packages/react-router-serve/CHANGELOG.md @@ -1,5 +1,14 @@ # `@react-router/serve` +## v8.3.0 + +### Patch Changes + +- Updated dependencies: + - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0) + - [`@react-router/express@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/express@8.3.0) + - [`@react-router/node@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@8.3.0) + ## v8.2.0 ### Patch Changes diff --git a/packages/react-router-serve/package.json b/packages/react-router-serve/package.json index e4bb702106..906ef0f3f3 100644 --- a/packages/react-router-serve/package.json +++ b/packages/react-router-serve/package.json @@ -1,7 +1,7 @@ { "name": "@react-router/serve", "type": "module", - "version": "8.2.0", + "version": "8.3.0", "description": "Production application server for React Router", "bugs": { "url": "https://github.com/remix-run/react-router/issues" diff --git a/packages/react-router/.changes/patch.encode-path-params-pchar.md b/packages/react-router/.changes/patch.encode-path-params-pchar.md deleted file mode 100644 index 811f55cafe..0000000000 --- a/packages/react-router/.changes/patch.encode-path-params-pchar.md +++ /dev/null @@ -1,4 +0,0 @@ -Encode path params in `href`/`generatePath` per RFC 3986 path-segment rules instead of `encodeURIComponent` - -- Characters that are valid literally in a path segment (`$ & + , ; = : @` — RFC 3986 `pchar`) are no longer percent-encoded, so values like a semver build `1.0.0+1` interpolate unchanged instead of becoming `1.0.0%2B1` -- Structural/unsafe characters (`/ ? # %`, whitespace, non-ASCII) are still escaped exactly as before diff --git a/packages/react-router/.changes/patch.memory-session-random-uuid.md b/packages/react-router/.changes/patch.memory-session-random-uuid.md deleted file mode 100644 index a201faead7..0000000000 --- a/packages/react-router/.changes/patch.memory-session-random-uuid.md +++ /dev/null @@ -1,3 +0,0 @@ -Use `crypto.randomUUID()` for `createMemorySessionStorage` session ids - -- `createMemorySessionStorage` is only intended for local development and testing - sessions are lost when the server restarts diff --git a/packages/react-router/.changes/patch.navlink-pending-trailing-slash.md b/packages/react-router/.changes/patch.navlink-pending-trailing-slash.md deleted file mode 100644 index 085ad0f54f..0000000000 --- a/packages/react-router/.changes/patch.navlink-pending-trailing-slash.md +++ /dev/null @@ -1 +0,0 @@ -Fix `NavLink` not applying its `pending` state when `to` has a trailing slash diff --git a/packages/react-router/.changes/patch.rsc-client-loader-revalidation.md b/packages/react-router/.changes/patch.rsc-client-loader-revalidation.md deleted file mode 100644 index 64eff1648b..0000000000 --- a/packages/react-router/.changes/patch.rsc-client-loader-revalidation.md +++ /dev/null @@ -1 +0,0 @@ -Preserve RSC route component metadata so routes with a `clientLoader` can skip unnecessary server requests once their components have rendered while still fetching missing server-rendered elements diff --git a/packages/react-router/.changes/patch.rsc-csrf.md b/packages/react-router/.changes/patch.rsc-csrf.md deleted file mode 100644 index 5855da9cfc..0000000000 --- a/packages/react-router/.changes/patch.rsc-csrf.md +++ /dev/null @@ -1 +0,0 @@ -Harden RSC CSRF code paths diff --git a/packages/react-router/.changes/patch.rsc-html-stream-cancel.md b/packages/react-router/.changes/patch.rsc-html-stream-cancel.md deleted file mode 100644 index 62b6bdadf4..0000000000 --- a/packages/react-router/.changes/patch.rsc-html-stream-cancel.md +++ /dev/null @@ -1,3 +0,0 @@ -Fix server crash (`TypeError: Invalid state: Unable to enqueue`) when a request is aborted while the RSC HTML stream has a pending flush - -- Handle cancellation of the `injectRSCPayload` readable side, clear the pending flush, and cancel the underlying RSC payload stream diff --git a/packages/react-router/.changes/unstable.rsc-client-version.md b/packages/react-router/.changes/unstable.rsc-client-version.md deleted file mode 100644 index 66d652cf88..0000000000 --- a/packages/react-router/.changes/unstable.rsc-client-version.md +++ /dev/null @@ -1,14 +0,0 @@ -Detect stale RSC clients during lazy route discovery and reload the destination document - -#### Migration - -Apps using the default RSC Framework entry do not need to make any changes. Apps with a custom `entry.rsc.tsx` should import the generated client version and pass it to `unstable_matchRSCServerRequest`: - -```tsx -import clientVersion from "virtual:react-router/unstable_rsc/client-version"; - -return unstable_matchRSCServerRequest({ - // ... - clientVersion, -}); -``` diff --git a/packages/react-router/.changes/unstable.rsc-nonce.md b/packages/react-router/.changes/unstable.rsc-nonce.md deleted file mode 100644 index b4ce627b20..0000000000 --- a/packages/react-router/.changes/unstable.rsc-nonce.md +++ /dev/null @@ -1,32 +0,0 @@ -Add CSP nonce support to RSC document rendering - -- Add `nonce` options to `unstable_routeRSCServerRequest` and `unstable_RSCStaticRouter` -- Forward the nonce to the HTML renderer and apply it to injected RSC payload scripts and nonce-aware framework components - -To adopt nonce-based CSP, update your `entry.ssr.tsx` (run `react-router reveal entry.ssr` first in RSC Framework Mode) to generate a fresh nonce for each request. Pass it to `routeRSCServerRequest`, spread the `renderHTML` options into React's HTML renderer, pass `options.nonce` to `RSCStaticRouter`, and use the same nonce in the `Content-Security-Policy` response header: - -```tsx -const nonce = crypto.randomUUID(); -const response = await routeRSCServerRequest({ - request, - serverResponse, - createFromReadableStream, - nonce, - async renderHTML(getPayload, options) { - const payload = getPayload(); - return renderHTMLToReadableStream( - , - { - ...options, - bootstrapScriptContent, - formState: await payload.formState, - signal: request.signal, - }, - ); - }, -}); -response.headers.set( - "Content-Security-Policy", - `script-src 'self' 'nonce-${nonce}'`, -); -``` diff --git a/packages/react-router/CHANGELOG.md b/packages/react-router/CHANGELOG.md index 2883614256..c868b58e5e 100644 --- a/packages/react-router/CHANGELOG.md +++ b/packages/react-router/CHANGELOG.md @@ -1,5 +1,72 @@ # `react-router` +## v8.3.0 + +### Patch Changes + +- Encode path params in `href`/`generatePath` per RFC 3986 path-segment rules instead of `encodeURIComponent` ([#15310](https://github.com/remix-run/react-router/pull/15310)) + - Characters that are valid literally in a path segment (`$ & + , ; = : @` — RFC 3986 `pchar`) are no longer percent-encoded, so values like a semver build `1.0.0+1` interpolate unchanged instead of becoming `1.0.0%2B1` + - Structural/unsafe characters (`/ ? # %`, whitespace, non-ASCII) are still escaped exactly as before +- Use `crypto.randomUUID()` for `createMemorySessionStorage` session ids ([#15302](https://github.com/remix-run/react-router/pull/15302)) + - `createMemorySessionStorage` is only intended for local development and testing - sessions are lost when the server restarts +- Fix `NavLink` not applying its `pending` state when `to` has a trailing slash ([#15300](https://github.com/remix-run/react-router/pull/15300)) +- Preserve RSC route component metadata so routes with a `clientLoader` can skip unnecessary server requests once their components have rendered while still fetching missing server-rendered elements ([#15323](https://github.com/remix-run/react-router/pull/15323)) +- Harden RSC CSRF code paths ([#15311](https://github.com/remix-run/react-router/pull/15311)) +- Fix server crash (`TypeError: Invalid state: Unable to enqueue`) when a request is aborted while the RSC HTML stream has a pending flush ([#15286](https://github.com/remix-run/react-router/pull/15286)) + - Handle cancellation of the `injectRSCPayload` readable side, clear the pending flush, and cancel the underlying RSC payload stream + +### Unstable Changes + +⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_ + +- Detect stale RSC clients during lazy route discovery and reload the destination document ([#15318](https://github.com/remix-run/react-router/pull/15318)) + + #### Migration + + Apps using the default RSC Framework entry do not need to make any changes. Apps with a custom `entry.rsc.tsx` should import the generated client version and pass it to `unstable_matchRSCServerRequest`: + + ```tsx + import clientVersion from "virtual:react-router/unstable_rsc/client-version"; + + return unstable_matchRSCServerRequest({ + // ... + clientVersion, + }); + ``` + +- Add CSP nonce support to RSC document rendering ([#15320](https://github.com/remix-run/react-router/pull/15320)) + + - Add `nonce` options to `unstable_routeRSCServerRequest` and `unstable_RSCStaticRouter` + - Forward the nonce to the HTML renderer and apply it to injected RSC payload scripts and nonce-aware framework components + + To adopt nonce-based CSP, update your `entry.ssr.tsx` (run `react-router reveal entry.ssr` first in RSC Framework Mode) to generate a fresh nonce for each request. Pass it to `routeRSCServerRequest`, spread the `renderHTML` options into React's HTML renderer, pass `options.nonce` to `RSCStaticRouter`, and use the same nonce in the `Content-Security-Policy` response header: + + ```tsx + const nonce = crypto.randomUUID(); + const response = await routeRSCServerRequest({ + request, + serverResponse, + createFromReadableStream, + nonce, + async renderHTML(getPayload, options) { + const payload = getPayload(); + return renderHTMLToReadableStream( + , + { + ...options, + bootstrapScriptContent, + formState: await payload.formState, + signal: request.signal, + }, + ); + }, + }); + response.headers.set( + "Content-Security-Policy", + `script-src 'self' 'nonce-${nonce}'`, + ); + ``` + ## v8.2.0 ### Patch Changes diff --git a/packages/react-router/package.json b/packages/react-router/package.json index db9c66f667..91528904fc 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -1,7 +1,7 @@ { "name": "react-router", "type": "module", - "version": "8.2.0", + "version": "8.3.0", "description": "Declarative routing for React", "keywords": [ "react", diff --git a/scripts/changes/whats-changed.md b/scripts/changes/whats-changed.md deleted file mode 100644 index 74473eb724..0000000000 --- a/scripts/changes/whats-changed.md +++ /dev/null @@ -1,5 +0,0 @@ -#### RSC Entry Updates - -This release includes several updates for unstable RSC apps that use custom entry files. Apps using the default RSC Framework entries do not need any changes. - -If you maintain custom RSC entries, review the generated unstable change notes for the new client version, subresource integrity, and CSP nonce wiring. Custom `entry.rsc.tsx` files should pass the generated client version to `unstable_matchRSCServerRequest`, and custom `entry.ssr.tsx` files may need to pass the generated import map integrity data and request nonce through React's HTML renderer. From 55ff211cf55318f564a1c05cbc7d12c8019782c2 Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Wed, 22 Jul 2026 11:13:55 -0400 Subject: [PATCH 4/5] Update release notes --- CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6260d84232..967dfd527b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -135,10 +135,6 @@ If you maintain custom RSC entries, review the generated unstable change notes f - `react-router` - Use `crypto.randomUUID()` for `createMemorySessionStorage` session ids ([#15302](https://github.com/remix-run/react-router/pull/15302)) - `createMemorySessionStorage` is only intended for local development and testing - sessions are lost when the server restarts - `react-router` - Fix `NavLink` not applying its `pending` state when `to` has a trailing slash ([#15300](https://github.com/remix-run/react-router/pull/15300)) -- `react-router` - Preserve RSC route component metadata so routes with a `clientLoader` can skip unnecessary server requests once their components have rendered while still fetching missing server-rendered elements ([#15323](https://github.com/remix-run/react-router/pull/15323)) -- `react-router` - Harden RSC CSRF code paths ([#15311](https://github.com/remix-run/react-router/pull/15311)) -- `react-router` - Fix server crash (`TypeError: Invalid state: Unable to enqueue`) when a request is aborted while the RSC HTML stream has a pending flush ([#15286](https://github.com/remix-run/react-router/pull/15286)) - - Handle cancellation of the `injectRSCPayload` readable side, clear the pending flush, and cancel the underlying RSC payload stream - `@react-router/architect` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) - `@react-router/cloudflare` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) - `@react-router/dev` - Allow `typescript@7` to be used ([#15317](https://github.com/remix-run/react-router/pull/15317)) @@ -151,6 +147,10 @@ If you maintain custom RSC entries, review the generated unstable change notes f ⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_ +- `react-router` - Preserve RSC route component metadata so routes with a `clientLoader` can skip unnecessary server requests once their components have rendered while still fetching missing server-rendered elements ([#15323](https://github.com/remix-run/react-router/pull/15323)) +- `react-router` - Harden RSC CSRF code paths ([#15311](https://github.com/remix-run/react-router/pull/15311)) +- `react-router` - Fix server crash (`TypeError: Invalid state: Unable to enqueue`) when a request is aborted while the RSC HTML stream has a pending flush ([#15286](https://github.com/remix-run/react-router/pull/15286)) + - Handle cancellation of the `injectRSCPayload` readable side, clear the pending flush, and cancel the underlying RSC payload stream - `react-router` - Detect stale RSC clients during lazy route discovery and reload the destination document ([#15318](https://github.com/remix-run/react-router/pull/15318)) #### Migration From 8bc59bc7b027d5f2aba15a6dd72f44e757dbd8f9 Mon Sep 17 00:00:00 2001 From: Remix Run Bot Date: Wed, 22 Jul 2026 15:14:39 +0000 Subject: [PATCH 5/5] chore: format --- CHANGELOG.md | 3 +-- packages/react-router-dev/CHANGELOG.md | 3 ++- packages/react-router/CHANGELOG.md | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 967dfd527b..6a91a2fec4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -145,7 +145,7 @@ If you maintain custom RSC entries, review the generated unstable change notes f ### Unstable Changes -⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_ +⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_ - `react-router` - Preserve RSC route component metadata so routes with a `clientLoader` can skip unnecessary server requests once their components have rendered while still fetching missing server-rendered elements ([#15323](https://github.com/remix-run/react-router/pull/15323)) - `react-router` - Harden RSC CSRF code paths ([#15311](https://github.com/remix-run/react-router/pull/15311)) @@ -167,7 +167,6 @@ If you maintain custom RSC entries, review the generated unstable change notes f ``` - `react-router` - Add CSP nonce support to RSC document rendering ([#15320](https://github.com/remix-run/react-router/pull/15320)) - - Add `nonce` options to `unstable_routeRSCServerRequest` and `unstable_RSCStaticRouter` - Forward the nonce to the HTML renderer and apply it to injected RSC payload scripts and nonce-aware framework components diff --git a/packages/react-router-dev/CHANGELOG.md b/packages/react-router-dev/CHANGELOG.md index 162209de91..ffb149f4b0 100644 --- a/packages/react-router-dev/CHANGELOG.md +++ b/packages/react-router-dev/CHANGELOG.md @@ -12,7 +12,7 @@ ### Unstable Changes -⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_ +⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_ - Add `unstable_rsc/client-version` client build version virtual module ([#15318](https://github.com/remix-run/react-router/pull/15318)) @@ -35,6 +35,7 @@ signal: request.signal, }); ``` + - Updated dependencies: - [`react-router@8.3.0`](https://github.com/remix-run/react-router/releases/tag/react-router@8.3.0) - [`@react-router/node@8.3.0`](https://github.com/remix-run/react-router/releases/tag/@react-router/node@8.3.0) diff --git a/packages/react-router/CHANGELOG.md b/packages/react-router/CHANGELOG.md index c868b58e5e..45abf9f3f4 100644 --- a/packages/react-router/CHANGELOG.md +++ b/packages/react-router/CHANGELOG.md @@ -17,7 +17,7 @@ ### Unstable Changes -⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_ +⚠️ _[Unstable features](https://reactrouter.com/community/api-development-strategy#unstable-flags) are not recommended for production use_ - Detect stale RSC clients during lazy route discovery and reload the destination document ([#15318](https://github.com/remix-run/react-router/pull/15318)) @@ -35,7 +35,6 @@ ``` - Add CSP nonce support to RSC document rendering ([#15320](https://github.com/remix-run/react-router/pull/15320)) - - Add `nonce` options to `unstable_routeRSCServerRequest` and `unstable_RSCStaticRouter` - Forward the nonce to the HTML renderer and apply it to injected RSC payload scripts and nonce-aware framework components