Repository navigation
Conversation
A file or a blob only reached a server function as its only argument. Next to other arguments, or inside an object, the call failed with `SerovalUnsupportedTypeError`, because the serializer has no plugin for them. When the arguments hold files, the client now sends multipart form data: the serialized arguments in one field, and each file in its own part. A seroval plugin for the call replaces each file with its part's index, wherever seroval finds it. On the server, a plugin created for that request turns the indexes back into the parts, and rejects a missing part or a bad index. Other bodies are read without it, so an index means nothing there. Calls without files are sent as before. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 03d48c2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
✅ Deploy Preview for solid-start-landing-page ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
commit: |
lxsmnsyc
added a commit
to lxsmnsyc/solid
that referenced
this pull request
Oct 21, 2026
With enableRichArguments(), a call whose arguments hold files or blobs used to fail before sending, unless the file was the only argument or the last one. Ports solidjs/solid-start#2359 to the core transport. - The rich-args encoder finds each file with a seroval plugin made for the call, wherever the codec meets it: arguments, arrays, objects, maps, sets and FormData entries. - A call with files sends multipart form data. The codec output goes in the `args` field and each file goes as it is in a `file<index>` part. - The new BodyFormat.SerializedFormData ("10") marks the request. - The server decodes `args` with a plugin made for that request, which turns each index back into its part. Other bodies decode without it. - A missing `args` field, a bad index or a missing part is refused with 400. bodySizeLimit bounds the whole body. - Default JSON mode is unchanged. Upload code ships only in the rich-args entry. - The version skew spec moves its unknown tag from "10" to "11". Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ryansolid
added a commit
to solidjs/solid
that referenced
this pull request
Oct 21, 2026
Ports solidjs/solid-start#2359 (from #4177 by @lxsmnsyc), with uploads kept off the core client request path: they keep the Serialized tag and the handler spots them by their multipart content type. Co-authored-by: Alexis H. Munsayac <alexis.munsayac@gmail.com>
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.
Problem
A file or a blob only reaches a server function as its only argument. Anywhere else, the call fails before it's sent:
Calls with more than one argument, or with a file inside a value, go through seroval. Start's plugin list has no plugin for
BloborFile.Change
When the arguments hold files, the client sends multipart form data:
argsfield. Each file goes in its ownfile<i>part, so it's sent as it is, without base64.BodyFormat.SerovalFormData("8") marks the request.The files are found by a seroval plugin created for the call (
createUploadSerializer). It replaces each file or blob with the index of its part wherever seroval finds it: arguments, arrays, objects,Map,Set, andFormDataentries.FormDataonly takes its own realm's blobs.On the server,
extractBodyreads the form and deserializesargswith the usual chunk size limit and a plugin created for that request (createUploadDeserializer), which turns each index back into its part.argsfield is rejected.Calls without files are sent exactly as before, and the single-argument fast paths (
FormData,File,Blob, …) are unchanged.serializeToJSONString,serializeToJSONStreamanddeserializeJSONStreamtake per-call plugins, tried before the built-in and user plugins.This follows the upload design of brumate's server functions. The difference is that a seroval plugin finds the files, instead of a walk over arrays and plain objects.
Limits
request.formData(), as the existing single-FormDatapath does. There is no total size limit.Filevalues. ABlobcomes back as aFilenamedblob, with its type kept.Note for later
uploads.tshas a comment comparing this with seroval's binary mode (in development on seroval'sbinary-modebranch):BlobPluginandFilePluginread the whole file witharrayBuffer()before sending, and sending binary output as it's produced needs a streamed request body (duplex: "half"), which not every browser supports. AFileinFormDatais read by the browser as it sends.A migration can move the arguments to binary mode and keep files as parts. Servers should accept both formats for a while.
Verification
fns/uploads.spec.ts. They do a full client-to-extractBodyround trip with: a file plus metadata, files in arrays/maps/sets,FormDataas one of several arguments, a file used twice, a blob's type, a cross-realm blob, a call without files staying as text, and the three rejections.server-function-uploadroute plus a Playwright test. It sends a file, an object holding blobs, and aFormDatawith a file in one call. The test fails without this change.packages/start: 276 tests, typecheck, build, format check.apps/tests: unit, Playwright default (45), bundled-dev (45) and base (3) all pass.The 1.x version is #2360.
🤖 Generated with Claude Code