This commit is contained in:
2022-07-18 02:50:52 +00:00
parent befd344ab0
commit 06181b34d6
8569 changed files with 818704 additions and 352705 deletions
+50
View File
@@ -5,6 +5,56 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [3.3.0] - 2022-06-28
- Added `onRetry` callback option
## [3.2.6] - 2022-06-28
- Add types export to package.json
## [3.2.5] - 2022-04-29
- handle retryCondition false return value
## [3.2.4] - 2021-10-27
- fix: add package.json to exports
## [3.2.3] - 2021-10-19
- fix: removed breaking requirements introduced in 3.2.1
- fix: allow Typescript CommonJS default import
## [3.2.2] - 2021-10-14
- fix: added missing @babel/runtime runtime dep
## [3.2.1] - 2021-10-14
- updated all dependencies
- made the package hybrid (ES modules and CommonJS)
- BREAKING: axios >=0.21.2 is now required to work as a peer dep.
- BREAKING: NodeJS "^12.20.0 || ^14.13.1 || >=16.0.0" to work
## [3.2.0] - 2021-09-28
### Added
- Retry condition accepts a function that returns a Promise resolving to a boolean
## [3.1.9] - 2020-09-18
### Fixed
- TS: extended AxiosRequestConfig with optional "axios-retry" property
## [3.1.8] - 2019-04-24
### Fixed
- TS: export types for all functions
## [3.1.7] - 2019-04-23
### Fixed
+5 -7
View File
@@ -1,6 +1,6 @@
# axios-retry
[![Build Status](https://travis-ci.org/softonic/axios-retry.svg?branch=master)](https://travis-ci.org/softonic/axios-retry)
[![Node.js CI](https://github.com/softonic/axios-retry/actions/workflows/node.js.yml/badge.svg)](https://github.com/softonic/axios-retry/actions/workflows/node.js.yml)
Axios plugin that intercepts failed requests and retries them whenever possible.
@@ -10,9 +10,6 @@ Axios plugin that intercepts failed requests and retries them whenever possible.
npm install axios-retry
```
### Note
Not working with `axios 0.19.0`. For details see the [bug](https://github.com/axios/axios/issues/2203). [`axios 0.19.1`](https://github.com/axios/axios/releases/tag/0.19.1) has fixed this bug.
## Usage
```js
@@ -30,7 +27,7 @@ axios.get('http://example.com/test') // The first request fails and the second r
});
// Exponential back-off retry delay between requests
axiosRetry(axios, { retryDelay: axiosRetry.exponentialDelay});
axiosRetry(axios, { retryDelay: axiosRetry.exponentialDelay });
// Custom retry delay
axiosRetry(axios, { retryDelay: (retryCount) => {
@@ -64,10 +61,11 @@ client
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| retries | `Number` | `3` | The number of times to retry before failing. |
| retries | `Number` | `3` | The number of times to retry before failing. 1 = One retry after first failure |
| retryCondition | `Function` | `isNetworkOrIdempotentRequestError` | A callback to further control if a request should be retried. By default, it retries if it is a network error or a 5xx error on an idempotent request (GET, HEAD, OPTIONS, PUT or DELETE). |
| shouldResetTimeout | `Boolean` | false | Defines if the timeout should be reset between retries |
| retryDelay | `Function` | `function noDelay() { return 0; }` | A callback to further control the delay between retried requests. By default there is no delay between retries. Another option is exponentialDelay ([Exponential Backoff](https://developers.google.com/analytics/devguides/reporting/core/v3/errors#backoff)). The function is passed `retryCount` and `error`. |
| retryDelay | `Function` | `function noDelay() { return 0; }` | A callback to further control the delay in milliseconds between retried requests. By default there is no delay between retries. Another option is exponentialDelay ([Exponential Backoff](https://developers.google.com/analytics/devguides/reporting/core/v3/errors#backoff)). The function is passed `retryCount` and `error`. |
| onRetry | `Function` | `function onRetry(retryCount, error, requestConfig) { return; }` | A callback to notify when a retry is about to occur. Useful for tracing. By default nothing will occur. The function is passed `retryCount`, `error`, and `requestConfig`. |
## Testing
+255
View File
@@ -0,0 +1,255 @@
import isRetryAllowed from 'is-retry-allowed';
const namespace = 'axios-retry';
/**
* @param {Error} error
* @return {boolean}
*/
export function isNetworkError(error) {
return (
!error.response &&
Boolean(error.code) && // Prevents retrying cancelled requests
error.code !== 'ECONNABORTED' && // Prevents retrying timed out requests
isRetryAllowed(error)
); // Prevents retrying unsafe errors
}
const SAFE_HTTP_METHODS = ['get', 'head', 'options'];
const IDEMPOTENT_HTTP_METHODS = SAFE_HTTP_METHODS.concat(['put', 'delete']);
/**
* @param {Error} error
* @return {boolean}
*/
export function isRetryableError(error) {
return (
error.code !== 'ECONNABORTED' &&
(!error.response || (error.response.status >= 500 && error.response.status <= 599))
);
}
/**
* @param {Error} error
* @return {boolean}
*/
export function isSafeRequestError(error) {
if (!error.config) {
// Cannot determine if the request can be retried
return false;
}
return isRetryableError(error) && SAFE_HTTP_METHODS.indexOf(error.config.method) !== -1;
}
/**
* @param {Error} error
* @return {boolean}
*/
export function isIdempotentRequestError(error) {
if (!error.config) {
// Cannot determine if the request can be retried
return false;
}
return isRetryableError(error) && IDEMPOTENT_HTTP_METHODS.indexOf(error.config.method) !== -1;
}
/**
* @param {Error} error
* @return {boolean}
*/
export function isNetworkOrIdempotentRequestError(error) {
return isNetworkError(error) || isIdempotentRequestError(error);
}
/**
* @return {number} - delay in milliseconds, always 0
*/
function noDelay() {
return 0;
}
/**
* @param {number} [retryNumber=0]
* @return {number} - delay in milliseconds
*/
export function exponentialDelay(retryNumber = 0) {
const delay = Math.pow(2, retryNumber) * 100;
const randomSum = delay * 0.2 * Math.random(); // 0-20% of the delay
return delay + randomSum;
}
/**
* Initializes and returns the retry state for the given request/config
* @param {AxiosRequestConfig} config
* @return {Object}
*/
function getCurrentState(config) {
const currentState = config[namespace] || {};
currentState.retryCount = currentState.retryCount || 0;
config[namespace] = currentState;
return currentState;
}
/**
* Returns the axios-retry options for the current request
* @param {AxiosRequestConfig} config
* @param {AxiosRetryConfig} defaultOptions
* @return {AxiosRetryConfig}
*/
function getRequestOptions(config, defaultOptions) {
return { ...defaultOptions, ...config[namespace] };
}
/**
* @param {Axios} axios
* @param {AxiosRequestConfig} config
*/
function fixConfig(axios, config) {
if (axios.defaults.agent === config.agent) {
delete config.agent;
}
if (axios.defaults.httpAgent === config.httpAgent) {
delete config.httpAgent;
}
if (axios.defaults.httpsAgent === config.httpsAgent) {
delete config.httpsAgent;
}
}
/**
* Checks retryCondition if request can be retried. Handles it's retruning value or Promise.
* @param {number} retries
* @param {Function} retryCondition
* @param {Object} currentState
* @param {Error} error
* @return {boolean}
*/
async function shouldRetry(retries, retryCondition, currentState, error) {
const shouldRetryOrPromise = currentState.retryCount < retries && retryCondition(error);
// This could be a promise
if (typeof shouldRetryOrPromise === 'object') {
try {
const shouldRetryPromiseResult = await shouldRetryOrPromise;
// keep return true unless shouldRetryPromiseResult return false for compatibility
return shouldRetryPromiseResult !== false;
} catch (_err) {
return false;
}
}
return shouldRetryOrPromise;
}
/**
* Adds response interceptors to an axios instance to retry requests failed due to network issues
*
* @example
*
* import axios from 'axios';
*
* axiosRetry(axios, { retries: 3 });
*
* axios.get('http://example.com/test') // The first request fails and the second returns 'ok'
* .then(result => {
* result.data; // 'ok'
* });
*
* // Exponential back-off retry delay between requests
* axiosRetry(axios, { retryDelay : axiosRetry.exponentialDelay});
*
* // Custom retry delay
* axiosRetry(axios, { retryDelay : (retryCount) => {
* return retryCount * 1000;
* }});
*
* // Also works with custom axios instances
* const client = axios.create({ baseURL: 'http://example.com' });
* axiosRetry(client, { retries: 3 });
*
* client.get('/test') // The first request fails and the second returns 'ok'
* .then(result => {
* result.data; // 'ok'
* });
*
* // Allows request-specific configuration
* client
* .get('/test', {
* 'axios-retry': {
* retries: 0
* }
* })
* .catch(error => { // The first request fails
* error !== undefined
* });
*
* @param {Axios} axios An axios instance (the axios object or one created from axios.create)
* @param {Object} [defaultOptions]
* @param {number} [defaultOptions.retries=3] Number of retries
* @param {boolean} [defaultOptions.shouldResetTimeout=false]
* Defines if the timeout should be reset between retries
* @param {Function} [defaultOptions.retryCondition=isNetworkOrIdempotentRequestError]
* A function to determine if the error can be retried
* @param {Function} [defaultOptions.retryDelay=noDelay]
* A function to determine the delay between retry requests
* @param {Function} [defaultOptions.onRetry=()=>{}]
* A function to get notified when a retry occurs
*/
export default function axiosRetry(axios, defaultOptions) {
axios.interceptors.request.use((config) => {
const currentState = getCurrentState(config);
currentState.lastRequestTime = Date.now();
return config;
});
axios.interceptors.response.use(null, async (error) => {
const { config } = error;
// If we have no information to retry the request
if (!config) {
return Promise.reject(error);
}
const {
retries = 3,
retryCondition = isNetworkOrIdempotentRequestError,
retryDelay = noDelay,
shouldResetTimeout = false,
onRetry = () => {}
} = getRequestOptions(config, defaultOptions);
const currentState = getCurrentState(config);
if (await shouldRetry(retries, retryCondition, currentState, error)) {
currentState.retryCount += 1;
const delay = retryDelay(currentState.retryCount, error);
// Axios fails merging this configuration to the default configuration because it has an issue
// with circular structures: https://github.com/mzabriskie/axios/issues/370
fixConfig(axios, config);
if (!shouldResetTimeout && config.timeout && currentState.lastRequestTime) {
const lastRequestDuration = Date.now() - currentState.lastRequestTime;
// Minimum 1ms timeout (passing 0 or less to XHR means no timeout)
config.timeout = Math.max(config.timeout - lastRequestDuration - delay, 1);
}
config.transformRequest = [(data) => data];
onRetry(currentState.retryCount, error, config);
return new Promise((resolve) => setTimeout(() => resolve(axios(config)), delay));
}
return Promise.reject(error);
});
}
// Compatibility with CommonJS
axiosRetry.isNetworkError = isNetworkError;
axiosRetry.isSafeRequestError = isSafeRequestError;
axiosRetry.isIdempotentRequestError = isIdempotentRequestError;
axiosRetry.isNetworkOrIdempotentRequestError = isNetworkOrIdempotentRequestError;
axiosRetry.exponentialDelay = exponentialDelay;
axiosRetry.isRetryableError = isRetryableError;
+13 -1
View File
@@ -43,13 +43,19 @@ declare namespace IAxiosRetry {
*
* @type {Function}
*/
retryCondition?: (error: axios.AxiosError) => boolean,
retryCondition?: (error: axios.AxiosError) => boolean | Promise<boolean>,
/**
* A callback to further control the delay between retry requests. By default there is no delay.
*
* @type {Function}
*/
retryDelay?: (retryCount: number, error: axios.AxiosError) => number
/**
* A callback to get notified when a retry occurs, the number of times it has occurre, and the error
*
* @type {Function}
*/
onRetry?: (retryCount: number, error: axios.AxiosError, requestConfig: axios.AxiosRequestConfig) => void
}
}
@@ -58,3 +64,9 @@ declare const axiosRetry: IAxiosRetry;
export type IAxiosRetryConfig = IAxiosRetry.IAxiosRetryConfig;
export default axiosRetry;
declare module 'axios' {
export interface AxiosRequestConfig {
'axios-retry'?: IAxiosRetryConfig;
}
}
+4 -1
View File
@@ -1 +1,4 @@
module.exports = require('./lib/index').default;
const axiosRetry = require('./lib/cjs/index').default;
module.exports = axiosRetry;
module.exports.default = axiosRetry;
+343
View File
@@ -0,0 +1,343 @@
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isNetworkError = isNetworkError;
exports.isRetryableError = isRetryableError;
exports.isSafeRequestError = isSafeRequestError;
exports.isIdempotentRequestError = isIdempotentRequestError;
exports.isNetworkOrIdempotentRequestError = isNetworkOrIdempotentRequestError;
exports.exponentialDelay = exponentialDelay;
exports.default = axiosRetry;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _isRetryAllowed = _interopRequireDefault(require("is-retry-allowed"));
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
var namespace = 'axios-retry';
/**
* @param {Error} error
* @return {boolean}
*/
function isNetworkError(error) {
return !error.response && Boolean(error.code) && // Prevents retrying cancelled requests
error.code !== 'ECONNABORTED' && // Prevents retrying timed out requests
(0, _isRetryAllowed.default)(error); // Prevents retrying unsafe errors
}
var SAFE_HTTP_METHODS = ['get', 'head', 'options'];
var IDEMPOTENT_HTTP_METHODS = SAFE_HTTP_METHODS.concat(['put', 'delete']);
/**
* @param {Error} error
* @return {boolean}
*/
function isRetryableError(error) {
return error.code !== 'ECONNABORTED' && (!error.response || error.response.status >= 500 && error.response.status <= 599);
}
/**
* @param {Error} error
* @return {boolean}
*/
function isSafeRequestError(error) {
if (!error.config) {
// Cannot determine if the request can be retried
return false;
}
return isRetryableError(error) && SAFE_HTTP_METHODS.indexOf(error.config.method) !== -1;
}
/**
* @param {Error} error
* @return {boolean}
*/
function isIdempotentRequestError(error) {
if (!error.config) {
// Cannot determine if the request can be retried
return false;
}
return isRetryableError(error) && IDEMPOTENT_HTTP_METHODS.indexOf(error.config.method) !== -1;
}
/**
* @param {Error} error
* @return {boolean}
*/
function isNetworkOrIdempotentRequestError(error) {
return isNetworkError(error) || isIdempotentRequestError(error);
}
/**
* @return {number} - delay in milliseconds, always 0
*/
function noDelay() {
return 0;
}
/**
* @param {number} [retryNumber=0]
* @return {number} - delay in milliseconds
*/
function exponentialDelay() {
var retryNumber = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
var delay = Math.pow(2, retryNumber) * 100;
var randomSum = delay * 0.2 * Math.random(); // 0-20% of the delay
return delay + randomSum;
}
/**
* Initializes and returns the retry state for the given request/config
* @param {AxiosRequestConfig} config
* @return {Object}
*/
function getCurrentState(config) {
var currentState = config[namespace] || {};
currentState.retryCount = currentState.retryCount || 0;
config[namespace] = currentState;
return currentState;
}
/**
* Returns the axios-retry options for the current request
* @param {AxiosRequestConfig} config
* @param {AxiosRetryConfig} defaultOptions
* @return {AxiosRetryConfig}
*/
function getRequestOptions(config, defaultOptions) {
return _objectSpread(_objectSpread({}, defaultOptions), config[namespace]);
}
/**
* @param {Axios} axios
* @param {AxiosRequestConfig} config
*/
function fixConfig(axios, config) {
if (axios.defaults.agent === config.agent) {
delete config.agent;
}
if (axios.defaults.httpAgent === config.httpAgent) {
delete config.httpAgent;
}
if (axios.defaults.httpsAgent === config.httpsAgent) {
delete config.httpsAgent;
}
}
/**
* Checks retryCondition if request can be retried. Handles it's retruning value or Promise.
* @param {number} retries
* @param {Function} retryCondition
* @param {Object} currentState
* @param {Error} error
* @return {boolean}
*/
function shouldRetry(_x, _x2, _x3, _x4) {
return _shouldRetry.apply(this, arguments);
}
/**
* Adds response interceptors to an axios instance to retry requests failed due to network issues
*
* @example
*
* import axios from 'axios';
*
* axiosRetry(axios, { retries: 3 });
*
* axios.get('http://example.com/test') // The first request fails and the second returns 'ok'
* .then(result => {
* result.data; // 'ok'
* });
*
* // Exponential back-off retry delay between requests
* axiosRetry(axios, { retryDelay : axiosRetry.exponentialDelay});
*
* // Custom retry delay
* axiosRetry(axios, { retryDelay : (retryCount) => {
* return retryCount * 1000;
* }});
*
* // Also works with custom axios instances
* const client = axios.create({ baseURL: 'http://example.com' });
* axiosRetry(client, { retries: 3 });
*
* client.get('/test') // The first request fails and the second returns 'ok'
* .then(result => {
* result.data; // 'ok'
* });
*
* // Allows request-specific configuration
* client
* .get('/test', {
* 'axios-retry': {
* retries: 0
* }
* })
* .catch(error => { // The first request fails
* error !== undefined
* });
*
* @param {Axios} axios An axios instance (the axios object or one created from axios.create)
* @param {Object} [defaultOptions]
* @param {number} [defaultOptions.retries=3] Number of retries
* @param {boolean} [defaultOptions.shouldResetTimeout=false]
* Defines if the timeout should be reset between retries
* @param {Function} [defaultOptions.retryCondition=isNetworkOrIdempotentRequestError]
* A function to determine if the error can be retried
* @param {Function} [defaultOptions.retryDelay=noDelay]
* A function to determine the delay between retry requests
* @param {Function} [defaultOptions.onRetry=()=>{}]
* A function to get notified when a retry occurs
*/
function _shouldRetry() {
_shouldRetry = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(retries, retryCondition, currentState, error) {
var shouldRetryOrPromise, shouldRetryPromiseResult;
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
shouldRetryOrPromise = currentState.retryCount < retries && retryCondition(error); // This could be a promise
if (!((0, _typeof2.default)(shouldRetryOrPromise) === 'object')) {
_context2.next = 12;
break;
}
_context2.prev = 2;
_context2.next = 5;
return shouldRetryOrPromise;
case 5:
shouldRetryPromiseResult = _context2.sent;
return _context2.abrupt("return", shouldRetryPromiseResult !== false);
case 9:
_context2.prev = 9;
_context2.t0 = _context2["catch"](2);
return _context2.abrupt("return", false);
case 12:
return _context2.abrupt("return", shouldRetryOrPromise);
case 13:
case "end":
return _context2.stop();
}
}
}, _callee2, null, [[2, 9]]);
}));
return _shouldRetry.apply(this, arguments);
}
function axiosRetry(axios, defaultOptions) {
axios.interceptors.request.use(function (config) {
var currentState = getCurrentState(config);
currentState.lastRequestTime = Date.now();
return config;
});
axios.interceptors.response.use(null, /*#__PURE__*/function () {
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(error) {
var config, _getRequestOptions, _getRequestOptions$re, retries, _getRequestOptions$re2, retryCondition, _getRequestOptions$re3, retryDelay, _getRequestOptions$sh, shouldResetTimeout, _getRequestOptions$on, onRetry, currentState, delay, lastRequestDuration;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
config = error.config; // If we have no information to retry the request
if (config) {
_context.next = 3;
break;
}
return _context.abrupt("return", Promise.reject(error));
case 3:
_getRequestOptions = getRequestOptions(config, defaultOptions), _getRequestOptions$re = _getRequestOptions.retries, retries = _getRequestOptions$re === void 0 ? 3 : _getRequestOptions$re, _getRequestOptions$re2 = _getRequestOptions.retryCondition, retryCondition = _getRequestOptions$re2 === void 0 ? isNetworkOrIdempotentRequestError : _getRequestOptions$re2, _getRequestOptions$re3 = _getRequestOptions.retryDelay, retryDelay = _getRequestOptions$re3 === void 0 ? noDelay : _getRequestOptions$re3, _getRequestOptions$sh = _getRequestOptions.shouldResetTimeout, shouldResetTimeout = _getRequestOptions$sh === void 0 ? false : _getRequestOptions$sh, _getRequestOptions$on = _getRequestOptions.onRetry, onRetry = _getRequestOptions$on === void 0 ? function () {} : _getRequestOptions$on;
currentState = getCurrentState(config);
_context.next = 7;
return shouldRetry(retries, retryCondition, currentState, error);
case 7:
if (!_context.sent) {
_context.next = 15;
break;
}
currentState.retryCount += 1;
delay = retryDelay(currentState.retryCount, error); // Axios fails merging this configuration to the default configuration because it has an issue
// with circular structures: https://github.com/mzabriskie/axios/issues/370
fixConfig(axios, config);
if (!shouldResetTimeout && config.timeout && currentState.lastRequestTime) {
lastRequestDuration = Date.now() - currentState.lastRequestTime; // Minimum 1ms timeout (passing 0 or less to XHR means no timeout)
config.timeout = Math.max(config.timeout - lastRequestDuration - delay, 1);
}
config.transformRequest = [function (data) {
return data;
}];
onRetry(currentState.retryCount, error, config);
return _context.abrupt("return", new Promise(function (resolve) {
return setTimeout(function () {
return resolve(axios(config));
}, delay);
}));
case 15:
return _context.abrupt("return", Promise.reject(error));
case 16:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function (_x5) {
return _ref.apply(this, arguments);
};
}());
} // Compatibility with CommonJS
axiosRetry.isNetworkError = isNetworkError;
axiosRetry.isSafeRequestError = isSafeRequestError;
axiosRetry.isIdempotentRequestError = isIdempotentRequestError;
axiosRetry.isNetworkOrIdempotentRequestError = isNetworkOrIdempotentRequestError;
axiosRetry.exponentialDelay = exponentialDelay;
axiosRetry.isRetryableError = isRetryableError;
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
{
"type": "commonjs"
}
+275
View File
@@ -0,0 +1,275 @@
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import isRetryAllowed from 'is-retry-allowed';
var namespace = 'axios-retry';
/**
* @param {Error} error
* @return {boolean}
*/
export function isNetworkError(error) {
return !error.response && Boolean(error.code) && // Prevents retrying cancelled requests
error.code !== 'ECONNABORTED' && // Prevents retrying timed out requests
isRetryAllowed(error); // Prevents retrying unsafe errors
}
var SAFE_HTTP_METHODS = ['get', 'head', 'options'];
var IDEMPOTENT_HTTP_METHODS = SAFE_HTTP_METHODS.concat(['put', 'delete']);
/**
* @param {Error} error
* @return {boolean}
*/
export function isRetryableError(error) {
return error.code !== 'ECONNABORTED' && (!error.response || error.response.status >= 500 && error.response.status <= 599);
}
/**
* @param {Error} error
* @return {boolean}
*/
export function isSafeRequestError(error) {
if (!error.config) {
// Cannot determine if the request can be retried
return false;
}
return isRetryableError(error) && SAFE_HTTP_METHODS.indexOf(error.config.method) !== -1;
}
/**
* @param {Error} error
* @return {boolean}
*/
export function isIdempotentRequestError(error) {
if (!error.config) {
// Cannot determine if the request can be retried
return false;
}
return isRetryableError(error) && IDEMPOTENT_HTTP_METHODS.indexOf(error.config.method) !== -1;
}
/**
* @param {Error} error
* @return {boolean}
*/
export function isNetworkOrIdempotentRequestError(error) {
return isNetworkError(error) || isIdempotentRequestError(error);
}
/**
* @return {number} - delay in milliseconds, always 0
*/
function noDelay() {
return 0;
}
/**
* @param {number} [retryNumber=0]
* @return {number} - delay in milliseconds
*/
export function exponentialDelay() {
var retryNumber = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
var delay = Math.pow(2, retryNumber) * 100;
var randomSum = delay * 0.2 * Math.random(); // 0-20% of the delay
return delay + randomSum;
}
/**
* Initializes and returns the retry state for the given request/config
* @param {AxiosRequestConfig} config
* @return {Object}
*/
function getCurrentState(config) {
var currentState = config[namespace] || {};
currentState.retryCount = currentState.retryCount || 0;
config[namespace] = currentState;
return currentState;
}
/**
* Returns the axios-retry options for the current request
* @param {AxiosRequestConfig} config
* @param {AxiosRetryConfig} defaultOptions
* @return {AxiosRetryConfig}
*/
function getRequestOptions(config, defaultOptions) {
return _objectSpread(_objectSpread({}, defaultOptions), config[namespace]);
}
/**
* @param {Axios} axios
* @param {AxiosRequestConfig} config
*/
function fixConfig(axios, config) {
if (axios.defaults.agent === config.agent) {
delete config.agent;
}
if (axios.defaults.httpAgent === config.httpAgent) {
delete config.httpAgent;
}
if (axios.defaults.httpsAgent === config.httpsAgent) {
delete config.httpsAgent;
}
}
/**
* Checks retryCondition if request can be retried. Handles it's retruning value or Promise.
* @param {number} retries
* @param {Function} retryCondition
* @param {Object} currentState
* @param {Error} error
* @return {boolean}
*/
function shouldRetry(_x, _x2, _x3, _x4) {
return _shouldRetry.apply(this, arguments);
}
/**
* Adds response interceptors to an axios instance to retry requests failed due to network issues
*
* @example
*
* import axios from 'axios';
*
* axiosRetry(axios, { retries: 3 });
*
* axios.get('http://example.com/test') // The first request fails and the second returns 'ok'
* .then(result => {
* result.data; // 'ok'
* });
*
* // Exponential back-off retry delay between requests
* axiosRetry(axios, { retryDelay : axiosRetry.exponentialDelay});
*
* // Custom retry delay
* axiosRetry(axios, { retryDelay : (retryCount) => {
* return retryCount * 1000;
* }});
*
* // Also works with custom axios instances
* const client = axios.create({ baseURL: 'http://example.com' });
* axiosRetry(client, { retries: 3 });
*
* client.get('/test') // The first request fails and the second returns 'ok'
* .then(result => {
* result.data; // 'ok'
* });
*
* // Allows request-specific configuration
* client
* .get('/test', {
* 'axios-retry': {
* retries: 0
* }
* })
* .catch(error => { // The first request fails
* error !== undefined
* });
*
* @param {Axios} axios An axios instance (the axios object or one created from axios.create)
* @param {Object} [defaultOptions]
* @param {number} [defaultOptions.retries=3] Number of retries
* @param {boolean} [defaultOptions.shouldResetTimeout=false]
* Defines if the timeout should be reset between retries
* @param {Function} [defaultOptions.retryCondition=isNetworkOrIdempotentRequestError]
* A function to determine if the error can be retried
* @param {Function} [defaultOptions.retryDelay=noDelay]
* A function to determine the delay between retry requests
* @param {Function} [defaultOptions.onRetry=()=>{}]
* A function to get notified when a retry occurs
*/
function _shouldRetry() {
_shouldRetry = _asyncToGenerator(function* (retries, retryCondition, currentState, error) {
var shouldRetryOrPromise = currentState.retryCount < retries && retryCondition(error); // This could be a promise
if (typeof shouldRetryOrPromise === 'object') {
try {
var shouldRetryPromiseResult = yield shouldRetryOrPromise; // keep return true unless shouldRetryPromiseResult return false for compatibility
return shouldRetryPromiseResult !== false;
} catch (_err) {
return false;
}
}
return shouldRetryOrPromise;
});
return _shouldRetry.apply(this, arguments);
}
export default function axiosRetry(axios, defaultOptions) {
axios.interceptors.request.use(config => {
var currentState = getCurrentState(config);
currentState.lastRequestTime = Date.now();
return config;
});
axios.interceptors.response.use(null, /*#__PURE__*/function () {
var _ref = _asyncToGenerator(function* (error) {
var {
config
} = error; // If we have no information to retry the request
if (!config) {
return Promise.reject(error);
}
var {
retries = 3,
retryCondition = isNetworkOrIdempotentRequestError,
retryDelay = noDelay,
shouldResetTimeout = false,
onRetry = () => {}
} = getRequestOptions(config, defaultOptions);
var currentState = getCurrentState(config);
if (yield shouldRetry(retries, retryCondition, currentState, error)) {
currentState.retryCount += 1;
var delay = retryDelay(currentState.retryCount, error); // Axios fails merging this configuration to the default configuration because it has an issue
// with circular structures: https://github.com/mzabriskie/axios/issues/370
fixConfig(axios, config);
if (!shouldResetTimeout && config.timeout && currentState.lastRequestTime) {
var lastRequestDuration = Date.now() - currentState.lastRequestTime; // Minimum 1ms timeout (passing 0 or less to XHR means no timeout)
config.timeout = Math.max(config.timeout - lastRequestDuration - delay, 1);
}
config.transformRequest = [data => data];
onRetry(currentState.retryCount, error, config);
return new Promise(resolve => setTimeout(() => resolve(axios(config)), delay));
}
return Promise.reject(error);
});
return function (_x5) {
return _ref.apply(this, arguments);
};
}());
} // Compatibility with CommonJS
axiosRetry.isNetworkError = isNetworkError;
axiosRetry.isSafeRequestError = isSafeRequestError;
axiosRetry.isIdempotentRequestError = isIdempotentRequestError;
axiosRetry.isNetworkOrIdempotentRequestError = isNetworkOrIdempotentRequestError;
axiosRetry.exponentialDelay = exponentialDelay;
axiosRetry.isRetryableError = isRetryableError;
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
+3
View File
@@ -0,0 +1,3 @@
{
"type": "module"
}
+48 -36
View File
@@ -1,32 +1,32 @@
{
"_args": [
[
"axios-retry@3.1.8",
"/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series"
"axios-retry@3.3.1",
"/home/node/nuxt"
]
],
"_from": "axios-retry@3.1.8",
"_id": "axios-retry@3.1.8",
"_from": "axios-retry@3.3.1",
"_id": "axios-retry@3.3.1",
"_inBundle": false,
"_integrity": "sha512-yPw5Y4Bg6Dgmhm35KaJFtlh23s1TecW0HsUerK4/IS1UKl0gtN2aJqdEKtVomiOS/bDo5w4P3sqgki/M10eF8Q==",
"_integrity": "sha512-RohAUQTDxBSWLFEnoIG/6bvmy8l3TfpkclgStjl5MDCMBDgapAWCmr1r/9harQfWC8bzLC8job6UcL1A1Yc+/Q==",
"_location": "/axios-retry",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "axios-retry@3.1.8",
"raw": "axios-retry@3.3.1",
"name": "axios-retry",
"escapedName": "axios-retry",
"rawSpec": "3.1.8",
"rawSpec": "3.3.1",
"saveSpec": null,
"fetchSpec": "3.1.8"
"fetchSpec": "3.3.1"
},
"_requiredBy": [
"/@nuxtjs/axios"
],
"_resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.1.8.tgz",
"_spec": "3.1.8",
"_where": "/mnt/Foxconn/Digitalent/Deverloper/liff-push_2series",
"_resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-3.3.1.tgz",
"_spec": "3.3.1",
"_where": "/home/node/nuxt",
"author": {
"name": "Rubén Norte",
"email": "ruben.norte@softonic.com"
@@ -35,25 +35,35 @@
"url": "https://github.com/softonic/axios-retry/issues"
},
"dependencies": {
"is-retry-allowed": "^1.1.0"
"@babel/runtime": "^7.15.4",
"is-retry-allowed": "^2.2.0"
},
"description": "Axios plugin that intercepts failed requests and retries them whenever posible.",
"devDependencies": {
"axios": "^0.15.2",
"babel-cli": "^6.10.1",
"babel-preset-es2015": "^6.9.0",
"babel-register": "^6.9.0",
"eslint": "^4.4.1",
"eslint-config-airbnb-base": "^11.3.1",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-jasmine": "^1.8.1",
"eslint-plugin-prettier": "^2.6.0",
"husky": "^0.14.3",
"jasmine": "^2.4.1",
"lint-staged": "^7.1.2",
"nock": "^8.0.0",
"prettier": "^1.12.1"
"@babel/cli": "^7.15.7",
"@babel/core": "^7.15.5",
"@babel/plugin-transform-runtime": "^7.15.8",
"@babel/preset-env": "^7.15.6",
"axios": "^0.21.2",
"eslint": "^7.32.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.24.2",
"eslint-plugin-jasmine": "^4.1.2",
"eslint-plugin-prettier": "^4.0.0",
"husky": "^7.0.2",
"jasmine": "^3.9.0",
"lint-staged": "^11.2.0",
"nock": "^13.1.3",
"prettier": "^2.4.1"
},
"exports": {
".": {
"types": "./index.d.ts",
"import": "./lib/esm/index.js",
"require": "./index.js"
},
"./package.json": "./package.json"
},
"files": [
"es",
@@ -64,29 +74,31 @@
"homepage": "https://github.com/softonic/axios-retry",
"license": "Apache-2.0",
"lint-staged": {
"*.+(js|jsx|scss)": [
"prettier --write",
"git add"
]
"*.+(js|mjs)": [
"eslint --cache --fix",
"prettier --write"
],
"*.js": "eslint --cache --fix"
},
"main": "index.js",
"module": "lib/esm/index.js",
"name": "axios-retry",
"repository": {
"type": "git",
"url": "git+https://github.com/softonic/axios-retry.git"
},
"scripts": {
"build": "rm -rf lib && babel es -d lib --source-maps",
"lint": "eslint es/**/*.js spec/**/*.spec.js",
"build": "rm -rf lib && babel es -d lib/esm --source-maps && babel es -d lib/cjs --config-file ./babel.config.cjs.json --source-maps && ./fixup",
"lint": "eslint es/**/*.mjs spec/**/*.spec.mjs",
"postrelease": "npm run push && npm publish",
"prebuild": "npm run test",
"precommit": "lint-staged",
"prepare": "husky install",
"prerelease": "npm run build",
"pretest": "npm run lint",
"push": "git push origin master && git push origin --tags",
"release": "npm version -m \"New version: %s\"",
"test": "jasmine"
"test": "NODE_OPTIONS=--es-module-specifier-resolution=node jasmine"
},
"typings": "./index.d.ts",
"version": "3.1.8"
"version": "3.3.1"
}