"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isTransientNetworkError = isTransientNetworkError;
const command_1 = require("./command");
const TRANSIENT_NETWORK_ERROR_CODES = new Set([
    "ENOTFOUND",
    "EAI_AGAIN",
    "ECONNRESET",
    "ECONNREFUSED",
    "ETIMEDOUT",
    "ENETUNREACH",
    "EHOSTUNREACH",
    "ECONNABORTED",
]);
const TRANSIENT_NETWORK_SUBSTRINGS = [
    "stream disconnected before completion",
    "error sending request for url",
    "fetch failed",
    "network error",
    "connection reset",
    "socket hang up",
    "temporary failure in name resolution",
    "name resolution",
    "getaddrinfo enotfound",
    "eai_again",
    "etimedout",
    "econnreset",
    "econnrefused",
    "enetunreach",
    "ehostunreach",
    "tls handshake timeout",
    "request timed out",
    "api rate limit exceeded",
    "rate limit exceeded",
    "secondary rate limit",
    "retry-after",
    "retry after",
    "too many requests",
    "abuse detection",
    "abuse limit",
    "http 429",
    "status 429",
];
function isTransientNetworkError(error) {
    return visitError(error, new Set());
}
function visitError(error, seen) {
    if (error === null || error === undefined || seen.has(error)) {
        return false;
    }
    if (typeof error !== "object" && !(error instanceof Error)) {
        return false;
    }
    seen.add(error);
    if (matchesTransientNetworkError(error)) {
        return true;
    }
    if (error instanceof command_1.CommandError) {
        return matchesTransientNetworkText([error.message, error.stdout, error.stderr].join("\n"));
    }
    if (error instanceof Error) {
        return visitError(error.cause, seen);
    }
    if ("cause" in error) {
        return visitError(error.cause, seen);
    }
    return false;
}
function matchesTransientNetworkError(error) {
    if (error instanceof Error) {
        const code = "code" in error
            ? String(error.code ?? "")
            : "";
        if (code && TRANSIENT_NETWORK_ERROR_CODES.has(code)) {
            return true;
        }
        return matchesTransientNetworkText(error.message);
    }
    return false;
}
function matchesTransientNetworkText(text) {
    const normalized = text.toLowerCase();
    return TRANSIENT_NETWORK_SUBSTRINGS.some((fragment) => normalized.includes(fragment));
}
