Commit ec5274befe6 for nodejs

commit ec5274befe6aefb6ca82896f2e8823a195b025ce
Author: James M Snell <jasnell@gmail.com>
Date:   Sat Oct 3 14:51:44 2026 +0000

    stream: bound pre-batched async values in from()

    When an async source yielded an already-batched Uint8Array[] value,
    from() passed it through as-is, however large it was. Every other
    input shape (a sync source, or an array passed to from() or
    fromSync() directly) splits such batches into batches of at most 128
    chunks, which bounds the memory transforms must allocate per batch.

    Apply the same bound to async sources. Batches within the bound are
    still passed through without copying.

    Assisted-by: OpenCode
    Signed-off-by: James M Snell <jasnell@gmail.com>
    PR-URL: https://github.com/nodejs/node/pull/66483
    Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>

diff --git a/lib/internal/streams/iter/from.js b/lib/internal/streams/iter/from.js
index cac8fd3565b..841041469fc 100644
--- a/lib/internal/streams/iter/from.js
+++ b/lib/internal/streams/iter/from.js
@@ -547,9 +547,7 @@ async function* normalizeAsyncSource(source, context) {
     for await (const value of iterable) {
       // Fast path 1: value is already a Uint8Array[] batch
       if (isUint8ArrayBatch(value)) {
-        if (value.length > 0) {
-          yield value;
-        }
+        yield* yieldBoundedBatch(value);
         continue;
       }
       // Fast path 2: value is a single Uint8Array (very common)
diff --git a/test/parallel/test-stream-iter-from-async.js b/test/parallel/test-stream-iter-from-async.js
index 29ecdf42576..2be5a2c55e4 100644
--- a/test/parallel/test-stream-iter-from-async.js
+++ b/test/parallel/test-stream-iter-from-async.js
@@ -105,6 +105,27 @@ async function testFromBoundsNestedAsyncIterable() {
   assert.strictEqual(nestedClosed, true);
 }

+async function testFromBoundsPreBatchedAsyncValues() {
+  // An async source yielding an already-batched Uint8Array[] larger than the
+  // batch bound is split, like the same batch from a sync source.
+  const big = Array.from({ length: 300 }, (_, i) => new Uint8Array([i & 0xff]));
+  async function* source() {
+    yield big;
+  }
+  const sizes = [];
+  for await (const batch of from(source())) sizes.push(batch.length);
+  assert.deepStrictEqual(sizes, [128, 128, 44]);
+
+  // Batches within the bound are still passed through as-is.
+  const small = [new Uint8Array([1]), new Uint8Array([2])];
+  async function* smallSource() {
+    yield small;
+  }
+  for await (const batch of from(smallSource())) {
+    assert.strictEqual(batch, small);
+  }
+}
+
 async function testFromSyncIterableAsAsync() {
   // Sync iterable passed to from() should work
   function* gen() {
@@ -464,6 +485,7 @@ Promise.all([
   testFromAsyncIteratorResultShapes(),
   testFromSourceErrorDoesNotWaitForReturn(),
   testFromBoundsNestedAsyncIterable(),
+  testFromBoundsPreBatchedAsyncValues(),
   testFromSyncIterableAsAsync(),
   testFromSyncIterableAwaitsPromiseValues(),
   testFromSyncIterableRejectsNestedAsyncIterable(),