Commit Graph
168 Commits
Author SHA1 Message Date
Jeong SeokChan 6c862f4c6f stream: fix recursive WritableStream abort
Recheck the stream state after signaling abort, as required by steps 3
and 4 of the WritableStreamAbort algorithm.

Only reject pending close promise caches, as a cache materialized after
the stream becomes errored may already contain a rejected promise.

This makes the recursive abort WPT pass and removes its expected-failure
entry.

Refs: https://streams.spec.whatwg.org/#writable-stream-abort
Signed-off-by: Jeong SeokChan <starp321@naver.com>
PR-URL: https://github.com/nodejs/node/pull/64825
Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
2026-08-06 21:25:00 +00:00
Matteo Collina 3fc98b802e stream: cut per-chunk allocations in pipeTo
readableStreamPipeTo allocated, for every chunk written to the
destination, a { promise, resolve, reject } write request record that
it immediately marked as handled, and drove its loop with an async
step()/run() pair whose implicit promises cost one allocation and one
reaction per iteration. The parked-read path additionally allocated a
read request object, a PromiseWithResolvers record, and a microtask
closure per chunk; this is the steady state for pipeThrough, since a
TransformStream's readable side has a high water mark of zero.

Replace the per-write records with a single per-pipe tracker that the
write request queue holds once per pending write and whose
resolve()/reject() methods maintain a pending-write count, drive the
pump loop with plain callbacks instead of async functions, and reuse
one read request and one forwarding function across all chunks, the
same pattern tee uses since c543cfb72b.

Benchmark results (benchmark/compare.js --runs 20):
webstreams/pipe-to.js +29.9% to +35.8% across all 16 configurations
(all 99.9% confidence); a pipeThrough(TransformStream) passthrough
loop improves ~17%; every other webstreams benchmark is unchanged.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/64890
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
2026-08-04 11:06:00 +00:00
Matteo Collina c543cfb72b stream: use the ring buffer for pending BYOB pull-into descriptors
The byte controller's [[pendingPullIntos]] list was still a plain array
consumed with ArrayPrototypeShift, while every other per-chunk queue in
the WHATWG streams implementation has moved to the Queue ring buffer.
BYOB reads push and shift one descriptor per read, and Array.prototype
shift has real per-call cost even at length 1.

Back the descriptor list with the same lazily materialized Queue used
for the request queues, so constructing a byte stream still allocates
no descriptor storage.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/64818
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-07-31 22:33:39 +00:00
Mohamed Sayed 4314d136f0 stream: fix uncatchable error closing half-open Duplex.toWeb() writable
Signed-off-by: Mohamed Sayed <k@3zrv.com>
PR-URL: https://github.com/nodejs/node/pull/64161
Fixes: https://github.com/nodejs/node/issues/64120
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Jason Zhang <xzha4350@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
2026-07-26 04:01:05 +00:00
Antoine du Hamel 15d5b8f7fe stream: remove custom CloneableDOMException implementation
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/64469
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-07-22 10:34:47 +00:00
Matteo Collina cf882a7904 stream: fold desired-size check into WHATWG backpressure update
writableStreamUpdateBackpressure ran two release-mode assertions and
took a precomputed backpressure value that every caller derived with a
separate GetBackpressure/GetDesiredSize call pair. All callers already
hold the 'writable', not-close-queued invariant the assertions checked,
so derive the backpressure from the desired size inside the function and
drop the assertions and the helper. This runs up to twice per write.

writer.write() loop: +10%, pipe-to: +4.6% avg over 16 configs (local
harness / benchmark, all configs positive).

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/64451
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-07-16 13:34:09 +02:00
Antoine du Hamel bf5c221704 stream: simplify nested PromisePrototypeThens
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/64470
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-07-15 08:42:05 +00:00
Matteo Collina ace91de608 stream: use the ring buffer for WHATWG stream request queues
The [[queue]] backing the controllers became a ring buffer, but the
read and write request queues (readRequests, readIntoRequests,
writeRequests) were left as plain arrays consumed with
ArrayPrototypeShift, which is O(n) and, even for the single pending
request of the await-each regime, far slower than an indexed head
advance. Back them with the same Queue, materialized lazily from the
shared empty queue so acquiring a reader or constructing a writer
allocates no request storage until a read or write actually parks.

pipe-to: +4.7% to +9.4% (all 16 configs, ***)
readable-read type=byob: +2.3% (**)
parked read loop: +15%, write loop: +11% (local harness)

Follow-up to https://github.com/nodejs/node/pull/64312.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/64431
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2026-07-13 20:07:12 +00:00
Matteo Collina 9f1ae2222c stream: speed up reads and iteration over default WHATWG streams
Skip the size algorithm call and its result validation when the size
algorithm is the default one, and stop re-running the full
ShouldCallPull predicate at per-chunk call sites where its inputs are
already established.

readable-async-iterator type=normal: +16.6% (***)
readable-read-buffered: +13.9% to +27.5% (**/***)
pipe-to: +3.7% to +6.0% (15/16 configs significant)

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/64320
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-07-11 08:53:54 +00:00
Yagiz Nizipli 1912893c29 stream: use ring buffer for WHATWG stream queues
The [[queue]] backing every default readable/writable controller was a
plain array of { value, size } wrappers consumed with
ArrayPrototypeShift, so each buffered chunk allocated a wrapper object
and each dequeue moved (or forced the engine to re-linearize) the
remaining elements; the byte controller queue paid the same shift cost
for its chunk descriptor records.

Replace the array with a power-of-two ring buffer. Default controller
queues store each entry as (value, size) in two consecutive slots, so
the per-chunk wrapper allocation disappears; the byte controller keeps
its descriptor records (they are mutated in place at the head) in
single slots. Controllers start from (and are reset to) a shared
immutable empty queue, so constructing a stream allocates no queue
storage until a chunk is actually buffered. Enqueues measured by the
internal default size algorithm (never observable by user code, always
returns 1, cannot throw) skip the algorithm call and its try/catch
entirely.

The layout mirrors what Bun/WebKit use for the same spec structure:
[[queue]] as a ring-buffer deque (WTF::Deque in Bun's
src/jsc/bindings/webcore/streams/StreamQueue.h), the pure-JS ring
buffer in Bun's src/js/internal/fifo.ts, and the trivial-size-algorithm
bypass in
src/jsc/bindings/webcore/streams/JSReadableStreamDefaultController.cpp.

benchmark/compare.js against the unmodified baseline (30-run capture
plus an independent 15-run repeat, Welch t-test, all p < 1e-5):
webstreams/pipe-to.js +12-17% across all sixteen high-water-mark
configurations, readable-read-buffered +20% (bufferSize=1) to +49%
(bufferSize=1000), readable-async-iterator +21%. No stable significant
regression across the rest of the webstreams suite: the creation.js and
readable-read.js deltas seen in the full-suite capture disappear in
isolated 60-run rechecks.

Refs: https://github.com/oven-sh/bun/blob/main/src/js/internal/fifo.ts
Signed-off-by: Yagiz Nizipli <yagiz@nizipli.com>
Assisted-by: Grok (Grok Build)
PR-URL: https://github.com/nodejs/node/pull/64312
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-07-08 15:05:45 +00:00
Matteo Collina 309213f5d8 stream: speed up async iteration over WHATWG byte streams
for await / reader.read() loops over byte streams were ~4x slower than
over default streams. Three per-chunk costs, none required by the spec:

- ArrayBufferViewGetBuffer/ByteLength/ByteOffset went through
  ReflectGet(view.constructor.prototype, ...), a reflective get that is
  ~3.5x slower than the original prototype getters from primordials and
  spoofable through a user-defined .constructor to boot.

- The buffered fast paths in ReadableStreamDefaultReader.read() and the
  async iterator only covered default controllers, so byte streams with
  queued data still allocated a read request and PromiseWithResolvers
  per chunk. Byte-queue dequeue is fully synchronous (it is the
  queue-filled arm of the byte controller's pull steps), so both fast
  paths now resolve directly from the byte queue.

- readableByteStreamControllerEnqueue re-ran the reader brand check and
  re-loaded the read request list four times per chunk across
  HasDefaultReader / ProcessReadRequestsUsingQueue / GetNumReadRequests
  / FulfillReadRequest; it now does a single pass. The async iterator
  also reuses its read request object across reads (at most one is ever
  in flight).

benchmark/webstreams interleaved same-day A/B, --runs 10:
readable-async-iterator bytes +16.3% (***), readable-read byob +9.1%
(***), all other rows neutral. Profiler harness: parked byte iteration
+14%, buffered byte iteration +37%, buffered byte read loop +18%,
default-stream rows at parity. WPT streams/compression/encoding
subtests identical to baseline.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/64291
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-07-07 09:38:24 +00:00
Antoine du Hamel 3ee5f31b9b stream: refactor unnecessary optional chaining away
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/64253
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-07-04 19:14:16 +02:00
Matteo Collina cc05d1cf58 stream: cut per-chunk overhead in WHATWG streams
Consolidate the spec's per-chunk predicate chains (CanCloseOrEnqueue,
IsLocked, HasDefaultReader, GetNumReadRequests, GetDesiredSize and the
writable-side equivalents) into single passes over the controller and
stream state, mirror "close queued or in flight" as a boolean flag
maintained at the few close-request transition sites, and materialize
the TransformStream [[backpressureChangePromise]] record lazily on
first observation so backpressure flips nobody is waiting on allocate
nothing.

Assisted-by: Claude Code
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/64252
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-07-04 05:54:40 +00:00
Matteo Collina ca406b2b9a stream: fix Writable.toWeb() desiredSize for non-object-mode
Writable.toWeb() used a plain { highWaterMark } as the queuing
strategy for non-object-mode streams, which meant no size function
was provided. The WritableStream defaulted to counting each chunk
as size 1, so desiredSize was incorrect (e.g., a 3-byte Uint8Array
was counted as size 1 instead of 3).

Add a size() function to the strategy that mirrors how the Node.js
stream computes chunk length: byteLength for typed arrays, length
for strings/buffers, falling back to 1.

Fixes: https://github.com/nodejs/node/issues/56269
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/62986
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-06-21 21:56:57 +00:00
Matteo Collina fa2eaa54fb stream: reduce allocations on WHATWG streams hot paths
Pure-JavaScript optimizations to lib/internal/webstreams/* that reduce
per-chunk and per-construction allocations on hot paths without
observable behavior change.

Per-chunk: reuse promise-reaction closures per controller, add buffered
fast path for async iterator, specialize callback wrappers by arity,
and share immutable nil records for writable stream resets.

Per-construction: use queueMicrotask for non-object start results,
materialize reader/writer .closed and .ready records lazily, and remove
dead allocations.

Assisted-by: Claude Fable 5
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/63876
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2026-06-20 14:19:08 +00:00
Antoine du HamelandMatteo Collina 65ffd025a5 stream: only pass the expected number of parameters to callbacks
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
Co-authored-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/63909
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-06-16 09:35:29 +00:00
Matteo Collina 6af90267de stream: optimize pipeTo promise handling
Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/63572
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2026-06-02 15:57:37 +00:00
Trivikram Kamat 92f48f43fe tools: enforce iterator result property order
Add a custom ESLint rule requiring iterator result objects to place
`done` before `value`, and update existing lib iterator result objects
to follow the rule.

Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: openai:gpt-5.5
PR-URL: https://github.com/nodejs/node/pull/63526
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-05-26 17:19:42 +00:00
sangwook 7e7bde86b3 stream: fix Writable.toWeb() hang on synchronous drain
A race condition in the Writable.toWeb() adapter caused the stream
to hang if the underlying Node.js Writable emitted a 'drain' event
synchronously during a write() call. This often happened when
highWaterMark was set to 0.

By checking writableNeedDrain immediately after a backpressured write,
the adapter now correctly detects if the stream has already drained,
resolving the backpressure promise instead of waiting indefinitely
for an event that has already occurred.

Fixes: https://github.com/nodejs/node/issues/61145
Signed-off-by: sangwook <rewq5991@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/61197
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-05-22 06:21:25 +00:00
ikeyan 783b382483 stream: align Readable.toWeb termination with eos
PR-URL: https://github.com/nodejs/node/pull/62394
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-05-19 15:38:22 +02:00
Antoine du Hamel 13c2374d0b stream: remove unnecessary check
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/63030
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
2026-05-16 19:27:02 +00:00
RoomWithOutRoof 0a60e9013b lib: narrow ReadableStreamBYOBRequest.view return type to Uint8Array
Follow WHATWG streams spec update: https://github.com/whatwg/streams/pull/1367

ReadableStreamBYOBRequest.view is always constructed as a Uint8Array.

This changes the documented return type from ArrayBufferView to
Uint8Array per the updated spec.

Fixes: https://github.com/nodejs/node/issues/62952

Signed-off-by: Jah-yee <166608075+Jah-yee@users.noreply.github.com>
PR-URL: https://github.com/nodejs/node/pull/63017
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Jason Zhang <xzha4350@gmail.com>
2026-05-11 07:36:19 +00:00
Antoine du Hamel 7eab492728 stream: copyedit webstreams/adapter.js
- Simplify `ZLIB_FAILURES` creation.
- Cache `cause.code` in `handleKnownInternalErrors` in case of a getter.
- Replace `SafePromiseAll` with `SafePromiseAllReturnVoid` to reduce the
  number of allocated promises.

Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/63034
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-05-04 16:31:06 +00:00
Antoine du Hamel 266cd6749d stream: remove duplicated utility
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/63031
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-05-04 16:07:26 +00:00
Antoine du Hamel 5e61a07d03 stream: simplify setPromiseHandled utility
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/63032
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-05-01 22:08:25 +00:00
Daeyeon Jeong 42a154bad1 stream: validate ReadableStream.from iterator objects
Signed-off-by: Daeyeon Jeong <daeyeon.dev@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/62911
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
2026-04-25 14:31:42 +00:00
Filip Skokan 978a8c405e lib: fix lint in internal/webstreams/util.js
PR-URL: https://github.com/nodejs/node/pull/62806
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
Reviewed-By: Richard Lau <richard.lau@ibm.com>
2026-04-18 20:03:12 +02:00
Antoine du Hamel 1266013d19 stream: simplify readableStreamFromIterable
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/62651
Reviewed-By: Aviv Keller <me@aviv.sh>
2026-04-18 14:27:54 +00:00
Ali Hassan bee1087258 lib: reject SharedArrayBuffer in web APIs per spec
Signed-off-by: Ali Hassan <ali-hassan27@outlook.com>
PR-URL: https://github.com/nodejs/node/pull/62632
Refs: https://github.com/nodejs/node/issues/59688
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2026-04-16 19:53:24 +00:00
René 9cae81932c stream: allow shared array buffer sources in writable webstream adapter
Refs: https://github.com/nodejs/node/pull/61913
Signed-off-by: Renegade334 <contact.9a5d6388@renegade334.me.uk>
PR-URL: https://github.com/nodejs/node/pull/62163
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-04-13 15:42:29 +00:00
Antoine du Hamel 0fea43023a stream: simplify createPromiseCallback
Signed-off-by: Antoine du Hamel <duhamelantoine1995@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/62650
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-04-11 15:45:39 +00:00
sangwook 20cacec5c6 stream: fix writev unhandled rejection in fromWeb
When using Duplex.fromWeb() or Writable.fromWeb() with cork()/uncork(),
writes are batched into _writev(). If destroy() is called in the same
microtask, the underlying WritableStream writer gets aborted, causing
SafePromiseAll() to reject with a non-array value (e.g. an AbortError).

The done() callback in _writev() of both fromWeb adapter functions
unconditionally called error.filter(), assuming the value was always an
array. This caused a TypeError that became an unhandled rejection,
crashing the process.

Fix by separating the resolve and reject handlers of SafePromiseAll:
use () => done() on the resolve path (all writes succeeded, no error)
and done on the reject path (error passed directly to callback).

Fixes: https://github.com/nodejs/node/issues/62199
Signed-off-by: sangwook <rewq5991@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/62297
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
2026-04-10 20:39:49 +00:00
René ac6375417a stream: promote DEP0201 to runtime deprecation
PR-URL: https://github.com/nodejs/node/pull/62173
Refs: https://github.com/nodejs/node/pull/61632
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Jake Yuesong Li <jake.yuesong@gmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2026-03-17 13:38:50 +00:00
Mattias Buelens f82525e9c8 stream: optimize webstreams pipeTo
PR-URL: https://github.com/nodejs/node/pull/62079
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-03-09 03:18:17 +00:00
Filip Skokan 3725bd2145 stream: fix brotli error handling in web compression streams
Convert brotli decompression errors to TypeError to match the
Compression Streams spec, by extending handleKnownInternalErrors()
in the adapters layer to recognize brotli error codes.

This replaces the manual error event handler on DecompressionStream
which was redundant with the adapter's built-in error propagation.

PR-URL: https://github.com/nodejs/node/pull/62107
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
2026-03-06 22:08:57 +00:00
Filip Skokan 7991cd2a71 stream: improve Web Compression spec compliance
Pass rejectGarbageAfterEnd: true to createInflateRaw() and
createBrotliDecompress(), matching the behavior already in place
for deflate and gzip. The Compression Streams spec treats any
data following a valid compressed payload as an error.

When the underlying Node.js stream throws synchronously from
write() (e.g. zlib rejects an invalid chunk type), destroy the
stream so that the readable side is also errored. Without this,
the readable side hangs forever waiting for data that will never
arrive.

Introduce a kValidateChunk callback option in the webstreams
adapter layer. Compression streams use this to validate that
chunks are BufferSource instances not backed by SharedArrayBuffer,
replacing the previous monkey-patching of the underlying
handle's write method.

Unskip WPT compression bad-chunks tests which now run instead of
hang and mark the remaining expected failures.

PR-URL: https://github.com/nodejs/node/pull/62107
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
2026-03-06 22:08:56 +00:00
Marco 16472884aa stream: fix TransformStream race on cancel with pending write
Signed-off-by: marcopiraccini <marco.piraccini@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/62040
Fixes: https://github.com/nodejs/node/issues/62036
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
2026-03-04 16:02:27 +00:00
조수민 cb6ff03cc5 stream: accept ArrayBuffer in CompressionStream and DecompressionStream
PR-URL: https://github.com/nodejs/node/pull/61913
Fixes: https://github.com/nodejs/node/issues/43433
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Jason Zhang <xzha4350@gmail.com>
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
2026-03-02 23:15:09 +00:00
Matteo Collina abddfc921b stream: fix pipeTo to defer writes per WHATWG spec
The WHATWG Streams spec requires that pipeTo's chunk handling must
queue a microtask before calling the write algorithm. This ensures
that enqueue() does not synchronously trigger writes.

Previously, PipeToReadableStreamReadRequest[kChunk] would synchronously
call writableStreamDefaultWriterWrite(), which violated the spec and
caused the WPT test "enqueue() must not synchronously call write
algorithm" to fail.

Fix by wrapping the write operation in queueMicrotask(), which defers
it to the next microtask as required by the spec.

Refs: https://github.com/whatwg/streams/issues/1243
PR-URL: https://github.com/nodejs/node/pull/61800
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
2026-02-26 07:54:39 +00:00
Matteo CollinaandMalte Ubl 199daab0b0 stream: add fast paths for webstreams read and pipeTo
Add internal fast paths to improve webstreams performance without
changing the public API or breaking spec compliance.

1. ReadableStreamDefaultReader.read() fast path:
   When data is already buffered in the controller's queue, return
   PromiseResolve() directly without creating a DefaultReadRequest
   object. This is spec-compliant because read() returns a Promise,
   and resolved promises still run callbacks in the microtask queue.

2. pipeTo() batch read fast path:
   When data is buffered, batch reads directly from the controller
   queue up to highWaterMark without creating
   PipeToReadableStreamReadRequest objects per chunk. Respects
   backpressure by checking desiredSize after each write.

Benchmark results:
  - pipeTo:          ~11% faster (***)
  - buffered read(): ~17-20% faster (***)

Co-Authored-By: Malte Ubl <malte@vercel.com>
PR-URL: https://github.com/nodejs/node/pull/61807
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
2026-02-19 21:53:46 +00:00
René 04946a7a8c stream: rename Duplex.toWeb() type option to readableType
PR-URL: https://github.com/nodejs/node/pull/61632
Refs: https://github.com/nodejs/node/pull/58664
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
2026-02-11 02:15:43 +00:00
René 5d39030b2e stream: export namespace object from internal end-of-stream module
PR-URL: https://github.com/nodejs/node/pull/61455
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
2026-01-23 11:47:27 +00:00
René ecdf6a8c53 stream: fix isErrored/isWritable for WritableStreams
PR-URL: https://github.com/nodejs/node/pull/60905
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
2025-12-03 13:08:34 +00:00
Michaël Zasso 10837e33b0 lib,test: fix jsdoc comments
To prepare for eslint-plugin-jsdoc update.

Refs: https://github.com/nodejs/node/pull/60535
PR-URL: https://github.com/nodejs/node/pull/60870
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
2025-11-30 19:14:12 +01:00
Hans Klunder 33b1574cbf lib: add support for readable byte streams to .toWeb()
Add support for the creation of ReadableByteStream to Readable.toWeb()
and Duplex.toWeb()
This enables the use of .getReader({ mode: "byob" }) on
e.g. socket().toWeb()

Refs: https://github.com/nodejs/node/issues/56004#issuecomment-2908265316
Refs: https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_byte_streams
PR-URL: https://github.com/nodejs/node/pull/58664
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2025-11-16 06:51:24 +00:00
Khafra 44d9e6d8ad stream: add brotli support to CompressionStream and DecompressionStream
Refs: https://github.com/whatwg/compression/issues/34
PR-URL: https://github.com/nodejs/node/pull/59464
Reviewed-By: Mattias Buelens <mattias@buelens.com>
Reviewed-By: Jason Zhang <xzha4350@gmail.com>
Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
2025-08-21 02:22:19 +00:00
Yagiz Nizipli 0fd1ecded6 meta: enable jsdoc/check-tag-names rule
PR-URL: https://github.com/nodejs/node/pull/58521
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: LiviaMedeiros <livia@cirno.name>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2025-07-18 09:28:21 +00:00
0hm☘️ 62855f3b8c stream: making DecompressionStream spec compilent for trailing junk
Introduce `ERR_TRAILING_JUNK_AFTER_STREAM_END`
error to handle unexpected data after the end of
a compressed stream. This ensures proper error
reporting when decompressing deflate or gzip
streams with trailing junk. Added tests to
verify the behavior.

Fixes: https://github.com/nodejs/node/issues/58247
PR-URL: https://github.com/nodejs/node/pull/58316
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Matthew Aitken <maitken033380023@gmail.com>
2025-05-26 00:38:39 +00:00
Daeyeon Jeong c566639026 stream: fix sizeAlgorithm validation in WritableStream
Signed-off-by: Daeyeon Jeong <daeyeon.dev@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/57280
Fixes: https://github.com/nodejs/node/issues/57272
Refs: https://github.com/nodejs/node/pull/56067
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Minwoo Jung <nodecorelab@gmail.com>
Reviewed-By: Jason Zhang <xzha4350@gmail.com>
2025-03-05 03:04:39 +00:00
James M Snell 85c0f7aef3 lib: fixup more incorrect ERR_INVALID_ARG_VALUE uses
PR-URL: https://github.com/nodejs/node/pull/57177
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
2025-02-24 23:23:32 +00:00