UNPKG

wretch

Version:

A tiny wrapper built around fetch with an intuitive syntax.

1 lines 6.61 kB
{"version":3,"file":"retry.min.mjs","sources":["../../../src/middlewares/retry.ts"],"sourcesContent":["import type { ConfiguredMiddleware, WretchOptions } from \"../types.js\"\n\n/* Types */\n\nexport type DelayRampFunction = (delay: number, nbOfAttempts: number) => number\nexport type UntilFunction = (response?: Response, error?: Error) => boolean | Promise<boolean>\nexport type OnRetryFunctionResponse = { url?: string; options?: WretchOptions } | undefined\nexport type OnRetryFunction = (args: {\n response?: Response,\n error?: Error,\n url: string,\n options: WretchOptions\n}) => void | OnRetryFunctionResponse | Promise<OnRetryFunctionResponse>\nexport type RetryOptions = {\n /**\n * The timer between each attempt in milliseconds.\n *\n * _Default: `500`_\n */\n delayTimer?: number,\n /**\n * The custom function that is used to calculate the actual delay based on the the timer & the number of attemps.\n *\n * _Default: `delay * nbOfAttemps`_\n */\n delayRamp?: DelayRampFunction,\n /**\n * The maximum number of retries before resolving the promise with the last error. Specifying 0 means infinite retries.\n *\n * _Default: `10`_\n */\n maxAttempts?: number,\n /**\n * The request will be retried until that condition is satisfied.\n *\n * _Default: `response && response.ok`_\n */\n until?: UntilFunction,\n /**\n * Callback that will get executed before retrying the request. If this function returns an object having url and/or options properties, they will override existing values in the retried request.\n *\n * _Default: `undefined`_\n */\n onRetry?: OnRetryFunction,\n /**\n * If true, will retry the request if a network error was thrown. Will also provide an 'error' argument to the `onRetry` and `until` methods.\n *\n * _Default: `false`_\n */\n retryOnNetworkError?: boolean,\n /**\n * If true, the request will be resolved with the latest response instead of rejected with an error.\n *\n * _Default: `false`_\n */\n resolveWithLatestResponse?: boolean\n}\n\n/**\n * ## Retry middleware\n *\n * #### Retries a request multiple times in case of an error (or until a custom condition is true).\n *\n * ```ts\n * import wretch from 'wretch'\n * import { retry } from 'wretch/middlewares'\n *\n * wretch().middlewares([\n * retry({\n * // Options - defaults below\n * delayTimer: 500,\n * delayRamp: (delay, nbOfAttempts) => delay * nbOfAttempts,\n * maxAttempts: 10,\n * until: (response, error) => response && response.ok,\n * onRetry: null,\n * retryOnNetworkError: false,\n * resolveWithLatestResponse: false\n * })\n * ])\n *\n * // You can also return a Promise, which is useful if you want to inspect the body:\n * wretch().middlewares([\n * retry({\n * until: response =>\n * response.clone().json().then(body =>\n * body.field === 'something'\n * )\n * })\n * ])\n * ```\n */\nexport type RetryMiddleware = (options?: RetryOptions) => ConfiguredMiddleware\n\n/* Defaults */\n\nconst defaultDelayRamp: DelayRampFunction = (delay, nbOfAttempts) => (\n delay * nbOfAttempts\n)\nconst defaultUntil: UntilFunction = response => response && response.ok\n\nexport const retry: RetryMiddleware = ({\n delayTimer = 500,\n delayRamp = defaultDelayRamp,\n maxAttempts = 10,\n until = defaultUntil,\n onRetry = null,\n retryOnNetworkError = false,\n resolveWithLatestResponse = false\n} = {}) => {\n\n return next => (url, opts) => {\n let numberOfAttemptsMade = 0\n\n const checkStatus = (response?: Response, error?: Error) => {\n return Promise.resolve(until(response, error)).then(done => {\n // If the response is not suitable\n if (!done) {\n numberOfAttemptsMade++\n\n if (!maxAttempts || numberOfAttemptsMade <= maxAttempts) {\n // We need to recurse until we have a correct response and chain the checks\n return new Promise(resolve => {\n const delay = delayRamp(delayTimer, numberOfAttemptsMade)\n setTimeout(() => {\n if (typeof onRetry === \"function\") {\n Promise.resolve(onRetry({\n response,\n error,\n url,\n options: opts\n })).then((values = {}) => {\n resolve(next((values && values.url) ?? url, (values && values.options) ?? opts))\n })\n } else {\n resolve(next(url, opts))\n }\n }, delay)\n }).then(checkStatus).catch(error => {\n if (!retryOnNetworkError)\n throw error\n return checkStatus(null, error)\n })\n } else {\n return !!response && resolveWithLatestResponse ? response : Promise.reject(error || new Error(\"Number of attempts exceeded.\"))\n }\n }\n\n return !!response && resolveWithLatestResponse ? response : error ? Promise.reject(error) : response\n })\n }\n\n return next(url, opts)\n .then(checkStatus)\n .catch(error => {\n if (!retryOnNetworkError)\n throw error\n return checkStatus(null, error)\n })\n }\n}\n"],"names":["defaultDelayRamp","delay","nbOfAttempts","defaultUntil","response","ok","retry","delayTimer","delayRamp","maxAttempts","until","onRetry","retryOnNetworkError","resolveWithLatestResponse","next","url","opts","numberOfAttemptsMade","checkStatus","error","Promise","resolve","then","done","reject","setTimeout","options","values","_a","_b","catch","Error"],"mappings":"AA+FA,MAAMA,EAAsC,CAACC,EAAOC,IAClDD,EAAQC,EAEJC,EAA8BC,GAAYA,GAAYA,EAASC,GAExDC,EAAyB,EACpCC,aAAa,IACbC,YAAYR,EACZS,cAAc,GACdC,QAAQP,EACRQ,UAAU,KACVC,sBAAsB,EACtBC,4BAA4B,GAC1B,KAEKC,GAAQ,CAACC,EAAKC,KACnB,IAAIC,EAAuB,EAE3B,MAAMC,EAAc,CAACd,EAAqBe,IACjCC,QAAQC,QAAQX,EAAMN,EAAUe,IAAQG,MAAKC,GAE7CA,EA+BInB,GAAYS,EAA4BT,EAAWe,EAAQC,QAAQI,OAAOL,GAASf,GA9B1Fa,KAEKR,GAAeQ,GAAwBR,EAEnC,IAAIW,SAAQC,IACjB,MAAMpB,EAAQO,EAAUD,EAAYU,GACpCQ,YAAW,KACc,mBAAZd,EACTS,QAAQC,QAAQV,EAAQ,CACtBP,WACAe,QACAJ,MACAW,QAASV,KACPM,MAAK,CAACK,EAAS,CAAA,aACjBN,EAAQP,EAA+B,QAA1Bc,EAACD,GAAUA,EAAOZ,WAAQ,IAAAa,EAAAA,EAAAb,EAAmC,QAA9Bc,EAACF,GAAUA,EAAOD,eAAY,IAAAG,EAAAA,EAAAb,GAAM,IAGlFK,EAAQP,EAAKC,EAAKC,GACnB,GACAf,EAAM,IACRqB,KAAKJ,GAAaY,OAAMX,IACzB,IAAKP,EACH,MAAMO,EACR,OAAOD,EAAY,KAAMC,EAAM,IAGxBf,GAAYS,EAA4BT,EAAWgB,QAAQI,OAAOL,GAAS,IAAIY,MAAM,oCAQtG,OAAOjB,EAAKC,EAAKC,GACdM,KAAKJ,GACLY,OAAMX,IACL,IAAKP,EACH,MAAMO,EACR,OAAOD,EAAY,KAAMC,EAAM,GAC/B"}