diff --git a/lib/internal/webstreams/adapters.js b/lib/internal/webstreams/adapters.js index 188f715a62d3c1..f19ac70eeb7982 100644 --- a/lib/internal/webstreams/adapters.js +++ b/lib/internal/webstreams/adapters.js @@ -238,6 +238,9 @@ function newWritableStreamFromStreamWritable(streamWritable, options = kEmptyObj options[kValidateChunk]?.(chunk); if (streamWritable.writableNeedDrain || !streamWritable.write(chunk)) { backpressurePromise = PromiseWithResolvers(); + if (!streamWritable.writableNeedDrain) { + backpressurePromise.resolve(); + } return SafePromisePrototypeFinally( backpressurePromise.promise, () => { backpressurePromise = undefined; diff --git a/test/parallel/test-whatwg-webstreams-adapters-to-writablestream.js b/test/parallel/test-whatwg-webstreams-adapters-to-writablestream.js index 23e6319563daa0..60c0538a0c1efb 100644 --- a/test/parallel/test-whatwg-webstreams-adapters-to-writablestream.js +++ b/test/parallel/test-whatwg-webstreams-adapters-to-writablestream.js @@ -197,3 +197,26 @@ class TestWritable extends Writable { assert.strictEqual(chunk, arrayBuffer); })); } + +{ + // Test that the stream doesn't hang when the underlying Writable + // emits 'drain' synchronously during write(). + // Fixes: https://github.com/nodejs/node/issues/61145 + const writable = new Writable({ + write(chunk, encoding, callback) { + callback(); + }, + }); + + // Force synchronous 'drain' emission during write() + // to simulate a stream that doesn't have Node.js's built-in kSync protection. + writable.write = function(chunk) { + this.emit('drain'); + return false; + }; + + const writableStream = newWritableStreamFromStreamWritable(writable); + const writer = writableStream.getWriter(); + writer.write(new Uint8Array([1, 2, 3])).then(common.mustCall()); + writer.write(new Uint8Array([4, 5, 6])).then(common.mustCall()); +}