* Create a pair of connected duplex channels for bidirectional communication. * @param {{ highWaterMark?: number, backpressure?: string, signal?: AbortSignal, * a?: object, b?: object }} [options] * @returns {[DuplexChannel, DuplexChannel]}
(options = { __proto__: null })
| 25 | * @returns {[DuplexChannel, DuplexChannel]} |
| 26 | */ |
| 27 | function duplex(options = { __proto__: null }) { |
| 28 | validateObject(options, 'options'); |
| 29 | const { highWaterMark, backpressure, signal, a, b } = options; |
| 30 | if (a !== undefined) { |
| 31 | validateObject(a, 'options.a'); |
| 32 | } |
| 33 | if (b !== undefined) { |
| 34 | validateObject(b, 'options.b'); |
| 35 | } |
| 36 | if (signal !== undefined) { |
| 37 | validateAbortSignal(signal, 'options.signal'); |
| 38 | } |
| 39 | |
| 40 | // Channel A writes to B's readable (A->B direction). |
| 41 | // Signal is NOT passed to push() -- we handle abort via close() below. |
| 42 | const { writer: aWriter, readable: bReadable } = push({ |
| 43 | highWaterMark: a?.highWaterMark ?? highWaterMark, |
| 44 | backpressure: a?.backpressure ?? backpressure, |
| 45 | }); |
| 46 | |
| 47 | // Channel B writes to A's readable (B->A direction) |
| 48 | const { writer: bWriter, readable: aReadable } = push({ |
| 49 | highWaterMark: b?.highWaterMark ?? highWaterMark, |
| 50 | backpressure: b?.backpressure ?? backpressure, |
| 51 | }); |
| 52 | |
| 53 | let aClosed = false; |
| 54 | let bClosed = false; |
| 55 | // Track active iterators so close() can call .return() on them |
| 56 | let aReadableIterator = null; |
| 57 | let bReadableIterator = null; |
| 58 | |
| 59 | const channelA = { |
| 60 | __proto__: null, |
| 61 | get writer() { return aWriter; }, |
| 62 | // Wrap readable to track the iterator for cleanup on close() |
| 63 | get readable() { |
| 64 | return { |
| 65 | __proto__: null, |
| 66 | [SymbolAsyncIterator]() { |
| 67 | const iter = aReadable[SymbolAsyncIterator](); |
| 68 | aReadableIterator = iter; |
| 69 | return iter; |
| 70 | }, |
| 71 | }; |
| 72 | }, |
| 73 | async close() { |
| 74 | if (aClosed) return; |
| 75 | aClosed = true; |
| 76 | // End the writer (signals end-of-stream to B's readable) |
| 77 | aWriter.endSync(); |
| 78 | // Stop iteration of this channel's readable |
| 79 | if (aReadableIterator?.return) { |
| 80 | await aReadableIterator.return(); |
| 81 | aReadableIterator = null; |
| 82 | } |
| 83 | }, |
| 84 | [SymbolAsyncDispose]() { |
no test coverage detected
searching dependent graphs…