UNPKG

retry-axios

Version:
195 lines (193 loc) 6.63 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // build/src/index.js var index_exports = {}; __export(index_exports, { attach: () => attach, detach: () => detach, getConfig: () => getConfig, shouldRetryRequest: () => shouldRetryRequest }); module.exports = __toCommonJS(index_exports); var import_axios = __toESM(require("axios"), 1); var retryRanges = [ // https://en.wikipedia.org/wiki/List_of_HTTP_status_codes // 1xx - Retry (Informational, request still processing) // 2xx - Do not retry (Success) // 3xx - Do not retry (Redirect) // 4xx - Do not retry (Client errors) // 429 - Retry ("Too Many Requests") // 5xx - Retry (Server errors) [100, 199], [429, 429], [500, 599] ]; function attach(instance) { const inst = instance || import_axios.default; return inst.interceptors.response.use(onFulfilled, async (error) => onError(inst, error)); } function detach(interceptorId, instance) { const inst = instance || import_axios.default; inst.interceptors.response.eject(interceptorId); } function onFulfilled(result) { return result; } function normalizeArray(object) { const array = []; if (!object) { return void 0; } if (Array.isArray(object)) { return object; } if (typeof object === "object") { for (const key of Object.keys(object)) { const number_ = Number.parseInt(key, 10); if (!Number.isNaN(number_)) { array[number_] = object[key]; } } } return array; } function parseRetryAfter(header) { const value = Number(header); if (!Number.isNaN(value)) { return value * 1e3; } const dateTime = Date.parse(header); if (!Number.isNaN(dateTime)) { return dateTime - Date.now(); } return void 0; } async function onError(instance, error) { if ((0, import_axios.isCancel)(error)) { throw error; } const config = getConfig(error) || {}; config.currentRetryAttempt ||= 0; config.retry = typeof config.retry === "number" ? config.retry : 3; config.retryDelay = typeof config.retryDelay === "number" ? config.retryDelay : 100; config.instance ||= instance; config.backoffType ||= "exponential"; config.httpMethodsToRetry = normalizeArray(config.httpMethodsToRetry) || [ "GET", "HEAD", "PUT", "OPTIONS", "DELETE" ]; config.noResponseRetries = typeof config.noResponseRetries === "number" ? config.noResponseRetries : 2; config.checkRetryAfter = typeof config.checkRetryAfter === "boolean" ? config.checkRetryAfter : true; config.maxRetryAfter = typeof config.maxRetryAfter === "number" ? config.maxRetryAfter : 6e4 * 5; config.statusCodesToRetry = normalizeArray(config.statusCodesToRetry) || retryRanges; const axiosError = error; axiosError.config = axiosError.config || {}; axiosError.config.raxConfig = { ...config }; const shouldRetryFunction = config.shouldRetry || shouldRetryRequest; if (!shouldRetryFunction(axiosError)) { throw axiosError; } const onBackoffPromise = new Promise((resolve, reject) => { let delay = 0; if (config.checkRetryAfter && axiosError.response?.headers?.["retry-after"]) { const retryAfter = parseRetryAfter(axiosError.response.headers["retry-after"]); if (retryAfter && retryAfter > 0 && retryAfter <= (config.maxRetryAfter ?? 0)) { delay = retryAfter; } else { reject(axiosError); return; } } axiosError.config.raxConfig.currentRetryAttempt += 1; const retrycount = axiosError.config.raxConfig.currentRetryAttempt; if (delay === 0) { if (config.backoffType === "linear") { delay = retrycount * 1e3; } else if (config.backoffType === "static") { delay = config.retryDelay; } else { delay = (2 ** retrycount - 1) / 2 * 1e3; } if (typeof config.maxRetryDelay === "number") { delay = Math.min(delay, config.maxRetryDelay); } } setTimeout(resolve, delay); }); if (config.onRetryAttempt) { config.onRetryAttempt(axiosError); } const onRetryAttemptPromise = Promise.resolve(); return Promise.resolve().then(async () => onBackoffPromise).then(async () => onRetryAttemptPromise).then(async () => config.instance?.request(axiosError.config)); } function shouldRetryRequest(error) { const config = error.config.raxConfig; if (!config || config.retry === 0) { return false; } if (!error.response && (config.currentRetryAttempt || 0) >= (config.noResponseRetries ?? 0)) { return false; } if (!error.config?.method || !config.httpMethodsToRetry?.includes(error.config.method.toUpperCase())) { return false; } if (error.response?.status) { let isInRange = false; for (const [min, max] of config.statusCodesToRetry) { const { status } = error.response; if (status >= min && status <= max) { isInRange = true; break; } } if (!isInRange) { return false; } } config.currentRetryAttempt ||= 0; if (config.currentRetryAttempt >= (config.retry ?? 0)) { return false; } return true; } function getConfig(error) { if (error?.config) { return error.config.raxConfig; } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { attach, detach, getConfig, shouldRetryRequest });