"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.http = exports.HttpError = void 0;
class HttpError extends Error {
    status;
    response;
    constructor(status, response, message) {
        super(message);
        this.status = status;
        this.response = response;
        this.name = "HttpError";
    }
}
exports.HttpError = HttpError;
async function parseBody(response, responseType) {
    if (responseType === "arraybuffer") {
        return (await response.arrayBuffer());
    }
    if (responseType === "stream") {
        return response.body;
    }
    const text = await response.text();
    if (!text)
        return undefined;
    try {
        return JSON.parse(text);
    }
    catch {
        return text;
    }
}
async function request(url, options = {}) {
    const { method = "GET", headers = {}, body, responseType, params, timeout = 30000 } = options;
    let fullUrl = url;
    if (params && Object.keys(params).length > 0) {
        const searchParams = new URLSearchParams();
        for (const [k, v] of Object.entries(params)) {
            if (v !== undefined && v !== null) {
                searchParams.set(k, String(v));
            }
        }
        fullUrl = `${url}?${searchParams.toString()}`;
    }
    const fetchOptions = {
        method,
        headers: { ...headers },
    };
    if (body !== undefined && body !== null) {
        if (body instanceof Buffer || body instanceof Uint8Array || typeof body.pipe === "function") {
            fetchOptions.body = body;
        }
        else if (typeof body === "object" && !(body instanceof FormData)) {
            fetchOptions.body = JSON.stringify(body);
            fetchOptions.headers["Content-Type"] = "application/json";
        }
        else {
            fetchOptions.body = body;
        }
    }
    let timeoutId;
    if (timeout > 0) {
        const controller = new AbortController();
        fetchOptions.signal = controller.signal;
        timeoutId = setTimeout(() => {
            controller.abort();
        }, timeout);
    }
    let response;
    try {
        response = await fetch(fullUrl, fetchOptions);
    }
    catch (e) {
        if (e?.name === "AbortError") {
            throw new HttpError(408, undefined, `Request timeout after ${timeout}ms: ${url}`);
        }
        throw e;
    }
    finally {
        if (timeoutId !== undefined)
            clearTimeout(timeoutId);
    }
    if (!response.ok) {
        const text = await response.text().catch(() => "");
        throw new HttpError(response.status, response, `HTTP ${response.status}: ${text}`);
    }
    const data = await parseBody(response, responseType);
    return { data, status: response.status, headers: response.headers };
}
exports.http = {
    get: (url, options) => request(url, { ...options, method: "GET" }),
    post: (url, body, options) => request(url, { ...options, method: "POST", body }),
    put: (url, body, options) => request(url, { ...options, method: "PUT", body }),
    patch: (url, body, options) => request(url, { ...options, method: "PATCH", body }),
    delete: (url, options) => request(url, { ...options, method: "DELETE" }),
    isHttpError: (e) => e instanceof HttpError,
};
exports.default = exports.http;
//# sourceMappingURL=http.js.map