{"version":3,"file":"dedupe.min.cjs","names":[],"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(([, 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"],"mappings":"mEAoCA,MAAM,GAAmC,EAAG,IAC1C,EAAK,YAAc,EAAK,SAAW,MAE/B,GAAiC,EAAa,IAAS,EAAK,OAAS,IAAM,EAC3E,EAA0C,GAAY,EAAS,OAAO,CAE/D,GAA4B,CAAE,OAAO,EAAa,MAAM,EAAY,WAAW,GAAoB,EAAE,GAAK,CAErH,IAAM,EAAW,IAAI,IAErB,MAAO,KAAS,EAAK,IAAS,CAE5B,GAAI,EAAK,EAAK,EAAK,CACjB,OAAO,EAAK,EAAK,EAAK,CAGxB,IAAM,EAAO,EAAI,EAAK,EAAK,CAE3B,GAAI,CAAC,EAAS,IAAI,EAAK,CACrB,EAAS,IAAI,EAAM,EAAE,CAAC,MAEtB,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,EAAS,IAAI,EAAK,CAAC,KAAK,CAAC,EAAS,EAAO,CAAC,EAC1C,CAGJ,GAAI,CACF,OAAO,EAAK,EAAK,EAAK,CACnB,KAAK,IAEJ,EAAS,IAAI,EAAK,CAAC,SAAS,CAAC,KAAa,EAAQ,EAAS,EAAS,CAAC,CAAC,CAEtE,EAAS,OAAO,EAAK,CAEd,GACP,CACD,MAAM,GAAS,CAId,MAFA,EAAS,IAAI,EAAK,CAAC,SAAS,EAAG,KAAY,EAAO,EAAM,CAAC,CACzD,EAAS,OAAO,EAAK,CACf,GACN,OACG,EAAO,CAEd,OADA,EAAS,OAAO,EAAK,CACd,QAAQ,OAAO,EAAM"}