{"version":3,"file":"configRequestDedupe.mjs","names":["Axios","configure","DEDUPE_CONFIG_FLAG","inFlightRequests","Map","requestKey","requestConfig","JSON","stringify","dedupedRequest","config","cancelToken","key","shared","get","finally","delete","set","cancellation","promise","then","reason","catch","Promise","race","configured","enableConfigRequestDedupe","axios","configResults","configPromises","fetchConfigOnce","request","has","resolve","pending","result"],"sources":["../../src/utilities/configRequestDedupe.js"],"sourcesContent":["import Axios from 'axios';\nimport { configure } from 'axios-hooks';\n\n/**\n * Request de-duplication for configuration reads (api catalog metadata,\n * promoted methods, ...). Config data changes rarely, so the same URL should be\n * fetched at most once per session and shared by every consumer.\n *\n * axios-hooks already keeps a module level LRU of *completed* responses, but it\n * has no in-flight de-duplication: N components mounting at the same time with\n * the same request config all miss the cache and all issue a request. The\n * wrapper installed here closes that gap without changing behaviour for\n * anything that does not opt in.\n */\n\n/**\n * Marker added to an axios config by `useAxiosGet` when the call site opted in\n * to caching. Only flagged requests are de-duplicated.\n */\nexport const DEDUPE_CONFIG_FLAG = 'udpDedupeConfigRequest';\n\n/** @type {Map<string, Promise<import('axios').AxiosResponse>>} */\nconst inFlightRequests = new Map();\n\nconst requestKey = (requestConfig) => JSON.stringify(requestConfig);\n\n/**\n * Issues the request once per key, handing the same promise to every caller\n * that asks for it while it is still in flight.\n *\n * The shared request is issued without a cancel token so that one consumer\n * unmounting cannot cancel the response every other consumer is waiting for.\n * Each caller still honours its own cancel token by racing against it, which\n * preserves axios-hooks' \"cancelled requests do not dispatch\" semantics.\n */\nconst dedupedRequest = (config) => {\n  const { cancelToken, ...requestConfig } = config;\n  const key = requestKey(requestConfig);\n\n  let shared = inFlightRequests.get(key);\n  if (!shared) {\n    shared = Axios(requestConfig).finally(() => {\n      inFlightRequests.delete(key);\n    });\n    inFlightRequests.set(key, shared);\n  }\n\n  if (!cancelToken) {\n    return shared;\n  }\n\n  const cancellation = cancelToken.promise.then((reason) => {\n    throw reason;\n  });\n  // The losing side of the race must not surface as an unhandled rejection.\n  cancellation.catch(() => {});\n\n  return Promise.race([shared, cancellation]);\n};\n\nlet configured = false;\n\n/**\n * Installs the de-duplicating request function on axios-hooks. Idempotent, and\n * a pass-through for every request that is not flagged for de-duplication.\n */\nexport const enableConfigRequestDedupe = () => {\n  if (configured) return;\n  configured = true;\n\n  configure({\n    axios: (config) =>\n      config?.[DEDUPE_CONFIG_FLAG] ? dedupedRequest(config) : Axios(config)\n  });\n};\n\n/** @type {Map<string, unknown>} */\nconst configResults = new Map();\n/** @type {Map<string, Promise<unknown>>} */\nconst configPromises = new Map();\n\n/**\n * Session cache + in-flight guard for config reads that do not go through\n * axios-hooks (POST based catalog lookups, for instance).\n * @template T\n * @param {string} key - Stable identity of the read (url or id tuple).\n * @param {() => Promise<T>} request - Issues the request on a cache miss.\n * @returns {Promise<T>}\n */\nexport const fetchConfigOnce = (key, request) => {\n  if (configResults.has(key)) {\n    return Promise.resolve(/** @type {T} */ (configResults.get(key)));\n  }\n\n  const pending = configPromises.get(key);\n  if (pending) {\n    return /** @type {Promise<T>} */ (pending);\n  }\n\n  const promise = request()\n    .then((result) => {\n      configResults.set(key, result);\n      return result;\n    })\n    .finally(() => {\n      configPromises.delete(key);\n    });\n\n  configPromises.set(key, promise);\n  return promise;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmBA,MAAaE,qBAAqB;;AAGlC,MAAMC,mCAAmB,IAAIC,KAAK;AAElC,MAAMC,cAAcC,kBAAkBC,KAAKC,UAAUF,cAAc;;;;;;;;;;AAWnE,MAAMG,kBAAkBC,WAAW;CACjC,MAAM,EAAEC,aAAa,GAAGL,kBAAkBI;CAC1C,MAAME,MAAMP,WAAWC,cAAc;CAErC,IAAIO,SAASV,iBAAiBW,IAAIF,IAAI;AACtC,KAAI,CAACC,QAAQ;AACXA,WAASb,MAAMM,cAAc,CAACS,cAAc;AAC1CZ,oBAAiBa,OAAOJ,IAAI;IAC5B;AACFT,mBAAiBc,IAAIL,KAAKC,OAAO;;AAGnC,KAAI,CAACF,YACH,QAAOE;CAGT,MAAMK,eAAeP,YAAYQ,QAAQC,MAAMC,WAAW;AACxD,QAAMA;GACN;AAEFH,cAAaI,YAAY,GAAG;AAE5B,QAAOC,QAAQC,KAAK,CAACX,QAAQK,aAAa,CAAC;;AAG7C,IAAIO,aAAa;;;;;AAMjB,MAAaC,kCAAkC;AAC7C,KAAID,WAAY;AAChBA,cAAa;AAEbxB,WAAU,EACR0B,QAAQjB,WACNA,SAAAA,4BAA+BD,eAAeC,OAAO,GAAGV,MAAMU,OAAM,EACvE,CAAC;;;AAIJ,MAAMkB,gCAAgB,IAAIxB,KAAK;;AAE/B,MAAMyB,iCAAiB,IAAIzB,KAAK;;;;;;;;;AAUhC,MAAa0B,mBAAmBlB,KAAKmB,YAAY;AAC/C,KAAIH,cAAcI,IAAIpB,IAAI,CACxB,QAAOW,QAAQU;;EAA0BL,cAAcd,IAAIF,IAAK;EAAC;CAGnE,MAAMsB,UAAUL,eAAef,IAAIF,IAAI;AACvC,KAAIsB,QACF,QAAkCA;CAGpC,MAAMf,UAAUY,SAAS,CACtBX,MAAMe,WAAW;AAChBP,gBAAcX,IAAIL,KAAKuB,OAAO;AAC9B,SAAOA;GACP,CACDpB,cAAc;AACbc,iBAAeb,OAAOJ,IAAI;GAC1B;AAEJiB,gBAAeZ,IAAIL,KAAKO,QAAQ;AAChC,QAAOA"}