You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 lines
4.3 KiB

'use strict';
module.exports = function (fetch, defaults) {
defaults = defaults || {};
if (typeof fetch !== 'function') {
throw new ArgumentError('fetch must be a function');
}
if (typeof defaults !== 'object') {
throw new ArgumentError('defaults must be an object');
}
if (defaults.retries !== undefined && !isPositiveInteger(defaults.retries)) {
throw new ArgumentError('retries must be a positive integer');
}
if (defaults.retryDelay !== undefined && !isPositiveInteger(defaults.retryDelay) && typeof defaults.retryDelay !== 'function') {
throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');
}
if (defaults.retryOn !== undefined && !Array.isArray(defaults.retryOn) && typeof defaults.retryOn !== 'function') {
throw new ArgumentError('retryOn property expects an array or function');
}
var baseDefaults = {
retries: 3,
retryDelay: 1000,
retryOn: [],
};
defaults = Object.assign(baseDefaults, defaults);
return function fetchRetry(input, init) {
var retries = defaults.retries;
var retryDelay = defaults.retryDelay;
var retryOn = defaults.retryOn;
if (init && init.retries !== undefined) {
if (isPositiveInteger(init.retries)) {
retries = init.retries;
} else {
throw new ArgumentError('retries must be a positive integer');
}
}
if (init && init.retryDelay !== undefined) {
if (isPositiveInteger(init.retryDelay) || (typeof init.retryDelay === 'function')) {
retryDelay = init.retryDelay;
} else {
throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');
}
}
if (init && init.retryOn) {
if (Array.isArray(init.retryOn) || (typeof init.retryOn === 'function')) {
retryOn = init.retryOn;
} else {
throw new ArgumentError('retryOn property expects an array or function');
}
}
// eslint-disable-next-line no-undef
return new Promise(function (resolve, reject) {
var wrappedFetch = function (attempt) {
fetch(input, init)
.then(function (response) {
if (Array.isArray(retryOn) && retryOn.indexOf(response.status) === -1) {
resolve(response);
} else if (typeof retryOn === 'function') {
try {
// eslint-disable-next-line no-undef
return Promise.resolve(retryOn(attempt, null, response))
.then(function (retryOnResponse) {
if(retryOnResponse) {
retry(attempt, null, response);
} else {
resolve(response);
}
}).catch(reject);
} catch (error) {
reject(error);
}
} else {
if (attempt < retries) {
retry(attempt, null, response);
} else {
resolve(response);
}
}
})
.catch(function (error) {
if (typeof retryOn === 'function') {
try {
// eslint-disable-next-line no-undef
Promise.resolve(retryOn(attempt, error, null))
.then(function (retryOnResponse) {
if(retryOnResponse) {
retry(attempt, error, null);
} else {
reject(error);
}
})
.catch(function(error) {
reject(error);
});
} catch(error) {
reject(error);
}
} else if (attempt < retries) {
retry(attempt, error, null);
} else {
reject(error);
}
});
};
function retry(attempt, error, response) {
var delay = (typeof retryDelay === 'function') ?
retryDelay(attempt, error, response) : retryDelay;
setTimeout(function () {
wrappedFetch(++attempt);
}, delay);
}
wrappedFetch(0);
});
};
};
function isPositiveInteger(value) {
return Number.isInteger(value) && value >= 0;
}
function ArgumentError(message) {
this.name = 'ArgumentError';
this.message = message;
}