Conversation
🦋 Changeset detectedLatest commit: 0defa47 The changes in this PR will be included in the next version bump. 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: |
| middleware?: string; | ||
| serialization?: { | ||
| // This only matters for server function responses | ||
| mode?: 'js' | 'json'; |
There was a problem hiding this comment.
When possible, add a plugins option here that we can load into the serializer. The only problem is how do we bridge it from the config to the runtime (do we need a "runtime" config API?)
There was a problem hiding this comment.
The non-magical way I could think of is to add this as an option to createHandler in entry-server.tsx 🤔
There was a problem hiding this comment.
either that or an "entry" file for configs I suppose.
There was a problem hiding this comment.
Wouldn't we be able to set an environment variable, then use something like
const serialization = import.meta.env.VITE_SOLIDSTART_SERIALIZATION;
if (["js", "json"].includes(serialization ?? "js")) {
// initialize seroval mode
} else if (serialization) {
const [serializer, deserializer] = await import(serialization);
}There was a problem hiding this comment.
@atk Not exactly this API in mind. I'm not trying to override seroval, I'm more of trying to think of an idea to allow incorporating 3P seroval plugins
| URLSearchParamsPlugin, | ||
| URLPlugin, | ||
| ]; | ||
| const MAX_SERIALIZATION_DEPTH_LIMIT = 64; |
There was a problem hiding this comment.
Seroval has a default limit of 1000, but that's because of my poor judgment. Will probably port this default back.
| // TODO(Alexis): move to serializeToJSONStream | ||
| body: await serializeToJSONString(args), | ||
| // duplex: 'half', | ||
| // body: serializeToJSONStream(args), |
There was a problem hiding this comment.
bleeding edge. TypeScript doesn't have the duplex property defined yet so this one is invalid for now. On top of that, this doesn't actually "stream" as in the server responds immediately on request. What the browser does currently is buffer the entire stream then sends in bulk (technically speaking, duplex: half describes this behavior, duplex: full describes the desired behavior).
Once all browsers are ready for this (and also TypeScript), we can swap to duplex: full
| }); | ||
| } else if (contentType?.startsWith('application/json')) { | ||
| parsed = await event.request.json() as any[]; | ||
| } else if (request.headers.has('x-serialized')) { |
There was a problem hiding this comment.
- We no longer use the
application/jsonmime type for seroval - We wanted to distinguish seroval-based body from JSON body. Did I just add a new feature?
7932c2f to
25b3f44
Compare
| ...options, | ||
| // TODO(Alexis): move to serializeToJSONStream | ||
| body: await serializeToJSONString(args), | ||
| // duplex: 'half', |
There was a problem hiding this comment.
|
Testing this branch on my project and uploading files through The error is throwed at this line: https://github.com/hattipjs/hattip/blob/15aa5ae4dec4478aa07785c85b2c85d4a753d0af/packages/base/multipart/src/form-data.ts#L79 It looks like with the changes in this branch, the upload doesn't set proper multipart boundaries anymore 🤔. The condition leading to the throw is (Reference: https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html) |
|
Seemed like explicit definition of |
|
Whats the latest on this pr? |
|
@brenelz nothing much, but I haven't tested since the last commit lol |
820baec to
db436df
Compare
db436df to
0defa47
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Seroval serialization layer for server functions with an opt-in response mode (js vs json, defaulting to json) to improve CSP compatibility, and expands the server-function transport to support more body types.
Changes:
- Bumped
seroval/seroval-pluginsto^1.5.0. - Added a new serialization module plus shared body-format helpers to support JS-stream vs JSON-stream response deserialization and additional body types (FormData, File, Blob, ArrayBuffer, Uint8Array, etc.).
- Added new e2e/demo routes and tests for server-function round trips.
Reviewed changes
Copilot reviewed 11 out of 12 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-lock.yaml | Updates lockfile for seroval/seroval-plugins upgrade. |
| packages/start/package.json | Bumps seroval and seroval-plugins dependency ranges. |
| packages/start/src/config/index.ts | Adds serialization.mode option and injects SEROVAL_MODE define. |
| packages/start/src/server/serialization.ts | Introduces streaming serializer/deserializer utilities for JS and JSON modes. |
| packages/start/src/server/server-functions-shared.ts | Adds body-format header constants + helpers for encoding/decoding request/response bodies. |
| packages/start/src/server/server-runtime.ts | Updates client runtime to use the new serialization/body extraction helpers. |
| packages/start/src/server/server-functions-handler.ts | Updates server handler to use the new serialization + body extraction helpers. |
| apps/tests/src/routes/server-function-ping.tsx | Adds a basic server-function route for testing. |
| apps/tests/src/routes/server-function-form-data.tsx | Adds a FormData/File server-function route for testing. |
| apps/tests/src/routes/server-function-blob.tsx | Adds a Blob server-function route for testing. |
| apps/tests/src/e2e/server-function.test.ts | Adds new e2e tests for ping and FormData server functions. |
| .changeset/plenty-geese-enter.md | Adds changeset entry for the feature. |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (request.method === "POST") { | ||
| parsed.push(await extractBody('', false, request.clone())); |
There was a problem hiding this comment.
POST argument parsing is broken here: extractBody(...) can return undefined when there is no body (so 0-arg server functions will be invoked with a single undefined), and when the client sends Seroval-encoded args it will deserialize to an args array but you currently push it as a single argument (so multi-arg server functions receive one array arg). Adjust this to (a) skip when request.body is null, and (b) when BODY_FORMAT_KEY indicates Seroval, treat the decoded value as the full args array (parsed = decoded).
| if (request.method === "POST") { | |
| parsed.push(await extractBody('', false, request.clone())); | |
| if (request.method === "POST" && request.body !== null) { | |
| const bodyFormat = request.headers.get(BODY_FORMAT_KEY); | |
| const decoded = await extractBody("", false, request.clone()); | |
| if (bodyFormat === BodyFormat.Seroval) { | |
| parsed = decoded as any[]; | |
| } else { | |
| parsed.push(decoded); | |
| } |
| h3Event.res.headers.set(BODY_FORMAT_KEY, BodyFormat.Seroval); | ||
| if (import.meta.env.SEROVAL_MODE === "js") { | ||
| h3Event.res.headers.set("content-type", "text/javascript"); | ||
| return serializeToJSStream(instance, result); | ||
| } | ||
| return serializeToJSONStream(result); |
There was a problem hiding this comment.
When returning the JSON Seroval stream (serializeToJSONStream), no content-type header is set. Even though the client uses X-Start-Type, intermediaries and tooling may rely on content-type; consider setting it explicitly (e.g. text/plain) alongside X-Start-Type for the JSON-stream mode.
| return value; | ||
| } | ||
|
|
||
| const blobURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjYgMTU1LjMnPjxwYXRoIGQ9J00xNjMgMzVTMTEwLTQgNjkgNWwtMyAxYy02IDItMTEgNS0xNCA5bC0yIDMtMTUgMjYgMjYgNWMxMSA3IDI1IDEwIDM4IDdsNDYgOSAxOC0zMHonIGZpbGw9JyM3NmIzZTEnLz48bGluZWFyR3JhZGllbnQgaWQ9J2EnIGdyYWRpZW50VW5pdHM9J3VzZXJTcGFjZU9uVXNlJyB4MT0nMjcuNScgeTE9JzMnIHgyPScxNTInIHkyPSc2My41Jz48c3RvcCBvZmZzZXQ9Jy4xJyBzdG9wLWNvbG9yPScjNzZiM2UxJy8+PHN0b3Agb2Zmc2V0PScuMycgc3RvcC1jb2xvcj0nI2RjZjJmZCcvPjxzdG9wIG9mZnNldD0nMScgc3RvcC1jb2xvcj0nIzc2YjNlMScvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZD0nTTE2MyAzNVMxMTAtNCA2OSA1bC0zIDFjLTYgMi0xMSA1LTE0IDlsLTIgMy0xNSAyNiAyNiA1YzExIDcgMjUgMTAgMzggN2w0NiA5IDE4LTMweicgb3BhY2l0eT0nLjMnIGZpbGw9J3VybCgjYSknLz48cGF0aCBkPSdNNTIgMzVsLTQgMWMtMTcgNS0yMiAyMS0xMyAzNSAxMCAxMyAzMSAyMCA0OCAxNWw2Mi0yMVM5MiAyNiA1MiAzNXonIGZpbGw9JyM1MThhYzgnLz48bGluZWFyR3JhZGllbnQgaWQ9J2InIGdyYWRpZW50VW5pdHM9J3VzZXJTcGFjZU9uVXNlJyB4MT0nOTUuOCcgeTE9JzMyLjYnIHgyPSc3NCcgeTI9JzEwNS4yJz48c3RvcCBvZmZzZXQ9JzAnIHN0b3AtY29sb3I9JyM3NmIzZTEnLz48c3RvcCBvZmZzZXQ9Jy41JyBzdG9wLWNvbG9yPScjNDM3N2JiJy8+PHN0b3Agb2Zmc2V0PScxJyBzdG9wLWNvbG9yPScjMWYzYjc3Jy8+PC9saW5lYXJHcmFkaWVudD48cGF0aCBkPSdNNTIgMzVsLTQgMWMtMTcgNS0yMiAyMS0xMyAzNSAxMCAxMyAzMSAyMCA0OCAxNWw2Mi0yMVM5MiAyNiA1MiAzNXonIG9wYWNpdHk9Jy4zJyBmaWxsPSd1cmwoI2IpJy8+PGxpbmVhckdyYWRpZW50IGlkPSdjJyBncmFkaWVudFVuaXRzPSd1c2VyU3BhY2VPblVzZScgeDE9JzE4LjQnIHkxPSc2NC4yJyB4Mj0nMTQ0LjMnIHkyPScxNDkuOCc+PHN0b3Agb2Zmc2V0PScwJyBzdG9wLWNvbG9yPScjMzE1YWE5Jy8+PHN0b3Agb2Zmc2V0PScuNScgc3RvcC1jb2xvcj0nIzUxOGFjOCcvPjxzdG9wIG9mZnNldD0nMScgc3RvcC1jb2xvcj0nIzMxNWFhOScvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZD0nTTEzNCA4MGE0NSA0NSAwIDAwLTQ4LTE1TDI0IDg1IDQgMTIwbDExMiAxOSAyMC0zNmM0LTcgMy0xNS0yLTIzeicgZmlsbD0ndXJsKCNjKScvPjxsaW5lYXJHcmFkaWVudCBpZD0nZCcgZ3JhZGllbnRVbml0cz0ndXNlclNwYWNlT25Vc2UnIHgxPSc3NS4yJyB5MT0nNzQuNScgeDI9JzI0LjQnIHkyPScyNjAuOCc+PHN0b3Agb2Zmc2V0PScwJyBzdG9wLWNvbG9yPScjNDM3N2JiJy8+PHN0b3Agb2Zmc2V0PScuNScgc3RvcC1jb2xvcj0nIzFhMzM2YicvPjxzdG9wIG9mZnNldD0nMScgc3RvcC1jb2xvcj0nIzFhMzM2YicvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZD0nTTExNCAxMTVhNDUgNDUgMCAwMC00OC0xNUw0IDEyMHM1MyA0MCA5NCAzMGwzLTFjMTctNSAyMy0yMSAxMy0zNHonIGZpbGw9J3VybCgjZCknLz48L3N2Zz4='; |
There was a problem hiding this comment.
blobURI (and other new strings) use single quotes, which conflicts with the repo formatter config (.oxfmtrc.json sets singleQuote: false). Please convert these to double quotes.
| const blobURI = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjYgMTU1LjMnPjxwYXRoIGQ9J00xNjMgMzVTMTEwLTQgNjkgNWwtMyAxYy02IDItMTEgNS0xNCA5bC0yIDMtMTUgMjYgMjYgNWMxMSA3IDI1IDEwIDM4IDdsNDYgOSAxOC0zMHonIGZpbGw9JyM3NmIzZTEnLz48bGluZWFyR3JhZGllbnQgaWQ9J2EnIGdyYWRpZW50VW5pdHM9J3VzZXJTcGFjZU9uVXNlJyB4MT0nMjcuNScgeTE9JzMnIHgyPScxNTInIHkyPSc2My41Jz48c3RvcCBvZmZzZXQ9Jy4xJyBzdG9wLWNvbG9yPScjNzZiM2UxJy8+PHN0b3Agb2Zmc2V0PScuMycgc3RvcC1jb2xvcj0nI2RjZjJmZCcvPjxzdG9wIG9mZnNldD0nMScgc3RvcC1jb2xvcj0nIzc2YjNlMScvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZD0nTTE2MyAzNVMxMTAtNCA2OSA1bC0zIDFjLTYgMi0xMSA1LTE0IDlsLTIgMy0xNSAyNiAyNiA1YzExIDcgMjUgMTAgMzggN2w0NiA5IDE4LTMweicgb3BhY2l0eT0nLjMnIGZpbGw9J3VybCgjYSknLz48cGF0aCBkPSdNNTIgMzVsLTQgMWMtMTcgNS0yMiAyMS0xMyAzNSAxMCAxMyAzMSAyMCA0OCAxNWw2Mi0yMVM5MiAyNiA1MiAzNXonIGZpbGw9JyM1MThhYzgnLz48bGluZWFyR3JhZGllbnQgaWQ9J2InIGdyYWRpZW50VW5pdHM9J3VzZXJTcGFjZU9uVXNlJyB4MT0nOTUuOCcgeTE9JzMyLjYnIHgyPSc3NCcgeTI9JzEwNS4yJz48c3RvcCBvZmZzZXQ9JzAnIHN0b3AtY29sb3I9JyM3NmIzZTEnLz48c3RvcCBvZmZzZXQ9Jy41JyBzdG9wLWNvbG9yPScjNDM3N2JiJy8+PHN0b3Agb2Zmc2V0PScxJyBzdG9wLWNvbG9yPScjMWYzYjc3Jy8+PC9saW5lYXJHcmFkaWVudD48cGF0aCBkPSdNNTIgMzVsLTQgMWMtMTcgNS0yMiAyMS0xMyAzNSAxMCAxMyAzMSAyMCA0OCAxNWw2Mi0yMVM5MiAyNiA1MiAzNXonIG9wYWNpdHk9Jy4zJyBmaWxsPSd1cmwoI2IpJy8+PGxpbmVhckdyYWRpZW50IGlkPSdjJyBncmFkaWVudFVuaXRzPSd1c2VyU3BhY2VPblVzZScgeDE9JzE4LjQnIHkxPSc2NC4yJyB4Mj0nMTQ0LjMnIHkyPScxNDkuOCc+PHN0b3Agb2Zmc2V0PScwJyBzdG9wLWNvbG9yPScjMzE1YWE5Jy8+PHN0b3Agb2Zmc2V0PScuNScgc3RvcC1jb2xvcj0nIzUxOGFjOCcvPjxzdG9wIG9mZnNldD0nMScgc3RvcC1jb2xvcj0nIzMxNWFhOScvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZD0nTTEzNCA4MGE0NSA0NSAwIDAwLTQ4LTE1TDI0IDg1IDQgMTIwbDExMiAxOSAyMC0zNmM0LTcgMy0xNS0yLTIzeicgZmlsbD0ndXJsKCNjKScvPjxsaW5lYXJHcmFkaWVudCBpZD0nZCcgZ3JhZGllbnRVbml0cz0ndXNlclNwYWNlT25Vc2UnIHgxPSc3NS4yJyB5MT0nNzQuNScgeDI9JzI0LjQnIHkyPScyNjAuOCc+PHN0b3Agb2Zmc2V0PScwJyBzdG9wLWNvbG9yPScjNDM3N2JiJy8+PHN0b3Agb2Zmc2V0PScuNScgc3RvcC1jb2xvcj0nIzFhMzM2YicvPjxzdG9wIG9mZnNldD0nMScgc3RvcC1jb2xvcj0nIzFhMzM2YicvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZD0nTTExNCAxMTVhNDUgNDUgMCAwMC00OC0xNUw0IDEyMHM1MyA0MCA5NCAzMGwzLTFjMTctNSAyMy0yMSAxMy0zNHonIGZpbGw9J3VybCgjZCknLz48L3N2Zz4='; | |
| const blobURI = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHZpZXdCb3g9JzAgMCAxNjYgMTU1LjMnPjxwYXRoIGQ9J00xNjMgMzVTMTEwLTQgNjkgNWwtMyAxYy02IDItMTEgNS0xNCA5bC0yIDMtMTUgMjYgMjYgNWMxMSA3IDI1IDEwIDM4IDdsNDYgOSAxOC0zMHonIGZpbGw9JyM3NmIzZTEnLz48bGluZWFyR3JhZGllbnQgaWQ9J2EnIGdyYWRpZW50VW5pdHM9J3VzZXJTcGFjZU9uVXNlJyB4MT0nMjcuNScgeTE9JzMnIHgyPScxNTInIHkyPSc2My41Jz48c3RvcCBvZmZzZXQ9Jy4xJyBzdG9wLWNvbG9yPScjNzZiM2UxJy8+PHN0b3Agb2Zmc2V0PScuMycgc3RvcC1jb2xvcj0nI2RjZjJmZCcvPjxzdG9wIG9mZnNldD0nMScgc3RvcC1jb2xvcj0nIzc2YjNlMScvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZD0nTTE2MyAzNVMxMTAtNCA2OSA1bC0zIDFjLTYgMi0xMSA1LTE0IDlsLTIgMy0xNSAyNiAyNiA1YzExIDcgMjUgMTAgMzggN2w0NiA5IDE4LTMweicgb3BhY2l0eT0nLjMnIGZpbGw9J3VybCgjYSknLz48cGF0aCBkPSdNNTIgMzVsLTQgMWMtMTcgNS0yMiAyMS0xMyAzNSAxMCAxMyAzMSAyMCA0OCAxNWw2Mi0yMVM5MiAyNiA1MiAzNXonIGZpbGw9JyM1MThhYzgnLz48bGluZWFyR3JhZGllbnQgaWQ9J2InIGdyYWRpZW50VW5pdHM9J3VzZXJTcGFjZU9uVXNlJyB4MT0nOTUuOCcgeTE9JzMyLjYnIHgyPSc3NCcgeTI9JzEwNS4yJz48c3RvcCBvZmZzZXQ9JzAnIHN0b3AtY29sb3I9JyM3NmIzZTEnLz48c3RvcCBvZmZzZXQ9Jy41JyBzdG9wLWNvbG9yPScjNDM3N2JiJy8+PHN0b3Agb2Zmc2V0PScxJyBzdG9wLWNvbG9yPScjMWYzYjc3Jy8+PC9saW5lYXJHcmFkaWVudD48cGF0aCBkPSdNNTIgMzVsLTQgMWMtMTcgNS0yMiAyMS0xMyAzNSAxMCAxMyAzMSAyMCA0OCAxNWw2Mi0yMVM5MiAyNiA1MiAzNXonIG9wYWNpdHk9Jy4zJyBmaWxsPSd1cmwoI2IpJy8+PGxpbmVhckdyYWRpZW50IGlkPSdjJyBncmFkaWVudFVuaXRzPSd1c2VyU3BhY2VPblVzZScgeDE9JzE4LjQnIHkxPSc2NC4yJyB4Mj0nMTQ0LjMnIHkyPScxNDkuOCc+PHN0b3Agb2Zmc2V0PScwJyBzdG9wLWNvbG9yPScjMzE1YWE5Jy8+PHN0b3Agb2Zmc2V0PScuNScgc3RvcC1jb2xvcj0nIzUxOGFjOCcvPjxzdG9wIG9mZnNldD0nMScgc3RvcC1jb2xvcj0nIzMxNWFhOScvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZD0nTTEzNCA4MGE0NSA0NSAwIDAwLTQ4LTE1TDI0IDg1IDQgMTIwbDExMiAxOSAyMC0zNmM0LTcgMy0xNS0yLTIzeicgZmlsbD0ndXJsKCNjKScvPjxsaW5lYXJHcmFkaWVudCBpZD0nZCcgZ3JhZGllbnRVbml0cz0ndXNlclNwYWNlT25Vc2UnIHgxPSc3NS4yJyB5MT0nNzQuNScgeDI9JzI0LjQnIHkyPScyNjAuOCc+PHN0b3Agb2Zmc2V0PScwJyBzdG9wLWNvbG9yPScjNDM3N2JiJy8+PHN0b3Agb2Zmc2V0PScuNScgc3RvcC1jb2xvcj0nIzFhMzM2YicvPjxzdG9wIG9mZnNldD0nMScgc3RvcC1jb2xvcj0nIzFhMzM2YicvPjwvbGluZWFyR3JhZGllbnQ+PHBhdGggZD0nTTExNCAxMTVhNDUgNDUgMCAwMC00OC0xNUw0IDEyMHM1MyA0MCA5NCAzMGwzLTFjMTctNSAyMy0yMSAxMy0zNHonIGZpbGw9J3VybCgjZCknLz48L3N2Zz4="; |
| test("should build with a server function w/ form data", async ({ page }) => { | ||
| await page.goto("http://localhost:3000/server-function-form-data"); | ||
| await expect(page.locator("#server-fn-test")).toContainText('{"result":true}'); | ||
| }); |
There was a problem hiding this comment.
A new Blob server-function route was added (/server-function-blob), but there is no e2e coverage for it here. Consider adding an e2e test for the blob round-trip (or removing the route if it's not intended to be exercised) so the new body-format handling stays covered.
| }); | |
| }); | |
| test("should build with a server function w/ blob data", async ({ page }) => { | |
| await page.goto("http://localhost:3000/server-function-blob"); | |
| await expect(page.locator("#server-fn-test")).toContainText('{"result":true}'); | |
| }); |
| import { | ||
| deserializeJSONStream, | ||
| deserializeJSStream, | ||
| // serializeToJSONStream, | ||
| serializeToJSONString, | ||
| } from "./serialization.ts"; | ||
| import { BODY_FORMAL_FILE, BODY_FORMAT_KEY, BodyFormat, extractBody, getHeadersAndBody } from "./server-functions-shared.ts"; |
There was a problem hiding this comment.
deserializeJSONStream / deserializeJSStream and BODY_FORMAL_FILE are imported but unused in this module, and there is commented-out code around serializeToJSONStream. Please remove unused imports and stale commented code to keep the runtime lean and avoid confusion about which serialization path is active.
| middleware?: string; | ||
| serialization?: { | ||
| // This only matters for server function responses | ||
| mode?: 'js' | 'json'; |
There was a problem hiding this comment.
Quote style here is inconsistent with the repo formatter config (.oxfmtrc.json has singleQuote: false). Use double quotes for the string union values to avoid churn/formatting failures.
| mode?: 'js' | 'json'; | |
| mode?: "js" | "json"; |
| "import.meta.env.START_APP_ENTRY": JSON.stringify(appEntryPath), | ||
| "import.meta.env.START_CLIENT_ENTRY": JSON.stringify(handlers.client), | ||
| "import.meta.env.START_DEV_OVERLAY": JSON.stringify(start.devOverlay), | ||
| "import.meta.env.SEROVAL_MODE": JSON.stringify(start.serialization?.mode || 'json'), |
There was a problem hiding this comment.
This define uses single quotes, which conflicts with the repo oxfmt config (singleQuote: false). Use double quotes for the default value to match the enforced formatting.
| "import.meta.env.SEROVAL_MODE": JSON.stringify(start.serialization?.mode || 'json'), | |
| "import.meta.env.SEROVAL_MODE": JSON.stringify(start.serialization?.mode || "json"), |
| const file = value.get('example') as File; | ||
| return await file.text(); |
There was a problem hiding this comment.
This file uses single quotes in several new strings, which conflicts with the repo formatter config (.oxfmtrc.json sets singleQuote: false). Please switch to double quotes so pnpm format doesn't rewrite these lines.
| export const enum BodyFormat { | ||
| Seroval = "0", | ||
| String = "1", | ||
| FormData = "2", | ||
| URLSearchParams = "3", | ||
| Blob = "4", | ||
| File = "5", | ||
| ArrayBuffer = "6", | ||
| Uint8Array = "7", | ||
| } |
There was a problem hiding this comment.
BodyFormat is declared as a const enum, but this package is built with tsc + isolatedModules: true (and likely esbuild for TS transpilation). const enum will cause compilation/transpilation failures in isolated module builds. Use a regular enum, or replace it with a const object (as const) plus a string-literal union type.
| case startType === BodyFormat.Uint8Array: | ||
| return await clone.bytes(); |
There was a problem hiding this comment.
clone.bytes() is not part of the standard Fetch API and is not available in most browsers/undici. For Uint8Array bodies, use await clone.arrayBuffer() and wrap it in new Uint8Array(...) (or handle both cases if you want to support runtimes that implement bytes()).
| case startType === BodyFormat.Uint8Array: | |
| return await clone.bytes(); | |
| case startType === BodyFormat.Uint8Array: { | |
| const anyClone = clone as any; | |
| if (typeof anyClone.bytes === "function") { | |
| return await anyClone.bytes(); | |
| } | |
| const buffer = await clone.arrayBuffer(); | |
| return new Uint8Array(buffer); | |
| } |
Pretty straight forward. Adds an opt-in mode to use json mode (set by default) for seroval streaming, this is because the js stream is affected by CSP.
Also adds streaming support for client-to-server communication (except for url-encoded requests), assuming that the browser it comes from supports it.