Commit 70e1db3deb6 for nodejs

commit 70e1db3deb6ed16dad31ace0dbc61e0d8c6be0ff
Author: Matteo Collina <hello@matteocollina.com>
Date:   Mon Nov 2 09:35:07 2026 +0100

    stream: reject writes during WritableStream close

    WritableStreamDefaultControllerProcessClose clears the controller
    algorithms while the stream is still 'writable', before the sink close
    settles. A write in that window, such as writer.write() after
    writer.close() while the sink's close() or a TransformStream's flush()
    is pending, reached the cleared size algorithm and failed an internal
    assertion instead of being rejected as closing. Accept that state in
    writableStreamDefaultControllerGetChunkSize so the write is rejected
    with a TypeError, as it is once the stream has closed.

    Refs: https://github.com/nodejs/node/issues/57272
    Refs: https://github.com/whatwg/streams/issues/1341
    Signed-off-by: Matteo Collina <hello@matteocollina.com>
    PR-URL: https://github.com/nodejs/node/pull/67058
    Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
    Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>

diff --git a/lib/internal/webstreams/writablestream.js b/lib/internal/webstreams/writablestream.js
index dfde280e2da..d790264d000 100644
--- a/lib/internal/webstreams/writablestream.js
+++ b/lib/internal/webstreams/writablestream.js
@@ -1264,9 +1264,11 @@ function writableStreamDefaultControllerGetChunkSize(controller, chunk) {
     sizeAlgorithm,
   } = controller[kState];
   if (sizeAlgorithm === undefined) {
-    assert(stream[kState].state === 'closed' ||
-           stream[kState].state === 'errored' ||
-           stream[kState].state === 'erroring');
+    // The algorithms are also cleared while the close request is in
+    // flight, before the stream leaves the 'writable' state; the caller
+    // then rejects the write as closing.
+    assert(stream[kState].state !== 'writable' ||
+           stream[kState].closeQueuedOrInFlight);
     return 1;
   }

diff --git a/test/parallel/test-whatwg-writablestream-close.js b/test/parallel/test-whatwg-writablestream-close.js
index 1b987cf0c41..d89340cbfcb 100644
--- a/test/parallel/test-whatwg-writablestream-close.js
+++ b/test/parallel/test-whatwg-writablestream-close.js
@@ -27,3 +27,40 @@ test('should throw error when writing after close', async (t) => {
     }
   );
 });
+
+test('should reject writes while the close is in flight', async () => {
+  const { promise, resolve } = Promise.withResolvers();
+  const writable = new WritableStream({
+    close() {
+      return promise;
+    },
+  });
+
+  const writer = writable.getWriter();
+  const closed = writer.close();
+  // Let the close request reach the sink.
+  await new Promise(setImmediate);
+
+  await assert.rejects(writer.write('World'), { name: 'TypeError' });
+
+  resolve();
+  await closed;
+});
+
+test('should reject writes to a TransformStream while flush() is pending', async () => {
+  const { promise, resolve } = Promise.withResolvers();
+  const transform = new TransformStream({
+    flush() {
+      return promise;
+    },
+  });
+
+  const writer = transform.writable.getWriter();
+  const closed = writer.close();
+  await new Promise(setImmediate);
+
+  await assert.rejects(writer.write('World'), { name: 'TypeError' });
+
+  resolve();
+  await closed;
+});