UNPKG

wretch

Version:

A tiny wrapper built around fetch with an intuitive syntax.

1 lines 3.57 kB
{"version":3,"file":"dedupe.min.cjs","sources":["../../../src/middlewares/dedupe.ts"],"sourcesContent":["import type { ConfiguredMiddleware, WretchOptions } from \"../types.js\"\n\n/* Types */\n\nexport type DedupeSkipFunction = (url: string, opts: WretchOptions) => boolean\nexport type DedupeKeyFunction = (url: string, opts: WretchOptions) => string\nexport type DedupeResolverFunction = (response: Response) => Response\nexport type DedupeOptions = {\n skip?: DedupeSkipFunction,\n key?: DedupeKeyFunction,\n resolver?: DedupeResolverFunction\n}\n/**\n * ## Dedupe middleware\n *\n * #### Prevents having multiple identical requests on the fly at the same time.\n *\n * **Options**\n *\n * - *skip* `(url, opts) => boolean`\n *\n * > If skip returns true, then the dedupe check is skipped.\n *\n * - *key* `(url, opts) => string`\n *\n * > Returns a key that is used to identify the request.\n *\n * - *resolver* `(response: Response) => Response`\n *\n * > This function is called when resolving the fetch response from duplicate calls.\n * By default it clones the response to allow reading the body from multiple sources.\n */\nexport type DedupeMiddleware = (options?: DedupeOptions) => ConfiguredMiddleware\n\n/* Defaults */\n\nconst defaultSkip: DedupeSkipFunction = (_, opts) => (\n opts.skipDedupe || opts.method !== \"GET\"\n)\nconst defaultKey: DedupeKeyFunction = (url: string, opts) => opts.method + \"@\" + url\nconst defaultResolver: DedupeResolverFunction = response => response.clone()\n\nexport const dedupe: DedupeMiddleware = ({ skip = defaultSkip, key = defaultKey, resolver = defaultResolver } = {}) => {\n\n const inflight = new Map()\n\n return next => (url, opts) => {\n\n if (skip(url, opts)) {\n return next(url, opts)\n }\n\n const _key = key(url, opts)\n\n if (!inflight.has(_key)) {\n inflight.set(_key, [])\n } else {\n return new Promise((resolve, reject) => {\n inflight.get(_key).push([resolve, reject])\n })\n }\n\n try {\n return next(url, opts)\n .then(response => {\n // Resolve pending promises\n inflight.get(_key).forEach(([resolve]) => resolve(resolver(response)))\n // Remove the inflight pending promises\n inflight.delete(_key)\n // Return the original response\n return response\n })\n .catch(error => {\n // Reject pending promises on error\n inflight.get(_key).forEach(([resolve, reject]) => reject(error))\n inflight.delete(_key)\n throw error\n })\n } catch (error) {\n inflight.delete(_key)\n return Promise.reject(error)\n }\n\n }\n}\n"],"names":["defaultKey","url","opts","method","defaultResolver","response","clone","dedupe","skip","defaultSkip","key","inflight","Map","next","has","_key","Promise","resolve","reject","get","push","set","then","forEach","resolver","delete","catch","error"],"mappings":"8CAkCAA,EAAA,CAAAC,EAAAC,IAAAA,EAAAC,OAAA,IAAAF,EAEMG,EAAsCC,GAC1CA,EAAKC,QAEDC,EAAU,EAAAC,OAAoCC,EAAaC,MAAOV,aAAYI,GAAA,CAAA,KAC9E,MAAAO,EAAe,IAAmCC,cAET,CAAAX,EAAGC,QAElCM,EAAAP,EAAOC,GAEV,OAAIW,EAAIZ,EAAMC,GAGrB,QAAWQ,IAAMR,GAClB,GAAAS,EAAAG,IAAAC,GAMA,OAAA,IAAAC,SAAA,CAAAC,EAAAC,KAAMP,EAAAQ,IAAAJ,GAAAK,KAAA,CAAAH,EAAAC,GAAA,IAJPP,EAAaU,IAAIN,EAAS,IAOxB,IACD,OAAAF,EAAAZ,EAAAC,GAEGoB,MAAAjB,IAECM,EAAKQ,IAAAJ,GAAWQ,SAAA,EAAAN,KAAAA,EAAAO,EAAAnB,MAEfM,EAASc,eAITC,OAAOC,IAIP,MAFDhB,EAAMQ,IAAQJ,GAAAQ,SAAA,EAAAN,EAAAC,KAAAA,EAAAS,iBAEbA,CAAY,GAKhB,CAFE,MAAEA,GACJ,OAADhB,EAAAc,OAAAV,WAAeG,OAAAS,EACd,EACA,SAINpB"}