fetch-retry.umd.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.fetchRetry = factory());
  5. })(this, (function () { 'use strict';
  6. var fetchRetry = function (fetch, defaults) {
  7. defaults = defaults || {};
  8. if (typeof fetch !== 'function') {
  9. throw new ArgumentError('fetch must be a function');
  10. }
  11. if (typeof defaults !== 'object') {
  12. throw new ArgumentError('defaults must be an object');
  13. }
  14. if (defaults.retries !== undefined && !isPositiveInteger(defaults.retries)) {
  15. throw new ArgumentError('retries must be a positive integer');
  16. }
  17. if (defaults.retryDelay !== undefined && !isPositiveInteger(defaults.retryDelay) && typeof defaults.retryDelay !== 'function') {
  18. throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');
  19. }
  20. if (defaults.retryOn !== undefined && !Array.isArray(defaults.retryOn) && typeof defaults.retryOn !== 'function') {
  21. throw new ArgumentError('retryOn property expects an array or function');
  22. }
  23. var baseDefaults = {
  24. retries: 3,
  25. retryDelay: 1000,
  26. retryOn: [],
  27. };
  28. defaults = Object.assign(baseDefaults, defaults);
  29. return function fetchRetry(input, init) {
  30. var retries = defaults.retries;
  31. var retryDelay = defaults.retryDelay;
  32. var retryOn = defaults.retryOn;
  33. if (init && init.retries !== undefined) {
  34. if (isPositiveInteger(init.retries)) {
  35. retries = init.retries;
  36. } else {
  37. throw new ArgumentError('retries must be a positive integer');
  38. }
  39. }
  40. if (init && init.retryDelay !== undefined) {
  41. if (isPositiveInteger(init.retryDelay) || (typeof init.retryDelay === 'function')) {
  42. retryDelay = init.retryDelay;
  43. } else {
  44. throw new ArgumentError('retryDelay must be a positive integer or a function returning a positive integer');
  45. }
  46. }
  47. if (init && init.retryOn) {
  48. if (Array.isArray(init.retryOn) || (typeof init.retryOn === 'function')) {
  49. retryOn = init.retryOn;
  50. } else {
  51. throw new ArgumentError('retryOn property expects an array or function');
  52. }
  53. }
  54. // eslint-disable-next-line no-undef
  55. return new Promise(function (resolve, reject) {
  56. var wrappedFetch = function (attempt) {
  57. // As of node 18, this is no longer needed since node comes with native support for fetch:
  58. /* istanbul ignore next */
  59. var _input =
  60. typeof Request !== 'undefined' && input instanceof Request
  61. ? input.clone()
  62. : input;
  63. fetch(_input, init)
  64. .then(function (response) {
  65. if (Array.isArray(retryOn) && retryOn.indexOf(response.status) === -1) {
  66. resolve(response);
  67. } else if (typeof retryOn === 'function') {
  68. try {
  69. // eslint-disable-next-line no-undef
  70. return Promise.resolve(retryOn(attempt, null, response))
  71. .then(function (retryOnResponse) {
  72. if(retryOnResponse) {
  73. retry(attempt, null, response);
  74. } else {
  75. resolve(response);
  76. }
  77. }).catch(reject);
  78. } catch (error) {
  79. reject(error);
  80. }
  81. } else {
  82. if (attempt < retries) {
  83. retry(attempt, null, response);
  84. } else {
  85. resolve(response);
  86. }
  87. }
  88. })
  89. .catch(function (error) {
  90. if (typeof retryOn === 'function') {
  91. try {
  92. // eslint-disable-next-line no-undef
  93. Promise.resolve(retryOn(attempt, error, null))
  94. .then(function (retryOnResponse) {
  95. if(retryOnResponse) {
  96. retry(attempt, error, null);
  97. } else {
  98. reject(error);
  99. }
  100. })
  101. .catch(function(error) {
  102. reject(error);
  103. });
  104. } catch(error) {
  105. reject(error);
  106. }
  107. } else if (attempt < retries) {
  108. retry(attempt, error, null);
  109. } else {
  110. reject(error);
  111. }
  112. });
  113. };
  114. function retry(attempt, error, response) {
  115. var delay = (typeof retryDelay === 'function') ?
  116. retryDelay(attempt, error, response) : retryDelay;
  117. setTimeout(function () {
  118. wrappedFetch(++attempt);
  119. }, delay);
  120. }
  121. wrappedFetch(0);
  122. });
  123. };
  124. };
  125. function isPositiveInteger(value) {
  126. return Number.isInteger(value) && value >= 0;
  127. }
  128. function ArgumentError(message) {
  129. this.name = 'ArgumentError';
  130. this.message = message;
  131. }
  132. return fetchRetry;
  133. }));