Repository navigation
feat(rsc): allow rejecting server references during decodeReply/decodeAction - #1520
Open
james-elicx wants to merge 2 commits into
Open
james-elicx wants to merge 2 commits into
james-elicx wants to merge 2 commits into
Conversation
james-elicx
marked this pull request as ready for review
October 19, 2026 10:56
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
decodeReply,decodeAction, anddecodeFormStatealways decode with the plugin's server manifest, which resolves any server reference the client sends. A framework can't limit which server functions a request is allowed to decode, for example to the actions its current route exposes. Next.js does this with a page-scoped server module map, so a server function passed as an argument, or bound to a form action, has to belong to the current page.Today a framework has to skip these wrappers and call
@vitejs/plugin-rsc/vendor/react-server-dom/server.edgedirectly with its own manifest built on top ofcreateServerManifest().This adds an experimental
onServerReferencecallback in an optional last parameter, alongside the existingonClientReferenceextension onrenderToReadableStream:The callback receives
{ id, name }for each server reference React resolves while decoding. That includes the action itself indecodeAction, and any server function passed as an argument or bound to an action. Throwing rejects the reference before its module loads, and decoding fails.decodeReplyFromBusboyin@vitejs/plugin-rsc/rsc/server.nodegets the same parameter. Without the callback, nothing changes.loadServerActiondoesn't call it, so for fetch actions a framework still checks the action id itself. The README says so.Tests
New
e2e/server-reference-callback.test.ts, an inlinestarter-extrafixture, in dev and build. Its RSC entry rejects one named server reference. Two forms bind a recording action to an allowed and a rejected server function, and each is submitted twice:decodeReply);decodeAction).The rejected submissions fail with a 500 and never run the action. The allowed ones run with the bound server function. Without the source change, the rejected submissions return 200 and run the action.
decodeFormStatepasses the callback through too, but the test doesn't exercise it. React only decodes there foruseActionStateforms ($ACTION_KEY), anddecodeActionalready rejects the same bound references first.