"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isRedirect = exports.Response = void 0;
const core_loggers_1 = require("@pnpm/core-loggers");
const retry = require("@zkochan/retry");
const node_fetch_1 = require("node-fetch");
Object.defineProperty(exports, "Response", { enumerable: true, get: function () { return node_fetch_1.Response; } });
const fetch = require("node-fetch-unix");
// retry settings
const MIN_TIMEOUT = 10;
const MAX_RETRIES = 5;
const MAX_RETRY_AFTER = 20;
const FACTOR = 6;
exports.isRedirect = fetch.isRedirect;
async function fetchRetry(url, opts = {}) {
    const retryOpts = Object.assign({
        factor: FACTOR,
        // timeouts will be [10, 60, 360, 2160, 12960]
        // (before randomization is added)
        maxRetryAfter: MAX_RETRY_AFTER,
        minTimeout: MIN_TIMEOUT,
        retries: MAX_RETRIES,
    }, opts.retry);
    const op = retry.operation(retryOpts);
    try {
        return await new Promise((resolve, reject) => op.attempt(async (attempt) => {
            var _a;
            try {
                // this will be retried
                const res = await fetch(url, opts);
                if ((res.status >= 500 && res.status < 600) || res.status === 429) {
                    throw new ResponseError(res);
                }
                else {
                    resolve(res);
                    return;
                }
            }
            catch (error) {
                const timeout = op.retry(error);
                if (timeout === false) {
                    reject(op.mainError());
                    return;
                }
                core_loggers_1.requestRetryLogger.debug({
                    attempt,
                    error,
                    maxRetries: retryOpts.retries,
                    method: (_a = opts.method) !== null && _a !== void 0 ? _a : 'GET',
                    timeout,
                    url: url.toString(),
                });
            }
        }));
    }
    catch (err) {
        if (err instanceof ResponseError) {
            return err.res;
        }
        throw err;
    }
}
exports.default = fetchRetry;
class ResponseError extends Error {
    constructor(res) {
        super(res.statusText);
        if (Error.captureStackTrace) {
            Error.captureStackTrace(this, ResponseError);
        }
        this.name = this.constructor.name;
        this.res = res;
        // backward compat
        this.code = this.status = this.statusCode = res.status;
        this.url = res.url;
    }
}
exports.ResponseError = ResponseError;
//# sourceMappingURL=index.js.map