"use strict";
/**
 * Native Stream Implementation - Node.js
 *
 * Uses Node.js native stream module for maximum performance.
 * Provides Readable, Writable, Transform, Duplex, and PassThrough streams.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.promises = exports.consumers = exports.BufferedStream = exports.BufferChunk = exports.StringChunk = exports.PullStream = exports.Collector = exports.PassThrough = exports.Duplex = exports.Transform = exports.Readable = exports.Writable = void 0;
exports.normalizeWritable = normalizeWritable;
exports.pipeline = pipeline;
exports.finished = finished;
exports.createReadable = createReadable;
exports.createReadableFromAsyncIterable = createReadableFromAsyncIterable;
exports.createReadableFromArray = createReadableFromArray;
exports.createWritable = createWritable;
exports.createTransform = createTransform;
exports.createDuplex = createDuplex;
exports.createPassThrough = createPassThrough;
exports.createCollector = createCollector;
exports.createPullStream = createPullStream;
exports.createBufferedStream = createBufferedStream;
exports.streamToPromise = streamToPromise;
exports.streamToBuffer = streamToBuffer;
exports.streamToUint8Array = streamToUint8Array;
exports.streamToString = streamToString;
exports.drainStream = drainStream;
exports.copyStream = copyStream;
exports.addAbortSignal = addAbortSignal;
exports.createReadableFromGenerator = createReadableFromGenerator;
exports.createReadableFromPromise = createReadableFromPromise;
exports.compose = compose;
exports.finishedAll = finishedAll;
exports.createEmptyReadable = createEmptyReadable;
exports.createNullWritable = createNullWritable;
exports.once = once;
exports.promisify = promisify;
exports.isReadable = isReadable;
exports.isWritable = isWritable;
exports.isTransform = isTransform;
exports.isDuplex = isDuplex;
exports.isStream = isStream;
exports.isDestroyed = isDestroyed;
exports.isDisturbed = isDisturbed;
exports.isErrored = isErrored;
exports.getDefaultHighWaterMark = getDefaultHighWaterMark;
exports.setDefaultHighWaterMark = setDefaultHighWaterMark;
exports.duplexPair = duplexPair;
const stream_1 = require("stream");
Object.defineProperty(exports, "Readable", { enumerable: true, get: function () { return stream_1.Readable; } });
Object.defineProperty(exports, "Transform", { enumerable: true, get: function () { return stream_1.Transform; } });
Object.defineProperty(exports, "Duplex", { enumerable: true, get: function () { return stream_1.Duplex; } });
Object.defineProperty(exports, "PassThrough", { enumerable: true, get: function () { return stream_1.PassThrough; } });
const buffered_stream_1 = require("./buffered-stream.js");
const pull_stream_1 = require("./pull-stream.js");
/**
 * Unified Writable class - wraps Node.js Writable with browser-compatible API
 *
 * Supports the same `{ stream }` option as browser version for wrapping existing streams.
 */
class Writable extends stream_1.Writable {
    constructor(options) {
        // If wrapping an existing stream, proxy to it
        if (options?.stream) {
            // Create a pass-through wrapper that proxies to the underlying stream
            super({
                highWaterMark: options?.highWaterMark,
                objectMode: options?.objectMode,
                write(chunk, encoding, callback) {
                    options.stream.write(chunk, encoding, callback);
                },
                final(callback) {
                    options.stream.end(callback);
                }
            });
            // Proxy events from underlying stream
            options.stream.on("error", err => this.emit("error", err));
            options.stream.on("close", () => this.emit("close"));
        }
        else {
            super({
                highWaterMark: options?.highWaterMark,
                objectMode: options?.objectMode,
                write: options?.write,
                final: options?.final
            });
        }
    }
}
exports.Writable = Writable;
// =============================================================================
// Cross-environment stream normalization
// =============================================================================
/**
 * Normalize a user-provided writable into a Node.js-compatible Writable.
 *
 * This keeps Web/Node branching at the stream-module boundary.
 */
function normalizeWritable(stream) {
    if (stream instanceof Writable) {
        return stream;
    }
    // Node.js Writable: accept structurally even if typed as unknown.
    if (stream instanceof stream_1.Writable) {
        return new Writable({ stream: stream });
    }
    // Web WritableStream: detect by getWriter() (avoid relying on global WritableStream).
    if (stream?.getWriter) {
        const nodeWritable = stream_1.Writable.fromWeb(stream);
        return new Writable({ stream: nodeWritable });
    }
    // Assume it structurally matches Node's Writable; wrap for consistent API.
    return new Writable({ stream: stream });
}
// Import for internal use
const shared_1 = require("./shared.js");
const isReadableStream = (value) => !!value && typeof value === "object" && typeof value.getReader === "function";
const isAsyncIterable = (value) => {
    if (!value || (typeof value !== "object" && typeof value !== "function")) {
        return false;
    }
    return typeof value[Symbol.asyncIterator] === "function";
};
const isWritableStream = (value) => !!value && typeof value === "object" && typeof value.getWriter === "function";
const isTransformStream = (value) => !!value &&
    typeof value === "object" &&
    !!value.readable &&
    !!value.writable &&
    isReadableStream(value.readable) &&
    isWritableStream(value.writable);
const isPipelineOptions = (value) => {
    if (!value || typeof value !== "object") {
        return false;
    }
    // IMPORTANT:
    // Do NOT use `"end" in obj` here because streams have `.end()` and would be
    // misclassified as options, breaking argument parsing and potentially hanging.
    if (typeof value.pipe === "function" ||
        typeof value.write === "function" ||
        typeof value.end === "function" ||
        typeof value.getReader === "function" ||
        typeof value.getWriter === "function") {
        return false;
    }
    return (Object.prototype.hasOwnProperty.call(value, "signal") ||
        Object.prototype.hasOwnProperty.call(value, "end"));
};
const toNodePipelineStream = (stream) => {
    // Node native streams (Readable/Transform/Duplex/Writable) are already compatible.
    if (stream instanceof stream_1.Readable ||
        stream instanceof stream_1.Transform ||
        stream instanceof stream_1.Duplex ||
        stream instanceof stream_1.Writable) {
        return stream;
    }
    if (isTransformStream(stream)) {
        return stream_1.Transform.fromWeb(stream);
    }
    if (isReadableStream(stream)) {
        return stream_1.Readable.fromWeb(stream);
    }
    if (isWritableStream(stream)) {
        return stream_1.Writable.fromWeb(stream);
    }
    return stream;
};
/**
 * Pipeline streams together with proper error handling and cleanup.
 * Node.js compatible with support for options and callbacks.
 */
function pipeline(...args) {
    let streams;
    let options;
    let callback;
    const lastArg = args[args.length - 1];
    if (typeof lastArg === "function") {
        callback = lastArg;
        streams = args.slice(0, -1);
    }
    else if (isPipelineOptions(lastArg)) {
        options = lastArg;
        streams = args.slice(0, -1);
    }
    else {
        streams = args;
    }
    const normalizedStreams = streams.map(toNodePipelineStream);
    const promise = new Promise((resolve, reject) => {
        const done = (err) => {
            if (err) {
                reject(err);
            }
            else {
                resolve();
            }
        };
        if (options) {
            stream_1.pipeline(...normalizedStreams, options, done);
        }
        else {
            stream_1.pipeline(...normalizedStreams, done);
        }
    });
    if (callback) {
        promise.then(() => callback()).catch(err => callback(err));
    }
    return promise;
}
/**
 * Wait for a stream to finish, close, or error.
 * Node.js compatible with support for options and callbacks.
 */
function finished(stream, optionsOrCallback, callback) {
    let options;
    let cb;
    if (typeof optionsOrCallback === "function") {
        cb = optionsOrCallback;
    }
    else {
        options = optionsOrCallback;
        cb = callback;
    }
    const promise = new Promise((resolve, reject) => {
        const normalizedStream = toNodePipelineStream(stream);
        stream_1.finished(normalizedStream, options, (err) => {
            if (err && !(options && options.error)) {
                reject(err);
            }
            else {
                resolve();
            }
        });
    });
    if (cb) {
        promise.then(() => cb()).catch(err => cb(err));
    }
    return promise;
}
// =============================================================================
// Stream Creation Functions
// =============================================================================
/**
 * Create a readable stream from various sources
 */
function createReadable(options) {
    return new stream_1.Readable({
        highWaterMark: options?.highWaterMark,
        objectMode: options?.objectMode,
        read: options?.read,
        destroy: options?.destroy
    });
}
/**
 * Create a readable stream from an async iterable
 */
function createReadableFromAsyncIterable(iterable, options) {
    return stream_1.Readable.from(iterable, {
        highWaterMark: options?.highWaterMark,
        objectMode: options?.objectMode ?? true
    });
}
/**
 * Create a readable stream from an array
 */
function createReadableFromArray(data, options) {
    let index = 0;
    return new stream_1.Readable({
        highWaterMark: options?.highWaterMark,
        objectMode: options?.objectMode ?? true,
        read() {
            if (index < data.length) {
                this.push(data[index++]);
            }
            else {
                this.push(null);
            }
        }
    });
}
/**
 * Create a writable stream
 */
function createWritable(options) {
    return new Writable({
        highWaterMark: options?.highWaterMark,
        objectMode: options?.objectMode,
        write: options?.write,
        final: options?.final
    });
}
/**
 * Create a transform stream from a transform function
 */
function createTransform(transformFn, options) {
    return new stream_1.Transform({
        highWaterMark: options?.highWaterMark,
        objectMode: options?.objectMode,
        transform(chunk, encoding, callback) {
            try {
                const result = transformFn(chunk, encoding);
                if (result instanceof Promise) {
                    result
                        .then(data => {
                        if (data !== undefined) {
                            callback(null, data);
                        }
                        else {
                            callback();
                        }
                    })
                        .catch(callback);
                }
                else {
                    if (result !== undefined) {
                        callback(null, result);
                    }
                    else {
                        callback();
                    }
                }
            }
            catch (err) {
                callback(err);
            }
        },
        flush: options?.flush
            ? function (callback) {
                try {
                    const result = options.flush();
                    if (result instanceof Promise) {
                        result.then(data => callback(null, data)).catch(callback);
                    }
                    else if (result !== undefined) {
                        callback(null, result);
                    }
                    else {
                        callback();
                    }
                }
                catch (err) {
                    callback(err);
                }
            }
            : undefined
    });
}
/**
 * Create a duplex stream
 */
function createDuplex(options) {
    return new stream_1.Duplex({
        allowHalfOpen: options?.allowHalfOpen,
        readableHighWaterMark: options?.readableHighWaterMark,
        writableHighWaterMark: options?.writableHighWaterMark,
        readableObjectMode: options?.readableObjectMode,
        writableObjectMode: options?.writableObjectMode,
        read: options?.read,
        write: options?.write,
        final: options?.final,
        destroy: options?.destroy
    });
}
/**
 * Create a passthrough stream
 */
function createPassThrough(options) {
    return new stream_1.PassThrough({
        highWaterMark: options?.highWaterMark,
        objectMode: options?.objectMode
    });
}
// =============================================================================
// Collector Stream - Collects all chunks into an array
// =============================================================================
/**
 * A writable stream that collects all chunks
 */
class Collector extends Writable {
    constructor(options) {
        super({
            highWaterMark: options?.highWaterMark,
            objectMode: options?.objectMode ?? true,
            write: ((chunk, _encoding, callback) => {
                this.chunks.push(chunk);
                callback();
            })
        });
        this.chunks = [];
    }
    /**
     * Get all collected data as a single Uint8Array (for binary mode)
     */
    toUint8Array() {
        const chunks = this.chunks;
        const len = chunks.length;
        if (len === 0) {
            return new Uint8Array(0);
        }
        if (len === 1) {
            const first = chunks[0];
            if (first instanceof Uint8Array) {
                return first;
            }
            if (Buffer.isBuffer(first)) {
                return new Uint8Array(first.buffer, first.byteOffset, first.byteLength);
            }
        }
        // Fast path: check first chunk type once
        const first = chunks[0];
        if (first instanceof Uint8Array || Buffer.isBuffer(first)) {
            // Calculate total length with simple loop (faster than reduce)
            let totalLength = 0;
            for (let i = 0; i < len; i++) {
                totalLength += chunks[i].length;
            }
            const result = new Uint8Array(totalLength);
            let offset = 0;
            for (let i = 0; i < len; i++) {
                const arr = chunks[i];
                result.set(arr, offset);
                offset += arr.length;
            }
            return result;
        }
        throw new Error("Collector contains non-binary data");
    }
    /**
     * Get all collected data as a string
     */
    toString() {
        const chunks = this.chunks;
        const len = chunks.length;
        if (len === 0) {
            return "";
        }
        const first = chunks[0];
        if (typeof first === "string") {
            // Fast path for string chunks
            if (len === 1) {
                return first;
            }
            return chunks.join("");
        }
        // Binary data - decode to string
        return shared_1.textDecoder.decode(this.toUint8Array());
    }
}
exports.Collector = Collector;
/**
 * Create a collector stream
 */
function createCollector(options) {
    return new Collector(options);
}
// =============================================================================
// Pull Stream - Read data on demand with pattern matching
// =============================================================================
class PullStream extends pull_stream_1.PullStream {
}
exports.PullStream = PullStream;
/**
 * Create a pull stream
 */
function createPullStream(options) {
    return new PullStream(options);
}
// =============================================================================
// Buffered Stream - Efficient chunk management
// =============================================================================
/**
 * String chunk implementation
 */
class StringChunk extends buffered_stream_1.StringChunk {
}
exports.StringChunk = StringChunk;
/**
 * Buffer chunk implementation
 */
class BufferChunk extends buffered_stream_1.BufferChunk {
}
exports.BufferChunk = BufferChunk;
/**
 * Buffered stream with efficient chunk management
 */
class BufferedStream extends buffered_stream_1.BufferedStream {
}
exports.BufferedStream = BufferedStream;
/**
 * Create a buffered stream
 */
function createBufferedStream(options) {
    return new BufferedStream(options);
}
// =============================================================================
// Utility Functions
// =============================================================================
/**
 * Convert a stream to a promise that resolves when finished
 */
async function streamToPromise(stream) {
    return finished(stream);
}
/**
 * Collect all data from a readable stream into a Uint8Array
 * (Node.js equivalent of browser streamToBuffer)
 */
async function streamToBuffer(stream) {
    let iterable;
    if (isReadableStream(stream)) {
        iterable = stream_1.Readable.fromWeb(stream);
    }
    else if (isAsyncIterable(stream)) {
        iterable = stream;
    }
    else {
        throw new Error("streamToBuffer: unsupported stream type");
    }
    const chunks = [];
    let totalLength = 0;
    for await (const chunk of iterable) {
        const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
        chunks.push(buf);
        totalLength += buf.length;
    }
    if (chunks.length === 0) {
        return new Uint8Array(0);
    }
    if (chunks.length === 1) {
        const b = chunks[0];
        return new Uint8Array(b.buffer, b.byteOffset, b.byteLength);
    }
    // Use pre-calculated length for faster concat
    const buffer = Buffer.concat(chunks, totalLength);
    return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
}
/**
 * Collect all data from a readable stream into a Uint8Array
 */
async function streamToUint8Array(stream) {
    return streamToBuffer(stream);
}
/**
 * Collect all data from a readable stream into a string
 */
async function streamToString(stream, encoding) {
    const bytes = await streamToUint8Array(stream);
    return Buffer.from(bytes).toString((encoding ?? "utf8"));
}
/**
 * Drain a stream (consume all data without processing)
 */
async function drainStream(stream) {
    let iterable;
    if (isReadableStream(stream)) {
        iterable = stream_1.Readable.fromWeb(stream);
    }
    else if (isAsyncIterable(stream)) {
        iterable = stream;
    }
    else {
        throw new Error("drainStream: unsupported stream type");
    }
    for await (const _chunk of iterable) {
        // Consume data
    }
}
/**
 * Copy from a readable stream to a writable stream
 */
async function copyStream(source, destination) {
    return pipeline(source, destination);
}
// =============================================================================
// Additional Utility Functions
// =============================================================================
/**
 * Add abort signal handling to any stream
 */
function addAbortSignal(signal, stream) {
    if (signal.aborted) {
        stream.destroy(new Error("Aborted"));
        return stream;
    }
    const onAbort = () => {
        stream.destroy(new Error("Aborted"));
    };
    signal.addEventListener("abort", onAbort, { once: true });
    stream.on("close", () => {
        signal.removeEventListener("abort", onAbort);
    });
    return stream;
}
/**
 * Create a readable stream from a generator function
 */
function createReadableFromGenerator(generator, options) {
    return stream_1.Readable.from(generator(), {
        highWaterMark: options?.highWaterMark,
        objectMode: options?.objectMode ?? true
    });
}
/**
 * Create a readable stream from a Promise
 */
function createReadableFromPromise(promise, options) {
    const readable = new stream_1.Readable({
        highWaterMark: options?.highWaterMark,
        objectMode: options?.objectMode ?? true,
        read() { }
    });
    promise
        .then(value => {
        readable.push(value);
        readable.push(null);
    })
        .catch(err => {
        readable.destroy(err);
    });
    return readable;
}
/**
 * Compose multiple transform streams into one
 */
function compose(...transforms) {
    const len = transforms.length;
    if (len === 0) {
        return new stream_1.PassThrough();
    }
    const isNativeTransform = (stream) => stream instanceof stream_1.Transform;
    if (len === 1 && isNativeTransform(transforms[0])) {
        return transforms[0];
    }
    // Chain all transforms together
    for (let i = 0; i < len - 1; i++) {
        transforms[i].pipe(transforms[i + 1]);
    }
    // Create a Duplex that writes to first and reads from last
    const first = transforms[0];
    const last = transforms[len - 1];
    // Create a PassThrough as the composed stream
    const composed = new stream_1.PassThrough({ objectMode: first.readableObjectMode });
    // Store original methods for forwarding
    const passthroughWrite = composed.write.bind(composed);
    const passthroughEnd = composed.end.bind(composed);
    // Override write to write to first transform
    composed.write = function (chunk, encodingOrCallback, callback) {
        if (typeof encodingOrCallback === "function") {
            return first.write(chunk, encodingOrCallback);
        }
        return first.write(chunk, encodingOrCallback, callback);
    };
    // Override end to end first transform
    composed.end = function (chunkOrCallback, encodingOrCallback, callback) {
        if (typeof chunkOrCallback === "function") {
            first.end(chunkOrCallback);
        }
        else if (typeof encodingOrCallback === "function") {
            first.end(chunkOrCallback, encodingOrCallback);
        }
        else {
            first.end(chunkOrCallback, encodingOrCallback, callback);
        }
        return composed;
    };
    // Override pipe to pipe from last transform
    composed.pipe = function (dest) {
        return last.pipe(dest);
    };
    // Forward data from last to composed
    last.on("data", (chunk) => {
        passthroughWrite(chunk);
    });
    // Forward end from last
    last.on("end", () => {
        passthroughEnd();
    });
    // Forward errors from any transform
    for (const transform of transforms) {
        transform.on("error", (err) => {
            composed.emit("error", err);
        });
    }
    return composed;
}
/**
 * Wait for multiple streams to finish
 */
async function finishedAll(streams) {
    const len = streams.length;
    if (len === 0) {
        return;
    }
    if (len === 1) {
        await finished(streams[0]);
        return;
    }
    // Create promise array in-place without intermediate allocation
    const promises = new Array(len);
    for (let i = 0; i < len; i++) {
        promises[i] = finished(streams[i]);
    }
    await Promise.all(promises);
}
// Reusable empty read function
const emptyRead = function () {
    this.push(null);
};
/**
 * Create a readable stream that emits nothing and immediately ends
 */
function createEmptyReadable(options) {
    return new stream_1.Readable({
        highWaterMark: options?.highWaterMark,
        objectMode: options?.objectMode,
        read: emptyRead
    });
}
// Reusable null write function
const nullWrite = (_chunk, _encoding, callback) => {
    callback();
};
/**
 * Create a writable stream that discards all data (like /dev/null)
 */
function createNullWritable(options) {
    return new Writable({
        highWaterMark: options?.highWaterMark,
        objectMode: options?.objectMode,
        write: nullWrite
    });
}
/**
 * Promisified version of once for events
 */
function once(emitter, event, options) {
    return new Promise((resolve, reject) => {
        const cleanup = () => {
            emitter.off(event, onEvent);
            emitter.off("error", onError);
            if (options?.signal) {
                options.signal.removeEventListener("abort", onAbort);
            }
        };
        const onEvent = (...args) => {
            cleanup();
            resolve(args);
        };
        const onError = (err) => {
            cleanup();
            reject(err);
        };
        const onAbort = () => {
            cleanup();
            reject(new Error("Aborted"));
        };
        emitter.once(event, onEvent);
        emitter.once("error", onError);
        if (options?.signal) {
            if (options.signal.aborted) {
                onAbort();
                return;
            }
            options.signal.addEventListener("abort", onAbort);
        }
    });
}
/**
 * Convert a callback-based operation to a promise
 */
function promisify(fn) {
    return new Promise((resolve, reject) => {
        fn((error, result) => {
            if (error) {
                reject(error);
            }
            else {
                resolve(result);
            }
        });
    });
}
// =============================================================================
// Type Guards
// =============================================================================
/**
 * Check if an object is a readable stream
 */
function isReadable(obj) {
    if (obj == null) {
        return false;
    }
    if (obj instanceof stream_1.Readable) {
        return true;
    }
    const o = obj;
    return typeof o.read === "function" && typeof o.pipe === "function";
}
/**
 * Check if an object is a writable stream
 */
function isWritable(obj) {
    if (obj == null) {
        return false;
    }
    if (obj instanceof Writable) {
        return true;
    }
    const o = obj;
    return typeof o.write === "function" && typeof o.end === "function";
}
/**
 * Check if an object is a transform stream
 */
function isTransform(obj) {
    if (obj == null) {
        return false;
    }
    if (obj instanceof stream_1.Transform) {
        return true;
    }
    const o = obj;
    return (typeof o.read === "function" &&
        typeof o.pipe === "function" &&
        typeof o.write === "function" &&
        typeof o._transform === "function");
}
/**
 * Check if an object is a duplex stream
 */
function isDuplex(obj) {
    if (obj == null) {
        return false;
    }
    if (obj instanceof stream_1.Duplex) {
        return true;
    }
    const o = obj;
    return (typeof o.read === "function" &&
        typeof o.pipe === "function" &&
        typeof o.write === "function" &&
        typeof o.end === "function");
}
/**
 * Check if an object is any kind of stream
 */
function isStream(obj) {
    if (obj == null) {
        return false;
    }
    if (obj instanceof stream_1.Readable || obj instanceof Writable) {
        return true;
    }
    const o = obj;
    return ((typeof o.read === "function" && typeof o.pipe === "function") ||
        (typeof o.write === "function" && typeof o.end === "function"));
}
// =============================================================================
// Stream State Inspection Functions
// =============================================================================
/**
 * Check if a stream has been destroyed
 */
function isDestroyed(stream) {
    return !!stream?.destroyed;
}
/**
 * Check if a readable stream has been disturbed (read from)
 */
function isDisturbed(stream) {
    if (stream?.locked !== undefined) {
        return !!stream.locked;
    }
    const s = stream;
    return !!(s?.readableDidRead ||
        s?._didRead ||
        s?.readableEnded ||
        s?.destroyed ||
        s?._ended ||
        s?._destroyed);
}
/**
 * Check if a stream has an error
 */
function isErrored(stream) {
    return !!stream?.errored;
}
// =============================================================================
// Default High Water Mark Management
// =============================================================================
/**
 * Get the default high water mark for streams
 */
function getDefaultHighWaterMark(objectMode) {
    // Default values from Node.js stream module
    return objectMode ? 16 : 16 * 1024;
}
/**
 * Set the default high water mark for streams
 * Note: This is a no-op in this implementation as we use fixed defaults
 */
function setDefaultHighWaterMark(_objectMode, _value) {
    // No-op - Node.js internal state cannot be modified safely
}
// =============================================================================
// Duplex Pair
// =============================================================================
/**
 * Create a pair of connected Duplex streams
 */
function duplexPair(options) {
    // Use PassThrough as the simplest implementation
    const objectMode = options?.readableObjectMode ?? options?.writableObjectMode ?? options?.objectMode ?? false;
    const highWaterMark = options?.readableHighWaterMark ?? options?.writableHighWaterMark ?? options?.highWaterMark;
    const nodeOpts = {
        objectMode,
        highWaterMark
    };
    const passthrough1 = new stream_1.PassThrough(nodeOpts);
    const passthrough2 = new stream_1.PassThrough(nodeOpts);
    const duplex1 = new stream_1.Duplex({
        allowHalfOpen: options?.allowHalfOpen,
        readableHighWaterMark: options?.readableHighWaterMark ?? highWaterMark,
        writableHighWaterMark: options?.writableHighWaterMark ?? highWaterMark,
        readableObjectMode: options?.readableObjectMode ?? objectMode,
        writableObjectMode: options?.writableObjectMode ?? objectMode,
        read() {
            // Will be pushed from duplex2
        },
        write(chunk, encoding, callback) {
            passthrough1.write(chunk, encoding, callback);
        },
        final(callback) {
            passthrough1.end(callback);
        }
    });
    const duplex2 = new stream_1.Duplex({
        allowHalfOpen: options?.allowHalfOpen,
        readableHighWaterMark: options?.readableHighWaterMark ?? highWaterMark,
        writableHighWaterMark: options?.writableHighWaterMark ?? highWaterMark,
        readableObjectMode: options?.readableObjectMode ?? objectMode,
        writableObjectMode: options?.writableObjectMode ?? objectMode,
        read() {
            // Will be pushed from duplex1
        },
        write(chunk, encoding, callback) {
            passthrough2.write(chunk, encoding, callback);
        },
        final(callback) {
            passthrough2.end(callback);
        }
    });
    // Connect them
    passthrough1.on("data", chunk => duplex2.push(chunk));
    passthrough1.on("end", () => duplex2.push(null));
    passthrough2.on("data", chunk => duplex1.push(chunk));
    passthrough2.on("end", () => duplex1.push(null));
    return [duplex1, duplex2];
}
// =============================================================================
// Stream Consumers (like stream/consumers in Node.js)
// =============================================================================
exports.consumers = {
    async arrayBuffer(stream) {
        const bytes = await streamToUint8Array(stream);
        return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
    },
    async blob(stream, options) {
        const bytes = await streamToUint8Array(stream);
        return new Blob([bytes], options);
    },
    async buffer(stream) {
        return streamToUint8Array(stream);
    },
    async json(stream) {
        const text = await exports.consumers.text(stream);
        return JSON.parse(text);
    },
    async text(stream, encoding) {
        return streamToString(stream, encoding);
    }
};
// =============================================================================
// Promises API (like stream/promises in Node.js)
// =============================================================================
exports.promises = {
    pipeline,
    finished
};
