"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.customGot = customGot;
exports.customFetch = customFetch;
const got_1 = __importDefault(require("got"));
const Context_1 = require("../p2p/Context");
const web_1 = require("stream/web");
function customGot(maxBytes) {
    return got_1.default.extend({
        handlers: [
            (options, next) => {
                const downloadLimit = maxBytes ?? Context_1.config.p2p.maxResponseSize;
                const promiseOrStream = next(options);
                // A destroy function that supports both promises and streams
                const destroy = (message) => {
                    if (options.isStream) {
                        // Type the stream properly
                        const stream = promiseOrStream;
                        stream.destroy(new Error(message));
                        return;
                    }
                    // Type the promise properly
                    const promise = promiseOrStream;
                    promise.cancel(message);
                };
                if (typeof downloadLimit === 'number') {
                    promiseOrStream.on('downloadProgress', (progress) => {
                        if (progress.transferred > downloadLimit) {
                            destroy(`Exceeded the download limit of ${downloadLimit} bytes`);
                        }
                    });
                }
                return promiseOrStream;
            },
        ],
    });
}
/**
 * A custom fetch function with size limiting.
 * @param input URL or Request object.
 * @param init Optional fetch configuration.
 * @param maxBytes Maximum response size in bytes (default: config.p2p.maxResponseSize).
 * @returns A Response with a ReadableStream that enforces the download limit.
 */
async function customFetch(input, init, maxBytes) {
    const downloadLimit = maxBytes ?? Context_1.config.p2p.maxResponseSize;
    const response = await fetch(input, init);
    // Check Content-Length header if available
    const contentLength = response.headers.get('content-length');
    if (contentLength && parseInt(contentLength, 10) > downloadLimit) {
        throw new Error(`Exceeded the download limit of ${downloadLimit} bytes`);
    }
    // If there's no body, just return the response
    if (!response.body)
        return response;
    const reader = response.body.getReader();
    const stream = new web_1.ReadableStream({
        async start(controller) {
            let bytesReceived = 0;
            try {
                const processChunk = async () => {
                    const { done, value } = await reader.read();
                    if (done) {
                        controller.close();
                        return;
                    }
                    bytesReceived += value.length;
                    if (bytesReceived > downloadLimit) {
                        const error = new Error(`Exceeded the download limit of ${downloadLimit} bytes`);
                        controller.error(error);
                        await reader.cancel(error);
                        return;
                    }
                    controller.enqueue(value);
                    await processChunk(); // Process next chunk with tail recursion
                };
                await processChunk(); // Start processing
            }
            catch (error) {
                controller.error(error);
                await reader.cancel(error);
            }
        },
    });
    return new Response(stream, {
        headers: response.headers,
        status: response.status,
        statusText: response.statusText,
    });
}
//# sourceMappingURL=customHttpFunctions.js.map