"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_ACCEPT_ENCODING = exports.fakePromise = void 0;
exports.getHeadersObj = getHeadersObj;
exports.defaultHeadersSerializer = defaultHeadersSerializer;
exports.isArrayBufferView = isArrayBufferView;
exports.isNodeReadable = isNodeReadable;
exports.isIterable = isIterable;
exports.shouldRedirect = shouldRedirect;
exports.pipeThrough = pipeThrough;
exports.endStream = endStream;
exports.safeWrite = safeWrite;
exports.getSupportedFormats = getSupportedFormats;
const tslib_1 = require("tslib");
const node_events_1 = require("node:events");
const node_zlib_1 = tslib_1.__importDefault(require("node:zlib"));
function isHeadersInstance(obj) {
    return obj?.forEach != null;
}
function getHeadersObj(headers) {
    if (headers == null || !isHeadersInstance(headers)) {
        return headers;
    }
    // @ts-expect-error - `headersInit` is not a public property
    if (headers.headersInit && !headers._map && !isHeadersInstance(headers.headersInit)) {
        // @ts-expect-error - `headersInit` is not a public property
        return headers.headersInit;
    }
    return Object.fromEntries(headers.entries());
}
function defaultHeadersSerializer(headers, onContentLength) {
    const headerArray = [];
    headers.forEach((value, key) => {
        if (onContentLength && key === 'content-length') {
            onContentLength(value);
        }
        headerArray.push(`${key}: ${value}`);
    });
    return headerArray;
}
var promise_helpers_1 = require("@whatwg-node/promise-helpers");
Object.defineProperty(exports, "fakePromise", { enumerable: true, get: function () { return promise_helpers_1.fakePromise; } });
function isArrayBufferView(obj) {
    return obj != null && obj.buffer != null && obj.byteLength != null && obj.byteOffset != null;
}
function isNodeReadable(obj) {
    return obj != null && obj.pipe != null;
}
function isIterable(value) {
    return value?.[Symbol.iterator] != null;
}
function shouldRedirect(status) {
    return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
}
function pipeThrough({ src, dest, signal, onError, }) {
    if (onError) {
        // listen for errors on the destination stream if necessary. if the readable
        // stream (src) emits an error, the writable destination (dest) will be
        // destroyed with that error (see below)
        dest.once('error', onError);
    }
    src.once('error', (e) => {
        // if the readable stream (src) emits an error during pipe, the writable
        // destination (dest) is not closed automatically. that needs to be
        // done manually. the readable stream is closed when error is emitted,
        // so only the writable destination needs to be destroyed
        dest.destroy(e);
    });
    dest.once('close', () => {
        // if the writable destination (dest) is closed, the readable stream (src)
        // is not closed automatically. that needs to be done manually
        if (!src.destroyed) {
            src.destroy();
        }
    });
    if (signal) {
        // this is faster than `import('node:signal').addAbortSignal(signal, src)`
        const srcRef = new WeakRef(src);
        const signalRef = new WeakRef(signal);
        function cleanup() {
            signalRef.deref()?.removeEventListener('abort', onAbort);
            srcRef.deref()?.removeListener('end', cleanup);
            srcRef.deref()?.removeListener('error', cleanup);
            srcRef.deref()?.removeListener('close', cleanup);
        }
        function onAbort() {
            srcRef.deref()?.destroy(new AbortError());
            cleanup();
        }
        signal.addEventListener('abort', onAbort, { once: true });
        // this is faster than `import('node:signal').finished(src, cleanup)`
        src.once('end', cleanup);
        src.once('error', cleanup);
        src.once('close', cleanup);
    }
    src.pipe(dest, { end: true /* already default */ });
}
function endStream(stream) {
    // Avoid arguments adaptor trampoline https://v8.dev/blog/adaptor-frame
    return stream.end(null, null, null);
}
function safeWrite(chunk, stream) {
    const result = stream.write(chunk);
    if (!result) {
        return (0, node_events_1.once)(stream, 'drain');
    }
}
// https://github.com/nodejs/node/blob/f692878dec6354c0a82241f224906981861bc840/lib/internal/errors.js#L961-L973
class AbortError extends Error {
    constructor(message = 'The operation was aborted', options = undefined) {
        super(message, options);
        this.name = 'AbortError';
    }
}
exports.DEFAULT_ACCEPT_ENCODING = getSupportedFormats().join(', ');
function getSupportedFormats() {
    const baseFormats = ['gzip', 'deflate', 'br'];
    if (!globalThis.process?.versions?.node?.startsWith('2')) {
        baseFormats.push('deflate-raw');
    }
    if (node_zlib_1.default.createZstdCompress != null) {
        baseFormats.push('zstd');
    }
    return baseFormats;
}
