-
Notifications
You must be signed in to change notification settings - Fork 29.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
filehandle.readableWebStream() chunks return incompatible ArrayBuffer
instead of Uint8Array
#54041
Comments
Taking a look 👀 |
My understanding is that the The best solution I could recommend right now is to maybe use a Also, I assume the code you provided is just for reproduction purposes, but it's pretty inefficient to go from Node Stream to Web Stream back to Node stream. Keep it all as a Node stream, or convert it to Web stream and keep it as that. |
Roughly:
🤷♂️ |
Regarding an actual fix to Node.js, I'd say we have to improve |
Oh ok, interesting - or should there a better default for
Right, I can see how converting back and forth multiple times with this code would seem unrealistic or add overhead. But this may not be so unrealistic if working with a Node.js framework that expects Web streams in user code - eg. Route Handlers in Next.js:
import fs from "fs/promises"
import path from "path"
export const dynamic = 'force-dynamic'
export async function GET(request: Request) {
const filePath = path.resolve("./public/image.jpg")
const stats = await fs.stat(filePath);
const fileHandle = await fs.open(filePath)
const stream = fileHandle.readableWebStream()
return new Response(stream, {
status: 200,
headers: new Headers({
"content-disposition": `attachment; filename=${path.basename(filePath)}`,
"content-type": "image/jpeg",
"content-length": stats.size + "",
})
}) ...where in the background, there may be code like this to convert it to a Node.js stream:
If there was a mode / way of working to instead keep everything as a Web stream, and also serve up Web streams from a Node.js response with |
Maybe, I'm trying to think through where to best "fix" this. Because both side's limitation make sense to me. On one hand, you don't really want |
FWIW, The |
Ah I misunderstood the code here node/lib/internal/fs/promises.js Lines 284 to 335 in 2d1b4a8
Do you foresee any issue with that change in default? |
I wouldn't imagine any issues but it would need to be a semvver-major change that should be called out in notable changes. |
@karlhorky ... can you verify quickly if |
Should be pretty easy to change the CodeSandbox linked above yep. Although probably I'll need to check that out tomorrow |
The method is still labeled as experimental in the docs, so would it really be a major change? I think a fix is appropriate |
Seems to work, yes! 👍 CodeSandbox: https://codesandbox.io/p/devbox/filehandle-readablewebstream-with-new-response-forked-mszlgw?file=%2Findex.js Changes to original sandbox from PR description:
cc @eric-burel |
@karlhorky absolutely wonderful, I'll update my resources on the topic to match this API.
When passing the stream to Note that you can't close a file after the Response is sent in Next.js, so no way to properly close the file (closing it before the stream is sent will trigger an error as expected). |
@eric-burel that is an issue on the Next.js side. I believe it is a mismatch between Node.js Web Stream types and the Web Stream types from TypeScript's standard library ( |
I'm looking into this problem and I'm not sure why the stream should ever be allowed to not be byte-oriented. It's not clear to me why this should be an option in the API at all. For example, as far as I know, the Node stream APIs in |
The original implementation of the experimental `FileHandle.readableWebStream` API created non-`type: 'bytes'` streams, which prevented callers from creating `mode: 'byob'` readers from the returned stream, which means they could not achieve the associated "zero-copy" performance characteristics. Then, nodejs#46933 added a parameter allowing callers to pass the `type` parameter down to the ReadableStream constructor, exposing the same semantics to callers of `FileHandle.readableWebStream`. But there is no point to giving callers this choice: FileHandle-derived streams are by their very nature byte streams. We should not require callers to explicitly opt in to having byte stream semantics. Moreover, I do not see a situation in which callers would ever want to have a non-bytes stream: bytes-streams only do anything differently than normal ones if `mode: 'byob'` is passed to `getReader`. So, remove the `options` parameter and always create a ReadableStream with `type: 'bytes'`. Fixes nodejs#54041.
The original implementation of the experimental `FileHandle.readableWebStream` API created non-`type: 'bytes'` streams, which prevented callers from creating `mode: 'byob'` readers from the returned stream, which means they could not achieve the associated "zero-copy" performance characteristics. Then, nodejs#46933 added a parameter allowing callers to pass the `type` parameter down to the ReadableStream constructor, exposing the same semantics to callers of `FileHandle.readableWebStream`. But there is no point to giving callers this choice: FileHandle-derived streams are by their very nature byte streams. We should not require callers to explicitly opt in to having byte stream semantics. Moreover, I do not see a situation in which callers would ever want to have a non-bytes stream: bytes-streams only do anything differently than normal ones if `mode: 'byob'` is passed to `getReader`. So, remove the `options` parameter and always create a ReadableStream with `type: 'bytes'`. Fixes nodejs#54041.
The original implementation of the experimental `FileHandle.readableWebStream` API created non-`type: 'bytes'` streams, which prevented callers from creating `mode: 'byob'` readers from the returned stream, which means they could not achieve the associated "zero-copy" performance characteristics. Then, nodejs#46933 added a parameter allowing callers to pass the `type` parameter down to the ReadableStream constructor, exposing the same semantics to callers of `FileHandle.readableWebStream`. But there is no point to giving callers this choice: FileHandle-derived streams are by their very nature byte streams. We should not require callers to explicitly opt in to having byte stream semantics. Moreover, I do not see a situation in which callers would ever want to have a non-bytes stream: bytes-streams only do anything differently than normal ones if `mode: 'byob'` is passed to `getReader`. So, remove the `options` parameter and always create a ReadableStream with `type: 'bytes'`. Fixes nodejs#54041.
@jasnell @Ethan-Arrowood PR has been opened by @isker over here: |
The original implementation of the experimental `FileHandle.readableWebStream` API created non-`type: 'bytes'` streams, which prevented callers from creating `mode: 'byob'` readers from the returned stream, which means they could not achieve the associated "zero-copy" performance characteristics. Then, nodejs#46933 added a parameter allowing callers to pass the `type` parameter down to the ReadableStream constructor, exposing the same semantics to callers of `FileHandle.readableWebStream`. But there is no point to giving callers this choice: FileHandle-derived streams are by their very nature byte streams. We should not require callers to explicitly opt in to having byte stream semantics. Moreover, I do not see a situation in which callers would ever want to have a non-bytes stream: bytes-streams only do anything differently than normal ones if `mode: 'byob'` is passed to `getReader`. So, remove the `options` parameter and always create a ReadableStream with `type: 'bytes'`. Fixes nodejs#54041.
The original implementation of the experimental `FileHandle.readableWebStream` API created non-`type: 'bytes'` streams, which prevented callers from creating `mode: 'byob'` readers from the returned stream, which means they could not achieve the associated "zero-copy" performance characteristics. Then, nodejs#46933 added a parameter allowing callers to pass the `type` parameter down to the ReadableStream constructor, exposing the same semantics to callers of `FileHandle.readableWebStream`. But there is no point to giving callers this choice: FileHandle-derived streams are by their very nature byte streams. We should not require callers to explicitly opt in to having byte stream semantics. Moreover, I do not see a situation in which callers would ever want to have a non-bytes stream: bytes-streams only do anything differently than normal ones if `mode: 'byob'` is passed to `getReader`. So, remove the `options` parameter and always create a ReadableStream with `type: 'bytes'`. Fixes nodejs#54041.
The original implementation of the experimental `FileHandle.readableWebStream` API created non-`type: 'bytes'` streams, which prevented callers from creating `mode: 'byob'` readers from the returned stream, which means they could not achieve the associated "zero-copy" performance characteristics. Then, nodejs#46933 added a parameter allowing callers to pass the `type` parameter down to the ReadableStream constructor, exposing the same semantics to callers of `FileHandle.readableWebStream`. But there is no point to giving callers this choice: FileHandle-derived streams are by their very nature byte streams. We should not require callers to explicitly opt in to having byte stream semantics. Moreover, I do not see a situation in which callers would ever want to have a non-bytes stream: bytes-streams only do anything differently than normal ones if `mode: 'byob'` is passed to `getReader`. So, remove the `options` parameter and always create a ReadableStream with `type: 'bytes'`. Fixes nodejs#54041.
Version
v20.12.0
Platform
Subsystem
No response
What steps will reproduce the bug?
ERR_INVALID_ARG_TYPE
error belowCodeSandbox demo: https://codesandbox.io/p/devbox/filehandle-readablewebstream-with-new-response-ljysjk?file=%2Findex.js
Error:
Alternative version with
new Response()
:How often does it reproduce? Is there a required condition?
Always
What is the expected behavior? Why is that the expected behavior?
Web streams created by
fileHandle.readableWebStream()
should be compatible withReadable.fromWeb()
What do you see instead?
Web streams created by
fileHandle.readableWebStream()
should are incompatible withReadable.fromWeb()
Additional information
Also reported over here:
cc @jasnell
The text was updated successfully, but these errors were encountered: