diff --git a/README.md b/README.md index bc1af52b..83b71c68 100644 --- a/README.md +++ b/README.md @@ -1149,6 +1149,8 @@ const api = createApiFetcher({ 4. **Consider user experience** - Network revalidation happens silently in the background, providing smooth UX without loading spinners. > ⚠️ **Browser Support**: These features work in all modern browsers that support the `focus` and `online` events. In server-side environments (Node.js), these options are safely ignored. +> +> **React Native**: Use `setEventProvider()` to enable these features. See the [React Native](#react-native) section for details. @@ -3798,6 +3800,38 @@ For environments that do not support modern JavaScript features or APIs, you mig - **Promise Polyfill**: For older browsers that do not support Promises. Libraries like [es6-promise](https://github.com/stefanpenner/es6-promise) can be used. - **AbortController Polyfill**: For environments that do not support the `AbortController` API used for aborting fetch requests. You can use the [abort-controller](https://github.com/mysticatea/abort-controller) polyfill. +### React Native + +`fetchff` is fully compatible with React Native. Core features like caching, retries, deduplication, and the React hook work out of the box. + +To enable `refetchOnFocus` and `refetchOnReconnect`, register event providers at your app's entry point using `setEventProvider()`: + +```ts +import { AppState } from 'react-native'; +import NetInfo from '@react-native-community/netinfo'; +import { setEventProvider } from 'fetchff'; + +// Refetch when app comes to foreground +setEventProvider('focus', (handler) => { + const sub = AppState.addEventListener('change', (state) => { + if (state === 'active') handler(); + }); + return () => sub.remove(); +}); + +// Refetch when network reconnects +setEventProvider('online', (handler) => { + let wasConnected = true; + const unsubscribe = NetInfo.addEventListener((state) => { + if (state.isConnected && !wasConnected) handler(); + wasConnected = !!state.isConnected; + }); + return unsubscribe; +}); +``` + +> **Note:** `@react-native-community/netinfo` is optional — only needed if you use `refetchOnReconnect`. + ### Using `node-fetch` for Node.js < 18 If you need to support Node.js versions below 18 (not officially supported), you can use the [`node-fetch`](https://www.npmjs.com/package/node-fetch) package to polyfill the `fetch` API. Install it with: diff --git a/dist/browser/index.global.js b/dist/browser/index.global.js index f49227c7..6736400c 100644 --- a/dist/browser/index.global.js +++ b/dist/browser/index.global.js @@ -1,3 +1,3 @@ -var fetchff=(function(exports){'use strict';var ct=Object.defineProperty;var ft=(e,t,r)=>t in e?ct(e,t,{enumerable:true,configurable:true,writable:true,value:r}):e[t]=r;var L=(e,t,r)=>ft(e,typeof t!="symbol"?t+"":t,r);var x="application/",j=x+"json",Ne="charset=utf-8",C="Content-Type",h="undefined",K="object",b="string",g="function",ee="AbortError",Se="TimeoutError",O="GET",ve="HEAD",te="reject";var Ue=10;function re(e){return e instanceof URLSearchParams}function p(e){return e!==null&&typeof e===K}function J(e){let t={...e};return delete t.__proto__,delete t.constructor,delete t.prototype,t}function He(e){let t=Object.keys(e);t.sort();let r={};for(let a=0,n=t.length;a{i=typeof i===g?i():i,i=i===null||i===void 0?"":i,r[r.length]=a(l)+"="+a(i);},s=(l,i,m=0)=>{if(m>=Ue)return r;let c,R,P;if(l)if(Array.isArray(i))for(c=0,R=i.length;c{if(Object.prototype.hasOwnProperty.call(r,n)){let s=r[n];if(s!=null)return encodeURIComponent(String(s))}return a})}function ae(e){return e.includes("://")}var y=()=>Date.now(),Q=()=>{};function ge(e){let t=typeof e;return e==null?false:t===b||t==="number"||t==="boolean"||Array.isArray(e)?true:typeof globalThis!==h&&typeof globalThis.Buffer!==h&&globalThis.Buffer.isBuffer(e)||e instanceof Date||re(e)?false:!!(p(e)&&(Object.getPrototypeOf(e)===Object.prototype||typeof e.toJSON===g))}async function N(e){return new Promise(t=>setTimeout(()=>t(true),e))}function De(e,t=0){return t>=Ue?e:e&&p(e)&&typeof e.data!==h?De(e.data,t+1):e}function ne(e){if(!e)return {};let t={};if(e instanceof Headers)e.forEach((r,a)=>{t[a]=r;});else if(p(e))for(let[r,a]of Object.entries(e))t[r.toLowerCase()]=a;return t}function se(){return typeof window!==h&&typeof window.addEventListener===g}var Te=()=>{if(!se())return false;let e=navigator&&navigator.connection;return e&&["slow-2g","2g","3g"].includes(e.effectiveType)};async function w(e,t,...r){if(e){if(typeof e===g){let a=await e(t,...r);a&&p(t)&&p(a)&&Object.assign(t,a);}else if(Array.isArray(e))for(let a of e){let n=await a(t,...r);n&&p(t)&&p(n)&&Object.assign(t,n);}}}var oe=class extends Error{constructor(r,a,n){super(r);this.request=a;this.response=n;L(this,"status");L(this,"statusText");L(this,"config");L(this,"isCancelled");this.name="FetchError",this.status=n?n.status:0,this.statusText=n?n.statusText:"",this.config=a,this.isCancelled=false;}};var ie=class extends oe{constructor(t,r,a){super(t,r,a),this.name="ResponseError";}};var le=600,ue=1e3,mt=le*ue,k=Array(le).fill(0).map(()=>[]),q=new Map,z=0,E=null,je=([e,t])=>{q.delete(e);try{let r=t();r&&r instanceof Promise&&r.catch(Q);}catch(r){}},I=(e,t,r)=>{if(S(e),r>mt||r%ue!==0){q.set(e,[setTimeout(je.bind(null,[e,t]),r)]);return}let a=r/ue,n=(z+a)%le;k[n].push([e,t]),q.set(e,n),E||(E=setInterval(()=>{z=(z+1)%le,k[z].forEach(je),k[z]=[],!q.size&&E&&(clearInterval(E),E=null);},ue));},S=e=>{let t=q.get(e);t!==void 0&&(Array.isArray(t)?clearTimeout(t[0]):k[t].splice(k[t].findIndex(([r])=>r===e),1),q.delete(e),!q.size&&E&&(clearInterval(E),E=null));};var A=new Map;function Ke(e,t,r,a,n,s){if(!e)return new AbortController;let o=A.get(e),u=null;if(o){let i=o[0],m=o[3];if(!m&&y()-o[2]{Je(e,new DOMException(t+" aborted due to timeout",Se));},r),l}async function Je(e,t=null){if(e){let r=A.get(e);r&&(t&&r[0].abort(t),ce(e));}}function ce(e){S(e),A.delete(e);}function ze(e,t){let r=A.get(e);r&&(r[4]=t,A.set(e,r));}function be(e,t){if(!e)return null;let r=A.get(e);return r&&r[4]&&!r[3]&&y()-r[2]{if(!n[r])return;n[1]=a;let s=t?n[4]:n[0];s&&Promise.resolve(s(t)).catch(Q);});}async function me(e,t=false){if(!e)return null;let r=W.get(e);if(r){r[1]=y();let a=t?r[4]:r[0];if(a)return await a(t)}return null}function dt(e){Rt(e);let t=e==="focus"?5:6;W.forEach((r,a)=>{r[t]&&yt(a);});}function ke(e){if(!se()||fe.has(e))return;let t=Ge.bind(null,e,true);fe.set(e,t),window.addEventListener(e,t);}function Rt(e){if(!se())return;let t=fe.get(e);t&&(window.removeEventListener(e,t),fe.delete(e));}function We(e,t,r,a,n,s,o){W.set(e,[t,y(),pt,a,n,s,o]),s&&ke("focus"),o&&ke("online"),a&&I("s:"+e,me.bind(null,e,true),a*1e3);}function yt(e){W.delete(e),S("s:"+e);}var v=new Map;function Pt(e){return v.has(e)||v.set(e,new Set),v.get(e)}function ht(e,t){Pt(e).add(t);}function gt(e,t){let r=v.get(e);r&&(r.delete(t),r.size===0&&v.delete(e));}function _(e,t){let r=v.get(e);if(r)if(r.size===1){let a=r.values().next().value;a(t);}else r.forEach(a=>a(t));}function Dt(e,t){return e?(ht(e,t),()=>{gt(e,t);}):Q}var Ee=(Te()?60:30)*1e3,U={strategy:te,timeout:Ee,headers:{Accept:j+", text/plain, */*","Accept-Encoding":"gzip, deflate, br"},retry:{delay:Ee/30,maxDelay:Ee,resetTimeout:true,backoff:1.5,retryOn:[408,409,425,429,500,502,503,504]}};function Tt(e){let t=J(e);return Object.assign(U,t),U}function Ve(){return {...U}}function Ce(e,t){if(!t)return Ye(e,Ve());let r=J(t),a=Y(U,r);return Ye(e,a)}function Ye(e,t){var i;let r=t.method;r=r?r.toUpperCase():O;let a;r!==O&&r!==ve&&(a=(i=t.body)!=null?i:t.data,a&&typeof a!==b&&ge(a)&&(a=JSON.stringify(a))),bt(t.headers,a);let n=t.withCredentials?"include":t.credentials,s=Le(e,t.urlPathParams),o=Me(s,t.params),l=ae(e)?"":t.baseURL||t.apiUrl||"";return t.url=l+o,t.method=r,t.credentials=n,t.body=a,t}function bt(e,t){if(!e||!t||t instanceof FormData||typeof Blob!==h&&t instanceof Blob||typeof File!==h&&t instanceof File||typeof ReadableStream!==h&&t instanceof ReadableStream)return;let r;if(re(t))r=x+"x-www-form-urlencoded";else if(t instanceof ArrayBuffer||ArrayBuffer.isView(t))r=x+"octet-stream";else if(ge(t))r=j+";"+Ne;else return;e instanceof Headers?e.has(C)||e.set(C,r):p(e)&&!Array.isArray(e)&&!e[C]&&(e[C]=r);}function Y(e,t){let r=Object.assign({},e,t);return $e("retry",r,e,t),$e("headers",r,e,t),xe("onRequest",r,e,t),xe("onResponse",r,e,t),xe("onError",r,e,t),r}function xe(e,t,r,a){let n=r[e],s=a[e];if(!n&&!s)return;if(!n){t[e]=s;return}if(!s){t[e]=n;return}let o=Array.isArray(n)?n:[n],u=Array.isArray(s)?s:[s];t[e]=e==="onResponse"?u.concat(o):o.concat(u);}function $e(e,t,r,a){a[e]&&(t[e]={...r[e],...a[e]});}var de=new Map,B="|",we=64,Ze=new RegExp("[^\\w\\-_|]","g"),Et=new Set(["accept","accept-language","accept-encoding","authorization","content-type","referer","origin","user-agent","cookie","x-api-key","x-requested-with","x-client-id","x-tenant-id","x-user-id","x-app-version","x-feature-flag","x-device-id","x-platform","x-session-id","x-locale"]);function $(e,t=true){let r=e.cacheKey;if(r&&t)return typeof r===b?r:r(e);let{url:a="",method:n=O,headers:s=null,body:o=null,credentials:u="same-origin"}=e,l="";if(s){let m;s instanceof Headers?m=ne(s):m=s;let c=Object.keys(m),R=c.length;R>1&&c.sort();let P="";for(let f=0;f{i+=c+"="+m+"&";}),i.length>we&&(i=G(i));else if(typeof Blob!==h&&o instanceof Blob||typeof File!==h&&o instanceof File)i="BF"+o.size+o.type;else if(o instanceof ArrayBuffer||ArrayBuffer.isView(o))i="AB"+o.byteLength;else {let m=p(o)?JSON.stringify(He(o)):String(o);i=m.length>we?G(m):m;}return (n+B+a+B+u+B+l+B+i).replace(Ze,"")}function Xe(e){return e.expiry?y()>e.expiry:false}function xt(e){return e.stale?y()>e.stale:false}function Re(e){return de.get(e)}function ye(e,t,r,a){if(r===0){pe(e);return}let n=y(),s=r?r*1e3:0;de.set(e,{data:t,time:n,stale:a&&a>0?n+a*1e3:a,expiry:r===-1?void 0:n+s}),s>0&&I("c:"+e,()=>{pe(e,true);},s);}function pe(e,t=false){if(t){let r=Re(e);if(!r||!Xe(r))return}de.delete(e);}async function qe(e,t,r){if(!e)return null;let a=Re(e);if(!a)return null;let n=p(t)?J(t):t,s={...a.data,data:n},o={...a,data:s};return de.set(e,o),_(e,s),r&&r.refetch?await me(e):null}function Pe(e,t,r){if(!e||t===void 0||t===null)return null;let a=r.cacheBuster||U.cacheBuster;if(a&&a(r)||r.cache&&r.cache==="reload")return null;let n=Re(e);if(!n)return null;let s=Xe(n),o=xt(n);return s?(pe(e),null):!o||o&&!s?n.data:null}function Ie(e,t,r=false){let a=t.cacheKey;if(a){let n=t.cacheTime,s=t.skipCache;n&&(!r||t.cacheErrors)&&!(s&&s(e,t))&&ye(a,e,n,t.staleTime),_(a,e),ce(a);let o=t._prevKey;o&&ce(o);}}async function et(e){var n;if(!e)return null;let t=(n=e.headers)==null?void 0:n.get(C);t?t=t.toLowerCase().trim():t="";let r=t.split(";",1)[0],a;try{if(r.includes(j)||r.includes("+json"))a=await e.json();else if((r.includes("multipart/form-data")||r.includes(x+"x-www-form-urlencoded"))&&typeof e.formData===g)a=await e.formData();else if(r.includes(x+"octet-stream")&&typeof e.blob===g)a=await e.blob();else if(a=await e.text(),typeof a===b){let s=a.trim();if(s.startsWith("{")&&s.endsWith("}")||s.startsWith("[")&&s.endsWith("]"))try{a=JSON.parse(s);}catch(o){}}}catch(s){a=null;}return a}var Ae=(e,t,r=null)=>{let a=t.defaultResponse,n=t.cacheKey,s=qe.bind(null,n);if(!e)return {ok:false,error:r,data:a!=null?a:null,headers:null,config:t,mutate:s,isFetching:false,isSuccess:false,isError:true};let o=typeof Response===g&&e instanceof Response,u=e.data;a!==void 0&&(u==null||typeof u===K&&Object.keys(u).length===0)&&(e.data=u=a),t.flattenResponse&&(e.data=u=De(u)),t.select&&(e.data=u=t.select(u));let l=ne(e.headers);return o?{body:e.body,bodyUsed:e.bodyUsed,ok:e.ok,redirected:e.redirected,type:e.type,url:e.url,status:e.status,statusText:e.statusText,blob:()=>e.blob(),json:()=>e.json(),text:()=>e.text(),clone:()=>e.clone(),arrayBuffer:()=>e.arrayBuffer(),formData:()=>e.formData(),bytes:()=>e.bytes(),error:r,data:u,headers:l,config:t,mutate:s,isFetching:false,isSuccess:e.ok&&!r,isError:!!r}:(p(e)&&(e.error=r,e.headers=l,e.isFetching=false,e.mutate=s,e.isSuccess=e.ok&&!r,e.isError=!!r),e)};function tt(e){let t=Date.parse(e)-y();return isNaN(t)?null:Math.max(0,Math.floor(t))}function Ct(e){if(!e)return null;let t=e.headers||{},r=t["retry-after"];if(r){let o=Number(r);if(!isNaN(o)&&o>=0)return o*1e3;let u=tt(r);if(u!==null)return u}let a="ratelimit-reset",n=t[a+"-after"]||t["x-"+a+"-after"];if(n){let o=Number(n);if(!isNaN(o))return o*1e3}let s=t[a+"-at"]||t["x-"+a+"-at"];return s?tt(s):null}async function rt(e,t){let{retries:r=0,delay:a=0,backoff:n=1,maxDelay:s,retryOn:o=[],shouldRetry:u}=t,l=0,i=a,m=r>0?r:0,c;for(;l<=m;){if(l>0&&c){let f=c.config,H=f.onRetry;H&&(await w(H,c,l),f._isAutoKey&&(f._prevKey=f.cacheKey,f.cacheKey=$(f,false)));}c=await e(l>0,l);let R=c.error;if(!R){if(u&&l0&&await N(n),o=await e(),s++,!(a>0&&s>=a||!t||r&&r(o,s)));)await N(t);return o}async function nt(e,t,r){let a=await t(e),n=a.error;if(!n)return Ie(a,r),a;r.onError&&await w(r.onError,n);let s=n.isCancelled;if(!s&&r.logger&&qt(r,"FETCH ERROR",n),Ie(a,r,true),!s||r.rejectCancelled){let u=r.strategy;if(u===te)return Promise.reject(n);u==="silent"&&await new Promise(()=>null);}return a}function st(e,t,r){e.status=e.status||(t==null?void 0:t.status)||0,e.statusText=e.statusText||(t==null?void 0:t.statusText)||"",e.config=e.request=r,e.response=t,e.isCancelled=e.name===ee;}function qt(e,...t){let r=e.logger;r&&r.warn&&r.warn(...t);}var Be={isFetching:true};async function he(e,t=null){let r=Ce(e,t),{timeout:a,cancellable:n,cacheKey:s,dedupeTime:o,cacheTime:u,staleTime:l,refetchOnFocus:i,refetchOnReconnect:m,pollingInterval:c=0}=r,R=u!==void 0||l!==void 0,P=!!(s||a||o||R||n||i||m),f=null;if(P&&(f=$(r)),f&&R){let T=Pe(f,u,r);if(T)return T}if(f&&o){let T=be(f,o);if(T)return T}let H=r.retry||{},{retries:ot=0,resetTimeout:it}=H,Fe=async(T=false,Qe=0)=>{Qe||(f&&!T&&(l?Pe(f,u,r)||(ye(f,Be,u,l),_(f,Be)):_(f,Be)),r.cacheKey=f);let Z=r.url,lt=Ke(f,Z,a,o||0,!!n,!!(a&&(!Qe||it))),D=r;D.signal=lt.signal;let X,d=null;try{r.onRequest&&await w(r.onRequest,D);let F=r.fetcher;if(d=F?await F(Z,D):await fetch(Z,D),p(d)&&(typeof Response===g&&d instanceof Response?d.data=await et(d):F&&("data"in d&&"body"in d||(d={data:d})),d.config=D,d.ok!==void 0&&!d.ok))throw new ie(`${D.method} to ${Z} failed! Status: ${d.status||null}`,D,d);X=Ae(d,D);let M=r.onResponse;M&&await w(M,X);}catch(F){let M=F;st(M,d,D),X=Ae(d,D,M);}return X},ut=ot>0?()=>rt(Fe,H):Fe,V=(T=false)=>nt(T,ut,r),Oe=c?at(V,c,r.shouldStopPolling,r.maxPollingAttempts,r.pollingDelay):V();return f&&(o&&ze(f,Oe),We(f,V,void 0,l,V,!!i,!!m)),Oe}function It(e){let t=e.endpoints;function r(n){return console.error(`Add ${n} to 'endpoints'.`),Promise.resolve(null)}let a={config:e,endpoints:t,async request(n,s={}){let o=t[n],u=o||{url:String(n)},l=u.url;if(l.startsWith("//"))throw new Error("Protocol-relative URLs are not allowed.");let i=ae(l)?(o==null?void 0:o.url)===l?Y(u,s):s:Y(Y(e,u),s);return he(l,i)}};return new Proxy(a,{get(n,s){return s in a?a[s]:t[s]?a.request.bind(null,s):r.bind(null,s)}})} -exports.abortRequest=Je;exports.addTimeout=I;exports.buildConfig=Ce;exports.createApiFetcher=It;exports.deleteCache=pe;exports.fetchf=he;exports.fetchff=he;exports.generateCacheKey=$;exports.getCache=Re;exports.getCachedResponse=Pe;exports.getDefaultConfig=Ve;exports.getInFlightPromise=be;exports.isSlowConnection=Te;exports.mutate=qe;exports.removeRevalidators=dt;exports.revalidate=me;exports.revalidateAll=Ge;exports.setCache=ye;exports.setDefaultConfig=Tt;exports.subscribe=Dt;return exports;})({});//# sourceMappingURL=index.global.js.map +var fetchff=(function(exports){'use strict';var yt=Object.defineProperty;var Rt=(e,t,r)=>t in e?yt(e,t,{enumerable:true,configurable:true,writable:true,value:r}):e[t]=r;var z=(e,t,r)=>Rt(e,typeof t!="symbol"?t+"":t,r);var w="application/",J=w+"json",Ne="charset=utf-8",C="Content-Type",P="undefined",k="object",b="string",D="function",ae="AbortError",Se="TimeoutError",Q="GET",_e="HEAD",ne="reject";var Ue=10;function se(e){return e instanceof URLSearchParams}function d(e){return e!==null&&typeof e===k}function G(e){let t=Object.prototype.hasOwnProperty.call(e,"__proto__"),r=Object.prototype.hasOwnProperty.call(e,"constructor"),a=Object.prototype.hasOwnProperty.call(e,"prototype");if(!t&&!r&&!a)return e;let n={...e};return t&&delete n.__proto__,r&&delete n.constructor,a&&delete n.prototype,n}function Me(e){let t=Object.keys(e);t.sort();let r={};for(let a=0,n=t.length;a{i=typeof i===D?i():i,i=i===null||i===void 0?"":i,r[r.length]=a(l)+"="+a(i);},s=(l,i,m=0)=>{if(m>=Ue)return r;let c,p,g;if(l)if(Array.isArray(i))for(c=0,p=i.length;c{if(Object.prototype.hasOwnProperty.call(r,n)){let s=r[n];if(s!=null)return encodeURIComponent(String(s))}return a})}function oe(e){return e.includes("://")}var h=()=>Date.now(),N=()=>{};function ge(e){let t=typeof e;return e==null?false:t===b||t==="number"||t==="boolean"||Array.isArray(e)?true:typeof globalThis!==P&&typeof globalThis.Buffer!==P&&globalThis.Buffer.isBuffer(e)||e instanceof Date||se(e)?false:!!(d(e)&&(Object.getPrototypeOf(e)===Object.prototype||typeof e.toJSON===D))}async function S(e){return new Promise(t=>setTimeout(()=>t(true),e))}function De(e,t=0){return t>=Ue?e:e&&d(e)&&typeof e.data!==P?De(e.data,t+1):e}function A(e){if(!e)return {};let t={};if(e instanceof Headers)e.forEach((r,a)=>{t[a.toLowerCase()]=r;});else if(d(e))for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r.toLowerCase()]=e[r]);return t}function Ke(){return typeof window!==P&&typeof window.addEventListener===D}function ie(e,t){if(typeof DOMException!==P)return new DOMException(e,t);let r=new Error(e);return r.name=t,r}var Ee=()=>{let e=typeof navigator!==P&&navigator.connection;return e&&["slow-2g","2g","3g"].includes(e.effectiveType)};async function I(e,t,...r){if(e){if(typeof e===D){let a=await e(t,...r);a&&d(t)&&d(a)&&Object.assign(t,a);}else if(Array.isArray(e))for(let a of e){let n=await a(t,...r);n&&d(t)&&d(n)&&Object.assign(t,n);}}}var ue=class extends Error{constructor(r,a,n){super(r);this.request=a;this.response=n;z(this,"status");z(this,"statusText");z(this,"config");z(this,"isCancelled");this.name="FetchError",this.status=n?n.status:0,this.statusText=n?n.statusText:"",this.config=a,this.isCancelled=false;}};var le=class extends ue{constructor(t,r,a){super(t,r,a),this.name="ResponseError";}};var fe=600,W=1e3,Pt=fe*W,Te=Array(fe).fill(0).map(()=>[]),q=new Map,ce=0,x=null,ze=([e,t])=>{q.delete(e);try{let r=t();r&&r instanceof Promise&&r.catch(N);}catch(r){}},B=(e,t,r)=>{if(_(e),rPt||r%W!==0){q.set(e,[setTimeout(ze.bind(null,[e,t]),r)]);return}let a=r/W,n=(ce+a)%fe;Te[n].push([e,t]),q.set(e,n),x||(x=setInterval(()=>{ce=(ce+1)%fe;let s=Te[ce];for(let o=0;o{let t=q.get(e);if(t!==void 0){if(Array.isArray(t))clearTimeout(t[0]);else {let r=Te[t],a=r.findIndex(([n])=>n===e);a!==-1&&r.splice(a,1);}q.delete(e),!q.size&&x&&(clearInterval(x),x=null);}};var H=new Map;function Je(e,t,r,a,n,s){if(!e)return new AbortController;let o=h(),u=H.get(e),l=null;if(u){let m=u[0],c=u[3];if(!c&&o-u[2]{ke(e,ie(t+" aborted due to timeout",Se));},r),i}async function ke(e,t=null){if(e){let r=H.get(e);r&&(t&&r[0].abort(t),me(e));}}function me(e){_(e),H.delete(e);}function Ge(e,t){let r=H.get(e);r&&(r[4]=t);}function be(e,t){if(!e)return null;let r=H.get(e);return r&&r[4]&&!r[3]&&h()-r[2]{if(!n[r])return;n[1]=a;let s=t?n[4]:n[0];s&&Promise.resolve(s(t)).catch(N);});}async function pe(e,t=false){if(!e)return null;let r=M.get(e);if(r){r[1]=h();let a=t?r[4]:r[0];if(a)return await a(t)}return null}function gt(e){Ze(e);let t=e==="focus"?5:6;M.forEach((r,a)=>{r[t]&&Dt(a);});}function xe(e){if(U.has(e))return;let t=$e.bind(null,e,true),r=Ye.get(e);if(r){let a=r(t);U.set(e,a);return}Ke()&&(window.addEventListener(e,t),U.set(e,()=>window.removeEventListener(e,t)));}function Ze(e){let t=U.get(e);t&&(t(),U.delete(e));}function Ve(e,t,r,a,n,s,o){let u=M.get(e);u?(u[0]=t,u[1]=h(),u[2]=We,u[3]=a,u[4]=n,u[5]=s,u[6]=o):M.set(e,[t,h(),We,a,n,s,o]),s&&xe("focus"),o&&xe("online"),a&&B("s:"+e,pe.bind(null,e,true),a*1e3);}function Dt(e){M.delete(e),_("s:"+e);}var $=new Map;function Et(e){let t=$.get(e);return t||(t=new Set,$.set(e,t)),t}function Tt(e,t){Et(e).add(t);}function bt(e,t){let r=$.get(e);r&&(r.delete(t),r.size===0&&$.delete(e));}function L(e,t){let r=$.get(e);if(r)if(r.size===1){let a=r.values().next().value;a(t);}else r.forEach(a=>a(t));}function xt(e,t){return e?(Tt(e,t),()=>{bt(e,t);}):N}var we=(Ee()?60:30)*1e3,Z={strategy:ne,timeout:we,headers:{Accept:J+", text/plain, */*","Accept-Encoding":"gzip, deflate, br"},retry:{delay:we/30,maxDelay:we,resetTimeout:true,backoff:1.5,retryOn:[408,409,425,429,500,502,503,504]}};function wt(e){let t=G(e);return j({},t,Z)}function tt(){return {...Z}}function Ae(e,t){if(!t)return Xe(e,tt());let r=G(t),a=j(Z,r);return Xe(e,a)}function Xe(e,t){var i;let r=t.method;r=r?r.toUpperCase():Q;let a;r!==Q&&r!==_e&&(a=(i=t.body)!=null?i:t.data,a&&typeof a!==b&&ge(a)&&(a=JSON.stringify(a))),Ct(t.headers,a);let n=t.withCredentials?"include":t.credentials,s=je(e,t.urlPathParams),o=Le(s,t.params),l=oe(e)?"":t.baseURL||t.apiUrl||"";return t.url=l+o,t.method=r,t.credentials=n,t.body=a,t}function Ct(e,t){if(!e||!t||t instanceof FormData||typeof Blob!==P&&t instanceof Blob||typeof File!==P&&t instanceof File||typeof ReadableStream!==P&&t instanceof ReadableStream)return;let r;if(se(t))r=w+"x-www-form-urlencoded";else if(t instanceof ArrayBuffer||ArrayBuffer.isView(t))r=w+"octet-stream";else if(ge(t))r=J+";"+Ne;else return;e instanceof Headers?e.has(C)||e.set(C,r):d(e)&&!Array.isArray(e)&&!e[C]&&(e[C]=r);}function j(e,t,r={}){return Object.assign(r,e,t),et("retry",e,t,r),et("headers",e,t,r),Ce("onRequest",e,t,r),Ce("onResponse",e,t,r),Ce("onError",e,t,r),r}function Ce(e,t,r,a){let n=t[e],s=r[e];if(!n&&!s)return;if(!n){a[e]=s;return}if(!s){a[e]=n;return}let o=Array.isArray(n)?n:[n],u=Array.isArray(s)?s:[s];a[e]=e==="onResponse"?u.concat(o):o.concat(u);}function et(e,t,r,a){if(r[e]){let n=t[e],s=r[e];if(e==="headers"&&(n instanceof Headers||s instanceof Headers)){let o=A(n),u=A(s);a[e]={...o,...u};}else a[e]={...n,...s};}}var ye=new Map,F="|",Ie=64,rt=/[^\w\-_|/:@.?=&~%#]/g,at=/[^\w\-_|/:@.?=&~%#]/,At=new Set(["accept","accept-language","accept-encoding","authorization","content-type","referer","origin","user-agent","cookie","x-api-key","x-requested-with","x-client-id","x-tenant-id","x-user-id","x-app-version","x-feature-flag","x-device-id","x-platform","x-session-id","x-locale"]);function V(e,t=true){let r=e.cacheKey;if(r&&t)return typeof r===b?r:r(e);let{url:a="",method:n=Q,headers:s=null,body:o=null,credentials:u="same-origin"}=e,l="";if(s){let c;s instanceof Headers?c=A(s):c=s;let p=Object.keys(c),g=p.length;g>1&&p.sort();let f="";for(let E=0;E{i+=p+"="+c+"&";}),i.length>Ie&&(i=Y(i));else if(typeof Blob!==P&&o instanceof Blob||typeof File!==P&&o instanceof File)i="BF"+o.size+o.type;else if(o instanceof ArrayBuffer||ArrayBuffer.isView(o))i="AB"+o.byteLength;else {let c=d(o)?JSON.stringify(Me(o)):String(o);i=c.length>Ie?Y(c):c;}let m=n+F+a+F+u+F+l+F+i;return at.test(m)?m.replace(rt,""):m}function nt(e){return e.expiry?h()>e.expiry:false}function Re(e){return ye.get(e)}function Pe(e,t,r,a){if(r===0){de(e);return}let n=h(),s=r?r*1e3:0,o=a?a*1e3:0;ye.set(e,{data:t,time:n,stale:o>0?n+o:void 0,expiry:r===-1?void 0:n+s}),s>0&&B("c:"+e,()=>{de(e,true);},s);}function de(e,t=false){if(t){let r=Re(e);if(!r||!nt(r))return}ye.delete(e);}async function qe(e,t,r){if(!e)return null;let a=Re(e);if(!a)return null;let n=d(t)?G(t):t,s={...a.data,data:n},o={...a,data:s};return ye.set(e,o),L(e,s),r&&r.refetch?await pe(e):null}function X(e,t,r){if(!e||t===void 0||t===null)return null;let a=r.cacheBuster||Z.cacheBuster;if(a&&a(r)||r.cache&&r.cache==="reload")return null;let n=Re(e);return n?nt(n)?(de(e),null):n.data:null}function Be(e,t,r=false){let a=t.cacheKey;if(a){let n=t.cacheTime,s=t.skipCache;n&&(!r||t.cacheErrors)&&!(s&&s(e,t))&&Pe(a,e,n,t.staleTime),L(a,e),me(a);let o=t._prevKey;o&&me(o);}}async function st(e){var n;if(!e)return null;let t=(n=e.headers)==null?void 0:n.get(C);t?t=t.toLowerCase().trim():t="";let r=t.split(";",1)[0],a;try{if(r.includes(J)||r.includes("+json"))a=await e.json();else if((r.includes("multipart/form-data")||r.includes(w+"x-www-form-urlencoded"))&&typeof e.formData===D)a=await e.formData();else if(r.includes(w+"octet-stream")&&typeof e.blob===D)a=await e.blob();else if(a=await e.text(),typeof a===b){let s=a.trim();if(s.startsWith("{")&&s.endsWith("}")||s.startsWith("[")&&s.endsWith("]"))try{a=JSON.parse(s);}catch(o){}}}catch(s){a=null;}return a}var Fe=(e,t,r=null)=>{let a=t.defaultResponse,n=t.cacheKey,s=qe.bind(null,n);if(!e)return {ok:false,error:r,data:a!=null?a:null,headers:null,config:t,mutate:s,isFetching:false,isSuccess:false,isError:true};let o=typeof Response===D&&e instanceof Response,u=e.data;a!==void 0&&(u==null||typeof u===k&&Object.keys(u).length===0)&&(e.data=u=a),t.flattenResponse&&(e.data=u=De(u)),t.select&&(e.data=u=t.select(u));let l=A(e.headers);return o?{body:e.body,bodyUsed:e.bodyUsed,ok:e.ok,redirected:e.redirected,type:e.type,url:e.url,status:e.status,statusText:e.statusText,blob:()=>e.blob(),json:()=>e.json(),text:()=>e.text(),clone:()=>e.clone(),arrayBuffer:()=>e.arrayBuffer(),formData:()=>e.formData(),bytes:()=>e.bytes(),error:r,data:u,headers:l,config:t,mutate:s,isFetching:false,isSuccess:e.ok&&!r,isError:!!r}:(d(e)&&(e.error=r,e.headers=l,e.isFetching=false,e.mutate=s,e.isSuccess=e.ok&&!r,e.isError=!!r),e)};function ot(e){let t=Date.parse(e)-h();return isNaN(t)?null:Math.max(0,Math.floor(t))}function It(e){if(!e)return null;let t=e.headers||{},r=t["retry-after"];if(r){let o=Number(r);if(!isNaN(o)&&o>=0)return o*1e3;let u=ot(r);if(u!==null)return u}let a="ratelimit-reset",n=t[a+"-after"]||t["x-"+a+"-after"];if(n){let o=Number(n);if(!isNaN(o))return o*1e3}let s=t[a+"-at"]||t["x-"+a+"-at"];return s?ot(s):null}async function it(e,t){let{retries:r=0,delay:a=0,backoff:n=1,maxDelay:s,retryOn:o=[],shouldRetry:u}=t,l=0,i=a,m=r>0?r:0,c;for(;l<=m;){if(l>0&&c){let f=c.config,E=f.onRetry;E&&(await I(E,c,l),f._isAutoKey&&(f._prevKey=f.cacheKey,f.cacheKey=V(f,false)));}c=await e(l>0,l);let p=c.error;if(!p){if(u&&l0&&await S(n),o=await e(),s++,!(a>0&&s>=a||!t||r&&r(o,s)));)await S(t);return o}async function lt(e,t,r){let a=await t(e),n=a.error;if(!n)return Be(a,r),a;r.onError&&await I(r.onError,n);let s=n.isCancelled;if(!s&&r.logger&&Bt(r,"FETCH ERROR",n),Be(a,r,true),!s||r.rejectCancelled){let u=r.strategy;if(u===ne)return Promise.reject(n);u==="silent"&&await new Promise(()=>null);}return a}function ct(e,t,r){e.status=e.status||(t==null?void 0:t.status)||0,e.statusText=e.statusText||(t==null?void 0:t.statusText)||"",e.config=e.request=r,e.response=t,e.isCancelled=e.name===ae;}function Bt(e,...t){let r=e.logger;r&&r.warn&&r.warn(...t);}var Oe=Object.freeze({isFetching:true});async function he(e,t=null){if(t&&typeof t.cacheKey=="string"){let R=X(t.cacheKey,t.cacheTime,t);if(R)return R}let r=Ae(e,t),{timeout:a,cancellable:n,cacheKey:s,dedupeTime:o,cacheTime:u,staleTime:l,refetchOnFocus:i,refetchOnReconnect:m,pollingInterval:c=0}=r,p=u!==void 0||l!==void 0,g=!!(s||a||o||p||n||i||m),f=null;if(g&&(f=V(r)),f&&p){let R=X(f,u,r);if(R)return R}if(f&&o){let R=be(f,o);if(R)return R}let E=r.retry||{},{retries:ft=0,resetTimeout:mt}=E,ve=async(R=false,te=0)=>{te||(f&&!R&&(l?X(f,u,r)||(Pe(f,Oe,u,l),L(f,Oe)):L(f,Oe)),r.cacheKey=f);let O=r.url,dt=Je(f,O,a,o||0,!!n,!!(a&&(!te||mt))),T=r;T.signal=dt.signal;let re,y=null;try{r.onRequest&&(f&&o&&!te&&await null,await I(r.onRequest,T));let v=r.fetcher;if(y=v?await v(O,T):await fetch(O,T),d(y)&&(typeof Response===D&&y instanceof Response?y.data=await st(y):v&&("data"in y&&"body"in y||(y={data:y})),y.config=T,y.ok!==void 0&&!y.ok))throw new le(`${T.method} to ${O} failed! Status: ${y.status||null}`,T,y);re=Fe(y,T);let K=r.onResponse;K&&await I(K,re);}catch(v){let K=v;ct(K,y,T),re=Fe(y,T,K);}return re},pt=ft>0?(R=false)=>it((te,O)=>ve(R,O),E):ve,ee=(R=false)=>lt(R,pt,r),Qe=c?ut(ee,c,r.shouldStopPolling,r.maxPollingAttempts,r.pollingDelay):ee();return f&&(o&&Ge(f,Qe),(l||i||m)&&Ve(f,ee,void 0,l,ee,!!i,!!m)),Qe}function Ft(e){let t=e.endpoints;function r(n){return console.error(`Add ${n} to 'endpoints'.`),Promise.resolve(null)}let a={config:e,endpoints:t,async request(n,s={}){let o=t[n],u=o||{url:String(n)},l=u.url;if(l.startsWith("//"))throw new Error("Protocol-relative URLs are not allowed.");let i=oe(l)?(o==null?void 0:o.url)===l?j(u,s):s:j(j(e,u),s);return he(l,i)}};return new Proxy(a,{get(n,s){return s in a?a[s]:t[s]?a.request.bind(null,s):r.bind(null,s)}})} +exports.abortRequest=ke;exports.addTimeout=B;exports.buildConfig=Ae;exports.createAbortError=ie;exports.createApiFetcher=Ft;exports.deleteCache=de;exports.fetchf=he;exports.fetchff=he;exports.generateCacheKey=V;exports.getCache=Re;exports.getCachedResponse=X;exports.getDefaultConfig=tt;exports.getInFlightPromise=be;exports.isSlowConnection=Ee;exports.mutate=qe;exports.removeRevalidators=gt;exports.revalidate=pe;exports.revalidateAll=$e;exports.setCache=Pe;exports.setDefaultConfig=wt;exports.setEventProvider=ht;exports.subscribe=xt;return exports;})({});//# sourceMappingURL=index.global.js.map //# sourceMappingURL=index.global.js.map \ No newline at end of file diff --git a/dist/browser/index.global.js.map b/dist/browser/index.global.js.map index 0f006c71..6d022f4a 100644 --- a/dist/browser/index.global.js.map +++ b/dist/browser/index.global.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../src/constants.ts","../../src/utils.ts","../../src/interceptor-manager.ts","../../src/errors/fetch-error.ts","../../src/errors/response-error.ts","../../src/timeout-wheel.ts","../../src/inflight-manager.ts","../../src/hash.ts","../../src/revalidator-manager.ts","../../src/pubsub-manager.ts","../../src/config-handler.ts","../../src/cache-manager.ts","../../src/response-parser.ts","../../src/retry-handler.ts","../../src/polling-handler.ts","../../src/error-handler.ts","../../src/request-handler.ts","../../src/api-handler.ts"],"names":["APPLICATION_CONTENT_TYPE","APPLICATION_JSON","CHARSET_UTF_8","CONTENT_TYPE","UNDEFINED","OBJECT","STRING","FUNCTION","ABORT_ERROR","TIMEOUT_ERROR","GET","HEAD","REJECT","MAX_DEPTH","isSearchParams","data","isObject","value","sanitizeObject","obj","safeObj","sortObject","keys","sortedObj","i","len","key","appendQueryStringToUrl","baseUrl","queryString","appendQueryParams","url","params","encodedQueryString","s","encode","add","k","v","buildParams","prefix","depth","replaceUrlPathParams","urlPathParams","match","isAbsoluteUrl","timeNow","noop","isJSONSerializable","delayInvocation","ms","resolve","flattenData","processHeaders","headers","headersObject","isBrowser","isSlowConnection","conn","applyInterceptors","interceptors","args","interceptor","FetchError","message","request","response","__publicField","ResponseError","WHEEL_SIZE","SECOND","MAX_WHEEL_MS","wheel","keyMap","position","timer","handleCallback","callback","result","e","addTimeout","cb","removeTimeout","seconds","slot","slotOrTimeout","inFlight","markInFlight","timeout","dedupeTime","isCancellable","isTimeoutEnabled","item","prevPromise","prevController","prevIsCancellable","controller","abortRequest","error","removeInFlight","setInFlightPromise","promise","getInFlightPromise","prevReq","hash","str","char","DEFAULT_TTL","revalidators","eventHandlers","revalidateAll","type","isStaleRevalidation","flagIndex","now","entry","revalidator","revalidate","removeRevalidators","removeEventHandler","removeRevalidator","addEventHandler","event","handler","addRevalidator","revalidatorFn","ttl","staleTime","bgRevalidatorFn","refetchOnFocus","refetchOnReconnect","listeners","ensureListenerSet","addListener","fn","removeListener","set","notifySubscribers","fns","subscribe","defaultTimeoutMs","defaultConfig","setDefaultConfig","customConfig","sanitized","getDefaultConfig","buildConfig","reqConfig","buildFetcherConfig","merged","mergeConfigs","requestConfig","_a","method","body","setContentTypeIfNeeded","credentials","dynamicUrl","urlPath","baseURL","contentTypeValue","baseConfig","overrideConfig","mergedConfig","mergeConfig","mergeInterceptors","property","targetConfig","baseInterceptor","newInterceptor","baseArr","newArr","_cache","DELIMITER","MIN_LENGTH_TO_HASH","CACHE_KEY_SANITIZE_PATTERN","CACHE_KEY_HEADER_WHITELIST","generateCacheKey","config","cacheKeyCheck","headersString","bodyString","o","isCacheExpired","isCacheStale","getCache","setCache","deleteCache","time","ttlMs","removeExpired","mutate","newData","settings","updatedData","updatedResponse","updatedEntry","getCachedResponse","cacheKey","cacheTime","buster","isExpired","isStale","handleResponseCache","output","isError","skipCache","prevCacheKey","parseResponseData","contentType","mimeType","trimmed","_error","prepareResponse","defaultResponse","mutatator","isNativeResponse","getMsFromHttpDate","dateString","getRetryAfterMs","extendedResponse","retryAfter","RATELIMIT_RESET","rateLimitResetAfter","rateLimitResetAt","withRetry","requestFn","retries","delay","backoff","maxDelay","retryOn","shouldRetry","attempt","waitTime","maxRetries","cfg","onRetry","getShouldStopRetrying","retryAfterMs","_b","customDecision","withPolling","pollingInterval","shouldStopPolling","maxAttempts","pollingDelay","pollingAttempt","withErrorHandling","isCancelled","logger","strategy","enhanceError","inFlightResponse","fetchf","fetcherConfig","cancellable","isCacheEnabled","needsCacheKey","_cacheKey","cached","inflight","retryConfig","resetTimeout","doRequestOnce","onResponse","baseRequest","requestWithErrorHandling","doRequestPromise","createApiFetcher","endpoints","handleNonImplemented","endpointName","apiHandler","endpointConfig","_endpointConfig","_target","prop"],"mappings":"0NAAO,IAAMA,CAAAA,CAA2B,cAAA,CAE3BC,CAAAA,CAAmBD,CAAAA,CAA2B,MAAA,CAC9CE,EAAAA,CAAgB,eAAA,CAChBC,CAAAA,CAAe,cAAA,CAEfC,CAAAA,CAAY,WAAA,CACZC,CAAAA,CAAS,QAAA,CACTC,EAAS,QAAA,CACTC,CAAAA,CAAW,UAAA,CAEXC,EAAAA,CAAc,YAAA,CACdC,EAAAA,CAAgB,cAAA,CAEhBC,CAAAA,CAAM,KAAA,CACNC,EAAAA,CAAO,MAAA,CAEPC,EAAAA,CAAS,QAAA,CCPtB,IAAMC,GAAY,EAAA,CAEX,SAASC,EAAAA,CAAeC,CAAAA,CAAwB,CACrD,OAAOA,CAAAA,YAAgB,eACzB,CAQO,SAASC,CAAAA,CAASC,CAAAA,CAA0C,CACjE,OAAOA,IAAU,IAAA,EAAQ,OAAOA,CAAAA,GAAUZ,CAC5C,CA8BO,SAASa,CAAAA,CAA8CC,CAAAA,CAAW,CACvE,IAAMC,CAAAA,CAAU,CAAE,GAAGD,CAAI,EAEzB,OAAA,OAAOC,CAAAA,CAAQ,SAAA,CACf,OAAQA,CAAAA,CAAgB,WAAA,CACxB,OAAOA,CAAAA,CAAQ,SAAA,CAERA,CACT,CAWO,SAASC,EAAAA,CAAWF,CAAAA,CAAkC,CAC3D,IAAMG,CAAAA,CAAO,MAAA,CAAO,IAAA,CAAKH,CAAG,CAAA,CAE5BG,CAAAA,CAAK,IAAA,EAAK,CAEV,IAAMC,CAAAA,CAAY,EAAC,CAEnB,IAAA,IAASC,EAAI,CAAA,CAAGC,CAAAA,CAAMH,CAAAA,CAAK,MAAA,CAAQE,CAAAA,CAAIC,CAAAA,CAAKD,CAAAA,EAAAA,CAAK,CAC/C,IAAME,CAAAA,CAAMJ,CAAAA,CAAKE,CAAC,CAAA,CAElBD,CAAAA,CAAUG,CAAG,CAAA,CAAIP,CAAAA,CAAIO,CAAG,EAC1B,CAEA,OAAOH,CACT,CASA,SAASI,EAAAA,CAAuBC,CAAAA,CAAiBC,CAAAA,CAA6B,CAC5E,OAAKA,CAAAA,CAIED,EAAQ,QAAA,CAAS,GAAG,CAAA,CACvB,CAAA,EAAGA,CAAO,CAAA,CAAA,EAAIC,CAAW,CAAA,CAAA,CACzB,CAAA,EAAGD,CAAO,CAAA,CAAA,EAAIC,CAAW,CAAA,CAAA,CALpBD,CAMX,CASO,SAASE,EAAAA,CAAkBC,CAAAA,CAAaC,CAAAA,CAA6B,CAC1E,GAAI,CAACA,CAAAA,CACH,OAAOD,CAAAA,CAIT,GAAIjB,EAAAA,CAAekB,CAAM,CAAA,CAAG,CAC1B,IAAMC,CAAAA,CAAqBD,CAAAA,CAAO,QAAA,EAAS,CAE3C,OAAOL,EAAAA,CAAuBI,CAAAA,CAAKE,CAAkB,CACvD,CAGA,IAAMC,CAAAA,CAAc,GACdC,CAAAA,CAAS,kBAAA,CACTC,CAAAA,CAAM,CAACC,CAAAA,CAAWC,CAAAA,GAAW,CACjCA,CAAAA,CAAI,OAAOA,CAAAA,GAAM/B,CAAAA,CAAW+B,CAAAA,EAAE,CAAIA,CAAAA,CAClCA,EAAIA,CAAAA,GAAM,IAAA,EAAYA,CAAAA,GAAM,MAAA,CAAX,EAAA,CAA4BA,CAAAA,CAC7CJ,CAAAA,CAAEA,CAAAA,CAAE,MAAM,CAAA,CAAIC,CAAAA,CAAOE,CAAC,CAAA,CAAI,GAAA,CAAMF,EAAOG,CAAC,EAC1C,CAAA,CAEMC,CAAAA,CAAc,CAACC,CAAAA,CAAgBrB,CAAAA,CAAUsB,CAAAA,CAAQ,CAAA,GAAM,CAE3D,GAAIA,CAAAA,EAAS5B,EAAAA,CACX,OAAOqB,EAGT,IAAIV,CAAAA,CAAWC,CAAAA,CAAaC,CAAAA,CAE5B,GAAIc,CAAAA,CACF,GAAI,KAAA,CAAM,OAAA,CAAQrB,CAAG,CAAA,CACnB,IAAKK,CAAAA,CAAI,CAAA,CAAGC,CAAAA,CAAMN,CAAAA,CAAI,MAAA,CAAQK,CAAAA,CAAIC,CAAAA,CAAKD,CAAAA,EAAAA,CACrCe,CAAAA,CACEC,CAAAA,CAAS,GAAA,EAAO,OAAOrB,CAAAA,CAAIK,CAAC,CAAA,GAAMnB,CAAAA,EAAUc,CAAAA,CAAIK,CAAC,EAAIA,CAAAA,CAAI,EAAA,CAAA,CAAM,GAAA,CAC/DL,CAAAA,CAAIK,CAAC,CAAA,CACLiB,CAAAA,CAAQ,CACV,CAAA,CAAA,KAAA,GAEOzB,CAAAA,CAASG,CAAG,CAAA,CACrB,IAAKO,CAAAA,IAAOP,EACVoB,CAAAA,CAAYC,CAAAA,CAAS,GAAA,CAAMd,CAAAA,CAAM,GAAA,CAAKP,CAAAA,CAAIO,CAAG,CAAA,CAAGe,CAAAA,CAAQ,CAAC,CAAA,CAAA,KAG3DL,CAAAA,CAAII,CAAAA,CAAQrB,CAAG,UAER,KAAA,CAAM,OAAA,CAAQA,CAAG,CAAA,CAC1B,IAAKK,CAAAA,CAAI,CAAA,CAAGC,CAAAA,CAAMN,CAAAA,CAAI,MAAA,CAAQK,CAAAA,CAAIC,CAAAA,CAAKD,CAAAA,EAAAA,CACrCY,CAAAA,CAAIjB,EAAIK,CAAC,CAAA,CAAE,IAAA,CAAML,CAAAA,CAAIK,CAAC,CAAA,CAAE,KAAK,CAAA,CAAA,KAG/B,IAAKE,CAAAA,IAAOP,CAAAA,CACVoB,CAAAA,CAAYb,CAAAA,CAAKP,CAAAA,CAAIO,CAAG,CAAA,CAAGe,CAAAA,CAAQ,CAAC,CAAA,CAGxC,OAAOP,CACT,CAAA,CAMMD,CAAAA,CAJmBM,CAAAA,CAAY,EAAA,CAAIP,CAAM,CAAA,CAAE,IAAA,CAAK,GAAG,EAIb,OAAA,CAAQ,SAAA,CAAW,IAAI,CAAA,CAEnE,OAAOL,EAAAA,CAAuBI,CAAAA,CAAKE,CAAkB,CACvD,CAWO,SAASS,EAAAA,CACdX,CAAAA,CACAY,CAAAA,CACQ,CACR,GAAI,CAACA,CAAAA,EAAiBZ,CAAAA,CAAI,OAAA,CAAQ,GAAG,CAAA,GAAM,EAAA,CACzC,OAAOA,CAAAA,CAKT,IAAMC,CAAAA,CAASW,CAAAA,CAGf,OAAOZ,CAAAA,CAAI,OAAA,CAAQ,mBAAA,CAAqB,CAACa,CAAAA,CAAOlB,CAAAA,GAAQ,CAEtD,GAAI,MAAA,CAAO,SAAA,CAAU,cAAA,CAAe,IAAA,CAAKM,CAAAA,CAAQN,CAAG,CAAA,CAAG,CACrD,IAAMT,CAAAA,CAAQe,CAAAA,CAAON,CAAG,CAAA,CAGxB,GAA2BT,CAAAA,EAAU,IAAA,CACnC,OAAO,kBAAA,CAAmB,MAAA,CAAOA,CAAK,CAAC,CAE3C,CAEA,OAAO2B,CACT,CAAC,CACH,CAUO,SAASC,EAAAA,CAAcd,CAAAA,CAAsB,CAClD,OAAOA,CAAAA,CAAI,QAAA,CAAS,KAAK,CAC3B,CAEO,IAAMe,CAAAA,CAAU,IAAM,IAAA,CAAK,GAAA,EAAI,CAEzBC,CAAAA,CAAO,IAAM,CAAC,CAAA,CAcpB,SAASC,EAAAA,CAAmB/B,CAAAA,CAAqB,CACtD,IAAM,EAAI,OAAOA,CAAAA,CAEjB,OAA2BA,CAAAA,EAAU,IAAA,CAC5B,KAAA,CAGL,CAAA,GAAMX,CAAAA,EAAU,CAAA,GAAM,QAAA,EAAY,CAAA,GAAM,SAAA,EAIxC,KAAA,CAAM,OAAA,CAAQW,CAAK,CAAA,CACd,IAAA,CAIP,OAAO,UAAA,GAAeb,CAAAA,EACtB,OAAO,UAAA,CAAW,MAAA,GAAWA,CAAAA,EAC7B,UAAA,CAAW,MAAA,CAAO,QAAA,CAASa,CAAK,CAAA,EAK9BA,aAAiB,IAAA,EAAQH,EAAAA,CAAeG,CAAK,CAAA,CACxC,KAAA,CAGL,CAAA,EAAAD,CAAAA,CAASC,CAAK,CAAA,GACF,MAAA,CAAO,cAAA,CAAeA,CAAK,CAAA,GAG3B,MAAA,CAAO,WAKjB,OAAOA,CAAAA,CAAM,MAAA,GAAWV,CAAAA,CAAAA,CAMhC,CAEA,eAAsB0C,CAAAA,CAAgBC,CAAAA,CAA8B,CAClE,OAAO,IAAI,OAAA,CAASC,CAAAA,EAClB,UAAA,CAAW,IACFA,CAAAA,CAAQ,IAAI,CAAA,CAClBD,CAAE,CACP,CACF,CAWO,SAASE,EAAAA,CAAYrC,CAAAA,CAAW0B,CAAAA,CAAQ,CAAA,CAAQ,CACrD,OAAIA,CAAAA,EAAS5B,GACJE,CAAAA,CAGLA,CAAAA,EAAQC,CAAAA,CAASD,CAAI,CAAA,EAAK,OAAOA,CAAAA,CAAK,IAAA,GAASX,CAAAA,CAC1CgD,EAAAA,CAAYrC,CAAAA,CAAK,IAAA,CAAM0B,CAAAA,CAAQ,CAAC,EAGlC1B,CACT,CAYO,SAASsC,EAAAA,CACdC,CAAAA,CACe,CACf,GAAI,CAACA,CAAAA,CACH,OAAO,EAAC,CAGV,IAAMC,CAAAA,CAA+B,EAAC,CAGtC,GAAID,CAAAA,YAAmB,OAAA,CACrBA,CAAAA,CAAQ,OAAA,CAAQ,CAACrC,CAAAA,CAAOS,CAAAA,GAAQ,CAC9B6B,CAAAA,CAAc7B,CAAG,CAAA,CAAIT,EACvB,CAAC,CAAA,CAAA,KAAA,GACQD,CAAAA,CAASsC,CAAO,CAAA,CAEzB,IAAA,GAAW,CAAC5B,CAAAA,CAAKT,CAAK,CAAA,GAAK,MAAA,CAAO,OAAA,CAAQqC,CAAO,CAAA,CAG/CC,CAAAA,CAAc7B,EAAI,WAAA,EAAa,CAAA,CAAIT,CAAAA,CAIvC,OAAOsC,CACT,CAOO,SAASC,EAAAA,EAAqB,CAEnC,OACE,OAAO,MAAA,GAAWpD,CAAAA,EAAa,OAAO,MAAA,CAAO,gBAAA,GAAqBG,CAEtE,CAMO,IAAMkD,EAAAA,CAAmB,IAAe,CAE7C,GAAI,CAACD,EAAAA,EAAU,CACb,OAAO,MAAA,CAGT,IAAME,CAAAA,CAAO,SAAA,EAAc,SAAA,CAAkB,UAAA,CAE7C,OAAOA,CAAAA,EAAQ,CAAC,SAAA,CAAW,IAAA,CAAM,IAAI,CAAA,CAAE,QAAA,CAASA,CAAAA,CAAK,aAAa,CACpE,ECzWA,eAAsBC,CAAAA,CAKpBC,CAAAA,CAA6B7C,CAAAA,CAAAA,GAAY8C,CAAAA,CAA2B,CACpE,GAAKD,CAAAA,CAAAA,CAIL,GAAI,OAAOA,CAAAA,GAAiBrD,CAAAA,CAAU,CACpC,IAAMU,EAAQ,MAAO2C,CAAAA,CACnB7C,CAAAA,CACA,GAAG8C,CACL,CAAA,CAEI5C,CAAAA,EAASD,CAAAA,CAASD,CAAI,CAAA,EAAKC,CAAAA,CAASC,CAAK,CAAA,EAC3C,MAAA,CAAO,OAAOF,CAAAA,CAAME,CAAK,EAE7B,CAAA,KAAA,GAAW,KAAA,CAAM,OAAA,CAAQ2C,CAAY,CAAA,CACnC,IAAA,IAAWE,CAAAA,IAAeF,CAAAA,CAAc,CACtC,IAAM3C,CAAAA,CAAQ,MAAM6C,CAAAA,CAAY/C,CAAAA,CAAM,GAAG8C,CAAI,CAAA,CAEzC5C,CAAAA,EAASD,CAAAA,CAASD,CAAI,CAAA,EAAKC,CAAAA,CAASC,CAAK,CAAA,EAC3C,MAAA,CAAO,MAAA,CAAOF,EAAME,CAAK,EAE7B,CAAA,CAEJ,CCjCO,IAAM8C,EAAAA,CAAN,cAKG,KAAM,CAMd,WAAA,CACEC,CAAAA,CACOC,CAAAA,CAMAC,CAAAA,CAMP,CACA,MAAMF,CAAO,CAAA,CAbN,IAAA,CAAA,OAAA,CAAAC,CAAAA,CAMA,IAAA,CAAA,QAAA,CAAAC,CAAAA,CAbTC,CAAAA,CAAA,IAAA,CAAA,QAAA,CAAA,CACAA,CAAAA,CAAA,IAAA,CAAA,YAAA,CAAA,CACAA,CAAAA,CAAA,IAAA,CAAA,QAAA,CAAA,CACAA,CAAAA,CAAA,IAAA,CAAA,aAAA,CAAA,CAmBE,KAAK,IAAA,CAAO,YAAA,CACZ,IAAA,CAAK,MAAA,CAASD,CAAAA,CAAWA,CAAAA,CAAS,MAAA,CAAS,CAAA,CAC3C,IAAA,CAAK,UAAA,CAAaA,CAAAA,CAAWA,CAAAA,CAAS,UAAA,CAAa,EAAA,CACnD,KAAK,MAAA,CAASD,CAAAA,CACd,IAAA,CAAK,WAAA,CAAc,MACrB,CACF,CAAA,CCpCO,IAAMG,EAAAA,CAAN,cAKGL,EAA+D,CACvE,WAAA,CACEC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CAMA,CACA,KAAA,CAAMF,CAAAA,CAASC,CAAAA,CAASC,CAAQ,CAAA,CAEhC,IAAA,CAAK,IAAA,CAAO,gBACd,CACF,CAAA,CCHA,IAAMG,EAAAA,CAAa,GAAA,CACbC,GAAS,GAAA,CACTC,EAAAA,CAAeF,EAAAA,CAAaC,EAAAA,CAC5BE,CAAAA,CAAyB,KAAA,CAAMH,EAAU,CAAA,CAC5C,IAAA,CAAK,CAAC,CAAA,CACN,GAAA,CAAI,IAAM,EAAE,CAAA,CAETI,CAAAA,CAAS,IAAI,GAAA,CACfC,CAAAA,CAAW,CAAA,CACXC,CAAAA,CAA+B,IAAA,CAE7BC,EAAAA,CAAiB,CAAC,CAAClD,CAAAA,CAAKmD,CAAQ,CAAA,GAAyB,CAC7DJ,CAAAA,CAAO,MAAA,CAAO/C,CAAG,CAAA,CAEjB,GAAI,CACF,IAAMoD,CAAAA,CAASD,CAAAA,EAAS,CACpBC,CAAAA,EAAUA,CAAAA,YAAkB,OAAA,EAE9BA,CAAAA,CAAO,MAAM/B,CAAI,EAErB,CAAA,MAAQgC,CAAAA,CAAA,CAER,CACF,CAAA,CAEaC,CAAAA,CAAa,CACxBtD,CAAAA,CACAuD,CAAAA,CACA/B,CAAAA,GACS,CAIT,GAHAgC,EAAcxD,CAAG,CAAA,CAGbwB,CAAAA,CAAKqB,EAAAA,EAAgBrB,CAAAA,CAAKoB,EAAAA,GAAW,CAAA,CAAG,CAC1CG,CAAAA,CAAO,GAAA,CAAI/C,CAAAA,CAAK,CAAC,UAAA,CAAWkD,EAAAA,CAAe,KAAK,IAAA,CAAM,CAAClD,CAAAA,CAAKuD,CAAE,CAAC,CAAA,CAAG/B,CAAE,CAAC,CAAC,CAAA,CAEtE,MACF,CAGA,IAAMiC,CAAAA,CAAUjC,EAAKoB,EAAAA,CACfc,CAAAA,CAAAA,CAAQV,CAAAA,CAAWS,CAAAA,EAAWd,EAAAA,CAEpCG,CAAAA,CAAMY,CAAI,CAAA,CAAE,IAAA,CAAK,CAAC1D,CAAAA,CAAKuD,CAAE,CAAC,CAAA,CAC1BR,CAAAA,CAAO,GAAA,CAAI/C,CAAAA,CAAK0D,CAAI,CAAA,CAEfT,CAAAA,GACHA,CAAAA,CAAQ,WAAA,CAAY,IAAM,CACxBD,CAAAA,CAAAA,CAAYA,CAAAA,CAAW,CAAA,EAAKL,EAAAA,CAC5BG,CAAAA,CAAME,CAAQ,EAAE,OAAA,CAAQE,EAAc,CAAA,CACtCJ,CAAAA,CAAME,CAAQ,CAAA,CAAI,EAAC,CAEf,CAACD,CAAAA,CAAO,IAAA,EAAQE,CAAAA,GAClB,aAAA,CAAcA,CAAK,EACnBA,CAAAA,CAAQ,IAAA,EAEZ,CAAA,CAAGL,EAAM,CAAA,EAEb,CAAA,CAEaY,CAAAA,CAAiBxD,CAAAA,EAAsB,CAClD,IAAM2D,CAAAA,CAAgBZ,CAAAA,CAAO,GAAA,CAAI/C,CAAG,EAEhC2D,CAAAA,GAAkB,MAAA,GAEhB,KAAA,CAAM,OAAA,CAAQA,CAAa,CAAA,CAC7B,YAAA,CAAaA,CAAAA,CAAc,CAAC,CAAC,CAAA,CAE7Bb,CAAAA,CAAMa,CAAa,CAAA,CAAE,OACnBb,CAAAA,CAAMa,CAAa,CAAA,CAAE,SAAA,CAAU,CAAC,CAAChD,CAAC,CAAA,GAAMA,CAAAA,GAAMX,CAAG,CAAA,CACjD,CACF,CAAA,CAGF+C,CAAAA,CAAO,OAAO/C,CAAG,CAAA,CAEb,CAAC+C,CAAAA,CAAO,IAAA,EAAQE,CAAAA,GAClB,aAAA,CAAcA,CAAK,CAAA,CACnBA,CAAAA,CAAQ,IAAA,CAAA,EAGd,EC5EA,IAAMW,CAAAA,CAAsC,IAAI,GAAA,CAazC,SAASC,EAAAA,CACd7D,CAAAA,CACAK,CAAAA,CACAyD,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACiB,CACjB,GAAI,CAACjE,CAAAA,CACH,OAAO,IAAI,eAAA,CAGb,IAAMkE,CAAAA,CAAON,CAAAA,CAAS,GAAA,CAAI5D,CAAG,CAAA,CACzBmE,CAAAA,CAAuC,IAAA,CAG3C,GAAID,CAAAA,CAAM,CACR,IAAME,CAAAA,CAAiBF,CAAAA,CAAK,CAAC,CAAA,CACvBG,CAAAA,CAAoBH,CAAAA,CAAK,CAAC,CAAA,CAGhC,GACE,CAACG,CAAAA,EACDjD,CAAAA,EAAQ,CAAI8C,CAAAA,CAAK,CAAC,CAAA,CAAIH,CAAAA,EACtB,CAACK,CAAAA,CAAe,MAAA,CAAO,OAAA,CAEvB,OAAOA,CAAAA,CAKLC,CAAAA,EACFD,CAAAA,CAAe,KAAA,CACb,IAAI,YAAA,CAAa,4BAAA,CAA8BtF,EAAW,CAC5D,CAAA,CAGF0E,EAAcxD,CAAG,CAAA,CACjBmE,CAAAA,CAAcD,CAAAA,CAAK,CAAC,EACtB,CAEA,IAAMI,CAAAA,CAAa,IAAI,eAAA,CAEvB,OAAAV,CAAAA,CAAS,GAAA,CAAI5D,EAAK,CAChBsE,CAAAA,CACAL,CAAAA,CACA7C,CAAAA,EAAQ,CACR4C,CAAAA,CACAG,CACF,CAAC,CAAA,CAEGF,CAAAA,EACFX,CAAAA,CACEtD,CAAAA,CACA,IAAM,CACJuE,GACEvE,CAAAA,CACA,IAAI,YAAA,CAAaK,CAAAA,CAAM,yBAAA,CAA2BtB,EAAa,CACjE,EACF,CAAA,CACA+E,CACF,CAAA,CAGKQ,CACT,CASA,eAAsBC,GACpBvE,CAAAA,CACAwE,CAAAA,CAAsC,IAAA,CACvB,CAEf,GAAIxE,CAAAA,CAAK,CACP,IAAMkE,CAAAA,CAAON,CAAAA,CAAS,GAAA,CAAI5D,CAAG,CAAA,CAEzBkE,CAAAA,GAEEM,GACiBN,CAAAA,CAAK,CAAC,CAAA,CACd,KAAA,CAAMM,CAAK,CAAA,CAGxBC,EAAAA,CAAezE,CAAG,CAAA,EAEtB,CACF,CAOO,SAASyE,EAAAA,CAAezE,CAAAA,CAA0B,CACvDwD,CAAAA,CAAcxD,CAAI,CAAA,CAClB4D,CAAAA,CAAS,MAAA,CAAO5D,CAAI,EACtB,CAsBO,SAAS0E,EAAAA,CACd1E,CAAAA,CACA2E,CAAAA,CACM,CACN,IAAMT,CAAAA,CAAON,CAAAA,CAAS,GAAA,CAAI5D,CAAG,CAAA,CACzBkE,CAAAA,GAEFA,CAAAA,CAAK,CAAC,CAAA,CAAIS,CAAAA,CAEVf,CAAAA,CAAS,GAAA,CAAI5D,CAAAA,CAAKkE,CAAI,CAAA,EAE1B,CASO,SAASU,EAAAA,CACd5E,CAAAA,CACA+D,CAAAA,CACmB,CACnB,GAAI,CAAC/D,CAAAA,CACH,OAAO,IAAA,CAGT,IAAM6E,CAAAA,CAAUjB,CAAAA,CAAS,GAAA,CAAI5D,CAAG,EAEhC,OACE6E,CAAAA,EAEAA,CAAAA,CAAQ,CAAC,CAAA,EAET,CAACA,CAAAA,CAAQ,CAAC,CAAA,EAEVzD,CAAAA,EAAQ,CAAIyD,CAAAA,CAAQ,CAAC,CAAA,CAAId,GAEzB,CAACc,CAAAA,CAAQ,CAAC,CAAA,CAAE,MAAA,CAAO,OAAA,CAEZA,CAAAA,CAAQ,CAAC,CAAA,CAGX,IACT,CC5MO,SAASC,CAAAA,CAAKC,CAAAA,CAAqB,CACxC,IAAID,CAAAA,CAAO,CAAA,CAEX,IAAA,IAAShF,CAAAA,CAAI,CAAA,CAAGC,CAAAA,CAAMgF,CAAAA,CAAI,MAAA,CAAQjF,CAAAA,CAAIC,CAAAA,CAAKD,CAAAA,EAAAA,CAAK,CAC9C,IAAMkF,EAAOD,CAAAA,CAAI,UAAA,CAAWjF,CAAC,CAAA,CAC7BgF,CAAAA,CAAQA,CAAAA,CAAO,EAAA,CAAmBE,CAAAA,CAAQ,EAC5C,CAEA,OAAO,MAAA,CAAOF,CAAI,CACpB,CCmBA,IAAMG,EAAAA,CAAc,GAAA,CAAS,GAAA,CACvBC,CAAAA,CAAe,IAAI,GAAA,CAUnBC,EAAAA,CAAgB,IAAI,GAAA,CAUnB,SAASC,EAAAA,CACdC,CAAAA,CACAC,CAAAA,CAA+B,KAC/B,CACA,IAAMC,CAAAA,CAAYF,CAAAA,GAAS,OAAA,CAAU,CAAA,CAAI,CAAA,CACnCG,CAAAA,CAAMpE,CAAAA,EAAQ,CAEpB8D,CAAAA,CAAa,OAAA,CAASO,CAAAA,EAAU,CAC9B,GAAI,CAACA,CAAAA,CAAMF,CAAS,CAAA,CAClB,OAGFE,CAAAA,CAAM,CAAC,CAAA,CAAID,CAAAA,CAGX,IAAME,CAAAA,CAAcJ,CAAAA,CAAsBG,CAAAA,CAAM,CAAC,CAAA,CAAIA,EAAM,CAAC,CAAA,CAExDC,CAAAA,EACF,OAAA,CAAQ,OAAA,CAAQA,CAAAA,CAAYJ,CAAmB,CAAC,CAAA,CAAE,KAAA,CAAMjE,CAAI,EAEhE,CAAC,EACH,CAUA,eAAsBsE,EAAAA,CACpB3F,CAAAA,CACAsF,CAAAA,CAA+B,KAAA,CACI,CAEnC,GAAI,CAACtF,CAAAA,CACH,OAAO,IAAA,CAGT,IAAMyF,CAAAA,CAAQP,CAAAA,CAAa,IAAIlF,CAAG,CAAA,CAElC,GAAIyF,CAAAA,CAAO,CAETA,CAAAA,CAAM,CAAC,CAAA,CAAIrE,CAAAA,EAAQ,CAEnB,IAAMsE,CAAAA,CAAcJ,CAAAA,CAAsBG,CAAAA,CAAM,CAAC,CAAA,CAAIA,CAAAA,CAAM,CAAC,CAAA,CAG5D,GAAIC,CAAAA,CACF,OAAO,MAAMA,CAAAA,CAAYJ,CAAmB,CAEhD,CAGA,OAAO,IACT,CAOO,SAASM,EAAAA,CAAmBP,CAAAA,CAAiB,CAClDQ,EAAAA,CAAmBR,CAAI,CAAA,CAEvB,IAAME,CAAAA,CAAYF,CAAAA,GAAS,OAAA,CAAU,CAAA,CAAI,CAAA,CAGzCH,CAAAA,CAAa,QAAQ,CAACO,CAAAA,CAAOzF,CAAAA,GAAQ,CAC/ByF,CAAAA,CAAMF,CAAS,CAAA,EACjBO,EAAAA,CAAkB9F,CAAG,EAEzB,CAAC,EACH,CAQA,SAAS+F,GAAgBC,CAAAA,CAAkB,CACzC,GAAI,CAAClE,EAAAA,EAAU,EAAKqD,EAAAA,CAAc,GAAA,CAAIa,CAAK,CAAA,CACzC,OAGF,IAAMC,CAAAA,CAAUb,EAAAA,CAAc,IAAA,CAAK,IAAA,CAAMY,CAAAA,CAAO,IAAI,CAAA,CAEpDb,EAAAA,CAAc,GAAA,CAAIa,CAAAA,CAAOC,CAAO,CAAA,CAChC,MAAA,CAAO,gBAAA,CAAiBD,CAAAA,CAAOC,CAAO,EACxC,CAOA,SAASJ,EAAAA,CAAmBG,CAAAA,CAAkB,CAC5C,GAAI,CAAClE,EAAAA,EAAU,CACb,OAGF,IAAMmE,CAAAA,CAAUd,EAAAA,CAAc,GAAA,CAAIa,CAAK,CAAA,CAEnCC,IACF,MAAA,CAAO,mBAAA,CAAoBD,CAAAA,CAAOC,CAAO,CAAA,CAEzCd,EAAAA,CAAc,MAAA,CAAOa,CAAK,CAAA,EAE9B,CAaO,SAASE,EAAAA,CACdlG,CAAAA,CACAmG,CAAAA,CACAC,EACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACA,CACAtB,CAAAA,CAAa,GAAA,CAAIlF,CAAAA,CAAK,CACpBmG,CAAAA,CACA/E,CAAAA,EAAQ,CACD6D,EAAAA,CACPoB,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CACF,CAAC,CAAA,CAEGD,CAAAA,EACFR,EAAAA,CAAgB,OAAO,CAAA,CAGrBS,CAAAA,EACFT,EAAAA,CAAgB,QAAQ,EAGtBM,CAAAA,EACF/C,CAAAA,CAAW,IAAA,CAAOtD,CAAAA,CAAK2F,EAAAA,CAAW,IAAA,CAAK,IAAA,CAAM3F,CAAAA,CAAK,IAAI,CAAA,CAAGqG,CAAAA,CAAY,GAAI,EAE7E,CAEO,SAASP,EAAAA,CAAkB9F,CAAAA,CAAa,CAC7CkF,CAAAA,CAAa,MAAA,CAAOlF,CAAG,CAAA,CAGvBwD,CAAAA,CAAc,IAAA,CAAOxD,CAAG,EAC1B,CChMA,IAAMyG,CAAAA,CAAY,IAAI,GAAA,CAEtB,SAASC,EAAAA,CAAkB1G,CAAAA,CAAa,CACtC,OAAKyG,CAAAA,CAAU,GAAA,CAAIzG,CAAG,CAAA,EACpByG,CAAAA,CAAU,GAAA,CAAIzG,CAAAA,CAAK,IAAI,GAAK,CAAA,CAGvByG,CAAAA,CAAU,GAAA,CAAIzG,CAAG,CAC1B,CAGO,SAAS2G,EAAAA,CAAqB3G,CAAAA,CAAa4G,CAAAA,CAAuB,CACvEF,EAAAA,CAAkB1G,CAAG,CAAA,CAAE,GAAA,CAAI4G,CAAE,EAC/B,CAEO,SAASC,EAAAA,CAAkB7G,CAAAA,CAAa4G,CAAAA,CAAiB,CAC9D,IAAME,CAAAA,CAAML,CAAAA,CAAU,GAAA,CAAIzG,CAAG,CAAA,CAEzB8G,CAAAA,GACFA,EAAI,MAAA,CAAOF,CAAE,CAAA,CAGTE,CAAAA,CAAI,IAAA,GAAS,CAAA,EACfL,CAAAA,CAAU,MAAA,CAAOzG,CAAG,CAAA,EAG1B,CAEO,SAAS+G,CAAAA,CAAqB/G,CAAAA,CAAawC,EAAa,CAC7D,IAAMwE,CAAAA,CAAMP,CAAAA,CAAU,GAAA,CAAIzG,CAAG,CAAA,CAE7B,GAAIgH,CAAAA,CACF,GAAIA,CAAAA,CAAI,IAAA,GAAS,CAAA,CAAG,CAElB,IAAMJ,CAAAA,CAAKI,CAAAA,CAAI,MAAA,EAAO,CAAE,IAAA,EAAK,CAAE,KAAA,CAC/BJ,CAAAA,CAAIpE,CAAQ,EACd,CAAA,KACEwE,CAAAA,CAAI,OAAA,CAASJ,CAAAA,EAAOA,EAAGpE,CAAQ,CAAC,EAGtC,CAEO,SAASyE,EAAAA,CAAajH,CAAAA,CAAoB4G,CAAAA,CAA2B,CAC1E,OAAK5G,CAAAA,EAKL2G,EAAAA,CAAe3G,CAAAA,CAAK4G,CAAE,EAGf,IAAM,CACXC,EAAAA,CAAe7G,CAAAA,CAAK4G,CAAE,EACxB,CAAA,EARSvF,CASX,CCtDA,IAAM6F,EAAAA,CAAAA,CAAoBnF,EAAAA,EAAiB,CAAI,EAAA,CAAK,IAAM,GAAA,CAE7CoF,CAAAA,CAA+B,CAC1C,QAAA,CAAUjI,EAAAA,CACV,OAAA,CAASgI,EAAAA,CACT,OAAA,CAAS,CACP,MAAA,CAAQ3I,CAAAA,CAAmB,mBAAA,CAC3B,iBAAA,CAAmB,mBACrB,CAAA,CACA,KAAA,CAAO,CACL,KAAA,CAAO2I,EAAAA,CAAmB,EAAA,CAC1B,QAAA,CAAUA,EAAAA,CACV,YAAA,CAAc,IAAA,CACd,OAAA,CAAS,GAAA,CAGT,OAAA,CAAS,CACP,GAAA,CACA,GAAA,CACA,IACA,GAAA,CACA,GAAA,CACA,GAAA,CACA,GAAA,CACA,GACF,CACF,CACF,CAAA,CAQO,SAASE,EAAAA,CACdC,CAAAA,CACwB,CACxB,IAAMC,CAAAA,CAAY9H,EAAe6H,CAAY,CAAA,CAE7C,OAAA,MAAA,CAAO,MAAA,CAAOF,CAAAA,CAAeG,CAAS,CAAA,CAE/BH,CACT,CAOO,SAASI,EAAAA,EAAkC,CAChD,OAAO,CAAE,GAAGJ,CAAc,CAC5B,CASO,SAASK,EAAAA,CACdnH,CAAAA,CACAoH,CAAAA,CAMmE,CACnE,GAAI,CAACA,CAAAA,CACH,OAAOC,EAAAA,CAAmBrH,CAAAA,CAAKkH,IAAkB,CAAA,CAGnD,IAAMD,CAAAA,CAAY9H,CAAAA,CAAeiI,CAAS,CAAA,CACpCE,CAAAA,CAASC,CAAAA,CAAaT,CAAAA,CAAeG,CAAS,CAAA,CAEpD,OAAOI,EAAAA,CAAmBrH,EAAKsH,CAAM,CACvC,CASO,SAASD,EAAAA,CACdrH,CAAAA,CACAwH,CAAAA,CACe,CArHjB,IAAAC,CAAAA,CAsHE,IAAIC,CAAAA,CAASF,CAAAA,CAAc,MAAA,CAC3BE,EAASA,CAAAA,CAAUA,CAAAA,CAAO,WAAA,EAAY,CAAe/I,CAAAA,CAErD,IAAIgJ,CAAAA,CAGAD,CAAAA,GAAW/I,CAAAA,EAAO+I,CAAAA,GAAW9I,EAAAA,GAC/B+I,CAAAA,CAAAA,CAAOF,CAAAA,CAAAD,CAAAA,CAAc,OAAd,IAAA,CAAAC,CAAAA,CAAsBD,CAAAA,CAAc,IAAA,CAGvCG,CAAAA,EAAQ,OAAOA,CAAAA,GAASpJ,CAAAA,EAAU0C,EAAAA,CAAmB0G,CAAI,CAAA,GAC3DA,CAAAA,CAAO,IAAA,CAAK,SAAA,CAAUA,CAAI,CAAA,CAAA,CAAA,CAI9BC,EAAAA,CAAuBJ,CAAAA,CAAc,OAAA,CAASG,CAAI,CAAA,CAGlD,IAAME,CAAAA,CAAcL,CAAAA,CAAc,eAAA,CAC9B,SAAA,CACAA,CAAAA,CAAc,WAAA,CAGZM,CAAAA,CAAanH,EAAAA,CAAqBX,EAAKwH,CAAAA,CAAc,aAAa,CAAA,CAClEO,CAAAA,CAAUhI,EAAAA,CAAkB+H,CAAAA,CAAYN,CAAAA,CAAc,MAAM,CAAA,CAE5DQ,CAAAA,CADYlH,EAAAA,CAAcd,CAAG,CAAA,CAE/B,EAAA,CACAwH,EAAc,OAAA,EAAWA,CAAAA,CAAc,MAAA,EAAU,EAAA,CAErD,OAAAA,CAAAA,CAAc,GAAA,CAAMQ,CAAAA,CAAUD,CAAAA,CAC9BP,CAAAA,CAAc,MAAA,CAASE,CAAAA,CACvBF,CAAAA,CAAc,WAAA,CAAcK,EAC5BL,CAAAA,CAAc,IAAA,CAAOG,CAAAA,CAEdH,CACT,CAWA,SAASI,EAAAA,CACPrG,CAAAA,CACAoG,CAAAA,CACM,CAON,GALI,CAACpG,CAAAA,EAAW,CAACoG,GAMfA,CAAAA,YAAgB,QAAA,EACf,OAAO,IAAA,GAAStJ,CAAAA,EAAasJ,CAAAA,YAAgB,IAAA,EAC7C,OAAO,IAAA,GAAStJ,CAAAA,EAAasJ,CAAAA,YAAgB,IAAA,EAC7C,OAAO,cAAA,GAAmBtJ,GAAasJ,CAAAA,YAAgB,cAAA,CAExD,OAGF,IAAIM,CAAAA,CAEJ,GAAIlJ,EAAAA,CAAe4I,CAAI,CAAA,CACrBM,CAAAA,CAAmBhK,CAAAA,CAA2B,uBAAA,CAAA,KAAA,GACrC0J,CAAAA,YAAgB,WAAA,EAAe,YAAY,MAAA,CAAOA,CAAI,CAAA,CAC/DM,CAAAA,CAAmBhK,CAAAA,CAA2B,cAAA,CAAA,KAAA,GACrCgD,EAAAA,CAAmB0G,CAAI,CAAA,CAChCM,CAAAA,CAAmB/J,CAAAA,CAAmB,GAAA,CAAMC,EAAAA,CAAAA,KAG5C,OAGEoD,aAAmB,OAAA,CAChBA,CAAAA,CAAQ,GAAA,CAAInD,CAAY,CAAA,EAC3BmD,CAAAA,CAAQ,GAAA,CAAInD,CAAAA,CAAc6J,CAAgB,CAAA,CAG5ChJ,CAAAA,CAASsC,CAAO,CAAA,EAChB,CAAC,KAAA,CAAM,OAAA,CAAQA,CAAO,CAAA,EACtB,CAACA,CAAAA,CAAQnD,CAAY,CAAA,GAErBmD,CAAAA,CAAQnD,CAAY,CAAA,CAAI6J,CAAAA,EAE5B,CAEO,SAASV,CAAAA,CACdW,CAAAA,CACAC,EACe,CACf,IAAMC,CAAAA,CAA8B,MAAA,CAAO,MAAA,CACzC,EAAC,CACDF,CAAAA,CACAC,CACF,CAAA,CAGA,OAAAE,EAAAA,CAAY,OAAA,CAASD,CAAAA,CAAcF,EAAYC,CAAc,CAAA,CAC7DE,EAAAA,CAAY,SAAA,CAAWD,CAAAA,CAAcF,CAAAA,CAAYC,CAAc,CAAA,CAG/DG,EAAAA,CAAkB,WAAA,CAAaF,CAAAA,CAAcF,CAAAA,CAAYC,CAAc,CAAA,CACvEG,GAAkB,YAAA,CAAcF,CAAAA,CAAcF,CAAAA,CAAYC,CAAc,CAAA,CACxEG,EAAAA,CAAkB,SAAA,CAAWF,CAAAA,CAAcF,CAAAA,CAAYC,CAAc,CAAA,CAE9DC,CACT,CAKA,SAASE,GAGPC,CAAAA,CACAC,CAAAA,CACAN,CAAAA,CACAC,CAAAA,CACM,CACN,IAAMM,CAAAA,CAAkBP,CAAAA,CAAWK,CAAQ,CAAA,CACrCG,CAAAA,CAAiBP,CAAAA,CAAeI,CAAQ,CAAA,CAE9C,GAAI,CAACE,CAAAA,EAAmB,CAACC,CAAAA,CACvB,OAGF,GAAI,CAACD,CAAAA,CAAiB,CACpBD,CAAAA,CAAaD,CAAQ,CAAA,CAAIG,CAAAA,CACzB,MACF,CAEA,GAAI,CAACA,CAAAA,CAAgB,CACnBF,CAAAA,CAAaD,CAAQ,CAAA,CAAIE,CAAAA,CACzB,MACF,CAEA,IAAME,CAAAA,CAAU,KAAA,CAAM,OAAA,CAAQF,CAAe,CAAA,CACzCA,CAAAA,CACA,CAACA,CAAe,CAAA,CACdG,CAAAA,CAAS,KAAA,CAAM,OAAA,CAAQF,CAAc,CAAA,CACvCA,CAAAA,CACA,CAACA,CAAc,CAAA,CAGnBF,CAAAA,CAAaD,CAAQ,CAAA,CACnBA,CAAAA,GAAa,YAAA,CAAeK,CAAAA,CAAO,MAAA,CAAOD,CAAO,CAAA,CAAIA,CAAAA,CAAQ,MAAA,CAAOC,CAAM,EAC9E,CAUO,SAASP,EAAAA,CACdE,EACAC,CAAAA,CACAN,CAAAA,CACAC,CAAAA,CACM,CACFA,CAAAA,CAAeI,CAAQ,CAAA,GACzBC,CAAAA,CAAaD,CAAQ,CAAA,CAAI,CACvB,GAAGL,CAAAA,CAAWK,CAAQ,EACtB,GAAGJ,CAAAA,CAAeI,CAAQ,CAC5B,CAAA,EAEJ,CC9QA,IAAMM,EAAAA,CAAS,IAAI,GAAA,CACbC,CAAAA,CAAY,GAAA,CACZC,EAAAA,CAAqB,EAAA,CACrBC,GAA6B,IAAI,MAAA,CAAO,aAAA,CAAe,GAAG,CAAA,CAM1DC,EAAAA,CAA6B,IAAI,GAAA,CAAI,CAEzC,QAAA,CACA,iBAAA,CACA,iBAAA,CAGA,eAAA,CAGA,cAAA,CAGA,UACA,QAAA,CACA,YAAA,CAGA,QAAA,CAGA,WAAA,CACA,kBAAA,CACA,aAAA,CACA,aAAA,CACA,WAAA,CAEA,eAAA,CACA,gBAAA,CACA,aAAA,CACA,YAAA,CAEA,cAAA,CACA,UACF,CAAC,CAAA,CA0BM,SAASC,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CAAgB,IAAA,CACR,CAGR,IAAMzJ,CAAAA,CAAMwJ,CAAAA,CAAO,QAAA,CAEnB,GAAIxJ,CAAAA,EAAOyJ,CAAAA,CACT,OAAO,OAAOzJ,CAAAA,GAAQpB,CAAAA,CACjBoB,CAAAA,CACAA,CAAAA,CAAyBwJ,CAAM,CAAA,CAGtC,GAAM,CACJ,GAAA,CAAAnJ,CAAAA,CAAM,EAAA,CACN,MAAA,CAAA0H,CAAAA,CAAS/I,EACT,OAAA,CAAA4C,CAAAA,CAAU,IAAA,CACV,IAAA,CAAAoG,CAAAA,CAAO,IAAA,CACP,WAAA,CAAAE,CAAAA,CAAc,aAChB,CAAA,CAAIsB,CAAAA,CAIAE,CAAAA,CAAgB,EAAA,CACpB,GAAI9H,CAAAA,CAAS,CACX,IAAInC,CAAAA,CAEAmC,CAAAA,YAAmB,OAAA,CACrBnC,CAAAA,CAAMkC,EAAAA,CAAeC,CAAO,CAAA,CAE5BnC,CAAAA,CAAMmC,CAAAA,CAKR,IAAMhC,CAAAA,CAAO,MAAA,CAAO,IAAA,CAAKH,CAAG,CAAA,CACtBM,CAAAA,CAAMH,CAAAA,CAAK,MAAA,CAGbG,CAAAA,CAAM,CAAA,EACRH,CAAAA,CAAK,IAAA,EAAK,CAGZ,IAAImF,CAAAA,CAAM,EAAA,CACV,IAAA,IAASjF,CAAAA,CAAI,EAAGA,CAAAA,CAAIC,CAAAA,CAAK,EAAED,CAAAA,CACrBwJ,EAAAA,CAA2B,GAAA,CAAI1J,CAAAA,CAAKE,CAAC,CAAA,CAAE,WAAA,EAAa,CAAA,GACtDiF,CAAAA,EAAOnF,CAAAA,CAAKE,CAAC,CAAA,CAAI,GAAA,CAAML,CAAAA,CAAIG,CAAAA,CAAKE,CAAC,CAAC,CAAA,CAAI,GAAA,CAAA,CAI1C4J,CAAAA,CAAgB5E,CAAAA,CAAKC,CAAG,EAC1B,CAGA,GAAIgD,IAAW/I,CAAAA,CACb,OAAA,CACE+I,CAAAA,CACAoB,CAAAA,CACA9I,CAAAA,CACA8I,CAAAA,CACAjB,CAAAA,CACAiB,CAAAA,CACAO,CAAAA,EACA,OAAA,CAAQL,EAAAA,CAA4B,EAAE,CAAA,CAG1C,IAAIM,EAAa,EAAA,CACjB,GAAI3B,CAAAA,CACF,GAAI,OAAOA,CAAAA,GAASpJ,CAAAA,CAClB+K,CAAAA,CAAa3B,CAAAA,CAAK,MAAA,CAASoB,EAAAA,CAAqBpB,CAAAA,CAAOlD,CAAAA,CAAKkD,CAAI,UACvDA,CAAAA,YAAgB,QAAA,CACzBA,CAAAA,CAAK,OAAA,CAAQ,CAACzI,CAAAA,CAAOS,CAAAA,GAAQ,CAE3B2J,CAAAA,EAAc3J,CAAAA,CAAM,GAAA,CAAMT,CAAAA,CAAQ,IACpC,CAAC,EAEGoK,CAAAA,CAAW,MAAA,CAASP,EAAAA,GACtBO,CAAAA,CAAa7E,CAAAA,CAAK6E,CAAU,CAAA,CAAA,CAAA,KAAA,GAG7B,OAAO,IAAA,GAASjL,CAAAA,EAAasJ,CAAAA,YAAgB,IAAA,EAC7C,OAAO,IAAA,GAAStJ,CAAAA,EAAasJ,CAAAA,YAAgB,IAAA,CAE9C2B,CAAAA,CAAa,IAAA,CAAO3B,CAAAA,CAAK,IAAA,CAAOA,CAAAA,CAAK,IAAA,CAAA,KAAA,GAC5BA,CAAAA,YAAgB,WAAA,EAAe,WAAA,CAAY,MAAA,CAAOA,CAAI,CAAA,CAC/D2B,CAAAA,CAAa,KAAO3B,CAAAA,CAAK,UAAA,CAAA,KACpB,CACL,IAAM4B,CAAAA,CAAItK,CAAAA,CAAS0I,CAAI,CAAA,CACnB,IAAA,CAAK,SAAA,CAAUrI,EAAAA,CAAWqI,CAAI,CAAC,CAAA,CAC/B,OAAOA,CAAI,CAAA,CAEf2B,CAAAA,CAAaC,CAAAA,CAAE,MAAA,CAASR,EAAAA,CAAqBtE,CAAAA,CAAK8E,CAAC,CAAA,CAAIA,EACzD,CAKF,OAAA,CACE7B,CAAAA,CACAoB,CAAAA,CACA9I,EACA8I,CAAAA,CACAjB,CAAAA,CACAiB,CAAAA,CACAO,CAAAA,CACAP,CAAAA,CACAQ,CAAAA,EACA,OAAA,CAAQN,EAAAA,CAA4B,EAAE,CAC1C,CAQA,SAASQ,EAAAA,CAAepE,CAAAA,CAAiC,CAEvD,OAAKA,CAAAA,CAAM,MAAA,CAIJrE,CAAAA,EAAQ,CAAIqE,CAAAA,CAAM,MAAA,CAHhB,KAIX,CAQA,SAASqE,EAAAA,CAAarE,CAAAA,CAAiC,CACrD,OAAKA,EAAM,KAAA,CAIJrE,CAAAA,EAAQ,CAAIqE,CAAAA,CAAM,KAAA,CAHhB,KAIX,CA+BO,SAASsE,EAAAA,CACd/J,CAAAA,CAMY,CACZ,OAAOkJ,EAAAA,CAAO,GAAA,CAAIlJ,CAAa,CACjC,CAUO,SAASgK,EAAAA,CACdhK,CAAAA,CACAX,CAAAA,CACA+G,CAAAA,CACAC,CAAAA,CACM,CACN,GAAID,CAAAA,GAAQ,CAAA,CAAG,CACb6D,EAAAA,CAAYjK,CAAG,CAAA,CACf,MACF,CAEA,IAAMkK,CAAAA,CAAO9I,CAAAA,EAAQ,CACf+I,CAAAA,CAAQ/D,CAAAA,CAAMA,CAAAA,CAAM,GAAA,CAAO,CAAA,CAEjC8C,EAAAA,CAAO,GAAA,CAAIlJ,CAAAA,CAAK,CACd,IAAA,CAAAX,CAAAA,CACA,IAAA,CAAA6K,CAAAA,CACA,KAAA,CAAO7D,CAAAA,EAAaA,CAAAA,CAAY,CAAA,CAAI6D,CAAAA,CAAO7D,CAAAA,CAAY,GAAA,CAAOA,CAAAA,CAC9D,MAAA,CAAQD,CAAAA,GAAQ,GAAK,MAAA,CAAY8D,CAAAA,CAAOC,CAC1C,CAAC,CAAA,CAEGA,CAAAA,CAAQ,CAAA,EACV7G,CAAAA,CACE,IAAA,CAAOtD,CAAAA,CACP,IAAM,CACJiK,EAAAA,CAAYjK,CAAAA,CAAK,IAAI,EACvB,CAAA,CACAmK,CACF,EAEJ,CAQO,SAASF,EAAAA,CAAYjK,CAAAA,CAAaoK,CAAAA,CAAyB,KAAA,CAAa,CAC7E,GAAIA,CAAAA,CAAe,CACjB,IAAM3E,CAAAA,CAAQsE,EAAAA,CAAS/J,CAAG,CAAA,CAG1B,GAAI,CAACyF,CAAAA,EAAS,CAACoE,EAAAA,CAAepE,CAAK,CAAA,CACjC,MAEJ,CAEAyD,EAAAA,CAAO,OAAOlJ,CAAG,EACnB,CAgBA,eAAsBqK,EAAAA,CAMpBrK,CAAAA,CACAsK,CAAAA,CACAC,CAAAA,CAMQ,CAER,GAAI,CAACvK,CAAAA,CACH,OAAO,IAAA,CAGT,IAAMyF,CAAAA,CAAQsE,EAAAA,CACZ/J,CACF,CAAA,CAEA,GAAI,CAACyF,CAAAA,CACH,OAAO,IAAA,CAGT,IAAM+E,CAAAA,CAAclL,CAAAA,CAASgL,CAAO,CAAA,CAAI9K,EAAe8K,CAAO,CAAA,CAAIA,CAAAA,CAE5DG,CAAAA,CAAkB,CACtB,GAAGhF,CAAAA,CAAM,IAAA,CACT,IAAA,CAAM+E,CACR,CAAA,CAEME,CAAAA,CAAe,CACnB,GAAGjF,EACH,IAAA,CAAMgF,CACR,CAAA,CAKA,OAHAvB,EAAAA,CAAO,GAAA,CAAIlJ,CAAAA,CAAK0K,CAAY,CAAA,CAC5B3D,CAAAA,CAAkB/G,CAAAA,CAAKyK,CAAe,CAAA,CAElCF,CAAAA,EAAYA,CAAAA,CAAS,OAAA,CAChB,MAAM5E,EAAAA,CAAW3F,CAAG,CAAA,CAGtB,IACT,CAcO,SAAS2K,EAAAA,CAMdC,CAAAA,CACAC,CAAAA,CACAhD,CAAAA,CAM0E,CAE1E,GAAI,CAAC+C,GAAYC,CAAAA,GAAc,MAAA,EAAaA,CAAAA,GAAc,IAAA,CACxD,OAAO,IAAA,CAIT,IAAMC,CAAAA,CAASjD,CAAAA,CAAc,WAAA,EAAeV,CAAAA,CAAc,WAAA,CAK1D,GAJI2D,CAAAA,EAAUA,EAAOjD,CAAa,CAAA,EAI9BA,CAAAA,CAAc,KAAA,EAASA,CAAAA,CAAc,KAAA,GAAU,QAAA,CACjD,OAAO,IAAA,CAIT,IAAMpC,CAAAA,CAAQsE,EAAAA,CACZa,CACF,CAAA,CAEA,GAAI,CAACnF,CAAAA,CACH,OAAO,IAAA,CAGT,IAAMsF,CAAAA,CAAYlB,EAAAA,CAAepE,CAAK,CAAA,CAChCuF,CAAAA,CAAUlB,EAAAA,CAAarE,CAAK,CAAA,CAGlC,OAAIsF,GACFd,EAAAA,CAAYW,CAAQ,CAAA,CACb,IAAA,EAIL,CAACI,CAAAA,EAKDA,CAAAA,EAAW,CAACD,CAAAA,CAGPtF,CAAAA,CAAM,IAAA,CAGR,IACT,CASO,SAASwF,GAMdC,CAAAA,CACArD,CAAAA,CAMAsD,CAAAA,CAAmB,KAAA,CACb,CAEN,IAAMP,CAAAA,CAAW/C,CAAAA,CAAc,QAAA,CAE/B,GAAI+C,CAAAA,CAAU,CACZ,IAAMC,CAAAA,CAAYhD,EAAc,SAAA,CAC1BuD,CAAAA,CAAYvD,CAAAA,CAAc,SAAA,CAI9BgD,CAAAA,GACC,CAACM,CAAAA,EAAWtD,CAAAA,CAAc,WAAA,CAAA,EAC3B,EAAEuD,CAAAA,EAAaA,CAAAA,CAAUF,CAAAA,CAAQrD,CAAa,IAE9CmC,EAAAA,CAASY,CAAAA,CAAUM,CAAAA,CAAQL,CAAAA,CAAWhD,CAAAA,CAAc,SAAS,CAAA,CAG/Dd,CAAAA,CAAkB6D,CAAAA,CAAUM,CAAM,CAAA,CAClCzG,EAAAA,CAAemG,CAAQ,CAAA,CAEvB,IAAMS,CAAAA,CAAexD,CAAAA,CAAc,QAAA,CAE/BwD,CAAAA,EACF5G,EAAAA,CAAe4G,CAAY,EAE/B,CACF,CCzeA,eAAsBC,EAAAA,CAMpB9I,CAAAA,CACc,CAlChB,IAAAsF,CAAAA,CAoCE,GAAI,CAACtF,CAAAA,CACH,OAAO,IAAA,CAIT,IAAI+I,CAAAA,CAAAA,CAAezD,CAAAA,CAAAtF,CAAAA,CAAsB,OAAA,GAAtB,IAAA,CAAA,MAAA,CAAAsF,CAAAA,CAA+B,GAAA,CAAIrJ,CAAAA,CAAAA,CAElD8M,CAAAA,CAEFA,EAAcA,CAAAA,CAAY,WAAA,EAAY,CAAE,IAAA,EAAK,CAE7CA,CAAAA,CAAc,EAAA,CAIhB,IAAMC,CAAAA,CAAWD,CAAAA,CAAY,KAAA,CAAM,GAAA,CAAK,CAAC,CAAA,CAAE,CAAC,CAAA,CAExClM,CAAAA,CAEJ,GAAI,CACF,GAAImM,CAAAA,CAAS,QAAA,CAASjN,CAAgB,CAAA,EAAKiN,CAAAA,CAAS,QAAA,CAAS,OAAO,CAAA,CAClEnM,CAAAA,CAAO,MAAMmD,CAAAA,CAAS,IAAA,EAAK,CAAA,KAAA,GAAA,CAE1BgJ,CAAAA,CAAS,QAAA,CAAS,qBAAqB,CAAA,EACtCA,CAAAA,CAAS,QAAA,CACPlN,CAAAA,CAA2B,uBAC7B,CAAA,GACF,OAAOkE,CAAAA,CAAS,WAAa3D,CAAAA,CAE7BQ,CAAAA,CAAO,MAAMmD,CAAAA,CAAS,QAAA,EAAS,CAAA,KAAA,GAE/BgJ,CAAAA,CAAS,QAAA,CAASlN,CAAAA,CAA2B,cAAc,CAAA,EAC3D,OAAOkE,CAAAA,CAAS,IAAA,GAAS3D,EAEzBQ,CAAAA,CAAO,MAAMmD,CAAAA,CAAS,IAAA,EAAK,CAAA,KAAA,GAE3BnD,CAAAA,CAAO,MAAMmD,CAAAA,CAAS,IAAA,EAAK,CAEvB,OAAOnD,CAAAA,GAAST,CAAAA,CAAQ,CAC1B,IAAM6M,CAAAA,CAAUpM,CAAAA,CAAK,IAAA,EAAK,CAC1B,GACGoM,CAAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,EAAKA,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,EAC/CA,CAAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,EAAKA,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,CAEhD,GAAI,CACFpM,CAAAA,CAAO,IAAA,CAAK,KAAA,CAAMoM,CAAO,EAC3B,CAAA,MAAQpI,CAAAA,CAAA,CAER,CAEJ,CAGJ,CAAA,MAASqI,CAAAA,CAAQ,CAEfrM,CAAAA,CAAO,KACT,CAEA,OAAOA,CACT,CAUO,IAAMsM,EAAAA,CAAkB,CAM7BnJ,EAMAgH,CAAAA,CACAhF,CAAAA,CAKW,IAAA,GAC2D,CACtE,IAAMoH,CAAAA,CAAkBpC,CAAAA,CAAO,eAAA,CACzBoB,CAAAA,CAAWpB,CAAAA,CAAO,QAAA,CAClBqC,CAAAA,CAAYxB,EAAAA,CAAO,IAAA,CAAK,KAAMO,CAAkB,CAAA,CAQtD,GAAI,CAACpI,CAAAA,CACH,OAAO,CACL,EAAA,CAAI,KAAA,CAEJ,KAAA,CAAAgC,CAAAA,CACA,IAAA,CAAMoH,CAAAA,EAAA,IAAA,CAAAA,EAAmB,IAAA,CACzB,OAAA,CAAS,IAAA,CACT,MAAA,CAAApC,CAAAA,CACA,MAAA,CAAQqC,CAAAA,CACR,UAAA,CAAY,KAAA,CACZ,SAAA,CAAW,KAAA,CACX,OAAA,CAAS,IACX,CAAA,CAQF,IAAMC,CAAAA,CACJ,OAAO,QAAA,GAAajN,CAAAA,EAAY2D,CAAAA,YAAoB,QAAA,CAElDnD,CAAAA,CAAOmD,CAAAA,CAAS,IAAA,CAIlBoJ,CAAAA,GAAoB,MAAA,GAElBvM,CAAAA,EAAS,IAAA,EACR,OAAOA,IAASV,CAAAA,EAAU,MAAA,CAAO,IAAA,CAAKU,CAAI,CAAA,CAAE,MAAA,GAAW,CAAA,CAAA,GAE1DmD,CAAAA,CAAS,IAAA,CAAOnD,CAAAA,CAAOuM,CAAAA,CAAAA,CAGrBpC,CAAAA,CAAO,eAAA,GACThH,CAAAA,CAAS,KAAOnD,CAAAA,CAAOqC,EAAAA,CAAYrC,CAAI,CAAA,CAAA,CAGrCmK,CAAAA,CAAO,MAAA,GACThH,CAAAA,CAAS,IAAA,CAAOnD,CAAAA,CAAOmK,CAAAA,CAAO,MAAA,CAAOnK,CAAI,CAAA,CAAA,CAG3C,IAAMuC,CAAAA,CAAUD,EAAAA,CAAea,CAAAA,CAAS,OAAO,CAAA,CAG/C,OAAIsJ,CAAAA,CACK,CACL,IAAA,CAAMtJ,CAAAA,CAAS,IAAA,CACf,QAAA,CAAUA,CAAAA,CAAS,QAAA,CACnB,EAAA,CAAIA,CAAAA,CAAS,GACb,UAAA,CAAYA,CAAAA,CAAS,UAAA,CACrB,IAAA,CAAMA,CAAAA,CAAS,IAAA,CACf,GAAA,CAAKA,CAAAA,CAAS,GAAA,CACd,MAAA,CAAQA,CAAAA,CAAS,MAAA,CACjB,UAAA,CAAYA,CAAAA,CAAS,WAGrB,IAAA,CAAM,IAAMA,CAAAA,CAAS,IAAA,EAAK,CAC1B,IAAA,CAAM,IAAMA,CAAAA,CAAS,IAAA,EAAK,CAC1B,IAAA,CAAM,IAAMA,CAAAA,CAAS,IAAA,GACrB,KAAA,CAAO,IAAMA,CAAAA,CAAS,KAAA,EAAM,CAC5B,WAAA,CAAa,IAAMA,CAAAA,CAAS,WAAA,EAAY,CACxC,QAAA,CAAU,IAAMA,CAAAA,CAAS,QAAA,GACzB,KAAA,CAAO,IAAMA,CAAAA,CAAS,KAAA,EAAM,CAG5B,KAAA,CAAAgC,CAAAA,CACA,IAAA,CAAAnF,CAAAA,CACA,OAAA,CAAAuC,CAAAA,CACA,MAAA,CAAA4H,CAAAA,CACA,MAAA,CAAQqC,EACR,UAAA,CAAY,KAAA,CACZ,SAAA,CAAWrJ,CAAAA,CAAS,EAAA,EAAM,CAACgC,CAAAA,CAC3B,OAAA,CAAS,CAAC,CAACA,CACb,CAAA,EAIElF,CAAAA,CAASkD,CAAQ,IACnBA,CAAAA,CAAS,KAAA,CAAQgC,CAAAA,CACjBhC,CAAAA,CAAS,OAAA,CAAUZ,CAAAA,CACnBY,CAAAA,CAAS,UAAA,CAAa,KAAA,CACtBA,CAAAA,CAAS,MAAA,CAASqJ,CAAAA,CAClBrJ,CAAAA,CAAS,SAAA,CAAYA,EAAS,EAAA,EAAM,CAACgC,CAAAA,CACrChC,CAAAA,CAAS,OAAA,CAAU,CAAC,CAACgC,CAAAA,CAAAA,CAGhBhC,CAAAA,CACT,CAAA,CC3NA,SAASuJ,EAAAA,CAAkBC,CAAAA,CAAmC,CAC5D,IAAMxK,CAAAA,CAAK,IAAA,CAAK,KAAA,CAAMwK,CAAU,CAAA,CAAI5K,CAAAA,EAAQ,CAE5C,OAAK,KAAA,CAAMI,CAAE,CAAA,CAGN,IAAA,CAFE,IAAA,CAAK,GAAA,CAAI,CAAA,CAAG,KAAK,KAAA,CAAMA,CAAE,CAAC,CAGrC,CAaO,SAASyK,EAAAA,CACdC,CAAAA,CACe,CACf,GAAI,CAACA,CAAAA,CACH,OAAO,IAAA,CAGT,IAAMtK,CAAAA,CAAUsK,CAAAA,CAAiB,OAAA,EAAW,EAAC,CACvCC,CAAAA,CAAavK,CAAAA,CAAQ,aAAa,CAAA,CAExC,GAAIuK,CAAAA,CAAY,CAEd,IAAM1I,CAAAA,CAAU,OAAO0I,CAAU,CAAA,CAEjC,GAAI,CAAC,KAAA,CAAM1I,CAAO,CAAA,EAAKA,CAAAA,EAAW,CAAA,CAChC,OAAOA,CAAAA,CAAU,GAAA,CAGnB,IAAMjC,CAAAA,CAAKuK,GAAkBI,CAAU,CAAA,CAEvC,GAAI3K,CAAAA,GAAO,IAAA,CACT,OAAOA,CAEX,CAGA,IAAM4K,CAAAA,CAAkB,iBAAA,CAIlBC,CAAAA,CACJzK,CAAAA,CAAQwK,CAAAA,CAAkB,QAAQ,CAAA,EAClCxK,CAAAA,CAAQ,IAAA,CAAOwK,CAAAA,CAAkB,QAAQ,CAAA,CAE3C,GAAIC,CAAAA,CAAqB,CACvB,IAAM5I,CAAAA,CAAU,MAAA,CAAO4I,CAAmB,CAAA,CAE1C,GAAI,CAAC,KAAA,CAAM5I,CAAO,CAAA,CAChB,OAAOA,CAAAA,CAAU,GAErB,CAIA,IAAM6I,CAAAA,CACJ1K,CAAAA,CAAQwK,CAAAA,CAAkB,KAAK,CAAA,EAAKxK,EAAQ,IAAA,CAAOwK,CAAAA,CAAkB,KAAK,CAAA,CAE5E,OAAIE,CAAAA,CACKP,EAAAA,CAAkBO,CAAgB,CAAA,CAGpC,IACT,CAkBA,eAAsBC,EAAAA,CAMpBC,CAAAA,CAMAhD,CAAAA,CAC4E,CAC5E,GAAM,CACJ,OAAA,CAAAiD,CAAAA,CAAU,CAAA,CACV,KAAA,CAAAC,CAAAA,CAAQ,CAAA,CACR,OAAA,CAAAC,CAAAA,CAAU,CAAA,CACV,QAAA,CAAAC,CAAAA,CACA,OAAA,CAAAC,EAAU,EAAC,CACX,WAAA,CAAAC,CACF,CAAA,CAAItD,CAAAA,CAEAuD,CAAAA,CAAU,CAAA,CACVC,CAAAA,CAAWN,CAAAA,CACTO,CAAAA,CAAaR,CAAAA,CAAU,CAAA,CAAIA,CAAAA,CAAU,EACvCvB,CAAAA,CAEJ,KAAO6B,CAAAA,EAAWE,CAAAA,EAAY,CAG5B,GAAIF,CAAAA,CAAU,CAAA,EAAK7B,CAAAA,CAAS,CAC1B,IAAMgC,CAAAA,CAAMhC,CAAAA,CAAO,MAAA,CACbiC,EAAUD,CAAAA,CAAI,OAAA,CAEhBC,CAAAA,GACF,MAAMlL,CAAAA,CAAkBkL,CAAAA,CAASjC,CAAAA,CAAQ6B,CAAO,CAAA,CAI5CG,CAAAA,CAAI,UAAA,GACNA,CAAAA,CAAI,QAAA,CAAWA,CAAAA,CAAI,SACnBA,CAAAA,CAAI,QAAA,CAAW3D,CAAAA,CAAiB2D,CAAAA,CAAK,KAAK,CAAA,CAAA,EAGhD,CAKAhC,CAAAA,CAAS,MAAMsB,CAAAA,CAAUO,CAAAA,CAAU,CAAA,CAAGA,CAAO,CAAA,CAC7C,IAAMvI,CAAAA,CAAQ0G,CAAAA,CAAO,KAAA,CAGrB,GAAI,CAAC1G,CAAAA,CAAO,CACV,GAAIsI,CAAAA,EAAeC,CAAAA,CAAUE,CAAAA,EACD,MAAMH,CAAAA,CAAY5B,CAAAA,CAAQ6B,CAAO,CAAA,CAEpC,CACrB,MAAMxL,CAAAA,CAAgByL,CAAQ,CAAA,CAC9BA,CAAAA,EAAYL,CAAAA,EAAW,CAAA,CACvBK,CAAAA,CAAW,IAAA,CAAK,GAAA,CAAIA,CAAAA,CAAUJ,CAAAA,EAAYI,CAAQ,CAAA,CAClDD,CAAAA,EAAAA,CACA,QACF,CAGF,KACF,CAWA,GAR2B,MAAMK,EAAAA,CAC/BlC,CAAAA,CACA6B,CAAAA,CACAE,CAAAA,CACAH,CAAAA,CACAD,CACF,CAAA,CAGE,MAKF,GAAIrI,CAAAA,CAAM,MAAA,GAAW,GAAA,EAAOA,CAAAA,CAAM,MAAA,GAAW,GAAA,CAAK,CAEhD,IAAM6I,CAAAA,CAAepB,EAAAA,CAAgBf,CAAM,CAAA,CAGvCmC,CAAAA,GAAiB,OACnBL,CAAAA,CAAWK,CAAAA,EAEf,CAEA,MAAM9L,CAAAA,CAAgByL,CAAQ,CAAA,CAC9BA,CAAAA,EAAYL,CAAAA,EAAW,CAAA,CACvBK,CAAAA,CAAW,IAAA,CAAK,GAAA,CAAIA,CAAAA,CAAUJ,GAAYI,CAAQ,CAAA,CAClDD,CAAAA,GACF,CAEA,OAAO7B,CACT,CAqBA,eAAsBkC,EAAAA,CAMpBlC,CAAAA,CACA6B,CAAAA,CACAE,CAAAA,CACAH,CAAAA,CAMAD,CAAAA,CAAoB,EAAC,CACH,CA1OpB,IAAA/E,CAAAA,CAAAwF,CAAAA,CA8OE,GAAIP,CAAAA,GAAYE,CAAAA,CACd,OAAO,KAAA,CAGT,IAAIM,CAAAA,CAAiC,IAAA,CAGrC,OAAIT,IAEFS,CAAAA,CADe,MAAMT,CAAAA,CAAY5B,CAAAA,CAAQ6B,CAAO,CAAA,CAI5CQ,CAAAA,GAAmB,IAAA,CAAA,CACd,CAACA,CAAAA,CAIL,CAAA,CAAEV,CAAAA,EAAW,EAAC,EAAG,UAASS,CAAAA,CAAAA,CAAAxF,CAAAA,CAAAoD,CAAAA,CAAO,KAAA,GAAP,IAAA,CAAA,MAAA,CAAApD,CAAAA,CAAc,MAAA,GAAd,IAAA,CAAAwF,CAAAA,CAAwB,CAAC,CAC5D,CCjPA,eAAsBE,EAAAA,CAMpBhB,EAMAiB,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CAAc,CAAA,CACdC,CAAAA,CAAe,CAAA,CAC6D,CAC5E,GAAI,CAACH,CAAAA,CACH,OAAOjB,CAAAA,EAAU,CAGnB,IAAIqB,EAAiB,CAAA,CACjB3C,CAAAA,CAEJ,KAAA,CAAOyC,CAAAA,GAAgB,CAAA,EAAKE,CAAAA,CAAiBF,CAAAA,IACvCC,CAAAA,CAAe,CAAA,EACjB,MAAMrM,CAAAA,CAAgBqM,CAAY,CAAA,CAGpC1C,CAAAA,CAAS,MAAMsB,CAAAA,EAAU,CAEzBqB,CAAAA,EAAAA,CAGG,EAAAF,CAAAA,CAAc,CAAA,EAAKE,CAAAA,EAAkBF,CAAAA,EACtC,CAACF,CAAAA,EACAC,CAAAA,EAAqBA,CAAAA,CAAkBxC,CAAAA,CAAQ2C,CAAc,CAAA,CAAA,CAAA,EAKhE,MAAMtM,CAAAA,CAAgBkM,CAAe,CAAA,CAGvC,OAAOvC,CACT,CC7CA,eAAsB4C,EAAAA,CAMpBxI,CAAAA,CACAkH,CAAAA,CAKA3E,CAAAA,CAM4E,CAC5E,IAAMqD,CAAAA,CAAS,MAAMsB,CAAAA,CAAUlH,CAAmB,CAAA,CAC5Cd,CAAAA,CAAQ0G,CAAAA,CAAO,KAAA,CAErB,GAAI,CAAC1G,CAAAA,CAEH,OAAAyG,EAAAA,CAAoBC,CAAAA,CAAQrD,CAAa,CAAA,CAElCqD,EAKLrD,CAAAA,CAAc,OAAA,EAChB,MAAM5F,CAAAA,CAAkB4F,CAAAA,CAAc,OAAA,CAASrD,CAAK,CAAA,CAKtD,IAAMuJ,CAAAA,CAAcvJ,CAAAA,CAAM,WAAA,CAY1B,GAVI,CAACuJ,GAAelG,CAAAA,CAAc,MAAA,EAChCmG,EAAAA,CAAOnG,CAAAA,CAAe,aAAA,CAAerD,CAAsB,CAAA,CAI7DyG,EAAAA,CAAoBC,CAAAA,CAAQrD,CAAAA,CAAe,IAAI,CAAA,CAGrB,CAACkG,CAAAA,EAAelG,EAAc,eAAA,CAEjC,CACrB,IAAMoG,CAAAA,CAAWpG,CAAAA,CAAc,QAAA,CAE/B,GAAIoG,CAAAA,GAAa/O,EAAAA,CACf,OAAO,OAAA,CAAQ,MAAA,CAAOsF,CAAK,CAAA,CAIzByJ,IAAa,QAAA,EACf,MAAM,IAAI,OAAA,CAAQ,IAAM,IAAI,EAEhC,CAEA,OAAO/C,CACT,CAEO,SAASgD,EAAAA,CAOd1J,CAAAA,CACAhC,EAMAqF,CAAAA,CAMM,CACNrD,CAAAA,CAAM,MAAA,CAASA,CAAAA,CAAM,MAAA,GAAUhC,CAAAA,EAAA,IAAA,CAAA,MAAA,CAAAA,CAAAA,CAAU,MAAA,CAAA,EAAU,CAAA,CACnDgC,CAAAA,CAAM,UAAA,CAAaA,CAAAA,CAAM,UAAA,GAAchC,CAAAA,EAAA,IAAA,CAAA,MAAA,CAAAA,CAAAA,CAAU,UAAA,CAAA,EAAc,EAAA,CAC/DgC,CAAAA,CAAM,MAAA,CAASA,CAAAA,CAAM,OAAA,CAAUqD,CAAAA,CAC/BrD,CAAAA,CAAM,QAAA,CAAWhC,CAAAA,CACjBgC,CAAAA,CAAM,WAAA,CAAcA,EAAM,IAAA,GAAS1F,GACrC,CAQA,SAASkP,EAAAA,CACPvG,CAAAA,CAAAA,GACGtF,CAAAA,CACG,CACN,IAAM6L,CAAAA,CAASvG,CAAAA,CAAU,MAAA,CAErBuG,CAAAA,EAAUA,CAAAA,CAAO,MACnBA,CAAAA,CAAO,IAAA,CAAK,GAAG7L,CAAI,EAEvB,CC/FA,IAAMgM,EAAAA,CAAmB,CACvB,UAAA,CAAY,IACd,CAAA,CAqBA,eAAsBC,EAAAA,CAMpB/N,EACAoH,CAAAA,CAKW,IAAA,CACiE,CAC5E,IAAM4G,CAAAA,CAAgB7G,EAAAA,CAKpBnH,CAAAA,CAAKoH,CAAS,CAAA,CAEV,CACJ,OAAA,CAAA3D,CAAAA,CACA,WAAA,CAAAwK,CAAAA,CACA,SAAA1D,CAAAA,CACA,UAAA,CAAA7G,CAAAA,CACA,SAAA,CAAA8G,CAAAA,CACA,SAAA,CAAAxE,CAAAA,CACA,cAAA,CAAAE,CAAAA,CACA,kBAAA,CAAAC,CAAAA,CACA,eAAA,CAAAiH,CAAAA,CAAkB,CACpB,EAAIY,CAAAA,CACEE,CAAAA,CAAiB1D,CAAAA,GAAc,MAAA,EAAaxE,CAAAA,GAAc,MAAA,CAE1DmI,CAAAA,CAAgB,CAAC,EACrB5D,CAAAA,EACA9G,CAAAA,EACAC,CAAAA,EACAwK,CAAAA,EACAD,CAAAA,EACA/H,GACAC,CAAAA,CAAAA,CAGEiI,CAAAA,CAA2B,IAAA,CAQ/B,GALID,CAAAA,GACFC,CAAAA,CAAYlF,CAAAA,CAAiB8E,CAAa,CAAA,CAAA,CAIxCI,CAAAA,EAAaF,CAAAA,CAAgB,CAC/B,IAAMG,CAAAA,CAAS/D,GAKb8D,CAAAA,CAAW5D,CAAAA,CAAWwD,CAAa,CAAA,CAErC,GAAIK,CAAAA,CACF,OAAOA,CAEX,CAGA,GAAID,CAAAA,EAAa1K,CAAAA,CAAY,CAC3B,IAAM4K,CAAAA,CAAW/J,EAAAA,CAEf6J,CAAAA,CAAW1K,CAAU,CAAA,CAEvB,GAAI4K,CAAAA,CACF,OAAOA,CAEX,CAEA,IAAMC,CAAAA,CAAcP,CAAAA,CAAc,KAAA,EAAS,EAAC,CACtC,CAAE,OAAA,CAAA5B,EAAAA,CAAU,CAAA,CAAG,YAAA,CAAAoC,EAAa,CAAA,CAAID,CAAAA,CAGhCE,EAAAA,CAAgB,MAAOxJ,CAAAA,CAAsB,KAAA,CAAOyH,EAAAA,CAAU,CAAA,GAAM,CAInEA,KACC0B,CAAAA,EAAa,CAACnJ,CAAAA,GACZe,CAAAA,CACoBsE,EAAAA,CACpB8D,CAAAA,CACA5D,CAAAA,CACAwD,CACF,CAAA,GAKErE,EAAAA,CAASyE,CAAAA,CAAWN,EAAAA,CAAkBtD,CAAAA,CAAWxE,CAAS,EAC1DU,CAAAA,CAAkB0H,CAAAA,CAAWN,EAAgB,CAAA,CAAA,CAG/CpH,CAAAA,CAAkB0H,CAAAA,CAAWN,EAAgB,CAAA,CAAA,CAKjDE,CAAAA,CAAc,QAAA,CAAWI,CAAAA,CAAAA,CAG3B,IAAMpO,CAAAA,CAAMgO,CAAAA,CAAc,IAGpB/J,EAAAA,CAAaT,EAAAA,CACjB4K,CAAAA,CACApO,CAAAA,CACAyD,CAAAA,CACAC,CAAAA,EAAc,CAAA,CACd,CAAC,CAACuK,CAAAA,CAEF,CAAC,EAAExK,CAAAA,GAAY,CAACiJ,IAAW8B,EAAAA,CAAAA,CAC7B,CAAA,CAIMhH,CAAAA,CAAgBwG,CAAAA,CAEtBxG,CAAAA,CAAc,MAAA,CAASvD,EAAAA,CAAW,MAAA,CAElC,IAAI4G,CAAAA,CAMA1I,CAAAA,CAKO,IAAA,CAEX,GAAI,CACE6L,EAAc,SAAA,EAChB,MAAMpM,CAAAA,CAAkBoM,CAAAA,CAAc,SAAA,CAAWxG,CAAa,CAAA,CAIhE,IAAMjB,CAAAA,CAAKyH,CAAAA,CAAc,OAAA,CAkBzB,GAhBA7L,CAAAA,CAAYoE,CAAAA,CACR,MAAMA,CAAAA,CACJvG,CAAAA,CACAwH,CACF,CAAA,CACA,MAAM,KAAA,CACJxH,CAAAA,CACAwH,CACF,CAAA,CAQAvI,CAAAA,CAASkD,CAAQ,CAAA,GAEf,OAAO,QAAA,GAAa3D,CAAAA,EAAY2D,CAAAA,YAAoB,QAAA,CACtDA,CAAAA,CAAS,IAAA,CAAO,MAAM8I,EAAAA,CAAkB9I,CAAQ,CAAA,CACvCoE,CAAAA,GAEH,MAAA,GAAUpE,CAAAA,EAAY,MAAA,GAAUA,CAAAA,GAEpCA,CAAAA,CAAW,CAAE,KAAMA,CAAS,CAAA,CAAA,CAAA,CAYhCA,CAAAA,CAAS,MAAA,CAASqF,CAAAA,CAIdrF,CAAAA,CAAS,EAAA,GAAO,KAAA,CAAA,EAAa,CAACA,CAAAA,CAAS,EAAA,CAAA,CACzC,MAAM,IAAIE,EAAAA,CACR,GAAGmF,CAAAA,CAAc,MAAM,CAAA,IAAA,EAAOxH,CAAG,CAAA,iBAAA,EAAoBmC,CAAAA,CAAS,MAAA,EAAU,IAAI,CAAA,CAAA,CAC5EqF,CAAAA,CACArF,CACF,CAAA,CAIJ0I,CAAAA,CAASS,EAAAA,CAKPnJ,EAAUqF,CAAa,CAAA,CAEzB,IAAMkH,CAAAA,CAAaV,CAAAA,CAAc,UAAA,CAE7BU,CAAAA,EACF,MAAM9M,CAAAA,CAAkB8M,CAAAA,CAAY7D,CAAM,EAE9C,CAAA,MAASQ,CAAAA,CAAQ,CACf,IAAMlH,CAAAA,CAAQkH,CAAAA,CAQdwC,EAAAA,CACE1J,CAAAA,CACAhC,CAAAA,CACAqF,CACF,CAAA,CAGAqD,CAAAA,CAASS,EAAAA,CAKPnJ,CAAAA,CAAUqF,CAAAA,CAAerD,CAAK,EAClC,CAEA,OAAO0G,CACT,CAAA,CAGM8D,EAAAA,CACJvC,EAAAA,CAAU,CAAA,CAAI,IAAMF,EAAAA,CAAUuC,EAAAA,CAAeF,CAAW,CAAA,CAAIE,EAAAA,CAExDG,CAAAA,CAA2B,CAAC3J,EAAsB,KAAA,GACtDwI,EAAAA,CACExI,CAAAA,CACA0J,EAAAA,CACAX,CACF,CAAA,CAGIa,EAAAA,CAAmBzB,CAAAA,CACrBD,EAAAA,CACEyB,CAAAA,CACAxB,CAAAA,CACAY,CAAAA,CAAc,iBAAA,CACdA,CAAAA,CAAc,mBACdA,CAAAA,CAAc,YAChB,CAAA,CACAY,CAAAA,EAAyB,CAG7B,OAAIR,CAAAA,GACE1K,CAAAA,EACFW,EAAAA,CAAmB+J,CAAAA,CAAWS,EAAgB,CAAA,CAGhDhJ,EAAAA,CACEuI,CAAAA,CACAQ,CAAAA,CACA,MAAA,CACA5I,CAAAA,CACA4I,CAAAA,CACA,CAAC,CAAC1I,CAAAA,CACF,CAAC,CAACC,CACJ,CAAA,CAAA,CAGK0I,EACT,CC3RA,SAASC,EAAAA,CAGP3F,CAAAA,CAAyC,CACzC,IAAM4F,CAAAA,CAAY5F,CAAAA,CAAO,SAAA,CAQzB,SAAS6F,CAAAA,CAAqBC,CAAAA,CAAqC,CACjE,OAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,IAAA,EAAOA,CAAY,CAAA,gBAAA,CAAkB,CAAA,CAE5C,QAAQ,OAAA,CAAQ,IAAI,CAC7B,CAEA,IAAMC,CAAAA,CAAsD,CAC1D,MAAA,CAAA/F,CAAAA,CACA,SAAA,CAAA4F,CAAAA,CASA,MAAM,OAAA,CAAQE,CAAAA,CAAczH,EAAgB,EAAC,CAAG,CAE9C,IAAM2H,CAAAA,CAAiBJ,CAAAA,CAAUE,CAAY,CAAA,CACvCG,CAAAA,CACJD,CAAAA,EACC,CAAE,GAAA,CAAK,MAAA,CAAOF,CAAY,CAAE,CAAA,CACzBjP,CAAAA,CAAMoP,CAAAA,CAAgB,GAAA,CAG5B,GAAIpP,CAAAA,CAAI,UAAA,CAAW,IAAI,CAAA,CACrB,MAAM,IAAI,KAAA,CAAM,yCAAyC,CAAA,CAI3D,IAAMoI,EAAetH,EAAAA,CAAcd,CAAG,CAAA,CAAA,CAElCmP,CAAAA,EAAA,IAAA,CAAA,MAAA,CAAAA,CAAAA,CAAgB,GAAA,IAAQnP,CAAAA,CACtBuH,CAAAA,CAAa6H,CAAAA,CAAiB5H,CAAa,CAAA,CAC3CA,CAAAA,CACFD,CAAAA,CAAaA,EAAa4B,CAAAA,CAAQiG,CAAe,CAAA,CAAG5H,CAAa,CAAA,CAIrE,OAAOuG,EAAAA,CAAO/N,CAAAA,CAAKoI,CAAY,CACjC,CACF,CAAA,CAOA,OAAO,IAAI,MACT8G,CAAAA,CACA,CACE,GAAA,CAAIG,CAAAA,CAASC,CAAAA,CAAc,CACzB,OAAIA,CAAAA,IAAQJ,CAAAA,CACHA,CAAAA,CAAWI,CAA0C,CAAA,CAI1DP,CAAAA,CAAUO,CAAI,CAAA,CACTJ,CAAAA,CAAW,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAMI,CAAI,CAAA,CAGpCN,CAAAA,CAAqB,IAAA,CAAK,IAAA,CAAMM,CAAI,CAC7C,CACF,CACF,CACF","file":"index.global.js","sourcesContent":["export const APPLICATION_CONTENT_TYPE = 'application/';\n\nexport const APPLICATION_JSON = APPLICATION_CONTENT_TYPE + 'json';\nexport const CHARSET_UTF_8 = 'charset=utf-8';\nexport const CONTENT_TYPE = 'Content-Type';\n\nexport const UNDEFINED = 'undefined';\nexport const OBJECT = 'object';\nexport const STRING = 'string';\nexport const FUNCTION = 'function';\n\nexport const ABORT_ERROR = 'AbortError';\nexport const TIMEOUT_ERROR = 'TimeoutError';\n\nexport const GET = 'GET';\nexport const HEAD = 'HEAD';\n\nexport const REJECT = 'reject';\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { FUNCTION, OBJECT, STRING, UNDEFINED } from './constants';\nimport type {\n DefaultUrlParams,\n HeadersObject,\n QueryParams,\n UrlPathParams,\n} from './types';\n\n// Prevent stack overflow with recursion depth limit\nconst MAX_DEPTH = 10;\n\nexport function isSearchParams(data: unknown): boolean {\n return data instanceof URLSearchParams;\n}\n\n/**\n * Determines if a value is a non-null object.\n *\n * @param {any} value - The value to check.\n * @returns {boolean} - True if the value is a non-null object.\n */\nexport function isObject(value: any): value is Record {\n return value !== null && typeof value === OBJECT;\n}\n\n/**\n * Shallowly serializes an object by converting its key-value pairs into a string representation.\n * This function does not recursively serialize nested objects.\n *\n * @param obj - The object to serialize.\n * @returns A string representation of the object's top-level properties.\n */\nexport function shallowSerialize(obj: Record): string {\n let result = '';\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n result += key + ':' + obj[key];\n }\n }\n\n return result;\n}\n\n/**\n * Removes properties that could lead to prototype pollution from an object.\n *\n * This function creates a shallow copy of the input object with dangerous\n * properties like '__proto__', 'constructor', and 'prototype' removed.\n *\n * @param obj - The object to sanitize\n * @returns A new object without dangerous properties\n */\nexport function sanitizeObject>(obj: T): T {\n const safeObj = { ...obj };\n\n delete safeObj.__proto__;\n delete (safeObj as any).constructor;\n delete safeObj.prototype;\n\n return safeObj;\n}\n\n/**\n * Sorts the keys of an object and returns a new object with sorted keys.\n *\n * This function is optimized for performance by minimizing the number of object operations\n * and using a single pass to create the sorted object.\n *\n * @param {Object} obj - The object to be sorted by keys.\n * @returns {Object} - A new object with keys sorted in ascending order.\n */\nexport function sortObject(obj: Record): object {\n const keys = Object.keys(obj);\n\n keys.sort();\n\n const sortedObj = {} as Record;\n\n for (let i = 0, len = keys.length; i < len; i++) {\n const key = keys[i];\n\n sortedObj[key] = obj[key];\n }\n\n return sortedObj;\n}\n\n/**\n * Appends a query string to a URL, ensuring proper handling of existing query parameters.\n *\n * @param baseUrl - The base URL to which the query string will be appended.\n * @param queryString - The encoded query string to append.\n * @returns The URL with the appended query string, or the original URL if no query string is provided.\n */\nfunction appendQueryStringToUrl(baseUrl: string, queryString: string): string {\n if (!queryString) {\n return baseUrl;\n }\n\n return baseUrl.includes('?')\n ? `${baseUrl}&${queryString}`\n : `${baseUrl}?${queryString}`;\n}\n\n/**\n * Appends query parameters to a given URL.\n *\n * @param {string} url - The base URL to which query parameters will be appended.\n * @param {QueryParams} params - An object containing the query parameters to append.\n * @returns {string} - The URL with the appended query parameters.\n */\nexport function appendQueryParams(url: string, params: QueryParams): string {\n if (!params) {\n return url;\n }\n\n // Check if `params` is an instance of URLSearchParams and bail early if it is\n if (isSearchParams(params)) {\n const encodedQueryString = params.toString();\n\n return appendQueryStringToUrl(url, encodedQueryString);\n }\n\n // This is exact copy of what JQ used to do. It works much better than URLSearchParams\n const s: string[] = [];\n const encode = encodeURIComponent;\n const add = (k: string, v: any) => {\n v = typeof v === FUNCTION ? v() : v;\n v = v === null ? '' : v === undefined ? '' : v;\n s[s.length] = encode(k) + '=' + encode(v);\n };\n\n const buildParams = (prefix: string, obj: any, depth = 0) => {\n // Stop recursion if maximum depth is reached\n if (depth >= MAX_DEPTH) {\n return s;\n }\n\n let i: number, len: number, key: string;\n\n if (prefix) {\n if (Array.isArray(obj)) {\n for (i = 0, len = obj.length; i < len; i++) {\n buildParams(\n prefix + '[' + (typeof obj[i] === OBJECT && obj[i] ? i : '') + ']',\n obj[i],\n depth + 1,\n );\n }\n } else if (isObject(obj)) {\n for (key in obj) {\n buildParams(prefix + '[' + key + ']', obj[key], depth + 1);\n }\n } else {\n add(prefix, obj);\n }\n } else if (Array.isArray(obj)) {\n for (i = 0, len = obj.length; i < len; i++) {\n add(obj[i].name, obj[i].value);\n }\n } else {\n for (key in obj) {\n buildParams(key, obj[key], depth + 1);\n }\n }\n return s;\n };\n\n const queryStringParts = buildParams('', params).join('&');\n\n // Encode special characters as per RFC 3986, https://datatracker.ietf.org/doc/html/rfc3986\n // This is for compatibility with server frameworks that expect the literal notation\n const encodedQueryString = queryStringParts.replace(/%5B%5D/g, '[]'); // Keep '[]' for arrays\n\n return appendQueryStringToUrl(url, encodedQueryString);\n}\n\n/**\n * Replaces dynamic URI parameters in a URL string with values from the provided `urlPathParams` object.\n * Parameters in the URL are denoted by `:`, where `` is a key in `urlPathParams`.\n *\n * @param {string} url - The URL string containing placeholders in the format `:`.\n * @param {Object} urlPathParams - An object containing the parameter values to replace placeholders.\n * @param {string} urlPathParams.paramName - The value to replace the placeholder `:` in the URL.\n * @returns {string} - The URL string with placeholders replaced by corresponding values from `urlPathParams`.\n */\nexport function replaceUrlPathParams(\n url: string,\n urlPathParams: UrlPathParams,\n): string {\n if (!urlPathParams || url.indexOf(':') === -1) {\n return url;\n }\n\n // Use a single RegExp and avoid unnecessary casts and function calls\n // Precompute keys for faster lookup\n const params = urlPathParams as DefaultUrlParams;\n\n // Use a replacer function that avoids extra work\n return url.replace(/:([a-zA-Z0-9_]+)/g, (match, key) => {\n // Use hasOwnProperty for strict key existence check\n if (Object.prototype.hasOwnProperty.call(params, key)) {\n const value = params[key];\n\n // Only replace if value is not undefined or null\n if (value !== undefined && value !== null) {\n return encodeURIComponent(String(value));\n }\n }\n\n return match;\n });\n}\n\n/**\n * Determines whether the provided URL is absolute.\n *\n * An absolute URL contains a scheme (e.g., \"http://\", \"https://\").\n *\n * @param url - The URL string to check.\n * @returns `true` if the URL is absolute, otherwise `false`.\n */\nexport function isAbsoluteUrl(url: string): boolean {\n return url.includes('://');\n}\n\nexport const timeNow = () => Date.now();\n\nexport const noop = () => {};\n\n/**\n * Checks if a value is JSON serializable.\n *\n * JSON serializable values include:\n * - Primitive types: string, number, boolean, null\n * - Arrays\n * - Plain objects (i.e., objects without special methods)\n * - Values with a `toJSON` method\n *\n * @param {any} value - The value to check for JSON serializability.\n * @returns {boolean} - Returns `true` if the value is JSON serializable, otherwise `false`.\n */\nexport function isJSONSerializable(value: any): boolean {\n const t = typeof value;\n\n if (value === undefined || value === null) {\n return false;\n }\n\n if (t === STRING || t === 'number' || t === 'boolean') {\n return true;\n }\n\n if (Array.isArray(value)) {\n return true;\n }\n\n if (\n typeof globalThis !== UNDEFINED &&\n typeof globalThis.Buffer !== UNDEFINED &&\n globalThis.Buffer.isBuffer(value)\n ) {\n return false;\n }\n\n if (value instanceof Date || isSearchParams(value)) {\n return false;\n }\n\n if (isObject(value)) {\n const proto = Object.getPrototypeOf(value);\n\n // Check if the prototype is `Object.prototype` (plain object)\n if (proto === Object.prototype) {\n return true;\n }\n\n // Check if the object has a toJSON method\n if (typeof value.toJSON === FUNCTION) {\n return true;\n }\n }\n\n return false;\n}\n\nexport async function delayInvocation(ms: number): Promise {\n return new Promise((resolve) =>\n setTimeout(() => {\n return resolve(true);\n }, ms),\n );\n}\n\n/**\n * Recursively flattens the data object if it meets specific criteria.\n *\n * The method checks if the provided `data` is an object with exactly one property named `data`.\n * If so, it recursively flattens the `data` property. Otherwise, it returns the `data` as-is.\n *\n * @param {any} data - The data to be flattened. Can be of any type, including objects, arrays, or primitives.\n * @returns {any} - The flattened data if the criteria are met; otherwise, the original `data`.\n */\nexport function flattenData(data: any, depth = 0): any {\n if (depth >= MAX_DEPTH) {\n return data;\n }\n\n if (data && isObject(data) && typeof data.data !== UNDEFINED) {\n return flattenData(data.data, depth + 1);\n }\n\n return data;\n}\n\n/**\n * Processes headers and returns them as a normalized object.\n *\n * Handles both `Headers` instances and plain objects. Normalizes header keys to lowercase\n * as per RFC 2616 section 4.2.\n *\n * @param headers - The headers to process. Can be an instance of `Headers`, a plain object,\n * or `null`. If `null`, an empty object is returned.\n * @returns {HeadersObject} - A normalized headers object with lowercase keys.\n */\nexport function processHeaders(\n headers?: (HeadersObject & HeadersInit) | null | Headers,\n): HeadersObject {\n if (!headers) {\n return {};\n }\n\n const headersObject: HeadersObject = {};\n\n // Handle Headers object with entries() method\n if (headers instanceof Headers) {\n headers.forEach((value, key) => {\n headersObject[key] = value;\n });\n } else if (isObject(headers)) {\n // Handle plain object\n for (const [key, value] of Object.entries(headers)) {\n // Normalize keys to lowercase as per RFC 2616 4.2\n // https://datatracker.ietf.org/doc/html/rfc2616#section-4.2\n headersObject[key.toLowerCase()] = value;\n }\n }\n\n return headersObject;\n}\n\n/**\n * Determines if the current environment is a browser.\n *\n * @returns {boolean} - True if running in a browser environment, false otherwise.\n */\nexport function isBrowser(): boolean {\n // For node and and some mobile frameworks like React Native, `add/removeEventListener` doesn't exist on window!\n return (\n typeof window !== UNDEFINED && typeof window.addEventListener === FUNCTION\n );\n}\n\n/**\n * Detects if the user is on a slow network connection\n * @returns {boolean} True if connection is slow, false otherwise or if detection unavailable\n */\nexport const isSlowConnection = (): boolean => {\n // Only works in browser environments\n if (!isBrowser()) {\n return false;\n }\n\n const conn = navigator && (navigator as any).connection;\n\n return conn && ['slow-2g', '2g', '3g'].includes(conn.effectiveType);\n};\n","import { FUNCTION } from './constants';\nimport type { InterceptorFunction } from './types/interceptor-manager';\nimport { isObject } from './utils';\n\n/**\n * Applies interceptors to the object. Interceptors can be a single function or an array of functions.\n *\n * @template T - Type of the object.\n * @template Args - Type of additional arguments.\n * @template I - Type of interceptors.\n *\n * @param {InterceptorFunction | InterceptorFunction[]} [interceptors] - Interceptor function(s).\n * @param {T} data - The data object to process.\n * @param {...Args} args - Additional arguments to pass to interceptors.\n *\n * @returns {Promise} - Nothing as the function is non-idempotent.\n */\nexport async function applyInterceptors<\n T extends object,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Args extends any[] = any[],\n I = InterceptorFunction | InterceptorFunction[],\n>(interceptors: I | undefined, data: T, ...args: Args): Promise {\n if (!interceptors) {\n return;\n }\n\n if (typeof interceptors === FUNCTION) {\n const value = await (interceptors as InterceptorFunction)(\n data,\n ...args,\n );\n\n if (value && isObject(data) && isObject(value)) {\n Object.assign(data, value);\n }\n } else if (Array.isArray(interceptors)) {\n for (const interceptor of interceptors) {\n const value = await interceptor(data, ...args);\n\n if (value && isObject(data) && isObject(value)) {\n Object.assign(data, value);\n }\n }\n }\n}\n","import type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '../types';\n\n/**\n * This is a base error class\n */\nexport class FetchError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n> extends Error {\n status: number;\n statusText: string;\n config: RequestConfig;\n isCancelled: boolean;\n\n constructor(\n message: string,\n public request: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n public response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n ) {\n super(message);\n\n this.name = 'FetchError';\n this.status = response ? response.status : 0;\n this.statusText = response ? response.statusText : '';\n this.config = request;\n this.isCancelled = false;\n }\n}\n","import { FetchError } from './fetch-error';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '../types';\n\nexport class ResponseError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n> extends FetchError {\n constructor(\n message: string,\n request: RequestConfig,\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n ) {\n super(message, request, response);\n\n this.name = 'ResponseError';\n }\n}\n","/**\n * @module timeout-wheel\n * @description\n * Ultra-minimal timing wheel implementation optimized for max performance & many requests.\n * For most of the cases it's 4-100x faster than setTimeout and setInterval alone.\n * Provides efficient scheduling and cancellation of timeouts using a circular array.\n *\n * Position 0 → 1 → 2 → ... → 599 → 0 → 1 → 2 ...\n * Time: 0s 1s 2s 599s 600s 601s 602s\n *\n * The timing wheel consists of 600 slots (one per second for 10 min).\n * Each slot contains a list of timeout items, each associated with a unique key and callback.\n * Timeouts are scheduled by placing them in the appropriate slot based on the delay in seconds.\n * The wheel advances every second, executing and removing callbacks as their timeouts expire.\n * Defaults to setTimeout if the delay exceeds 10 minutes or is not divisible by 1000.\n *\n * @remarks\n * - Designed for minimal footprint and simplicity.\n * - Only supports second-level granularity (minimum timeout: 1 second).\n * - Automatically stops the internal timer when no timeouts remain.\n */\n\nimport { noop } from './utils';\n\ntype TimeoutCallback = () => unknown | Promise;\ntype TimeoutItem = [string, TimeoutCallback]; // [key, callback]\n\nconst WHEEL_SIZE = 600; // 600 slots for 10 min (1 slot per second)\nconst SECOND = 1000; // 1 second in milliseconds\nconst MAX_WHEEL_MS = WHEEL_SIZE * SECOND;\nconst wheel: TimeoutItem[][] = Array(WHEEL_SIZE)\n .fill(0)\n .map(() => []);\n\nconst keyMap = new Map();\nlet position = 0;\nlet timer: NodeJS.Timeout | null = null;\n\nconst handleCallback = ([key, callback]: TimeoutItem): void => {\n keyMap.delete(key);\n\n try {\n const result = callback();\n if (result && result instanceof Promise) {\n // Silently ignore async errors to prevent wheel from stopping\n result.catch(noop);\n }\n } catch {\n // Ignore callback errors to prevent wheel from stopping\n }\n};\n\nexport const addTimeout = (\n key: string,\n cb: TimeoutCallback,\n ms: number,\n): void => {\n removeTimeout(key);\n\n // Fallback to setTimeout if wheel size is exceeded or ms is not divisible by SECOND\n if (ms > MAX_WHEEL_MS || ms % SECOND !== 0) {\n keyMap.set(key, [setTimeout(handleCallback.bind(null, [key, cb]), ms)]); // Store timeout ID instead of slot\n\n return;\n }\n\n // No need for Math.ceil here since ms is guaranteed by modulo above\n const seconds = ms / SECOND;\n const slot = (position + seconds) % WHEEL_SIZE;\n\n wheel[slot].push([key, cb]);\n keyMap.set(key, slot);\n\n if (!timer) {\n timer = setInterval(() => {\n position = (position + 1) % WHEEL_SIZE;\n wheel[position].forEach(handleCallback);\n wheel[position] = [];\n\n if (!keyMap.size && timer) {\n clearInterval(timer);\n timer = null;\n }\n }, SECOND);\n }\n};\n\nexport const removeTimeout = (key: string): void => {\n const slotOrTimeout = keyMap.get(key);\n\n if (slotOrTimeout !== undefined) {\n // It's a Timeout object from setTimeout\n if (Array.isArray(slotOrTimeout)) {\n clearTimeout(slotOrTimeout[0]);\n } else {\n wheel[slotOrTimeout].splice(\n wheel[slotOrTimeout].findIndex(([k]) => k === key),\n 1,\n );\n }\n\n keyMap.delete(key);\n\n if (!keyMap.size && timer) {\n clearInterval(timer);\n timer = null;\n }\n }\n};\n\nexport const clearAllTimeouts = () => {\n // Clear native setTimeout timeouts first!\n keyMap.forEach((value) => {\n if (Array.isArray(value)) {\n clearTimeout(value[0]);\n }\n });\n\n if (timer) {\n clearInterval(timer);\n timer = null;\n }\n\n keyMap.clear();\n wheel.forEach((slot) => (slot.length = 0));\n position = 0;\n};\n","/**\n * @module inflight-manager\n *\n * Manages in-flight asynchronous requests using unique keys to enable deduplication and cancellation.\n *\n * Provides utilities for:\n * - Deduplication of requests within a configurable time window (`dedupeTime`)\n * - Timeout management and automatic request abortion\n * - AbortController lifecycle and cancellation logic\n * - Concurrency control and request state tracking\n * - In-flight promise deduplication to prevent duplicate network calls\n *\n * @remarks\n * - Requests with the same key within the deduplication interval share the same AbortController and in-flight promise.\n * - Supports cancellation of previous requests when a new one with the same key is issued, if `isCancellable` is enabled.\n * - Timeout logic ensures requests are aborted after a specified duration, if enabled.\n * - Internal queue state is managed via a Map, keyed by request identifier.\n * - Polled requests are also marked as \"in-flight\" to prevent duplicate requests.\n */\n\nimport { ABORT_ERROR, TIMEOUT_ERROR } from './constants';\nimport { addTimeout, removeTimeout } from './timeout-wheel';\nimport { timeNow } from './utils';\n\nexport type InFlightItem = [\n AbortController, // AbortController for the request\n boolean, // Whether timeout is enabled for the request\n number, // Timestamp when the request was marked in-flight\n boolean, // isCancellable - whether the request can be cancelled\n Promise | null, // Optional in-flight promise for deduplication\n];\n\nconst inFlight: Map = new Map();\n\n/**\n * Adds a request to the queue if it's not already being processed within the dedupeTime interval.\n *\n * @param {string | null} key - Unique key for the request (e.g. cache key).\n * @param {string} url - The request URL (for error messages/timeouts).\n * @param {number} timeout - Timeout in milliseconds for the request.\n * @param {number} dedupeTime - Deduplication time in milliseconds.\n * @param {boolean} isCancellable - If true, then the previous request with same configuration should be aborted.\n * @param {boolean} isTimeoutEnabled - Whether timeout is enabled.\n * @returns {AbortController} - A promise that resolves to an AbortController.\n */\nexport function markInFlight(\n key: string | null,\n url: string,\n timeout: number | undefined,\n dedupeTime: number,\n isCancellable: boolean,\n isTimeoutEnabled: boolean,\n): AbortController {\n if (!key) {\n return new AbortController();\n }\n\n const item = inFlight.get(key);\n let prevPromise: Promise | null = null;\n\n // Previous request is in-flight, check if we can reuse it\n if (item) {\n const prevController = item[0];\n const prevIsCancellable = item[3];\n\n // If the request is already in the queue and within the dedupeTime, reuse the existing controller\n if (\n !prevIsCancellable &&\n timeNow() - item[2] < dedupeTime &&\n !prevController.signal.aborted\n ) {\n return prevController;\n }\n\n // If the request is too old, remove it and proceed to add a new one\n // Abort previous request, if applicable, and continue as usual\n if (prevIsCancellable) {\n prevController.abort(\n new DOMException('Aborted due to new request', ABORT_ERROR),\n );\n }\n\n removeTimeout(key);\n prevPromise = item[4];\n }\n\n const controller = new AbortController();\n\n inFlight.set(key, [\n controller,\n isTimeoutEnabled,\n timeNow(),\n isCancellable,\n prevPromise,\n ]);\n\n if (isTimeoutEnabled) {\n addTimeout(\n key,\n () => {\n abortRequest(\n key,\n new DOMException(url + ' aborted due to timeout', TIMEOUT_ERROR),\n );\n },\n timeout as number,\n );\n }\n\n return controller;\n}\n\n/**\n * Removes a request from the queue and clears its timeout.\n *\n * @param key - Unique key for the request.\n * @param {boolean} error - Optional error to abort the request with. If null, the request is simply removed but no abort sent.\n * @returns {Promise} - A promise that resolves when the request is aborted and removed.\n */\nexport async function abortRequest(\n key: string | null,\n error: DOMException | null | string = null,\n): Promise {\n // If the key is not in the queue, there's nothing to remove\n if (key) {\n const item = inFlight.get(key);\n\n if (item) {\n // If the request is not yet aborted, abort it with the provided error\n if (error) {\n const controller = item[0];\n controller.abort(error);\n }\n\n removeInFlight(key);\n }\n }\n}\n\n/**\n * Removes a request from the in-flight queue without aborting or clearing timeout.\n *\n * @param key - Unique key for the request.\n */\nexport function removeInFlight(key: string | null): void {\n removeTimeout(key!);\n inFlight.delete(key!);\n}\n\n/**\n * Gets the AbortController for a request key.\n *\n * @param key - Unique key for the request.\n * @returns {AbortController | undefined} - The AbortController or undefined.\n */\nexport async function getController(\n key: string,\n): Promise {\n const item = inFlight.get(key);\n\n return item?.[0];\n}\n\n/**\n * Adds helpers for in-flight promise deduplication.\n *\n * @param key - Unique key for the request.\n * @param promise - The promise to store.\n */\nexport function setInFlightPromise(\n key: string,\n promise: Promise,\n): void {\n const item = inFlight.get(key);\n if (item) {\n // store the promise at index 4\n item[4] = promise;\n\n inFlight.set(key, item);\n }\n}\n\n/**\n * Retrieves the in-flight promise for a request key if it exists and is within the dedupeTime interval.\n *\n * @param key - Unique key for the request.\n * @param dedupeTime - Deduplication time in milliseconds.\n * @returns {Promise | null} - The in-flight promise or null.\n */\nexport function getInFlightPromise(\n key: string | null,\n dedupeTime: number,\n): Promise | null {\n if (!key) {\n return null;\n }\n\n const prevReq = inFlight.get(key);\n\n if (\n prevReq &&\n // If the request is in-flight and has a promise\n prevReq[4] &&\n // If the request is cancellable, we will not reuse it\n !prevReq[3] &&\n // If the request is within the dedupeTime\n timeNow() - prevReq[2] < dedupeTime &&\n // If one request is cancelled, ALL deduped requests get cancelled\n !prevReq[0].signal.aborted\n ) {\n return prevReq[4] as Promise;\n }\n\n return null;\n}\n","const PRIME_MULTIPLIER = 31;\n\n/**\n * Computes a hash value for a given string using the variant of djb2 hash function.\n * This hash function is non-cryptographic and designed for speed.\n * @author Daniel J. Bernstein (of djb2)\n *\n * @param str Input string to hash\n * @returns {string} Hash\n */\nexport function hash(str: string): string {\n let hash = 0;\n\n for (let i = 0, len = str.length; i < len; i++) {\n const char = str.charCodeAt(i);\n hash = (hash * PRIME_MULTIPLIER + char) | 0;\n }\n\n return String(hash);\n}\n","/**\n * @module revalidator-manager\n *\n * Provides utilities for managing cache revalidation functions, including:\n * - Registering and unregistering revalidators for specific cache keys.\n * - Triggering revalidation for a given key.\n * - Enabling or disabling automatic revalidation on window focus and if user comes back online for specific keys.\n * - Attaching and removing global focus and online event handlers to trigger revalidation.\n *\n * Revalidators are functions that can be registered to revalidate cache entries when needed.\n * They are typically used to refresh data in the cache when the window gains focus or when specific actions occur.\n * @performance O(1) lookup by key makes it blazing fast to register, unregister, and revalidate cache entries.\n * - Designed for high performance: minimizes unnecessary re-renders and leverages fast cache key generation.\n * - Integrates with a global cache and pub/sub system for efficient state updates across contexts.\n * - Handles automatic revalidation, deduplication, retries, and cache management out of the box.\n * @remarks\n * - Designed to be used in various environments (Deno, Node.js, Bun, Browser, etc.) to ensure cache consistency and freshness.\n */\nimport { addTimeout, removeTimeout } from './timeout-wheel';\nimport { FetchResponse } from './types';\nimport { isBrowser, noop, timeNow } from './utils';\n\nexport type RevalidatorFn = (\n isStaleRevalidation?: boolean,\n) => Promise;\n\ntype EventType = 'focus' | 'online';\n\ntype RevalidatorEntry = [\n RevalidatorFn, // main revalidator\n number, // lastUsed\n number, // ttl\n number?, // staleTime\n RevalidatorFn?, // bgRevalidator\n boolean?, // refetchOnFocus\n boolean?, // refetchOnReconnect\n];\n\nconst DEFAULT_TTL = 3 * 60 * 1000; // Default TTL of 3 minutes\nconst revalidators = new Map();\n\n/**\n * Stores global event handlers for cache revalidation events (e.g., focus, online).\n * This avoids attaching multiple event listeners by maintaining a single handler per event type.\n * Event handlers are registered as needed when revalidators are registered with the corresponding flags.\n * @remarks\n * - Improves performance by reducing the number of event listeners.\n * - Enables efficient O(1) lookup and management of event handlers for revalidation.\n */\nconst eventHandlers = new Map void>();\n\n/**\n * Triggers revalidation for all registered entries based on the given event type.\n * For example, if it's a 'focus' event, it will revalidate entries that have the `refetchOnFocus` flag set.\n * Updates the timestamp and invokes the revalidator function for each applicable entry.\n *\n * @param type - The type of event that caused the revalidation (e.g., 'focus' or 'online').\n * @param isStaleRevalidation - If `true`, uses background revalidator and doesn't mark as in-flight.\n */\nexport function revalidateAll(\n type: EventType,\n isStaleRevalidation: boolean = true,\n) {\n const flagIndex = type === 'focus' ? 5 : 6;\n const now = timeNow();\n\n revalidators.forEach((entry) => {\n if (!entry[flagIndex]) {\n return;\n }\n\n entry[1] = now;\n\n // If it's a stale revalidation, use the background revalidator function\n const revalidator = isStaleRevalidation ? entry[4] : entry[0];\n\n if (revalidator) {\n Promise.resolve(revalidator(isStaleRevalidation)).catch(noop);\n }\n });\n}\n\n/**\n * Revalidates an entry by executing the registered revalidation function.\n *\n * @param key The unique identifier for the cache entry to revalidate. If `null`, no revalidation occurs.\n * @param isStaleRevalidation - If `true`, it does not mark revalidated requests as in-flight.\n * @returns A promise that resolves to the result of the revalidator function, or\n * `null` if no key or revalidator is found, or a `FetchResponse` if applicable.\n */\nexport async function revalidate(\n key: string | null,\n isStaleRevalidation: boolean = false,\n): Promise {\n // If no key is provided, no revalidation occurs\n if (!key) {\n return null;\n }\n\n const entry = revalidators.get(key);\n\n if (entry) {\n // Update only the lastUsed timestamp without resetting the whole array\n entry[1] = timeNow();\n\n const revalidator = isStaleRevalidation ? entry[4] : entry[0];\n\n // If no revalidator function is registered, return null\n if (revalidator) {\n return await revalidator(isStaleRevalidation);\n }\n }\n\n // If no revalidator is registered for the key, return null\n return null;\n}\n\n/**\n * Removes all revalidators associated with the specified event type.\n *\n * @param type - The event type whose revalidators should be removed.\n */\nexport function removeRevalidators(type: EventType) {\n removeEventHandler(type);\n\n const flagIndex = type === 'focus' ? 5 : 6;\n\n // Clear all revalidators with this flag\n revalidators.forEach((entry, key) => {\n if (entry[flagIndex]) {\n removeRevalidator(key);\n }\n });\n}\n\n/**\n * Registers a generic revalidation event handler for the specified event type.\n * Ensures the handler is only added once and only in browser environments.\n *\n * @param event - The type of event to listen for (e.g., 'focus', 'visibilitychange').\n */\nfunction addEventHandler(event: EventType) {\n if (!isBrowser() || eventHandlers.has(event)) {\n return;\n }\n\n const handler = revalidateAll.bind(null, event, true);\n\n eventHandlers.set(event, handler);\n window.addEventListener(event, handler);\n}\n\n/**\n * Removes the generic event handler for the specified event type from the window object.\n *\n * @param event - The type of event whose handler should be removed.\n */\nfunction removeEventHandler(event: EventType) {\n if (!isBrowser()) {\n return;\n }\n\n const handler = eventHandlers.get(event);\n\n if (handler) {\n window.removeEventListener(event, handler);\n\n eventHandlers.delete(event);\n }\n}\n\n/**\n * Registers a revalidation functions for a specific cache key.\n *\n * @param {string} key Cache key to utilize\n * @param {RevalidatorFn} revalidatorFn Main revalidation function (marks in-flight requests)\n * @param {number} [ttl] Time to live in milliseconds (default: 3 minutes)\n * @param {number} [staleTime] Time (in seconds) after which the cache entry is considered stale\n * @param {RevalidatorFn} [bgRevalidatorFn] For stale revalidation (does not mark in-flight requests)\n * @param {boolean} [refetchOnFocus] Whether to revalidate on window focus\n * @param {boolean} [refetchOnReconnect] Whether to revalidate on network reconnect\n */\nexport function addRevalidator(\n key: string,\n revalidatorFn: RevalidatorFn, // Main revalidation function (marks in-flight requests)\n ttl?: number,\n staleTime?: number,\n bgRevalidatorFn?: RevalidatorFn, // For stale revalidation (does not mark in-flight requests)\n refetchOnFocus?: boolean,\n refetchOnReconnect?: boolean,\n) {\n revalidators.set(key, [\n revalidatorFn,\n timeNow(),\n ttl ?? DEFAULT_TTL,\n staleTime,\n bgRevalidatorFn,\n refetchOnFocus,\n refetchOnReconnect,\n ]);\n\n if (refetchOnFocus) {\n addEventHandler('focus');\n }\n\n if (refetchOnReconnect) {\n addEventHandler('online');\n }\n\n if (staleTime) {\n addTimeout('s:' + key, revalidate.bind(null, key, true), staleTime * 1000);\n }\n}\n\nexport function removeRevalidator(key: string) {\n revalidators.delete(key);\n\n // Clean up stale timer\n removeTimeout('s:' + key);\n}\n\n/**\n * Periodically cleans up expired revalidators from the registry.\n * Removes any revalidator whose TTL has expired.\n *\n * @param {number} intervalMs How often to run cleanup (default: 3 minutes)\n * @returns {() => void} A function to stop the periodic cleanup\n */\nexport function startRevalidatorCleanup(\n intervalMs: number = DEFAULT_TTL,\n): () => void {\n const intervalId = setInterval(() => {\n const now = timeNow();\n\n revalidators.forEach(\n ([, lastUsed, ttl, , , refetchOnFocus, refetchOnReconnect], key) => {\n // Skip focus-only or reconnect-only revalidators to keep them alive\n if (refetchOnFocus || refetchOnReconnect) {\n return;\n }\n\n if (ttl > 0 && now - lastUsed > ttl) {\n removeRevalidator(key);\n }\n },\n );\n }, intervalMs);\n\n return () => clearInterval(intervalId);\n}\n","/**\n * Manages a set of listeners (subscribers) for arbitrary string keys, allowing cross-context or cross-component\n * cache updates and synchronization. Provides functions to add, remove, and notify listeners, as well as a\n * convenient subscribe/unsubscribe API.\n *\n * @template T - The type of the response object passed to listeners.\n *\n * @remarks\n * - Listeners are grouped by a string key, which typically represents a cache key or resource identifier.\n * - When `notifySubscribers` is called for a key, all listeners registered for that key are invoked with the provided response.\n * - The `subscribe` function returns an unsubscribe function for convenient cleanup.\n *\n * @example\n * ```ts\n * const unsubscribe = subscribe('user:123', (response) => {\n * // handle updated data\n * });\n * // Later, to stop listening:\n * unsubscribe();\n * ```\n */\n\nimport { noop } from './utils';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Listener = (response: T) => void;\n\nconst listeners = new Map>();\n\nfunction ensureListenerSet(key: string) {\n if (!listeners.has(key)) {\n listeners.set(key, new Set());\n }\n\n return listeners.get(key)!;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function addListener(key: string, fn: Listener): void {\n ensureListenerSet(key).add(fn);\n}\n\nexport function removeListener(key: string, fn: Listener) {\n const set = listeners.get(key);\n\n if (set) {\n set.delete(fn);\n\n // If the set is empty, remove the key from the listeners map\n if (set.size === 0) {\n listeners.delete(key);\n }\n }\n}\n\nexport function notifySubscribers(key: string, response: T) {\n const fns = listeners.get(key);\n\n if (fns) {\n if (fns.size === 1) {\n // If there's only one listener, call it directly\n const fn = fns.values().next().value;\n fn!(response);\n } else {\n fns.forEach((fn) => fn(response));\n }\n }\n}\n\nexport function subscribe(key: string | null, fn: (response: T) => void) {\n if (!key) {\n // No op if no key is provided\n return noop;\n }\n\n addListener(key, fn);\n\n // Return an unsubscribe function\n return () => {\n removeListener(key, fn);\n };\n}\n","import {\n GET,\n APPLICATION_JSON,\n HEAD,\n STRING,\n CHARSET_UTF_8,\n CONTENT_TYPE,\n REJECT,\n UNDEFINED,\n APPLICATION_CONTENT_TYPE,\n} from './constants';\nimport type {\n HeadersObject,\n Method,\n RequestConfig,\n} from './types/request-handler';\nimport {\n replaceUrlPathParams,\n appendQueryParams,\n isSearchParams,\n isJSONSerializable,\n isSlowConnection,\n isAbsoluteUrl,\n sanitizeObject,\n isObject,\n} from './utils';\n\nconst defaultTimeoutMs = (isSlowConnection() ? 60 : 30) * 1000;\n\nexport const defaultConfig: RequestConfig = {\n strategy: REJECT,\n timeout: defaultTimeoutMs, // 30 seconds (60 on slow connections)\n headers: {\n Accept: APPLICATION_JSON + ', text/plain, */*',\n 'Accept-Encoding': 'gzip, deflate, br',\n },\n retry: {\n delay: defaultTimeoutMs / 30, // 1 second (2 on slow connections)\n maxDelay: defaultTimeoutMs, // 30 seconds (60 on slow connections)\n resetTimeout: true,\n backoff: 1.5,\n\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status\n retryOn: [\n 408, // Request Timeout\n 409, // Conflict\n 425, // Too Early\n 429, // Too Many Requests\n 500, // Internal Server Error\n 502, // Bad Gateway\n 503, // Service Unavailable\n 504, // Gateway Timeout\n ],\n },\n};\n\n/**\n * Overwrites the default configuration with the provided custom configuration.\n *\n * @param {Partial} customConfig - The custom configuration to merge into the default config.\n * @returns {Partial} - The updated default configuration object.\n */\nexport function setDefaultConfig(\n customConfig: Partial,\n): Partial {\n const sanitized = sanitizeObject(customConfig);\n\n Object.assign(defaultConfig, sanitized);\n\n return defaultConfig;\n}\n\n/**\n * Returns a shallow copy of the current default configuration.\n *\n * @returns {RequestConfig} - The current default configuration.\n */\nexport function getDefaultConfig(): RequestConfig {\n return { ...defaultConfig };\n}\n\n/**\n * Build request configuration from defaults and overrides.\n * This function merges the default configuration with the provided request configuration,\n * @param {string} url - Request url\n * @param {RequestConfig | null | undefined} reqConfig - Request configuration\n * @return {RequestConfig} - Merged request configuration\n */\nexport function buildConfig(\n url: string,\n reqConfig?: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > | null,\n): RequestConfig {\n if (!reqConfig) {\n return buildFetcherConfig(url, getDefaultConfig());\n }\n\n const sanitized = sanitizeObject(reqConfig);\n const merged = mergeConfigs(defaultConfig, sanitized);\n\n return buildFetcherConfig(url, merged);\n}\n\n/**\n * Builds the fetcher configuration by setting the method, body, headers, and URL.\n * It also handles query parameters and path parameters. This fn mutates the passed `requestConfig` object.\n * @param {string} url - The endpoint URL to which the request will be sent.\n * @param {RequestConfig} requestConfig - The request configuration object containing method, body, headers, and other options.\n * @return {RequestConfig} - The modified request configuration object with the URL, method, body, and headers set appropriately.\n **/\nexport function buildFetcherConfig(\n url: string,\n requestConfig: RequestConfig,\n): RequestConfig {\n let method = requestConfig.method as Method;\n method = method ? (method.toUpperCase() as Method) : GET;\n\n let body: RequestConfig['data'] | undefined;\n\n // Only applicable for request methods 'PUT', 'POST', 'DELETE', and 'PATCH'\n if (method !== GET && method !== HEAD) {\n body = requestConfig.body ?? requestConfig.data;\n\n // Automatically stringify request body, if possible and when not dealing with strings\n if (body && typeof body !== STRING && isJSONSerializable(body)) {\n body = JSON.stringify(body);\n }\n }\n\n setContentTypeIfNeeded(requestConfig.headers, body);\n\n // Native fetch compatible settings\n const credentials = requestConfig.withCredentials\n ? 'include'\n : requestConfig.credentials;\n\n // The explicitly passed query params\n const dynamicUrl = replaceUrlPathParams(url, requestConfig.urlPathParams);\n const urlPath = appendQueryParams(dynamicUrl, requestConfig.params);\n const isFullUrl = isAbsoluteUrl(url);\n const baseURL = isFullUrl\n ? ''\n : requestConfig.baseURL || requestConfig.apiUrl || '';\n\n requestConfig.url = baseURL + urlPath;\n requestConfig.method = method;\n requestConfig.credentials = credentials;\n requestConfig.body = body;\n\n return requestConfig;\n}\n\n/**\n * Ensures the `Content-Type` header is set to `application/json; charset=utf-8`\n * if it is not already present and the request method and body meet specific conditions.\n *\n * @param headers - The headers object to modify. Can be an instance of `Headers`\n * or a plain object conforming to `HeadersInit`.\n * @param body - The optional body of the request. If no body is provided and the\n * method is 'GET' or 'HEAD', the function exits without modifying headers.\n */\nfunction setContentTypeIfNeeded(\n headers?: HeadersInit | HeadersObject,\n body?: unknown,\n): void {\n // If no headers are provided, or if the body is not set and the method is PUT or DELETE, do nothing\n if (!headers || !body) {\n return;\n }\n\n // Types that should not have Content-Type set (browser handles these)\n if (\n body instanceof FormData || // Browser automatically sets multipart/form-data with boundary\n (typeof Blob !== UNDEFINED && body instanceof Blob) || // Blob/File already have their own MIME types, don't override\n (typeof File !== UNDEFINED && body instanceof File) ||\n (typeof ReadableStream !== UNDEFINED && body instanceof ReadableStream) // Stream type should be determined by the stream source\n ) {\n return;\n }\n\n let contentTypeValue: string;\n\n if (isSearchParams(body)) {\n contentTypeValue = APPLICATION_CONTENT_TYPE + 'x-www-form-urlencoded';\n } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {\n contentTypeValue = APPLICATION_CONTENT_TYPE + 'octet-stream';\n } else if (isJSONSerializable(body)) {\n contentTypeValue = APPLICATION_JSON + ';' + CHARSET_UTF_8;\n } else {\n // Do not set Content-Type if content is not recognizable\n return;\n }\n\n if (headers instanceof Headers) {\n if (!headers.has(CONTENT_TYPE)) {\n headers.set(CONTENT_TYPE, contentTypeValue);\n }\n } else if (\n isObject(headers) &&\n !Array.isArray(headers) &&\n !headers[CONTENT_TYPE]\n ) {\n headers[CONTENT_TYPE] = contentTypeValue;\n }\n}\n\nexport function mergeConfigs(\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n): RequestConfig {\n const mergedConfig: RequestConfig = Object.assign(\n {},\n baseConfig,\n overrideConfig,\n );\n\n // Ensure that retry and headers are merged correctly\n mergeConfig('retry', mergedConfig, baseConfig, overrideConfig);\n mergeConfig('headers', mergedConfig, baseConfig, overrideConfig);\n\n // Merge interceptors efficiently\n mergeInterceptors('onRequest', mergedConfig, baseConfig, overrideConfig);\n mergeInterceptors('onResponse', mergedConfig, baseConfig, overrideConfig);\n mergeInterceptors('onError', mergedConfig, baseConfig, overrideConfig);\n\n return mergedConfig;\n}\n\n/**\n * Efficiently merges interceptor functions from base and new configs\n */\nfunction mergeInterceptors<\n K extends 'onRequest' | 'onResponse' | 'onError' | 'onRetry',\n>(\n property: K,\n targetConfig: RequestConfig,\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n): void {\n const baseInterceptor = baseConfig[property];\n const newInterceptor = overrideConfig[property];\n\n if (!baseInterceptor && !newInterceptor) {\n return;\n }\n\n if (!baseInterceptor) {\n targetConfig[property] = newInterceptor;\n return;\n }\n\n if (!newInterceptor) {\n targetConfig[property] = baseInterceptor;\n return;\n }\n\n const baseArr = Array.isArray(baseInterceptor)\n ? baseInterceptor\n : [baseInterceptor];\n const newArr = Array.isArray(newInterceptor)\n ? newInterceptor\n : [newInterceptor];\n\n // This is the only LIFO interceptor, so we apply it after the response is prepared\n targetConfig[property] =\n property === 'onResponse' ? newArr.concat(baseArr) : baseArr.concat(newArr);\n}\n\n/**\n * Merges the specified property from the base configuration and the override configuration into the target configuration.\n *\n * @param {K} property - The property key to merge from the base and override configurations. Must be a key of RequestConfig.\n * @param {RequestConfig} targetConfig - The configuration object that will receive the merged properties.\n * @param {RequestConfig} baseConfig - The base configuration object that provides default values.\n * @param {RequestConfig} overrideConfig - The override configuration object that contains user-specific settings to merge.\n */\nexport function mergeConfig(\n property: K,\n targetConfig: RequestConfig,\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n): void {\n if (overrideConfig[property]) {\n targetConfig[property] = {\n ...baseConfig[property],\n ...overrideConfig[property],\n };\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { hash } from './hash';\nimport type {\n CacheKeyFunction,\n DefaultResponse,\n FetchResponse,\n MutationSettings,\n RequestConfig,\n} from './types/request-handler';\nimport type { CacheEntry } from './types/cache-manager';\nimport { GET, STRING, UNDEFINED } from './constants';\nimport { isObject, sanitizeObject, sortObject, timeNow } from './utils';\nimport { revalidate } from './revalidator-manager';\nimport { notifySubscribers } from './pubsub-manager';\nimport type { DefaultPayload, DefaultParams, DefaultUrlParams } from './types';\nimport { removeInFlight } from './inflight-manager';\nimport { addTimeout } from './timeout-wheel';\nimport { defaultConfig } from './config-handler';\nimport { processHeaders } from './utils';\n\nexport const IMMEDIATE_DISCARD_CACHE_TIME = 0; // Use it for cache entries that need to be persistent until unused by components or manually deleted\n\nconst _cache = new Map>();\nconst DELIMITER = '|';\nconst MIN_LENGTH_TO_HASH = 64;\nconst CACHE_KEY_SANITIZE_PATTERN = new RegExp('[^\\\\w\\\\-_|]', 'g');\n\n/**\n * Headers that may affect HTTP response content and should be included in cache key generation.\n * All header names must be lowercase to match normalized request headers.\n */\nconst CACHE_KEY_HEADER_WHITELIST = new Set([\n // Content negotiation\n 'accept', // Affects response format (e.g. JSON, HTML)\n 'accept-language', // Affects localization of the response\n 'accept-encoding', // Affects response compression (e.g. gzip, br)\n\n // Authentication\n 'authorization', // Affects access to protected resources\n\n // Request body metadata\n 'content-type', // Affects how the request body is interpreted\n\n // Optional headers\n 'referer', // May influence behavior in some APIs\n 'origin', // Relevant in CORS or tenant-specific APIs\n 'user-agent', // Included only for reason if server returns client-specific content\n\n // Cookies — only if server uses session-based responses\n 'cookie', // Can fragment cache heavily; use only if necessary\n\n // Custom headers that may affect response content\n 'x-api-key', // Token-based access, often affects authorization\n 'x-requested-with', // AJAX requests (used historically for distinguishing frontend calls)\n 'x-client-id', // Per-client/partner identity; often used in multi-tenant APIs\n 'x-tenant-id', // Multi-tenant segmentation; often changes response per tenant\n 'x-user-id', // Explicit user context (less common, but may exist)\n\n 'x-app-version', // Used for version-specific behavior (e.g. mobile apps)\n 'x-feature-flag', // Controls feature rollout behavior server-side\n 'x-device-id', // Used when response varies per device/app instance\n 'x-platform', // e.g. 'ios', 'android', 'web' — used in apps that serve different content\n\n 'x-session-id', // Only if backend uses it to affect the response directly (rare)\n 'x-locale', // Sometimes used in addition to or instead of `accept-language`\n]);\n\n/**\n * Generates a unique cache key for a given URL and fetch options, ensuring that key factors\n * like method, headers, body, and other options are included in the cache key.\n * Headers and other objects are sorted by key to ensure consistent cache keys.\n *\n * @param {RequestConfig} config - The fetch options that may affect the request. The most important are:\n * @property {string} [method=\"GET\"] - The HTTP method (GET, POST, etc.).\n * @property {HeadersInit} [headers={}] - The request headers.\n * @property {BodyInit | null} [body=\"\"] - The body of the request (only for methods like POST, PUT).\n * @property {RequestCredentials} [credentials=\"same-origin\"] - Whether to include credentials (include, same-origin, omit).\n * @property {RequestCache} [cache=\"default\"] - The cache mode (e.g., default, no-store, reload).\n * @returns {string} - A unique cache key string based on the provided options.\n *\n * @example\n * const cacheKey = generateCacheKey({\n * url: 'https://api.example.com/data',\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ name: 'Alice' }),\n * mode: 'cors',\n * credentials: 'include',\n * });\n * console.log(cacheKey);\n */\nexport function generateCacheKey(\n config: RequestConfig,\n cacheKeyCheck = true,\n): string {\n // This is super fast. Effectively a no-op if cacheKey is\n // a string or a function that returns a string.\n const key = config.cacheKey;\n\n if (key && cacheKeyCheck) {\n return typeof key === STRING\n ? (key as string)\n : (key as CacheKeyFunction)(config);\n }\n\n const {\n url = '',\n method = GET,\n headers = null,\n body = null,\n credentials = 'same-origin',\n } = config;\n\n // Sort headers and body + convert sorted to strings for hashing purposes\n // Native serializer is on avg. 3.5x faster than a Fast Hash or FNV-1a\n let headersString = '';\n if (headers) {\n let obj: Record;\n\n if (headers instanceof Headers) {\n obj = processHeaders(headers);\n } else {\n obj = headers as Record;\n }\n\n // Filter headers to only include those that affect request identity\n // Include only headers that affect request identity, not execution behavior\n const keys = Object.keys(obj);\n const len = keys.length;\n\n // Sort keys manually for fastest deterministic output\n if (len > 1) {\n keys.sort();\n }\n\n let str = '';\n for (let i = 0; i < len; ++i) {\n if (CACHE_KEY_HEADER_WHITELIST.has(keys[i].toLowerCase())) {\n str += keys[i] + ':' + obj[keys[i]] + ';';\n }\n }\n\n headersString = hash(str);\n }\n\n // For GET requests, return early with shorter cache key\n if (method === GET) {\n return (\n method +\n DELIMITER +\n url +\n DELIMITER +\n credentials +\n DELIMITER +\n headersString\n ).replace(CACHE_KEY_SANITIZE_PATTERN, '');\n }\n\n let bodyString = '';\n if (body) {\n if (typeof body === STRING) {\n bodyString = body.length < MIN_LENGTH_TO_HASH ? body : hash(body); // hash only if large\n } else if (body instanceof FormData) {\n body.forEach((value, key) => {\n // Append key=value and '&' directly to the result\n bodyString += key + '=' + value + '&';\n });\n\n if (bodyString.length > MIN_LENGTH_TO_HASH) {\n bodyString = hash(bodyString);\n }\n } else if (\n (typeof Blob !== UNDEFINED && body instanceof Blob) ||\n (typeof File !== UNDEFINED && body instanceof File)\n ) {\n bodyString = 'BF' + body.size + body.type;\n } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {\n bodyString = 'AB' + body.byteLength;\n } else {\n const o = isObject(body)\n ? JSON.stringify(sortObject(body))\n : String(body);\n\n bodyString = o.length > MIN_LENGTH_TO_HASH ? hash(o) : o;\n }\n }\n\n // Concatenate all key parts into a cache key string\n // Template literals are apparently slower\n return (\n method +\n DELIMITER +\n url +\n DELIMITER +\n credentials +\n DELIMITER +\n headersString +\n DELIMITER +\n bodyString\n ).replace(CACHE_KEY_SANITIZE_PATTERN, ''); // Prevent cache poisoning by removal of anything that isn't letters, numbers, -, _, or |\n}\n\n/**\n * Checks if the cache entry is expired based on its timestamp and the expiry time.\n *\n * @param {CacheEntry} entry - The cache entry to check.\n * @returns {boolean} - Returns true if the cache entry is expired, false otherwise.\n */\nfunction isCacheExpired(entry: CacheEntry): boolean {\n // No expiry time means the entry never expires\n if (!entry.expiry) {\n return false;\n }\n\n return timeNow() > entry.expiry;\n}\n\n/**\n * Checks if the cache entry is stale based on its timestamp and the stale time.\n *\n * @param {CacheEntry} entry - The cache entry to check.\n * @returns {boolean} - Returns true if the cache entry is stale, false otherwise.\n */\nfunction isCacheStale(entry: CacheEntry): boolean {\n if (!entry.stale) {\n return false;\n }\n\n return timeNow() > entry.stale;\n}\n\n/**\n * Retrieves a cached response from the internal cache using the provided key.\n *\n * @param key - The unique key identifying the cached entry. If null, returns null.\n * @returns The cached {@link FetchResponse} if found, otherwise null.\n */\nexport function getCacheData<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n key: string | null,\n): FetchResponse | null {\n if (!key) {\n return null;\n }\n\n const entry = _cache.get(key);\n\n return entry ? entry.data : null;\n}\n\n/**\n * Retrieves a cache entry if it exists and is not expired.\n *\n * @param {string} key Cache key to utilize\n * @returns {CacheEntry | null} - The cache entry if it exists and is not expired, null otherwise.\n */\nexport function getCache(\n key: string | null,\n):\n | CacheEntry<\n FetchResponse\n >\n | null\n | undefined {\n return _cache.get(key as string);\n}\n\n/**\n * Sets a new cache entry or updates an existing one, with optional TTL (time-to-live).\n *\n * @param {string} key Cache key to utilize\n * @param {T} data - The data to be cached.\n * @param {number} [ttl] - Optional TTL in seconds. If not provided, the cache entry will not expire.\n * @param {number} [staleTime] - Optional stale time in seconds. If provided, the cache entry will be considered stale after this time.\n */\nexport function setCache(\n key: string,\n data: T,\n ttl?: number,\n staleTime?: number,\n): void {\n if (ttl === 0) {\n deleteCache(key);\n return;\n }\n\n const time = timeNow();\n const ttlMs = ttl ? ttl * 1000 : 0;\n\n _cache.set(key, {\n data,\n time,\n stale: staleTime && staleTime > 0 ? time + staleTime * 1000 : staleTime,\n expiry: ttl === -1 ? undefined : time + ttlMs,\n });\n\n if (ttlMs > 0) {\n addTimeout(\n 'c:' + key,\n () => {\n deleteCache(key, true);\n },\n ttlMs,\n );\n }\n}\n\n/**\n * Invalidates (deletes) a cache entry.\n *\n * @param {string} key Cache key to utilize\n * @param {boolean} [removeExpired=false] - If true, only deletes the cache entry if it is expired or stale.\n */\nexport function deleteCache(key: string, removeExpired: boolean = false): void {\n if (removeExpired) {\n const entry = getCache(key);\n\n // If the entry does not exist, or it is neither expired nor stale, do not delete\n if (!entry || !isCacheExpired(entry)) {\n return;\n }\n }\n\n _cache.delete(key);\n}\n\n/**\n * Prunes the cache by removing entries that have expired based on the provided cache time.\n */\nexport function pruneCache(): void {\n _cache.clear();\n}\n\n/**\n * Mutates a cache entry with new data and optionally revalidates it.\n *\n * @param {string | null} key Cache key to utilize. If null, no mutation occurs.\n * @param {ResponseData} newData - The new data to be cached.\n * @param {MutationSettings|undefined} settings - Mutation settings.\n */\nexport async function mutate<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n key: string | null,\n newData: ResponseData,\n settings?: MutationSettings,\n): Promise | null> {\n // If no key is provided, do nothing\n if (!key) {\n return null;\n }\n\n const entry = getCache(\n key,\n );\n\n if (!entry) {\n return null;\n }\n\n const updatedData = isObject(newData) ? sanitizeObject(newData) : newData;\n\n const updatedResponse = {\n ...entry.data,\n data: updatedData,\n };\n\n const updatedEntry = {\n ...entry,\n data: updatedResponse,\n };\n\n _cache.set(key, updatedEntry);\n notifySubscribers(key, updatedResponse);\n\n if (settings && settings.refetch) {\n return await revalidate(key);\n }\n\n return null;\n}\n\n/**\n * Retrieves a cached response if available and valid, otherwise returns null.\n *\n * @template ResponseData - The type of the response data.\n * @template RequestBody - The type of the request body.\n * @template QueryParams - The type of the query parameters.\n * @template PathParams - The type of the path parameters.\n * @param {string | null} cacheKey - The cache key to look up.\n * @param {number | undefined} cacheTime - The maximum time to cache entry.\n * @param {RequestConfig} requestConfig - The fetcher configuration.\n * @returns {FetchResponse | null} - The cached response or null.\n */\nexport function getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n cacheKey: string | null,\n cacheTime: number | undefined,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): FetchResponse | null {\n // If cache key or time is not provided, return null\n if (!cacheKey || cacheTime === undefined || cacheTime === null) {\n return null;\n }\n\n // Check if cache should be bypassed\n const buster = requestConfig.cacheBuster || defaultConfig.cacheBuster;\n if (buster && buster(requestConfig)) {\n return null;\n }\n\n if (requestConfig.cache && requestConfig.cache === 'reload') {\n return null; // Skip cache lookup entirely\n }\n\n // Retrieve the cached entry\n const entry = getCache(\n cacheKey,\n );\n\n if (!entry) {\n return null;\n }\n\n const isExpired = isCacheExpired(entry);\n const isStale = isCacheStale(entry);\n\n // If completely expired, delete and return null\n if (isExpired) {\n deleteCache(cacheKey);\n return null;\n }\n\n // If fresh (not stale), return immediately\n if (!isStale) {\n return entry.data;\n }\n\n // SWR: Data is stale but not expired\n if (isStale && !isExpired) {\n // Triggering background revalidation here could cause race conditions\n // So we return stale data immediately and leave it up to implementers to handle revalidation\n return entry.data;\n }\n\n return null;\n}\n\n/**\n * Sets or deletes the response cache based on cache settings and notifies subscribers.\n *\n * @param {FetchResponse} output - The response to cache.\n * @param {RequestConfig} requestConfig - The request configuration.\n * @param {boolean} [isError=false] - Whether the response is an error.\n */\nexport function handleResponseCache<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n output: FetchResponse,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n isError: boolean = false,\n): void {\n // It is string as it is called once request is made\n const cacheKey = requestConfig.cacheKey as string;\n\n if (cacheKey) {\n const cacheTime = requestConfig.cacheTime;\n const skipCache = requestConfig.skipCache;\n\n // Fast path: only set cache if cacheTime is positive and not skipping cache\n if (\n cacheTime &&\n (!isError || requestConfig.cacheErrors) &&\n !(skipCache && skipCache(output, requestConfig))\n ) {\n setCache(cacheKey, output, cacheTime, requestConfig.staleTime);\n }\n\n notifySubscribers(cacheKey, output);\n removeInFlight(cacheKey);\n\n const prevCacheKey = requestConfig._prevKey;\n\n if (prevCacheKey) {\n removeInFlight(prevCacheKey);\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { mutate } from './cache-manager';\nimport {\n APPLICATION_CONTENT_TYPE,\n APPLICATION_JSON,\n CONTENT_TYPE,\n FUNCTION,\n OBJECT,\n STRING,\n} from './constants';\nimport {\n DefaultResponse,\n FetchResponse,\n RequestConfig,\n ResponseError,\n DefaultParams,\n DefaultUrlParams,\n DefaultPayload,\n} from './types';\nimport { flattenData, isObject, processHeaders } from './utils';\n\n/**\n * Parses the response data based on the Content-Type header.\n *\n * @param response - The Response object to parse.\n * @returns A Promise that resolves to the parsed data.\n */\nexport async function parseResponseData<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n response: FetchResponse,\n): Promise {\n // Bail early if response is null or undefined\n if (!response) {\n return null;\n }\n\n // Get the content-type header once\n let contentType = (response as Response).headers?.get(CONTENT_TYPE);\n\n if (contentType) {\n // Lowercase and trim for consistent matching\n contentType = contentType.toLowerCase().trim();\n } else {\n contentType = '';\n }\n\n // Split for mime type without charset\n const mimeType = contentType.split(';', 1)[0];\n\n let data;\n\n try {\n if (mimeType.includes(APPLICATION_JSON) || mimeType.includes('+json')) {\n data = await response.json(); // Parse JSON response\n } else if (\n (mimeType.includes('multipart/form-data') || // Parse as FormData\n mimeType.includes(\n APPLICATION_CONTENT_TYPE + 'x-www-form-urlencoded', // Handle URL-encoded forms\n )) &&\n typeof response.formData === FUNCTION\n ) {\n data = await response.formData();\n } else if (\n mimeType.includes(APPLICATION_CONTENT_TYPE + 'octet-stream') &&\n typeof response.blob === FUNCTION\n ) {\n data = await response.blob(); // Parse as blob\n } else {\n data = await response.text();\n\n if (typeof data === STRING) {\n const trimmed = data.trim();\n if (\n (trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))\n ) {\n try {\n data = JSON.parse(trimmed);\n } catch {\n // leave as text if parsing fails\n }\n }\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (_error) {\n // Parsing failed, fallback to null\n data = null;\n }\n\n return data;\n}\n\n/**\n * Prepare response object with additional information.\n *\n * @param Response. It may be \"null\" in case of request being aborted.\n * @param {RequestConfig} config - Request config\n * @param error - whether the response is erroneous\n * @returns {FetchResponse} Response data\n */\nexport const prepareResponse = <\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n config: RequestConfig,\n error: ResponseError<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null = null,\n): FetchResponse => {\n const defaultResponse = config.defaultResponse;\n const cacheKey = config.cacheKey;\n const mutatator = mutate.bind(null, cacheKey as string) as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >['mutate'];\n\n // This may happen when request is cancelled.\n if (!response) {\n return {\n ok: false,\n // Enhance the response with extra information\n error,\n data: defaultResponse ?? null,\n headers: null,\n config,\n mutate: mutatator,\n isFetching: false,\n isSuccess: false,\n isError: true,\n } as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }\n\n const isNativeResponse =\n typeof Response === FUNCTION && response instanceof Response;\n\n let data = response.data;\n\n // Set the default response if the provided data is an empty object\n if (\n defaultResponse !== undefined &&\n (data === undefined ||\n data === null ||\n (typeof data === OBJECT && Object.keys(data).length === 0))\n ) {\n response.data = data = defaultResponse;\n }\n\n if (config.flattenResponse) {\n response.data = data = flattenData(data);\n }\n\n if (config.select) {\n response.data = data = config.select(data);\n }\n\n const headers = processHeaders(response.headers);\n\n // Native fetch Response extended by extra information\n if (isNativeResponse) {\n return {\n body: response.body,\n bodyUsed: response.bodyUsed,\n ok: response.ok,\n redirected: response.redirected,\n type: response.type,\n url: response.url,\n status: response.status,\n statusText: response.statusText,\n\n // Convert methods to use arrow functions to preserve correct return types\n blob: () => response.blob(),\n json: () => response.json(),\n text: () => response.text(),\n clone: () => response.clone(),\n arrayBuffer: () => response.arrayBuffer(),\n formData: () => response.formData(),\n bytes: () => response.bytes(),\n\n // Enhance the response with extra information\n error,\n data,\n headers,\n config,\n mutate: mutatator,\n isFetching: false,\n isSuccess: response.ok && !error,\n isError: !!error,\n };\n }\n\n // If it's a custom fetcher, and it does not return any Response instance, it may have its own internal handler\n if (isObject(response)) {\n response.error = error;\n response.headers = headers;\n response.isFetching = false;\n response.mutate = mutatator;\n response.isSuccess = response.ok && !error;\n response.isError = !!error;\n }\n\n return response;\n};\n","import { applyInterceptors } from './interceptor-manager';\nimport type { FetchResponse, RetryConfig, RetryFunction } from './types';\nimport { delayInvocation, timeNow } from './utils';\nimport { generateCacheKey } from './cache-manager';\n\nfunction getMsFromHttpDate(dateString: string): number | null {\n const ms = Date.parse(dateString) - timeNow();\n\n if (!isNaN(ms)) {\n return Math.max(0, Math.floor(ms));\n }\n return null;\n}\n\n/**\n * Calculates the number of milliseconds to wait before retrying a request,\n * based on the `Retry-After` HTTP header in the provided response.\n *\n * The function supports both numeric (seconds) and HTTP-date formats for the `Retry-After` header.\n * - If the header is a number, it is interpreted as seconds and converted to milliseconds.\n * - If the header is a date, the function calculates the difference between the date and the current time.\n *\n * @param extendedResponse - The response object containing headers, or `null`.\n * @returns The number of milliseconds to wait before retrying, or `null` if the header is not present or invalid.\n */\nexport function getRetryAfterMs(\n extendedResponse: FetchResponse | null,\n): number | null {\n if (!extendedResponse) {\n return null;\n }\n\n const headers = extendedResponse.headers || {};\n const retryAfter = headers['retry-after'];\n\n if (retryAfter) {\n // Try parsing as seconds\n const seconds = Number(retryAfter);\n\n if (!isNaN(seconds) && seconds >= 0) {\n return seconds * 1000;\n }\n\n const ms = getMsFromHttpDate(retryAfter);\n\n if (ms !== null) {\n return ms;\n }\n }\n\n // Headers are already in lowercase\n const RATELIMIT_RESET = 'ratelimit-reset';\n\n // Unix timestamp when the rate limit window resets (relative to current time)\n // Fallback to checking 'ratelimit-reset-after' OR 'x-ratelimit-reset-after' headers\n const rateLimitResetAfter =\n headers[RATELIMIT_RESET + '-after'] ||\n headers['x-' + RATELIMIT_RESET + '-after'];\n\n if (rateLimitResetAfter) {\n const seconds = Number(rateLimitResetAfter);\n\n if (!isNaN(seconds)) {\n return seconds * 1000;\n }\n }\n\n // ISO 8601 datetime when the rate limit resets\n // Fallback to checking 'ratelimit-reset-at' 'x-ratelimit-reset-at' headers\n const rateLimitResetAt =\n headers[RATELIMIT_RESET + '-at'] || headers['x-' + RATELIMIT_RESET + '-at'];\n\n if (rateLimitResetAt) {\n return getMsFromHttpDate(rateLimitResetAt);\n }\n\n return null;\n}\n\n/**\n * Executes a request function with retry logic according to the provided configuration.\n *\n * The function attempts the request up to the specified number of retries, applying delay and backoff strategies.\n * Retries can be triggered based on response status codes, custom logic, or the presence of a `Retry-After` header.\n * Optionally, an `onRetry` interceptor can be invoked before each retry attempt.\n *\n * @typeParam ResponseData - The type of the response data.\n * @typeParam RequestBody - The type of the request body.\n * @typeParam QueryParams - The type of the query parameters.\n * @typeParam PathParams - The type of the path parameters.\n * @param requestFn - The function that performs the request. Receives `isStaleRevalidation` and `attempt` as arguments.\n * @param config - The retry configuration, including retry count, delay, backoff, retry conditions, and hooks.\n * @returns A promise resolving to the fetch response, or rejecting if all retries are exhausted.\n * @throws Error if the maximum number of retries is exceeded or a non-retriable error occurs.\n */\nexport async function withRetry<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n requestFn: (\n isStaleRevalidation: boolean,\n attempt: number,\n ) => Promise<\n FetchResponse\n >,\n config: RetryConfig,\n): Promise> {\n const {\n retries = 0,\n delay = 0,\n backoff = 1,\n maxDelay,\n retryOn = [],\n shouldRetry,\n } = config;\n\n let attempt = 0;\n let waitTime = delay;\n const maxRetries = retries > 0 ? retries : 0;\n let output: FetchResponse;\n\n while (attempt <= maxRetries) {\n // Subsequent attempts will have output defined, but the first attempt may not.\n // Let's apply onRetry interceptor and regenerate cache key if ot really changes.\n if (attempt > 0 && output!) {\n const cfg = output.config;\n const onRetry = cfg.onRetry;\n\n if (onRetry) {\n await applyInterceptors(onRetry, output, attempt);\n\n // If the key was automatically generated, we need to regenerate it as config may change.\n // We don't detect whether config changed for performance reasons.\n if (cfg._isAutoKey) {\n cfg._prevKey = cfg.cacheKey as string;\n cfg.cacheKey = generateCacheKey(cfg, false);\n }\n }\n }\n\n // Performance optimization: Call the request function with the current attempt number\n // If this is the first attempt, we pass `isStaleRevalidation` as `false`,\n // otherwise we pass `true` to indicate that this is a stale revalidation (no cache hit).\n output = await requestFn(attempt > 0, attempt);\n const error = output.error;\n\n // Check if we should retry based on successful response\n if (!error) {\n if (shouldRetry && attempt < maxRetries) {\n const shouldRetryResult = await shouldRetry(output, attempt);\n\n if (shouldRetryResult) {\n await delayInvocation(waitTime);\n waitTime *= backoff || 1;\n waitTime = Math.min(waitTime, maxDelay || waitTime);\n attempt++;\n continue;\n }\n }\n\n break;\n }\n\n // Determine if we should stop retrying\n const shouldStopRetrying = await getShouldStopRetrying(\n output,\n attempt,\n maxRetries,\n shouldRetry,\n retryOn,\n );\n\n if (shouldStopRetrying) {\n break;\n }\n\n // If we should not stop retrying, continue to the next attempt\n // Handle rate limiting if the error status is 429 (Too Many Requests) or 503 (Service Unavailable)\n if (error.status === 429 || error.status === 503) {\n // Try to extract the \"Retry-After\" value from the response headers\n const retryAfterMs = getRetryAfterMs(output);\n\n // If a valid retry-after value is found, override the wait time before next retry\n if (retryAfterMs !== null) {\n waitTime = retryAfterMs;\n }\n }\n\n await delayInvocation(waitTime);\n waitTime *= backoff || 1;\n waitTime = Math.min(waitTime, maxDelay || waitTime);\n attempt++;\n }\n\n return output!;\n}\n\n/**\n * Determines whether to stop retrying based on the error, current attempt count, and retry configuration.\n *\n * This function checks:\n * - If the maximum number of retries has been reached.\n * - If a custom `shouldRetry` callback is provided, its result is used to decide.\n * - If no custom logic is provided, falls back to checking if the error status is included in the `retryOn` list.\n *\n * @typeParam ResponseData - The type of the response data.\n * @typeParam RequestBody - The type of the request body.\n * @typeParam QueryParams - The type of the query parameters.\n * @typeParam PathParams - The type of the path parameters.\n * @param output - The response object containing the error and request configuration.\n * @param attempt - The current retry attempt number.\n * @param maxRetries - The maximum number of retry attempts allowed.\n * @param shouldRetry - Optional custom function to determine if a retry should occur.\n * @param retryOn - Optional list of HTTP status codes that should trigger a retry.\n * @returns A promise resolving to `true` if retrying should stop, or `false` to continue retrying.\n */\nexport async function getShouldStopRetrying<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n output: FetchResponse,\n attempt: number,\n maxRetries: number,\n shouldRetry?: RetryFunction<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n retryOn: number[] = [],\n): Promise {\n // Safety first: always respect max retries\n // We check retries provided regardless of the shouldRetry being provided so to avoid infinite loops.\n // It is a fail-safe so to prevent excessive retry attempts even if custom retry logic suggests a retry.\n if (attempt === maxRetries) {\n return true;\n }\n\n let customDecision: boolean | null = null;\n\n // Get custom decision if shouldRetry is provided\n if (shouldRetry) {\n const result = await shouldRetry(output, attempt);\n customDecision = result;\n\n // Decision cascade:\n if (customDecision !== null) {\n return !customDecision;\n }\n }\n\n return !(retryOn || []).includes(output.error?.status ?? 0);\n}\n","import type { RequestConfig, FetchResponse } from './types';\nimport { delayInvocation } from './utils';\n\n/**\n * Executes a request function with polling, stopping when shouldStopPolling returns true,\n * pollingInterval is not set, or maxAttempts is reached.\n *\n * @template Output The type of the output returned by the request function.\n * @param requestFn - The function that performs a single request (with retries).\n * @param pollingInterval - Interval in ms between polling attempts.\n * @param shouldStopPolling - Function to determine if polling should stop.\n * @param maxAttempts - Maximum number of polling attempts, default: 0 (unlimited).\n * @param pollingDelay - Delay in ms before each polling attempt, default: 0.\n * @returns The final output from the last request.\n */\nexport async function withPolling<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n requestFn: (\n isStaleRevalidation?: boolean,\n attempt?: number,\n ) => Promise<\n FetchResponse\n >,\n pollingInterval?: RequestConfig['pollingInterval'],\n shouldStopPolling?: RequestConfig['shouldStopPolling'],\n maxAttempts = 0,\n pollingDelay = 0,\n): Promise> {\n if (!pollingInterval) {\n return requestFn();\n }\n\n let pollingAttempt = 0;\n let output: FetchResponse;\n\n while (maxAttempts === 0 || pollingAttempt < maxAttempts) {\n if (pollingDelay > 0) {\n await delayInvocation(pollingDelay);\n }\n\n output = await requestFn();\n\n pollingAttempt++;\n\n if (\n (maxAttempts > 0 && pollingAttempt >= maxAttempts) ||\n !pollingInterval ||\n (shouldStopPolling && shouldStopPolling(output, pollingAttempt))\n ) {\n break;\n }\n\n await delayInvocation(pollingInterval);\n }\n\n return output!;\n}\n","import type { ResponseError } from './errors/response-error';\nimport type {\n DefaultResponse,\n FetchResponse,\n RequestConfig,\n} from './types/request-handler';\nimport { applyInterceptors } from './interceptor-manager';\nimport { handleResponseCache } from './cache-manager';\nimport { ABORT_ERROR, REJECT } from './constants';\nimport { DefaultParams, DefaultUrlParams, DefaultPayload } from './types';\n\n/**\n * Handles final processing for both success and error responses\n * Applies error interceptors, caching, notifications, and error strategy\n */\nexport async function withErrorHandling<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n isStaleRevalidation: boolean,\n requestFn: (\n isStaleRevalidation: boolean,\n ) => Promise<\n FetchResponse\n >,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): Promise> {\n const output = await requestFn(isStaleRevalidation);\n const error = output.error;\n\n if (!error) {\n // SUCCESS PATH\n handleResponseCache(output, requestConfig);\n\n return output;\n }\n\n // ERROR PATH\n\n if (requestConfig.onError) {\n await applyInterceptors(requestConfig.onError, error);\n }\n\n // Timeouts and request cancellations using AbortController do not throw any errors unless rejectCancelled is true.\n // Only handle the error if the request was not cancelled, or if it was cancelled and rejectCancelled is true.\n const isCancelled = error.isCancelled;\n\n if (!isCancelled && requestConfig.logger) {\n logger(requestConfig, 'FETCH ERROR', error as ResponseError);\n }\n\n // Handle cache and notifications FIRST (before strategy)\n handleResponseCache(output, requestConfig, true);\n\n // handle error strategy as the last part\n const shouldHandleError = !isCancelled || requestConfig.rejectCancelled;\n\n if (shouldHandleError) {\n const strategy = requestConfig.strategy;\n // Reject the promise\n if (strategy === REJECT) {\n return Promise.reject(error);\n }\n\n // Hang the promise\n if (strategy === 'silent') {\n await new Promise(() => null);\n }\n }\n\n return output;\n}\n\nexport function enhanceError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n error: any,\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): void {\n error.status = error.status || response?.status || 0;\n error.statusText = error.statusText || response?.statusText || '';\n error.config = error.request = requestConfig;\n error.response = response;\n error.isCancelled = error.name === ABORT_ERROR;\n}\n\n/**\n * Logs messages or errors using the configured logger's `warn` method.\n *\n * @param {RequestConfig} reqConfig - Request config passed when making the request\n * @param {...(string | ResponseError)} args - Messages or errors to log.\n */\nfunction logger(\n reqConfig: RequestConfig,\n ...args: (string | ResponseError)[]\n): void {\n const logger = reqConfig.logger;\n\n if (logger && logger.warn) {\n logger.warn(...args);\n }\n}\n","import type {\n DefaultResponse,\n RequestConfig,\n FetchResponse,\n} from './types/request-handler';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultUrlParams,\n} from './types/api-handler';\nimport { applyInterceptors } from './interceptor-manager';\nimport { ResponseError } from './errors/response-error';\nimport { isObject } from './utils';\nimport {\n markInFlight,\n setInFlightPromise,\n getInFlightPromise,\n} from './inflight-manager';\nimport { parseResponseData, prepareResponse } from './response-parser';\nimport { generateCacheKey, getCachedResponse, setCache } from './cache-manager';\nimport { withRetry } from './retry-handler';\nimport { withPolling } from './polling-handler';\nimport { notifySubscribers } from './pubsub-manager';\nimport { addRevalidator } from './revalidator-manager';\nimport { enhanceError, withErrorHandling } from './error-handler';\nimport { FUNCTION } from './constants';\nimport { buildConfig } from './config-handler';\n\nconst inFlightResponse = {\n isFetching: true,\n};\n\n/**\n * Sends an HTTP request to the specified URL using the provided configuration and returns a typed response.\n *\n * @typeParam ResponseData - The expected shape of the response data. Defaults to `DefaultResponse`.\n * @typeParam RequestBody - The type of the request payload/body. Defaults to `DefaultPayload`.\n * @typeParam QueryParams - The type of the query parameters. Defaults to `DefaultParams`.\n * @typeParam PathParams - The type of the path parameters. Defaults to `DefaultUrlParams`.\n *\n * @param url - The endpoint URL to which the request will be sent.\n * @param config - Optional configuration object for the request, including headers, method, body, query, and path parameters.\n *\n * @returns A promise that resolves to a `FetchResponse` containing the typed response data and request metadata.\n *\n * @example\n * ```typescript\n * const { data } = await fetchf('/api/user', { method: 'GET' });\n * console.log(data);\n * ```\n */\nexport async function fetchf<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n url: string,\n reqConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > | null = null,\n): Promise> {\n const fetcherConfig = buildConfig<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(url, reqConfig);\n\n const {\n timeout,\n cancellable,\n cacheKey,\n dedupeTime,\n cacheTime,\n staleTime,\n refetchOnFocus,\n refetchOnReconnect,\n pollingInterval = 0,\n } = fetcherConfig;\n const isCacheEnabled = cacheTime !== undefined || staleTime !== undefined;\n\n const needsCacheKey = !!(\n cacheKey ||\n timeout ||\n dedupeTime ||\n isCacheEnabled ||\n cancellable ||\n refetchOnFocus ||\n refetchOnReconnect\n );\n\n let _cacheKey: string | null = null;\n\n // Generate cache key if required\n if (needsCacheKey) {\n _cacheKey = generateCacheKey(fetcherConfig);\n }\n\n // Cache handling logic\n if (_cacheKey && isCacheEnabled) {\n const cached = getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(_cacheKey, cacheTime, fetcherConfig);\n\n if (cached) {\n return cached;\n }\n }\n\n // Deduplication logic\n if (_cacheKey && dedupeTime) {\n const inflight = getInFlightPromise<\n FetchResponse\n >(_cacheKey, dedupeTime);\n\n if (inflight) {\n return inflight;\n }\n }\n\n const retryConfig = fetcherConfig.retry || {};\n const { retries = 0, resetTimeout } = retryConfig;\n\n // The actual request logic as a function (one poll attempt, with retries)\n const doRequestOnce = async (isStaleRevalidation = false, attempt = 0) => {\n // If cache key is specified, we will handle optimistic updates\n // and mark the request as in-flight, so to catch \"fetching\" state.\n // This is useful for Optimistic UI updates (e.g., showing loading spinners).\n if (!attempt) {\n if (_cacheKey && !isStaleRevalidation) {\n if (staleTime) {\n const existingCache = getCachedResponse(\n _cacheKey,\n cacheTime,\n fetcherConfig,\n );\n\n // Don't notify subscribers when cache exists\n // Let them continue showing stale data during background revalidation\n if (!existingCache) {\n setCache(_cacheKey, inFlightResponse, cacheTime, staleTime);\n notifySubscribers(_cacheKey, inFlightResponse);\n }\n } else {\n notifySubscribers(_cacheKey, inFlightResponse);\n }\n }\n\n // Attach cache key so that it can be reused in interceptors or in the final response\n fetcherConfig.cacheKey = _cacheKey;\n }\n\n const url = fetcherConfig.url as string;\n\n // Add the request to the queue. Make sure to handle deduplication, cancellation, timeouts in accordance to retry settings\n const controller = markInFlight(\n _cacheKey,\n url,\n timeout,\n dedupeTime || 0,\n !!cancellable,\n // Enable timeout either by default or when retries & resetTimeout are enabled\n !!(timeout && (!attempt || resetTimeout)),\n );\n\n // Do not create a shallow copy to maintain idempotency here.\n // This ensures the original object is mutated by interceptors whenever needed, including retry logic.\n const requestConfig = fetcherConfig;\n\n requestConfig.signal = controller.signal;\n\n let output: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n let response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null = null;\n\n try {\n if (fetcherConfig.onRequest) {\n await applyInterceptors(fetcherConfig.onRequest, requestConfig);\n }\n\n // Custom fetcher\n const fn = fetcherConfig.fetcher;\n\n response = (fn\n ? await fn(\n url,\n requestConfig,\n )\n : await fetch(\n url,\n requestConfig as RequestInit,\n )) as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n\n // Custom fetcher may return a raw data object instead of a Response instance\n if (isObject(response)) {\n // Case 1: Native Response instance\n if (typeof Response === FUNCTION && response instanceof Response) {\n response.data = await parseResponseData(response);\n } else if (fn) {\n // Case 2: Custom fetcher that returns a response object\n if (!('data' in response && 'body' in response)) {\n // Case 3: Raw data, wrap it\n response = { data: response } as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }\n }\n\n // Attach config and data to the response\n // This is useful for custom fetchers that do not return a Response instance\n // and for interceptors that may need to access the request config\n response.config = requestConfig;\n\n // Check if the response status is not outside the range 200-299 and if so, output error\n // This is the pattern for fetch responses as per spec, but custom fetchers may not follow it so we check for `ok` property\n if (response.ok !== undefined && !response.ok) {\n throw new ResponseError(\n `${requestConfig.method} to ${url} failed! Status: ${response.status || null}`,\n requestConfig,\n response,\n );\n }\n }\n\n output = prepareResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(response, requestConfig);\n\n const onResponse = fetcherConfig.onResponse;\n\n if (onResponse) {\n await applyInterceptors(onResponse, output);\n }\n } catch (_error) {\n const error = _error as ResponseError<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n\n // Append additional information to Network, CORS or any other fetch() errors\n enhanceError(\n error,\n response,\n requestConfig,\n );\n\n // Prepare Extended Response\n output = prepareResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(response, requestConfig, error);\n }\n\n return output;\n };\n\n // Inline and minimize function wrappers for performance\n const baseRequest =\n retries > 0 ? () => withRetry(doRequestOnce, retryConfig) : doRequestOnce;\n\n const requestWithErrorHandling = (isStaleRevalidation = false) =>\n withErrorHandling(\n isStaleRevalidation,\n baseRequest,\n fetcherConfig,\n );\n\n // Avoid unnecessary function wrapping if polling is not enabled\n const doRequestPromise = pollingInterval\n ? withPolling(\n requestWithErrorHandling,\n pollingInterval,\n fetcherConfig.shouldStopPolling,\n fetcherConfig.maxPollingAttempts,\n fetcherConfig.pollingDelay,\n )\n : requestWithErrorHandling();\n\n // If deduplication is enabled, store the in-flight promise immediately\n if (_cacheKey) {\n if (dedupeTime) {\n setInFlightPromise(_cacheKey, doRequestPromise);\n }\n\n addRevalidator(\n _cacheKey,\n requestWithErrorHandling,\n undefined,\n staleTime,\n requestWithErrorHandling,\n !!refetchOnFocus,\n !!refetchOnReconnect,\n );\n }\n\n return doRequestPromise;\n}\n","import type {\n ApiHandlerConfig,\n ApiHandlerDefaultMethods,\n ApiHandlerMethods,\n RequestConfigUrlRequired,\n} from './types/api-handler';\nimport { fetchf } from '.';\nimport { mergeConfigs } from './config-handler';\nimport { isAbsoluteUrl } from './utils';\n\n/**\n * Creates an instance of API Handler.\n * It creates an API fetcher function using native fetch() or a custom fetcher if passed as \"fetcher\".\n * @see https://github.com/MattCCC/fetchff#configuration\n *\n * @param {Object} config - Configuration object for the API fetcher (see link above for full options).\n * @param {Object} config.endpoints - An object containing endpoint definitions.\n * @param {string} [config.baseURL] - The base URL for the API.\n * @param {Object} [config.headers] - Optional default headers to include in every request.\n * @param {Function} [config.onError] - Optional callback function for handling errors.\n * @returns API handler functions and endpoints to call\n *\n * @example\n * // Define endpoint paths\n * const endpoints = {\n * getUser: '/user',\n * createPost: '/post',\n * };\n *\n * // Create the API fetcher with configuration\n * const api = createApiFetcher({\n * endpoints,\n * apiUrl: 'https://example.com/api',\n * onError(error) {\n * console.log('Request failed', error);\n * },\n * headers: {\n * 'my-auth-key': 'example-auth-key-32rjjfa',\n * },\n * });\n *\n * // Fetch user data\n * const response = await api.getUser({ userId: 1, ratings: [1, 2] })\n */\nfunction createApiFetcher<\n EndpointTypes extends object,\n EndpointsSettings = never,\n>(config: ApiHandlerConfig) {\n const endpoints = config.endpoints;\n\n /**\n * Triggered when trying to use non-existent endpoints\n *\n * @param endpointName Endpoint Name\n * @returns {Promise}\n */\n function handleNonImplemented(endpointName: string): Promise {\n console.error(`Add ${endpointName} to 'endpoints'.`);\n\n return Promise.resolve(null);\n }\n\n const apiHandler: ApiHandlerDefaultMethods = {\n config,\n endpoints,\n /**\n * Handle Single API Request\n * It considers settings in following order: per-request settings, global per-endpoint settings, global settings.\n *\n * @param endpointName - The name of the API endpoint to call.\n * @param requestConfig - Additional configuration for the request.\n * @returns A promise that resolves with the response from the API provider.\n */\n async request(endpointName, requestConfig = {}) {\n // Use global and per-endpoint settings\n const endpointConfig = endpoints[endpointName];\n const _endpointConfig =\n endpointConfig ||\n ({ url: String(endpointName) } as RequestConfigUrlRequired);\n const url = _endpointConfig.url;\n\n // Block Protocol-relative URLs as they could lead to SSRF (Server-Side Request Forgery)\n if (url.startsWith('//')) {\n throw new Error('Protocol-relative URLs are not allowed.');\n }\n\n // Prevent potential Server-Side Request Forgery attack and leakage of credentials when same instance is used for external requests\n const mergedConfig = isAbsoluteUrl(url)\n ? // Merge endpoints configs for absolute URLs only if urls match\n endpointConfig?.url === url\n ? mergeConfigs(_endpointConfig, requestConfig)\n : requestConfig\n : mergeConfigs(mergeConfigs(config, _endpointConfig), requestConfig);\n\n // We prevent potential Server-Side Request Forgery attack and leakage of credentials as the same instance is not used for external requests\n // Retrigger fetch to ensure completely new instance of handler being triggered for external URLs\n return fetchf(url, mergedConfig);\n },\n };\n\n /**\n * Maps all API requests using native Proxy\n *\n * @param {*} prop Caller\n */\n return new Proxy>(\n apiHandler as ApiHandlerMethods,\n {\n get(_target, prop: string) {\n if (prop in apiHandler) {\n return apiHandler[prop as unknown as keyof typeof apiHandler];\n }\n\n // Prevent handler from triggering non-existent endpoints\n if (endpoints[prop]) {\n return apiHandler.request.bind(null, prop);\n }\n\n return handleNonImplemented.bind(null, prop);\n },\n },\n );\n}\n\nexport { createApiFetcher };\n"]} \ No newline at end of file +{"version":3,"sources":["../../src/constants.ts","../../src/utils.ts","../../src/interceptor-manager.ts","../../src/errors/fetch-error.ts","../../src/errors/response-error.ts","../../src/timeout-wheel.ts","../../src/inflight-manager.ts","../../src/hash.ts","../../src/revalidator-manager.ts","../../src/pubsub-manager.ts","../../src/config-handler.ts","../../src/cache-manager.ts","../../src/response-parser.ts","../../src/retry-handler.ts","../../src/polling-handler.ts","../../src/error-handler.ts","../../src/request-handler.ts","../../src/api-handler.ts"],"names":["APPLICATION_CONTENT_TYPE","APPLICATION_JSON","CHARSET_UTF_8","CONTENT_TYPE","UNDEFINED","OBJECT","STRING","FUNCTION","ABORT_ERROR","TIMEOUT_ERROR","GET","HEAD","REJECT","MAX_DEPTH","isSearchParams","data","isObject","value","sanitizeObject","obj","hasProto","hasCtor","hasPrototype","safeObj","sortObject","keys","sortedObj","i","len","key","appendQueryStringToUrl","baseUrl","queryString","appendQueryParams","url","params","encodedQueryString","s","encode","add","k","v","buildParams","prefix","depth","replaceUrlPathParams","urlPathParams","match","isAbsoluteUrl","timeNow","noop","isJSONSerializable","delayInvocation","ms","resolve","flattenData","processHeaders","headers","headersObject","isBrowser","createAbortError","message","name","error","isSlowConnection","conn","applyInterceptors","interceptors","args","interceptor","FetchError","request","response","__publicField","ResponseError","WHEEL_SIZE","SECOND","MAX_WHEEL_MS","wheel","keyMap","position","timer","handleCallback","callback","result","e","addTimeout","cb","removeTimeout","seconds","slot","slotOrTimeout","slotArr","idx","inFlight","markInFlight","timeout","dedupeTime","isCancellable","isTimeoutEnabled","now","item","prevPromise","prevController","prevIsCancellable","controller","abortRequest","removeInFlight","setInFlightPromise","promise","getInFlightPromise","prevReq","hash","str","char","DEFAULT_TTL","revalidators","eventHandlers","customEventProviders","setEventProvider","type","provider","removeEventHandler","addEventHandler","revalidateAll","isStaleRevalidation","flagIndex","entry","revalidator","revalidate","removeRevalidators","removeRevalidator","event","handler","customProvider","cleanup","addRevalidator","revalidatorFn","ttl","staleTime","bgRevalidatorFn","refetchOnFocus","refetchOnReconnect","existing","listeners","ensureListenerSet","set","addListener","fn","removeListener","notifySubscribers","fns","subscribe","defaultTimeoutMs","defaultConfig","setDefaultConfig","customConfig","sanitized","mergeConfigs","getDefaultConfig","buildConfig","reqConfig","buildFetcherConfig","merged","requestConfig","_a","method","body","setContentTypeIfNeeded","credentials","dynamicUrl","urlPath","baseURL","contentTypeValue","baseConfig","overrideConfig","targetConfig","mergeConfig","mergeInterceptors","property","baseInterceptor","newInterceptor","baseArr","newArr","base","override","baseNormalized","overrideNormalized","_cache","DELIMITER","MIN_LENGTH_TO_HASH","CACHE_KEY_SANITIZE_PATTERN","CACHE_KEY_NEEDS_SANITIZE","CACHE_KEY_HEADER_WHITELIST","generateCacheKey","config","cacheKeyCheck","headersString","cacheStr","bodyString","o","isCacheExpired","getCache","setCache","deleteCache","time","ttlMs","staleTimeMs","removeExpired","mutate","newData","settings","updatedData","updatedResponse","updatedEntry","getCachedResponse","cacheKey","cacheTime","buster","handleResponseCache","output","isError","skipCache","prevCacheKey","parseResponseData","contentType","mimeType","trimmed","_error","prepareResponse","defaultResponse","mutatator","isNativeResponse","getMsFromHttpDate","dateString","getRetryAfterMs","extendedResponse","retryAfter","RATELIMIT_RESET","rateLimitResetAfter","rateLimitResetAt","withRetry","requestFn","retries","delay","backoff","maxDelay","retryOn","shouldRetry","attempt","waitTime","maxRetries","cfg","onRetry","getShouldStopRetrying","retryAfterMs","_b","customDecision","withPolling","pollingInterval","shouldStopPolling","maxAttempts","pollingDelay","pollingAttempt","withErrorHandling","isCancelled","logger","strategy","enhanceError","inFlightResponse","fetchf","cached","fetcherConfig","cancellable","isCacheEnabled","needsCacheKey","_cacheKey","inflight","retryConfig","resetTimeout","doRequestOnce","onResponse","baseRequest","_","requestWithErrorHandling","doRequestPromise","createApiFetcher","endpoints","handleNonImplemented","endpointName","apiHandler","endpointConfig","_endpointConfig","mergedConfig","_target","prop"],"mappings":"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","file":"index.global.js","sourcesContent":["export const APPLICATION_CONTENT_TYPE = 'application/';\n\nexport const APPLICATION_JSON = APPLICATION_CONTENT_TYPE + 'json';\nexport const CHARSET_UTF_8 = 'charset=utf-8';\nexport const CONTENT_TYPE = 'Content-Type';\n\nexport const UNDEFINED = 'undefined';\nexport const OBJECT = 'object';\nexport const STRING = 'string';\nexport const FUNCTION = 'function';\n\nexport const ABORT_ERROR = 'AbortError';\nexport const TIMEOUT_ERROR = 'TimeoutError';\n\nexport const GET = 'GET';\nexport const HEAD = 'HEAD';\n\nexport const REJECT = 'reject';\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { FUNCTION, OBJECT, STRING, UNDEFINED } from './constants';\nimport type {\n DefaultUrlParams,\n HeadersObject,\n QueryParams,\n UrlPathParams,\n} from './types';\n\n// Prevent stack overflow with recursion depth limit\nconst MAX_DEPTH = 10;\n\nexport function isSearchParams(data: unknown): boolean {\n return data instanceof URLSearchParams;\n}\n\n/**\n * Determines if a value is a non-null object.\n *\n * @param {any} value - The value to check.\n * @returns {boolean} - True if the value is a non-null object.\n */\nexport function isObject(value: any): value is Record {\n return value !== null && typeof value === OBJECT;\n}\n\n/**\n * Shallowly serializes an object by converting its key-value pairs into a string representation.\n * This function does not recursively serialize nested objects.\n *\n * @param obj - The object to serialize.\n * @returns A string representation of the object's top-level properties.\n */\nexport function shallowSerialize(obj: Record): string {\n let result = '';\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n result += key + ':' + obj[key];\n }\n }\n\n return result;\n}\n\n/**\n * Removes properties that could lead to prototype pollution from an object.\n *\n * This function checks for dangerous properties like '__proto__', 'constructor',\n * and 'prototype'. If none are present, the object is returned as-is (zero-copy fast path).\n * Otherwise, a shallow copy is created with the dangerous properties removed.\n *\n * @param obj - The object to sanitize\n * @returns A safe object without dangerous properties\n */\nexport function sanitizeObject>(obj: T): T {\n const hasProto = Object.prototype.hasOwnProperty.call(obj, '__proto__');\n const hasCtor = Object.prototype.hasOwnProperty.call(obj, 'constructor');\n const hasPrototype = Object.prototype.hasOwnProperty.call(obj, 'prototype');\n\n if (!hasProto && !hasCtor && !hasPrototype) {\n return obj;\n }\n\n const safeObj = { ...obj };\n\n if (hasProto) delete safeObj.__proto__;\n if (hasCtor) delete (safeObj as any).constructor;\n if (hasPrototype) delete safeObj.prototype;\n\n return safeObj;\n}\n\n/**\n * Sorts the keys of an object and returns a new object with sorted keys.\n *\n * This function is optimized for performance by minimizing the number of object operations\n * and using a single pass to create the sorted object.\n *\n * @param {Object} obj - The object to be sorted by keys.\n * @returns {Object} - A new object with keys sorted in ascending order.\n */\nexport function sortObject(obj: Record): object {\n const keys = Object.keys(obj);\n\n keys.sort();\n\n const sortedObj = {} as Record;\n\n for (let i = 0, len = keys.length; i < len; i++) {\n const key = keys[i];\n\n sortedObj[key] = obj[key];\n }\n\n return sortedObj;\n}\n\n/**\n * Appends a query string to a URL, ensuring proper handling of existing query parameters.\n *\n * @param baseUrl - The base URL to which the query string will be appended.\n * @param queryString - The encoded query string to append.\n * @returns The URL with the appended query string, or the original URL if no query string is provided.\n */\nfunction appendQueryStringToUrl(baseUrl: string, queryString: string): string {\n if (!queryString) {\n return baseUrl;\n }\n\n return baseUrl.includes('?')\n ? `${baseUrl}&${queryString}`\n : `${baseUrl}?${queryString}`;\n}\n\n/**\n * Appends query parameters to a given URL.\n *\n * @param {string} url - The base URL to which query parameters will be appended.\n * @param {QueryParams} params - An object containing the query parameters to append.\n * @returns {string} - The URL with the appended query parameters.\n */\nexport function appendQueryParams(url: string, params: QueryParams): string {\n if (!params) {\n return url;\n }\n\n // Check if `params` is an instance of URLSearchParams and bail early if it is\n if (isSearchParams(params)) {\n const encodedQueryString = params.toString();\n\n return appendQueryStringToUrl(url, encodedQueryString);\n }\n\n // This is exact copy of what JQ used to do. It works much better than URLSearchParams\n const s: string[] = [];\n const encode = encodeURIComponent;\n const add = (k: string, v: any) => {\n v = typeof v === FUNCTION ? v() : v;\n v = v === null ? '' : v === undefined ? '' : v;\n s[s.length] = encode(k) + '=' + encode(v);\n };\n\n const buildParams = (prefix: string, obj: any, depth = 0) => {\n // Stop recursion if maximum depth is reached\n if (depth >= MAX_DEPTH) {\n return s;\n }\n\n let i: number, len: number, key: string;\n\n if (prefix) {\n if (Array.isArray(obj)) {\n for (i = 0, len = obj.length; i < len; i++) {\n buildParams(\n prefix + '[' + (typeof obj[i] === OBJECT && obj[i] ? i : '') + ']',\n obj[i],\n depth + 1,\n );\n }\n } else if (isObject(obj)) {\n for (key in obj) {\n buildParams(prefix + '[' + key + ']', obj[key], depth + 1);\n }\n } else {\n add(prefix, obj);\n }\n } else if (Array.isArray(obj)) {\n for (i = 0, len = obj.length; i < len; i++) {\n add(obj[i].name, obj[i].value);\n }\n } else {\n for (key in obj) {\n buildParams(key, obj[key], depth + 1);\n }\n }\n return s;\n };\n\n const queryStringParts = buildParams('', params).join('&');\n\n // Encode special characters as per RFC 3986, https://datatracker.ietf.org/doc/html/rfc3986\n // This is for compatibility with server frameworks that expect the literal notation\n const encodedQueryString = queryStringParts.replace(/%5B%5D/g, '[]'); // Keep '[]' for arrays\n\n return appendQueryStringToUrl(url, encodedQueryString);\n}\n\n/**\n * Replaces dynamic URI parameters in a URL string with values from the provided `urlPathParams` object.\n * Parameters in the URL are denoted by `:`, where `` is a key in `urlPathParams`.\n *\n * @param {string} url - The URL string containing placeholders in the format `:`.\n * @param {Object} urlPathParams - An object containing the parameter values to replace placeholders.\n * @param {string} urlPathParams.paramName - The value to replace the placeholder `:` in the URL.\n * @returns {string} - The URL string with placeholders replaced by corresponding values from `urlPathParams`.\n */\nexport function replaceUrlPathParams(\n url: string,\n urlPathParams: UrlPathParams,\n): string {\n if (!urlPathParams || url.indexOf(':') === -1) {\n return url;\n }\n\n // Use a single RegExp and avoid unnecessary casts and function calls\n // Precompute keys for faster lookup\n const params = urlPathParams as DefaultUrlParams;\n\n // Use a replacer function that avoids extra work\n return url.replace(/:([a-zA-Z0-9_]+)/g, (match, key) => {\n // Use hasOwnProperty for strict key existence check\n if (Object.prototype.hasOwnProperty.call(params, key)) {\n const value = params[key];\n\n // Only replace if value is not undefined or null\n if (value !== undefined && value !== null) {\n return encodeURIComponent(String(value));\n }\n }\n\n return match;\n });\n}\n\n/**\n * Determines whether the provided URL is absolute.\n *\n * An absolute URL contains a scheme (e.g., \"http://\", \"https://\").\n *\n * @param url - The URL string to check.\n * @returns `true` if the URL is absolute, otherwise `false`.\n */\nexport function isAbsoluteUrl(url: string): boolean {\n return url.includes('://');\n}\n\nexport const timeNow = () => Date.now();\n\nexport const noop = () => {};\n\n/**\n * Checks if a value is JSON serializable.\n *\n * JSON serializable values include:\n * - Primitive types: string, number, boolean, null\n * - Arrays\n * - Plain objects (i.e., objects without special methods)\n * - Values with a `toJSON` method\n *\n * @param {any} value - The value to check for JSON serializability.\n * @returns {boolean} - Returns `true` if the value is JSON serializable, otherwise `false`.\n */\nexport function isJSONSerializable(value: any): boolean {\n const t = typeof value;\n\n if (value === undefined || value === null) {\n return false;\n }\n\n if (t === STRING || t === 'number' || t === 'boolean') {\n return true;\n }\n\n if (Array.isArray(value)) {\n return true;\n }\n\n if (\n typeof globalThis !== UNDEFINED &&\n typeof globalThis.Buffer !== UNDEFINED &&\n globalThis.Buffer.isBuffer(value)\n ) {\n return false;\n }\n\n if (value instanceof Date || isSearchParams(value)) {\n return false;\n }\n\n if (isObject(value)) {\n const proto = Object.getPrototypeOf(value);\n\n // Check if the prototype is `Object.prototype` (plain object)\n if (proto === Object.prototype) {\n return true;\n }\n\n // Check if the object has a toJSON method\n if (typeof value.toJSON === FUNCTION) {\n return true;\n }\n }\n\n return false;\n}\n\nexport async function delayInvocation(ms: number): Promise {\n return new Promise((resolve) =>\n setTimeout(() => {\n return resolve(true);\n }, ms),\n );\n}\n\n/**\n * Recursively flattens the data object if it meets specific criteria.\n *\n * The method checks if the provided `data` is an object with exactly one property named `data`.\n * If so, it recursively flattens the `data` property. Otherwise, it returns the `data` as-is.\n *\n * @param {any} data - The data to be flattened. Can be of any type, including objects, arrays, or primitives.\n * @returns {any} - The flattened data if the criteria are met; otherwise, the original `data`.\n */\nexport function flattenData(data: any, depth = 0): any {\n if (depth >= MAX_DEPTH) {\n return data;\n }\n\n if (data && isObject(data) && typeof data.data !== UNDEFINED) {\n return flattenData(data.data, depth + 1);\n }\n\n return data;\n}\n\n/**\n * Processes headers and returns them as a normalized object.\n *\n * Handles both `Headers` instances and plain objects. Normalizes header keys to lowercase\n * as per RFC 2616 section 4.2.\n *\n * @param headers - The headers to process. Can be an instance of `Headers`, a plain object,\n * or `null`. If `null`, an empty object is returned.\n * @returns {HeadersObject} - A normalized headers object with lowercase keys.\n */\nexport function processHeaders(\n headers?: (HeadersObject & HeadersInit) | null | Headers,\n): HeadersObject {\n if (!headers) {\n return {};\n }\n\n const headersObject: HeadersObject = {};\n\n // Normalize keys to lowercase as per RFC 2616 4.2\n // https://datatracker.ietf.org/doc/html/rfc2616#section-4.2\n if (headers instanceof Headers) {\n headers.forEach((value, key) => {\n headersObject[key.toLowerCase()] = value;\n });\n } else if (isObject(headers)) {\n // Handle plain object — use for...in to avoid Object.entries() allocation\n for (const key in headers) {\n if (Object.prototype.hasOwnProperty.call(headers, key)) {\n headersObject[key.toLowerCase()] = headers[key];\n }\n }\n }\n\n return headersObject;\n}\n\n/**\n * Determines if the current environment is a browser.\n *\n * @returns {boolean} - True if running in a browser environment, false otherwise.\n */\nexport function isBrowser(): boolean {\n // For node and some mobile frameworks like React Native, `add/removeEventListener` doesn't exist on window!\n return (\n typeof window !== UNDEFINED && typeof window.addEventListener === FUNCTION\n );\n}\n\n/**\n * Creates an abort/timeout error compatible with all JS runtimes.\n * Falls back to a plain Error with the correct `name` when DOMException is unavailable (e.g. React Native).\n *\n * @param {string} message - The error message.\n * @param {string} name - The error name (e.g. 'AbortError', 'TimeoutError').\n * @returns {DOMException | Error} - An error object with the specified name.\n */\nexport function createAbortError(\n message: string,\n name: string,\n): DOMException | Error {\n if (typeof DOMException !== UNDEFINED) {\n return new DOMException(message, name);\n }\n\n const error = new Error(message);\n error.name = name;\n\n return error;\n}\n\n/**\n * Detects if the user is on a slow network connection\n * @returns {boolean} True if connection is slow, false otherwise or if detection unavailable\n */\nexport const isSlowConnection = (): boolean => {\n const conn = typeof navigator !== UNDEFINED && (navigator as any).connection;\n\n return conn && ['slow-2g', '2g', '3g'].includes(conn.effectiveType);\n};\n","import { FUNCTION } from './constants';\nimport type { InterceptorFunction } from './types/interceptor-manager';\nimport { isObject } from './utils';\n\n/**\n * Applies interceptors to the object. Interceptors can be a single function or an array of functions.\n *\n * @template T - Type of the object.\n * @template Args - Type of additional arguments.\n * @template I - Type of interceptors.\n *\n * @param {InterceptorFunction | InterceptorFunction[]} [interceptors] - Interceptor function(s).\n * @param {T} data - The data object to process.\n * @param {...Args} args - Additional arguments to pass to interceptors.\n *\n * @returns {Promise} - Nothing as the function is non-idempotent.\n */\nexport async function applyInterceptors<\n T extends object,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Args extends any[] = any[],\n I = InterceptorFunction | InterceptorFunction[],\n>(interceptors: I | undefined, data: T, ...args: Args): Promise {\n if (!interceptors) {\n return;\n }\n\n if (typeof interceptors === FUNCTION) {\n const value = await (interceptors as InterceptorFunction)(\n data,\n ...args,\n );\n\n if (value && isObject(data) && isObject(value)) {\n Object.assign(data, value);\n }\n } else if (Array.isArray(interceptors)) {\n for (const interceptor of interceptors) {\n const value = await interceptor(data, ...args);\n\n if (value && isObject(data) && isObject(value)) {\n Object.assign(data, value);\n }\n }\n }\n}\n","import type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '../types';\n\n/**\n * This is a base error class\n */\nexport class FetchError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n> extends Error {\n status: number;\n statusText: string;\n config: RequestConfig;\n isCancelled: boolean;\n\n constructor(\n message: string,\n public request: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n public response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n ) {\n super(message);\n\n this.name = 'FetchError';\n this.status = response ? response.status : 0;\n this.statusText = response ? response.statusText : '';\n this.config = request;\n this.isCancelled = false;\n }\n}\n","import { FetchError } from './fetch-error';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '../types';\n\nexport class ResponseError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n> extends FetchError {\n constructor(\n message: string,\n request: RequestConfig,\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n ) {\n super(message, request, response);\n\n this.name = 'ResponseError';\n }\n}\n","/**\n * @module timeout-wheel\n * @description\n * Ultra-minimal timing wheel implementation optimized for max performance & many requests.\n * For most of the cases it's 4-100x faster than setTimeout and setInterval alone.\n * Provides efficient scheduling and cancellation of timeouts using a circular array.\n *\n * Position 0 → 1 → 2 → ... → 599 → 0 → 1 → 2 ...\n * Time: 0s 1s 2s 599s 600s 601s 602s\n *\n * The timing wheel consists of 600 slots (one per second for 10 min).\n * Each slot contains a list of timeout items, each associated with a unique key and callback.\n * Timeouts are scheduled by placing them in the appropriate slot based on the delay in seconds.\n * The wheel advances every second, executing and removing callbacks as their timeouts expire.\n * Defaults to setTimeout if the delay exceeds 10 minutes or is not divisible by 1000.\n *\n * @remarks\n * - Designed for minimal footprint and simplicity.\n * - Only supports second-level granularity (minimum timeout: 1 second).\n * - Automatically stops the internal timer when no timeouts remain.\n */\n\nimport { noop } from './utils';\n\ntype TimeoutCallback = () => unknown | Promise;\ntype TimeoutItem = [string, TimeoutCallback]; // [key, callback]\n\nconst WHEEL_SIZE = 600; // 600 slots for 10 min (1 slot per second)\nconst SECOND = 1000; // 1 second in milliseconds\nconst MAX_WHEEL_MS = WHEEL_SIZE * SECOND;\nconst wheel: TimeoutItem[][] = Array(WHEEL_SIZE)\n .fill(0)\n .map(() => []);\n\nconst keyMap = new Map();\nlet position = 0;\nlet timer: NodeJS.Timeout | null = null;\n\nconst handleCallback = ([key, callback]: TimeoutItem): void => {\n keyMap.delete(key);\n\n try {\n const result = callback();\n if (result && result instanceof Promise) {\n // Silently ignore async errors to prevent wheel from stopping\n result.catch(noop);\n }\n } catch {\n // Ignore callback errors to prevent wheel from stopping\n }\n};\n\nexport const addTimeout = (\n key: string,\n cb: TimeoutCallback,\n ms: number,\n): void => {\n removeTimeout(key);\n\n // Fallback to setTimeout if wheel size is exceeded, ms is sub-second, or ms is not divisible by SECOND\n if (ms < SECOND || ms > MAX_WHEEL_MS || ms % SECOND !== 0) {\n keyMap.set(key, [setTimeout(handleCallback.bind(null, [key, cb]), ms)]); // Store timeout ID instead of slot\n\n return;\n }\n\n // No need for Math.ceil here since ms is guaranteed by modulo above\n const seconds = ms / SECOND;\n const slot = (position + seconds) % WHEEL_SIZE;\n\n wheel[slot].push([key, cb]);\n keyMap.set(key, slot);\n\n if (!timer) {\n timer = setInterval(() => {\n position = (position + 1) % WHEEL_SIZE;\n const slot = wheel[position];\n\n // Use slot.length directly (not cached) so mid-iteration mutations\n // from callbacks (e.g. removeTimeout) are handled correctly\n for (let i = 0; i < slot.length; i++) {\n handleCallback(slot[i]);\n }\n\n slot.length = 0; // Reuse array, avoid GC allocation\n\n if (!keyMap.size && timer) {\n clearInterval(timer);\n timer = null;\n }\n }, SECOND);\n }\n};\n\nexport const removeTimeout = (key: string): void => {\n const slotOrTimeout = keyMap.get(key);\n\n if (slotOrTimeout !== undefined) {\n // It's a Timeout object from setTimeout\n if (Array.isArray(slotOrTimeout)) {\n clearTimeout(slotOrTimeout[0]);\n } else {\n const slotArr = wheel[slotOrTimeout];\n const idx = slotArr.findIndex(([k]) => k === key);\n\n if (idx !== -1) {\n slotArr.splice(idx, 1);\n }\n }\n\n keyMap.delete(key);\n\n if (!keyMap.size && timer) {\n clearInterval(timer);\n timer = null;\n }\n }\n};\n\nexport const clearAllTimeouts = () => {\n // Clear native setTimeout timeouts first!\n keyMap.forEach((value) => {\n if (Array.isArray(value)) {\n clearTimeout(value[0]);\n }\n });\n\n if (timer) {\n clearInterval(timer);\n timer = null;\n }\n\n keyMap.clear();\n\n for (let i = 0; i < WHEEL_SIZE; i++) {\n wheel[i].length = 0;\n }\n\n position = 0;\n};\n","/**\n * @module inflight-manager\n *\n * Manages in-flight asynchronous requests using unique keys to enable deduplication and cancellation.\n *\n * Provides utilities for:\n * - Deduplication of requests within a configurable time window (`dedupeTime`)\n * - Timeout management and automatic request abortion\n * - AbortController lifecycle and cancellation logic\n * - Concurrency control and request state tracking\n * - In-flight promise deduplication to prevent duplicate network calls\n *\n * @remarks\n * - Requests with the same key within the deduplication interval share the same AbortController and in-flight promise.\n * - Supports cancellation of previous requests when a new one with the same key is issued, if `isCancellable` is enabled.\n * - Timeout logic ensures requests are aborted after a specified duration, if enabled.\n * - Internal queue state is managed via a Map, keyed by request identifier.\n * - Polled requests are also marked as \"in-flight\" to prevent duplicate requests.\n */\n\nimport { ABORT_ERROR, TIMEOUT_ERROR } from './constants';\nimport { addTimeout, removeTimeout } from './timeout-wheel';\nimport { createAbortError, timeNow } from './utils';\n\nexport type InFlightItem = [\n AbortController, // AbortController for the request\n boolean, // Whether timeout is enabled for the request\n number, // Timestamp when the request was marked in-flight\n boolean, // isCancellable - whether the request can be cancelled\n Promise | null, // Optional in-flight promise for deduplication\n];\n\nconst inFlight: Map = new Map();\n\n/**\n * Adds a request to the queue if it's not already being processed within the dedupeTime interval.\n *\n * @param {string | null} key - Unique key for the request (e.g. cache key).\n * @param {string} url - The request URL (for error messages/timeouts).\n * @param {number} timeout - Timeout in milliseconds for the request.\n * @param {number} dedupeTime - Deduplication time in milliseconds.\n * @param {boolean} isCancellable - If true, then the previous request with same configuration should be aborted.\n * @param {boolean} isTimeoutEnabled - Whether timeout is enabled.\n * @returns {AbortController} - A promise that resolves to an AbortController.\n */\nexport function markInFlight(\n key: string | null,\n url: string,\n timeout: number | undefined,\n dedupeTime: number,\n isCancellable: boolean,\n isTimeoutEnabled: boolean,\n): AbortController {\n if (!key) {\n return new AbortController();\n }\n\n const now = timeNow();\n const item = inFlight.get(key);\n let prevPromise: Promise | null = null;\n\n // Previous request is in-flight, check if we can reuse it\n if (item) {\n const prevController = item[0];\n const prevIsCancellable = item[3];\n\n // If the request is already in the queue and within the dedupeTime, reuse the existing controller\n if (\n !prevIsCancellable &&\n now - item[2] < dedupeTime &&\n !prevController.signal.aborted\n ) {\n return prevController;\n }\n\n // If the request is too old, remove it and proceed to add a new one\n // Abort previous request, if applicable, and continue as usual\n if (prevIsCancellable) {\n prevController.abort(\n createAbortError('Aborted due to new request', ABORT_ERROR),\n );\n }\n\n removeTimeout(key);\n prevPromise = item[4];\n }\n\n const controller = new AbortController();\n\n inFlight.set(key, [\n controller,\n isTimeoutEnabled,\n now,\n isCancellable,\n prevPromise,\n ]);\n\n if (isTimeoutEnabled) {\n addTimeout(\n key,\n () => {\n abortRequest(\n key,\n createAbortError(url + ' aborted due to timeout', TIMEOUT_ERROR),\n );\n },\n timeout as number,\n );\n }\n\n return controller;\n}\n\n/**\n * Removes a request from the queue and clears its timeout.\n *\n * @param key - Unique key for the request.\n * @param {boolean} error - Optional error to abort the request with. If null, the request is simply removed but no abort sent.\n * @returns {Promise} - A promise that resolves when the request is aborted and removed.\n */\nexport async function abortRequest(\n key: string | null,\n error: DOMException | Error | null | string = null,\n): Promise {\n // If the key is not in the queue, there's nothing to remove\n if (key) {\n const item = inFlight.get(key);\n\n if (item) {\n // If the request is not yet aborted, abort it with the provided error\n if (error) {\n const controller = item[0];\n controller.abort(error);\n }\n\n removeInFlight(key);\n }\n }\n}\n\n/**\n * Removes a request from the in-flight queue without aborting or clearing timeout.\n *\n * @param key - Unique key for the request.\n */\nexport function removeInFlight(key: string | null): void {\n removeTimeout(key!);\n inFlight.delete(key!);\n}\n\n/**\n * Gets the AbortController for a request key.\n *\n * @param key - Unique key for the request.\n * @returns {AbortController | undefined} - The AbortController or undefined.\n */\nexport async function getController(\n key: string,\n): Promise {\n const item = inFlight.get(key);\n\n return item?.[0];\n}\n\n/**\n * Adds helpers for in-flight promise deduplication.\n *\n * @param key - Unique key for the request.\n * @param promise - The promise to store.\n */\nexport function setInFlightPromise(\n key: string,\n promise: Promise,\n): void {\n const item = inFlight.get(key);\n if (item) {\n // store the promise at index 4 — item is already the Map's reference, no need to re-set\n item[4] = promise;\n }\n}\n\n/**\n * Retrieves the in-flight promise for a request key if it exists and is within the dedupeTime interval.\n *\n * @param key - Unique key for the request.\n * @param dedupeTime - Deduplication time in milliseconds.\n * @returns {Promise | null} - The in-flight promise or null.\n */\nexport function getInFlightPromise(\n key: string | null,\n dedupeTime: number,\n): Promise | null {\n if (!key) {\n return null;\n }\n\n const prevReq = inFlight.get(key);\n\n if (\n prevReq &&\n // If the request is in-flight and has a promise\n prevReq[4] &&\n // If the request is cancellable, we will not reuse it\n !prevReq[3] &&\n // If the request is within the dedupeTime\n timeNow() - prevReq[2] < dedupeTime &&\n // If one request is cancelled, ALL deduped requests get cancelled\n !prevReq[0].signal.aborted\n ) {\n return prevReq[4] as Promise;\n }\n\n return null;\n}\n","const PRIME_MULTIPLIER = 31;\n\n/**\n * Computes a hash value for a given string using the variant of djb2 hash function.\n * This hash function is non-cryptographic and designed for speed.\n * @author Daniel J. Bernstein (of djb2)\n *\n * @param str Input string to hash\n * @returns {string} Hash\n */\nexport function hash(str: string): string {\n let hash = 0;\n\n for (let i = 0, len = str.length; i < len; i++) {\n const char = str.charCodeAt(i);\n hash = (hash * PRIME_MULTIPLIER + char) | 0;\n }\n\n return String(hash);\n}\n","/**\n * @module revalidator-manager\n *\n * Provides utilities for managing cache revalidation functions, including:\n * - Registering and unregistering revalidators for specific cache keys.\n * - Triggering revalidation for a given key.\n * - Enabling or disabling automatic revalidation on window focus and if user comes back online for specific keys.\n * - Attaching and removing global focus and online event handlers to trigger revalidation.\n *\n * Revalidators are functions that can be registered to revalidate cache entries when needed.\n * They are typically used to refresh data in the cache when the window gains focus or when specific actions occur.\n * @performance O(1) lookup by key makes it blazing fast to register, unregister, and revalidate cache entries.\n * - Designed for high performance: minimizes unnecessary re-renders and leverages fast cache key generation.\n * - Integrates with a global cache and pub/sub system for efficient state updates across contexts.\n * - Handles automatic revalidation, deduplication, retries, and cache management out of the box.\n * @remarks\n * - Designed to be used in various environments (Deno, Node.js, Bun, Browser, etc.) to ensure cache consistency and freshness.\n */\nimport { addTimeout, removeTimeout } from './timeout-wheel';\nimport { FetchResponse } from './types';\nimport { isBrowser, noop, timeNow } from './utils';\n\nexport type RevalidatorFn = (\n isStaleRevalidation?: boolean,\n) => Promise;\n\ntype EventType = 'focus' | 'online';\n\ntype RevalidatorEntry = [\n RevalidatorFn, // main revalidator\n number, // lastUsed\n number, // ttl\n number?, // staleTime\n RevalidatorFn?, // bgRevalidator\n boolean?, // refetchOnFocus\n boolean?, // refetchOnReconnect\n];\n\nconst DEFAULT_TTL = 3 * 60 * 1000; // Default TTL of 3 minutes\nconst revalidators = new Map();\n\n/**\n * Stores cleanup functions for active event handlers (browser or custom providers).\n * Each entry removes the corresponding event listener when called.\n * @remarks\n * - Improves performance by reducing the number of event listeners.\n * - Enables efficient O(1) lookup and management of event handlers for revalidation.\n */\nconst eventHandlers = new Map void>();\n\n/** Subscribe to an event and return a cleanup function */\nexport type EventProvider = (handler: () => void) => () => void;\n\nconst customEventProviders = new Map();\n\n/**\n * Registers a custom event provider for 'focus' or 'online' events.\n * Useful for non-browser environments like React Native.\n *\n * @param type - The event type ('focus' or 'online').\n * @param provider - A function that subscribes to the event and returns a cleanup function.\n */\nexport function setEventProvider(\n type: EventType,\n provider: EventProvider,\n): void {\n customEventProviders.set(type, provider);\n\n // Re-register if already active\n if (eventHandlers.has(type)) {\n removeEventHandler(type);\n addEventHandler(type);\n }\n}\n\n/**\n * Triggers revalidation for all registered entries based on the given event type.\n * For example, if it's a 'focus' event, it will revalidate entries that have the `refetchOnFocus` flag set.\n * Updates the timestamp and invokes the revalidator function for each applicable entry.\n *\n * @param type - The type of event that caused the revalidation (e.g., 'focus' or 'online').\n * @param isStaleRevalidation - If `true`, uses background revalidator and doesn't mark as in-flight.\n */\nexport function revalidateAll(\n type: EventType,\n isStaleRevalidation: boolean = true,\n) {\n const flagIndex = type === 'focus' ? 5 : 6;\n const now = timeNow();\n\n revalidators.forEach((entry) => {\n if (!entry[flagIndex]) {\n return;\n }\n\n entry[1] = now;\n\n // If it's a stale revalidation, use the background revalidator function\n const revalidator = isStaleRevalidation ? entry[4] : entry[0];\n\n if (revalidator) {\n Promise.resolve(revalidator(isStaleRevalidation)).catch(noop);\n }\n });\n}\n\n/**\n * Revalidates an entry by executing the registered revalidation function.\n *\n * @param key The unique identifier for the cache entry to revalidate. If `null`, no revalidation occurs.\n * @param isStaleRevalidation - If `true`, it does not mark revalidated requests as in-flight.\n * @returns A promise that resolves to the result of the revalidator function, or\n * `null` if no key or revalidator is found, or a `FetchResponse` if applicable.\n */\nexport async function revalidate(\n key: string | null,\n isStaleRevalidation: boolean = false,\n): Promise {\n // If no key is provided, no revalidation occurs\n if (!key) {\n return null;\n }\n\n const entry = revalidators.get(key);\n\n if (entry) {\n // Update only the lastUsed timestamp without resetting the whole array\n entry[1] = timeNow();\n\n const revalidator = isStaleRevalidation ? entry[4] : entry[0];\n\n // If no revalidator function is registered, return null\n if (revalidator) {\n return await revalidator(isStaleRevalidation);\n }\n }\n\n // If no revalidator is registered for the key, return null\n return null;\n}\n\n/**\n * Removes all revalidators associated with the specified event type.\n *\n * @param type - The event type whose revalidators should be removed.\n */\nexport function removeRevalidators(type: EventType) {\n removeEventHandler(type);\n\n const flagIndex = type === 'focus' ? 5 : 6;\n\n // Clear all revalidators with this flag\n revalidators.forEach((entry, key) => {\n if (entry[flagIndex]) {\n removeRevalidator(key);\n }\n });\n}\n\n/**\n * Registers a generic revalidation event handler for the specified event type.\n * Supports browser window events and custom event providers (e.g. for React Native).\n * Ensures the handler is only added once.\n *\n * @param event - The type of event to listen for (e.g., 'focus', 'online').\n */\nfunction addEventHandler(event: EventType) {\n if (eventHandlers.has(event)) {\n return;\n }\n\n const handler = revalidateAll.bind(null, event, true);\n\n // Priority 1: Custom event provider (works in any environment including React Native)\n const customProvider = customEventProviders.get(event);\n\n if (customProvider) {\n const cleanup = customProvider(handler);\n\n eventHandlers.set(event, cleanup);\n\n return;\n }\n\n // Priority 2: Browser window events\n if (isBrowser()) {\n window.addEventListener(event, handler);\n\n eventHandlers.set(event, () => window.removeEventListener(event, handler));\n }\n}\n\n/**\n * Removes the event handler for the specified event type.\n *\n * @param event - The type of event whose handler should be removed.\n */\nfunction removeEventHandler(event: EventType) {\n const cleanup = eventHandlers.get(event);\n\n if (cleanup) {\n cleanup();\n eventHandlers.delete(event);\n }\n}\n\n/**\n * Registers a revalidation functions for a specific cache key.\n *\n * @param {string} key Cache key to utilize\n * @param {RevalidatorFn} revalidatorFn Main revalidation function (marks in-flight requests)\n * @param {number} [ttl] Time to live in milliseconds (default: 3 minutes)\n * @param {number} [staleTime] Time (in seconds) after which the cache entry is considered stale\n * @param {RevalidatorFn} [bgRevalidatorFn] For stale revalidation (does not mark in-flight requests)\n * @param {boolean} [refetchOnFocus] Whether to revalidate on window focus\n * @param {boolean} [refetchOnReconnect] Whether to revalidate on network reconnect\n */\nexport function addRevalidator(\n key: string,\n revalidatorFn: RevalidatorFn, // Main revalidation function (marks in-flight requests)\n ttl?: number,\n staleTime?: number,\n bgRevalidatorFn?: RevalidatorFn, // For stale revalidation (does not mark in-flight requests)\n refetchOnFocus?: boolean,\n refetchOnReconnect?: boolean,\n) {\n const existing = revalidators.get(key);\n\n if (existing) {\n // Update in-place to avoid allocating a new tuple array\n existing[0] = revalidatorFn;\n existing[1] = timeNow();\n existing[2] = ttl ?? DEFAULT_TTL;\n existing[3] = staleTime;\n existing[4] = bgRevalidatorFn;\n existing[5] = refetchOnFocus;\n existing[6] = refetchOnReconnect;\n } else {\n revalidators.set(key, [\n revalidatorFn,\n timeNow(),\n ttl ?? DEFAULT_TTL,\n staleTime,\n bgRevalidatorFn,\n refetchOnFocus,\n refetchOnReconnect,\n ]);\n }\n\n if (refetchOnFocus) {\n addEventHandler('focus');\n }\n\n if (refetchOnReconnect) {\n addEventHandler('online');\n }\n\n if (staleTime) {\n addTimeout('s:' + key, revalidate.bind(null, key, true), staleTime * 1000);\n }\n}\n\nexport function removeRevalidator(key: string) {\n revalidators.delete(key);\n\n // Clean up stale timer\n removeTimeout('s:' + key);\n}\n\n/**\n * Periodically cleans up expired revalidators from the registry.\n * Removes any revalidator whose TTL has expired.\n *\n * @param {number} intervalMs How often to run cleanup (default: 3 minutes)\n * @returns {() => void} A function to stop the periodic cleanup\n */\nexport function startRevalidatorCleanup(\n intervalMs: number = DEFAULT_TTL,\n): () => void {\n const intervalId = setInterval(() => {\n const now = timeNow();\n\n revalidators.forEach(\n ([, lastUsed, ttl, , , refetchOnFocus, refetchOnReconnect], key) => {\n // Skip focus-only or reconnect-only revalidators to keep them alive\n if (refetchOnFocus || refetchOnReconnect) {\n return;\n }\n\n if (ttl > 0 && now - lastUsed > ttl) {\n removeRevalidator(key);\n }\n },\n );\n }, intervalMs);\n\n return () => clearInterval(intervalId);\n}\n","/**\n * Manages a set of listeners (subscribers) for arbitrary string keys, allowing cross-context or cross-component\n * cache updates and synchronization. Provides functions to add, remove, and notify listeners, as well as a\n * convenient subscribe/unsubscribe API.\n *\n * @template T - The type of the response object passed to listeners.\n *\n * @remarks\n * - Listeners are grouped by a string key, which typically represents a cache key or resource identifier.\n * - When `notifySubscribers` is called for a key, all listeners registered for that key are invoked with the provided response.\n * - The `subscribe` function returns an unsubscribe function for convenient cleanup.\n *\n * @example\n * ```ts\n * const unsubscribe = subscribe('user:123', (response) => {\n * // handle updated data\n * });\n * // Later, to stop listening:\n * unsubscribe();\n * ```\n */\n\nimport { noop } from './utils';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Listener = (response: T) => void;\n\nconst listeners = new Map>();\n\nfunction ensureListenerSet(key: string) {\n let set = listeners.get(key);\n\n if (!set) {\n set = new Set();\n listeners.set(key, set);\n }\n\n return set;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function addListener(key: string, fn: Listener): void {\n ensureListenerSet(key).add(fn);\n}\n\nexport function removeListener(key: string, fn: Listener) {\n const set = listeners.get(key);\n\n if (set) {\n set.delete(fn);\n\n // If the set is empty, remove the key from the listeners map\n if (set.size === 0) {\n listeners.delete(key);\n }\n }\n}\n\nexport function notifySubscribers(key: string, response: T) {\n const fns = listeners.get(key);\n\n if (fns) {\n if (fns.size === 1) {\n // If there's only one listener, call it directly\n const fn = fns.values().next().value;\n fn!(response);\n } else {\n fns.forEach((fn) => fn(response));\n }\n }\n}\n\nexport function subscribe(key: string | null, fn: (response: T) => void) {\n if (!key) {\n // No op if no key is provided\n return noop;\n }\n\n addListener(key, fn);\n\n // Return an unsubscribe function\n return () => {\n removeListener(key, fn);\n };\n}\n","import { processHeaders } from './utils';\nimport {\n GET,\n APPLICATION_JSON,\n HEAD,\n STRING,\n CHARSET_UTF_8,\n CONTENT_TYPE,\n REJECT,\n UNDEFINED,\n APPLICATION_CONTENT_TYPE,\n} from './constants';\nimport type {\n HeadersObject,\n Method,\n RequestConfig,\n} from './types/request-handler';\nimport {\n replaceUrlPathParams,\n appendQueryParams,\n isSearchParams,\n isJSONSerializable,\n isSlowConnection,\n isAbsoluteUrl,\n sanitizeObject,\n isObject,\n} from './utils';\n\nconst defaultTimeoutMs = (isSlowConnection() ? 60 : 30) * 1000;\n\nexport const defaultConfig: RequestConfig = {\n strategy: REJECT,\n timeout: defaultTimeoutMs, // 30 seconds (60 on slow connections)\n headers: {\n Accept: APPLICATION_JSON + ', text/plain, */*',\n 'Accept-Encoding': 'gzip, deflate, br',\n },\n retry: {\n delay: defaultTimeoutMs / 30, // 1 second (2 on slow connections)\n maxDelay: defaultTimeoutMs, // 30 seconds (60 on slow connections)\n resetTimeout: true,\n backoff: 1.5,\n\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status\n retryOn: [\n 408, // Request Timeout\n 409, // Conflict\n 425, // Too Early\n 429, // Too Many Requests\n 500, // Internal Server Error\n 502, // Bad Gateway\n 503, // Service Unavailable\n 504, // Gateway Timeout\n ],\n },\n};\n\n/**\n * Overwrites the default configuration with the provided custom configuration.\n *\n * @param {Partial} customConfig - The custom configuration to merge into the default config.\n * @returns {Partial} - The updated default configuration object.\n */\nexport function setDefaultConfig(\n customConfig: Partial,\n): Partial {\n const sanitized = sanitizeObject(customConfig);\n\n return mergeConfigs({}, sanitized, defaultConfig);\n}\n\n/**\n * Returns a shallow copy of the current default configuration.\n *\n * @returns {RequestConfig} - The current default configuration.\n */\nexport function getDefaultConfig(): RequestConfig {\n return { ...defaultConfig };\n}\n\n/**\n * Build request configuration from defaults and overrides.\n * This function merges the default configuration with the provided request configuration,\n * @param {string} url - Request url\n * @param {RequestConfig | null | undefined} reqConfig - Request configuration\n * @return {RequestConfig} - Merged request configuration\n */\nexport function buildConfig(\n url: string,\n reqConfig?: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > | null,\n): RequestConfig {\n if (!reqConfig) {\n return buildFetcherConfig(url, getDefaultConfig());\n }\n\n const sanitized = sanitizeObject(reqConfig);\n const merged = mergeConfigs(defaultConfig, sanitized);\n\n return buildFetcherConfig(url, merged);\n}\n\n/**\n * Builds the fetcher configuration by setting the method, body, headers, and URL.\n * It also handles query parameters and path parameters. This fn mutates the passed `requestConfig` object.\n * @param {string} url - The endpoint URL to which the request will be sent.\n * @param {RequestConfig} requestConfig - The request configuration object containing method, body, headers, and other options.\n * @return {RequestConfig} - The modified request configuration object with the URL, method, body, and headers set appropriately.\n **/\nexport function buildFetcherConfig(\n url: string,\n requestConfig: RequestConfig,\n): RequestConfig {\n let method = requestConfig.method as Method;\n method = method ? (method.toUpperCase() as Method) : GET;\n\n let body: RequestConfig['data'] | undefined;\n\n // Only applicable for request methods 'PUT', 'POST', 'DELETE', and 'PATCH'\n if (method !== GET && method !== HEAD) {\n body = requestConfig.body ?? requestConfig.data;\n\n // Automatically stringify request body, if possible and when not dealing with strings\n if (body && typeof body !== STRING && isJSONSerializable(body)) {\n body = JSON.stringify(body);\n }\n }\n\n setContentTypeIfNeeded(requestConfig.headers, body);\n\n // Native fetch compatible settings\n const credentials = requestConfig.withCredentials\n ? 'include'\n : requestConfig.credentials;\n\n // The explicitly passed query params\n const dynamicUrl = replaceUrlPathParams(url, requestConfig.urlPathParams);\n const urlPath = appendQueryParams(dynamicUrl, requestConfig.params);\n const isFullUrl = isAbsoluteUrl(url);\n const baseURL = isFullUrl\n ? ''\n : requestConfig.baseURL || requestConfig.apiUrl || '';\n\n requestConfig.url = baseURL + urlPath;\n requestConfig.method = method;\n requestConfig.credentials = credentials;\n requestConfig.body = body;\n\n return requestConfig;\n}\n\n/**\n * Ensures the `Content-Type` header is set to `application/json; charset=utf-8`\n * if it is not already present and the request method and body meet specific conditions.\n *\n * @param headers - The headers object to modify. Can be an instance of `Headers`\n * or a plain object conforming to `HeadersInit`.\n * @param body - The optional body of the request. If no body is provided and the\n * method is 'GET' or 'HEAD', the function exits without modifying headers.\n */\nfunction setContentTypeIfNeeded(\n headers?: HeadersInit | HeadersObject,\n body?: unknown,\n): void {\n // If no headers are provided, or if the body is not set and the method is PUT or DELETE, do nothing\n if (!headers || !body) {\n return;\n }\n\n // Types that should not have Content-Type set (browser handles these)\n if (\n body instanceof FormData || // Browser automatically sets multipart/form-data with boundary\n (typeof Blob !== UNDEFINED && body instanceof Blob) || // Blob/File already have their own MIME types, don't override\n (typeof File !== UNDEFINED && body instanceof File) ||\n (typeof ReadableStream !== UNDEFINED && body instanceof ReadableStream) // Stream type should be determined by the stream source\n ) {\n return;\n }\n\n let contentTypeValue: string;\n\n if (isSearchParams(body)) {\n contentTypeValue = APPLICATION_CONTENT_TYPE + 'x-www-form-urlencoded';\n } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {\n contentTypeValue = APPLICATION_CONTENT_TYPE + 'octet-stream';\n } else if (isJSONSerializable(body)) {\n contentTypeValue = APPLICATION_JSON + ';' + CHARSET_UTF_8;\n } else {\n // Do not set Content-Type if content is not recognizable\n return;\n }\n\n if (headers instanceof Headers) {\n if (!headers.has(CONTENT_TYPE)) {\n headers.set(CONTENT_TYPE, contentTypeValue);\n }\n } else if (\n isObject(headers) &&\n !Array.isArray(headers) &&\n !headers[CONTENT_TYPE]\n ) {\n headers[CONTENT_TYPE] = contentTypeValue;\n }\n}\n\n/**\n * Merges two request configurations, applying overrides from the second config to the first.\n * Handles special merging for nested properties like 'retry' and 'headers' (deep merge),\n * and concatenates interceptor arrays for 'onRequest', 'onResponse', and 'onError'.\n * If a target config is provided, it mutates that object; otherwise, creates a new one.\n *\n * @param {RequestConfig} baseConfig - The base configuration object to merge from.\n * @param {RequestConfig} overrideConfig - The override configuration object to apply on top of the base.\n * @param {RequestConfig} [targetConfig={}] - Optional target configuration object to merge into (mutated in place).\n * @returns {RequestConfig} The merged configuration object.\n *\n * @example\n * const base = { timeout: 5000, headers: { 'Accept': 'application/json' } };\n * const override = { timeout: 10000, headers: { 'Authorization': 'Bearer token' } };\n * const merged = mergeConfigs(base, override);\n * // Result: { timeout: 10000, headers: { Accept: 'application/json', Authorization: 'Bearer token' } }\n */\nexport function mergeConfigs(\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n targetConfig: RequestConfig = {},\n): RequestConfig {\n Object.assign(targetConfig, baseConfig, overrideConfig);\n\n // Ensure that retry and headers are merged correctly\n mergeConfig('retry', baseConfig, overrideConfig, targetConfig);\n mergeConfig('headers', baseConfig, overrideConfig, targetConfig);\n\n // Merge interceptors efficiently\n mergeInterceptors('onRequest', baseConfig, overrideConfig, targetConfig);\n mergeInterceptors('onResponse', baseConfig, overrideConfig, targetConfig);\n mergeInterceptors('onError', baseConfig, overrideConfig, targetConfig);\n\n return targetConfig;\n}\n\n/**\n * Efficiently merges interceptor functions from base and new configs\n */\nfunction mergeInterceptors<\n K extends 'onRequest' | 'onResponse' | 'onError' | 'onRetry',\n>(\n property: K,\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n targetConfig: RequestConfig,\n): void {\n const baseInterceptor = baseConfig[property];\n const newInterceptor = overrideConfig[property];\n\n if (!baseInterceptor && !newInterceptor) {\n return;\n }\n\n if (!baseInterceptor) {\n targetConfig[property] = newInterceptor;\n return;\n }\n\n if (!newInterceptor) {\n targetConfig[property] = baseInterceptor;\n return;\n }\n\n const baseArr = Array.isArray(baseInterceptor)\n ? baseInterceptor\n : [baseInterceptor];\n const newArr = Array.isArray(newInterceptor)\n ? newInterceptor\n : [newInterceptor];\n\n // This is the only LIFO interceptor, so we apply it after the response is prepared\n targetConfig[property] =\n property === 'onResponse' ? newArr.concat(baseArr) : baseArr.concat(newArr);\n}\n\n/**\n * Merges the specified property from the base configuration and the override configuration into the target configuration.\n *\n * @param {K} property - The property key to merge from the base and override configurations. Must be a key of RequestConfig.\n * @param {RequestConfig} baseConfig - The base configuration object that provides default values.\n * @param {RequestConfig} overrideConfig - The override configuration object that contains user-specific settings to merge.\n * @param {RequestConfig} targetConfig - The configuration object that will receive the merged properties.\n */\nexport function mergeConfig(\n property: K,\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n targetConfig: RequestConfig,\n): void {\n if (overrideConfig[property]) {\n const base = baseConfig[property];\n const override = overrideConfig[property];\n\n // Handle Headers instances which don't expose entries as own enumerable properties\n if (\n property === 'headers' &&\n ((base as Headers | (HeadersObject & HeadersInit)) instanceof Headers ||\n (override as Headers | (HeadersObject & HeadersInit)) instanceof\n Headers)\n ) {\n const baseNormalized = processHeaders(base);\n const overrideNormalized = processHeaders(override);\n targetConfig[property] = {\n ...baseNormalized,\n ...overrideNormalized,\n } as RequestConfig[K];\n } else {\n targetConfig[property] = {\n ...base,\n ...override,\n };\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { hash } from './hash';\nimport type {\n CacheKeyFunction,\n DefaultResponse,\n FetchResponse,\n MutationSettings,\n RequestConfig,\n} from './types/request-handler';\nimport type { CacheEntry } from './types/cache-manager';\nimport { GET, STRING, UNDEFINED } from './constants';\nimport { isObject, sanitizeObject, sortObject, timeNow } from './utils';\nimport { revalidate } from './revalidator-manager';\nimport { notifySubscribers } from './pubsub-manager';\nimport type { DefaultPayload, DefaultParams, DefaultUrlParams } from './types';\nimport { removeInFlight } from './inflight-manager';\nimport { addTimeout } from './timeout-wheel';\nimport { defaultConfig } from './config-handler';\nimport { processHeaders } from './utils';\n\nexport const IMMEDIATE_DISCARD_CACHE_TIME = 0; // Use it for cache entries that need to be persistent until unused by components or manually deleted\n\nconst _cache = new Map>();\nconst DELIMITER = '|';\nconst MIN_LENGTH_TO_HASH = 64;\nconst CACHE_KEY_SANITIZE_PATTERN = /[^\\w\\-_|/:@.?=&~%#]/g;\nconst CACHE_KEY_NEEDS_SANITIZE = /[^\\w\\-_|/:@.?=&~%#]/; // Non-global for fast test\n\n/**\n * Headers that may affect HTTP response content and should be included in cache key generation.\n * All header names must be lowercase to match normalized request headers.\n */\nconst CACHE_KEY_HEADER_WHITELIST = new Set([\n // Content negotiation\n 'accept', // Affects response format (e.g. JSON, HTML)\n 'accept-language', // Affects localization of the response\n 'accept-encoding', // Affects response compression (e.g. gzip, br)\n\n // Authentication\n 'authorization', // Affects access to protected resources\n\n // Request body metadata\n 'content-type', // Affects how the request body is interpreted\n\n // Optional headers\n 'referer', // May influence behavior in some APIs\n 'origin', // Relevant in CORS or tenant-specific APIs\n 'user-agent', // Included only for reason if server returns client-specific content\n\n // Cookies — only if server uses session-based responses\n 'cookie', // Can fragment cache heavily; use only if necessary\n\n // Custom headers that may affect response content\n 'x-api-key', // Token-based access, often affects authorization\n 'x-requested-with', // AJAX requests (used historically for distinguishing frontend calls)\n 'x-client-id', // Per-client/partner identity; often used in multi-tenant APIs\n 'x-tenant-id', // Multi-tenant segmentation; often changes response per tenant\n 'x-user-id', // Explicit user context (less common, but may exist)\n\n 'x-app-version', // Used for version-specific behavior (e.g. mobile apps)\n 'x-feature-flag', // Controls feature rollout behavior server-side\n 'x-device-id', // Used when response varies per device/app instance\n 'x-platform', // e.g. 'ios', 'android', 'web' — used in apps that serve different content\n\n 'x-session-id', // Only if backend uses it to affect the response directly (rare)\n 'x-locale', // Sometimes used in addition to or instead of `accept-language`\n]);\n\n/**\n * Generates a unique cache key for a given URL and fetch options, ensuring that key factors\n * like method, headers, body, and other options are included in the cache key.\n * Headers and other objects are sorted by key to ensure consistent cache keys.\n *\n * @param {RequestConfig} config - The fetch options that may affect the request. The most important are:\n * @property {string} [method=\"GET\"] - The HTTP method (GET, POST, etc.).\n * @property {HeadersInit} [headers={}] - The request headers.\n * @property {BodyInit | null} [body=\"\"] - The body of the request (only for methods like POST, PUT).\n * @property {RequestCredentials} [credentials=\"same-origin\"] - Whether to include credentials (include, same-origin, omit).\n * @property {RequestCache} [cache=\"default\"] - The cache mode (e.g., default, no-store, reload).\n * @returns {string} - A unique cache key string based on the provided options.\n *\n * @example\n * const cacheKey = generateCacheKey({\n * url: 'https://api.example.com/data',\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ name: 'Alice' }),\n * mode: 'cors',\n * credentials: 'include',\n * });\n * console.log(cacheKey);\n */\nexport function generateCacheKey(\n config: RequestConfig,\n cacheKeyCheck = true,\n): string {\n // This is super fast. Effectively a no-op if cacheKey is\n // a string or a function that returns a string.\n const key = config.cacheKey;\n\n if (key && cacheKeyCheck) {\n return typeof key === STRING\n ? (key as string)\n : (key as CacheKeyFunction)(config);\n }\n\n const {\n url = '',\n method = GET,\n headers = null,\n body = null,\n credentials = 'same-origin',\n } = config;\n\n // Sort headers and body + convert sorted to strings for hashing purposes\n // Native serializer is on avg. 3.5x faster than a Fast Hash or FNV-1a\n let headersString = '';\n if (headers) {\n let obj: Record;\n\n if (headers instanceof Headers) {\n obj = processHeaders(headers);\n } else {\n obj = headers as Record;\n }\n\n // Filter headers to only include those that affect request identity\n // Include only headers that affect request identity, not execution behavior\n const keys = Object.keys(obj);\n const len = keys.length;\n\n // Sort keys manually for fastest deterministic output\n if (len > 1) {\n keys.sort();\n }\n\n let str = '';\n for (let i = 0; i < len; ++i) {\n if (CACHE_KEY_HEADER_WHITELIST.has(keys[i].toLowerCase())) {\n str += keys[i] + ':' + obj[keys[i]] + ';';\n }\n }\n\n headersString = hash(str);\n }\n\n // For GET requests, return early with shorter cache key\n if (method === GET) {\n const cacheStr =\n method +\n DELIMITER +\n url +\n DELIMITER +\n credentials +\n DELIMITER +\n headersString;\n\n return CACHE_KEY_NEEDS_SANITIZE.test(cacheStr)\n ? cacheStr.replace(CACHE_KEY_SANITIZE_PATTERN, '')\n : cacheStr;\n }\n\n let bodyString = '';\n if (body) {\n if (typeof body === STRING) {\n bodyString = body.length < MIN_LENGTH_TO_HASH ? body : hash(body); // hash only if large\n } else if (body instanceof FormData) {\n body.forEach((value, key) => {\n // Append key=value and '&' directly to the result\n bodyString += key + '=' + value + '&';\n });\n\n if (bodyString.length > MIN_LENGTH_TO_HASH) {\n bodyString = hash(bodyString);\n }\n } else if (\n (typeof Blob !== UNDEFINED && body instanceof Blob) ||\n (typeof File !== UNDEFINED && body instanceof File)\n ) {\n bodyString = 'BF' + body.size + body.type;\n } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {\n bodyString = 'AB' + body.byteLength;\n } else {\n const o = isObject(body)\n ? JSON.stringify(sortObject(body))\n : String(body);\n\n bodyString = o.length > MIN_LENGTH_TO_HASH ? hash(o) : o;\n }\n }\n\n // Concatenate all key parts into a cache key string\n // Template literals are apparently slower\n const cacheStr =\n method +\n DELIMITER +\n url +\n DELIMITER +\n credentials +\n DELIMITER +\n headersString +\n DELIMITER +\n bodyString;\n\n // Prevent cache poisoning by removal of control chars and unusual characters\n return CACHE_KEY_NEEDS_SANITIZE.test(cacheStr)\n ? cacheStr.replace(CACHE_KEY_SANITIZE_PATTERN, '')\n : cacheStr;\n}\n\n/**\n * Checks if the cache entry is expired based on its timestamp and the expiry time.\n *\n * @param {CacheEntry} entry - The cache entry to check.\n * @returns {boolean} - Returns true if the cache entry is expired, false otherwise.\n */\nfunction isCacheExpired(entry: CacheEntry): boolean {\n // No expiry time means the entry never expires\n if (!entry.expiry) {\n return false;\n }\n\n return timeNow() > entry.expiry;\n}\n\n/**\n * Retrieves a cached response from the internal cache using the provided key.\n *\n * @param key - The unique key identifying the cached entry. If null, returns null.\n * @returns The cached {@link FetchResponse} if found, otherwise null.\n */\nexport function getCacheData<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n key: string | null,\n): FetchResponse | null {\n if (!key) {\n return null;\n }\n\n const entry = _cache.get(key);\n\n return entry ? entry.data : null;\n}\n\n/**\n * Retrieves a cache entry if it exists and is not expired.\n *\n * @param {string} key Cache key to utilize\n * @returns {CacheEntry | null} - The cache entry if it exists and is not expired, null otherwise.\n */\nexport function getCache(\n key: string | null,\n):\n | CacheEntry<\n FetchResponse\n >\n | null\n | undefined {\n return _cache.get(key as string);\n}\n\n/**\n * Sets a new cache entry or updates an existing one, with optional TTL (time-to-live).\n *\n * @param {string} key Cache key to utilize\n * @param {T} data - The data to be cached.\n * @param {number} [ttl] - Optional TTL in seconds. If not provided, the cache entry will not expire.\n * @param {number} [staleTime] - Optional stale time in seconds. If provided, the cache entry will be considered stale after this time.\n */\nexport function setCache(\n key: string,\n data: T,\n ttl?: number,\n staleTime?: number,\n): void {\n if (ttl === 0) {\n deleteCache(key);\n return;\n }\n\n const time = timeNow();\n const ttlMs = ttl ? ttl * 1000 : 0;\n const staleTimeMs = staleTime ? staleTime * 1000 : 0; // Ensure default value for staleTime\n\n _cache.set(key, {\n data,\n time,\n stale: staleTimeMs > 0 ? time + staleTimeMs : undefined, // Use undefined if staleTime is not set\n expiry: ttl === -1 ? undefined : time + ttlMs,\n });\n\n if (ttlMs > 0) {\n addTimeout(\n 'c:' + key,\n () => {\n deleteCache(key, true);\n },\n ttlMs,\n );\n }\n}\n\n/**\n * Invalidates (deletes) a cache entry.\n *\n * @param {string} key Cache key to utilize\n * @param {boolean} [removeExpired=false] - If true, only deletes the cache entry if it is expired or stale.\n */\nexport function deleteCache(key: string, removeExpired: boolean = false): void {\n if (removeExpired) {\n const entry = getCache(key);\n\n // If the entry does not exist, or it is neither expired nor stale, do not delete\n if (!entry || !isCacheExpired(entry)) {\n return;\n }\n }\n\n _cache.delete(key);\n}\n\n/**\n * Prunes the cache by removing entries that have expired based on the provided cache time.\n */\nexport function pruneCache(): void {\n _cache.clear();\n}\n\n/**\n * Mutates a cache entry with new data and optionally revalidates it.\n *\n * @param {string | null} key Cache key to utilize. If null, no mutation occurs.\n * @param {ResponseData} newData - The new data to be cached.\n * @param {MutationSettings|undefined} settings - Mutation settings.\n */\nexport async function mutate<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n key: string | null,\n newData: ResponseData,\n settings?: MutationSettings,\n): Promise | null> {\n // If no key is provided, do nothing\n if (!key) {\n return null;\n }\n\n const entry = getCache(\n key,\n );\n\n if (!entry) {\n return null;\n }\n\n const updatedData = isObject(newData) ? sanitizeObject(newData) : newData;\n\n const updatedResponse = {\n ...entry.data,\n data: updatedData,\n };\n\n const updatedEntry = {\n ...entry,\n data: updatedResponse,\n };\n\n _cache.set(key, updatedEntry);\n notifySubscribers(key, updatedResponse);\n\n if (settings && settings.refetch) {\n return await revalidate(key);\n }\n\n return null;\n}\n\n/**\n * Retrieves a cached response if available and valid, otherwise returns null.\n *\n * @template ResponseData - The type of the response data.\n * @template RequestBody - The type of the request body.\n * @template QueryParams - The type of the query parameters.\n * @template PathParams - The type of the path parameters.\n * @param {string | null} cacheKey - The cache key to look up.\n * @param {number | undefined} cacheTime - The maximum time to cache entry.\n * @param {RequestConfig} requestConfig - The fetcher configuration.\n * @returns {FetchResponse | null} - The cached response or null.\n */\nexport function getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n cacheKey: string | null,\n cacheTime: number | undefined,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): FetchResponse | null {\n // If cache key or time is not provided, return null\n if (!cacheKey || cacheTime === undefined || cacheTime === null) {\n return null;\n }\n\n // Check if cache should be bypassed\n const buster = requestConfig.cacheBuster || defaultConfig.cacheBuster;\n if (buster && buster(requestConfig)) {\n return null;\n }\n\n if (requestConfig.cache && requestConfig.cache === 'reload') {\n return null; // Skip cache lookup entirely\n }\n\n // Retrieve the cached entry\n const entry = getCache(\n cacheKey,\n );\n\n if (!entry) {\n return null;\n }\n\n const isExpired = isCacheExpired(entry);\n\n // If completely expired, delete and return null\n if (isExpired) {\n deleteCache(cacheKey);\n return null;\n }\n\n // Return data whether fresh or stale (SWR: serve stale, revalidation is timer-driven)\n return entry.data;\n}\n\n/**\n * Sets or deletes the response cache based on cache settings and notifies subscribers.\n *\n * @param {FetchResponse} output - The response to cache.\n * @param {RequestConfig} requestConfig - The request configuration.\n * @param {boolean} [isError=false] - Whether the response is an error.\n */\nexport function handleResponseCache<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n output: FetchResponse,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n isError: boolean = false,\n): void {\n // It is string as it is called once request is made\n const cacheKey = requestConfig.cacheKey as string;\n\n if (cacheKey) {\n const cacheTime = requestConfig.cacheTime;\n const skipCache = requestConfig.skipCache;\n\n // Fast path: only set cache if cacheTime is positive and not skipping cache\n if (\n cacheTime &&\n (!isError || requestConfig.cacheErrors) &&\n !(skipCache && skipCache(output, requestConfig))\n ) {\n setCache(cacheKey, output, cacheTime, requestConfig.staleTime);\n }\n\n notifySubscribers(cacheKey, output);\n removeInFlight(cacheKey);\n\n const prevCacheKey = requestConfig._prevKey;\n\n if (prevCacheKey) {\n removeInFlight(prevCacheKey);\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { mutate } from './cache-manager';\nimport {\n APPLICATION_CONTENT_TYPE,\n APPLICATION_JSON,\n CONTENT_TYPE,\n FUNCTION,\n OBJECT,\n STRING,\n} from './constants';\nimport {\n DefaultResponse,\n FetchResponse,\n RequestConfig,\n ResponseError,\n DefaultParams,\n DefaultUrlParams,\n DefaultPayload,\n} from './types';\nimport { flattenData, isObject, processHeaders } from './utils';\n\n/**\n * Parses the response data based on the Content-Type header.\n *\n * @param response - The Response object to parse.\n * @returns A Promise that resolves to the parsed data.\n */\nexport async function parseResponseData<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n response: FetchResponse,\n): Promise {\n // Bail early if response is null or undefined\n if (!response) {\n return null;\n }\n\n // Get the content-type header once\n let contentType = (response as Response).headers?.get(CONTENT_TYPE);\n\n if (contentType) {\n // Lowercase and trim for consistent matching\n contentType = contentType.toLowerCase().trim();\n } else {\n contentType = '';\n }\n\n // Split for mime type without charset\n const mimeType = contentType.split(';', 1)[0];\n\n let data;\n\n try {\n if (mimeType.includes(APPLICATION_JSON) || mimeType.includes('+json')) {\n data = await response.json(); // Parse JSON response\n } else if (\n (mimeType.includes('multipart/form-data') || // Parse as FormData\n mimeType.includes(\n APPLICATION_CONTENT_TYPE + 'x-www-form-urlencoded', // Handle URL-encoded forms\n )) &&\n typeof response.formData === FUNCTION\n ) {\n data = await response.formData();\n } else if (\n mimeType.includes(APPLICATION_CONTENT_TYPE + 'octet-stream') &&\n typeof response.blob === FUNCTION\n ) {\n data = await response.blob(); // Parse as blob\n } else {\n data = await response.text();\n\n if (typeof data === STRING) {\n const trimmed = data.trim();\n if (\n (trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))\n ) {\n try {\n data = JSON.parse(trimmed);\n } catch {\n // leave as text if parsing fails\n }\n }\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (_error) {\n // Parsing failed, fallback to null\n data = null;\n }\n\n return data;\n}\n\n/**\n * Prepare response object with additional information.\n *\n * @param Response. It may be \"null\" in case of request being aborted.\n * @param {RequestConfig} config - Request config\n * @param error - whether the response is erroneous\n * @returns {FetchResponse} Response data\n */\nexport const prepareResponse = <\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n config: RequestConfig,\n error: ResponseError<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null = null,\n): FetchResponse => {\n const defaultResponse = config.defaultResponse;\n const cacheKey = config.cacheKey;\n const mutatator = mutate.bind(null, cacheKey as string) as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >['mutate'];\n\n // This may happen when request is cancelled.\n if (!response) {\n return {\n ok: false,\n // Enhance the response with extra information\n error,\n data: defaultResponse ?? null,\n headers: null,\n config,\n mutate: mutatator,\n isFetching: false,\n isSuccess: false,\n isError: true,\n } as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }\n\n const isNativeResponse =\n typeof Response === FUNCTION && response instanceof Response;\n\n let data = response.data;\n\n // Set the default response if the provided data is an empty object\n if (\n defaultResponse !== undefined &&\n (data === undefined ||\n data === null ||\n (typeof data === OBJECT && Object.keys(data).length === 0))\n ) {\n response.data = data = defaultResponse;\n }\n\n if (config.flattenResponse) {\n response.data = data = flattenData(data);\n }\n\n if (config.select) {\n response.data = data = config.select(data);\n }\n\n const headers = processHeaders(response.headers);\n\n // Native fetch Response extended by extra information\n if (isNativeResponse) {\n return {\n body: response.body,\n bodyUsed: response.bodyUsed,\n ok: response.ok,\n redirected: response.redirected,\n type: response.type,\n url: response.url,\n status: response.status,\n statusText: response.statusText,\n\n // Convert methods to use arrow functions to preserve correct return types\n blob: () => response.blob(),\n json: () => response.json(),\n text: () => response.text(),\n clone: () => response.clone(),\n arrayBuffer: () => response.arrayBuffer(),\n formData: () => response.formData(),\n bytes: () => response.bytes(),\n\n // Enhance the response with extra information\n error,\n data,\n headers,\n config,\n mutate: mutatator,\n isFetching: false,\n isSuccess: response.ok && !error,\n isError: !!error,\n };\n }\n\n // If it's a custom fetcher, and it does not return any Response instance, it may have its own internal handler\n if (isObject(response)) {\n response.error = error;\n response.headers = headers;\n response.isFetching = false;\n response.mutate = mutatator;\n response.isSuccess = response.ok && !error;\n response.isError = !!error;\n }\n\n return response;\n};\n","import { applyInterceptors } from './interceptor-manager';\nimport type { FetchResponse, RetryConfig, RetryFunction } from './types';\nimport { delayInvocation, timeNow } from './utils';\nimport { generateCacheKey } from './cache-manager';\n\nfunction getMsFromHttpDate(dateString: string): number | null {\n const ms = Date.parse(dateString) - timeNow();\n\n if (!isNaN(ms)) {\n return Math.max(0, Math.floor(ms));\n }\n return null;\n}\n\n/**\n * Calculates the number of milliseconds to wait before retrying a request,\n * based on the `Retry-After` HTTP header in the provided response.\n *\n * The function supports both numeric (seconds) and HTTP-date formats for the `Retry-After` header.\n * - If the header is a number, it is interpreted as seconds and converted to milliseconds.\n * - If the header is a date, the function calculates the difference between the date and the current time.\n *\n * @param extendedResponse - The response object containing headers, or `null`.\n * @returns The number of milliseconds to wait before retrying, or `null` if the header is not present or invalid.\n */\nexport function getRetryAfterMs(\n extendedResponse: FetchResponse | null,\n): number | null {\n if (!extendedResponse) {\n return null;\n }\n\n const headers = extendedResponse.headers || {};\n const retryAfter = headers['retry-after'];\n\n if (retryAfter) {\n // Try parsing as seconds\n const seconds = Number(retryAfter);\n\n if (!isNaN(seconds) && seconds >= 0) {\n return seconds * 1000;\n }\n\n const ms = getMsFromHttpDate(retryAfter);\n\n if (ms !== null) {\n return ms;\n }\n }\n\n // Headers are already in lowercase\n const RATELIMIT_RESET = 'ratelimit-reset';\n\n // Unix timestamp when the rate limit window resets (relative to current time)\n // Fallback to checking 'ratelimit-reset-after' OR 'x-ratelimit-reset-after' headers\n const rateLimitResetAfter =\n headers[RATELIMIT_RESET + '-after'] ||\n headers['x-' + RATELIMIT_RESET + '-after'];\n\n if (rateLimitResetAfter) {\n const seconds = Number(rateLimitResetAfter);\n\n if (!isNaN(seconds)) {\n return seconds * 1000;\n }\n }\n\n // ISO 8601 datetime when the rate limit resets\n // Fallback to checking 'ratelimit-reset-at' 'x-ratelimit-reset-at' headers\n const rateLimitResetAt =\n headers[RATELIMIT_RESET + '-at'] || headers['x-' + RATELIMIT_RESET + '-at'];\n\n if (rateLimitResetAt) {\n return getMsFromHttpDate(rateLimitResetAt);\n }\n\n return null;\n}\n\n/**\n * Executes a request function with retry logic according to the provided configuration.\n *\n * The function attempts the request up to the specified number of retries, applying delay and backoff strategies.\n * Retries can be triggered based on response status codes, custom logic, or the presence of a `Retry-After` header.\n * Optionally, an `onRetry` interceptor can be invoked before each retry attempt.\n *\n * @typeParam ResponseData - The type of the response data.\n * @typeParam RequestBody - The type of the request body.\n * @typeParam QueryParams - The type of the query parameters.\n * @typeParam PathParams - The type of the path parameters.\n * @param requestFn - The function that performs the request. Receives `isStaleRevalidation` and `attempt` as arguments.\n * @param config - The retry configuration, including retry count, delay, backoff, retry conditions, and hooks.\n * @returns A promise resolving to the fetch response, or rejecting if all retries are exhausted.\n * @throws Error if the maximum number of retries is exceeded or a non-retriable error occurs.\n */\nexport async function withRetry<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n requestFn: (\n isStaleRevalidation: boolean,\n attempt: number,\n ) => Promise<\n FetchResponse\n >,\n config: RetryConfig,\n): Promise> {\n const {\n retries = 0,\n delay = 0,\n backoff = 1,\n maxDelay,\n retryOn = [],\n shouldRetry,\n } = config;\n\n let attempt = 0;\n let waitTime = delay;\n const maxRetries = retries > 0 ? retries : 0;\n let output: FetchResponse;\n\n while (attempt <= maxRetries) {\n // Subsequent attempts will have output defined, but the first attempt may not.\n // Let's apply onRetry interceptor and regenerate cache key if ot really changes.\n if (attempt > 0 && output!) {\n const cfg = output.config;\n const onRetry = cfg.onRetry;\n\n if (onRetry) {\n await applyInterceptors(onRetry, output, attempt);\n\n // If the key was automatically generated, we need to regenerate it as config may change.\n // We don't detect whether config changed for performance reasons.\n if (cfg._isAutoKey) {\n cfg._prevKey = cfg.cacheKey as string;\n cfg.cacheKey = generateCacheKey(cfg, false);\n }\n }\n }\n\n // Performance optimization: Call the request function with the current attempt number\n // If this is the first attempt, we pass `isStaleRevalidation` as `false`,\n // otherwise we pass `true` to indicate that this is a stale revalidation (no cache hit).\n output = await requestFn(attempt > 0, attempt);\n const error = output.error;\n\n // Check if we should retry based on successful response\n if (!error) {\n if (shouldRetry && attempt < maxRetries) {\n const shouldRetryResult = await shouldRetry(output, attempt);\n\n if (shouldRetryResult) {\n await delayInvocation(waitTime);\n waitTime *= backoff || 1;\n waitTime = Math.min(waitTime, maxDelay || waitTime);\n attempt++;\n continue;\n }\n }\n\n break;\n }\n\n // Determine if we should stop retrying\n const shouldStopRetrying = await getShouldStopRetrying(\n output,\n attempt,\n maxRetries,\n shouldRetry,\n retryOn,\n );\n\n if (shouldStopRetrying) {\n break;\n }\n\n // If we should not stop retrying, continue to the next attempt\n // Handle rate limiting if the error status is 429 (Too Many Requests) or 503 (Service Unavailable)\n if (error.status === 429 || error.status === 503) {\n // Try to extract the \"Retry-After\" value from the response headers\n const retryAfterMs = getRetryAfterMs(output);\n\n // If a valid retry-after value is found, override the wait time before next retry\n if (retryAfterMs !== null) {\n waitTime = retryAfterMs;\n }\n }\n\n await delayInvocation(waitTime);\n waitTime *= backoff || 1;\n waitTime = Math.min(waitTime, maxDelay || waitTime);\n attempt++;\n }\n\n return output!;\n}\n\n/**\n * Determines whether to stop retrying based on the error, current attempt count, and retry configuration.\n *\n * This function checks:\n * - If the maximum number of retries has been reached.\n * - If a custom `shouldRetry` callback is provided, its result is used to decide.\n * - If no custom logic is provided, falls back to checking if the error status is included in the `retryOn` list.\n *\n * @typeParam ResponseData - The type of the response data.\n * @typeParam RequestBody - The type of the request body.\n * @typeParam QueryParams - The type of the query parameters.\n * @typeParam PathParams - The type of the path parameters.\n * @param output - The response object containing the error and request configuration.\n * @param attempt - The current retry attempt number.\n * @param maxRetries - The maximum number of retry attempts allowed.\n * @param shouldRetry - Optional custom function to determine if a retry should occur.\n * @param retryOn - Optional list of HTTP status codes that should trigger a retry.\n * @returns A promise resolving to `true` if retrying should stop, or `false` to continue retrying.\n */\nexport async function getShouldStopRetrying<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n output: FetchResponse,\n attempt: number,\n maxRetries: number,\n shouldRetry?: RetryFunction<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n retryOn: number[] = [],\n): Promise {\n // Safety first: always respect max retries\n // We check retries provided regardless of the shouldRetry being provided so to avoid infinite loops.\n // It is a fail-safe so to prevent excessive retry attempts even if custom retry logic suggests a retry.\n if (attempt === maxRetries) {\n return true;\n }\n\n let customDecision: boolean | null = null;\n\n // Get custom decision if shouldRetry is provided\n if (shouldRetry) {\n const result = await shouldRetry(output, attempt);\n customDecision = result;\n\n // Decision cascade:\n if (customDecision !== null) {\n return !customDecision;\n }\n }\n\n return !(retryOn || []).includes(output.error?.status ?? 0);\n}\n","import type { RequestConfig, FetchResponse } from './types';\nimport { delayInvocation } from './utils';\n\n/**\n * Executes a request function with polling, stopping when shouldStopPolling returns true,\n * pollingInterval is not set, or maxAttempts is reached.\n *\n * @template Output The type of the output returned by the request function.\n * @param requestFn - The function that performs a single request (with retries).\n * @param pollingInterval - Interval in ms between polling attempts.\n * @param shouldStopPolling - Function to determine if polling should stop.\n * @param maxAttempts - Maximum number of polling attempts, default: 0 (unlimited).\n * @param pollingDelay - Delay in ms before each polling attempt, default: 0.\n * @returns The final output from the last request.\n */\nexport async function withPolling<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n requestFn: (\n isStaleRevalidation?: boolean,\n attempt?: number,\n ) => Promise<\n FetchResponse\n >,\n pollingInterval?: RequestConfig['pollingInterval'],\n shouldStopPolling?: RequestConfig['shouldStopPolling'],\n maxAttempts = 0,\n pollingDelay = 0,\n): Promise> {\n if (!pollingInterval) {\n return requestFn();\n }\n\n let pollingAttempt = 0;\n let output: FetchResponse;\n\n while (maxAttempts === 0 || pollingAttempt < maxAttempts) {\n if (pollingDelay > 0) {\n await delayInvocation(pollingDelay);\n }\n\n output = await requestFn();\n\n pollingAttempt++;\n\n if (\n (maxAttempts > 0 && pollingAttempt >= maxAttempts) ||\n !pollingInterval ||\n (shouldStopPolling && shouldStopPolling(output, pollingAttempt))\n ) {\n break;\n }\n\n await delayInvocation(pollingInterval);\n }\n\n return output!;\n}\n","import type { ResponseError } from './errors/response-error';\nimport type {\n DefaultResponse,\n FetchResponse,\n RequestConfig,\n} from './types/request-handler';\nimport { applyInterceptors } from './interceptor-manager';\nimport { handleResponseCache } from './cache-manager';\nimport { ABORT_ERROR, REJECT } from './constants';\nimport { DefaultParams, DefaultUrlParams, DefaultPayload } from './types';\n\n/**\n * Handles final processing for both success and error responses\n * Applies error interceptors, caching, notifications, and error strategy\n */\nexport async function withErrorHandling<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n isStaleRevalidation: boolean,\n requestFn: (\n isStaleRevalidation: boolean,\n ) => Promise<\n FetchResponse\n >,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): Promise> {\n const output = await requestFn(isStaleRevalidation);\n const error = output.error;\n\n if (!error) {\n // SUCCESS PATH\n handleResponseCache(output, requestConfig);\n\n return output;\n }\n\n // ERROR PATH\n\n if (requestConfig.onError) {\n await applyInterceptors(requestConfig.onError, error);\n }\n\n // Timeouts and request cancellations using AbortController do not throw any errors unless rejectCancelled is true.\n // Only handle the error if the request was not cancelled, or if it was cancelled and rejectCancelled is true.\n const isCancelled = error.isCancelled;\n\n if (!isCancelled && requestConfig.logger) {\n logger(requestConfig, 'FETCH ERROR', error as ResponseError);\n }\n\n // Handle cache and notifications FIRST (before strategy)\n handleResponseCache(output, requestConfig, true);\n\n // handle error strategy as the last part\n const shouldHandleError = !isCancelled || requestConfig.rejectCancelled;\n\n if (shouldHandleError) {\n const strategy = requestConfig.strategy;\n // Reject the promise\n if (strategy === REJECT) {\n return Promise.reject(error);\n }\n\n // Hang the promise\n if (strategy === 'silent') {\n await new Promise(() => null);\n }\n }\n\n return output;\n}\n\nexport function enhanceError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n error: any,\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): void {\n error.status = error.status || response?.status || 0;\n error.statusText = error.statusText || response?.statusText || '';\n error.config = error.request = requestConfig;\n error.response = response;\n error.isCancelled = error.name === ABORT_ERROR;\n}\n\n/**\n * Logs messages or errors using the configured logger's `warn` method.\n *\n * @param {RequestConfig} reqConfig - Request config passed when making the request\n * @param {...(string | ResponseError)} args - Messages or errors to log.\n */\nfunction logger(\n reqConfig: RequestConfig,\n ...args: (string | ResponseError)[]\n): void {\n const logger = reqConfig.logger;\n\n if (logger && logger.warn) {\n logger.warn(...args);\n }\n}\n","import type {\n DefaultResponse,\n RequestConfig,\n FetchResponse,\n} from './types/request-handler';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultUrlParams,\n} from './types/api-handler';\nimport { applyInterceptors } from './interceptor-manager';\nimport { ResponseError } from './errors/response-error';\nimport { isObject } from './utils';\nimport {\n markInFlight,\n setInFlightPromise,\n getInFlightPromise,\n} from './inflight-manager';\nimport { parseResponseData, prepareResponse } from './response-parser';\nimport { generateCacheKey, getCachedResponse, setCache } from './cache-manager';\nimport { withRetry } from './retry-handler';\nimport { withPolling } from './polling-handler';\nimport { notifySubscribers } from './pubsub-manager';\nimport { addRevalidator } from './revalidator-manager';\nimport { enhanceError, withErrorHandling } from './error-handler';\nimport { FUNCTION } from './constants';\nimport { buildConfig } from './config-handler';\n\nconst inFlightResponse = Object.freeze({\n isFetching: true,\n});\n\n/**\n * Sends an HTTP request to the specified URL using the provided configuration and returns a typed response.\n *\n * @typeParam ResponseData - The expected shape of the response data. Defaults to `DefaultResponse`.\n * @typeParam RequestBody - The type of the request payload/body. Defaults to `DefaultPayload`.\n * @typeParam QueryParams - The type of the query parameters. Defaults to `DefaultParams`.\n * @typeParam PathParams - The type of the path parameters. Defaults to `DefaultUrlParams`.\n *\n * @param url - The endpoint URL to which the request will be sent.\n * @param config - Optional configuration object for the request, including headers, method, body, query, and path parameters.\n *\n * @returns A promise that resolves to a `FetchResponse` containing the typed response data and request metadata.\n *\n * @example\n * ```typescript\n * const { data } = await fetchf('/api/user', { method: 'GET' });\n * console.log(data);\n * ```\n */\nexport async function fetchf<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n url: string,\n reqConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > | null = null,\n): Promise> {\n // Ultra-fast early cache check if cacheKey is provided as a string\n // For workloads dominated by repeated requests, this string caching optimization\n // can potentially support millions of requests per second with minimal CPU overhead\n if (reqConfig && typeof reqConfig.cacheKey === 'string') {\n const cached = getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(reqConfig.cacheKey, reqConfig.cacheTime, reqConfig);\n\n if (cached) {\n return cached;\n }\n }\n\n const fetcherConfig = buildConfig<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(url, reqConfig);\n\n const {\n timeout,\n cancellable,\n cacheKey,\n dedupeTime,\n cacheTime,\n staleTime,\n refetchOnFocus,\n refetchOnReconnect,\n pollingInterval = 0,\n } = fetcherConfig;\n const isCacheEnabled = cacheTime !== undefined || staleTime !== undefined;\n\n const needsCacheKey = !!(\n cacheKey ||\n timeout ||\n dedupeTime ||\n isCacheEnabled ||\n cancellable ||\n refetchOnFocus ||\n refetchOnReconnect\n );\n\n let _cacheKey: string | null = null;\n\n // Generate cache key if required\n if (needsCacheKey) {\n _cacheKey = generateCacheKey(fetcherConfig);\n }\n\n // Cache handling logic\n if (_cacheKey && isCacheEnabled) {\n const cached = getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(_cacheKey, cacheTime, fetcherConfig);\n\n if (cached) {\n return cached;\n }\n }\n\n // Deduplication logic\n if (_cacheKey && dedupeTime) {\n const inflight = getInFlightPromise<\n FetchResponse\n >(_cacheKey, dedupeTime);\n\n if (inflight) {\n return inflight;\n }\n }\n\n const retryConfig = fetcherConfig.retry || {};\n const { retries = 0, resetTimeout } = retryConfig;\n\n // The actual request logic as a function (one poll attempt, with retries)\n const doRequestOnce = async (isStaleRevalidation = false, attempt = 0) => {\n // If cache key is specified, we will handle optimistic updates\n // and mark the request as in-flight, so to catch \"fetching\" state.\n // This is useful for Optimistic UI updates (e.g., showing loading spinners).\n if (!attempt) {\n if (_cacheKey && !isStaleRevalidation) {\n if (staleTime) {\n const existingCache = getCachedResponse(\n _cacheKey,\n cacheTime,\n fetcherConfig,\n );\n\n // Don't notify subscribers when cache exists\n // Let them continue showing stale data during background revalidation\n if (!existingCache) {\n setCache(_cacheKey, inFlightResponse, cacheTime, staleTime);\n notifySubscribers(_cacheKey, inFlightResponse);\n }\n } else {\n notifySubscribers(_cacheKey, inFlightResponse);\n }\n }\n\n // Attach cache key so that it can be reused in interceptors or in the final response\n fetcherConfig.cacheKey = _cacheKey;\n }\n\n const url = fetcherConfig.url as string;\n\n // Add the request to the queue. Make sure to handle deduplication, cancellation, timeouts in accordance to retry settings\n const controller = markInFlight(\n _cacheKey,\n url,\n timeout,\n dedupeTime || 0,\n !!cancellable,\n // Enable timeout either by default or when retries & resetTimeout are enabled\n !!(timeout && (!attempt || resetTimeout)),\n );\n\n // Do not create a shallow copy to maintain idempotency here.\n // This ensures the original object is mutated by interceptors whenever needed, including retry logic.\n const requestConfig = fetcherConfig;\n\n requestConfig.signal = controller.signal;\n\n let output: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n let response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null = null;\n\n try {\n if (fetcherConfig.onRequest) {\n // Zero-allocation yield to microtask queue so the outer fetchf() can call setInFlightPromise()\n // before onRequest interceptors run. This ensures that if onRequest triggers\n // another fetchf() with the same cacheKey, getInFlightPromise() finds item[4].\n // On retries (attempt > 0), setInFlightPromise() was already called during the first attempt.\n // The promise stored in item[4] is the outer doRequestPromise which covers all retries.\n // So the race only matters on the very first attempt when the outer scope hasn't had a chance to call setInFlightPromise() yet.\n if (_cacheKey && dedupeTime && !attempt) {\n await null;\n }\n\n await applyInterceptors(fetcherConfig.onRequest, requestConfig);\n }\n\n // Custom fetcher\n const fn = fetcherConfig.fetcher;\n\n response = (fn\n ? await fn(\n url,\n requestConfig,\n )\n : await fetch(\n url,\n requestConfig as RequestInit,\n )) as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n\n // Custom fetcher may return a raw data object instead of a Response instance\n if (isObject(response)) {\n // Case 1: Native Response instance\n if (typeof Response === FUNCTION && response instanceof Response) {\n response.data = await parseResponseData(response);\n } else if (fn) {\n // Case 2: Custom fetcher that returns a response object\n if (!('data' in response && 'body' in response)) {\n // Case 3: Raw data, wrap it\n response = { data: response } as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }\n }\n\n // Attach config and data to the response\n // This is useful for custom fetchers that do not return a Response instance\n // and for interceptors that may need to access the request config\n response.config = requestConfig;\n\n // Check if the response status is not outside the range 200-299 and if so, output error\n // This is the pattern for fetch responses as per spec, but custom fetchers may not follow it so we check for `ok` property\n if (response.ok !== undefined && !response.ok) {\n throw new ResponseError(\n `${requestConfig.method} to ${url} failed! Status: ${response.status || null}`,\n requestConfig,\n response,\n );\n }\n }\n\n output = prepareResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(response, requestConfig);\n\n const onResponse = fetcherConfig.onResponse;\n\n if (onResponse) {\n await applyInterceptors(onResponse, output);\n }\n } catch (_error) {\n const error = _error as ResponseError<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n\n // Append additional information to Network, CORS or any other fetch() errors\n enhanceError(\n error,\n response,\n requestConfig,\n );\n\n // Prepare Extended Response\n output = prepareResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(response, requestConfig, error);\n }\n\n return output;\n };\n\n // Inline and minimize function wrappers for performance\n // When retries are enabled, forward isStaleRevalidation so the first attempt\n // of a background SWR revalidation doesn't incorrectly mark the request as in-flight\n const baseRequest =\n retries > 0\n ? (isStaleRevalidation = false) =>\n withRetry(\n (_, attempt) => doRequestOnce(isStaleRevalidation, attempt),\n retryConfig,\n )\n : doRequestOnce;\n\n const requestWithErrorHandling = (isStaleRevalidation = false) =>\n withErrorHandling(\n isStaleRevalidation,\n baseRequest,\n fetcherConfig,\n );\n\n // Avoid unnecessary function wrapping if polling is not enabled\n const doRequestPromise = pollingInterval\n ? withPolling(\n requestWithErrorHandling,\n pollingInterval,\n fetcherConfig.shouldStopPolling,\n fetcherConfig.maxPollingAttempts,\n fetcherConfig.pollingDelay,\n )\n : requestWithErrorHandling();\n\n // If deduplication is enabled, store the in-flight promise immediately\n if (_cacheKey) {\n if (dedupeTime) {\n setInFlightPromise(_cacheKey, doRequestPromise);\n }\n\n // Only register revalidator when revalidation features are actually requested\n if (staleTime || refetchOnFocus || refetchOnReconnect) {\n addRevalidator(\n _cacheKey,\n requestWithErrorHandling,\n undefined,\n staleTime,\n requestWithErrorHandling,\n !!refetchOnFocus,\n !!refetchOnReconnect,\n );\n }\n }\n\n return doRequestPromise;\n}\n","import type {\n ApiHandlerConfig,\n ApiHandlerDefaultMethods,\n ApiHandlerMethods,\n RequestConfigUrlRequired,\n} from './types/api-handler';\nimport { fetchf } from '.';\nimport { mergeConfigs } from './config-handler';\nimport { isAbsoluteUrl } from './utils';\n\n/**\n * Creates an instance of API Handler.\n * It creates an API fetcher function using native fetch() or a custom fetcher if passed as \"fetcher\".\n * @see https://github.com/MattCCC/fetchff#configuration\n *\n * @param {Object} config - Configuration object for the API fetcher (see link above for full options).\n * @param {Object} config.endpoints - An object containing endpoint definitions.\n * @param {string} [config.baseURL] - The base URL for the API.\n * @param {Object} [config.headers] - Optional default headers to include in every request.\n * @param {Function} [config.onError] - Optional callback function for handling errors.\n * @returns API handler functions and endpoints to call\n *\n * @example\n * // Define endpoint paths\n * const endpoints = {\n * getUser: '/user',\n * createPost: '/post',\n * };\n *\n * // Create the API fetcher with configuration\n * const api = createApiFetcher({\n * endpoints,\n * apiUrl: 'https://example.com/api',\n * onError(error) {\n * console.log('Request failed', error);\n * },\n * headers: {\n * 'my-auth-key': 'example-auth-key-32rjjfa',\n * },\n * });\n *\n * // Fetch user data\n * const response = await api.getUser({ userId: 1, ratings: [1, 2] })\n */\nfunction createApiFetcher<\n EndpointTypes extends object,\n EndpointsSettings = never,\n>(config: ApiHandlerConfig) {\n const endpoints = config.endpoints;\n\n /**\n * Triggered when trying to use non-existent endpoints\n *\n * @param endpointName Endpoint Name\n * @returns {Promise}\n */\n function handleNonImplemented(endpointName: string): Promise {\n console.error(`Add ${endpointName} to 'endpoints'.`);\n\n return Promise.resolve(null);\n }\n\n const apiHandler: ApiHandlerDefaultMethods = {\n config,\n endpoints,\n /**\n * Handle Single API Request\n * It considers settings in following order: per-request settings, global per-endpoint settings, global settings.\n *\n * @param endpointName - The name of the API endpoint to call.\n * @param requestConfig - Additional configuration for the request.\n * @returns A promise that resolves with the response from the API provider.\n */\n async request(endpointName, requestConfig = {}) {\n // Use global and per-endpoint settings\n const endpointConfig = endpoints[endpointName];\n const _endpointConfig =\n endpointConfig ||\n ({ url: String(endpointName) } as RequestConfigUrlRequired);\n const url = _endpointConfig.url;\n\n // Block Protocol-relative URLs as they could lead to SSRF (Server-Side Request Forgery)\n if (url.startsWith('//')) {\n throw new Error('Protocol-relative URLs are not allowed.');\n }\n\n // Prevent potential Server-Side Request Forgery attack and leakage of credentials when same instance is used for external requests\n const mergedConfig = isAbsoluteUrl(url)\n ? // Merge endpoints configs for absolute URLs only if urls match\n endpointConfig?.url === url\n ? mergeConfigs(_endpointConfig, requestConfig)\n : requestConfig\n : mergeConfigs(mergeConfigs(config, _endpointConfig), requestConfig);\n\n // We prevent potential Server-Side Request Forgery attack and leakage of credentials as the same instance is not used for external requests\n // Retrigger fetch to ensure completely new instance of handler being triggered for external URLs\n return fetchf(url, mergedConfig);\n },\n };\n\n /**\n * Maps all API requests using native Proxy\n *\n * @param {*} prop Caller\n */\n return new Proxy>(\n apiHandler as ApiHandlerMethods,\n {\n get(_target, prop: string) {\n if (prop in apiHandler) {\n return apiHandler[prop as unknown as keyof typeof apiHandler];\n }\n\n // Prevent handler from triggering non-existent endpoints\n if (endpoints[prop]) {\n return apiHandler.request.bind(null, prop);\n }\n\n return handleNonImplemented.bind(null, prop);\n },\n },\n );\n}\n\nexport { createApiFetcher };\n"]} \ No newline at end of file diff --git a/dist/browser/index.mjs b/dist/browser/index.mjs index ee7fae59..281457ad 100644 --- a/dist/browser/index.mjs +++ b/dist/browser/index.mjs @@ -1,3 +1,3 @@ -var ct=Object.defineProperty;var ft=(e,t,r)=>t in e?ct(e,t,{enumerable:true,configurable:true,writable:true,value:r}):e[t]=r;var L=(e,t,r)=>ft(e,typeof t!="symbol"?t+"":t,r);var x="application/",j=x+"json",Ne="charset=utf-8",C="Content-Type",h="undefined",K="object",b="string",g="function",ee="AbortError",Se="TimeoutError",O="GET",ve="HEAD",te="reject";var Ue=10;function re(e){return e instanceof URLSearchParams}function p(e){return e!==null&&typeof e===K}function J(e){let t={...e};return delete t.__proto__,delete t.constructor,delete t.prototype,t}function He(e){let t=Object.keys(e);t.sort();let r={};for(let a=0,n=t.length;a{i=typeof i===g?i():i,i=i===null||i===void 0?"":i,r[r.length]=a(l)+"="+a(i);},s=(l,i,m=0)=>{if(m>=Ue)return r;let c,R,P;if(l)if(Array.isArray(i))for(c=0,R=i.length;c{if(Object.prototype.hasOwnProperty.call(r,n)){let s=r[n];if(s!=null)return encodeURIComponent(String(s))}return a})}function ae(e){return e.includes("://")}var y=()=>Date.now(),Q=()=>{};function ge(e){let t=typeof e;return e==null?false:t===b||t==="number"||t==="boolean"||Array.isArray(e)?true:typeof globalThis!==h&&typeof globalThis.Buffer!==h&&globalThis.Buffer.isBuffer(e)||e instanceof Date||re(e)?false:!!(p(e)&&(Object.getPrototypeOf(e)===Object.prototype||typeof e.toJSON===g))}async function N(e){return new Promise(t=>setTimeout(()=>t(true),e))}function De(e,t=0){return t>=Ue?e:e&&p(e)&&typeof e.data!==h?De(e.data,t+1):e}function ne(e){if(!e)return {};let t={};if(e instanceof Headers)e.forEach((r,a)=>{t[a]=r;});else if(p(e))for(let[r,a]of Object.entries(e))t[r.toLowerCase()]=a;return t}function se(){return typeof window!==h&&typeof window.addEventListener===g}var Te=()=>{if(!se())return false;let e=navigator&&navigator.connection;return e&&["slow-2g","2g","3g"].includes(e.effectiveType)};async function w(e,t,...r){if(e){if(typeof e===g){let a=await e(t,...r);a&&p(t)&&p(a)&&Object.assign(t,a);}else if(Array.isArray(e))for(let a of e){let n=await a(t,...r);n&&p(t)&&p(n)&&Object.assign(t,n);}}}var oe=class extends Error{constructor(r,a,n){super(r);this.request=a;this.response=n;L(this,"status");L(this,"statusText");L(this,"config");L(this,"isCancelled");this.name="FetchError",this.status=n?n.status:0,this.statusText=n?n.statusText:"",this.config=a,this.isCancelled=false;}};var ie=class extends oe{constructor(t,r,a){super(t,r,a),this.name="ResponseError";}};var le=600,ue=1e3,mt=le*ue,k=Array(le).fill(0).map(()=>[]),q=new Map,z=0,E=null,je=([e,t])=>{q.delete(e);try{let r=t();r&&r instanceof Promise&&r.catch(Q);}catch(r){}},I=(e,t,r)=>{if(S(e),r>mt||r%ue!==0){q.set(e,[setTimeout(je.bind(null,[e,t]),r)]);return}let a=r/ue,n=(z+a)%le;k[n].push([e,t]),q.set(e,n),E||(E=setInterval(()=>{z=(z+1)%le,k[z].forEach(je),k[z]=[],!q.size&&E&&(clearInterval(E),E=null);},ue));},S=e=>{let t=q.get(e);t!==void 0&&(Array.isArray(t)?clearTimeout(t[0]):k[t].splice(k[t].findIndex(([r])=>r===e),1),q.delete(e),!q.size&&E&&(clearInterval(E),E=null));};var A=new Map;function Ke(e,t,r,a,n,s){if(!e)return new AbortController;let o=A.get(e),u=null;if(o){let i=o[0],m=o[3];if(!m&&y()-o[2]{Je(e,new DOMException(t+" aborted due to timeout",Se));},r),l}async function Je(e,t=null){if(e){let r=A.get(e);r&&(t&&r[0].abort(t),ce(e));}}function ce(e){S(e),A.delete(e);}function ze(e,t){let r=A.get(e);r&&(r[4]=t,A.set(e,r));}function be(e,t){if(!e)return null;let r=A.get(e);return r&&r[4]&&!r[3]&&y()-r[2]{if(!n[r])return;n[1]=a;let s=t?n[4]:n[0];s&&Promise.resolve(s(t)).catch(Q);});}async function me(e,t=false){if(!e)return null;let r=W.get(e);if(r){r[1]=y();let a=t?r[4]:r[0];if(a)return await a(t)}return null}function dt(e){Rt(e);let t=e==="focus"?5:6;W.forEach((r,a)=>{r[t]&&yt(a);});}function ke(e){if(!se()||fe.has(e))return;let t=Ge.bind(null,e,true);fe.set(e,t),window.addEventListener(e,t);}function Rt(e){if(!se())return;let t=fe.get(e);t&&(window.removeEventListener(e,t),fe.delete(e));}function We(e,t,r,a,n,s,o){W.set(e,[t,y(),pt,a,n,s,o]),s&&ke("focus"),o&&ke("online"),a&&I("s:"+e,me.bind(null,e,true),a*1e3);}function yt(e){W.delete(e),S("s:"+e);}var v=new Map;function Pt(e){return v.has(e)||v.set(e,new Set),v.get(e)}function ht(e,t){Pt(e).add(t);}function gt(e,t){let r=v.get(e);r&&(r.delete(t),r.size===0&&v.delete(e));}function _(e,t){let r=v.get(e);if(r)if(r.size===1){let a=r.values().next().value;a(t);}else r.forEach(a=>a(t));}function Dt(e,t){return e?(ht(e,t),()=>{gt(e,t);}):Q}var Ee=(Te()?60:30)*1e3,U={strategy:te,timeout:Ee,headers:{Accept:j+", text/plain, */*","Accept-Encoding":"gzip, deflate, br"},retry:{delay:Ee/30,maxDelay:Ee,resetTimeout:true,backoff:1.5,retryOn:[408,409,425,429,500,502,503,504]}};function Tt(e){let t=J(e);return Object.assign(U,t),U}function Ve(){return {...U}}function Ce(e,t){if(!t)return Ye(e,Ve());let r=J(t),a=Y(U,r);return Ye(e,a)}function Ye(e,t){var i;let r=t.method;r=r?r.toUpperCase():O;let a;r!==O&&r!==ve&&(a=(i=t.body)!=null?i:t.data,a&&typeof a!==b&&ge(a)&&(a=JSON.stringify(a))),bt(t.headers,a);let n=t.withCredentials?"include":t.credentials,s=Le(e,t.urlPathParams),o=Me(s,t.params),l=ae(e)?"":t.baseURL||t.apiUrl||"";return t.url=l+o,t.method=r,t.credentials=n,t.body=a,t}function bt(e,t){if(!e||!t||t instanceof FormData||typeof Blob!==h&&t instanceof Blob||typeof File!==h&&t instanceof File||typeof ReadableStream!==h&&t instanceof ReadableStream)return;let r;if(re(t))r=x+"x-www-form-urlencoded";else if(t instanceof ArrayBuffer||ArrayBuffer.isView(t))r=x+"octet-stream";else if(ge(t))r=j+";"+Ne;else return;e instanceof Headers?e.has(C)||e.set(C,r):p(e)&&!Array.isArray(e)&&!e[C]&&(e[C]=r);}function Y(e,t){let r=Object.assign({},e,t);return $e("retry",r,e,t),$e("headers",r,e,t),xe("onRequest",r,e,t),xe("onResponse",r,e,t),xe("onError",r,e,t),r}function xe(e,t,r,a){let n=r[e],s=a[e];if(!n&&!s)return;if(!n){t[e]=s;return}if(!s){t[e]=n;return}let o=Array.isArray(n)?n:[n],u=Array.isArray(s)?s:[s];t[e]=e==="onResponse"?u.concat(o):o.concat(u);}function $e(e,t,r,a){a[e]&&(t[e]={...r[e],...a[e]});}var de=new Map,B="|",we=64,Ze=new RegExp("[^\\w\\-_|]","g"),Et=new Set(["accept","accept-language","accept-encoding","authorization","content-type","referer","origin","user-agent","cookie","x-api-key","x-requested-with","x-client-id","x-tenant-id","x-user-id","x-app-version","x-feature-flag","x-device-id","x-platform","x-session-id","x-locale"]);function $(e,t=true){let r=e.cacheKey;if(r&&t)return typeof r===b?r:r(e);let{url:a="",method:n=O,headers:s=null,body:o=null,credentials:u="same-origin"}=e,l="";if(s){let m;s instanceof Headers?m=ne(s):m=s;let c=Object.keys(m),R=c.length;R>1&&c.sort();let P="";for(let f=0;f{i+=c+"="+m+"&";}),i.length>we&&(i=G(i));else if(typeof Blob!==h&&o instanceof Blob||typeof File!==h&&o instanceof File)i="BF"+o.size+o.type;else if(o instanceof ArrayBuffer||ArrayBuffer.isView(o))i="AB"+o.byteLength;else {let m=p(o)?JSON.stringify(He(o)):String(o);i=m.length>we?G(m):m;}return (n+B+a+B+u+B+l+B+i).replace(Ze,"")}function Xe(e){return e.expiry?y()>e.expiry:false}function xt(e){return e.stale?y()>e.stale:false}function Re(e){return de.get(e)}function ye(e,t,r,a){if(r===0){pe(e);return}let n=y(),s=r?r*1e3:0;de.set(e,{data:t,time:n,stale:a&&a>0?n+a*1e3:a,expiry:r===-1?void 0:n+s}),s>0&&I("c:"+e,()=>{pe(e,true);},s);}function pe(e,t=false){if(t){let r=Re(e);if(!r||!Xe(r))return}de.delete(e);}async function qe(e,t,r){if(!e)return null;let a=Re(e);if(!a)return null;let n=p(t)?J(t):t,s={...a.data,data:n},o={...a,data:s};return de.set(e,o),_(e,s),r&&r.refetch?await me(e):null}function Pe(e,t,r){if(!e||t===void 0||t===null)return null;let a=r.cacheBuster||U.cacheBuster;if(a&&a(r)||r.cache&&r.cache==="reload")return null;let n=Re(e);if(!n)return null;let s=Xe(n),o=xt(n);return s?(pe(e),null):!o||o&&!s?n.data:null}function Ie(e,t,r=false){let a=t.cacheKey;if(a){let n=t.cacheTime,s=t.skipCache;n&&(!r||t.cacheErrors)&&!(s&&s(e,t))&&ye(a,e,n,t.staleTime),_(a,e),ce(a);let o=t._prevKey;o&&ce(o);}}async function et(e){var n;if(!e)return null;let t=(n=e.headers)==null?void 0:n.get(C);t?t=t.toLowerCase().trim():t="";let r=t.split(";",1)[0],a;try{if(r.includes(j)||r.includes("+json"))a=await e.json();else if((r.includes("multipart/form-data")||r.includes(x+"x-www-form-urlencoded"))&&typeof e.formData===g)a=await e.formData();else if(r.includes(x+"octet-stream")&&typeof e.blob===g)a=await e.blob();else if(a=await e.text(),typeof a===b){let s=a.trim();if(s.startsWith("{")&&s.endsWith("}")||s.startsWith("[")&&s.endsWith("]"))try{a=JSON.parse(s);}catch(o){}}}catch(s){a=null;}return a}var Ae=(e,t,r=null)=>{let a=t.defaultResponse,n=t.cacheKey,s=qe.bind(null,n);if(!e)return {ok:false,error:r,data:a!=null?a:null,headers:null,config:t,mutate:s,isFetching:false,isSuccess:false,isError:true};let o=typeof Response===g&&e instanceof Response,u=e.data;a!==void 0&&(u==null||typeof u===K&&Object.keys(u).length===0)&&(e.data=u=a),t.flattenResponse&&(e.data=u=De(u)),t.select&&(e.data=u=t.select(u));let l=ne(e.headers);return o?{body:e.body,bodyUsed:e.bodyUsed,ok:e.ok,redirected:e.redirected,type:e.type,url:e.url,status:e.status,statusText:e.statusText,blob:()=>e.blob(),json:()=>e.json(),text:()=>e.text(),clone:()=>e.clone(),arrayBuffer:()=>e.arrayBuffer(),formData:()=>e.formData(),bytes:()=>e.bytes(),error:r,data:u,headers:l,config:t,mutate:s,isFetching:false,isSuccess:e.ok&&!r,isError:!!r}:(p(e)&&(e.error=r,e.headers=l,e.isFetching=false,e.mutate=s,e.isSuccess=e.ok&&!r,e.isError=!!r),e)};function tt(e){let t=Date.parse(e)-y();return isNaN(t)?null:Math.max(0,Math.floor(t))}function Ct(e){if(!e)return null;let t=e.headers||{},r=t["retry-after"];if(r){let o=Number(r);if(!isNaN(o)&&o>=0)return o*1e3;let u=tt(r);if(u!==null)return u}let a="ratelimit-reset",n=t[a+"-after"]||t["x-"+a+"-after"];if(n){let o=Number(n);if(!isNaN(o))return o*1e3}let s=t[a+"-at"]||t["x-"+a+"-at"];return s?tt(s):null}async function rt(e,t){let{retries:r=0,delay:a=0,backoff:n=1,maxDelay:s,retryOn:o=[],shouldRetry:u}=t,l=0,i=a,m=r>0?r:0,c;for(;l<=m;){if(l>0&&c){let f=c.config,H=f.onRetry;H&&(await w(H,c,l),f._isAutoKey&&(f._prevKey=f.cacheKey,f.cacheKey=$(f,false)));}c=await e(l>0,l);let R=c.error;if(!R){if(u&&l0&&await N(n),o=await e(),s++,!(a>0&&s>=a||!t||r&&r(o,s)));)await N(t);return o}async function nt(e,t,r){let a=await t(e),n=a.error;if(!n)return Ie(a,r),a;r.onError&&await w(r.onError,n);let s=n.isCancelled;if(!s&&r.logger&&qt(r,"FETCH ERROR",n),Ie(a,r,true),!s||r.rejectCancelled){let u=r.strategy;if(u===te)return Promise.reject(n);u==="silent"&&await new Promise(()=>null);}return a}function st(e,t,r){e.status=e.status||(t==null?void 0:t.status)||0,e.statusText=e.statusText||(t==null?void 0:t.statusText)||"",e.config=e.request=r,e.response=t,e.isCancelled=e.name===ee;}function qt(e,...t){let r=e.logger;r&&r.warn&&r.warn(...t);}var Be={isFetching:true};async function he(e,t=null){let r=Ce(e,t),{timeout:a,cancellable:n,cacheKey:s,dedupeTime:o,cacheTime:u,staleTime:l,refetchOnFocus:i,refetchOnReconnect:m,pollingInterval:c=0}=r,R=u!==void 0||l!==void 0,P=!!(s||a||o||R||n||i||m),f=null;if(P&&(f=$(r)),f&&R){let T=Pe(f,u,r);if(T)return T}if(f&&o){let T=be(f,o);if(T)return T}let H=r.retry||{},{retries:ot=0,resetTimeout:it}=H,Fe=async(T=false,Qe=0)=>{Qe||(f&&!T&&(l?Pe(f,u,r)||(ye(f,Be,u,l),_(f,Be)):_(f,Be)),r.cacheKey=f);let Z=r.url,lt=Ke(f,Z,a,o||0,!!n,!!(a&&(!Qe||it))),D=r;D.signal=lt.signal;let X,d=null;try{r.onRequest&&await w(r.onRequest,D);let F=r.fetcher;if(d=F?await F(Z,D):await fetch(Z,D),p(d)&&(typeof Response===g&&d instanceof Response?d.data=await et(d):F&&("data"in d&&"body"in d||(d={data:d})),d.config=D,d.ok!==void 0&&!d.ok))throw new ie(`${D.method} to ${Z} failed! Status: ${d.status||null}`,D,d);X=Ae(d,D);let M=r.onResponse;M&&await w(M,X);}catch(F){let M=F;st(M,d,D),X=Ae(d,D,M);}return X},ut=ot>0?()=>rt(Fe,H):Fe,V=(T=false)=>nt(T,ut,r),Oe=c?at(V,c,r.shouldStopPolling,r.maxPollingAttempts,r.pollingDelay):V();return f&&(o&&ze(f,Oe),We(f,V,void 0,l,V,!!i,!!m)),Oe}function It(e){let t=e.endpoints;function r(n){return console.error(`Add ${n} to 'endpoints'.`),Promise.resolve(null)}let a={config:e,endpoints:t,async request(n,s={}){let o=t[n],u=o||{url:String(n)},l=u.url;if(l.startsWith("//"))throw new Error("Protocol-relative URLs are not allowed.");let i=ae(l)?(o==null?void 0:o.url)===l?Y(u,s):s:Y(Y(e,u),s);return he(l,i)}};return new Proxy(a,{get(n,s){return s in a?a[s]:t[s]?a.request.bind(null,s):r.bind(null,s)}})} -export{Je as abortRequest,I as addTimeout,Ce as buildConfig,It as createApiFetcher,pe as deleteCache,he as fetchf,he as fetchff,$ as generateCacheKey,Re as getCache,Pe as getCachedResponse,Ve as getDefaultConfig,be as getInFlightPromise,Te as isSlowConnection,qe as mutate,dt as removeRevalidators,me as revalidate,Ge as revalidateAll,ye as setCache,Tt as setDefaultConfig,Dt as subscribe};//# sourceMappingURL=index.mjs.map +var yt=Object.defineProperty;var Rt=(e,t,r)=>t in e?yt(e,t,{enumerable:true,configurable:true,writable:true,value:r}):e[t]=r;var z=(e,t,r)=>Rt(e,typeof t!="symbol"?t+"":t,r);var w="application/",J=w+"json",Ne="charset=utf-8",C="Content-Type",P="undefined",k="object",b="string",D="function",ae="AbortError",Se="TimeoutError",Q="GET",_e="HEAD",ne="reject";var Ue=10;function se(e){return e instanceof URLSearchParams}function d(e){return e!==null&&typeof e===k}function G(e){let t=Object.prototype.hasOwnProperty.call(e,"__proto__"),r=Object.prototype.hasOwnProperty.call(e,"constructor"),a=Object.prototype.hasOwnProperty.call(e,"prototype");if(!t&&!r&&!a)return e;let n={...e};return t&&delete n.__proto__,r&&delete n.constructor,a&&delete n.prototype,n}function Me(e){let t=Object.keys(e);t.sort();let r={};for(let a=0,n=t.length;a{i=typeof i===D?i():i,i=i===null||i===void 0?"":i,r[r.length]=a(l)+"="+a(i);},s=(l,i,m=0)=>{if(m>=Ue)return r;let c,p,g;if(l)if(Array.isArray(i))for(c=0,p=i.length;c{if(Object.prototype.hasOwnProperty.call(r,n)){let s=r[n];if(s!=null)return encodeURIComponent(String(s))}return a})}function oe(e){return e.includes("://")}var h=()=>Date.now(),N=()=>{};function ge(e){let t=typeof e;return e==null?false:t===b||t==="number"||t==="boolean"||Array.isArray(e)?true:typeof globalThis!==P&&typeof globalThis.Buffer!==P&&globalThis.Buffer.isBuffer(e)||e instanceof Date||se(e)?false:!!(d(e)&&(Object.getPrototypeOf(e)===Object.prototype||typeof e.toJSON===D))}async function S(e){return new Promise(t=>setTimeout(()=>t(true),e))}function De(e,t=0){return t>=Ue?e:e&&d(e)&&typeof e.data!==P?De(e.data,t+1):e}function A(e){if(!e)return {};let t={};if(e instanceof Headers)e.forEach((r,a)=>{t[a.toLowerCase()]=r;});else if(d(e))for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r.toLowerCase()]=e[r]);return t}function Ke(){return typeof window!==P&&typeof window.addEventListener===D}function ie(e,t){if(typeof DOMException!==P)return new DOMException(e,t);let r=new Error(e);return r.name=t,r}var Ee=()=>{let e=typeof navigator!==P&&navigator.connection;return e&&["slow-2g","2g","3g"].includes(e.effectiveType)};async function I(e,t,...r){if(e){if(typeof e===D){let a=await e(t,...r);a&&d(t)&&d(a)&&Object.assign(t,a);}else if(Array.isArray(e))for(let a of e){let n=await a(t,...r);n&&d(t)&&d(n)&&Object.assign(t,n);}}}var ue=class extends Error{constructor(r,a,n){super(r);this.request=a;this.response=n;z(this,"status");z(this,"statusText");z(this,"config");z(this,"isCancelled");this.name="FetchError",this.status=n?n.status:0,this.statusText=n?n.statusText:"",this.config=a,this.isCancelled=false;}};var le=class extends ue{constructor(t,r,a){super(t,r,a),this.name="ResponseError";}};var fe=600,W=1e3,Pt=fe*W,Te=Array(fe).fill(0).map(()=>[]),q=new Map,ce=0,x=null,ze=([e,t])=>{q.delete(e);try{let r=t();r&&r instanceof Promise&&r.catch(N);}catch(r){}},B=(e,t,r)=>{if(_(e),rPt||r%W!==0){q.set(e,[setTimeout(ze.bind(null,[e,t]),r)]);return}let a=r/W,n=(ce+a)%fe;Te[n].push([e,t]),q.set(e,n),x||(x=setInterval(()=>{ce=(ce+1)%fe;let s=Te[ce];for(let o=0;o{let t=q.get(e);if(t!==void 0){if(Array.isArray(t))clearTimeout(t[0]);else {let r=Te[t],a=r.findIndex(([n])=>n===e);a!==-1&&r.splice(a,1);}q.delete(e),!q.size&&x&&(clearInterval(x),x=null);}};var H=new Map;function Je(e,t,r,a,n,s){if(!e)return new AbortController;let o=h(),u=H.get(e),l=null;if(u){let m=u[0],c=u[3];if(!c&&o-u[2]{ke(e,ie(t+" aborted due to timeout",Se));},r),i}async function ke(e,t=null){if(e){let r=H.get(e);r&&(t&&r[0].abort(t),me(e));}}function me(e){_(e),H.delete(e);}function Ge(e,t){let r=H.get(e);r&&(r[4]=t);}function be(e,t){if(!e)return null;let r=H.get(e);return r&&r[4]&&!r[3]&&h()-r[2]{if(!n[r])return;n[1]=a;let s=t?n[4]:n[0];s&&Promise.resolve(s(t)).catch(N);});}async function pe(e,t=false){if(!e)return null;let r=M.get(e);if(r){r[1]=h();let a=t?r[4]:r[0];if(a)return await a(t)}return null}function gt(e){Ze(e);let t=e==="focus"?5:6;M.forEach((r,a)=>{r[t]&&Dt(a);});}function xe(e){if(U.has(e))return;let t=$e.bind(null,e,true),r=Ye.get(e);if(r){let a=r(t);U.set(e,a);return}Ke()&&(window.addEventListener(e,t),U.set(e,()=>window.removeEventListener(e,t)));}function Ze(e){let t=U.get(e);t&&(t(),U.delete(e));}function Ve(e,t,r,a,n,s,o){let u=M.get(e);u?(u[0]=t,u[1]=h(),u[2]=We,u[3]=a,u[4]=n,u[5]=s,u[6]=o):M.set(e,[t,h(),We,a,n,s,o]),s&&xe("focus"),o&&xe("online"),a&&B("s:"+e,pe.bind(null,e,true),a*1e3);}function Dt(e){M.delete(e),_("s:"+e);}var $=new Map;function Et(e){let t=$.get(e);return t||(t=new Set,$.set(e,t)),t}function Tt(e,t){Et(e).add(t);}function bt(e,t){let r=$.get(e);r&&(r.delete(t),r.size===0&&$.delete(e));}function L(e,t){let r=$.get(e);if(r)if(r.size===1){let a=r.values().next().value;a(t);}else r.forEach(a=>a(t));}function xt(e,t){return e?(Tt(e,t),()=>{bt(e,t);}):N}var we=(Ee()?60:30)*1e3,Z={strategy:ne,timeout:we,headers:{Accept:J+", text/plain, */*","Accept-Encoding":"gzip, deflate, br"},retry:{delay:we/30,maxDelay:we,resetTimeout:true,backoff:1.5,retryOn:[408,409,425,429,500,502,503,504]}};function wt(e){let t=G(e);return j({},t,Z)}function tt(){return {...Z}}function Ae(e,t){if(!t)return Xe(e,tt());let r=G(t),a=j(Z,r);return Xe(e,a)}function Xe(e,t){var i;let r=t.method;r=r?r.toUpperCase():Q;let a;r!==Q&&r!==_e&&(a=(i=t.body)!=null?i:t.data,a&&typeof a!==b&&ge(a)&&(a=JSON.stringify(a))),Ct(t.headers,a);let n=t.withCredentials?"include":t.credentials,s=je(e,t.urlPathParams),o=Le(s,t.params),l=oe(e)?"":t.baseURL||t.apiUrl||"";return t.url=l+o,t.method=r,t.credentials=n,t.body=a,t}function Ct(e,t){if(!e||!t||t instanceof FormData||typeof Blob!==P&&t instanceof Blob||typeof File!==P&&t instanceof File||typeof ReadableStream!==P&&t instanceof ReadableStream)return;let r;if(se(t))r=w+"x-www-form-urlencoded";else if(t instanceof ArrayBuffer||ArrayBuffer.isView(t))r=w+"octet-stream";else if(ge(t))r=J+";"+Ne;else return;e instanceof Headers?e.has(C)||e.set(C,r):d(e)&&!Array.isArray(e)&&!e[C]&&(e[C]=r);}function j(e,t,r={}){return Object.assign(r,e,t),et("retry",e,t,r),et("headers",e,t,r),Ce("onRequest",e,t,r),Ce("onResponse",e,t,r),Ce("onError",e,t,r),r}function Ce(e,t,r,a){let n=t[e],s=r[e];if(!n&&!s)return;if(!n){a[e]=s;return}if(!s){a[e]=n;return}let o=Array.isArray(n)?n:[n],u=Array.isArray(s)?s:[s];a[e]=e==="onResponse"?u.concat(o):o.concat(u);}function et(e,t,r,a){if(r[e]){let n=t[e],s=r[e];if(e==="headers"&&(n instanceof Headers||s instanceof Headers)){let o=A(n),u=A(s);a[e]={...o,...u};}else a[e]={...n,...s};}}var ye=new Map,F="|",Ie=64,rt=/[^\w\-_|/:@.?=&~%#]/g,at=/[^\w\-_|/:@.?=&~%#]/,At=new Set(["accept","accept-language","accept-encoding","authorization","content-type","referer","origin","user-agent","cookie","x-api-key","x-requested-with","x-client-id","x-tenant-id","x-user-id","x-app-version","x-feature-flag","x-device-id","x-platform","x-session-id","x-locale"]);function V(e,t=true){let r=e.cacheKey;if(r&&t)return typeof r===b?r:r(e);let{url:a="",method:n=Q,headers:s=null,body:o=null,credentials:u="same-origin"}=e,l="";if(s){let c;s instanceof Headers?c=A(s):c=s;let p=Object.keys(c),g=p.length;g>1&&p.sort();let f="";for(let E=0;E{i+=p+"="+c+"&";}),i.length>Ie&&(i=Y(i));else if(typeof Blob!==P&&o instanceof Blob||typeof File!==P&&o instanceof File)i="BF"+o.size+o.type;else if(o instanceof ArrayBuffer||ArrayBuffer.isView(o))i="AB"+o.byteLength;else {let c=d(o)?JSON.stringify(Me(o)):String(o);i=c.length>Ie?Y(c):c;}let m=n+F+a+F+u+F+l+F+i;return at.test(m)?m.replace(rt,""):m}function nt(e){return e.expiry?h()>e.expiry:false}function Re(e){return ye.get(e)}function Pe(e,t,r,a){if(r===0){de(e);return}let n=h(),s=r?r*1e3:0,o=a?a*1e3:0;ye.set(e,{data:t,time:n,stale:o>0?n+o:void 0,expiry:r===-1?void 0:n+s}),s>0&&B("c:"+e,()=>{de(e,true);},s);}function de(e,t=false){if(t){let r=Re(e);if(!r||!nt(r))return}ye.delete(e);}async function qe(e,t,r){if(!e)return null;let a=Re(e);if(!a)return null;let n=d(t)?G(t):t,s={...a.data,data:n},o={...a,data:s};return ye.set(e,o),L(e,s),r&&r.refetch?await pe(e):null}function X(e,t,r){if(!e||t===void 0||t===null)return null;let a=r.cacheBuster||Z.cacheBuster;if(a&&a(r)||r.cache&&r.cache==="reload")return null;let n=Re(e);return n?nt(n)?(de(e),null):n.data:null}function Be(e,t,r=false){let a=t.cacheKey;if(a){let n=t.cacheTime,s=t.skipCache;n&&(!r||t.cacheErrors)&&!(s&&s(e,t))&&Pe(a,e,n,t.staleTime),L(a,e),me(a);let o=t._prevKey;o&&me(o);}}async function st(e){var n;if(!e)return null;let t=(n=e.headers)==null?void 0:n.get(C);t?t=t.toLowerCase().trim():t="";let r=t.split(";",1)[0],a;try{if(r.includes(J)||r.includes("+json"))a=await e.json();else if((r.includes("multipart/form-data")||r.includes(w+"x-www-form-urlencoded"))&&typeof e.formData===D)a=await e.formData();else if(r.includes(w+"octet-stream")&&typeof e.blob===D)a=await e.blob();else if(a=await e.text(),typeof a===b){let s=a.trim();if(s.startsWith("{")&&s.endsWith("}")||s.startsWith("[")&&s.endsWith("]"))try{a=JSON.parse(s);}catch(o){}}}catch(s){a=null;}return a}var Fe=(e,t,r=null)=>{let a=t.defaultResponse,n=t.cacheKey,s=qe.bind(null,n);if(!e)return {ok:false,error:r,data:a!=null?a:null,headers:null,config:t,mutate:s,isFetching:false,isSuccess:false,isError:true};let o=typeof Response===D&&e instanceof Response,u=e.data;a!==void 0&&(u==null||typeof u===k&&Object.keys(u).length===0)&&(e.data=u=a),t.flattenResponse&&(e.data=u=De(u)),t.select&&(e.data=u=t.select(u));let l=A(e.headers);return o?{body:e.body,bodyUsed:e.bodyUsed,ok:e.ok,redirected:e.redirected,type:e.type,url:e.url,status:e.status,statusText:e.statusText,blob:()=>e.blob(),json:()=>e.json(),text:()=>e.text(),clone:()=>e.clone(),arrayBuffer:()=>e.arrayBuffer(),formData:()=>e.formData(),bytes:()=>e.bytes(),error:r,data:u,headers:l,config:t,mutate:s,isFetching:false,isSuccess:e.ok&&!r,isError:!!r}:(d(e)&&(e.error=r,e.headers=l,e.isFetching=false,e.mutate=s,e.isSuccess=e.ok&&!r,e.isError=!!r),e)};function ot(e){let t=Date.parse(e)-h();return isNaN(t)?null:Math.max(0,Math.floor(t))}function It(e){if(!e)return null;let t=e.headers||{},r=t["retry-after"];if(r){let o=Number(r);if(!isNaN(o)&&o>=0)return o*1e3;let u=ot(r);if(u!==null)return u}let a="ratelimit-reset",n=t[a+"-after"]||t["x-"+a+"-after"];if(n){let o=Number(n);if(!isNaN(o))return o*1e3}let s=t[a+"-at"]||t["x-"+a+"-at"];return s?ot(s):null}async function it(e,t){let{retries:r=0,delay:a=0,backoff:n=1,maxDelay:s,retryOn:o=[],shouldRetry:u}=t,l=0,i=a,m=r>0?r:0,c;for(;l<=m;){if(l>0&&c){let f=c.config,E=f.onRetry;E&&(await I(E,c,l),f._isAutoKey&&(f._prevKey=f.cacheKey,f.cacheKey=V(f,false)));}c=await e(l>0,l);let p=c.error;if(!p){if(u&&l0&&await S(n),o=await e(),s++,!(a>0&&s>=a||!t||r&&r(o,s)));)await S(t);return o}async function lt(e,t,r){let a=await t(e),n=a.error;if(!n)return Be(a,r),a;r.onError&&await I(r.onError,n);let s=n.isCancelled;if(!s&&r.logger&&Bt(r,"FETCH ERROR",n),Be(a,r,true),!s||r.rejectCancelled){let u=r.strategy;if(u===ne)return Promise.reject(n);u==="silent"&&await new Promise(()=>null);}return a}function ct(e,t,r){e.status=e.status||(t==null?void 0:t.status)||0,e.statusText=e.statusText||(t==null?void 0:t.statusText)||"",e.config=e.request=r,e.response=t,e.isCancelled=e.name===ae;}function Bt(e,...t){let r=e.logger;r&&r.warn&&r.warn(...t);}var Oe=Object.freeze({isFetching:true});async function he(e,t=null){if(t&&typeof t.cacheKey=="string"){let R=X(t.cacheKey,t.cacheTime,t);if(R)return R}let r=Ae(e,t),{timeout:a,cancellable:n,cacheKey:s,dedupeTime:o,cacheTime:u,staleTime:l,refetchOnFocus:i,refetchOnReconnect:m,pollingInterval:c=0}=r,p=u!==void 0||l!==void 0,g=!!(s||a||o||p||n||i||m),f=null;if(g&&(f=V(r)),f&&p){let R=X(f,u,r);if(R)return R}if(f&&o){let R=be(f,o);if(R)return R}let E=r.retry||{},{retries:ft=0,resetTimeout:mt}=E,ve=async(R=false,te=0)=>{te||(f&&!R&&(l?X(f,u,r)||(Pe(f,Oe,u,l),L(f,Oe)):L(f,Oe)),r.cacheKey=f);let O=r.url,dt=Je(f,O,a,o||0,!!n,!!(a&&(!te||mt))),T=r;T.signal=dt.signal;let re,y=null;try{r.onRequest&&(f&&o&&!te&&await null,await I(r.onRequest,T));let v=r.fetcher;if(y=v?await v(O,T):await fetch(O,T),d(y)&&(typeof Response===D&&y instanceof Response?y.data=await st(y):v&&("data"in y&&"body"in y||(y={data:y})),y.config=T,y.ok!==void 0&&!y.ok))throw new le(`${T.method} to ${O} failed! Status: ${y.status||null}`,T,y);re=Fe(y,T);let K=r.onResponse;K&&await I(K,re);}catch(v){let K=v;ct(K,y,T),re=Fe(y,T,K);}return re},pt=ft>0?(R=false)=>it((te,O)=>ve(R,O),E):ve,ee=(R=false)=>lt(R,pt,r),Qe=c?ut(ee,c,r.shouldStopPolling,r.maxPollingAttempts,r.pollingDelay):ee();return f&&(o&&Ge(f,Qe),(l||i||m)&&Ve(f,ee,void 0,l,ee,!!i,!!m)),Qe}function Ft(e){let t=e.endpoints;function r(n){return console.error(`Add ${n} to 'endpoints'.`),Promise.resolve(null)}let a={config:e,endpoints:t,async request(n,s={}){let o=t[n],u=o||{url:String(n)},l=u.url;if(l.startsWith("//"))throw new Error("Protocol-relative URLs are not allowed.");let i=oe(l)?(o==null?void 0:o.url)===l?j(u,s):s:j(j(e,u),s);return he(l,i)}};return new Proxy(a,{get(n,s){return s in a?a[s]:t[s]?a.request.bind(null,s):r.bind(null,s)}})} +export{ke as abortRequest,B as addTimeout,Ae as buildConfig,ie as createAbortError,Ft as createApiFetcher,de as deleteCache,he as fetchf,he as fetchff,V as generateCacheKey,Re as getCache,X as getCachedResponse,tt as getDefaultConfig,be as getInFlightPromise,Ee as isSlowConnection,qe as mutate,gt as removeRevalidators,pe as revalidate,$e as revalidateAll,Pe as setCache,wt as setDefaultConfig,ht as setEventProvider,xt as subscribe};//# sourceMappingURL=index.mjs.map //# sourceMappingURL=index.mjs.map \ No newline at end of file diff --git a/dist/browser/index.mjs.map b/dist/browser/index.mjs.map index c3d4ba97..b2c6a805 100644 --- a/dist/browser/index.mjs.map +++ b/dist/browser/index.mjs.map @@ -1 +1 @@ -{"version":3,"sources":["../../src/constants.ts","../../src/utils.ts","../../src/interceptor-manager.ts","../../src/errors/fetch-error.ts","../../src/errors/response-error.ts","../../src/timeout-wheel.ts","../../src/inflight-manager.ts","../../src/hash.ts","../../src/revalidator-manager.ts","../../src/pubsub-manager.ts","../../src/config-handler.ts","../../src/cache-manager.ts","../../src/response-parser.ts","../../src/retry-handler.ts","../../src/polling-handler.ts","../../src/error-handler.ts","../../src/request-handler.ts","../../src/api-handler.ts"],"names":["APPLICATION_CONTENT_TYPE","APPLICATION_JSON","CHARSET_UTF_8","CONTENT_TYPE","UNDEFINED","OBJECT","STRING","FUNCTION","ABORT_ERROR","TIMEOUT_ERROR","GET","HEAD","REJECT","MAX_DEPTH","isSearchParams","data","isObject","value","sanitizeObject","obj","safeObj","sortObject","keys","sortedObj","i","len","key","appendQueryStringToUrl","baseUrl","queryString","appendQueryParams","url","params","encodedQueryString","s","encode","add","k","v","buildParams","prefix","depth","replaceUrlPathParams","urlPathParams","match","isAbsoluteUrl","timeNow","noop","isJSONSerializable","delayInvocation","ms","resolve","flattenData","processHeaders","headers","headersObject","isBrowser","isSlowConnection","conn","applyInterceptors","interceptors","args","interceptor","FetchError","message","request","response","__publicField","ResponseError","WHEEL_SIZE","SECOND","MAX_WHEEL_MS","wheel","keyMap","position","timer","handleCallback","callback","result","e","addTimeout","cb","removeTimeout","seconds","slot","slotOrTimeout","inFlight","markInFlight","timeout","dedupeTime","isCancellable","isTimeoutEnabled","item","prevPromise","prevController","prevIsCancellable","controller","abortRequest","error","removeInFlight","setInFlightPromise","promise","getInFlightPromise","prevReq","hash","str","char","DEFAULT_TTL","revalidators","eventHandlers","revalidateAll","type","isStaleRevalidation","flagIndex","now","entry","revalidator","revalidate","removeRevalidators","removeEventHandler","removeRevalidator","addEventHandler","event","handler","addRevalidator","revalidatorFn","ttl","staleTime","bgRevalidatorFn","refetchOnFocus","refetchOnReconnect","listeners","ensureListenerSet","addListener","fn","removeListener","set","notifySubscribers","fns","subscribe","defaultTimeoutMs","defaultConfig","setDefaultConfig","customConfig","sanitized","getDefaultConfig","buildConfig","reqConfig","buildFetcherConfig","merged","mergeConfigs","requestConfig","_a","method","body","setContentTypeIfNeeded","credentials","dynamicUrl","urlPath","baseURL","contentTypeValue","baseConfig","overrideConfig","mergedConfig","mergeConfig","mergeInterceptors","property","targetConfig","baseInterceptor","newInterceptor","baseArr","newArr","_cache","DELIMITER","MIN_LENGTH_TO_HASH","CACHE_KEY_SANITIZE_PATTERN","CACHE_KEY_HEADER_WHITELIST","generateCacheKey","config","cacheKeyCheck","headersString","bodyString","o","isCacheExpired","isCacheStale","getCache","setCache","deleteCache","time","ttlMs","removeExpired","mutate","newData","settings","updatedData","updatedResponse","updatedEntry","getCachedResponse","cacheKey","cacheTime","buster","isExpired","isStale","handleResponseCache","output","isError","skipCache","prevCacheKey","parseResponseData","contentType","mimeType","trimmed","_error","prepareResponse","defaultResponse","mutatator","isNativeResponse","getMsFromHttpDate","dateString","getRetryAfterMs","extendedResponse","retryAfter","RATELIMIT_RESET","rateLimitResetAfter","rateLimitResetAt","withRetry","requestFn","retries","delay","backoff","maxDelay","retryOn","shouldRetry","attempt","waitTime","maxRetries","cfg","onRetry","getShouldStopRetrying","retryAfterMs","_b","customDecision","withPolling","pollingInterval","shouldStopPolling","maxAttempts","pollingDelay","pollingAttempt","withErrorHandling","isCancelled","logger","strategy","enhanceError","inFlightResponse","fetchf","fetcherConfig","cancellable","isCacheEnabled","needsCacheKey","_cacheKey","cached","inflight","retryConfig","resetTimeout","doRequestOnce","onResponse","baseRequest","requestWithErrorHandling","doRequestPromise","createApiFetcher","endpoints","handleNonImplemented","endpointName","apiHandler","endpointConfig","_endpointConfig","_target","prop"],"mappings":"8KAAO,IAAMA,CAAAA,CAA2B,cAAA,CAE3BC,CAAAA,CAAmBD,CAAAA,CAA2B,MAAA,CAC9CE,EAAAA,CAAgB,eAAA,CAChBC,CAAAA,CAAe,cAAA,CAEfC,CAAAA,CAAY,WAAA,CACZC,CAAAA,CAAS,QAAA,CACTC,EAAS,QAAA,CACTC,CAAAA,CAAW,UAAA,CAEXC,EAAAA,CAAc,YAAA,CACdC,EAAAA,CAAgB,cAAA,CAEhBC,CAAAA,CAAM,KAAA,CACNC,EAAAA,CAAO,MAAA,CAEPC,EAAAA,CAAS,QAAA,CCPtB,IAAMC,GAAY,EAAA,CAEX,SAASC,EAAAA,CAAeC,CAAAA,CAAwB,CACrD,OAAOA,CAAAA,YAAgB,eACzB,CAQO,SAASC,CAAAA,CAASC,CAAAA,CAA0C,CACjE,OAAOA,IAAU,IAAA,EAAQ,OAAOA,CAAAA,GAAUZ,CAC5C,CA8BO,SAASa,CAAAA,CAA8CC,CAAAA,CAAW,CACvE,IAAMC,CAAAA,CAAU,CAAE,GAAGD,CAAI,EAEzB,OAAA,OAAOC,CAAAA,CAAQ,SAAA,CACf,OAAQA,CAAAA,CAAgB,WAAA,CACxB,OAAOA,CAAAA,CAAQ,SAAA,CAERA,CACT,CAWO,SAASC,EAAAA,CAAWF,CAAAA,CAAkC,CAC3D,IAAMG,CAAAA,CAAO,MAAA,CAAO,IAAA,CAAKH,CAAG,CAAA,CAE5BG,CAAAA,CAAK,IAAA,EAAK,CAEV,IAAMC,CAAAA,CAAY,EAAC,CAEnB,IAAA,IAASC,EAAI,CAAA,CAAGC,CAAAA,CAAMH,CAAAA,CAAK,MAAA,CAAQE,CAAAA,CAAIC,CAAAA,CAAKD,CAAAA,EAAAA,CAAK,CAC/C,IAAME,CAAAA,CAAMJ,CAAAA,CAAKE,CAAC,CAAA,CAElBD,CAAAA,CAAUG,CAAG,CAAA,CAAIP,CAAAA,CAAIO,CAAG,EAC1B,CAEA,OAAOH,CACT,CASA,SAASI,EAAAA,CAAuBC,CAAAA,CAAiBC,CAAAA,CAA6B,CAC5E,OAAKA,CAAAA,CAIED,EAAQ,QAAA,CAAS,GAAG,CAAA,CACvB,CAAA,EAAGA,CAAO,CAAA,CAAA,EAAIC,CAAW,CAAA,CAAA,CACzB,CAAA,EAAGD,CAAO,CAAA,CAAA,EAAIC,CAAW,CAAA,CAAA,CALpBD,CAMX,CASO,SAASE,EAAAA,CAAkBC,CAAAA,CAAaC,CAAAA,CAA6B,CAC1E,GAAI,CAACA,CAAAA,CACH,OAAOD,CAAAA,CAIT,GAAIjB,EAAAA,CAAekB,CAAM,CAAA,CAAG,CAC1B,IAAMC,CAAAA,CAAqBD,CAAAA,CAAO,QAAA,EAAS,CAE3C,OAAOL,EAAAA,CAAuBI,CAAAA,CAAKE,CAAkB,CACvD,CAGA,IAAMC,CAAAA,CAAc,GACdC,CAAAA,CAAS,kBAAA,CACTC,CAAAA,CAAM,CAACC,CAAAA,CAAWC,CAAAA,GAAW,CACjCA,CAAAA,CAAI,OAAOA,CAAAA,GAAM/B,CAAAA,CAAW+B,CAAAA,EAAE,CAAIA,CAAAA,CAClCA,EAAIA,CAAAA,GAAM,IAAA,EAAYA,CAAAA,GAAM,MAAA,CAAX,EAAA,CAA4BA,CAAAA,CAC7CJ,CAAAA,CAAEA,CAAAA,CAAE,MAAM,CAAA,CAAIC,CAAAA,CAAOE,CAAC,CAAA,CAAI,GAAA,CAAMF,EAAOG,CAAC,EAC1C,CAAA,CAEMC,CAAAA,CAAc,CAACC,CAAAA,CAAgBrB,CAAAA,CAAUsB,CAAAA,CAAQ,CAAA,GAAM,CAE3D,GAAIA,CAAAA,EAAS5B,EAAAA,CACX,OAAOqB,EAGT,IAAIV,CAAAA,CAAWC,CAAAA,CAAaC,CAAAA,CAE5B,GAAIc,CAAAA,CACF,GAAI,KAAA,CAAM,OAAA,CAAQrB,CAAG,CAAA,CACnB,IAAKK,CAAAA,CAAI,CAAA,CAAGC,CAAAA,CAAMN,CAAAA,CAAI,MAAA,CAAQK,CAAAA,CAAIC,CAAAA,CAAKD,CAAAA,EAAAA,CACrCe,CAAAA,CACEC,CAAAA,CAAS,GAAA,EAAO,OAAOrB,CAAAA,CAAIK,CAAC,CAAA,GAAMnB,CAAAA,EAAUc,CAAAA,CAAIK,CAAC,EAAIA,CAAAA,CAAI,EAAA,CAAA,CAAM,GAAA,CAC/DL,CAAAA,CAAIK,CAAC,CAAA,CACLiB,CAAAA,CAAQ,CACV,CAAA,CAAA,KAAA,GAEOzB,CAAAA,CAASG,CAAG,CAAA,CACrB,IAAKO,CAAAA,IAAOP,EACVoB,CAAAA,CAAYC,CAAAA,CAAS,GAAA,CAAMd,CAAAA,CAAM,GAAA,CAAKP,CAAAA,CAAIO,CAAG,CAAA,CAAGe,CAAAA,CAAQ,CAAC,CAAA,CAAA,KAG3DL,CAAAA,CAAII,CAAAA,CAAQrB,CAAG,UAER,KAAA,CAAM,OAAA,CAAQA,CAAG,CAAA,CAC1B,IAAKK,CAAAA,CAAI,CAAA,CAAGC,CAAAA,CAAMN,CAAAA,CAAI,MAAA,CAAQK,CAAAA,CAAIC,CAAAA,CAAKD,CAAAA,EAAAA,CACrCY,CAAAA,CAAIjB,EAAIK,CAAC,CAAA,CAAE,IAAA,CAAML,CAAAA,CAAIK,CAAC,CAAA,CAAE,KAAK,CAAA,CAAA,KAG/B,IAAKE,CAAAA,IAAOP,CAAAA,CACVoB,CAAAA,CAAYb,CAAAA,CAAKP,CAAAA,CAAIO,CAAG,CAAA,CAAGe,CAAAA,CAAQ,CAAC,CAAA,CAGxC,OAAOP,CACT,CAAA,CAMMD,CAAAA,CAJmBM,CAAAA,CAAY,EAAA,CAAIP,CAAM,CAAA,CAAE,IAAA,CAAK,GAAG,EAIb,OAAA,CAAQ,SAAA,CAAW,IAAI,CAAA,CAEnE,OAAOL,EAAAA,CAAuBI,CAAAA,CAAKE,CAAkB,CACvD,CAWO,SAASS,EAAAA,CACdX,CAAAA,CACAY,CAAAA,CACQ,CACR,GAAI,CAACA,CAAAA,EAAiBZ,CAAAA,CAAI,OAAA,CAAQ,GAAG,CAAA,GAAM,EAAA,CACzC,OAAOA,CAAAA,CAKT,IAAMC,CAAAA,CAASW,CAAAA,CAGf,OAAOZ,CAAAA,CAAI,OAAA,CAAQ,mBAAA,CAAqB,CAACa,CAAAA,CAAOlB,CAAAA,GAAQ,CAEtD,GAAI,MAAA,CAAO,SAAA,CAAU,cAAA,CAAe,IAAA,CAAKM,CAAAA,CAAQN,CAAG,CAAA,CAAG,CACrD,IAAMT,CAAAA,CAAQe,CAAAA,CAAON,CAAG,CAAA,CAGxB,GAA2BT,CAAAA,EAAU,IAAA,CACnC,OAAO,kBAAA,CAAmB,MAAA,CAAOA,CAAK,CAAC,CAE3C,CAEA,OAAO2B,CACT,CAAC,CACH,CAUO,SAASC,EAAAA,CAAcd,CAAAA,CAAsB,CAClD,OAAOA,CAAAA,CAAI,QAAA,CAAS,KAAK,CAC3B,CAEO,IAAMe,CAAAA,CAAU,IAAM,IAAA,CAAK,GAAA,EAAI,CAEzBC,CAAAA,CAAO,IAAM,CAAC,CAAA,CAcpB,SAASC,EAAAA,CAAmB/B,CAAAA,CAAqB,CACtD,IAAM,EAAI,OAAOA,CAAAA,CAEjB,OAA2BA,CAAAA,EAAU,IAAA,CAC5B,KAAA,CAGL,CAAA,GAAMX,CAAAA,EAAU,CAAA,GAAM,QAAA,EAAY,CAAA,GAAM,SAAA,EAIxC,KAAA,CAAM,OAAA,CAAQW,CAAK,CAAA,CACd,IAAA,CAIP,OAAO,UAAA,GAAeb,CAAAA,EACtB,OAAO,UAAA,CAAW,MAAA,GAAWA,CAAAA,EAC7B,UAAA,CAAW,MAAA,CAAO,QAAA,CAASa,CAAK,CAAA,EAK9BA,aAAiB,IAAA,EAAQH,EAAAA,CAAeG,CAAK,CAAA,CACxC,KAAA,CAGL,CAAA,EAAAD,CAAAA,CAASC,CAAK,CAAA,GACF,MAAA,CAAO,cAAA,CAAeA,CAAK,CAAA,GAG3B,MAAA,CAAO,WAKjB,OAAOA,CAAAA,CAAM,MAAA,GAAWV,CAAAA,CAAAA,CAMhC,CAEA,eAAsB0C,CAAAA,CAAgBC,CAAAA,CAA8B,CAClE,OAAO,IAAI,OAAA,CAASC,CAAAA,EAClB,UAAA,CAAW,IACFA,CAAAA,CAAQ,IAAI,CAAA,CAClBD,CAAE,CACP,CACF,CAWO,SAASE,EAAAA,CAAYrC,CAAAA,CAAW0B,CAAAA,CAAQ,CAAA,CAAQ,CACrD,OAAIA,CAAAA,EAAS5B,GACJE,CAAAA,CAGLA,CAAAA,EAAQC,CAAAA,CAASD,CAAI,CAAA,EAAK,OAAOA,CAAAA,CAAK,IAAA,GAASX,CAAAA,CAC1CgD,EAAAA,CAAYrC,CAAAA,CAAK,IAAA,CAAM0B,CAAAA,CAAQ,CAAC,EAGlC1B,CACT,CAYO,SAASsC,EAAAA,CACdC,CAAAA,CACe,CACf,GAAI,CAACA,CAAAA,CACH,OAAO,EAAC,CAGV,IAAMC,CAAAA,CAA+B,EAAC,CAGtC,GAAID,CAAAA,YAAmB,OAAA,CACrBA,CAAAA,CAAQ,OAAA,CAAQ,CAACrC,CAAAA,CAAOS,CAAAA,GAAQ,CAC9B6B,CAAAA,CAAc7B,CAAG,CAAA,CAAIT,EACvB,CAAC,CAAA,CAAA,KAAA,GACQD,CAAAA,CAASsC,CAAO,CAAA,CAEzB,IAAA,GAAW,CAAC5B,CAAAA,CAAKT,CAAK,CAAA,GAAK,MAAA,CAAO,OAAA,CAAQqC,CAAO,CAAA,CAG/CC,CAAAA,CAAc7B,EAAI,WAAA,EAAa,CAAA,CAAIT,CAAAA,CAIvC,OAAOsC,CACT,CAOO,SAASC,EAAAA,EAAqB,CAEnC,OACE,OAAO,MAAA,GAAWpD,CAAAA,EAAa,OAAO,MAAA,CAAO,gBAAA,GAAqBG,CAEtE,CAMO,IAAMkD,EAAAA,CAAmB,IAAe,CAE7C,GAAI,CAACD,EAAAA,EAAU,CACb,OAAO,MAAA,CAGT,IAAME,CAAAA,CAAO,SAAA,EAAc,SAAA,CAAkB,UAAA,CAE7C,OAAOA,CAAAA,EAAQ,CAAC,SAAA,CAAW,IAAA,CAAM,IAAI,CAAA,CAAE,QAAA,CAASA,CAAAA,CAAK,aAAa,CACpE,ECzWA,eAAsBC,CAAAA,CAKpBC,CAAAA,CAA6B7C,CAAAA,CAAAA,GAAY8C,CAAAA,CAA2B,CACpE,GAAKD,CAAAA,CAAAA,CAIL,GAAI,OAAOA,CAAAA,GAAiBrD,CAAAA,CAAU,CACpC,IAAMU,EAAQ,MAAO2C,CAAAA,CACnB7C,CAAAA,CACA,GAAG8C,CACL,CAAA,CAEI5C,CAAAA,EAASD,CAAAA,CAASD,CAAI,CAAA,EAAKC,CAAAA,CAASC,CAAK,CAAA,EAC3C,MAAA,CAAO,OAAOF,CAAAA,CAAME,CAAK,EAE7B,CAAA,KAAA,GAAW,KAAA,CAAM,OAAA,CAAQ2C,CAAY,CAAA,CACnC,IAAA,IAAWE,CAAAA,IAAeF,CAAAA,CAAc,CACtC,IAAM3C,CAAAA,CAAQ,MAAM6C,CAAAA,CAAY/C,CAAAA,CAAM,GAAG8C,CAAI,CAAA,CAEzC5C,CAAAA,EAASD,CAAAA,CAASD,CAAI,CAAA,EAAKC,CAAAA,CAASC,CAAK,CAAA,EAC3C,MAAA,CAAO,MAAA,CAAOF,EAAME,CAAK,EAE7B,CAAA,CAEJ,CCjCO,IAAM8C,EAAAA,CAAN,cAKG,KAAM,CAMd,WAAA,CACEC,CAAAA,CACOC,CAAAA,CAMAC,CAAAA,CAMP,CACA,MAAMF,CAAO,CAAA,CAbN,IAAA,CAAA,OAAA,CAAAC,CAAAA,CAMA,IAAA,CAAA,QAAA,CAAAC,CAAAA,CAbTC,CAAAA,CAAA,IAAA,CAAA,QAAA,CAAA,CACAA,CAAAA,CAAA,IAAA,CAAA,YAAA,CAAA,CACAA,CAAAA,CAAA,IAAA,CAAA,QAAA,CAAA,CACAA,CAAAA,CAAA,IAAA,CAAA,aAAA,CAAA,CAmBE,KAAK,IAAA,CAAO,YAAA,CACZ,IAAA,CAAK,MAAA,CAASD,CAAAA,CAAWA,CAAAA,CAAS,MAAA,CAAS,CAAA,CAC3C,IAAA,CAAK,UAAA,CAAaA,CAAAA,CAAWA,CAAAA,CAAS,UAAA,CAAa,EAAA,CACnD,KAAK,MAAA,CAASD,CAAAA,CACd,IAAA,CAAK,WAAA,CAAc,MACrB,CACF,CAAA,CCpCO,IAAMG,EAAAA,CAAN,cAKGL,EAA+D,CACvE,WAAA,CACEC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CAMA,CACA,KAAA,CAAMF,CAAAA,CAASC,CAAAA,CAASC,CAAQ,CAAA,CAEhC,IAAA,CAAK,IAAA,CAAO,gBACd,CACF,CAAA,CCHA,IAAMG,EAAAA,CAAa,GAAA,CACbC,GAAS,GAAA,CACTC,EAAAA,CAAeF,EAAAA,CAAaC,EAAAA,CAC5BE,CAAAA,CAAyB,KAAA,CAAMH,EAAU,CAAA,CAC5C,IAAA,CAAK,CAAC,CAAA,CACN,GAAA,CAAI,IAAM,EAAE,CAAA,CAETI,CAAAA,CAAS,IAAI,GAAA,CACfC,CAAAA,CAAW,CAAA,CACXC,CAAAA,CAA+B,IAAA,CAE7BC,EAAAA,CAAiB,CAAC,CAAClD,CAAAA,CAAKmD,CAAQ,CAAA,GAAyB,CAC7DJ,CAAAA,CAAO,MAAA,CAAO/C,CAAG,CAAA,CAEjB,GAAI,CACF,IAAMoD,CAAAA,CAASD,CAAAA,EAAS,CACpBC,CAAAA,EAAUA,CAAAA,YAAkB,OAAA,EAE9BA,CAAAA,CAAO,MAAM/B,CAAI,EAErB,CAAA,MAAQgC,CAAAA,CAAA,CAER,CACF,CAAA,CAEaC,CAAAA,CAAa,CACxBtD,CAAAA,CACAuD,CAAAA,CACA/B,CAAAA,GACS,CAIT,GAHAgC,EAAcxD,CAAG,CAAA,CAGbwB,CAAAA,CAAKqB,EAAAA,EAAgBrB,CAAAA,CAAKoB,EAAAA,GAAW,CAAA,CAAG,CAC1CG,CAAAA,CAAO,GAAA,CAAI/C,CAAAA,CAAK,CAAC,UAAA,CAAWkD,EAAAA,CAAe,KAAK,IAAA,CAAM,CAAClD,CAAAA,CAAKuD,CAAE,CAAC,CAAA,CAAG/B,CAAE,CAAC,CAAC,CAAA,CAEtE,MACF,CAGA,IAAMiC,CAAAA,CAAUjC,EAAKoB,EAAAA,CACfc,CAAAA,CAAAA,CAAQV,CAAAA,CAAWS,CAAAA,EAAWd,EAAAA,CAEpCG,CAAAA,CAAMY,CAAI,CAAA,CAAE,IAAA,CAAK,CAAC1D,CAAAA,CAAKuD,CAAE,CAAC,CAAA,CAC1BR,CAAAA,CAAO,GAAA,CAAI/C,CAAAA,CAAK0D,CAAI,CAAA,CAEfT,CAAAA,GACHA,CAAAA,CAAQ,WAAA,CAAY,IAAM,CACxBD,CAAAA,CAAAA,CAAYA,CAAAA,CAAW,CAAA,EAAKL,EAAAA,CAC5BG,CAAAA,CAAME,CAAQ,EAAE,OAAA,CAAQE,EAAc,CAAA,CACtCJ,CAAAA,CAAME,CAAQ,CAAA,CAAI,EAAC,CAEf,CAACD,CAAAA,CAAO,IAAA,EAAQE,CAAAA,GAClB,aAAA,CAAcA,CAAK,EACnBA,CAAAA,CAAQ,IAAA,EAEZ,CAAA,CAAGL,EAAM,CAAA,EAEb,CAAA,CAEaY,CAAAA,CAAiBxD,CAAAA,EAAsB,CAClD,IAAM2D,CAAAA,CAAgBZ,CAAAA,CAAO,GAAA,CAAI/C,CAAG,EAEhC2D,CAAAA,GAAkB,MAAA,GAEhB,KAAA,CAAM,OAAA,CAAQA,CAAa,CAAA,CAC7B,YAAA,CAAaA,CAAAA,CAAc,CAAC,CAAC,CAAA,CAE7Bb,CAAAA,CAAMa,CAAa,CAAA,CAAE,OACnBb,CAAAA,CAAMa,CAAa,CAAA,CAAE,SAAA,CAAU,CAAC,CAAChD,CAAC,CAAA,GAAMA,CAAAA,GAAMX,CAAG,CAAA,CACjD,CACF,CAAA,CAGF+C,CAAAA,CAAO,OAAO/C,CAAG,CAAA,CAEb,CAAC+C,CAAAA,CAAO,IAAA,EAAQE,CAAAA,GAClB,aAAA,CAAcA,CAAK,CAAA,CACnBA,CAAAA,CAAQ,IAAA,CAAA,EAGd,EC5EA,IAAMW,CAAAA,CAAsC,IAAI,GAAA,CAazC,SAASC,EAAAA,CACd7D,CAAAA,CACAK,CAAAA,CACAyD,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACiB,CACjB,GAAI,CAACjE,CAAAA,CACH,OAAO,IAAI,eAAA,CAGb,IAAMkE,CAAAA,CAAON,CAAAA,CAAS,GAAA,CAAI5D,CAAG,CAAA,CACzBmE,CAAAA,CAAuC,IAAA,CAG3C,GAAID,CAAAA,CAAM,CACR,IAAME,CAAAA,CAAiBF,CAAAA,CAAK,CAAC,CAAA,CACvBG,CAAAA,CAAoBH,CAAAA,CAAK,CAAC,CAAA,CAGhC,GACE,CAACG,CAAAA,EACDjD,CAAAA,EAAQ,CAAI8C,CAAAA,CAAK,CAAC,CAAA,CAAIH,CAAAA,EACtB,CAACK,CAAAA,CAAe,MAAA,CAAO,OAAA,CAEvB,OAAOA,CAAAA,CAKLC,CAAAA,EACFD,CAAAA,CAAe,KAAA,CACb,IAAI,YAAA,CAAa,4BAAA,CAA8BtF,EAAW,CAC5D,CAAA,CAGF0E,EAAcxD,CAAG,CAAA,CACjBmE,CAAAA,CAAcD,CAAAA,CAAK,CAAC,EACtB,CAEA,IAAMI,CAAAA,CAAa,IAAI,eAAA,CAEvB,OAAAV,CAAAA,CAAS,GAAA,CAAI5D,EAAK,CAChBsE,CAAAA,CACAL,CAAAA,CACA7C,CAAAA,EAAQ,CACR4C,CAAAA,CACAG,CACF,CAAC,CAAA,CAEGF,CAAAA,EACFX,CAAAA,CACEtD,CAAAA,CACA,IAAM,CACJuE,GACEvE,CAAAA,CACA,IAAI,YAAA,CAAaK,CAAAA,CAAM,yBAAA,CAA2BtB,EAAa,CACjE,EACF,CAAA,CACA+E,CACF,CAAA,CAGKQ,CACT,CASA,eAAsBC,GACpBvE,CAAAA,CACAwE,CAAAA,CAAsC,IAAA,CACvB,CAEf,GAAIxE,CAAAA,CAAK,CACP,IAAMkE,CAAAA,CAAON,CAAAA,CAAS,GAAA,CAAI5D,CAAG,CAAA,CAEzBkE,CAAAA,GAEEM,GACiBN,CAAAA,CAAK,CAAC,CAAA,CACd,KAAA,CAAMM,CAAK,CAAA,CAGxBC,EAAAA,CAAezE,CAAG,CAAA,EAEtB,CACF,CAOO,SAASyE,EAAAA,CAAezE,CAAAA,CAA0B,CACvDwD,CAAAA,CAAcxD,CAAI,CAAA,CAClB4D,CAAAA,CAAS,MAAA,CAAO5D,CAAI,EACtB,CAsBO,SAAS0E,EAAAA,CACd1E,CAAAA,CACA2E,CAAAA,CACM,CACN,IAAMT,CAAAA,CAAON,CAAAA,CAAS,GAAA,CAAI5D,CAAG,CAAA,CACzBkE,CAAAA,GAEFA,CAAAA,CAAK,CAAC,CAAA,CAAIS,CAAAA,CAEVf,CAAAA,CAAS,GAAA,CAAI5D,CAAAA,CAAKkE,CAAI,CAAA,EAE1B,CASO,SAASU,EAAAA,CACd5E,CAAAA,CACA+D,CAAAA,CACmB,CACnB,GAAI,CAAC/D,CAAAA,CACH,OAAO,IAAA,CAGT,IAAM6E,CAAAA,CAAUjB,CAAAA,CAAS,GAAA,CAAI5D,CAAG,EAEhC,OACE6E,CAAAA,EAEAA,CAAAA,CAAQ,CAAC,CAAA,EAET,CAACA,CAAAA,CAAQ,CAAC,CAAA,EAEVzD,CAAAA,EAAQ,CAAIyD,CAAAA,CAAQ,CAAC,CAAA,CAAId,GAEzB,CAACc,CAAAA,CAAQ,CAAC,CAAA,CAAE,MAAA,CAAO,OAAA,CAEZA,CAAAA,CAAQ,CAAC,CAAA,CAGX,IACT,CC5MO,SAASC,CAAAA,CAAKC,CAAAA,CAAqB,CACxC,IAAID,CAAAA,CAAO,CAAA,CAEX,IAAA,IAAShF,CAAAA,CAAI,CAAA,CAAGC,CAAAA,CAAMgF,CAAAA,CAAI,MAAA,CAAQjF,CAAAA,CAAIC,CAAAA,CAAKD,CAAAA,EAAAA,CAAK,CAC9C,IAAMkF,EAAOD,CAAAA,CAAI,UAAA,CAAWjF,CAAC,CAAA,CAC7BgF,CAAAA,CAAQA,CAAAA,CAAO,EAAA,CAAmBE,CAAAA,CAAQ,EAC5C,CAEA,OAAO,MAAA,CAAOF,CAAI,CACpB,CCmBA,IAAMG,EAAAA,CAAc,GAAA,CAAS,GAAA,CACvBC,CAAAA,CAAe,IAAI,GAAA,CAUnBC,EAAAA,CAAgB,IAAI,GAAA,CAUnB,SAASC,EAAAA,CACdC,CAAAA,CACAC,CAAAA,CAA+B,KAC/B,CACA,IAAMC,CAAAA,CAAYF,CAAAA,GAAS,OAAA,CAAU,CAAA,CAAI,CAAA,CACnCG,CAAAA,CAAMpE,CAAAA,EAAQ,CAEpB8D,CAAAA,CAAa,OAAA,CAASO,CAAAA,EAAU,CAC9B,GAAI,CAACA,CAAAA,CAAMF,CAAS,CAAA,CAClB,OAGFE,CAAAA,CAAM,CAAC,CAAA,CAAID,CAAAA,CAGX,IAAME,CAAAA,CAAcJ,CAAAA,CAAsBG,CAAAA,CAAM,CAAC,CAAA,CAAIA,EAAM,CAAC,CAAA,CAExDC,CAAAA,EACF,OAAA,CAAQ,OAAA,CAAQA,CAAAA,CAAYJ,CAAmB,CAAC,CAAA,CAAE,KAAA,CAAMjE,CAAI,EAEhE,CAAC,EACH,CAUA,eAAsBsE,EAAAA,CACpB3F,CAAAA,CACAsF,CAAAA,CAA+B,KAAA,CACI,CAEnC,GAAI,CAACtF,CAAAA,CACH,OAAO,IAAA,CAGT,IAAMyF,CAAAA,CAAQP,CAAAA,CAAa,IAAIlF,CAAG,CAAA,CAElC,GAAIyF,CAAAA,CAAO,CAETA,CAAAA,CAAM,CAAC,CAAA,CAAIrE,CAAAA,EAAQ,CAEnB,IAAMsE,CAAAA,CAAcJ,CAAAA,CAAsBG,CAAAA,CAAM,CAAC,CAAA,CAAIA,CAAAA,CAAM,CAAC,CAAA,CAG5D,GAAIC,CAAAA,CACF,OAAO,MAAMA,CAAAA,CAAYJ,CAAmB,CAEhD,CAGA,OAAO,IACT,CAOO,SAASM,EAAAA,CAAmBP,CAAAA,CAAiB,CAClDQ,EAAAA,CAAmBR,CAAI,CAAA,CAEvB,IAAME,CAAAA,CAAYF,CAAAA,GAAS,OAAA,CAAU,CAAA,CAAI,CAAA,CAGzCH,CAAAA,CAAa,QAAQ,CAACO,CAAAA,CAAOzF,CAAAA,GAAQ,CAC/ByF,CAAAA,CAAMF,CAAS,CAAA,EACjBO,EAAAA,CAAkB9F,CAAG,EAEzB,CAAC,EACH,CAQA,SAAS+F,GAAgBC,CAAAA,CAAkB,CACzC,GAAI,CAAClE,EAAAA,EAAU,EAAKqD,EAAAA,CAAc,GAAA,CAAIa,CAAK,CAAA,CACzC,OAGF,IAAMC,CAAAA,CAAUb,EAAAA,CAAc,IAAA,CAAK,IAAA,CAAMY,CAAAA,CAAO,IAAI,CAAA,CAEpDb,EAAAA,CAAc,GAAA,CAAIa,CAAAA,CAAOC,CAAO,CAAA,CAChC,MAAA,CAAO,gBAAA,CAAiBD,CAAAA,CAAOC,CAAO,EACxC,CAOA,SAASJ,EAAAA,CAAmBG,CAAAA,CAAkB,CAC5C,GAAI,CAAClE,EAAAA,EAAU,CACb,OAGF,IAAMmE,CAAAA,CAAUd,EAAAA,CAAc,GAAA,CAAIa,CAAK,CAAA,CAEnCC,IACF,MAAA,CAAO,mBAAA,CAAoBD,CAAAA,CAAOC,CAAO,CAAA,CAEzCd,EAAAA,CAAc,MAAA,CAAOa,CAAK,CAAA,EAE9B,CAaO,SAASE,EAAAA,CACdlG,CAAAA,CACAmG,CAAAA,CACAC,EACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACA,CACAtB,CAAAA,CAAa,GAAA,CAAIlF,CAAAA,CAAK,CACpBmG,CAAAA,CACA/E,CAAAA,EAAQ,CACD6D,EAAAA,CACPoB,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CACF,CAAC,CAAA,CAEGD,CAAAA,EACFR,EAAAA,CAAgB,OAAO,CAAA,CAGrBS,CAAAA,EACFT,EAAAA,CAAgB,QAAQ,EAGtBM,CAAAA,EACF/C,CAAAA,CAAW,IAAA,CAAOtD,CAAAA,CAAK2F,EAAAA,CAAW,IAAA,CAAK,IAAA,CAAM3F,CAAAA,CAAK,IAAI,CAAA,CAAGqG,CAAAA,CAAY,GAAI,EAE7E,CAEO,SAASP,EAAAA,CAAkB9F,CAAAA,CAAa,CAC7CkF,CAAAA,CAAa,MAAA,CAAOlF,CAAG,CAAA,CAGvBwD,CAAAA,CAAc,IAAA,CAAOxD,CAAG,EAC1B,CChMA,IAAMyG,CAAAA,CAAY,IAAI,GAAA,CAEtB,SAASC,EAAAA,CAAkB1G,CAAAA,CAAa,CACtC,OAAKyG,CAAAA,CAAU,GAAA,CAAIzG,CAAG,CAAA,EACpByG,CAAAA,CAAU,GAAA,CAAIzG,CAAAA,CAAK,IAAI,GAAK,CAAA,CAGvByG,CAAAA,CAAU,GAAA,CAAIzG,CAAG,CAC1B,CAGO,SAAS2G,EAAAA,CAAqB3G,CAAAA,CAAa4G,CAAAA,CAAuB,CACvEF,EAAAA,CAAkB1G,CAAG,CAAA,CAAE,GAAA,CAAI4G,CAAE,EAC/B,CAEO,SAASC,EAAAA,CAAkB7G,CAAAA,CAAa4G,CAAAA,CAAiB,CAC9D,IAAME,CAAAA,CAAML,CAAAA,CAAU,GAAA,CAAIzG,CAAG,CAAA,CAEzB8G,CAAAA,GACFA,EAAI,MAAA,CAAOF,CAAE,CAAA,CAGTE,CAAAA,CAAI,IAAA,GAAS,CAAA,EACfL,CAAAA,CAAU,MAAA,CAAOzG,CAAG,CAAA,EAG1B,CAEO,SAAS+G,CAAAA,CAAqB/G,CAAAA,CAAawC,EAAa,CAC7D,IAAMwE,CAAAA,CAAMP,CAAAA,CAAU,GAAA,CAAIzG,CAAG,CAAA,CAE7B,GAAIgH,CAAAA,CACF,GAAIA,CAAAA,CAAI,IAAA,GAAS,CAAA,CAAG,CAElB,IAAMJ,CAAAA,CAAKI,CAAAA,CAAI,MAAA,EAAO,CAAE,IAAA,EAAK,CAAE,KAAA,CAC/BJ,CAAAA,CAAIpE,CAAQ,EACd,CAAA,KACEwE,CAAAA,CAAI,OAAA,CAASJ,CAAAA,EAAOA,EAAGpE,CAAQ,CAAC,EAGtC,CAEO,SAASyE,EAAAA,CAAajH,CAAAA,CAAoB4G,CAAAA,CAA2B,CAC1E,OAAK5G,CAAAA,EAKL2G,EAAAA,CAAe3G,CAAAA,CAAK4G,CAAE,EAGf,IAAM,CACXC,EAAAA,CAAe7G,CAAAA,CAAK4G,CAAE,EACxB,CAAA,EARSvF,CASX,CCtDA,IAAM6F,EAAAA,CAAAA,CAAoBnF,EAAAA,EAAiB,CAAI,EAAA,CAAK,IAAM,GAAA,CAE7CoF,CAAAA,CAA+B,CAC1C,QAAA,CAAUjI,EAAAA,CACV,OAAA,CAASgI,EAAAA,CACT,OAAA,CAAS,CACP,MAAA,CAAQ3I,CAAAA,CAAmB,mBAAA,CAC3B,iBAAA,CAAmB,mBACrB,CAAA,CACA,KAAA,CAAO,CACL,KAAA,CAAO2I,EAAAA,CAAmB,EAAA,CAC1B,QAAA,CAAUA,EAAAA,CACV,YAAA,CAAc,IAAA,CACd,OAAA,CAAS,GAAA,CAGT,OAAA,CAAS,CACP,GAAA,CACA,GAAA,CACA,IACA,GAAA,CACA,GAAA,CACA,GAAA,CACA,GAAA,CACA,GACF,CACF,CACF,CAAA,CAQO,SAASE,EAAAA,CACdC,CAAAA,CACwB,CACxB,IAAMC,CAAAA,CAAY9H,EAAe6H,CAAY,CAAA,CAE7C,OAAA,MAAA,CAAO,MAAA,CAAOF,CAAAA,CAAeG,CAAS,CAAA,CAE/BH,CACT,CAOO,SAASI,EAAAA,EAAkC,CAChD,OAAO,CAAE,GAAGJ,CAAc,CAC5B,CASO,SAASK,EAAAA,CACdnH,CAAAA,CACAoH,CAAAA,CAMmE,CACnE,GAAI,CAACA,CAAAA,CACH,OAAOC,EAAAA,CAAmBrH,CAAAA,CAAKkH,IAAkB,CAAA,CAGnD,IAAMD,CAAAA,CAAY9H,CAAAA,CAAeiI,CAAS,CAAA,CACpCE,CAAAA,CAASC,CAAAA,CAAaT,CAAAA,CAAeG,CAAS,CAAA,CAEpD,OAAOI,EAAAA,CAAmBrH,EAAKsH,CAAM,CACvC,CASO,SAASD,EAAAA,CACdrH,CAAAA,CACAwH,CAAAA,CACe,CArHjB,IAAAC,CAAAA,CAsHE,IAAIC,CAAAA,CAASF,CAAAA,CAAc,MAAA,CAC3BE,EAASA,CAAAA,CAAUA,CAAAA,CAAO,WAAA,EAAY,CAAe/I,CAAAA,CAErD,IAAIgJ,CAAAA,CAGAD,CAAAA,GAAW/I,CAAAA,EAAO+I,CAAAA,GAAW9I,EAAAA,GAC/B+I,CAAAA,CAAAA,CAAOF,CAAAA,CAAAD,CAAAA,CAAc,OAAd,IAAA,CAAAC,CAAAA,CAAsBD,CAAAA,CAAc,IAAA,CAGvCG,CAAAA,EAAQ,OAAOA,CAAAA,GAASpJ,CAAAA,EAAU0C,EAAAA,CAAmB0G,CAAI,CAAA,GAC3DA,CAAAA,CAAO,IAAA,CAAK,SAAA,CAAUA,CAAI,CAAA,CAAA,CAAA,CAI9BC,EAAAA,CAAuBJ,CAAAA,CAAc,OAAA,CAASG,CAAI,CAAA,CAGlD,IAAME,CAAAA,CAAcL,CAAAA,CAAc,eAAA,CAC9B,SAAA,CACAA,CAAAA,CAAc,WAAA,CAGZM,CAAAA,CAAanH,EAAAA,CAAqBX,EAAKwH,CAAAA,CAAc,aAAa,CAAA,CAClEO,CAAAA,CAAUhI,EAAAA,CAAkB+H,CAAAA,CAAYN,CAAAA,CAAc,MAAM,CAAA,CAE5DQ,CAAAA,CADYlH,EAAAA,CAAcd,CAAG,CAAA,CAE/B,EAAA,CACAwH,EAAc,OAAA,EAAWA,CAAAA,CAAc,MAAA,EAAU,EAAA,CAErD,OAAAA,CAAAA,CAAc,GAAA,CAAMQ,CAAAA,CAAUD,CAAAA,CAC9BP,CAAAA,CAAc,MAAA,CAASE,CAAAA,CACvBF,CAAAA,CAAc,WAAA,CAAcK,EAC5BL,CAAAA,CAAc,IAAA,CAAOG,CAAAA,CAEdH,CACT,CAWA,SAASI,EAAAA,CACPrG,CAAAA,CACAoG,CAAAA,CACM,CAON,GALI,CAACpG,CAAAA,EAAW,CAACoG,GAMfA,CAAAA,YAAgB,QAAA,EACf,OAAO,IAAA,GAAStJ,CAAAA,EAAasJ,CAAAA,YAAgB,IAAA,EAC7C,OAAO,IAAA,GAAStJ,CAAAA,EAAasJ,CAAAA,YAAgB,IAAA,EAC7C,OAAO,cAAA,GAAmBtJ,GAAasJ,CAAAA,YAAgB,cAAA,CAExD,OAGF,IAAIM,CAAAA,CAEJ,GAAIlJ,EAAAA,CAAe4I,CAAI,CAAA,CACrBM,CAAAA,CAAmBhK,CAAAA,CAA2B,uBAAA,CAAA,KAAA,GACrC0J,CAAAA,YAAgB,WAAA,EAAe,YAAY,MAAA,CAAOA,CAAI,CAAA,CAC/DM,CAAAA,CAAmBhK,CAAAA,CAA2B,cAAA,CAAA,KAAA,GACrCgD,EAAAA,CAAmB0G,CAAI,CAAA,CAChCM,CAAAA,CAAmB/J,CAAAA,CAAmB,GAAA,CAAMC,EAAAA,CAAAA,KAG5C,OAGEoD,aAAmB,OAAA,CAChBA,CAAAA,CAAQ,GAAA,CAAInD,CAAY,CAAA,EAC3BmD,CAAAA,CAAQ,GAAA,CAAInD,CAAAA,CAAc6J,CAAgB,CAAA,CAG5ChJ,CAAAA,CAASsC,CAAO,CAAA,EAChB,CAAC,KAAA,CAAM,OAAA,CAAQA,CAAO,CAAA,EACtB,CAACA,CAAAA,CAAQnD,CAAY,CAAA,GAErBmD,CAAAA,CAAQnD,CAAY,CAAA,CAAI6J,CAAAA,EAE5B,CAEO,SAASV,CAAAA,CACdW,CAAAA,CACAC,EACe,CACf,IAAMC,CAAAA,CAA8B,MAAA,CAAO,MAAA,CACzC,EAAC,CACDF,CAAAA,CACAC,CACF,CAAA,CAGA,OAAAE,EAAAA,CAAY,OAAA,CAASD,CAAAA,CAAcF,EAAYC,CAAc,CAAA,CAC7DE,EAAAA,CAAY,SAAA,CAAWD,CAAAA,CAAcF,CAAAA,CAAYC,CAAc,CAAA,CAG/DG,EAAAA,CAAkB,WAAA,CAAaF,CAAAA,CAAcF,CAAAA,CAAYC,CAAc,CAAA,CACvEG,GAAkB,YAAA,CAAcF,CAAAA,CAAcF,CAAAA,CAAYC,CAAc,CAAA,CACxEG,EAAAA,CAAkB,SAAA,CAAWF,CAAAA,CAAcF,CAAAA,CAAYC,CAAc,CAAA,CAE9DC,CACT,CAKA,SAASE,GAGPC,CAAAA,CACAC,CAAAA,CACAN,CAAAA,CACAC,CAAAA,CACM,CACN,IAAMM,CAAAA,CAAkBP,CAAAA,CAAWK,CAAQ,CAAA,CACrCG,CAAAA,CAAiBP,CAAAA,CAAeI,CAAQ,CAAA,CAE9C,GAAI,CAACE,CAAAA,EAAmB,CAACC,CAAAA,CACvB,OAGF,GAAI,CAACD,CAAAA,CAAiB,CACpBD,CAAAA,CAAaD,CAAQ,CAAA,CAAIG,CAAAA,CACzB,MACF,CAEA,GAAI,CAACA,CAAAA,CAAgB,CACnBF,CAAAA,CAAaD,CAAQ,CAAA,CAAIE,CAAAA,CACzB,MACF,CAEA,IAAME,CAAAA,CAAU,KAAA,CAAM,OAAA,CAAQF,CAAe,CAAA,CACzCA,CAAAA,CACA,CAACA,CAAe,CAAA,CACdG,CAAAA,CAAS,KAAA,CAAM,OAAA,CAAQF,CAAc,CAAA,CACvCA,CAAAA,CACA,CAACA,CAAc,CAAA,CAGnBF,CAAAA,CAAaD,CAAQ,CAAA,CACnBA,CAAAA,GAAa,YAAA,CAAeK,CAAAA,CAAO,MAAA,CAAOD,CAAO,CAAA,CAAIA,CAAAA,CAAQ,MAAA,CAAOC,CAAM,EAC9E,CAUO,SAASP,EAAAA,CACdE,EACAC,CAAAA,CACAN,CAAAA,CACAC,CAAAA,CACM,CACFA,CAAAA,CAAeI,CAAQ,CAAA,GACzBC,CAAAA,CAAaD,CAAQ,CAAA,CAAI,CACvB,GAAGL,CAAAA,CAAWK,CAAQ,EACtB,GAAGJ,CAAAA,CAAeI,CAAQ,CAC5B,CAAA,EAEJ,CC9QA,IAAMM,EAAAA,CAAS,IAAI,GAAA,CACbC,CAAAA,CAAY,GAAA,CACZC,EAAAA,CAAqB,EAAA,CACrBC,GAA6B,IAAI,MAAA,CAAO,aAAA,CAAe,GAAG,CAAA,CAM1DC,EAAAA,CAA6B,IAAI,GAAA,CAAI,CAEzC,QAAA,CACA,iBAAA,CACA,iBAAA,CAGA,eAAA,CAGA,cAAA,CAGA,UACA,QAAA,CACA,YAAA,CAGA,QAAA,CAGA,WAAA,CACA,kBAAA,CACA,aAAA,CACA,aAAA,CACA,WAAA,CAEA,eAAA,CACA,gBAAA,CACA,aAAA,CACA,YAAA,CAEA,cAAA,CACA,UACF,CAAC,CAAA,CA0BM,SAASC,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CAAgB,IAAA,CACR,CAGR,IAAMzJ,CAAAA,CAAMwJ,CAAAA,CAAO,QAAA,CAEnB,GAAIxJ,CAAAA,EAAOyJ,CAAAA,CACT,OAAO,OAAOzJ,CAAAA,GAAQpB,CAAAA,CACjBoB,CAAAA,CACAA,CAAAA,CAAyBwJ,CAAM,CAAA,CAGtC,GAAM,CACJ,GAAA,CAAAnJ,CAAAA,CAAM,EAAA,CACN,MAAA,CAAA0H,CAAAA,CAAS/I,EACT,OAAA,CAAA4C,CAAAA,CAAU,IAAA,CACV,IAAA,CAAAoG,CAAAA,CAAO,IAAA,CACP,WAAA,CAAAE,CAAAA,CAAc,aAChB,CAAA,CAAIsB,CAAAA,CAIAE,CAAAA,CAAgB,EAAA,CACpB,GAAI9H,CAAAA,CAAS,CACX,IAAInC,CAAAA,CAEAmC,CAAAA,YAAmB,OAAA,CACrBnC,CAAAA,CAAMkC,EAAAA,CAAeC,CAAO,CAAA,CAE5BnC,CAAAA,CAAMmC,CAAAA,CAKR,IAAMhC,CAAAA,CAAO,MAAA,CAAO,IAAA,CAAKH,CAAG,CAAA,CACtBM,CAAAA,CAAMH,CAAAA,CAAK,MAAA,CAGbG,CAAAA,CAAM,CAAA,EACRH,CAAAA,CAAK,IAAA,EAAK,CAGZ,IAAImF,CAAAA,CAAM,EAAA,CACV,IAAA,IAASjF,CAAAA,CAAI,EAAGA,CAAAA,CAAIC,CAAAA,CAAK,EAAED,CAAAA,CACrBwJ,EAAAA,CAA2B,GAAA,CAAI1J,CAAAA,CAAKE,CAAC,CAAA,CAAE,WAAA,EAAa,CAAA,GACtDiF,CAAAA,EAAOnF,CAAAA,CAAKE,CAAC,CAAA,CAAI,GAAA,CAAML,CAAAA,CAAIG,CAAAA,CAAKE,CAAC,CAAC,CAAA,CAAI,GAAA,CAAA,CAI1C4J,CAAAA,CAAgB5E,CAAAA,CAAKC,CAAG,EAC1B,CAGA,GAAIgD,IAAW/I,CAAAA,CACb,OAAA,CACE+I,CAAAA,CACAoB,CAAAA,CACA9I,CAAAA,CACA8I,CAAAA,CACAjB,CAAAA,CACAiB,CAAAA,CACAO,CAAAA,EACA,OAAA,CAAQL,EAAAA,CAA4B,EAAE,CAAA,CAG1C,IAAIM,EAAa,EAAA,CACjB,GAAI3B,CAAAA,CACF,GAAI,OAAOA,CAAAA,GAASpJ,CAAAA,CAClB+K,CAAAA,CAAa3B,CAAAA,CAAK,MAAA,CAASoB,EAAAA,CAAqBpB,CAAAA,CAAOlD,CAAAA,CAAKkD,CAAI,UACvDA,CAAAA,YAAgB,QAAA,CACzBA,CAAAA,CAAK,OAAA,CAAQ,CAACzI,CAAAA,CAAOS,CAAAA,GAAQ,CAE3B2J,CAAAA,EAAc3J,CAAAA,CAAM,GAAA,CAAMT,CAAAA,CAAQ,IACpC,CAAC,EAEGoK,CAAAA,CAAW,MAAA,CAASP,EAAAA,GACtBO,CAAAA,CAAa7E,CAAAA,CAAK6E,CAAU,CAAA,CAAA,CAAA,KAAA,GAG7B,OAAO,IAAA,GAASjL,CAAAA,EAAasJ,CAAAA,YAAgB,IAAA,EAC7C,OAAO,IAAA,GAAStJ,CAAAA,EAAasJ,CAAAA,YAAgB,IAAA,CAE9C2B,CAAAA,CAAa,IAAA,CAAO3B,CAAAA,CAAK,IAAA,CAAOA,CAAAA,CAAK,IAAA,CAAA,KAAA,GAC5BA,CAAAA,YAAgB,WAAA,EAAe,WAAA,CAAY,MAAA,CAAOA,CAAI,CAAA,CAC/D2B,CAAAA,CAAa,KAAO3B,CAAAA,CAAK,UAAA,CAAA,KACpB,CACL,IAAM4B,CAAAA,CAAItK,CAAAA,CAAS0I,CAAI,CAAA,CACnB,IAAA,CAAK,SAAA,CAAUrI,EAAAA,CAAWqI,CAAI,CAAC,CAAA,CAC/B,OAAOA,CAAI,CAAA,CAEf2B,CAAAA,CAAaC,CAAAA,CAAE,MAAA,CAASR,EAAAA,CAAqBtE,CAAAA,CAAK8E,CAAC,CAAA,CAAIA,EACzD,CAKF,OAAA,CACE7B,CAAAA,CACAoB,CAAAA,CACA9I,EACA8I,CAAAA,CACAjB,CAAAA,CACAiB,CAAAA,CACAO,CAAAA,CACAP,CAAAA,CACAQ,CAAAA,EACA,OAAA,CAAQN,EAAAA,CAA4B,EAAE,CAC1C,CAQA,SAASQ,EAAAA,CAAepE,CAAAA,CAAiC,CAEvD,OAAKA,CAAAA,CAAM,MAAA,CAIJrE,CAAAA,EAAQ,CAAIqE,CAAAA,CAAM,MAAA,CAHhB,KAIX,CAQA,SAASqE,EAAAA,CAAarE,CAAAA,CAAiC,CACrD,OAAKA,EAAM,KAAA,CAIJrE,CAAAA,EAAQ,CAAIqE,CAAAA,CAAM,KAAA,CAHhB,KAIX,CA+BO,SAASsE,EAAAA,CACd/J,CAAAA,CAMY,CACZ,OAAOkJ,EAAAA,CAAO,GAAA,CAAIlJ,CAAa,CACjC,CAUO,SAASgK,EAAAA,CACdhK,CAAAA,CACAX,CAAAA,CACA+G,CAAAA,CACAC,CAAAA,CACM,CACN,GAAID,CAAAA,GAAQ,CAAA,CAAG,CACb6D,EAAAA,CAAYjK,CAAG,CAAA,CACf,MACF,CAEA,IAAMkK,CAAAA,CAAO9I,CAAAA,EAAQ,CACf+I,CAAAA,CAAQ/D,CAAAA,CAAMA,CAAAA,CAAM,GAAA,CAAO,CAAA,CAEjC8C,EAAAA,CAAO,GAAA,CAAIlJ,CAAAA,CAAK,CACd,IAAA,CAAAX,CAAAA,CACA,IAAA,CAAA6K,CAAAA,CACA,KAAA,CAAO7D,CAAAA,EAAaA,CAAAA,CAAY,CAAA,CAAI6D,CAAAA,CAAO7D,CAAAA,CAAY,GAAA,CAAOA,CAAAA,CAC9D,MAAA,CAAQD,CAAAA,GAAQ,GAAK,MAAA,CAAY8D,CAAAA,CAAOC,CAC1C,CAAC,CAAA,CAEGA,CAAAA,CAAQ,CAAA,EACV7G,CAAAA,CACE,IAAA,CAAOtD,CAAAA,CACP,IAAM,CACJiK,EAAAA,CAAYjK,CAAAA,CAAK,IAAI,EACvB,CAAA,CACAmK,CACF,EAEJ,CAQO,SAASF,EAAAA,CAAYjK,CAAAA,CAAaoK,CAAAA,CAAyB,KAAA,CAAa,CAC7E,GAAIA,CAAAA,CAAe,CACjB,IAAM3E,CAAAA,CAAQsE,EAAAA,CAAS/J,CAAG,CAAA,CAG1B,GAAI,CAACyF,CAAAA,EAAS,CAACoE,EAAAA,CAAepE,CAAK,CAAA,CACjC,MAEJ,CAEAyD,EAAAA,CAAO,OAAOlJ,CAAG,EACnB,CAgBA,eAAsBqK,EAAAA,CAMpBrK,CAAAA,CACAsK,CAAAA,CACAC,CAAAA,CAMQ,CAER,GAAI,CAACvK,CAAAA,CACH,OAAO,IAAA,CAGT,IAAMyF,CAAAA,CAAQsE,EAAAA,CACZ/J,CACF,CAAA,CAEA,GAAI,CAACyF,CAAAA,CACH,OAAO,IAAA,CAGT,IAAM+E,CAAAA,CAAclL,CAAAA,CAASgL,CAAO,CAAA,CAAI9K,EAAe8K,CAAO,CAAA,CAAIA,CAAAA,CAE5DG,CAAAA,CAAkB,CACtB,GAAGhF,CAAAA,CAAM,IAAA,CACT,IAAA,CAAM+E,CACR,CAAA,CAEME,CAAAA,CAAe,CACnB,GAAGjF,EACH,IAAA,CAAMgF,CACR,CAAA,CAKA,OAHAvB,EAAAA,CAAO,GAAA,CAAIlJ,CAAAA,CAAK0K,CAAY,CAAA,CAC5B3D,CAAAA,CAAkB/G,CAAAA,CAAKyK,CAAe,CAAA,CAElCF,CAAAA,EAAYA,CAAAA,CAAS,OAAA,CAChB,MAAM5E,EAAAA,CAAW3F,CAAG,CAAA,CAGtB,IACT,CAcO,SAAS2K,EAAAA,CAMdC,CAAAA,CACAC,CAAAA,CACAhD,CAAAA,CAM0E,CAE1E,GAAI,CAAC+C,GAAYC,CAAAA,GAAc,MAAA,EAAaA,CAAAA,GAAc,IAAA,CACxD,OAAO,IAAA,CAIT,IAAMC,CAAAA,CAASjD,CAAAA,CAAc,WAAA,EAAeV,CAAAA,CAAc,WAAA,CAK1D,GAJI2D,CAAAA,EAAUA,EAAOjD,CAAa,CAAA,EAI9BA,CAAAA,CAAc,KAAA,EAASA,CAAAA,CAAc,KAAA,GAAU,QAAA,CACjD,OAAO,IAAA,CAIT,IAAMpC,CAAAA,CAAQsE,EAAAA,CACZa,CACF,CAAA,CAEA,GAAI,CAACnF,CAAAA,CACH,OAAO,IAAA,CAGT,IAAMsF,CAAAA,CAAYlB,EAAAA,CAAepE,CAAK,CAAA,CAChCuF,CAAAA,CAAUlB,EAAAA,CAAarE,CAAK,CAAA,CAGlC,OAAIsF,GACFd,EAAAA,CAAYW,CAAQ,CAAA,CACb,IAAA,EAIL,CAACI,CAAAA,EAKDA,CAAAA,EAAW,CAACD,CAAAA,CAGPtF,CAAAA,CAAM,IAAA,CAGR,IACT,CASO,SAASwF,GAMdC,CAAAA,CACArD,CAAAA,CAMAsD,CAAAA,CAAmB,KAAA,CACb,CAEN,IAAMP,CAAAA,CAAW/C,CAAAA,CAAc,QAAA,CAE/B,GAAI+C,CAAAA,CAAU,CACZ,IAAMC,CAAAA,CAAYhD,EAAc,SAAA,CAC1BuD,CAAAA,CAAYvD,CAAAA,CAAc,SAAA,CAI9BgD,CAAAA,GACC,CAACM,CAAAA,EAAWtD,CAAAA,CAAc,WAAA,CAAA,EAC3B,EAAEuD,CAAAA,EAAaA,CAAAA,CAAUF,CAAAA,CAAQrD,CAAa,IAE9CmC,EAAAA,CAASY,CAAAA,CAAUM,CAAAA,CAAQL,CAAAA,CAAWhD,CAAAA,CAAc,SAAS,CAAA,CAG/Dd,CAAAA,CAAkB6D,CAAAA,CAAUM,CAAM,CAAA,CAClCzG,EAAAA,CAAemG,CAAQ,CAAA,CAEvB,IAAMS,CAAAA,CAAexD,CAAAA,CAAc,QAAA,CAE/BwD,CAAAA,EACF5G,EAAAA,CAAe4G,CAAY,EAE/B,CACF,CCzeA,eAAsBC,EAAAA,CAMpB9I,CAAAA,CACc,CAlChB,IAAAsF,CAAAA,CAoCE,GAAI,CAACtF,CAAAA,CACH,OAAO,IAAA,CAIT,IAAI+I,CAAAA,CAAAA,CAAezD,CAAAA,CAAAtF,CAAAA,CAAsB,OAAA,GAAtB,IAAA,CAAA,MAAA,CAAAsF,CAAAA,CAA+B,GAAA,CAAIrJ,CAAAA,CAAAA,CAElD8M,CAAAA,CAEFA,EAAcA,CAAAA,CAAY,WAAA,EAAY,CAAE,IAAA,EAAK,CAE7CA,CAAAA,CAAc,EAAA,CAIhB,IAAMC,CAAAA,CAAWD,CAAAA,CAAY,KAAA,CAAM,GAAA,CAAK,CAAC,CAAA,CAAE,CAAC,CAAA,CAExClM,CAAAA,CAEJ,GAAI,CACF,GAAImM,CAAAA,CAAS,QAAA,CAASjN,CAAgB,CAAA,EAAKiN,CAAAA,CAAS,QAAA,CAAS,OAAO,CAAA,CAClEnM,CAAAA,CAAO,MAAMmD,CAAAA,CAAS,IAAA,EAAK,CAAA,KAAA,GAAA,CAE1BgJ,CAAAA,CAAS,QAAA,CAAS,qBAAqB,CAAA,EACtCA,CAAAA,CAAS,QAAA,CACPlN,CAAAA,CAA2B,uBAC7B,CAAA,GACF,OAAOkE,CAAAA,CAAS,WAAa3D,CAAAA,CAE7BQ,CAAAA,CAAO,MAAMmD,CAAAA,CAAS,QAAA,EAAS,CAAA,KAAA,GAE/BgJ,CAAAA,CAAS,QAAA,CAASlN,CAAAA,CAA2B,cAAc,CAAA,EAC3D,OAAOkE,CAAAA,CAAS,IAAA,GAAS3D,EAEzBQ,CAAAA,CAAO,MAAMmD,CAAAA,CAAS,IAAA,EAAK,CAAA,KAAA,GAE3BnD,CAAAA,CAAO,MAAMmD,CAAAA,CAAS,IAAA,EAAK,CAEvB,OAAOnD,CAAAA,GAAST,CAAAA,CAAQ,CAC1B,IAAM6M,CAAAA,CAAUpM,CAAAA,CAAK,IAAA,EAAK,CAC1B,GACGoM,CAAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,EAAKA,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,EAC/CA,CAAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,EAAKA,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,CAEhD,GAAI,CACFpM,CAAAA,CAAO,IAAA,CAAK,KAAA,CAAMoM,CAAO,EAC3B,CAAA,MAAQpI,CAAAA,CAAA,CAER,CAEJ,CAGJ,CAAA,MAASqI,CAAAA,CAAQ,CAEfrM,CAAAA,CAAO,KACT,CAEA,OAAOA,CACT,CAUO,IAAMsM,EAAAA,CAAkB,CAM7BnJ,EAMAgH,CAAAA,CACAhF,CAAAA,CAKW,IAAA,GAC2D,CACtE,IAAMoH,CAAAA,CAAkBpC,CAAAA,CAAO,eAAA,CACzBoB,CAAAA,CAAWpB,CAAAA,CAAO,QAAA,CAClBqC,CAAAA,CAAYxB,EAAAA,CAAO,IAAA,CAAK,KAAMO,CAAkB,CAAA,CAQtD,GAAI,CAACpI,CAAAA,CACH,OAAO,CACL,EAAA,CAAI,KAAA,CAEJ,KAAA,CAAAgC,CAAAA,CACA,IAAA,CAAMoH,CAAAA,EAAA,IAAA,CAAAA,EAAmB,IAAA,CACzB,OAAA,CAAS,IAAA,CACT,MAAA,CAAApC,CAAAA,CACA,MAAA,CAAQqC,CAAAA,CACR,UAAA,CAAY,KAAA,CACZ,SAAA,CAAW,KAAA,CACX,OAAA,CAAS,IACX,CAAA,CAQF,IAAMC,CAAAA,CACJ,OAAO,QAAA,GAAajN,CAAAA,EAAY2D,CAAAA,YAAoB,QAAA,CAElDnD,CAAAA,CAAOmD,CAAAA,CAAS,IAAA,CAIlBoJ,CAAAA,GAAoB,MAAA,GAElBvM,CAAAA,EAAS,IAAA,EACR,OAAOA,IAASV,CAAAA,EAAU,MAAA,CAAO,IAAA,CAAKU,CAAI,CAAA,CAAE,MAAA,GAAW,CAAA,CAAA,GAE1DmD,CAAAA,CAAS,IAAA,CAAOnD,CAAAA,CAAOuM,CAAAA,CAAAA,CAGrBpC,CAAAA,CAAO,eAAA,GACThH,CAAAA,CAAS,KAAOnD,CAAAA,CAAOqC,EAAAA,CAAYrC,CAAI,CAAA,CAAA,CAGrCmK,CAAAA,CAAO,MAAA,GACThH,CAAAA,CAAS,IAAA,CAAOnD,CAAAA,CAAOmK,CAAAA,CAAO,MAAA,CAAOnK,CAAI,CAAA,CAAA,CAG3C,IAAMuC,CAAAA,CAAUD,EAAAA,CAAea,CAAAA,CAAS,OAAO,CAAA,CAG/C,OAAIsJ,CAAAA,CACK,CACL,IAAA,CAAMtJ,CAAAA,CAAS,IAAA,CACf,QAAA,CAAUA,CAAAA,CAAS,QAAA,CACnB,EAAA,CAAIA,CAAAA,CAAS,GACb,UAAA,CAAYA,CAAAA,CAAS,UAAA,CACrB,IAAA,CAAMA,CAAAA,CAAS,IAAA,CACf,GAAA,CAAKA,CAAAA,CAAS,GAAA,CACd,MAAA,CAAQA,CAAAA,CAAS,MAAA,CACjB,UAAA,CAAYA,CAAAA,CAAS,WAGrB,IAAA,CAAM,IAAMA,CAAAA,CAAS,IAAA,EAAK,CAC1B,IAAA,CAAM,IAAMA,CAAAA,CAAS,IAAA,EAAK,CAC1B,IAAA,CAAM,IAAMA,CAAAA,CAAS,IAAA,GACrB,KAAA,CAAO,IAAMA,CAAAA,CAAS,KAAA,EAAM,CAC5B,WAAA,CAAa,IAAMA,CAAAA,CAAS,WAAA,EAAY,CACxC,QAAA,CAAU,IAAMA,CAAAA,CAAS,QAAA,GACzB,KAAA,CAAO,IAAMA,CAAAA,CAAS,KAAA,EAAM,CAG5B,KAAA,CAAAgC,CAAAA,CACA,IAAA,CAAAnF,CAAAA,CACA,OAAA,CAAAuC,CAAAA,CACA,MAAA,CAAA4H,CAAAA,CACA,MAAA,CAAQqC,EACR,UAAA,CAAY,KAAA,CACZ,SAAA,CAAWrJ,CAAAA,CAAS,EAAA,EAAM,CAACgC,CAAAA,CAC3B,OAAA,CAAS,CAAC,CAACA,CACb,CAAA,EAIElF,CAAAA,CAASkD,CAAQ,IACnBA,CAAAA,CAAS,KAAA,CAAQgC,CAAAA,CACjBhC,CAAAA,CAAS,OAAA,CAAUZ,CAAAA,CACnBY,CAAAA,CAAS,UAAA,CAAa,KAAA,CACtBA,CAAAA,CAAS,MAAA,CAASqJ,CAAAA,CAClBrJ,CAAAA,CAAS,SAAA,CAAYA,EAAS,EAAA,EAAM,CAACgC,CAAAA,CACrChC,CAAAA,CAAS,OAAA,CAAU,CAAC,CAACgC,CAAAA,CAAAA,CAGhBhC,CAAAA,CACT,CAAA,CC3NA,SAASuJ,EAAAA,CAAkBC,CAAAA,CAAmC,CAC5D,IAAMxK,CAAAA,CAAK,IAAA,CAAK,KAAA,CAAMwK,CAAU,CAAA,CAAI5K,CAAAA,EAAQ,CAE5C,OAAK,KAAA,CAAMI,CAAE,CAAA,CAGN,IAAA,CAFE,IAAA,CAAK,GAAA,CAAI,CAAA,CAAG,KAAK,KAAA,CAAMA,CAAE,CAAC,CAGrC,CAaO,SAASyK,EAAAA,CACdC,CAAAA,CACe,CACf,GAAI,CAACA,CAAAA,CACH,OAAO,IAAA,CAGT,IAAMtK,CAAAA,CAAUsK,CAAAA,CAAiB,OAAA,EAAW,EAAC,CACvCC,CAAAA,CAAavK,CAAAA,CAAQ,aAAa,CAAA,CAExC,GAAIuK,CAAAA,CAAY,CAEd,IAAM1I,CAAAA,CAAU,OAAO0I,CAAU,CAAA,CAEjC,GAAI,CAAC,KAAA,CAAM1I,CAAO,CAAA,EAAKA,CAAAA,EAAW,CAAA,CAChC,OAAOA,CAAAA,CAAU,GAAA,CAGnB,IAAMjC,CAAAA,CAAKuK,GAAkBI,CAAU,CAAA,CAEvC,GAAI3K,CAAAA,GAAO,IAAA,CACT,OAAOA,CAEX,CAGA,IAAM4K,CAAAA,CAAkB,iBAAA,CAIlBC,CAAAA,CACJzK,CAAAA,CAAQwK,CAAAA,CAAkB,QAAQ,CAAA,EAClCxK,CAAAA,CAAQ,IAAA,CAAOwK,CAAAA,CAAkB,QAAQ,CAAA,CAE3C,GAAIC,CAAAA,CAAqB,CACvB,IAAM5I,CAAAA,CAAU,MAAA,CAAO4I,CAAmB,CAAA,CAE1C,GAAI,CAAC,KAAA,CAAM5I,CAAO,CAAA,CAChB,OAAOA,CAAAA,CAAU,GAErB,CAIA,IAAM6I,CAAAA,CACJ1K,CAAAA,CAAQwK,CAAAA,CAAkB,KAAK,CAAA,EAAKxK,EAAQ,IAAA,CAAOwK,CAAAA,CAAkB,KAAK,CAAA,CAE5E,OAAIE,CAAAA,CACKP,EAAAA,CAAkBO,CAAgB,CAAA,CAGpC,IACT,CAkBA,eAAsBC,EAAAA,CAMpBC,CAAAA,CAMAhD,CAAAA,CAC4E,CAC5E,GAAM,CACJ,OAAA,CAAAiD,CAAAA,CAAU,CAAA,CACV,KAAA,CAAAC,CAAAA,CAAQ,CAAA,CACR,OAAA,CAAAC,CAAAA,CAAU,CAAA,CACV,QAAA,CAAAC,CAAAA,CACA,OAAA,CAAAC,EAAU,EAAC,CACX,WAAA,CAAAC,CACF,CAAA,CAAItD,CAAAA,CAEAuD,CAAAA,CAAU,CAAA,CACVC,CAAAA,CAAWN,CAAAA,CACTO,CAAAA,CAAaR,CAAAA,CAAU,CAAA,CAAIA,CAAAA,CAAU,EACvCvB,CAAAA,CAEJ,KAAO6B,CAAAA,EAAWE,CAAAA,EAAY,CAG5B,GAAIF,CAAAA,CAAU,CAAA,EAAK7B,CAAAA,CAAS,CAC1B,IAAMgC,CAAAA,CAAMhC,CAAAA,CAAO,MAAA,CACbiC,EAAUD,CAAAA,CAAI,OAAA,CAEhBC,CAAAA,GACF,MAAMlL,CAAAA,CAAkBkL,CAAAA,CAASjC,CAAAA,CAAQ6B,CAAO,CAAA,CAI5CG,CAAAA,CAAI,UAAA,GACNA,CAAAA,CAAI,QAAA,CAAWA,CAAAA,CAAI,SACnBA,CAAAA,CAAI,QAAA,CAAW3D,CAAAA,CAAiB2D,CAAAA,CAAK,KAAK,CAAA,CAAA,EAGhD,CAKAhC,CAAAA,CAAS,MAAMsB,CAAAA,CAAUO,CAAAA,CAAU,CAAA,CAAGA,CAAO,CAAA,CAC7C,IAAMvI,CAAAA,CAAQ0G,CAAAA,CAAO,KAAA,CAGrB,GAAI,CAAC1G,CAAAA,CAAO,CACV,GAAIsI,CAAAA,EAAeC,CAAAA,CAAUE,CAAAA,EACD,MAAMH,CAAAA,CAAY5B,CAAAA,CAAQ6B,CAAO,CAAA,CAEpC,CACrB,MAAMxL,CAAAA,CAAgByL,CAAQ,CAAA,CAC9BA,CAAAA,EAAYL,CAAAA,EAAW,CAAA,CACvBK,CAAAA,CAAW,IAAA,CAAK,GAAA,CAAIA,CAAAA,CAAUJ,CAAAA,EAAYI,CAAQ,CAAA,CAClDD,CAAAA,EAAAA,CACA,QACF,CAGF,KACF,CAWA,GAR2B,MAAMK,EAAAA,CAC/BlC,CAAAA,CACA6B,CAAAA,CACAE,CAAAA,CACAH,CAAAA,CACAD,CACF,CAAA,CAGE,MAKF,GAAIrI,CAAAA,CAAM,MAAA,GAAW,GAAA,EAAOA,CAAAA,CAAM,MAAA,GAAW,GAAA,CAAK,CAEhD,IAAM6I,CAAAA,CAAepB,EAAAA,CAAgBf,CAAM,CAAA,CAGvCmC,CAAAA,GAAiB,OACnBL,CAAAA,CAAWK,CAAAA,EAEf,CAEA,MAAM9L,CAAAA,CAAgByL,CAAQ,CAAA,CAC9BA,CAAAA,EAAYL,CAAAA,EAAW,CAAA,CACvBK,CAAAA,CAAW,IAAA,CAAK,GAAA,CAAIA,CAAAA,CAAUJ,GAAYI,CAAQ,CAAA,CAClDD,CAAAA,GACF,CAEA,OAAO7B,CACT,CAqBA,eAAsBkC,EAAAA,CAMpBlC,CAAAA,CACA6B,CAAAA,CACAE,CAAAA,CACAH,CAAAA,CAMAD,CAAAA,CAAoB,EAAC,CACH,CA1OpB,IAAA/E,CAAAA,CAAAwF,CAAAA,CA8OE,GAAIP,CAAAA,GAAYE,CAAAA,CACd,OAAO,KAAA,CAGT,IAAIM,CAAAA,CAAiC,IAAA,CAGrC,OAAIT,IAEFS,CAAAA,CADe,MAAMT,CAAAA,CAAY5B,CAAAA,CAAQ6B,CAAO,CAAA,CAI5CQ,CAAAA,GAAmB,IAAA,CAAA,CACd,CAACA,CAAAA,CAIL,CAAA,CAAEV,CAAAA,EAAW,EAAC,EAAG,UAASS,CAAAA,CAAAA,CAAAxF,CAAAA,CAAAoD,CAAAA,CAAO,KAAA,GAAP,IAAA,CAAA,MAAA,CAAApD,CAAAA,CAAc,MAAA,GAAd,IAAA,CAAAwF,CAAAA,CAAwB,CAAC,CAC5D,CCjPA,eAAsBE,EAAAA,CAMpBhB,EAMAiB,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CAAc,CAAA,CACdC,CAAAA,CAAe,CAAA,CAC6D,CAC5E,GAAI,CAACH,CAAAA,CACH,OAAOjB,CAAAA,EAAU,CAGnB,IAAIqB,EAAiB,CAAA,CACjB3C,CAAAA,CAEJ,KAAA,CAAOyC,CAAAA,GAAgB,CAAA,EAAKE,CAAAA,CAAiBF,CAAAA,IACvCC,CAAAA,CAAe,CAAA,EACjB,MAAMrM,CAAAA,CAAgBqM,CAAY,CAAA,CAGpC1C,CAAAA,CAAS,MAAMsB,CAAAA,EAAU,CAEzBqB,CAAAA,EAAAA,CAGG,EAAAF,CAAAA,CAAc,CAAA,EAAKE,CAAAA,EAAkBF,CAAAA,EACtC,CAACF,CAAAA,EACAC,CAAAA,EAAqBA,CAAAA,CAAkBxC,CAAAA,CAAQ2C,CAAc,CAAA,CAAA,CAAA,EAKhE,MAAMtM,CAAAA,CAAgBkM,CAAe,CAAA,CAGvC,OAAOvC,CACT,CC7CA,eAAsB4C,EAAAA,CAMpBxI,CAAAA,CACAkH,CAAAA,CAKA3E,CAAAA,CAM4E,CAC5E,IAAMqD,CAAAA,CAAS,MAAMsB,CAAAA,CAAUlH,CAAmB,CAAA,CAC5Cd,CAAAA,CAAQ0G,CAAAA,CAAO,KAAA,CAErB,GAAI,CAAC1G,CAAAA,CAEH,OAAAyG,EAAAA,CAAoBC,CAAAA,CAAQrD,CAAa,CAAA,CAElCqD,EAKLrD,CAAAA,CAAc,OAAA,EAChB,MAAM5F,CAAAA,CAAkB4F,CAAAA,CAAc,OAAA,CAASrD,CAAK,CAAA,CAKtD,IAAMuJ,CAAAA,CAAcvJ,CAAAA,CAAM,WAAA,CAY1B,GAVI,CAACuJ,GAAelG,CAAAA,CAAc,MAAA,EAChCmG,EAAAA,CAAOnG,CAAAA,CAAe,aAAA,CAAerD,CAAsB,CAAA,CAI7DyG,EAAAA,CAAoBC,CAAAA,CAAQrD,CAAAA,CAAe,IAAI,CAAA,CAGrB,CAACkG,CAAAA,EAAelG,EAAc,eAAA,CAEjC,CACrB,IAAMoG,CAAAA,CAAWpG,CAAAA,CAAc,QAAA,CAE/B,GAAIoG,CAAAA,GAAa/O,EAAAA,CACf,OAAO,OAAA,CAAQ,MAAA,CAAOsF,CAAK,CAAA,CAIzByJ,IAAa,QAAA,EACf,MAAM,IAAI,OAAA,CAAQ,IAAM,IAAI,EAEhC,CAEA,OAAO/C,CACT,CAEO,SAASgD,EAAAA,CAOd1J,CAAAA,CACAhC,EAMAqF,CAAAA,CAMM,CACNrD,CAAAA,CAAM,MAAA,CAASA,CAAAA,CAAM,MAAA,GAAUhC,CAAAA,EAAA,IAAA,CAAA,MAAA,CAAAA,CAAAA,CAAU,MAAA,CAAA,EAAU,CAAA,CACnDgC,CAAAA,CAAM,UAAA,CAAaA,CAAAA,CAAM,UAAA,GAAchC,CAAAA,EAAA,IAAA,CAAA,MAAA,CAAAA,CAAAA,CAAU,UAAA,CAAA,EAAc,EAAA,CAC/DgC,CAAAA,CAAM,MAAA,CAASA,CAAAA,CAAM,OAAA,CAAUqD,CAAAA,CAC/BrD,CAAAA,CAAM,QAAA,CAAWhC,CAAAA,CACjBgC,CAAAA,CAAM,WAAA,CAAcA,EAAM,IAAA,GAAS1F,GACrC,CAQA,SAASkP,EAAAA,CACPvG,CAAAA,CAAAA,GACGtF,CAAAA,CACG,CACN,IAAM6L,CAAAA,CAASvG,CAAAA,CAAU,MAAA,CAErBuG,CAAAA,EAAUA,CAAAA,CAAO,MACnBA,CAAAA,CAAO,IAAA,CAAK,GAAG7L,CAAI,EAEvB,CC/FA,IAAMgM,EAAAA,CAAmB,CACvB,UAAA,CAAY,IACd,CAAA,CAqBA,eAAsBC,EAAAA,CAMpB/N,EACAoH,CAAAA,CAKW,IAAA,CACiE,CAC5E,IAAM4G,CAAAA,CAAgB7G,EAAAA,CAKpBnH,CAAAA,CAAKoH,CAAS,CAAA,CAEV,CACJ,OAAA,CAAA3D,CAAAA,CACA,WAAA,CAAAwK,CAAAA,CACA,SAAA1D,CAAAA,CACA,UAAA,CAAA7G,CAAAA,CACA,SAAA,CAAA8G,CAAAA,CACA,SAAA,CAAAxE,CAAAA,CACA,cAAA,CAAAE,CAAAA,CACA,kBAAA,CAAAC,CAAAA,CACA,eAAA,CAAAiH,CAAAA,CAAkB,CACpB,EAAIY,CAAAA,CACEE,CAAAA,CAAiB1D,CAAAA,GAAc,MAAA,EAAaxE,CAAAA,GAAc,MAAA,CAE1DmI,CAAAA,CAAgB,CAAC,EACrB5D,CAAAA,EACA9G,CAAAA,EACAC,CAAAA,EACAwK,CAAAA,EACAD,CAAAA,EACA/H,GACAC,CAAAA,CAAAA,CAGEiI,CAAAA,CAA2B,IAAA,CAQ/B,GALID,CAAAA,GACFC,CAAAA,CAAYlF,CAAAA,CAAiB8E,CAAa,CAAA,CAAA,CAIxCI,CAAAA,EAAaF,CAAAA,CAAgB,CAC/B,IAAMG,CAAAA,CAAS/D,GAKb8D,CAAAA,CAAW5D,CAAAA,CAAWwD,CAAa,CAAA,CAErC,GAAIK,CAAAA,CACF,OAAOA,CAEX,CAGA,GAAID,CAAAA,EAAa1K,CAAAA,CAAY,CAC3B,IAAM4K,CAAAA,CAAW/J,EAAAA,CAEf6J,CAAAA,CAAW1K,CAAU,CAAA,CAEvB,GAAI4K,CAAAA,CACF,OAAOA,CAEX,CAEA,IAAMC,CAAAA,CAAcP,CAAAA,CAAc,KAAA,EAAS,EAAC,CACtC,CAAE,OAAA,CAAA5B,EAAAA,CAAU,CAAA,CAAG,YAAA,CAAAoC,EAAa,CAAA,CAAID,CAAAA,CAGhCE,EAAAA,CAAgB,MAAOxJ,CAAAA,CAAsB,KAAA,CAAOyH,EAAAA,CAAU,CAAA,GAAM,CAInEA,KACC0B,CAAAA,EAAa,CAACnJ,CAAAA,GACZe,CAAAA,CACoBsE,EAAAA,CACpB8D,CAAAA,CACA5D,CAAAA,CACAwD,CACF,CAAA,GAKErE,EAAAA,CAASyE,CAAAA,CAAWN,EAAAA,CAAkBtD,CAAAA,CAAWxE,CAAS,EAC1DU,CAAAA,CAAkB0H,CAAAA,CAAWN,EAAgB,CAAA,CAAA,CAG/CpH,CAAAA,CAAkB0H,CAAAA,CAAWN,EAAgB,CAAA,CAAA,CAKjDE,CAAAA,CAAc,QAAA,CAAWI,CAAAA,CAAAA,CAG3B,IAAMpO,CAAAA,CAAMgO,CAAAA,CAAc,IAGpB/J,EAAAA,CAAaT,EAAAA,CACjB4K,CAAAA,CACApO,CAAAA,CACAyD,CAAAA,CACAC,CAAAA,EAAc,CAAA,CACd,CAAC,CAACuK,CAAAA,CAEF,CAAC,EAAExK,CAAAA,GAAY,CAACiJ,IAAW8B,EAAAA,CAAAA,CAC7B,CAAA,CAIMhH,CAAAA,CAAgBwG,CAAAA,CAEtBxG,CAAAA,CAAc,MAAA,CAASvD,EAAAA,CAAW,MAAA,CAElC,IAAI4G,CAAAA,CAMA1I,CAAAA,CAKO,IAAA,CAEX,GAAI,CACE6L,EAAc,SAAA,EAChB,MAAMpM,CAAAA,CAAkBoM,CAAAA,CAAc,SAAA,CAAWxG,CAAa,CAAA,CAIhE,IAAMjB,CAAAA,CAAKyH,CAAAA,CAAc,OAAA,CAkBzB,GAhBA7L,CAAAA,CAAYoE,CAAAA,CACR,MAAMA,CAAAA,CACJvG,CAAAA,CACAwH,CACF,CAAA,CACA,MAAM,KAAA,CACJxH,CAAAA,CACAwH,CACF,CAAA,CAQAvI,CAAAA,CAASkD,CAAQ,CAAA,GAEf,OAAO,QAAA,GAAa3D,CAAAA,EAAY2D,CAAAA,YAAoB,QAAA,CACtDA,CAAAA,CAAS,IAAA,CAAO,MAAM8I,EAAAA,CAAkB9I,CAAQ,CAAA,CACvCoE,CAAAA,GAEH,MAAA,GAAUpE,CAAAA,EAAY,MAAA,GAAUA,CAAAA,GAEpCA,CAAAA,CAAW,CAAE,KAAMA,CAAS,CAAA,CAAA,CAAA,CAYhCA,CAAAA,CAAS,MAAA,CAASqF,CAAAA,CAIdrF,CAAAA,CAAS,EAAA,GAAO,KAAA,CAAA,EAAa,CAACA,CAAAA,CAAS,EAAA,CAAA,CACzC,MAAM,IAAIE,EAAAA,CACR,GAAGmF,CAAAA,CAAc,MAAM,CAAA,IAAA,EAAOxH,CAAG,CAAA,iBAAA,EAAoBmC,CAAAA,CAAS,MAAA,EAAU,IAAI,CAAA,CAAA,CAC5EqF,CAAAA,CACArF,CACF,CAAA,CAIJ0I,CAAAA,CAASS,EAAAA,CAKPnJ,EAAUqF,CAAa,CAAA,CAEzB,IAAMkH,CAAAA,CAAaV,CAAAA,CAAc,UAAA,CAE7BU,CAAAA,EACF,MAAM9M,CAAAA,CAAkB8M,CAAAA,CAAY7D,CAAM,EAE9C,CAAA,MAASQ,CAAAA,CAAQ,CACf,IAAMlH,CAAAA,CAAQkH,CAAAA,CAQdwC,EAAAA,CACE1J,CAAAA,CACAhC,CAAAA,CACAqF,CACF,CAAA,CAGAqD,CAAAA,CAASS,EAAAA,CAKPnJ,CAAAA,CAAUqF,CAAAA,CAAerD,CAAK,EAClC,CAEA,OAAO0G,CACT,CAAA,CAGM8D,EAAAA,CACJvC,EAAAA,CAAU,CAAA,CAAI,IAAMF,EAAAA,CAAUuC,EAAAA,CAAeF,CAAW,CAAA,CAAIE,EAAAA,CAExDG,CAAAA,CAA2B,CAAC3J,EAAsB,KAAA,GACtDwI,EAAAA,CACExI,CAAAA,CACA0J,EAAAA,CACAX,CACF,CAAA,CAGIa,EAAAA,CAAmBzB,CAAAA,CACrBD,EAAAA,CACEyB,CAAAA,CACAxB,CAAAA,CACAY,CAAAA,CAAc,iBAAA,CACdA,CAAAA,CAAc,mBACdA,CAAAA,CAAc,YAChB,CAAA,CACAY,CAAAA,EAAyB,CAG7B,OAAIR,CAAAA,GACE1K,CAAAA,EACFW,EAAAA,CAAmB+J,CAAAA,CAAWS,EAAgB,CAAA,CAGhDhJ,EAAAA,CACEuI,CAAAA,CACAQ,CAAAA,CACA,MAAA,CACA5I,CAAAA,CACA4I,CAAAA,CACA,CAAC,CAAC1I,CAAAA,CACF,CAAC,CAACC,CACJ,CAAA,CAAA,CAGK0I,EACT,CC3RA,SAASC,EAAAA,CAGP3F,CAAAA,CAAyC,CACzC,IAAM4F,CAAAA,CAAY5F,CAAAA,CAAO,SAAA,CAQzB,SAAS6F,CAAAA,CAAqBC,CAAAA,CAAqC,CACjE,OAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,IAAA,EAAOA,CAAY,CAAA,gBAAA,CAAkB,CAAA,CAE5C,QAAQ,OAAA,CAAQ,IAAI,CAC7B,CAEA,IAAMC,CAAAA,CAAsD,CAC1D,MAAA,CAAA/F,CAAAA,CACA,SAAA,CAAA4F,CAAAA,CASA,MAAM,OAAA,CAAQE,CAAAA,CAAczH,EAAgB,EAAC,CAAG,CAE9C,IAAM2H,CAAAA,CAAiBJ,CAAAA,CAAUE,CAAY,CAAA,CACvCG,CAAAA,CACJD,CAAAA,EACC,CAAE,GAAA,CAAK,MAAA,CAAOF,CAAY,CAAE,CAAA,CACzBjP,CAAAA,CAAMoP,CAAAA,CAAgB,GAAA,CAG5B,GAAIpP,CAAAA,CAAI,UAAA,CAAW,IAAI,CAAA,CACrB,MAAM,IAAI,KAAA,CAAM,yCAAyC,CAAA,CAI3D,IAAMoI,EAAetH,EAAAA,CAAcd,CAAG,CAAA,CAAA,CAElCmP,CAAAA,EAAA,IAAA,CAAA,MAAA,CAAAA,CAAAA,CAAgB,GAAA,IAAQnP,CAAAA,CACtBuH,CAAAA,CAAa6H,CAAAA,CAAiB5H,CAAa,CAAA,CAC3CA,CAAAA,CACFD,CAAAA,CAAaA,EAAa4B,CAAAA,CAAQiG,CAAe,CAAA,CAAG5H,CAAa,CAAA,CAIrE,OAAOuG,EAAAA,CAAO/N,CAAAA,CAAKoI,CAAY,CACjC,CACF,CAAA,CAOA,OAAO,IAAI,MACT8G,CAAAA,CACA,CACE,GAAA,CAAIG,CAAAA,CAASC,CAAAA,CAAc,CACzB,OAAIA,CAAAA,IAAQJ,CAAAA,CACHA,CAAAA,CAAWI,CAA0C,CAAA,CAI1DP,CAAAA,CAAUO,CAAI,CAAA,CACTJ,CAAAA,CAAW,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAMI,CAAI,CAAA,CAGpCN,CAAAA,CAAqB,IAAA,CAAK,IAAA,CAAMM,CAAI,CAC7C,CACF,CACF,CACF","file":"index.mjs","sourcesContent":["export const APPLICATION_CONTENT_TYPE = 'application/';\n\nexport const APPLICATION_JSON = APPLICATION_CONTENT_TYPE + 'json';\nexport const CHARSET_UTF_8 = 'charset=utf-8';\nexport const CONTENT_TYPE = 'Content-Type';\n\nexport const UNDEFINED = 'undefined';\nexport const OBJECT = 'object';\nexport const STRING = 'string';\nexport const FUNCTION = 'function';\n\nexport const ABORT_ERROR = 'AbortError';\nexport const TIMEOUT_ERROR = 'TimeoutError';\n\nexport const GET = 'GET';\nexport const HEAD = 'HEAD';\n\nexport const REJECT = 'reject';\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { FUNCTION, OBJECT, STRING, UNDEFINED } from './constants';\nimport type {\n DefaultUrlParams,\n HeadersObject,\n QueryParams,\n UrlPathParams,\n} from './types';\n\n// Prevent stack overflow with recursion depth limit\nconst MAX_DEPTH = 10;\n\nexport function isSearchParams(data: unknown): boolean {\n return data instanceof URLSearchParams;\n}\n\n/**\n * Determines if a value is a non-null object.\n *\n * @param {any} value - The value to check.\n * @returns {boolean} - True if the value is a non-null object.\n */\nexport function isObject(value: any): value is Record {\n return value !== null && typeof value === OBJECT;\n}\n\n/**\n * Shallowly serializes an object by converting its key-value pairs into a string representation.\n * This function does not recursively serialize nested objects.\n *\n * @param obj - The object to serialize.\n * @returns A string representation of the object's top-level properties.\n */\nexport function shallowSerialize(obj: Record): string {\n let result = '';\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n result += key + ':' + obj[key];\n }\n }\n\n return result;\n}\n\n/**\n * Removes properties that could lead to prototype pollution from an object.\n *\n * This function creates a shallow copy of the input object with dangerous\n * properties like '__proto__', 'constructor', and 'prototype' removed.\n *\n * @param obj - The object to sanitize\n * @returns A new object without dangerous properties\n */\nexport function sanitizeObject>(obj: T): T {\n const safeObj = { ...obj };\n\n delete safeObj.__proto__;\n delete (safeObj as any).constructor;\n delete safeObj.prototype;\n\n return safeObj;\n}\n\n/**\n * Sorts the keys of an object and returns a new object with sorted keys.\n *\n * This function is optimized for performance by minimizing the number of object operations\n * and using a single pass to create the sorted object.\n *\n * @param {Object} obj - The object to be sorted by keys.\n * @returns {Object} - A new object with keys sorted in ascending order.\n */\nexport function sortObject(obj: Record): object {\n const keys = Object.keys(obj);\n\n keys.sort();\n\n const sortedObj = {} as Record;\n\n for (let i = 0, len = keys.length; i < len; i++) {\n const key = keys[i];\n\n sortedObj[key] = obj[key];\n }\n\n return sortedObj;\n}\n\n/**\n * Appends a query string to a URL, ensuring proper handling of existing query parameters.\n *\n * @param baseUrl - The base URL to which the query string will be appended.\n * @param queryString - The encoded query string to append.\n * @returns The URL with the appended query string, or the original URL if no query string is provided.\n */\nfunction appendQueryStringToUrl(baseUrl: string, queryString: string): string {\n if (!queryString) {\n return baseUrl;\n }\n\n return baseUrl.includes('?')\n ? `${baseUrl}&${queryString}`\n : `${baseUrl}?${queryString}`;\n}\n\n/**\n * Appends query parameters to a given URL.\n *\n * @param {string} url - The base URL to which query parameters will be appended.\n * @param {QueryParams} params - An object containing the query parameters to append.\n * @returns {string} - The URL with the appended query parameters.\n */\nexport function appendQueryParams(url: string, params: QueryParams): string {\n if (!params) {\n return url;\n }\n\n // Check if `params` is an instance of URLSearchParams and bail early if it is\n if (isSearchParams(params)) {\n const encodedQueryString = params.toString();\n\n return appendQueryStringToUrl(url, encodedQueryString);\n }\n\n // This is exact copy of what JQ used to do. It works much better than URLSearchParams\n const s: string[] = [];\n const encode = encodeURIComponent;\n const add = (k: string, v: any) => {\n v = typeof v === FUNCTION ? v() : v;\n v = v === null ? '' : v === undefined ? '' : v;\n s[s.length] = encode(k) + '=' + encode(v);\n };\n\n const buildParams = (prefix: string, obj: any, depth = 0) => {\n // Stop recursion if maximum depth is reached\n if (depth >= MAX_DEPTH) {\n return s;\n }\n\n let i: number, len: number, key: string;\n\n if (prefix) {\n if (Array.isArray(obj)) {\n for (i = 0, len = obj.length; i < len; i++) {\n buildParams(\n prefix + '[' + (typeof obj[i] === OBJECT && obj[i] ? i : '') + ']',\n obj[i],\n depth + 1,\n );\n }\n } else if (isObject(obj)) {\n for (key in obj) {\n buildParams(prefix + '[' + key + ']', obj[key], depth + 1);\n }\n } else {\n add(prefix, obj);\n }\n } else if (Array.isArray(obj)) {\n for (i = 0, len = obj.length; i < len; i++) {\n add(obj[i].name, obj[i].value);\n }\n } else {\n for (key in obj) {\n buildParams(key, obj[key], depth + 1);\n }\n }\n return s;\n };\n\n const queryStringParts = buildParams('', params).join('&');\n\n // Encode special characters as per RFC 3986, https://datatracker.ietf.org/doc/html/rfc3986\n // This is for compatibility with server frameworks that expect the literal notation\n const encodedQueryString = queryStringParts.replace(/%5B%5D/g, '[]'); // Keep '[]' for arrays\n\n return appendQueryStringToUrl(url, encodedQueryString);\n}\n\n/**\n * Replaces dynamic URI parameters in a URL string with values from the provided `urlPathParams` object.\n * Parameters in the URL are denoted by `:`, where `` is a key in `urlPathParams`.\n *\n * @param {string} url - The URL string containing placeholders in the format `:`.\n * @param {Object} urlPathParams - An object containing the parameter values to replace placeholders.\n * @param {string} urlPathParams.paramName - The value to replace the placeholder `:` in the URL.\n * @returns {string} - The URL string with placeholders replaced by corresponding values from `urlPathParams`.\n */\nexport function replaceUrlPathParams(\n url: string,\n urlPathParams: UrlPathParams,\n): string {\n if (!urlPathParams || url.indexOf(':') === -1) {\n return url;\n }\n\n // Use a single RegExp and avoid unnecessary casts and function calls\n // Precompute keys for faster lookup\n const params = urlPathParams as DefaultUrlParams;\n\n // Use a replacer function that avoids extra work\n return url.replace(/:([a-zA-Z0-9_]+)/g, (match, key) => {\n // Use hasOwnProperty for strict key existence check\n if (Object.prototype.hasOwnProperty.call(params, key)) {\n const value = params[key];\n\n // Only replace if value is not undefined or null\n if (value !== undefined && value !== null) {\n return encodeURIComponent(String(value));\n }\n }\n\n return match;\n });\n}\n\n/**\n * Determines whether the provided URL is absolute.\n *\n * An absolute URL contains a scheme (e.g., \"http://\", \"https://\").\n *\n * @param url - The URL string to check.\n * @returns `true` if the URL is absolute, otherwise `false`.\n */\nexport function isAbsoluteUrl(url: string): boolean {\n return url.includes('://');\n}\n\nexport const timeNow = () => Date.now();\n\nexport const noop = () => {};\n\n/**\n * Checks if a value is JSON serializable.\n *\n * JSON serializable values include:\n * - Primitive types: string, number, boolean, null\n * - Arrays\n * - Plain objects (i.e., objects without special methods)\n * - Values with a `toJSON` method\n *\n * @param {any} value - The value to check for JSON serializability.\n * @returns {boolean} - Returns `true` if the value is JSON serializable, otherwise `false`.\n */\nexport function isJSONSerializable(value: any): boolean {\n const t = typeof value;\n\n if (value === undefined || value === null) {\n return false;\n }\n\n if (t === STRING || t === 'number' || t === 'boolean') {\n return true;\n }\n\n if (Array.isArray(value)) {\n return true;\n }\n\n if (\n typeof globalThis !== UNDEFINED &&\n typeof globalThis.Buffer !== UNDEFINED &&\n globalThis.Buffer.isBuffer(value)\n ) {\n return false;\n }\n\n if (value instanceof Date || isSearchParams(value)) {\n return false;\n }\n\n if (isObject(value)) {\n const proto = Object.getPrototypeOf(value);\n\n // Check if the prototype is `Object.prototype` (plain object)\n if (proto === Object.prototype) {\n return true;\n }\n\n // Check if the object has a toJSON method\n if (typeof value.toJSON === FUNCTION) {\n return true;\n }\n }\n\n return false;\n}\n\nexport async function delayInvocation(ms: number): Promise {\n return new Promise((resolve) =>\n setTimeout(() => {\n return resolve(true);\n }, ms),\n );\n}\n\n/**\n * Recursively flattens the data object if it meets specific criteria.\n *\n * The method checks if the provided `data` is an object with exactly one property named `data`.\n * If so, it recursively flattens the `data` property. Otherwise, it returns the `data` as-is.\n *\n * @param {any} data - The data to be flattened. Can be of any type, including objects, arrays, or primitives.\n * @returns {any} - The flattened data if the criteria are met; otherwise, the original `data`.\n */\nexport function flattenData(data: any, depth = 0): any {\n if (depth >= MAX_DEPTH) {\n return data;\n }\n\n if (data && isObject(data) && typeof data.data !== UNDEFINED) {\n return flattenData(data.data, depth + 1);\n }\n\n return data;\n}\n\n/**\n * Processes headers and returns them as a normalized object.\n *\n * Handles both `Headers` instances and plain objects. Normalizes header keys to lowercase\n * as per RFC 2616 section 4.2.\n *\n * @param headers - The headers to process. Can be an instance of `Headers`, a plain object,\n * or `null`. If `null`, an empty object is returned.\n * @returns {HeadersObject} - A normalized headers object with lowercase keys.\n */\nexport function processHeaders(\n headers?: (HeadersObject & HeadersInit) | null | Headers,\n): HeadersObject {\n if (!headers) {\n return {};\n }\n\n const headersObject: HeadersObject = {};\n\n // Handle Headers object with entries() method\n if (headers instanceof Headers) {\n headers.forEach((value, key) => {\n headersObject[key] = value;\n });\n } else if (isObject(headers)) {\n // Handle plain object\n for (const [key, value] of Object.entries(headers)) {\n // Normalize keys to lowercase as per RFC 2616 4.2\n // https://datatracker.ietf.org/doc/html/rfc2616#section-4.2\n headersObject[key.toLowerCase()] = value;\n }\n }\n\n return headersObject;\n}\n\n/**\n * Determines if the current environment is a browser.\n *\n * @returns {boolean} - True if running in a browser environment, false otherwise.\n */\nexport function isBrowser(): boolean {\n // For node and and some mobile frameworks like React Native, `add/removeEventListener` doesn't exist on window!\n return (\n typeof window !== UNDEFINED && typeof window.addEventListener === FUNCTION\n );\n}\n\n/**\n * Detects if the user is on a slow network connection\n * @returns {boolean} True if connection is slow, false otherwise or if detection unavailable\n */\nexport const isSlowConnection = (): boolean => {\n // Only works in browser environments\n if (!isBrowser()) {\n return false;\n }\n\n const conn = navigator && (navigator as any).connection;\n\n return conn && ['slow-2g', '2g', '3g'].includes(conn.effectiveType);\n};\n","import { FUNCTION } from './constants';\nimport type { InterceptorFunction } from './types/interceptor-manager';\nimport { isObject } from './utils';\n\n/**\n * Applies interceptors to the object. Interceptors can be a single function or an array of functions.\n *\n * @template T - Type of the object.\n * @template Args - Type of additional arguments.\n * @template I - Type of interceptors.\n *\n * @param {InterceptorFunction | InterceptorFunction[]} [interceptors] - Interceptor function(s).\n * @param {T} data - The data object to process.\n * @param {...Args} args - Additional arguments to pass to interceptors.\n *\n * @returns {Promise} - Nothing as the function is non-idempotent.\n */\nexport async function applyInterceptors<\n T extends object,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Args extends any[] = any[],\n I = InterceptorFunction | InterceptorFunction[],\n>(interceptors: I | undefined, data: T, ...args: Args): Promise {\n if (!interceptors) {\n return;\n }\n\n if (typeof interceptors === FUNCTION) {\n const value = await (interceptors as InterceptorFunction)(\n data,\n ...args,\n );\n\n if (value && isObject(data) && isObject(value)) {\n Object.assign(data, value);\n }\n } else if (Array.isArray(interceptors)) {\n for (const interceptor of interceptors) {\n const value = await interceptor(data, ...args);\n\n if (value && isObject(data) && isObject(value)) {\n Object.assign(data, value);\n }\n }\n }\n}\n","import type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '../types';\n\n/**\n * This is a base error class\n */\nexport class FetchError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n> extends Error {\n status: number;\n statusText: string;\n config: RequestConfig;\n isCancelled: boolean;\n\n constructor(\n message: string,\n public request: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n public response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n ) {\n super(message);\n\n this.name = 'FetchError';\n this.status = response ? response.status : 0;\n this.statusText = response ? response.statusText : '';\n this.config = request;\n this.isCancelled = false;\n }\n}\n","import { FetchError } from './fetch-error';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '../types';\n\nexport class ResponseError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n> extends FetchError {\n constructor(\n message: string,\n request: RequestConfig,\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n ) {\n super(message, request, response);\n\n this.name = 'ResponseError';\n }\n}\n","/**\n * @module timeout-wheel\n * @description\n * Ultra-minimal timing wheel implementation optimized for max performance & many requests.\n * For most of the cases it's 4-100x faster than setTimeout and setInterval alone.\n * Provides efficient scheduling and cancellation of timeouts using a circular array.\n *\n * Position 0 → 1 → 2 → ... → 599 → 0 → 1 → 2 ...\n * Time: 0s 1s 2s 599s 600s 601s 602s\n *\n * The timing wheel consists of 600 slots (one per second for 10 min).\n * Each slot contains a list of timeout items, each associated with a unique key and callback.\n * Timeouts are scheduled by placing them in the appropriate slot based on the delay in seconds.\n * The wheel advances every second, executing and removing callbacks as their timeouts expire.\n * Defaults to setTimeout if the delay exceeds 10 minutes or is not divisible by 1000.\n *\n * @remarks\n * - Designed for minimal footprint and simplicity.\n * - Only supports second-level granularity (minimum timeout: 1 second).\n * - Automatically stops the internal timer when no timeouts remain.\n */\n\nimport { noop } from './utils';\n\ntype TimeoutCallback = () => unknown | Promise;\ntype TimeoutItem = [string, TimeoutCallback]; // [key, callback]\n\nconst WHEEL_SIZE = 600; // 600 slots for 10 min (1 slot per second)\nconst SECOND = 1000; // 1 second in milliseconds\nconst MAX_WHEEL_MS = WHEEL_SIZE * SECOND;\nconst wheel: TimeoutItem[][] = Array(WHEEL_SIZE)\n .fill(0)\n .map(() => []);\n\nconst keyMap = new Map();\nlet position = 0;\nlet timer: NodeJS.Timeout | null = null;\n\nconst handleCallback = ([key, callback]: TimeoutItem): void => {\n keyMap.delete(key);\n\n try {\n const result = callback();\n if (result && result instanceof Promise) {\n // Silently ignore async errors to prevent wheel from stopping\n result.catch(noop);\n }\n } catch {\n // Ignore callback errors to prevent wheel from stopping\n }\n};\n\nexport const addTimeout = (\n key: string,\n cb: TimeoutCallback,\n ms: number,\n): void => {\n removeTimeout(key);\n\n // Fallback to setTimeout if wheel size is exceeded or ms is not divisible by SECOND\n if (ms > MAX_WHEEL_MS || ms % SECOND !== 0) {\n keyMap.set(key, [setTimeout(handleCallback.bind(null, [key, cb]), ms)]); // Store timeout ID instead of slot\n\n return;\n }\n\n // No need for Math.ceil here since ms is guaranteed by modulo above\n const seconds = ms / SECOND;\n const slot = (position + seconds) % WHEEL_SIZE;\n\n wheel[slot].push([key, cb]);\n keyMap.set(key, slot);\n\n if (!timer) {\n timer = setInterval(() => {\n position = (position + 1) % WHEEL_SIZE;\n wheel[position].forEach(handleCallback);\n wheel[position] = [];\n\n if (!keyMap.size && timer) {\n clearInterval(timer);\n timer = null;\n }\n }, SECOND);\n }\n};\n\nexport const removeTimeout = (key: string): void => {\n const slotOrTimeout = keyMap.get(key);\n\n if (slotOrTimeout !== undefined) {\n // It's a Timeout object from setTimeout\n if (Array.isArray(slotOrTimeout)) {\n clearTimeout(slotOrTimeout[0]);\n } else {\n wheel[slotOrTimeout].splice(\n wheel[slotOrTimeout].findIndex(([k]) => k === key),\n 1,\n );\n }\n\n keyMap.delete(key);\n\n if (!keyMap.size && timer) {\n clearInterval(timer);\n timer = null;\n }\n }\n};\n\nexport const clearAllTimeouts = () => {\n // Clear native setTimeout timeouts first!\n keyMap.forEach((value) => {\n if (Array.isArray(value)) {\n clearTimeout(value[0]);\n }\n });\n\n if (timer) {\n clearInterval(timer);\n timer = null;\n }\n\n keyMap.clear();\n wheel.forEach((slot) => (slot.length = 0));\n position = 0;\n};\n","/**\n * @module inflight-manager\n *\n * Manages in-flight asynchronous requests using unique keys to enable deduplication and cancellation.\n *\n * Provides utilities for:\n * - Deduplication of requests within a configurable time window (`dedupeTime`)\n * - Timeout management and automatic request abortion\n * - AbortController lifecycle and cancellation logic\n * - Concurrency control and request state tracking\n * - In-flight promise deduplication to prevent duplicate network calls\n *\n * @remarks\n * - Requests with the same key within the deduplication interval share the same AbortController and in-flight promise.\n * - Supports cancellation of previous requests when a new one with the same key is issued, if `isCancellable` is enabled.\n * - Timeout logic ensures requests are aborted after a specified duration, if enabled.\n * - Internal queue state is managed via a Map, keyed by request identifier.\n * - Polled requests are also marked as \"in-flight\" to prevent duplicate requests.\n */\n\nimport { ABORT_ERROR, TIMEOUT_ERROR } from './constants';\nimport { addTimeout, removeTimeout } from './timeout-wheel';\nimport { timeNow } from './utils';\n\nexport type InFlightItem = [\n AbortController, // AbortController for the request\n boolean, // Whether timeout is enabled for the request\n number, // Timestamp when the request was marked in-flight\n boolean, // isCancellable - whether the request can be cancelled\n Promise | null, // Optional in-flight promise for deduplication\n];\n\nconst inFlight: Map = new Map();\n\n/**\n * Adds a request to the queue if it's not already being processed within the dedupeTime interval.\n *\n * @param {string | null} key - Unique key for the request (e.g. cache key).\n * @param {string} url - The request URL (for error messages/timeouts).\n * @param {number} timeout - Timeout in milliseconds for the request.\n * @param {number} dedupeTime - Deduplication time in milliseconds.\n * @param {boolean} isCancellable - If true, then the previous request with same configuration should be aborted.\n * @param {boolean} isTimeoutEnabled - Whether timeout is enabled.\n * @returns {AbortController} - A promise that resolves to an AbortController.\n */\nexport function markInFlight(\n key: string | null,\n url: string,\n timeout: number | undefined,\n dedupeTime: number,\n isCancellable: boolean,\n isTimeoutEnabled: boolean,\n): AbortController {\n if (!key) {\n return new AbortController();\n }\n\n const item = inFlight.get(key);\n let prevPromise: Promise | null = null;\n\n // Previous request is in-flight, check if we can reuse it\n if (item) {\n const prevController = item[0];\n const prevIsCancellable = item[3];\n\n // If the request is already in the queue and within the dedupeTime, reuse the existing controller\n if (\n !prevIsCancellable &&\n timeNow() - item[2] < dedupeTime &&\n !prevController.signal.aborted\n ) {\n return prevController;\n }\n\n // If the request is too old, remove it and proceed to add a new one\n // Abort previous request, if applicable, and continue as usual\n if (prevIsCancellable) {\n prevController.abort(\n new DOMException('Aborted due to new request', ABORT_ERROR),\n );\n }\n\n removeTimeout(key);\n prevPromise = item[4];\n }\n\n const controller = new AbortController();\n\n inFlight.set(key, [\n controller,\n isTimeoutEnabled,\n timeNow(),\n isCancellable,\n prevPromise,\n ]);\n\n if (isTimeoutEnabled) {\n addTimeout(\n key,\n () => {\n abortRequest(\n key,\n new DOMException(url + ' aborted due to timeout', TIMEOUT_ERROR),\n );\n },\n timeout as number,\n );\n }\n\n return controller;\n}\n\n/**\n * Removes a request from the queue and clears its timeout.\n *\n * @param key - Unique key for the request.\n * @param {boolean} error - Optional error to abort the request with. If null, the request is simply removed but no abort sent.\n * @returns {Promise} - A promise that resolves when the request is aborted and removed.\n */\nexport async function abortRequest(\n key: string | null,\n error: DOMException | null | string = null,\n): Promise {\n // If the key is not in the queue, there's nothing to remove\n if (key) {\n const item = inFlight.get(key);\n\n if (item) {\n // If the request is not yet aborted, abort it with the provided error\n if (error) {\n const controller = item[0];\n controller.abort(error);\n }\n\n removeInFlight(key);\n }\n }\n}\n\n/**\n * Removes a request from the in-flight queue without aborting or clearing timeout.\n *\n * @param key - Unique key for the request.\n */\nexport function removeInFlight(key: string | null): void {\n removeTimeout(key!);\n inFlight.delete(key!);\n}\n\n/**\n * Gets the AbortController for a request key.\n *\n * @param key - Unique key for the request.\n * @returns {AbortController | undefined} - The AbortController or undefined.\n */\nexport async function getController(\n key: string,\n): Promise {\n const item = inFlight.get(key);\n\n return item?.[0];\n}\n\n/**\n * Adds helpers for in-flight promise deduplication.\n *\n * @param key - Unique key for the request.\n * @param promise - The promise to store.\n */\nexport function setInFlightPromise(\n key: string,\n promise: Promise,\n): void {\n const item = inFlight.get(key);\n if (item) {\n // store the promise at index 4\n item[4] = promise;\n\n inFlight.set(key, item);\n }\n}\n\n/**\n * Retrieves the in-flight promise for a request key if it exists and is within the dedupeTime interval.\n *\n * @param key - Unique key for the request.\n * @param dedupeTime - Deduplication time in milliseconds.\n * @returns {Promise | null} - The in-flight promise or null.\n */\nexport function getInFlightPromise(\n key: string | null,\n dedupeTime: number,\n): Promise | null {\n if (!key) {\n return null;\n }\n\n const prevReq = inFlight.get(key);\n\n if (\n prevReq &&\n // If the request is in-flight and has a promise\n prevReq[4] &&\n // If the request is cancellable, we will not reuse it\n !prevReq[3] &&\n // If the request is within the dedupeTime\n timeNow() - prevReq[2] < dedupeTime &&\n // If one request is cancelled, ALL deduped requests get cancelled\n !prevReq[0].signal.aborted\n ) {\n return prevReq[4] as Promise;\n }\n\n return null;\n}\n","const PRIME_MULTIPLIER = 31;\n\n/**\n * Computes a hash value for a given string using the variant of djb2 hash function.\n * This hash function is non-cryptographic and designed for speed.\n * @author Daniel J. Bernstein (of djb2)\n *\n * @param str Input string to hash\n * @returns {string} Hash\n */\nexport function hash(str: string): string {\n let hash = 0;\n\n for (let i = 0, len = str.length; i < len; i++) {\n const char = str.charCodeAt(i);\n hash = (hash * PRIME_MULTIPLIER + char) | 0;\n }\n\n return String(hash);\n}\n","/**\n * @module revalidator-manager\n *\n * Provides utilities for managing cache revalidation functions, including:\n * - Registering and unregistering revalidators for specific cache keys.\n * - Triggering revalidation for a given key.\n * - Enabling or disabling automatic revalidation on window focus and if user comes back online for specific keys.\n * - Attaching and removing global focus and online event handlers to trigger revalidation.\n *\n * Revalidators are functions that can be registered to revalidate cache entries when needed.\n * They are typically used to refresh data in the cache when the window gains focus or when specific actions occur.\n * @performance O(1) lookup by key makes it blazing fast to register, unregister, and revalidate cache entries.\n * - Designed for high performance: minimizes unnecessary re-renders and leverages fast cache key generation.\n * - Integrates with a global cache and pub/sub system for efficient state updates across contexts.\n * - Handles automatic revalidation, deduplication, retries, and cache management out of the box.\n * @remarks\n * - Designed to be used in various environments (Deno, Node.js, Bun, Browser, etc.) to ensure cache consistency and freshness.\n */\nimport { addTimeout, removeTimeout } from './timeout-wheel';\nimport { FetchResponse } from './types';\nimport { isBrowser, noop, timeNow } from './utils';\n\nexport type RevalidatorFn = (\n isStaleRevalidation?: boolean,\n) => Promise;\n\ntype EventType = 'focus' | 'online';\n\ntype RevalidatorEntry = [\n RevalidatorFn, // main revalidator\n number, // lastUsed\n number, // ttl\n number?, // staleTime\n RevalidatorFn?, // bgRevalidator\n boolean?, // refetchOnFocus\n boolean?, // refetchOnReconnect\n];\n\nconst DEFAULT_TTL = 3 * 60 * 1000; // Default TTL of 3 minutes\nconst revalidators = new Map();\n\n/**\n * Stores global event handlers for cache revalidation events (e.g., focus, online).\n * This avoids attaching multiple event listeners by maintaining a single handler per event type.\n * Event handlers are registered as needed when revalidators are registered with the corresponding flags.\n * @remarks\n * - Improves performance by reducing the number of event listeners.\n * - Enables efficient O(1) lookup and management of event handlers for revalidation.\n */\nconst eventHandlers = new Map void>();\n\n/**\n * Triggers revalidation for all registered entries based on the given event type.\n * For example, if it's a 'focus' event, it will revalidate entries that have the `refetchOnFocus` flag set.\n * Updates the timestamp and invokes the revalidator function for each applicable entry.\n *\n * @param type - The type of event that caused the revalidation (e.g., 'focus' or 'online').\n * @param isStaleRevalidation - If `true`, uses background revalidator and doesn't mark as in-flight.\n */\nexport function revalidateAll(\n type: EventType,\n isStaleRevalidation: boolean = true,\n) {\n const flagIndex = type === 'focus' ? 5 : 6;\n const now = timeNow();\n\n revalidators.forEach((entry) => {\n if (!entry[flagIndex]) {\n return;\n }\n\n entry[1] = now;\n\n // If it's a stale revalidation, use the background revalidator function\n const revalidator = isStaleRevalidation ? entry[4] : entry[0];\n\n if (revalidator) {\n Promise.resolve(revalidator(isStaleRevalidation)).catch(noop);\n }\n });\n}\n\n/**\n * Revalidates an entry by executing the registered revalidation function.\n *\n * @param key The unique identifier for the cache entry to revalidate. If `null`, no revalidation occurs.\n * @param isStaleRevalidation - If `true`, it does not mark revalidated requests as in-flight.\n * @returns A promise that resolves to the result of the revalidator function, or\n * `null` if no key or revalidator is found, or a `FetchResponse` if applicable.\n */\nexport async function revalidate(\n key: string | null,\n isStaleRevalidation: boolean = false,\n): Promise {\n // If no key is provided, no revalidation occurs\n if (!key) {\n return null;\n }\n\n const entry = revalidators.get(key);\n\n if (entry) {\n // Update only the lastUsed timestamp without resetting the whole array\n entry[1] = timeNow();\n\n const revalidator = isStaleRevalidation ? entry[4] : entry[0];\n\n // If no revalidator function is registered, return null\n if (revalidator) {\n return await revalidator(isStaleRevalidation);\n }\n }\n\n // If no revalidator is registered for the key, return null\n return null;\n}\n\n/**\n * Removes all revalidators associated with the specified event type.\n *\n * @param type - The event type whose revalidators should be removed.\n */\nexport function removeRevalidators(type: EventType) {\n removeEventHandler(type);\n\n const flagIndex = type === 'focus' ? 5 : 6;\n\n // Clear all revalidators with this flag\n revalidators.forEach((entry, key) => {\n if (entry[flagIndex]) {\n removeRevalidator(key);\n }\n });\n}\n\n/**\n * Registers a generic revalidation event handler for the specified event type.\n * Ensures the handler is only added once and only in browser environments.\n *\n * @param event - The type of event to listen for (e.g., 'focus', 'visibilitychange').\n */\nfunction addEventHandler(event: EventType) {\n if (!isBrowser() || eventHandlers.has(event)) {\n return;\n }\n\n const handler = revalidateAll.bind(null, event, true);\n\n eventHandlers.set(event, handler);\n window.addEventListener(event, handler);\n}\n\n/**\n * Removes the generic event handler for the specified event type from the window object.\n *\n * @param event - The type of event whose handler should be removed.\n */\nfunction removeEventHandler(event: EventType) {\n if (!isBrowser()) {\n return;\n }\n\n const handler = eventHandlers.get(event);\n\n if (handler) {\n window.removeEventListener(event, handler);\n\n eventHandlers.delete(event);\n }\n}\n\n/**\n * Registers a revalidation functions for a specific cache key.\n *\n * @param {string} key Cache key to utilize\n * @param {RevalidatorFn} revalidatorFn Main revalidation function (marks in-flight requests)\n * @param {number} [ttl] Time to live in milliseconds (default: 3 minutes)\n * @param {number} [staleTime] Time (in seconds) after which the cache entry is considered stale\n * @param {RevalidatorFn} [bgRevalidatorFn] For stale revalidation (does not mark in-flight requests)\n * @param {boolean} [refetchOnFocus] Whether to revalidate on window focus\n * @param {boolean} [refetchOnReconnect] Whether to revalidate on network reconnect\n */\nexport function addRevalidator(\n key: string,\n revalidatorFn: RevalidatorFn, // Main revalidation function (marks in-flight requests)\n ttl?: number,\n staleTime?: number,\n bgRevalidatorFn?: RevalidatorFn, // For stale revalidation (does not mark in-flight requests)\n refetchOnFocus?: boolean,\n refetchOnReconnect?: boolean,\n) {\n revalidators.set(key, [\n revalidatorFn,\n timeNow(),\n ttl ?? DEFAULT_TTL,\n staleTime,\n bgRevalidatorFn,\n refetchOnFocus,\n refetchOnReconnect,\n ]);\n\n if (refetchOnFocus) {\n addEventHandler('focus');\n }\n\n if (refetchOnReconnect) {\n addEventHandler('online');\n }\n\n if (staleTime) {\n addTimeout('s:' + key, revalidate.bind(null, key, true), staleTime * 1000);\n }\n}\n\nexport function removeRevalidator(key: string) {\n revalidators.delete(key);\n\n // Clean up stale timer\n removeTimeout('s:' + key);\n}\n\n/**\n * Periodically cleans up expired revalidators from the registry.\n * Removes any revalidator whose TTL has expired.\n *\n * @param {number} intervalMs How often to run cleanup (default: 3 minutes)\n * @returns {() => void} A function to stop the periodic cleanup\n */\nexport function startRevalidatorCleanup(\n intervalMs: number = DEFAULT_TTL,\n): () => void {\n const intervalId = setInterval(() => {\n const now = timeNow();\n\n revalidators.forEach(\n ([, lastUsed, ttl, , , refetchOnFocus, refetchOnReconnect], key) => {\n // Skip focus-only or reconnect-only revalidators to keep them alive\n if (refetchOnFocus || refetchOnReconnect) {\n return;\n }\n\n if (ttl > 0 && now - lastUsed > ttl) {\n removeRevalidator(key);\n }\n },\n );\n }, intervalMs);\n\n return () => clearInterval(intervalId);\n}\n","/**\n * Manages a set of listeners (subscribers) for arbitrary string keys, allowing cross-context or cross-component\n * cache updates and synchronization. Provides functions to add, remove, and notify listeners, as well as a\n * convenient subscribe/unsubscribe API.\n *\n * @template T - The type of the response object passed to listeners.\n *\n * @remarks\n * - Listeners are grouped by a string key, which typically represents a cache key or resource identifier.\n * - When `notifySubscribers` is called for a key, all listeners registered for that key are invoked with the provided response.\n * - The `subscribe` function returns an unsubscribe function for convenient cleanup.\n *\n * @example\n * ```ts\n * const unsubscribe = subscribe('user:123', (response) => {\n * // handle updated data\n * });\n * // Later, to stop listening:\n * unsubscribe();\n * ```\n */\n\nimport { noop } from './utils';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Listener = (response: T) => void;\n\nconst listeners = new Map>();\n\nfunction ensureListenerSet(key: string) {\n if (!listeners.has(key)) {\n listeners.set(key, new Set());\n }\n\n return listeners.get(key)!;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function addListener(key: string, fn: Listener): void {\n ensureListenerSet(key).add(fn);\n}\n\nexport function removeListener(key: string, fn: Listener) {\n const set = listeners.get(key);\n\n if (set) {\n set.delete(fn);\n\n // If the set is empty, remove the key from the listeners map\n if (set.size === 0) {\n listeners.delete(key);\n }\n }\n}\n\nexport function notifySubscribers(key: string, response: T) {\n const fns = listeners.get(key);\n\n if (fns) {\n if (fns.size === 1) {\n // If there's only one listener, call it directly\n const fn = fns.values().next().value;\n fn!(response);\n } else {\n fns.forEach((fn) => fn(response));\n }\n }\n}\n\nexport function subscribe(key: string | null, fn: (response: T) => void) {\n if (!key) {\n // No op if no key is provided\n return noop;\n }\n\n addListener(key, fn);\n\n // Return an unsubscribe function\n return () => {\n removeListener(key, fn);\n };\n}\n","import {\n GET,\n APPLICATION_JSON,\n HEAD,\n STRING,\n CHARSET_UTF_8,\n CONTENT_TYPE,\n REJECT,\n UNDEFINED,\n APPLICATION_CONTENT_TYPE,\n} from './constants';\nimport type {\n HeadersObject,\n Method,\n RequestConfig,\n} from './types/request-handler';\nimport {\n replaceUrlPathParams,\n appendQueryParams,\n isSearchParams,\n isJSONSerializable,\n isSlowConnection,\n isAbsoluteUrl,\n sanitizeObject,\n isObject,\n} from './utils';\n\nconst defaultTimeoutMs = (isSlowConnection() ? 60 : 30) * 1000;\n\nexport const defaultConfig: RequestConfig = {\n strategy: REJECT,\n timeout: defaultTimeoutMs, // 30 seconds (60 on slow connections)\n headers: {\n Accept: APPLICATION_JSON + ', text/plain, */*',\n 'Accept-Encoding': 'gzip, deflate, br',\n },\n retry: {\n delay: defaultTimeoutMs / 30, // 1 second (2 on slow connections)\n maxDelay: defaultTimeoutMs, // 30 seconds (60 on slow connections)\n resetTimeout: true,\n backoff: 1.5,\n\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status\n retryOn: [\n 408, // Request Timeout\n 409, // Conflict\n 425, // Too Early\n 429, // Too Many Requests\n 500, // Internal Server Error\n 502, // Bad Gateway\n 503, // Service Unavailable\n 504, // Gateway Timeout\n ],\n },\n};\n\n/**\n * Overwrites the default configuration with the provided custom configuration.\n *\n * @param {Partial} customConfig - The custom configuration to merge into the default config.\n * @returns {Partial} - The updated default configuration object.\n */\nexport function setDefaultConfig(\n customConfig: Partial,\n): Partial {\n const sanitized = sanitizeObject(customConfig);\n\n Object.assign(defaultConfig, sanitized);\n\n return defaultConfig;\n}\n\n/**\n * Returns a shallow copy of the current default configuration.\n *\n * @returns {RequestConfig} - The current default configuration.\n */\nexport function getDefaultConfig(): RequestConfig {\n return { ...defaultConfig };\n}\n\n/**\n * Build request configuration from defaults and overrides.\n * This function merges the default configuration with the provided request configuration,\n * @param {string} url - Request url\n * @param {RequestConfig | null | undefined} reqConfig - Request configuration\n * @return {RequestConfig} - Merged request configuration\n */\nexport function buildConfig(\n url: string,\n reqConfig?: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > | null,\n): RequestConfig {\n if (!reqConfig) {\n return buildFetcherConfig(url, getDefaultConfig());\n }\n\n const sanitized = sanitizeObject(reqConfig);\n const merged = mergeConfigs(defaultConfig, sanitized);\n\n return buildFetcherConfig(url, merged);\n}\n\n/**\n * Builds the fetcher configuration by setting the method, body, headers, and URL.\n * It also handles query parameters and path parameters. This fn mutates the passed `requestConfig` object.\n * @param {string} url - The endpoint URL to which the request will be sent.\n * @param {RequestConfig} requestConfig - The request configuration object containing method, body, headers, and other options.\n * @return {RequestConfig} - The modified request configuration object with the URL, method, body, and headers set appropriately.\n **/\nexport function buildFetcherConfig(\n url: string,\n requestConfig: RequestConfig,\n): RequestConfig {\n let method = requestConfig.method as Method;\n method = method ? (method.toUpperCase() as Method) : GET;\n\n let body: RequestConfig['data'] | undefined;\n\n // Only applicable for request methods 'PUT', 'POST', 'DELETE', and 'PATCH'\n if (method !== GET && method !== HEAD) {\n body = requestConfig.body ?? requestConfig.data;\n\n // Automatically stringify request body, if possible and when not dealing with strings\n if (body && typeof body !== STRING && isJSONSerializable(body)) {\n body = JSON.stringify(body);\n }\n }\n\n setContentTypeIfNeeded(requestConfig.headers, body);\n\n // Native fetch compatible settings\n const credentials = requestConfig.withCredentials\n ? 'include'\n : requestConfig.credentials;\n\n // The explicitly passed query params\n const dynamicUrl = replaceUrlPathParams(url, requestConfig.urlPathParams);\n const urlPath = appendQueryParams(dynamicUrl, requestConfig.params);\n const isFullUrl = isAbsoluteUrl(url);\n const baseURL = isFullUrl\n ? ''\n : requestConfig.baseURL || requestConfig.apiUrl || '';\n\n requestConfig.url = baseURL + urlPath;\n requestConfig.method = method;\n requestConfig.credentials = credentials;\n requestConfig.body = body;\n\n return requestConfig;\n}\n\n/**\n * Ensures the `Content-Type` header is set to `application/json; charset=utf-8`\n * if it is not already present and the request method and body meet specific conditions.\n *\n * @param headers - The headers object to modify. Can be an instance of `Headers`\n * or a plain object conforming to `HeadersInit`.\n * @param body - The optional body of the request. If no body is provided and the\n * method is 'GET' or 'HEAD', the function exits without modifying headers.\n */\nfunction setContentTypeIfNeeded(\n headers?: HeadersInit | HeadersObject,\n body?: unknown,\n): void {\n // If no headers are provided, or if the body is not set and the method is PUT or DELETE, do nothing\n if (!headers || !body) {\n return;\n }\n\n // Types that should not have Content-Type set (browser handles these)\n if (\n body instanceof FormData || // Browser automatically sets multipart/form-data with boundary\n (typeof Blob !== UNDEFINED && body instanceof Blob) || // Blob/File already have their own MIME types, don't override\n (typeof File !== UNDEFINED && body instanceof File) ||\n (typeof ReadableStream !== UNDEFINED && body instanceof ReadableStream) // Stream type should be determined by the stream source\n ) {\n return;\n }\n\n let contentTypeValue: string;\n\n if (isSearchParams(body)) {\n contentTypeValue = APPLICATION_CONTENT_TYPE + 'x-www-form-urlencoded';\n } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {\n contentTypeValue = APPLICATION_CONTENT_TYPE + 'octet-stream';\n } else if (isJSONSerializable(body)) {\n contentTypeValue = APPLICATION_JSON + ';' + CHARSET_UTF_8;\n } else {\n // Do not set Content-Type if content is not recognizable\n return;\n }\n\n if (headers instanceof Headers) {\n if (!headers.has(CONTENT_TYPE)) {\n headers.set(CONTENT_TYPE, contentTypeValue);\n }\n } else if (\n isObject(headers) &&\n !Array.isArray(headers) &&\n !headers[CONTENT_TYPE]\n ) {\n headers[CONTENT_TYPE] = contentTypeValue;\n }\n}\n\nexport function mergeConfigs(\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n): RequestConfig {\n const mergedConfig: RequestConfig = Object.assign(\n {},\n baseConfig,\n overrideConfig,\n );\n\n // Ensure that retry and headers are merged correctly\n mergeConfig('retry', mergedConfig, baseConfig, overrideConfig);\n mergeConfig('headers', mergedConfig, baseConfig, overrideConfig);\n\n // Merge interceptors efficiently\n mergeInterceptors('onRequest', mergedConfig, baseConfig, overrideConfig);\n mergeInterceptors('onResponse', mergedConfig, baseConfig, overrideConfig);\n mergeInterceptors('onError', mergedConfig, baseConfig, overrideConfig);\n\n return mergedConfig;\n}\n\n/**\n * Efficiently merges interceptor functions from base and new configs\n */\nfunction mergeInterceptors<\n K extends 'onRequest' | 'onResponse' | 'onError' | 'onRetry',\n>(\n property: K,\n targetConfig: RequestConfig,\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n): void {\n const baseInterceptor = baseConfig[property];\n const newInterceptor = overrideConfig[property];\n\n if (!baseInterceptor && !newInterceptor) {\n return;\n }\n\n if (!baseInterceptor) {\n targetConfig[property] = newInterceptor;\n return;\n }\n\n if (!newInterceptor) {\n targetConfig[property] = baseInterceptor;\n return;\n }\n\n const baseArr = Array.isArray(baseInterceptor)\n ? baseInterceptor\n : [baseInterceptor];\n const newArr = Array.isArray(newInterceptor)\n ? newInterceptor\n : [newInterceptor];\n\n // This is the only LIFO interceptor, so we apply it after the response is prepared\n targetConfig[property] =\n property === 'onResponse' ? newArr.concat(baseArr) : baseArr.concat(newArr);\n}\n\n/**\n * Merges the specified property from the base configuration and the override configuration into the target configuration.\n *\n * @param {K} property - The property key to merge from the base and override configurations. Must be a key of RequestConfig.\n * @param {RequestConfig} targetConfig - The configuration object that will receive the merged properties.\n * @param {RequestConfig} baseConfig - The base configuration object that provides default values.\n * @param {RequestConfig} overrideConfig - The override configuration object that contains user-specific settings to merge.\n */\nexport function mergeConfig(\n property: K,\n targetConfig: RequestConfig,\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n): void {\n if (overrideConfig[property]) {\n targetConfig[property] = {\n ...baseConfig[property],\n ...overrideConfig[property],\n };\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { hash } from './hash';\nimport type {\n CacheKeyFunction,\n DefaultResponse,\n FetchResponse,\n MutationSettings,\n RequestConfig,\n} from './types/request-handler';\nimport type { CacheEntry } from './types/cache-manager';\nimport { GET, STRING, UNDEFINED } from './constants';\nimport { isObject, sanitizeObject, sortObject, timeNow } from './utils';\nimport { revalidate } from './revalidator-manager';\nimport { notifySubscribers } from './pubsub-manager';\nimport type { DefaultPayload, DefaultParams, DefaultUrlParams } from './types';\nimport { removeInFlight } from './inflight-manager';\nimport { addTimeout } from './timeout-wheel';\nimport { defaultConfig } from './config-handler';\nimport { processHeaders } from './utils';\n\nexport const IMMEDIATE_DISCARD_CACHE_TIME = 0; // Use it for cache entries that need to be persistent until unused by components or manually deleted\n\nconst _cache = new Map>();\nconst DELIMITER = '|';\nconst MIN_LENGTH_TO_HASH = 64;\nconst CACHE_KEY_SANITIZE_PATTERN = new RegExp('[^\\\\w\\\\-_|]', 'g');\n\n/**\n * Headers that may affect HTTP response content and should be included in cache key generation.\n * All header names must be lowercase to match normalized request headers.\n */\nconst CACHE_KEY_HEADER_WHITELIST = new Set([\n // Content negotiation\n 'accept', // Affects response format (e.g. JSON, HTML)\n 'accept-language', // Affects localization of the response\n 'accept-encoding', // Affects response compression (e.g. gzip, br)\n\n // Authentication\n 'authorization', // Affects access to protected resources\n\n // Request body metadata\n 'content-type', // Affects how the request body is interpreted\n\n // Optional headers\n 'referer', // May influence behavior in some APIs\n 'origin', // Relevant in CORS or tenant-specific APIs\n 'user-agent', // Included only for reason if server returns client-specific content\n\n // Cookies — only if server uses session-based responses\n 'cookie', // Can fragment cache heavily; use only if necessary\n\n // Custom headers that may affect response content\n 'x-api-key', // Token-based access, often affects authorization\n 'x-requested-with', // AJAX requests (used historically for distinguishing frontend calls)\n 'x-client-id', // Per-client/partner identity; often used in multi-tenant APIs\n 'x-tenant-id', // Multi-tenant segmentation; often changes response per tenant\n 'x-user-id', // Explicit user context (less common, but may exist)\n\n 'x-app-version', // Used for version-specific behavior (e.g. mobile apps)\n 'x-feature-flag', // Controls feature rollout behavior server-side\n 'x-device-id', // Used when response varies per device/app instance\n 'x-platform', // e.g. 'ios', 'android', 'web' — used in apps that serve different content\n\n 'x-session-id', // Only if backend uses it to affect the response directly (rare)\n 'x-locale', // Sometimes used in addition to or instead of `accept-language`\n]);\n\n/**\n * Generates a unique cache key for a given URL and fetch options, ensuring that key factors\n * like method, headers, body, and other options are included in the cache key.\n * Headers and other objects are sorted by key to ensure consistent cache keys.\n *\n * @param {RequestConfig} config - The fetch options that may affect the request. The most important are:\n * @property {string} [method=\"GET\"] - The HTTP method (GET, POST, etc.).\n * @property {HeadersInit} [headers={}] - The request headers.\n * @property {BodyInit | null} [body=\"\"] - The body of the request (only for methods like POST, PUT).\n * @property {RequestCredentials} [credentials=\"same-origin\"] - Whether to include credentials (include, same-origin, omit).\n * @property {RequestCache} [cache=\"default\"] - The cache mode (e.g., default, no-store, reload).\n * @returns {string} - A unique cache key string based on the provided options.\n *\n * @example\n * const cacheKey = generateCacheKey({\n * url: 'https://api.example.com/data',\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ name: 'Alice' }),\n * mode: 'cors',\n * credentials: 'include',\n * });\n * console.log(cacheKey);\n */\nexport function generateCacheKey(\n config: RequestConfig,\n cacheKeyCheck = true,\n): string {\n // This is super fast. Effectively a no-op if cacheKey is\n // a string or a function that returns a string.\n const key = config.cacheKey;\n\n if (key && cacheKeyCheck) {\n return typeof key === STRING\n ? (key as string)\n : (key as CacheKeyFunction)(config);\n }\n\n const {\n url = '',\n method = GET,\n headers = null,\n body = null,\n credentials = 'same-origin',\n } = config;\n\n // Sort headers and body + convert sorted to strings for hashing purposes\n // Native serializer is on avg. 3.5x faster than a Fast Hash or FNV-1a\n let headersString = '';\n if (headers) {\n let obj: Record;\n\n if (headers instanceof Headers) {\n obj = processHeaders(headers);\n } else {\n obj = headers as Record;\n }\n\n // Filter headers to only include those that affect request identity\n // Include only headers that affect request identity, not execution behavior\n const keys = Object.keys(obj);\n const len = keys.length;\n\n // Sort keys manually for fastest deterministic output\n if (len > 1) {\n keys.sort();\n }\n\n let str = '';\n for (let i = 0; i < len; ++i) {\n if (CACHE_KEY_HEADER_WHITELIST.has(keys[i].toLowerCase())) {\n str += keys[i] + ':' + obj[keys[i]] + ';';\n }\n }\n\n headersString = hash(str);\n }\n\n // For GET requests, return early with shorter cache key\n if (method === GET) {\n return (\n method +\n DELIMITER +\n url +\n DELIMITER +\n credentials +\n DELIMITER +\n headersString\n ).replace(CACHE_KEY_SANITIZE_PATTERN, '');\n }\n\n let bodyString = '';\n if (body) {\n if (typeof body === STRING) {\n bodyString = body.length < MIN_LENGTH_TO_HASH ? body : hash(body); // hash only if large\n } else if (body instanceof FormData) {\n body.forEach((value, key) => {\n // Append key=value and '&' directly to the result\n bodyString += key + '=' + value + '&';\n });\n\n if (bodyString.length > MIN_LENGTH_TO_HASH) {\n bodyString = hash(bodyString);\n }\n } else if (\n (typeof Blob !== UNDEFINED && body instanceof Blob) ||\n (typeof File !== UNDEFINED && body instanceof File)\n ) {\n bodyString = 'BF' + body.size + body.type;\n } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {\n bodyString = 'AB' + body.byteLength;\n } else {\n const o = isObject(body)\n ? JSON.stringify(sortObject(body))\n : String(body);\n\n bodyString = o.length > MIN_LENGTH_TO_HASH ? hash(o) : o;\n }\n }\n\n // Concatenate all key parts into a cache key string\n // Template literals are apparently slower\n return (\n method +\n DELIMITER +\n url +\n DELIMITER +\n credentials +\n DELIMITER +\n headersString +\n DELIMITER +\n bodyString\n ).replace(CACHE_KEY_SANITIZE_PATTERN, ''); // Prevent cache poisoning by removal of anything that isn't letters, numbers, -, _, or |\n}\n\n/**\n * Checks if the cache entry is expired based on its timestamp and the expiry time.\n *\n * @param {CacheEntry} entry - The cache entry to check.\n * @returns {boolean} - Returns true if the cache entry is expired, false otherwise.\n */\nfunction isCacheExpired(entry: CacheEntry): boolean {\n // No expiry time means the entry never expires\n if (!entry.expiry) {\n return false;\n }\n\n return timeNow() > entry.expiry;\n}\n\n/**\n * Checks if the cache entry is stale based on its timestamp and the stale time.\n *\n * @param {CacheEntry} entry - The cache entry to check.\n * @returns {boolean} - Returns true if the cache entry is stale, false otherwise.\n */\nfunction isCacheStale(entry: CacheEntry): boolean {\n if (!entry.stale) {\n return false;\n }\n\n return timeNow() > entry.stale;\n}\n\n/**\n * Retrieves a cached response from the internal cache using the provided key.\n *\n * @param key - The unique key identifying the cached entry. If null, returns null.\n * @returns The cached {@link FetchResponse} if found, otherwise null.\n */\nexport function getCacheData<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n key: string | null,\n): FetchResponse | null {\n if (!key) {\n return null;\n }\n\n const entry = _cache.get(key);\n\n return entry ? entry.data : null;\n}\n\n/**\n * Retrieves a cache entry if it exists and is not expired.\n *\n * @param {string} key Cache key to utilize\n * @returns {CacheEntry | null} - The cache entry if it exists and is not expired, null otherwise.\n */\nexport function getCache(\n key: string | null,\n):\n | CacheEntry<\n FetchResponse\n >\n | null\n | undefined {\n return _cache.get(key as string);\n}\n\n/**\n * Sets a new cache entry or updates an existing one, with optional TTL (time-to-live).\n *\n * @param {string} key Cache key to utilize\n * @param {T} data - The data to be cached.\n * @param {number} [ttl] - Optional TTL in seconds. If not provided, the cache entry will not expire.\n * @param {number} [staleTime] - Optional stale time in seconds. If provided, the cache entry will be considered stale after this time.\n */\nexport function setCache(\n key: string,\n data: T,\n ttl?: number,\n staleTime?: number,\n): void {\n if (ttl === 0) {\n deleteCache(key);\n return;\n }\n\n const time = timeNow();\n const ttlMs = ttl ? ttl * 1000 : 0;\n\n _cache.set(key, {\n data,\n time,\n stale: staleTime && staleTime > 0 ? time + staleTime * 1000 : staleTime,\n expiry: ttl === -1 ? undefined : time + ttlMs,\n });\n\n if (ttlMs > 0) {\n addTimeout(\n 'c:' + key,\n () => {\n deleteCache(key, true);\n },\n ttlMs,\n );\n }\n}\n\n/**\n * Invalidates (deletes) a cache entry.\n *\n * @param {string} key Cache key to utilize\n * @param {boolean} [removeExpired=false] - If true, only deletes the cache entry if it is expired or stale.\n */\nexport function deleteCache(key: string, removeExpired: boolean = false): void {\n if (removeExpired) {\n const entry = getCache(key);\n\n // If the entry does not exist, or it is neither expired nor stale, do not delete\n if (!entry || !isCacheExpired(entry)) {\n return;\n }\n }\n\n _cache.delete(key);\n}\n\n/**\n * Prunes the cache by removing entries that have expired based on the provided cache time.\n */\nexport function pruneCache(): void {\n _cache.clear();\n}\n\n/**\n * Mutates a cache entry with new data and optionally revalidates it.\n *\n * @param {string | null} key Cache key to utilize. If null, no mutation occurs.\n * @param {ResponseData} newData - The new data to be cached.\n * @param {MutationSettings|undefined} settings - Mutation settings.\n */\nexport async function mutate<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n key: string | null,\n newData: ResponseData,\n settings?: MutationSettings,\n): Promise | null> {\n // If no key is provided, do nothing\n if (!key) {\n return null;\n }\n\n const entry = getCache(\n key,\n );\n\n if (!entry) {\n return null;\n }\n\n const updatedData = isObject(newData) ? sanitizeObject(newData) : newData;\n\n const updatedResponse = {\n ...entry.data,\n data: updatedData,\n };\n\n const updatedEntry = {\n ...entry,\n data: updatedResponse,\n };\n\n _cache.set(key, updatedEntry);\n notifySubscribers(key, updatedResponse);\n\n if (settings && settings.refetch) {\n return await revalidate(key);\n }\n\n return null;\n}\n\n/**\n * Retrieves a cached response if available and valid, otherwise returns null.\n *\n * @template ResponseData - The type of the response data.\n * @template RequestBody - The type of the request body.\n * @template QueryParams - The type of the query parameters.\n * @template PathParams - The type of the path parameters.\n * @param {string | null} cacheKey - The cache key to look up.\n * @param {number | undefined} cacheTime - The maximum time to cache entry.\n * @param {RequestConfig} requestConfig - The fetcher configuration.\n * @returns {FetchResponse | null} - The cached response or null.\n */\nexport function getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n cacheKey: string | null,\n cacheTime: number | undefined,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): FetchResponse | null {\n // If cache key or time is not provided, return null\n if (!cacheKey || cacheTime === undefined || cacheTime === null) {\n return null;\n }\n\n // Check if cache should be bypassed\n const buster = requestConfig.cacheBuster || defaultConfig.cacheBuster;\n if (buster && buster(requestConfig)) {\n return null;\n }\n\n if (requestConfig.cache && requestConfig.cache === 'reload') {\n return null; // Skip cache lookup entirely\n }\n\n // Retrieve the cached entry\n const entry = getCache(\n cacheKey,\n );\n\n if (!entry) {\n return null;\n }\n\n const isExpired = isCacheExpired(entry);\n const isStale = isCacheStale(entry);\n\n // If completely expired, delete and return null\n if (isExpired) {\n deleteCache(cacheKey);\n return null;\n }\n\n // If fresh (not stale), return immediately\n if (!isStale) {\n return entry.data;\n }\n\n // SWR: Data is stale but not expired\n if (isStale && !isExpired) {\n // Triggering background revalidation here could cause race conditions\n // So we return stale data immediately and leave it up to implementers to handle revalidation\n return entry.data;\n }\n\n return null;\n}\n\n/**\n * Sets or deletes the response cache based on cache settings and notifies subscribers.\n *\n * @param {FetchResponse} output - The response to cache.\n * @param {RequestConfig} requestConfig - The request configuration.\n * @param {boolean} [isError=false] - Whether the response is an error.\n */\nexport function handleResponseCache<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n output: FetchResponse,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n isError: boolean = false,\n): void {\n // It is string as it is called once request is made\n const cacheKey = requestConfig.cacheKey as string;\n\n if (cacheKey) {\n const cacheTime = requestConfig.cacheTime;\n const skipCache = requestConfig.skipCache;\n\n // Fast path: only set cache if cacheTime is positive and not skipping cache\n if (\n cacheTime &&\n (!isError || requestConfig.cacheErrors) &&\n !(skipCache && skipCache(output, requestConfig))\n ) {\n setCache(cacheKey, output, cacheTime, requestConfig.staleTime);\n }\n\n notifySubscribers(cacheKey, output);\n removeInFlight(cacheKey);\n\n const prevCacheKey = requestConfig._prevKey;\n\n if (prevCacheKey) {\n removeInFlight(prevCacheKey);\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { mutate } from './cache-manager';\nimport {\n APPLICATION_CONTENT_TYPE,\n APPLICATION_JSON,\n CONTENT_TYPE,\n FUNCTION,\n OBJECT,\n STRING,\n} from './constants';\nimport {\n DefaultResponse,\n FetchResponse,\n RequestConfig,\n ResponseError,\n DefaultParams,\n DefaultUrlParams,\n DefaultPayload,\n} from './types';\nimport { flattenData, isObject, processHeaders } from './utils';\n\n/**\n * Parses the response data based on the Content-Type header.\n *\n * @param response - The Response object to parse.\n * @returns A Promise that resolves to the parsed data.\n */\nexport async function parseResponseData<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n response: FetchResponse,\n): Promise {\n // Bail early if response is null or undefined\n if (!response) {\n return null;\n }\n\n // Get the content-type header once\n let contentType = (response as Response).headers?.get(CONTENT_TYPE);\n\n if (contentType) {\n // Lowercase and trim for consistent matching\n contentType = contentType.toLowerCase().trim();\n } else {\n contentType = '';\n }\n\n // Split for mime type without charset\n const mimeType = contentType.split(';', 1)[0];\n\n let data;\n\n try {\n if (mimeType.includes(APPLICATION_JSON) || mimeType.includes('+json')) {\n data = await response.json(); // Parse JSON response\n } else if (\n (mimeType.includes('multipart/form-data') || // Parse as FormData\n mimeType.includes(\n APPLICATION_CONTENT_TYPE + 'x-www-form-urlencoded', // Handle URL-encoded forms\n )) &&\n typeof response.formData === FUNCTION\n ) {\n data = await response.formData();\n } else if (\n mimeType.includes(APPLICATION_CONTENT_TYPE + 'octet-stream') &&\n typeof response.blob === FUNCTION\n ) {\n data = await response.blob(); // Parse as blob\n } else {\n data = await response.text();\n\n if (typeof data === STRING) {\n const trimmed = data.trim();\n if (\n (trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))\n ) {\n try {\n data = JSON.parse(trimmed);\n } catch {\n // leave as text if parsing fails\n }\n }\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (_error) {\n // Parsing failed, fallback to null\n data = null;\n }\n\n return data;\n}\n\n/**\n * Prepare response object with additional information.\n *\n * @param Response. It may be \"null\" in case of request being aborted.\n * @param {RequestConfig} config - Request config\n * @param error - whether the response is erroneous\n * @returns {FetchResponse} Response data\n */\nexport const prepareResponse = <\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n config: RequestConfig,\n error: ResponseError<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null = null,\n): FetchResponse => {\n const defaultResponse = config.defaultResponse;\n const cacheKey = config.cacheKey;\n const mutatator = mutate.bind(null, cacheKey as string) as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >['mutate'];\n\n // This may happen when request is cancelled.\n if (!response) {\n return {\n ok: false,\n // Enhance the response with extra information\n error,\n data: defaultResponse ?? null,\n headers: null,\n config,\n mutate: mutatator,\n isFetching: false,\n isSuccess: false,\n isError: true,\n } as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }\n\n const isNativeResponse =\n typeof Response === FUNCTION && response instanceof Response;\n\n let data = response.data;\n\n // Set the default response if the provided data is an empty object\n if (\n defaultResponse !== undefined &&\n (data === undefined ||\n data === null ||\n (typeof data === OBJECT && Object.keys(data).length === 0))\n ) {\n response.data = data = defaultResponse;\n }\n\n if (config.flattenResponse) {\n response.data = data = flattenData(data);\n }\n\n if (config.select) {\n response.data = data = config.select(data);\n }\n\n const headers = processHeaders(response.headers);\n\n // Native fetch Response extended by extra information\n if (isNativeResponse) {\n return {\n body: response.body,\n bodyUsed: response.bodyUsed,\n ok: response.ok,\n redirected: response.redirected,\n type: response.type,\n url: response.url,\n status: response.status,\n statusText: response.statusText,\n\n // Convert methods to use arrow functions to preserve correct return types\n blob: () => response.blob(),\n json: () => response.json(),\n text: () => response.text(),\n clone: () => response.clone(),\n arrayBuffer: () => response.arrayBuffer(),\n formData: () => response.formData(),\n bytes: () => response.bytes(),\n\n // Enhance the response with extra information\n error,\n data,\n headers,\n config,\n mutate: mutatator,\n isFetching: false,\n isSuccess: response.ok && !error,\n isError: !!error,\n };\n }\n\n // If it's a custom fetcher, and it does not return any Response instance, it may have its own internal handler\n if (isObject(response)) {\n response.error = error;\n response.headers = headers;\n response.isFetching = false;\n response.mutate = mutatator;\n response.isSuccess = response.ok && !error;\n response.isError = !!error;\n }\n\n return response;\n};\n","import { applyInterceptors } from './interceptor-manager';\nimport type { FetchResponse, RetryConfig, RetryFunction } from './types';\nimport { delayInvocation, timeNow } from './utils';\nimport { generateCacheKey } from './cache-manager';\n\nfunction getMsFromHttpDate(dateString: string): number | null {\n const ms = Date.parse(dateString) - timeNow();\n\n if (!isNaN(ms)) {\n return Math.max(0, Math.floor(ms));\n }\n return null;\n}\n\n/**\n * Calculates the number of milliseconds to wait before retrying a request,\n * based on the `Retry-After` HTTP header in the provided response.\n *\n * The function supports both numeric (seconds) and HTTP-date formats for the `Retry-After` header.\n * - If the header is a number, it is interpreted as seconds and converted to milliseconds.\n * - If the header is a date, the function calculates the difference between the date and the current time.\n *\n * @param extendedResponse - The response object containing headers, or `null`.\n * @returns The number of milliseconds to wait before retrying, or `null` if the header is not present or invalid.\n */\nexport function getRetryAfterMs(\n extendedResponse: FetchResponse | null,\n): number | null {\n if (!extendedResponse) {\n return null;\n }\n\n const headers = extendedResponse.headers || {};\n const retryAfter = headers['retry-after'];\n\n if (retryAfter) {\n // Try parsing as seconds\n const seconds = Number(retryAfter);\n\n if (!isNaN(seconds) && seconds >= 0) {\n return seconds * 1000;\n }\n\n const ms = getMsFromHttpDate(retryAfter);\n\n if (ms !== null) {\n return ms;\n }\n }\n\n // Headers are already in lowercase\n const RATELIMIT_RESET = 'ratelimit-reset';\n\n // Unix timestamp when the rate limit window resets (relative to current time)\n // Fallback to checking 'ratelimit-reset-after' OR 'x-ratelimit-reset-after' headers\n const rateLimitResetAfter =\n headers[RATELIMIT_RESET + '-after'] ||\n headers['x-' + RATELIMIT_RESET + '-after'];\n\n if (rateLimitResetAfter) {\n const seconds = Number(rateLimitResetAfter);\n\n if (!isNaN(seconds)) {\n return seconds * 1000;\n }\n }\n\n // ISO 8601 datetime when the rate limit resets\n // Fallback to checking 'ratelimit-reset-at' 'x-ratelimit-reset-at' headers\n const rateLimitResetAt =\n headers[RATELIMIT_RESET + '-at'] || headers['x-' + RATELIMIT_RESET + '-at'];\n\n if (rateLimitResetAt) {\n return getMsFromHttpDate(rateLimitResetAt);\n }\n\n return null;\n}\n\n/**\n * Executes a request function with retry logic according to the provided configuration.\n *\n * The function attempts the request up to the specified number of retries, applying delay and backoff strategies.\n * Retries can be triggered based on response status codes, custom logic, or the presence of a `Retry-After` header.\n * Optionally, an `onRetry` interceptor can be invoked before each retry attempt.\n *\n * @typeParam ResponseData - The type of the response data.\n * @typeParam RequestBody - The type of the request body.\n * @typeParam QueryParams - The type of the query parameters.\n * @typeParam PathParams - The type of the path parameters.\n * @param requestFn - The function that performs the request. Receives `isStaleRevalidation` and `attempt` as arguments.\n * @param config - The retry configuration, including retry count, delay, backoff, retry conditions, and hooks.\n * @returns A promise resolving to the fetch response, or rejecting if all retries are exhausted.\n * @throws Error if the maximum number of retries is exceeded or a non-retriable error occurs.\n */\nexport async function withRetry<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n requestFn: (\n isStaleRevalidation: boolean,\n attempt: number,\n ) => Promise<\n FetchResponse\n >,\n config: RetryConfig,\n): Promise> {\n const {\n retries = 0,\n delay = 0,\n backoff = 1,\n maxDelay,\n retryOn = [],\n shouldRetry,\n } = config;\n\n let attempt = 0;\n let waitTime = delay;\n const maxRetries = retries > 0 ? retries : 0;\n let output: FetchResponse;\n\n while (attempt <= maxRetries) {\n // Subsequent attempts will have output defined, but the first attempt may not.\n // Let's apply onRetry interceptor and regenerate cache key if ot really changes.\n if (attempt > 0 && output!) {\n const cfg = output.config;\n const onRetry = cfg.onRetry;\n\n if (onRetry) {\n await applyInterceptors(onRetry, output, attempt);\n\n // If the key was automatically generated, we need to regenerate it as config may change.\n // We don't detect whether config changed for performance reasons.\n if (cfg._isAutoKey) {\n cfg._prevKey = cfg.cacheKey as string;\n cfg.cacheKey = generateCacheKey(cfg, false);\n }\n }\n }\n\n // Performance optimization: Call the request function with the current attempt number\n // If this is the first attempt, we pass `isStaleRevalidation` as `false`,\n // otherwise we pass `true` to indicate that this is a stale revalidation (no cache hit).\n output = await requestFn(attempt > 0, attempt);\n const error = output.error;\n\n // Check if we should retry based on successful response\n if (!error) {\n if (shouldRetry && attempt < maxRetries) {\n const shouldRetryResult = await shouldRetry(output, attempt);\n\n if (shouldRetryResult) {\n await delayInvocation(waitTime);\n waitTime *= backoff || 1;\n waitTime = Math.min(waitTime, maxDelay || waitTime);\n attempt++;\n continue;\n }\n }\n\n break;\n }\n\n // Determine if we should stop retrying\n const shouldStopRetrying = await getShouldStopRetrying(\n output,\n attempt,\n maxRetries,\n shouldRetry,\n retryOn,\n );\n\n if (shouldStopRetrying) {\n break;\n }\n\n // If we should not stop retrying, continue to the next attempt\n // Handle rate limiting if the error status is 429 (Too Many Requests) or 503 (Service Unavailable)\n if (error.status === 429 || error.status === 503) {\n // Try to extract the \"Retry-After\" value from the response headers\n const retryAfterMs = getRetryAfterMs(output);\n\n // If a valid retry-after value is found, override the wait time before next retry\n if (retryAfterMs !== null) {\n waitTime = retryAfterMs;\n }\n }\n\n await delayInvocation(waitTime);\n waitTime *= backoff || 1;\n waitTime = Math.min(waitTime, maxDelay || waitTime);\n attempt++;\n }\n\n return output!;\n}\n\n/**\n * Determines whether to stop retrying based on the error, current attempt count, and retry configuration.\n *\n * This function checks:\n * - If the maximum number of retries has been reached.\n * - If a custom `shouldRetry` callback is provided, its result is used to decide.\n * - If no custom logic is provided, falls back to checking if the error status is included in the `retryOn` list.\n *\n * @typeParam ResponseData - The type of the response data.\n * @typeParam RequestBody - The type of the request body.\n * @typeParam QueryParams - The type of the query parameters.\n * @typeParam PathParams - The type of the path parameters.\n * @param output - The response object containing the error and request configuration.\n * @param attempt - The current retry attempt number.\n * @param maxRetries - The maximum number of retry attempts allowed.\n * @param shouldRetry - Optional custom function to determine if a retry should occur.\n * @param retryOn - Optional list of HTTP status codes that should trigger a retry.\n * @returns A promise resolving to `true` if retrying should stop, or `false` to continue retrying.\n */\nexport async function getShouldStopRetrying<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n output: FetchResponse,\n attempt: number,\n maxRetries: number,\n shouldRetry?: RetryFunction<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n retryOn: number[] = [],\n): Promise {\n // Safety first: always respect max retries\n // We check retries provided regardless of the shouldRetry being provided so to avoid infinite loops.\n // It is a fail-safe so to prevent excessive retry attempts even if custom retry logic suggests a retry.\n if (attempt === maxRetries) {\n return true;\n }\n\n let customDecision: boolean | null = null;\n\n // Get custom decision if shouldRetry is provided\n if (shouldRetry) {\n const result = await shouldRetry(output, attempt);\n customDecision = result;\n\n // Decision cascade:\n if (customDecision !== null) {\n return !customDecision;\n }\n }\n\n return !(retryOn || []).includes(output.error?.status ?? 0);\n}\n","import type { RequestConfig, FetchResponse } from './types';\nimport { delayInvocation } from './utils';\n\n/**\n * Executes a request function with polling, stopping when shouldStopPolling returns true,\n * pollingInterval is not set, or maxAttempts is reached.\n *\n * @template Output The type of the output returned by the request function.\n * @param requestFn - The function that performs a single request (with retries).\n * @param pollingInterval - Interval in ms between polling attempts.\n * @param shouldStopPolling - Function to determine if polling should stop.\n * @param maxAttempts - Maximum number of polling attempts, default: 0 (unlimited).\n * @param pollingDelay - Delay in ms before each polling attempt, default: 0.\n * @returns The final output from the last request.\n */\nexport async function withPolling<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n requestFn: (\n isStaleRevalidation?: boolean,\n attempt?: number,\n ) => Promise<\n FetchResponse\n >,\n pollingInterval?: RequestConfig['pollingInterval'],\n shouldStopPolling?: RequestConfig['shouldStopPolling'],\n maxAttempts = 0,\n pollingDelay = 0,\n): Promise> {\n if (!pollingInterval) {\n return requestFn();\n }\n\n let pollingAttempt = 0;\n let output: FetchResponse;\n\n while (maxAttempts === 0 || pollingAttempt < maxAttempts) {\n if (pollingDelay > 0) {\n await delayInvocation(pollingDelay);\n }\n\n output = await requestFn();\n\n pollingAttempt++;\n\n if (\n (maxAttempts > 0 && pollingAttempt >= maxAttempts) ||\n !pollingInterval ||\n (shouldStopPolling && shouldStopPolling(output, pollingAttempt))\n ) {\n break;\n }\n\n await delayInvocation(pollingInterval);\n }\n\n return output!;\n}\n","import type { ResponseError } from './errors/response-error';\nimport type {\n DefaultResponse,\n FetchResponse,\n RequestConfig,\n} from './types/request-handler';\nimport { applyInterceptors } from './interceptor-manager';\nimport { handleResponseCache } from './cache-manager';\nimport { ABORT_ERROR, REJECT } from './constants';\nimport { DefaultParams, DefaultUrlParams, DefaultPayload } from './types';\n\n/**\n * Handles final processing for both success and error responses\n * Applies error interceptors, caching, notifications, and error strategy\n */\nexport async function withErrorHandling<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n isStaleRevalidation: boolean,\n requestFn: (\n isStaleRevalidation: boolean,\n ) => Promise<\n FetchResponse\n >,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): Promise> {\n const output = await requestFn(isStaleRevalidation);\n const error = output.error;\n\n if (!error) {\n // SUCCESS PATH\n handleResponseCache(output, requestConfig);\n\n return output;\n }\n\n // ERROR PATH\n\n if (requestConfig.onError) {\n await applyInterceptors(requestConfig.onError, error);\n }\n\n // Timeouts and request cancellations using AbortController do not throw any errors unless rejectCancelled is true.\n // Only handle the error if the request was not cancelled, or if it was cancelled and rejectCancelled is true.\n const isCancelled = error.isCancelled;\n\n if (!isCancelled && requestConfig.logger) {\n logger(requestConfig, 'FETCH ERROR', error as ResponseError);\n }\n\n // Handle cache and notifications FIRST (before strategy)\n handleResponseCache(output, requestConfig, true);\n\n // handle error strategy as the last part\n const shouldHandleError = !isCancelled || requestConfig.rejectCancelled;\n\n if (shouldHandleError) {\n const strategy = requestConfig.strategy;\n // Reject the promise\n if (strategy === REJECT) {\n return Promise.reject(error);\n }\n\n // Hang the promise\n if (strategy === 'silent') {\n await new Promise(() => null);\n }\n }\n\n return output;\n}\n\nexport function enhanceError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n error: any,\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): void {\n error.status = error.status || response?.status || 0;\n error.statusText = error.statusText || response?.statusText || '';\n error.config = error.request = requestConfig;\n error.response = response;\n error.isCancelled = error.name === ABORT_ERROR;\n}\n\n/**\n * Logs messages or errors using the configured logger's `warn` method.\n *\n * @param {RequestConfig} reqConfig - Request config passed when making the request\n * @param {...(string | ResponseError)} args - Messages or errors to log.\n */\nfunction logger(\n reqConfig: RequestConfig,\n ...args: (string | ResponseError)[]\n): void {\n const logger = reqConfig.logger;\n\n if (logger && logger.warn) {\n logger.warn(...args);\n }\n}\n","import type {\n DefaultResponse,\n RequestConfig,\n FetchResponse,\n} from './types/request-handler';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultUrlParams,\n} from './types/api-handler';\nimport { applyInterceptors } from './interceptor-manager';\nimport { ResponseError } from './errors/response-error';\nimport { isObject } from './utils';\nimport {\n markInFlight,\n setInFlightPromise,\n getInFlightPromise,\n} from './inflight-manager';\nimport { parseResponseData, prepareResponse } from './response-parser';\nimport { generateCacheKey, getCachedResponse, setCache } from './cache-manager';\nimport { withRetry } from './retry-handler';\nimport { withPolling } from './polling-handler';\nimport { notifySubscribers } from './pubsub-manager';\nimport { addRevalidator } from './revalidator-manager';\nimport { enhanceError, withErrorHandling } from './error-handler';\nimport { FUNCTION } from './constants';\nimport { buildConfig } from './config-handler';\n\nconst inFlightResponse = {\n isFetching: true,\n};\n\n/**\n * Sends an HTTP request to the specified URL using the provided configuration and returns a typed response.\n *\n * @typeParam ResponseData - The expected shape of the response data. Defaults to `DefaultResponse`.\n * @typeParam RequestBody - The type of the request payload/body. Defaults to `DefaultPayload`.\n * @typeParam QueryParams - The type of the query parameters. Defaults to `DefaultParams`.\n * @typeParam PathParams - The type of the path parameters. Defaults to `DefaultUrlParams`.\n *\n * @param url - The endpoint URL to which the request will be sent.\n * @param config - Optional configuration object for the request, including headers, method, body, query, and path parameters.\n *\n * @returns A promise that resolves to a `FetchResponse` containing the typed response data and request metadata.\n *\n * @example\n * ```typescript\n * const { data } = await fetchf('/api/user', { method: 'GET' });\n * console.log(data);\n * ```\n */\nexport async function fetchf<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n url: string,\n reqConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > | null = null,\n): Promise> {\n const fetcherConfig = buildConfig<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(url, reqConfig);\n\n const {\n timeout,\n cancellable,\n cacheKey,\n dedupeTime,\n cacheTime,\n staleTime,\n refetchOnFocus,\n refetchOnReconnect,\n pollingInterval = 0,\n } = fetcherConfig;\n const isCacheEnabled = cacheTime !== undefined || staleTime !== undefined;\n\n const needsCacheKey = !!(\n cacheKey ||\n timeout ||\n dedupeTime ||\n isCacheEnabled ||\n cancellable ||\n refetchOnFocus ||\n refetchOnReconnect\n );\n\n let _cacheKey: string | null = null;\n\n // Generate cache key if required\n if (needsCacheKey) {\n _cacheKey = generateCacheKey(fetcherConfig);\n }\n\n // Cache handling logic\n if (_cacheKey && isCacheEnabled) {\n const cached = getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(_cacheKey, cacheTime, fetcherConfig);\n\n if (cached) {\n return cached;\n }\n }\n\n // Deduplication logic\n if (_cacheKey && dedupeTime) {\n const inflight = getInFlightPromise<\n FetchResponse\n >(_cacheKey, dedupeTime);\n\n if (inflight) {\n return inflight;\n }\n }\n\n const retryConfig = fetcherConfig.retry || {};\n const { retries = 0, resetTimeout } = retryConfig;\n\n // The actual request logic as a function (one poll attempt, with retries)\n const doRequestOnce = async (isStaleRevalidation = false, attempt = 0) => {\n // If cache key is specified, we will handle optimistic updates\n // and mark the request as in-flight, so to catch \"fetching\" state.\n // This is useful for Optimistic UI updates (e.g., showing loading spinners).\n if (!attempt) {\n if (_cacheKey && !isStaleRevalidation) {\n if (staleTime) {\n const existingCache = getCachedResponse(\n _cacheKey,\n cacheTime,\n fetcherConfig,\n );\n\n // Don't notify subscribers when cache exists\n // Let them continue showing stale data during background revalidation\n if (!existingCache) {\n setCache(_cacheKey, inFlightResponse, cacheTime, staleTime);\n notifySubscribers(_cacheKey, inFlightResponse);\n }\n } else {\n notifySubscribers(_cacheKey, inFlightResponse);\n }\n }\n\n // Attach cache key so that it can be reused in interceptors or in the final response\n fetcherConfig.cacheKey = _cacheKey;\n }\n\n const url = fetcherConfig.url as string;\n\n // Add the request to the queue. Make sure to handle deduplication, cancellation, timeouts in accordance to retry settings\n const controller = markInFlight(\n _cacheKey,\n url,\n timeout,\n dedupeTime || 0,\n !!cancellable,\n // Enable timeout either by default or when retries & resetTimeout are enabled\n !!(timeout && (!attempt || resetTimeout)),\n );\n\n // Do not create a shallow copy to maintain idempotency here.\n // This ensures the original object is mutated by interceptors whenever needed, including retry logic.\n const requestConfig = fetcherConfig;\n\n requestConfig.signal = controller.signal;\n\n let output: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n let response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null = null;\n\n try {\n if (fetcherConfig.onRequest) {\n await applyInterceptors(fetcherConfig.onRequest, requestConfig);\n }\n\n // Custom fetcher\n const fn = fetcherConfig.fetcher;\n\n response = (fn\n ? await fn(\n url,\n requestConfig,\n )\n : await fetch(\n url,\n requestConfig as RequestInit,\n )) as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n\n // Custom fetcher may return a raw data object instead of a Response instance\n if (isObject(response)) {\n // Case 1: Native Response instance\n if (typeof Response === FUNCTION && response instanceof Response) {\n response.data = await parseResponseData(response);\n } else if (fn) {\n // Case 2: Custom fetcher that returns a response object\n if (!('data' in response && 'body' in response)) {\n // Case 3: Raw data, wrap it\n response = { data: response } as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }\n }\n\n // Attach config and data to the response\n // This is useful for custom fetchers that do not return a Response instance\n // and for interceptors that may need to access the request config\n response.config = requestConfig;\n\n // Check if the response status is not outside the range 200-299 and if so, output error\n // This is the pattern for fetch responses as per spec, but custom fetchers may not follow it so we check for `ok` property\n if (response.ok !== undefined && !response.ok) {\n throw new ResponseError(\n `${requestConfig.method} to ${url} failed! Status: ${response.status || null}`,\n requestConfig,\n response,\n );\n }\n }\n\n output = prepareResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(response, requestConfig);\n\n const onResponse = fetcherConfig.onResponse;\n\n if (onResponse) {\n await applyInterceptors(onResponse, output);\n }\n } catch (_error) {\n const error = _error as ResponseError<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n\n // Append additional information to Network, CORS or any other fetch() errors\n enhanceError(\n error,\n response,\n requestConfig,\n );\n\n // Prepare Extended Response\n output = prepareResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(response, requestConfig, error);\n }\n\n return output;\n };\n\n // Inline and minimize function wrappers for performance\n const baseRequest =\n retries > 0 ? () => withRetry(doRequestOnce, retryConfig) : doRequestOnce;\n\n const requestWithErrorHandling = (isStaleRevalidation = false) =>\n withErrorHandling(\n isStaleRevalidation,\n baseRequest,\n fetcherConfig,\n );\n\n // Avoid unnecessary function wrapping if polling is not enabled\n const doRequestPromise = pollingInterval\n ? withPolling(\n requestWithErrorHandling,\n pollingInterval,\n fetcherConfig.shouldStopPolling,\n fetcherConfig.maxPollingAttempts,\n fetcherConfig.pollingDelay,\n )\n : requestWithErrorHandling();\n\n // If deduplication is enabled, store the in-flight promise immediately\n if (_cacheKey) {\n if (dedupeTime) {\n setInFlightPromise(_cacheKey, doRequestPromise);\n }\n\n addRevalidator(\n _cacheKey,\n requestWithErrorHandling,\n undefined,\n staleTime,\n requestWithErrorHandling,\n !!refetchOnFocus,\n !!refetchOnReconnect,\n );\n }\n\n return doRequestPromise;\n}\n","import type {\n ApiHandlerConfig,\n ApiHandlerDefaultMethods,\n ApiHandlerMethods,\n RequestConfigUrlRequired,\n} from './types/api-handler';\nimport { fetchf } from '.';\nimport { mergeConfigs } from './config-handler';\nimport { isAbsoluteUrl } from './utils';\n\n/**\n * Creates an instance of API Handler.\n * It creates an API fetcher function using native fetch() or a custom fetcher if passed as \"fetcher\".\n * @see https://github.com/MattCCC/fetchff#configuration\n *\n * @param {Object} config - Configuration object for the API fetcher (see link above for full options).\n * @param {Object} config.endpoints - An object containing endpoint definitions.\n * @param {string} [config.baseURL] - The base URL for the API.\n * @param {Object} [config.headers] - Optional default headers to include in every request.\n * @param {Function} [config.onError] - Optional callback function for handling errors.\n * @returns API handler functions and endpoints to call\n *\n * @example\n * // Define endpoint paths\n * const endpoints = {\n * getUser: '/user',\n * createPost: '/post',\n * };\n *\n * // Create the API fetcher with configuration\n * const api = createApiFetcher({\n * endpoints,\n * apiUrl: 'https://example.com/api',\n * onError(error) {\n * console.log('Request failed', error);\n * },\n * headers: {\n * 'my-auth-key': 'example-auth-key-32rjjfa',\n * },\n * });\n *\n * // Fetch user data\n * const response = await api.getUser({ userId: 1, ratings: [1, 2] })\n */\nfunction createApiFetcher<\n EndpointTypes extends object,\n EndpointsSettings = never,\n>(config: ApiHandlerConfig) {\n const endpoints = config.endpoints;\n\n /**\n * Triggered when trying to use non-existent endpoints\n *\n * @param endpointName Endpoint Name\n * @returns {Promise}\n */\n function handleNonImplemented(endpointName: string): Promise {\n console.error(`Add ${endpointName} to 'endpoints'.`);\n\n return Promise.resolve(null);\n }\n\n const apiHandler: ApiHandlerDefaultMethods = {\n config,\n endpoints,\n /**\n * Handle Single API Request\n * It considers settings in following order: per-request settings, global per-endpoint settings, global settings.\n *\n * @param endpointName - The name of the API endpoint to call.\n * @param requestConfig - Additional configuration for the request.\n * @returns A promise that resolves with the response from the API provider.\n */\n async request(endpointName, requestConfig = {}) {\n // Use global and per-endpoint settings\n const endpointConfig = endpoints[endpointName];\n const _endpointConfig =\n endpointConfig ||\n ({ url: String(endpointName) } as RequestConfigUrlRequired);\n const url = _endpointConfig.url;\n\n // Block Protocol-relative URLs as they could lead to SSRF (Server-Side Request Forgery)\n if (url.startsWith('//')) {\n throw new Error('Protocol-relative URLs are not allowed.');\n }\n\n // Prevent potential Server-Side Request Forgery attack and leakage of credentials when same instance is used for external requests\n const mergedConfig = isAbsoluteUrl(url)\n ? // Merge endpoints configs for absolute URLs only if urls match\n endpointConfig?.url === url\n ? mergeConfigs(_endpointConfig, requestConfig)\n : requestConfig\n : mergeConfigs(mergeConfigs(config, _endpointConfig), requestConfig);\n\n // We prevent potential Server-Side Request Forgery attack and leakage of credentials as the same instance is not used for external requests\n // Retrigger fetch to ensure completely new instance of handler being triggered for external URLs\n return fetchf(url, mergedConfig);\n },\n };\n\n /**\n * Maps all API requests using native Proxy\n *\n * @param {*} prop Caller\n */\n return new Proxy>(\n apiHandler as ApiHandlerMethods,\n {\n get(_target, prop: string) {\n if (prop in apiHandler) {\n return apiHandler[prop as unknown as keyof typeof apiHandler];\n }\n\n // Prevent handler from triggering non-existent endpoints\n if (endpoints[prop]) {\n return apiHandler.request.bind(null, prop);\n }\n\n return handleNonImplemented.bind(null, prop);\n },\n },\n );\n}\n\nexport { createApiFetcher };\n"]} \ No newline at end of file +{"version":3,"sources":["../../src/constants.ts","../../src/utils.ts","../../src/interceptor-manager.ts","../../src/errors/fetch-error.ts","../../src/errors/response-error.ts","../../src/timeout-wheel.ts","../../src/inflight-manager.ts","../../src/hash.ts","../../src/revalidator-manager.ts","../../src/pubsub-manager.ts","../../src/config-handler.ts","../../src/cache-manager.ts","../../src/response-parser.ts","../../src/retry-handler.ts","../../src/polling-handler.ts","../../src/error-handler.ts","../../src/request-handler.ts","../../src/api-handler.ts"],"names":["APPLICATION_CONTENT_TYPE","APPLICATION_JSON","CHARSET_UTF_8","CONTENT_TYPE","UNDEFINED","OBJECT","STRING","FUNCTION","ABORT_ERROR","TIMEOUT_ERROR","GET","HEAD","REJECT","MAX_DEPTH","isSearchParams","data","isObject","value","sanitizeObject","obj","hasProto","hasCtor","hasPrototype","safeObj","sortObject","keys","sortedObj","i","len","key","appendQueryStringToUrl","baseUrl","queryString","appendQueryParams","url","params","encodedQueryString","s","encode","add","k","v","buildParams","prefix","depth","replaceUrlPathParams","urlPathParams","match","isAbsoluteUrl","timeNow","noop","isJSONSerializable","delayInvocation","ms","resolve","flattenData","processHeaders","headers","headersObject","isBrowser","createAbortError","message","name","error","isSlowConnection","conn","applyInterceptors","interceptors","args","interceptor","FetchError","request","response","__publicField","ResponseError","WHEEL_SIZE","SECOND","MAX_WHEEL_MS","wheel","keyMap","position","timer","handleCallback","callback","result","e","addTimeout","cb","removeTimeout","seconds","slot","slotOrTimeout","slotArr","idx","inFlight","markInFlight","timeout","dedupeTime","isCancellable","isTimeoutEnabled","now","item","prevPromise","prevController","prevIsCancellable","controller","abortRequest","removeInFlight","setInFlightPromise","promise","getInFlightPromise","prevReq","hash","str","char","DEFAULT_TTL","revalidators","eventHandlers","customEventProviders","setEventProvider","type","provider","removeEventHandler","addEventHandler","revalidateAll","isStaleRevalidation","flagIndex","entry","revalidator","revalidate","removeRevalidators","removeRevalidator","event","handler","customProvider","cleanup","addRevalidator","revalidatorFn","ttl","staleTime","bgRevalidatorFn","refetchOnFocus","refetchOnReconnect","existing","listeners","ensureListenerSet","set","addListener","fn","removeListener","notifySubscribers","fns","subscribe","defaultTimeoutMs","defaultConfig","setDefaultConfig","customConfig","sanitized","mergeConfigs","getDefaultConfig","buildConfig","reqConfig","buildFetcherConfig","merged","requestConfig","_a","method","body","setContentTypeIfNeeded","credentials","dynamicUrl","urlPath","baseURL","contentTypeValue","baseConfig","overrideConfig","targetConfig","mergeConfig","mergeInterceptors","property","baseInterceptor","newInterceptor","baseArr","newArr","base","override","baseNormalized","overrideNormalized","_cache","DELIMITER","MIN_LENGTH_TO_HASH","CACHE_KEY_SANITIZE_PATTERN","CACHE_KEY_NEEDS_SANITIZE","CACHE_KEY_HEADER_WHITELIST","generateCacheKey","config","cacheKeyCheck","headersString","cacheStr","bodyString","o","isCacheExpired","getCache","setCache","deleteCache","time","ttlMs","staleTimeMs","removeExpired","mutate","newData","settings","updatedData","updatedResponse","updatedEntry","getCachedResponse","cacheKey","cacheTime","buster","handleResponseCache","output","isError","skipCache","prevCacheKey","parseResponseData","contentType","mimeType","trimmed","_error","prepareResponse","defaultResponse","mutatator","isNativeResponse","getMsFromHttpDate","dateString","getRetryAfterMs","extendedResponse","retryAfter","RATELIMIT_RESET","rateLimitResetAfter","rateLimitResetAt","withRetry","requestFn","retries","delay","backoff","maxDelay","retryOn","shouldRetry","attempt","waitTime","maxRetries","cfg","onRetry","getShouldStopRetrying","retryAfterMs","_b","customDecision","withPolling","pollingInterval","shouldStopPolling","maxAttempts","pollingDelay","pollingAttempt","withErrorHandling","isCancelled","logger","strategy","enhanceError","inFlightResponse","fetchf","cached","fetcherConfig","cancellable","isCacheEnabled","needsCacheKey","_cacheKey","inflight","retryConfig","resetTimeout","doRequestOnce","onResponse","baseRequest","_","requestWithErrorHandling","doRequestPromise","createApiFetcher","endpoints","handleNonImplemented","endpointName","apiHandler","endpointConfig","_endpointConfig","mergedConfig","_target","prop"],"mappings":"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","file":"index.mjs","sourcesContent":["export const APPLICATION_CONTENT_TYPE = 'application/';\n\nexport const APPLICATION_JSON = APPLICATION_CONTENT_TYPE + 'json';\nexport const CHARSET_UTF_8 = 'charset=utf-8';\nexport const CONTENT_TYPE = 'Content-Type';\n\nexport const UNDEFINED = 'undefined';\nexport const OBJECT = 'object';\nexport const STRING = 'string';\nexport const FUNCTION = 'function';\n\nexport const ABORT_ERROR = 'AbortError';\nexport const TIMEOUT_ERROR = 'TimeoutError';\n\nexport const GET = 'GET';\nexport const HEAD = 'HEAD';\n\nexport const REJECT = 'reject';\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { FUNCTION, OBJECT, STRING, UNDEFINED } from './constants';\nimport type {\n DefaultUrlParams,\n HeadersObject,\n QueryParams,\n UrlPathParams,\n} from './types';\n\n// Prevent stack overflow with recursion depth limit\nconst MAX_DEPTH = 10;\n\nexport function isSearchParams(data: unknown): boolean {\n return data instanceof URLSearchParams;\n}\n\n/**\n * Determines if a value is a non-null object.\n *\n * @param {any} value - The value to check.\n * @returns {boolean} - True if the value is a non-null object.\n */\nexport function isObject(value: any): value is Record {\n return value !== null && typeof value === OBJECT;\n}\n\n/**\n * Shallowly serializes an object by converting its key-value pairs into a string representation.\n * This function does not recursively serialize nested objects.\n *\n * @param obj - The object to serialize.\n * @returns A string representation of the object's top-level properties.\n */\nexport function shallowSerialize(obj: Record): string {\n let result = '';\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n result += key + ':' + obj[key];\n }\n }\n\n return result;\n}\n\n/**\n * Removes properties that could lead to prototype pollution from an object.\n *\n * This function checks for dangerous properties like '__proto__', 'constructor',\n * and 'prototype'. If none are present, the object is returned as-is (zero-copy fast path).\n * Otherwise, a shallow copy is created with the dangerous properties removed.\n *\n * @param obj - The object to sanitize\n * @returns A safe object without dangerous properties\n */\nexport function sanitizeObject>(obj: T): T {\n const hasProto = Object.prototype.hasOwnProperty.call(obj, '__proto__');\n const hasCtor = Object.prototype.hasOwnProperty.call(obj, 'constructor');\n const hasPrototype = Object.prototype.hasOwnProperty.call(obj, 'prototype');\n\n if (!hasProto && !hasCtor && !hasPrototype) {\n return obj;\n }\n\n const safeObj = { ...obj };\n\n if (hasProto) delete safeObj.__proto__;\n if (hasCtor) delete (safeObj as any).constructor;\n if (hasPrototype) delete safeObj.prototype;\n\n return safeObj;\n}\n\n/**\n * Sorts the keys of an object and returns a new object with sorted keys.\n *\n * This function is optimized for performance by minimizing the number of object operations\n * and using a single pass to create the sorted object.\n *\n * @param {Object} obj - The object to be sorted by keys.\n * @returns {Object} - A new object with keys sorted in ascending order.\n */\nexport function sortObject(obj: Record): object {\n const keys = Object.keys(obj);\n\n keys.sort();\n\n const sortedObj = {} as Record;\n\n for (let i = 0, len = keys.length; i < len; i++) {\n const key = keys[i];\n\n sortedObj[key] = obj[key];\n }\n\n return sortedObj;\n}\n\n/**\n * Appends a query string to a URL, ensuring proper handling of existing query parameters.\n *\n * @param baseUrl - The base URL to which the query string will be appended.\n * @param queryString - The encoded query string to append.\n * @returns The URL with the appended query string, or the original URL if no query string is provided.\n */\nfunction appendQueryStringToUrl(baseUrl: string, queryString: string): string {\n if (!queryString) {\n return baseUrl;\n }\n\n return baseUrl.includes('?')\n ? `${baseUrl}&${queryString}`\n : `${baseUrl}?${queryString}`;\n}\n\n/**\n * Appends query parameters to a given URL.\n *\n * @param {string} url - The base URL to which query parameters will be appended.\n * @param {QueryParams} params - An object containing the query parameters to append.\n * @returns {string} - The URL with the appended query parameters.\n */\nexport function appendQueryParams(url: string, params: QueryParams): string {\n if (!params) {\n return url;\n }\n\n // Check if `params` is an instance of URLSearchParams and bail early if it is\n if (isSearchParams(params)) {\n const encodedQueryString = params.toString();\n\n return appendQueryStringToUrl(url, encodedQueryString);\n }\n\n // This is exact copy of what JQ used to do. It works much better than URLSearchParams\n const s: string[] = [];\n const encode = encodeURIComponent;\n const add = (k: string, v: any) => {\n v = typeof v === FUNCTION ? v() : v;\n v = v === null ? '' : v === undefined ? '' : v;\n s[s.length] = encode(k) + '=' + encode(v);\n };\n\n const buildParams = (prefix: string, obj: any, depth = 0) => {\n // Stop recursion if maximum depth is reached\n if (depth >= MAX_DEPTH) {\n return s;\n }\n\n let i: number, len: number, key: string;\n\n if (prefix) {\n if (Array.isArray(obj)) {\n for (i = 0, len = obj.length; i < len; i++) {\n buildParams(\n prefix + '[' + (typeof obj[i] === OBJECT && obj[i] ? i : '') + ']',\n obj[i],\n depth + 1,\n );\n }\n } else if (isObject(obj)) {\n for (key in obj) {\n buildParams(prefix + '[' + key + ']', obj[key], depth + 1);\n }\n } else {\n add(prefix, obj);\n }\n } else if (Array.isArray(obj)) {\n for (i = 0, len = obj.length; i < len; i++) {\n add(obj[i].name, obj[i].value);\n }\n } else {\n for (key in obj) {\n buildParams(key, obj[key], depth + 1);\n }\n }\n return s;\n };\n\n const queryStringParts = buildParams('', params).join('&');\n\n // Encode special characters as per RFC 3986, https://datatracker.ietf.org/doc/html/rfc3986\n // This is for compatibility with server frameworks that expect the literal notation\n const encodedQueryString = queryStringParts.replace(/%5B%5D/g, '[]'); // Keep '[]' for arrays\n\n return appendQueryStringToUrl(url, encodedQueryString);\n}\n\n/**\n * Replaces dynamic URI parameters in a URL string with values from the provided `urlPathParams` object.\n * Parameters in the URL are denoted by `:`, where `` is a key in `urlPathParams`.\n *\n * @param {string} url - The URL string containing placeholders in the format `:`.\n * @param {Object} urlPathParams - An object containing the parameter values to replace placeholders.\n * @param {string} urlPathParams.paramName - The value to replace the placeholder `:` in the URL.\n * @returns {string} - The URL string with placeholders replaced by corresponding values from `urlPathParams`.\n */\nexport function replaceUrlPathParams(\n url: string,\n urlPathParams: UrlPathParams,\n): string {\n if (!urlPathParams || url.indexOf(':') === -1) {\n return url;\n }\n\n // Use a single RegExp and avoid unnecessary casts and function calls\n // Precompute keys for faster lookup\n const params = urlPathParams as DefaultUrlParams;\n\n // Use a replacer function that avoids extra work\n return url.replace(/:([a-zA-Z0-9_]+)/g, (match, key) => {\n // Use hasOwnProperty for strict key existence check\n if (Object.prototype.hasOwnProperty.call(params, key)) {\n const value = params[key];\n\n // Only replace if value is not undefined or null\n if (value !== undefined && value !== null) {\n return encodeURIComponent(String(value));\n }\n }\n\n return match;\n });\n}\n\n/**\n * Determines whether the provided URL is absolute.\n *\n * An absolute URL contains a scheme (e.g., \"http://\", \"https://\").\n *\n * @param url - The URL string to check.\n * @returns `true` if the URL is absolute, otherwise `false`.\n */\nexport function isAbsoluteUrl(url: string): boolean {\n return url.includes('://');\n}\n\nexport const timeNow = () => Date.now();\n\nexport const noop = () => {};\n\n/**\n * Checks if a value is JSON serializable.\n *\n * JSON serializable values include:\n * - Primitive types: string, number, boolean, null\n * - Arrays\n * - Plain objects (i.e., objects without special methods)\n * - Values with a `toJSON` method\n *\n * @param {any} value - The value to check for JSON serializability.\n * @returns {boolean} - Returns `true` if the value is JSON serializable, otherwise `false`.\n */\nexport function isJSONSerializable(value: any): boolean {\n const t = typeof value;\n\n if (value === undefined || value === null) {\n return false;\n }\n\n if (t === STRING || t === 'number' || t === 'boolean') {\n return true;\n }\n\n if (Array.isArray(value)) {\n return true;\n }\n\n if (\n typeof globalThis !== UNDEFINED &&\n typeof globalThis.Buffer !== UNDEFINED &&\n globalThis.Buffer.isBuffer(value)\n ) {\n return false;\n }\n\n if (value instanceof Date || isSearchParams(value)) {\n return false;\n }\n\n if (isObject(value)) {\n const proto = Object.getPrototypeOf(value);\n\n // Check if the prototype is `Object.prototype` (plain object)\n if (proto === Object.prototype) {\n return true;\n }\n\n // Check if the object has a toJSON method\n if (typeof value.toJSON === FUNCTION) {\n return true;\n }\n }\n\n return false;\n}\n\nexport async function delayInvocation(ms: number): Promise {\n return new Promise((resolve) =>\n setTimeout(() => {\n return resolve(true);\n }, ms),\n );\n}\n\n/**\n * Recursively flattens the data object if it meets specific criteria.\n *\n * The method checks if the provided `data` is an object with exactly one property named `data`.\n * If so, it recursively flattens the `data` property. Otherwise, it returns the `data` as-is.\n *\n * @param {any} data - The data to be flattened. Can be of any type, including objects, arrays, or primitives.\n * @returns {any} - The flattened data if the criteria are met; otherwise, the original `data`.\n */\nexport function flattenData(data: any, depth = 0): any {\n if (depth >= MAX_DEPTH) {\n return data;\n }\n\n if (data && isObject(data) && typeof data.data !== UNDEFINED) {\n return flattenData(data.data, depth + 1);\n }\n\n return data;\n}\n\n/**\n * Processes headers and returns them as a normalized object.\n *\n * Handles both `Headers` instances and plain objects. Normalizes header keys to lowercase\n * as per RFC 2616 section 4.2.\n *\n * @param headers - The headers to process. Can be an instance of `Headers`, a plain object,\n * or `null`. If `null`, an empty object is returned.\n * @returns {HeadersObject} - A normalized headers object with lowercase keys.\n */\nexport function processHeaders(\n headers?: (HeadersObject & HeadersInit) | null | Headers,\n): HeadersObject {\n if (!headers) {\n return {};\n }\n\n const headersObject: HeadersObject = {};\n\n // Normalize keys to lowercase as per RFC 2616 4.2\n // https://datatracker.ietf.org/doc/html/rfc2616#section-4.2\n if (headers instanceof Headers) {\n headers.forEach((value, key) => {\n headersObject[key.toLowerCase()] = value;\n });\n } else if (isObject(headers)) {\n // Handle plain object — use for...in to avoid Object.entries() allocation\n for (const key in headers) {\n if (Object.prototype.hasOwnProperty.call(headers, key)) {\n headersObject[key.toLowerCase()] = headers[key];\n }\n }\n }\n\n return headersObject;\n}\n\n/**\n * Determines if the current environment is a browser.\n *\n * @returns {boolean} - True if running in a browser environment, false otherwise.\n */\nexport function isBrowser(): boolean {\n // For node and some mobile frameworks like React Native, `add/removeEventListener` doesn't exist on window!\n return (\n typeof window !== UNDEFINED && typeof window.addEventListener === FUNCTION\n );\n}\n\n/**\n * Creates an abort/timeout error compatible with all JS runtimes.\n * Falls back to a plain Error with the correct `name` when DOMException is unavailable (e.g. React Native).\n *\n * @param {string} message - The error message.\n * @param {string} name - The error name (e.g. 'AbortError', 'TimeoutError').\n * @returns {DOMException | Error} - An error object with the specified name.\n */\nexport function createAbortError(\n message: string,\n name: string,\n): DOMException | Error {\n if (typeof DOMException !== UNDEFINED) {\n return new DOMException(message, name);\n }\n\n const error = new Error(message);\n error.name = name;\n\n return error;\n}\n\n/**\n * Detects if the user is on a slow network connection\n * @returns {boolean} True if connection is slow, false otherwise or if detection unavailable\n */\nexport const isSlowConnection = (): boolean => {\n const conn = typeof navigator !== UNDEFINED && (navigator as any).connection;\n\n return conn && ['slow-2g', '2g', '3g'].includes(conn.effectiveType);\n};\n","import { FUNCTION } from './constants';\nimport type { InterceptorFunction } from './types/interceptor-manager';\nimport { isObject } from './utils';\n\n/**\n * Applies interceptors to the object. Interceptors can be a single function or an array of functions.\n *\n * @template T - Type of the object.\n * @template Args - Type of additional arguments.\n * @template I - Type of interceptors.\n *\n * @param {InterceptorFunction | InterceptorFunction[]} [interceptors] - Interceptor function(s).\n * @param {T} data - The data object to process.\n * @param {...Args} args - Additional arguments to pass to interceptors.\n *\n * @returns {Promise} - Nothing as the function is non-idempotent.\n */\nexport async function applyInterceptors<\n T extends object,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Args extends any[] = any[],\n I = InterceptorFunction | InterceptorFunction[],\n>(interceptors: I | undefined, data: T, ...args: Args): Promise {\n if (!interceptors) {\n return;\n }\n\n if (typeof interceptors === FUNCTION) {\n const value = await (interceptors as InterceptorFunction)(\n data,\n ...args,\n );\n\n if (value && isObject(data) && isObject(value)) {\n Object.assign(data, value);\n }\n } else if (Array.isArray(interceptors)) {\n for (const interceptor of interceptors) {\n const value = await interceptor(data, ...args);\n\n if (value && isObject(data) && isObject(value)) {\n Object.assign(data, value);\n }\n }\n }\n}\n","import type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '../types';\n\n/**\n * This is a base error class\n */\nexport class FetchError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n> extends Error {\n status: number;\n statusText: string;\n config: RequestConfig;\n isCancelled: boolean;\n\n constructor(\n message: string,\n public request: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n public response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n ) {\n super(message);\n\n this.name = 'FetchError';\n this.status = response ? response.status : 0;\n this.statusText = response ? response.statusText : '';\n this.config = request;\n this.isCancelled = false;\n }\n}\n","import { FetchError } from './fetch-error';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '../types';\n\nexport class ResponseError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n> extends FetchError {\n constructor(\n message: string,\n request: RequestConfig,\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n ) {\n super(message, request, response);\n\n this.name = 'ResponseError';\n }\n}\n","/**\n * @module timeout-wheel\n * @description\n * Ultra-minimal timing wheel implementation optimized for max performance & many requests.\n * For most of the cases it's 4-100x faster than setTimeout and setInterval alone.\n * Provides efficient scheduling and cancellation of timeouts using a circular array.\n *\n * Position 0 → 1 → 2 → ... → 599 → 0 → 1 → 2 ...\n * Time: 0s 1s 2s 599s 600s 601s 602s\n *\n * The timing wheel consists of 600 slots (one per second for 10 min).\n * Each slot contains a list of timeout items, each associated with a unique key and callback.\n * Timeouts are scheduled by placing them in the appropriate slot based on the delay in seconds.\n * The wheel advances every second, executing and removing callbacks as their timeouts expire.\n * Defaults to setTimeout if the delay exceeds 10 minutes or is not divisible by 1000.\n *\n * @remarks\n * - Designed for minimal footprint and simplicity.\n * - Only supports second-level granularity (minimum timeout: 1 second).\n * - Automatically stops the internal timer when no timeouts remain.\n */\n\nimport { noop } from './utils';\n\ntype TimeoutCallback = () => unknown | Promise;\ntype TimeoutItem = [string, TimeoutCallback]; // [key, callback]\n\nconst WHEEL_SIZE = 600; // 600 slots for 10 min (1 slot per second)\nconst SECOND = 1000; // 1 second in milliseconds\nconst MAX_WHEEL_MS = WHEEL_SIZE * SECOND;\nconst wheel: TimeoutItem[][] = Array(WHEEL_SIZE)\n .fill(0)\n .map(() => []);\n\nconst keyMap = new Map();\nlet position = 0;\nlet timer: NodeJS.Timeout | null = null;\n\nconst handleCallback = ([key, callback]: TimeoutItem): void => {\n keyMap.delete(key);\n\n try {\n const result = callback();\n if (result && result instanceof Promise) {\n // Silently ignore async errors to prevent wheel from stopping\n result.catch(noop);\n }\n } catch {\n // Ignore callback errors to prevent wheel from stopping\n }\n};\n\nexport const addTimeout = (\n key: string,\n cb: TimeoutCallback,\n ms: number,\n): void => {\n removeTimeout(key);\n\n // Fallback to setTimeout if wheel size is exceeded, ms is sub-second, or ms is not divisible by SECOND\n if (ms < SECOND || ms > MAX_WHEEL_MS || ms % SECOND !== 0) {\n keyMap.set(key, [setTimeout(handleCallback.bind(null, [key, cb]), ms)]); // Store timeout ID instead of slot\n\n return;\n }\n\n // No need for Math.ceil here since ms is guaranteed by modulo above\n const seconds = ms / SECOND;\n const slot = (position + seconds) % WHEEL_SIZE;\n\n wheel[slot].push([key, cb]);\n keyMap.set(key, slot);\n\n if (!timer) {\n timer = setInterval(() => {\n position = (position + 1) % WHEEL_SIZE;\n const slot = wheel[position];\n\n // Use slot.length directly (not cached) so mid-iteration mutations\n // from callbacks (e.g. removeTimeout) are handled correctly\n for (let i = 0; i < slot.length; i++) {\n handleCallback(slot[i]);\n }\n\n slot.length = 0; // Reuse array, avoid GC allocation\n\n if (!keyMap.size && timer) {\n clearInterval(timer);\n timer = null;\n }\n }, SECOND);\n }\n};\n\nexport const removeTimeout = (key: string): void => {\n const slotOrTimeout = keyMap.get(key);\n\n if (slotOrTimeout !== undefined) {\n // It's a Timeout object from setTimeout\n if (Array.isArray(slotOrTimeout)) {\n clearTimeout(slotOrTimeout[0]);\n } else {\n const slotArr = wheel[slotOrTimeout];\n const idx = slotArr.findIndex(([k]) => k === key);\n\n if (idx !== -1) {\n slotArr.splice(idx, 1);\n }\n }\n\n keyMap.delete(key);\n\n if (!keyMap.size && timer) {\n clearInterval(timer);\n timer = null;\n }\n }\n};\n\nexport const clearAllTimeouts = () => {\n // Clear native setTimeout timeouts first!\n keyMap.forEach((value) => {\n if (Array.isArray(value)) {\n clearTimeout(value[0]);\n }\n });\n\n if (timer) {\n clearInterval(timer);\n timer = null;\n }\n\n keyMap.clear();\n\n for (let i = 0; i < WHEEL_SIZE; i++) {\n wheel[i].length = 0;\n }\n\n position = 0;\n};\n","/**\n * @module inflight-manager\n *\n * Manages in-flight asynchronous requests using unique keys to enable deduplication and cancellation.\n *\n * Provides utilities for:\n * - Deduplication of requests within a configurable time window (`dedupeTime`)\n * - Timeout management and automatic request abortion\n * - AbortController lifecycle and cancellation logic\n * - Concurrency control and request state tracking\n * - In-flight promise deduplication to prevent duplicate network calls\n *\n * @remarks\n * - Requests with the same key within the deduplication interval share the same AbortController and in-flight promise.\n * - Supports cancellation of previous requests when a new one with the same key is issued, if `isCancellable` is enabled.\n * - Timeout logic ensures requests are aborted after a specified duration, if enabled.\n * - Internal queue state is managed via a Map, keyed by request identifier.\n * - Polled requests are also marked as \"in-flight\" to prevent duplicate requests.\n */\n\nimport { ABORT_ERROR, TIMEOUT_ERROR } from './constants';\nimport { addTimeout, removeTimeout } from './timeout-wheel';\nimport { createAbortError, timeNow } from './utils';\n\nexport type InFlightItem = [\n AbortController, // AbortController for the request\n boolean, // Whether timeout is enabled for the request\n number, // Timestamp when the request was marked in-flight\n boolean, // isCancellable - whether the request can be cancelled\n Promise | null, // Optional in-flight promise for deduplication\n];\n\nconst inFlight: Map = new Map();\n\n/**\n * Adds a request to the queue if it's not already being processed within the dedupeTime interval.\n *\n * @param {string | null} key - Unique key for the request (e.g. cache key).\n * @param {string} url - The request URL (for error messages/timeouts).\n * @param {number} timeout - Timeout in milliseconds for the request.\n * @param {number} dedupeTime - Deduplication time in milliseconds.\n * @param {boolean} isCancellable - If true, then the previous request with same configuration should be aborted.\n * @param {boolean} isTimeoutEnabled - Whether timeout is enabled.\n * @returns {AbortController} - A promise that resolves to an AbortController.\n */\nexport function markInFlight(\n key: string | null,\n url: string,\n timeout: number | undefined,\n dedupeTime: number,\n isCancellable: boolean,\n isTimeoutEnabled: boolean,\n): AbortController {\n if (!key) {\n return new AbortController();\n }\n\n const now = timeNow();\n const item = inFlight.get(key);\n let prevPromise: Promise | null = null;\n\n // Previous request is in-flight, check if we can reuse it\n if (item) {\n const prevController = item[0];\n const prevIsCancellable = item[3];\n\n // If the request is already in the queue and within the dedupeTime, reuse the existing controller\n if (\n !prevIsCancellable &&\n now - item[2] < dedupeTime &&\n !prevController.signal.aborted\n ) {\n return prevController;\n }\n\n // If the request is too old, remove it and proceed to add a new one\n // Abort previous request, if applicable, and continue as usual\n if (prevIsCancellable) {\n prevController.abort(\n createAbortError('Aborted due to new request', ABORT_ERROR),\n );\n }\n\n removeTimeout(key);\n prevPromise = item[4];\n }\n\n const controller = new AbortController();\n\n inFlight.set(key, [\n controller,\n isTimeoutEnabled,\n now,\n isCancellable,\n prevPromise,\n ]);\n\n if (isTimeoutEnabled) {\n addTimeout(\n key,\n () => {\n abortRequest(\n key,\n createAbortError(url + ' aborted due to timeout', TIMEOUT_ERROR),\n );\n },\n timeout as number,\n );\n }\n\n return controller;\n}\n\n/**\n * Removes a request from the queue and clears its timeout.\n *\n * @param key - Unique key for the request.\n * @param {boolean} error - Optional error to abort the request with. If null, the request is simply removed but no abort sent.\n * @returns {Promise} - A promise that resolves when the request is aborted and removed.\n */\nexport async function abortRequest(\n key: string | null,\n error: DOMException | Error | null | string = null,\n): Promise {\n // If the key is not in the queue, there's nothing to remove\n if (key) {\n const item = inFlight.get(key);\n\n if (item) {\n // If the request is not yet aborted, abort it with the provided error\n if (error) {\n const controller = item[0];\n controller.abort(error);\n }\n\n removeInFlight(key);\n }\n }\n}\n\n/**\n * Removes a request from the in-flight queue without aborting or clearing timeout.\n *\n * @param key - Unique key for the request.\n */\nexport function removeInFlight(key: string | null): void {\n removeTimeout(key!);\n inFlight.delete(key!);\n}\n\n/**\n * Gets the AbortController for a request key.\n *\n * @param key - Unique key for the request.\n * @returns {AbortController | undefined} - The AbortController or undefined.\n */\nexport async function getController(\n key: string,\n): Promise {\n const item = inFlight.get(key);\n\n return item?.[0];\n}\n\n/**\n * Adds helpers for in-flight promise deduplication.\n *\n * @param key - Unique key for the request.\n * @param promise - The promise to store.\n */\nexport function setInFlightPromise(\n key: string,\n promise: Promise,\n): void {\n const item = inFlight.get(key);\n if (item) {\n // store the promise at index 4 — item is already the Map's reference, no need to re-set\n item[4] = promise;\n }\n}\n\n/**\n * Retrieves the in-flight promise for a request key if it exists and is within the dedupeTime interval.\n *\n * @param key - Unique key for the request.\n * @param dedupeTime - Deduplication time in milliseconds.\n * @returns {Promise | null} - The in-flight promise or null.\n */\nexport function getInFlightPromise(\n key: string | null,\n dedupeTime: number,\n): Promise | null {\n if (!key) {\n return null;\n }\n\n const prevReq = inFlight.get(key);\n\n if (\n prevReq &&\n // If the request is in-flight and has a promise\n prevReq[4] &&\n // If the request is cancellable, we will not reuse it\n !prevReq[3] &&\n // If the request is within the dedupeTime\n timeNow() - prevReq[2] < dedupeTime &&\n // If one request is cancelled, ALL deduped requests get cancelled\n !prevReq[0].signal.aborted\n ) {\n return prevReq[4] as Promise;\n }\n\n return null;\n}\n","const PRIME_MULTIPLIER = 31;\n\n/**\n * Computes a hash value for a given string using the variant of djb2 hash function.\n * This hash function is non-cryptographic and designed for speed.\n * @author Daniel J. Bernstein (of djb2)\n *\n * @param str Input string to hash\n * @returns {string} Hash\n */\nexport function hash(str: string): string {\n let hash = 0;\n\n for (let i = 0, len = str.length; i < len; i++) {\n const char = str.charCodeAt(i);\n hash = (hash * PRIME_MULTIPLIER + char) | 0;\n }\n\n return String(hash);\n}\n","/**\n * @module revalidator-manager\n *\n * Provides utilities for managing cache revalidation functions, including:\n * - Registering and unregistering revalidators for specific cache keys.\n * - Triggering revalidation for a given key.\n * - Enabling or disabling automatic revalidation on window focus and if user comes back online for specific keys.\n * - Attaching and removing global focus and online event handlers to trigger revalidation.\n *\n * Revalidators are functions that can be registered to revalidate cache entries when needed.\n * They are typically used to refresh data in the cache when the window gains focus or when specific actions occur.\n * @performance O(1) lookup by key makes it blazing fast to register, unregister, and revalidate cache entries.\n * - Designed for high performance: minimizes unnecessary re-renders and leverages fast cache key generation.\n * - Integrates with a global cache and pub/sub system for efficient state updates across contexts.\n * - Handles automatic revalidation, deduplication, retries, and cache management out of the box.\n * @remarks\n * - Designed to be used in various environments (Deno, Node.js, Bun, Browser, etc.) to ensure cache consistency and freshness.\n */\nimport { addTimeout, removeTimeout } from './timeout-wheel';\nimport { FetchResponse } from './types';\nimport { isBrowser, noop, timeNow } from './utils';\n\nexport type RevalidatorFn = (\n isStaleRevalidation?: boolean,\n) => Promise;\n\ntype EventType = 'focus' | 'online';\n\ntype RevalidatorEntry = [\n RevalidatorFn, // main revalidator\n number, // lastUsed\n number, // ttl\n number?, // staleTime\n RevalidatorFn?, // bgRevalidator\n boolean?, // refetchOnFocus\n boolean?, // refetchOnReconnect\n];\n\nconst DEFAULT_TTL = 3 * 60 * 1000; // Default TTL of 3 minutes\nconst revalidators = new Map();\n\n/**\n * Stores cleanup functions for active event handlers (browser or custom providers).\n * Each entry removes the corresponding event listener when called.\n * @remarks\n * - Improves performance by reducing the number of event listeners.\n * - Enables efficient O(1) lookup and management of event handlers for revalidation.\n */\nconst eventHandlers = new Map void>();\n\n/** Subscribe to an event and return a cleanup function */\nexport type EventProvider = (handler: () => void) => () => void;\n\nconst customEventProviders = new Map();\n\n/**\n * Registers a custom event provider for 'focus' or 'online' events.\n * Useful for non-browser environments like React Native.\n *\n * @param type - The event type ('focus' or 'online').\n * @param provider - A function that subscribes to the event and returns a cleanup function.\n */\nexport function setEventProvider(\n type: EventType,\n provider: EventProvider,\n): void {\n customEventProviders.set(type, provider);\n\n // Re-register if already active\n if (eventHandlers.has(type)) {\n removeEventHandler(type);\n addEventHandler(type);\n }\n}\n\n/**\n * Triggers revalidation for all registered entries based on the given event type.\n * For example, if it's a 'focus' event, it will revalidate entries that have the `refetchOnFocus` flag set.\n * Updates the timestamp and invokes the revalidator function for each applicable entry.\n *\n * @param type - The type of event that caused the revalidation (e.g., 'focus' or 'online').\n * @param isStaleRevalidation - If `true`, uses background revalidator and doesn't mark as in-flight.\n */\nexport function revalidateAll(\n type: EventType,\n isStaleRevalidation: boolean = true,\n) {\n const flagIndex = type === 'focus' ? 5 : 6;\n const now = timeNow();\n\n revalidators.forEach((entry) => {\n if (!entry[flagIndex]) {\n return;\n }\n\n entry[1] = now;\n\n // If it's a stale revalidation, use the background revalidator function\n const revalidator = isStaleRevalidation ? entry[4] : entry[0];\n\n if (revalidator) {\n Promise.resolve(revalidator(isStaleRevalidation)).catch(noop);\n }\n });\n}\n\n/**\n * Revalidates an entry by executing the registered revalidation function.\n *\n * @param key The unique identifier for the cache entry to revalidate. If `null`, no revalidation occurs.\n * @param isStaleRevalidation - If `true`, it does not mark revalidated requests as in-flight.\n * @returns A promise that resolves to the result of the revalidator function, or\n * `null` if no key or revalidator is found, or a `FetchResponse` if applicable.\n */\nexport async function revalidate(\n key: string | null,\n isStaleRevalidation: boolean = false,\n): Promise {\n // If no key is provided, no revalidation occurs\n if (!key) {\n return null;\n }\n\n const entry = revalidators.get(key);\n\n if (entry) {\n // Update only the lastUsed timestamp without resetting the whole array\n entry[1] = timeNow();\n\n const revalidator = isStaleRevalidation ? entry[4] : entry[0];\n\n // If no revalidator function is registered, return null\n if (revalidator) {\n return await revalidator(isStaleRevalidation);\n }\n }\n\n // If no revalidator is registered for the key, return null\n return null;\n}\n\n/**\n * Removes all revalidators associated with the specified event type.\n *\n * @param type - The event type whose revalidators should be removed.\n */\nexport function removeRevalidators(type: EventType) {\n removeEventHandler(type);\n\n const flagIndex = type === 'focus' ? 5 : 6;\n\n // Clear all revalidators with this flag\n revalidators.forEach((entry, key) => {\n if (entry[flagIndex]) {\n removeRevalidator(key);\n }\n });\n}\n\n/**\n * Registers a generic revalidation event handler for the specified event type.\n * Supports browser window events and custom event providers (e.g. for React Native).\n * Ensures the handler is only added once.\n *\n * @param event - The type of event to listen for (e.g., 'focus', 'online').\n */\nfunction addEventHandler(event: EventType) {\n if (eventHandlers.has(event)) {\n return;\n }\n\n const handler = revalidateAll.bind(null, event, true);\n\n // Priority 1: Custom event provider (works in any environment including React Native)\n const customProvider = customEventProviders.get(event);\n\n if (customProvider) {\n const cleanup = customProvider(handler);\n\n eventHandlers.set(event, cleanup);\n\n return;\n }\n\n // Priority 2: Browser window events\n if (isBrowser()) {\n window.addEventListener(event, handler);\n\n eventHandlers.set(event, () => window.removeEventListener(event, handler));\n }\n}\n\n/**\n * Removes the event handler for the specified event type.\n *\n * @param event - The type of event whose handler should be removed.\n */\nfunction removeEventHandler(event: EventType) {\n const cleanup = eventHandlers.get(event);\n\n if (cleanup) {\n cleanup();\n eventHandlers.delete(event);\n }\n}\n\n/**\n * Registers a revalidation functions for a specific cache key.\n *\n * @param {string} key Cache key to utilize\n * @param {RevalidatorFn} revalidatorFn Main revalidation function (marks in-flight requests)\n * @param {number} [ttl] Time to live in milliseconds (default: 3 minutes)\n * @param {number} [staleTime] Time (in seconds) after which the cache entry is considered stale\n * @param {RevalidatorFn} [bgRevalidatorFn] For stale revalidation (does not mark in-flight requests)\n * @param {boolean} [refetchOnFocus] Whether to revalidate on window focus\n * @param {boolean} [refetchOnReconnect] Whether to revalidate on network reconnect\n */\nexport function addRevalidator(\n key: string,\n revalidatorFn: RevalidatorFn, // Main revalidation function (marks in-flight requests)\n ttl?: number,\n staleTime?: number,\n bgRevalidatorFn?: RevalidatorFn, // For stale revalidation (does not mark in-flight requests)\n refetchOnFocus?: boolean,\n refetchOnReconnect?: boolean,\n) {\n const existing = revalidators.get(key);\n\n if (existing) {\n // Update in-place to avoid allocating a new tuple array\n existing[0] = revalidatorFn;\n existing[1] = timeNow();\n existing[2] = ttl ?? DEFAULT_TTL;\n existing[3] = staleTime;\n existing[4] = bgRevalidatorFn;\n existing[5] = refetchOnFocus;\n existing[6] = refetchOnReconnect;\n } else {\n revalidators.set(key, [\n revalidatorFn,\n timeNow(),\n ttl ?? DEFAULT_TTL,\n staleTime,\n bgRevalidatorFn,\n refetchOnFocus,\n refetchOnReconnect,\n ]);\n }\n\n if (refetchOnFocus) {\n addEventHandler('focus');\n }\n\n if (refetchOnReconnect) {\n addEventHandler('online');\n }\n\n if (staleTime) {\n addTimeout('s:' + key, revalidate.bind(null, key, true), staleTime * 1000);\n }\n}\n\nexport function removeRevalidator(key: string) {\n revalidators.delete(key);\n\n // Clean up stale timer\n removeTimeout('s:' + key);\n}\n\n/**\n * Periodically cleans up expired revalidators from the registry.\n * Removes any revalidator whose TTL has expired.\n *\n * @param {number} intervalMs How often to run cleanup (default: 3 minutes)\n * @returns {() => void} A function to stop the periodic cleanup\n */\nexport function startRevalidatorCleanup(\n intervalMs: number = DEFAULT_TTL,\n): () => void {\n const intervalId = setInterval(() => {\n const now = timeNow();\n\n revalidators.forEach(\n ([, lastUsed, ttl, , , refetchOnFocus, refetchOnReconnect], key) => {\n // Skip focus-only or reconnect-only revalidators to keep them alive\n if (refetchOnFocus || refetchOnReconnect) {\n return;\n }\n\n if (ttl > 0 && now - lastUsed > ttl) {\n removeRevalidator(key);\n }\n },\n );\n }, intervalMs);\n\n return () => clearInterval(intervalId);\n}\n","/**\n * Manages a set of listeners (subscribers) for arbitrary string keys, allowing cross-context or cross-component\n * cache updates and synchronization. Provides functions to add, remove, and notify listeners, as well as a\n * convenient subscribe/unsubscribe API.\n *\n * @template T - The type of the response object passed to listeners.\n *\n * @remarks\n * - Listeners are grouped by a string key, which typically represents a cache key or resource identifier.\n * - When `notifySubscribers` is called for a key, all listeners registered for that key are invoked with the provided response.\n * - The `subscribe` function returns an unsubscribe function for convenient cleanup.\n *\n * @example\n * ```ts\n * const unsubscribe = subscribe('user:123', (response) => {\n * // handle updated data\n * });\n * // Later, to stop listening:\n * unsubscribe();\n * ```\n */\n\nimport { noop } from './utils';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Listener = (response: T) => void;\n\nconst listeners = new Map>();\n\nfunction ensureListenerSet(key: string) {\n let set = listeners.get(key);\n\n if (!set) {\n set = new Set();\n listeners.set(key, set);\n }\n\n return set;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function addListener(key: string, fn: Listener): void {\n ensureListenerSet(key).add(fn);\n}\n\nexport function removeListener(key: string, fn: Listener) {\n const set = listeners.get(key);\n\n if (set) {\n set.delete(fn);\n\n // If the set is empty, remove the key from the listeners map\n if (set.size === 0) {\n listeners.delete(key);\n }\n }\n}\n\nexport function notifySubscribers(key: string, response: T) {\n const fns = listeners.get(key);\n\n if (fns) {\n if (fns.size === 1) {\n // If there's only one listener, call it directly\n const fn = fns.values().next().value;\n fn!(response);\n } else {\n fns.forEach((fn) => fn(response));\n }\n }\n}\n\nexport function subscribe(key: string | null, fn: (response: T) => void) {\n if (!key) {\n // No op if no key is provided\n return noop;\n }\n\n addListener(key, fn);\n\n // Return an unsubscribe function\n return () => {\n removeListener(key, fn);\n };\n}\n","import { processHeaders } from './utils';\nimport {\n GET,\n APPLICATION_JSON,\n HEAD,\n STRING,\n CHARSET_UTF_8,\n CONTENT_TYPE,\n REJECT,\n UNDEFINED,\n APPLICATION_CONTENT_TYPE,\n} from './constants';\nimport type {\n HeadersObject,\n Method,\n RequestConfig,\n} from './types/request-handler';\nimport {\n replaceUrlPathParams,\n appendQueryParams,\n isSearchParams,\n isJSONSerializable,\n isSlowConnection,\n isAbsoluteUrl,\n sanitizeObject,\n isObject,\n} from './utils';\n\nconst defaultTimeoutMs = (isSlowConnection() ? 60 : 30) * 1000;\n\nexport const defaultConfig: RequestConfig = {\n strategy: REJECT,\n timeout: defaultTimeoutMs, // 30 seconds (60 on slow connections)\n headers: {\n Accept: APPLICATION_JSON + ', text/plain, */*',\n 'Accept-Encoding': 'gzip, deflate, br',\n },\n retry: {\n delay: defaultTimeoutMs / 30, // 1 second (2 on slow connections)\n maxDelay: defaultTimeoutMs, // 30 seconds (60 on slow connections)\n resetTimeout: true,\n backoff: 1.5,\n\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status\n retryOn: [\n 408, // Request Timeout\n 409, // Conflict\n 425, // Too Early\n 429, // Too Many Requests\n 500, // Internal Server Error\n 502, // Bad Gateway\n 503, // Service Unavailable\n 504, // Gateway Timeout\n ],\n },\n};\n\n/**\n * Overwrites the default configuration with the provided custom configuration.\n *\n * @param {Partial} customConfig - The custom configuration to merge into the default config.\n * @returns {Partial} - The updated default configuration object.\n */\nexport function setDefaultConfig(\n customConfig: Partial,\n): Partial {\n const sanitized = sanitizeObject(customConfig);\n\n return mergeConfigs({}, sanitized, defaultConfig);\n}\n\n/**\n * Returns a shallow copy of the current default configuration.\n *\n * @returns {RequestConfig} - The current default configuration.\n */\nexport function getDefaultConfig(): RequestConfig {\n return { ...defaultConfig };\n}\n\n/**\n * Build request configuration from defaults and overrides.\n * This function merges the default configuration with the provided request configuration,\n * @param {string} url - Request url\n * @param {RequestConfig | null | undefined} reqConfig - Request configuration\n * @return {RequestConfig} - Merged request configuration\n */\nexport function buildConfig(\n url: string,\n reqConfig?: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > | null,\n): RequestConfig {\n if (!reqConfig) {\n return buildFetcherConfig(url, getDefaultConfig());\n }\n\n const sanitized = sanitizeObject(reqConfig);\n const merged = mergeConfigs(defaultConfig, sanitized);\n\n return buildFetcherConfig(url, merged);\n}\n\n/**\n * Builds the fetcher configuration by setting the method, body, headers, and URL.\n * It also handles query parameters and path parameters. This fn mutates the passed `requestConfig` object.\n * @param {string} url - The endpoint URL to which the request will be sent.\n * @param {RequestConfig} requestConfig - The request configuration object containing method, body, headers, and other options.\n * @return {RequestConfig} - The modified request configuration object with the URL, method, body, and headers set appropriately.\n **/\nexport function buildFetcherConfig(\n url: string,\n requestConfig: RequestConfig,\n): RequestConfig {\n let method = requestConfig.method as Method;\n method = method ? (method.toUpperCase() as Method) : GET;\n\n let body: RequestConfig['data'] | undefined;\n\n // Only applicable for request methods 'PUT', 'POST', 'DELETE', and 'PATCH'\n if (method !== GET && method !== HEAD) {\n body = requestConfig.body ?? requestConfig.data;\n\n // Automatically stringify request body, if possible and when not dealing with strings\n if (body && typeof body !== STRING && isJSONSerializable(body)) {\n body = JSON.stringify(body);\n }\n }\n\n setContentTypeIfNeeded(requestConfig.headers, body);\n\n // Native fetch compatible settings\n const credentials = requestConfig.withCredentials\n ? 'include'\n : requestConfig.credentials;\n\n // The explicitly passed query params\n const dynamicUrl = replaceUrlPathParams(url, requestConfig.urlPathParams);\n const urlPath = appendQueryParams(dynamicUrl, requestConfig.params);\n const isFullUrl = isAbsoluteUrl(url);\n const baseURL = isFullUrl\n ? ''\n : requestConfig.baseURL || requestConfig.apiUrl || '';\n\n requestConfig.url = baseURL + urlPath;\n requestConfig.method = method;\n requestConfig.credentials = credentials;\n requestConfig.body = body;\n\n return requestConfig;\n}\n\n/**\n * Ensures the `Content-Type` header is set to `application/json; charset=utf-8`\n * if it is not already present and the request method and body meet specific conditions.\n *\n * @param headers - The headers object to modify. Can be an instance of `Headers`\n * or a plain object conforming to `HeadersInit`.\n * @param body - The optional body of the request. If no body is provided and the\n * method is 'GET' or 'HEAD', the function exits without modifying headers.\n */\nfunction setContentTypeIfNeeded(\n headers?: HeadersInit | HeadersObject,\n body?: unknown,\n): void {\n // If no headers are provided, or if the body is not set and the method is PUT or DELETE, do nothing\n if (!headers || !body) {\n return;\n }\n\n // Types that should not have Content-Type set (browser handles these)\n if (\n body instanceof FormData || // Browser automatically sets multipart/form-data with boundary\n (typeof Blob !== UNDEFINED && body instanceof Blob) || // Blob/File already have their own MIME types, don't override\n (typeof File !== UNDEFINED && body instanceof File) ||\n (typeof ReadableStream !== UNDEFINED && body instanceof ReadableStream) // Stream type should be determined by the stream source\n ) {\n return;\n }\n\n let contentTypeValue: string;\n\n if (isSearchParams(body)) {\n contentTypeValue = APPLICATION_CONTENT_TYPE + 'x-www-form-urlencoded';\n } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {\n contentTypeValue = APPLICATION_CONTENT_TYPE + 'octet-stream';\n } else if (isJSONSerializable(body)) {\n contentTypeValue = APPLICATION_JSON + ';' + CHARSET_UTF_8;\n } else {\n // Do not set Content-Type if content is not recognizable\n return;\n }\n\n if (headers instanceof Headers) {\n if (!headers.has(CONTENT_TYPE)) {\n headers.set(CONTENT_TYPE, contentTypeValue);\n }\n } else if (\n isObject(headers) &&\n !Array.isArray(headers) &&\n !headers[CONTENT_TYPE]\n ) {\n headers[CONTENT_TYPE] = contentTypeValue;\n }\n}\n\n/**\n * Merges two request configurations, applying overrides from the second config to the first.\n * Handles special merging for nested properties like 'retry' and 'headers' (deep merge),\n * and concatenates interceptor arrays for 'onRequest', 'onResponse', and 'onError'.\n * If a target config is provided, it mutates that object; otherwise, creates a new one.\n *\n * @param {RequestConfig} baseConfig - The base configuration object to merge from.\n * @param {RequestConfig} overrideConfig - The override configuration object to apply on top of the base.\n * @param {RequestConfig} [targetConfig={}] - Optional target configuration object to merge into (mutated in place).\n * @returns {RequestConfig} The merged configuration object.\n *\n * @example\n * const base = { timeout: 5000, headers: { 'Accept': 'application/json' } };\n * const override = { timeout: 10000, headers: { 'Authorization': 'Bearer token' } };\n * const merged = mergeConfigs(base, override);\n * // Result: { timeout: 10000, headers: { Accept: 'application/json', Authorization: 'Bearer token' } }\n */\nexport function mergeConfigs(\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n targetConfig: RequestConfig = {},\n): RequestConfig {\n Object.assign(targetConfig, baseConfig, overrideConfig);\n\n // Ensure that retry and headers are merged correctly\n mergeConfig('retry', baseConfig, overrideConfig, targetConfig);\n mergeConfig('headers', baseConfig, overrideConfig, targetConfig);\n\n // Merge interceptors efficiently\n mergeInterceptors('onRequest', baseConfig, overrideConfig, targetConfig);\n mergeInterceptors('onResponse', baseConfig, overrideConfig, targetConfig);\n mergeInterceptors('onError', baseConfig, overrideConfig, targetConfig);\n\n return targetConfig;\n}\n\n/**\n * Efficiently merges interceptor functions from base and new configs\n */\nfunction mergeInterceptors<\n K extends 'onRequest' | 'onResponse' | 'onError' | 'onRetry',\n>(\n property: K,\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n targetConfig: RequestConfig,\n): void {\n const baseInterceptor = baseConfig[property];\n const newInterceptor = overrideConfig[property];\n\n if (!baseInterceptor && !newInterceptor) {\n return;\n }\n\n if (!baseInterceptor) {\n targetConfig[property] = newInterceptor;\n return;\n }\n\n if (!newInterceptor) {\n targetConfig[property] = baseInterceptor;\n return;\n }\n\n const baseArr = Array.isArray(baseInterceptor)\n ? baseInterceptor\n : [baseInterceptor];\n const newArr = Array.isArray(newInterceptor)\n ? newInterceptor\n : [newInterceptor];\n\n // This is the only LIFO interceptor, so we apply it after the response is prepared\n targetConfig[property] =\n property === 'onResponse' ? newArr.concat(baseArr) : baseArr.concat(newArr);\n}\n\n/**\n * Merges the specified property from the base configuration and the override configuration into the target configuration.\n *\n * @param {K} property - The property key to merge from the base and override configurations. Must be a key of RequestConfig.\n * @param {RequestConfig} baseConfig - The base configuration object that provides default values.\n * @param {RequestConfig} overrideConfig - The override configuration object that contains user-specific settings to merge.\n * @param {RequestConfig} targetConfig - The configuration object that will receive the merged properties.\n */\nexport function mergeConfig(\n property: K,\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n targetConfig: RequestConfig,\n): void {\n if (overrideConfig[property]) {\n const base = baseConfig[property];\n const override = overrideConfig[property];\n\n // Handle Headers instances which don't expose entries as own enumerable properties\n if (\n property === 'headers' &&\n ((base as Headers | (HeadersObject & HeadersInit)) instanceof Headers ||\n (override as Headers | (HeadersObject & HeadersInit)) instanceof\n Headers)\n ) {\n const baseNormalized = processHeaders(base);\n const overrideNormalized = processHeaders(override);\n targetConfig[property] = {\n ...baseNormalized,\n ...overrideNormalized,\n } as RequestConfig[K];\n } else {\n targetConfig[property] = {\n ...base,\n ...override,\n };\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { hash } from './hash';\nimport type {\n CacheKeyFunction,\n DefaultResponse,\n FetchResponse,\n MutationSettings,\n RequestConfig,\n} from './types/request-handler';\nimport type { CacheEntry } from './types/cache-manager';\nimport { GET, STRING, UNDEFINED } from './constants';\nimport { isObject, sanitizeObject, sortObject, timeNow } from './utils';\nimport { revalidate } from './revalidator-manager';\nimport { notifySubscribers } from './pubsub-manager';\nimport type { DefaultPayload, DefaultParams, DefaultUrlParams } from './types';\nimport { removeInFlight } from './inflight-manager';\nimport { addTimeout } from './timeout-wheel';\nimport { defaultConfig } from './config-handler';\nimport { processHeaders } from './utils';\n\nexport const IMMEDIATE_DISCARD_CACHE_TIME = 0; // Use it for cache entries that need to be persistent until unused by components or manually deleted\n\nconst _cache = new Map>();\nconst DELIMITER = '|';\nconst MIN_LENGTH_TO_HASH = 64;\nconst CACHE_KEY_SANITIZE_PATTERN = /[^\\w\\-_|/:@.?=&~%#]/g;\nconst CACHE_KEY_NEEDS_SANITIZE = /[^\\w\\-_|/:@.?=&~%#]/; // Non-global for fast test\n\n/**\n * Headers that may affect HTTP response content and should be included in cache key generation.\n * All header names must be lowercase to match normalized request headers.\n */\nconst CACHE_KEY_HEADER_WHITELIST = new Set([\n // Content negotiation\n 'accept', // Affects response format (e.g. JSON, HTML)\n 'accept-language', // Affects localization of the response\n 'accept-encoding', // Affects response compression (e.g. gzip, br)\n\n // Authentication\n 'authorization', // Affects access to protected resources\n\n // Request body metadata\n 'content-type', // Affects how the request body is interpreted\n\n // Optional headers\n 'referer', // May influence behavior in some APIs\n 'origin', // Relevant in CORS or tenant-specific APIs\n 'user-agent', // Included only for reason if server returns client-specific content\n\n // Cookies — only if server uses session-based responses\n 'cookie', // Can fragment cache heavily; use only if necessary\n\n // Custom headers that may affect response content\n 'x-api-key', // Token-based access, often affects authorization\n 'x-requested-with', // AJAX requests (used historically for distinguishing frontend calls)\n 'x-client-id', // Per-client/partner identity; often used in multi-tenant APIs\n 'x-tenant-id', // Multi-tenant segmentation; often changes response per tenant\n 'x-user-id', // Explicit user context (less common, but may exist)\n\n 'x-app-version', // Used for version-specific behavior (e.g. mobile apps)\n 'x-feature-flag', // Controls feature rollout behavior server-side\n 'x-device-id', // Used when response varies per device/app instance\n 'x-platform', // e.g. 'ios', 'android', 'web' — used in apps that serve different content\n\n 'x-session-id', // Only if backend uses it to affect the response directly (rare)\n 'x-locale', // Sometimes used in addition to or instead of `accept-language`\n]);\n\n/**\n * Generates a unique cache key for a given URL and fetch options, ensuring that key factors\n * like method, headers, body, and other options are included in the cache key.\n * Headers and other objects are sorted by key to ensure consistent cache keys.\n *\n * @param {RequestConfig} config - The fetch options that may affect the request. The most important are:\n * @property {string} [method=\"GET\"] - The HTTP method (GET, POST, etc.).\n * @property {HeadersInit} [headers={}] - The request headers.\n * @property {BodyInit | null} [body=\"\"] - The body of the request (only for methods like POST, PUT).\n * @property {RequestCredentials} [credentials=\"same-origin\"] - Whether to include credentials (include, same-origin, omit).\n * @property {RequestCache} [cache=\"default\"] - The cache mode (e.g., default, no-store, reload).\n * @returns {string} - A unique cache key string based on the provided options.\n *\n * @example\n * const cacheKey = generateCacheKey({\n * url: 'https://api.example.com/data',\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ name: 'Alice' }),\n * mode: 'cors',\n * credentials: 'include',\n * });\n * console.log(cacheKey);\n */\nexport function generateCacheKey(\n config: RequestConfig,\n cacheKeyCheck = true,\n): string {\n // This is super fast. Effectively a no-op if cacheKey is\n // a string or a function that returns a string.\n const key = config.cacheKey;\n\n if (key && cacheKeyCheck) {\n return typeof key === STRING\n ? (key as string)\n : (key as CacheKeyFunction)(config);\n }\n\n const {\n url = '',\n method = GET,\n headers = null,\n body = null,\n credentials = 'same-origin',\n } = config;\n\n // Sort headers and body + convert sorted to strings for hashing purposes\n // Native serializer is on avg. 3.5x faster than a Fast Hash or FNV-1a\n let headersString = '';\n if (headers) {\n let obj: Record;\n\n if (headers instanceof Headers) {\n obj = processHeaders(headers);\n } else {\n obj = headers as Record;\n }\n\n // Filter headers to only include those that affect request identity\n // Include only headers that affect request identity, not execution behavior\n const keys = Object.keys(obj);\n const len = keys.length;\n\n // Sort keys manually for fastest deterministic output\n if (len > 1) {\n keys.sort();\n }\n\n let str = '';\n for (let i = 0; i < len; ++i) {\n if (CACHE_KEY_HEADER_WHITELIST.has(keys[i].toLowerCase())) {\n str += keys[i] + ':' + obj[keys[i]] + ';';\n }\n }\n\n headersString = hash(str);\n }\n\n // For GET requests, return early with shorter cache key\n if (method === GET) {\n const cacheStr =\n method +\n DELIMITER +\n url +\n DELIMITER +\n credentials +\n DELIMITER +\n headersString;\n\n return CACHE_KEY_NEEDS_SANITIZE.test(cacheStr)\n ? cacheStr.replace(CACHE_KEY_SANITIZE_PATTERN, '')\n : cacheStr;\n }\n\n let bodyString = '';\n if (body) {\n if (typeof body === STRING) {\n bodyString = body.length < MIN_LENGTH_TO_HASH ? body : hash(body); // hash only if large\n } else if (body instanceof FormData) {\n body.forEach((value, key) => {\n // Append key=value and '&' directly to the result\n bodyString += key + '=' + value + '&';\n });\n\n if (bodyString.length > MIN_LENGTH_TO_HASH) {\n bodyString = hash(bodyString);\n }\n } else if (\n (typeof Blob !== UNDEFINED && body instanceof Blob) ||\n (typeof File !== UNDEFINED && body instanceof File)\n ) {\n bodyString = 'BF' + body.size + body.type;\n } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {\n bodyString = 'AB' + body.byteLength;\n } else {\n const o = isObject(body)\n ? JSON.stringify(sortObject(body))\n : String(body);\n\n bodyString = o.length > MIN_LENGTH_TO_HASH ? hash(o) : o;\n }\n }\n\n // Concatenate all key parts into a cache key string\n // Template literals are apparently slower\n const cacheStr =\n method +\n DELIMITER +\n url +\n DELIMITER +\n credentials +\n DELIMITER +\n headersString +\n DELIMITER +\n bodyString;\n\n // Prevent cache poisoning by removal of control chars and unusual characters\n return CACHE_KEY_NEEDS_SANITIZE.test(cacheStr)\n ? cacheStr.replace(CACHE_KEY_SANITIZE_PATTERN, '')\n : cacheStr;\n}\n\n/**\n * Checks if the cache entry is expired based on its timestamp and the expiry time.\n *\n * @param {CacheEntry} entry - The cache entry to check.\n * @returns {boolean} - Returns true if the cache entry is expired, false otherwise.\n */\nfunction isCacheExpired(entry: CacheEntry): boolean {\n // No expiry time means the entry never expires\n if (!entry.expiry) {\n return false;\n }\n\n return timeNow() > entry.expiry;\n}\n\n/**\n * Retrieves a cached response from the internal cache using the provided key.\n *\n * @param key - The unique key identifying the cached entry. If null, returns null.\n * @returns The cached {@link FetchResponse} if found, otherwise null.\n */\nexport function getCacheData<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n key: string | null,\n): FetchResponse | null {\n if (!key) {\n return null;\n }\n\n const entry = _cache.get(key);\n\n return entry ? entry.data : null;\n}\n\n/**\n * Retrieves a cache entry if it exists and is not expired.\n *\n * @param {string} key Cache key to utilize\n * @returns {CacheEntry | null} - The cache entry if it exists and is not expired, null otherwise.\n */\nexport function getCache(\n key: string | null,\n):\n | CacheEntry<\n FetchResponse\n >\n | null\n | undefined {\n return _cache.get(key as string);\n}\n\n/**\n * Sets a new cache entry or updates an existing one, with optional TTL (time-to-live).\n *\n * @param {string} key Cache key to utilize\n * @param {T} data - The data to be cached.\n * @param {number} [ttl] - Optional TTL in seconds. If not provided, the cache entry will not expire.\n * @param {number} [staleTime] - Optional stale time in seconds. If provided, the cache entry will be considered stale after this time.\n */\nexport function setCache(\n key: string,\n data: T,\n ttl?: number,\n staleTime?: number,\n): void {\n if (ttl === 0) {\n deleteCache(key);\n return;\n }\n\n const time = timeNow();\n const ttlMs = ttl ? ttl * 1000 : 0;\n const staleTimeMs = staleTime ? staleTime * 1000 : 0; // Ensure default value for staleTime\n\n _cache.set(key, {\n data,\n time,\n stale: staleTimeMs > 0 ? time + staleTimeMs : undefined, // Use undefined if staleTime is not set\n expiry: ttl === -1 ? undefined : time + ttlMs,\n });\n\n if (ttlMs > 0) {\n addTimeout(\n 'c:' + key,\n () => {\n deleteCache(key, true);\n },\n ttlMs,\n );\n }\n}\n\n/**\n * Invalidates (deletes) a cache entry.\n *\n * @param {string} key Cache key to utilize\n * @param {boolean} [removeExpired=false] - If true, only deletes the cache entry if it is expired or stale.\n */\nexport function deleteCache(key: string, removeExpired: boolean = false): void {\n if (removeExpired) {\n const entry = getCache(key);\n\n // If the entry does not exist, or it is neither expired nor stale, do not delete\n if (!entry || !isCacheExpired(entry)) {\n return;\n }\n }\n\n _cache.delete(key);\n}\n\n/**\n * Prunes the cache by removing entries that have expired based on the provided cache time.\n */\nexport function pruneCache(): void {\n _cache.clear();\n}\n\n/**\n * Mutates a cache entry with new data and optionally revalidates it.\n *\n * @param {string | null} key Cache key to utilize. If null, no mutation occurs.\n * @param {ResponseData} newData - The new data to be cached.\n * @param {MutationSettings|undefined} settings - Mutation settings.\n */\nexport async function mutate<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n key: string | null,\n newData: ResponseData,\n settings?: MutationSettings,\n): Promise | null> {\n // If no key is provided, do nothing\n if (!key) {\n return null;\n }\n\n const entry = getCache(\n key,\n );\n\n if (!entry) {\n return null;\n }\n\n const updatedData = isObject(newData) ? sanitizeObject(newData) : newData;\n\n const updatedResponse = {\n ...entry.data,\n data: updatedData,\n };\n\n const updatedEntry = {\n ...entry,\n data: updatedResponse,\n };\n\n _cache.set(key, updatedEntry);\n notifySubscribers(key, updatedResponse);\n\n if (settings && settings.refetch) {\n return await revalidate(key);\n }\n\n return null;\n}\n\n/**\n * Retrieves a cached response if available and valid, otherwise returns null.\n *\n * @template ResponseData - The type of the response data.\n * @template RequestBody - The type of the request body.\n * @template QueryParams - The type of the query parameters.\n * @template PathParams - The type of the path parameters.\n * @param {string | null} cacheKey - The cache key to look up.\n * @param {number | undefined} cacheTime - The maximum time to cache entry.\n * @param {RequestConfig} requestConfig - The fetcher configuration.\n * @returns {FetchResponse | null} - The cached response or null.\n */\nexport function getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n cacheKey: string | null,\n cacheTime: number | undefined,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): FetchResponse | null {\n // If cache key or time is not provided, return null\n if (!cacheKey || cacheTime === undefined || cacheTime === null) {\n return null;\n }\n\n // Check if cache should be bypassed\n const buster = requestConfig.cacheBuster || defaultConfig.cacheBuster;\n if (buster && buster(requestConfig)) {\n return null;\n }\n\n if (requestConfig.cache && requestConfig.cache === 'reload') {\n return null; // Skip cache lookup entirely\n }\n\n // Retrieve the cached entry\n const entry = getCache(\n cacheKey,\n );\n\n if (!entry) {\n return null;\n }\n\n const isExpired = isCacheExpired(entry);\n\n // If completely expired, delete and return null\n if (isExpired) {\n deleteCache(cacheKey);\n return null;\n }\n\n // Return data whether fresh or stale (SWR: serve stale, revalidation is timer-driven)\n return entry.data;\n}\n\n/**\n * Sets or deletes the response cache based on cache settings and notifies subscribers.\n *\n * @param {FetchResponse} output - The response to cache.\n * @param {RequestConfig} requestConfig - The request configuration.\n * @param {boolean} [isError=false] - Whether the response is an error.\n */\nexport function handleResponseCache<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n output: FetchResponse,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n isError: boolean = false,\n): void {\n // It is string as it is called once request is made\n const cacheKey = requestConfig.cacheKey as string;\n\n if (cacheKey) {\n const cacheTime = requestConfig.cacheTime;\n const skipCache = requestConfig.skipCache;\n\n // Fast path: only set cache if cacheTime is positive and not skipping cache\n if (\n cacheTime &&\n (!isError || requestConfig.cacheErrors) &&\n !(skipCache && skipCache(output, requestConfig))\n ) {\n setCache(cacheKey, output, cacheTime, requestConfig.staleTime);\n }\n\n notifySubscribers(cacheKey, output);\n removeInFlight(cacheKey);\n\n const prevCacheKey = requestConfig._prevKey;\n\n if (prevCacheKey) {\n removeInFlight(prevCacheKey);\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { mutate } from './cache-manager';\nimport {\n APPLICATION_CONTENT_TYPE,\n APPLICATION_JSON,\n CONTENT_TYPE,\n FUNCTION,\n OBJECT,\n STRING,\n} from './constants';\nimport {\n DefaultResponse,\n FetchResponse,\n RequestConfig,\n ResponseError,\n DefaultParams,\n DefaultUrlParams,\n DefaultPayload,\n} from './types';\nimport { flattenData, isObject, processHeaders } from './utils';\n\n/**\n * Parses the response data based on the Content-Type header.\n *\n * @param response - The Response object to parse.\n * @returns A Promise that resolves to the parsed data.\n */\nexport async function parseResponseData<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n response: FetchResponse,\n): Promise {\n // Bail early if response is null or undefined\n if (!response) {\n return null;\n }\n\n // Get the content-type header once\n let contentType = (response as Response).headers?.get(CONTENT_TYPE);\n\n if (contentType) {\n // Lowercase and trim for consistent matching\n contentType = contentType.toLowerCase().trim();\n } else {\n contentType = '';\n }\n\n // Split for mime type without charset\n const mimeType = contentType.split(';', 1)[0];\n\n let data;\n\n try {\n if (mimeType.includes(APPLICATION_JSON) || mimeType.includes('+json')) {\n data = await response.json(); // Parse JSON response\n } else if (\n (mimeType.includes('multipart/form-data') || // Parse as FormData\n mimeType.includes(\n APPLICATION_CONTENT_TYPE + 'x-www-form-urlencoded', // Handle URL-encoded forms\n )) &&\n typeof response.formData === FUNCTION\n ) {\n data = await response.formData();\n } else if (\n mimeType.includes(APPLICATION_CONTENT_TYPE + 'octet-stream') &&\n typeof response.blob === FUNCTION\n ) {\n data = await response.blob(); // Parse as blob\n } else {\n data = await response.text();\n\n if (typeof data === STRING) {\n const trimmed = data.trim();\n if (\n (trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))\n ) {\n try {\n data = JSON.parse(trimmed);\n } catch {\n // leave as text if parsing fails\n }\n }\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (_error) {\n // Parsing failed, fallback to null\n data = null;\n }\n\n return data;\n}\n\n/**\n * Prepare response object with additional information.\n *\n * @param Response. It may be \"null\" in case of request being aborted.\n * @param {RequestConfig} config - Request config\n * @param error - whether the response is erroneous\n * @returns {FetchResponse} Response data\n */\nexport const prepareResponse = <\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n config: RequestConfig,\n error: ResponseError<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null = null,\n): FetchResponse => {\n const defaultResponse = config.defaultResponse;\n const cacheKey = config.cacheKey;\n const mutatator = mutate.bind(null, cacheKey as string) as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >['mutate'];\n\n // This may happen when request is cancelled.\n if (!response) {\n return {\n ok: false,\n // Enhance the response with extra information\n error,\n data: defaultResponse ?? null,\n headers: null,\n config,\n mutate: mutatator,\n isFetching: false,\n isSuccess: false,\n isError: true,\n } as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }\n\n const isNativeResponse =\n typeof Response === FUNCTION && response instanceof Response;\n\n let data = response.data;\n\n // Set the default response if the provided data is an empty object\n if (\n defaultResponse !== undefined &&\n (data === undefined ||\n data === null ||\n (typeof data === OBJECT && Object.keys(data).length === 0))\n ) {\n response.data = data = defaultResponse;\n }\n\n if (config.flattenResponse) {\n response.data = data = flattenData(data);\n }\n\n if (config.select) {\n response.data = data = config.select(data);\n }\n\n const headers = processHeaders(response.headers);\n\n // Native fetch Response extended by extra information\n if (isNativeResponse) {\n return {\n body: response.body,\n bodyUsed: response.bodyUsed,\n ok: response.ok,\n redirected: response.redirected,\n type: response.type,\n url: response.url,\n status: response.status,\n statusText: response.statusText,\n\n // Convert methods to use arrow functions to preserve correct return types\n blob: () => response.blob(),\n json: () => response.json(),\n text: () => response.text(),\n clone: () => response.clone(),\n arrayBuffer: () => response.arrayBuffer(),\n formData: () => response.formData(),\n bytes: () => response.bytes(),\n\n // Enhance the response with extra information\n error,\n data,\n headers,\n config,\n mutate: mutatator,\n isFetching: false,\n isSuccess: response.ok && !error,\n isError: !!error,\n };\n }\n\n // If it's a custom fetcher, and it does not return any Response instance, it may have its own internal handler\n if (isObject(response)) {\n response.error = error;\n response.headers = headers;\n response.isFetching = false;\n response.mutate = mutatator;\n response.isSuccess = response.ok && !error;\n response.isError = !!error;\n }\n\n return response;\n};\n","import { applyInterceptors } from './interceptor-manager';\nimport type { FetchResponse, RetryConfig, RetryFunction } from './types';\nimport { delayInvocation, timeNow } from './utils';\nimport { generateCacheKey } from './cache-manager';\n\nfunction getMsFromHttpDate(dateString: string): number | null {\n const ms = Date.parse(dateString) - timeNow();\n\n if (!isNaN(ms)) {\n return Math.max(0, Math.floor(ms));\n }\n return null;\n}\n\n/**\n * Calculates the number of milliseconds to wait before retrying a request,\n * based on the `Retry-After` HTTP header in the provided response.\n *\n * The function supports both numeric (seconds) and HTTP-date formats for the `Retry-After` header.\n * - If the header is a number, it is interpreted as seconds and converted to milliseconds.\n * - If the header is a date, the function calculates the difference between the date and the current time.\n *\n * @param extendedResponse - The response object containing headers, or `null`.\n * @returns The number of milliseconds to wait before retrying, or `null` if the header is not present or invalid.\n */\nexport function getRetryAfterMs(\n extendedResponse: FetchResponse | null,\n): number | null {\n if (!extendedResponse) {\n return null;\n }\n\n const headers = extendedResponse.headers || {};\n const retryAfter = headers['retry-after'];\n\n if (retryAfter) {\n // Try parsing as seconds\n const seconds = Number(retryAfter);\n\n if (!isNaN(seconds) && seconds >= 0) {\n return seconds * 1000;\n }\n\n const ms = getMsFromHttpDate(retryAfter);\n\n if (ms !== null) {\n return ms;\n }\n }\n\n // Headers are already in lowercase\n const RATELIMIT_RESET = 'ratelimit-reset';\n\n // Unix timestamp when the rate limit window resets (relative to current time)\n // Fallback to checking 'ratelimit-reset-after' OR 'x-ratelimit-reset-after' headers\n const rateLimitResetAfter =\n headers[RATELIMIT_RESET + '-after'] ||\n headers['x-' + RATELIMIT_RESET + '-after'];\n\n if (rateLimitResetAfter) {\n const seconds = Number(rateLimitResetAfter);\n\n if (!isNaN(seconds)) {\n return seconds * 1000;\n }\n }\n\n // ISO 8601 datetime when the rate limit resets\n // Fallback to checking 'ratelimit-reset-at' 'x-ratelimit-reset-at' headers\n const rateLimitResetAt =\n headers[RATELIMIT_RESET + '-at'] || headers['x-' + RATELIMIT_RESET + '-at'];\n\n if (rateLimitResetAt) {\n return getMsFromHttpDate(rateLimitResetAt);\n }\n\n return null;\n}\n\n/**\n * Executes a request function with retry logic according to the provided configuration.\n *\n * The function attempts the request up to the specified number of retries, applying delay and backoff strategies.\n * Retries can be triggered based on response status codes, custom logic, or the presence of a `Retry-After` header.\n * Optionally, an `onRetry` interceptor can be invoked before each retry attempt.\n *\n * @typeParam ResponseData - The type of the response data.\n * @typeParam RequestBody - The type of the request body.\n * @typeParam QueryParams - The type of the query parameters.\n * @typeParam PathParams - The type of the path parameters.\n * @param requestFn - The function that performs the request. Receives `isStaleRevalidation` and `attempt` as arguments.\n * @param config - The retry configuration, including retry count, delay, backoff, retry conditions, and hooks.\n * @returns A promise resolving to the fetch response, or rejecting if all retries are exhausted.\n * @throws Error if the maximum number of retries is exceeded or a non-retriable error occurs.\n */\nexport async function withRetry<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n requestFn: (\n isStaleRevalidation: boolean,\n attempt: number,\n ) => Promise<\n FetchResponse\n >,\n config: RetryConfig,\n): Promise> {\n const {\n retries = 0,\n delay = 0,\n backoff = 1,\n maxDelay,\n retryOn = [],\n shouldRetry,\n } = config;\n\n let attempt = 0;\n let waitTime = delay;\n const maxRetries = retries > 0 ? retries : 0;\n let output: FetchResponse;\n\n while (attempt <= maxRetries) {\n // Subsequent attempts will have output defined, but the first attempt may not.\n // Let's apply onRetry interceptor and regenerate cache key if ot really changes.\n if (attempt > 0 && output!) {\n const cfg = output.config;\n const onRetry = cfg.onRetry;\n\n if (onRetry) {\n await applyInterceptors(onRetry, output, attempt);\n\n // If the key was automatically generated, we need to regenerate it as config may change.\n // We don't detect whether config changed for performance reasons.\n if (cfg._isAutoKey) {\n cfg._prevKey = cfg.cacheKey as string;\n cfg.cacheKey = generateCacheKey(cfg, false);\n }\n }\n }\n\n // Performance optimization: Call the request function with the current attempt number\n // If this is the first attempt, we pass `isStaleRevalidation` as `false`,\n // otherwise we pass `true` to indicate that this is a stale revalidation (no cache hit).\n output = await requestFn(attempt > 0, attempt);\n const error = output.error;\n\n // Check if we should retry based on successful response\n if (!error) {\n if (shouldRetry && attempt < maxRetries) {\n const shouldRetryResult = await shouldRetry(output, attempt);\n\n if (shouldRetryResult) {\n await delayInvocation(waitTime);\n waitTime *= backoff || 1;\n waitTime = Math.min(waitTime, maxDelay || waitTime);\n attempt++;\n continue;\n }\n }\n\n break;\n }\n\n // Determine if we should stop retrying\n const shouldStopRetrying = await getShouldStopRetrying(\n output,\n attempt,\n maxRetries,\n shouldRetry,\n retryOn,\n );\n\n if (shouldStopRetrying) {\n break;\n }\n\n // If we should not stop retrying, continue to the next attempt\n // Handle rate limiting if the error status is 429 (Too Many Requests) or 503 (Service Unavailable)\n if (error.status === 429 || error.status === 503) {\n // Try to extract the \"Retry-After\" value from the response headers\n const retryAfterMs = getRetryAfterMs(output);\n\n // If a valid retry-after value is found, override the wait time before next retry\n if (retryAfterMs !== null) {\n waitTime = retryAfterMs;\n }\n }\n\n await delayInvocation(waitTime);\n waitTime *= backoff || 1;\n waitTime = Math.min(waitTime, maxDelay || waitTime);\n attempt++;\n }\n\n return output!;\n}\n\n/**\n * Determines whether to stop retrying based on the error, current attempt count, and retry configuration.\n *\n * This function checks:\n * - If the maximum number of retries has been reached.\n * - If a custom `shouldRetry` callback is provided, its result is used to decide.\n * - If no custom logic is provided, falls back to checking if the error status is included in the `retryOn` list.\n *\n * @typeParam ResponseData - The type of the response data.\n * @typeParam RequestBody - The type of the request body.\n * @typeParam QueryParams - The type of the query parameters.\n * @typeParam PathParams - The type of the path parameters.\n * @param output - The response object containing the error and request configuration.\n * @param attempt - The current retry attempt number.\n * @param maxRetries - The maximum number of retry attempts allowed.\n * @param shouldRetry - Optional custom function to determine if a retry should occur.\n * @param retryOn - Optional list of HTTP status codes that should trigger a retry.\n * @returns A promise resolving to `true` if retrying should stop, or `false` to continue retrying.\n */\nexport async function getShouldStopRetrying<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n output: FetchResponse,\n attempt: number,\n maxRetries: number,\n shouldRetry?: RetryFunction<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n retryOn: number[] = [],\n): Promise {\n // Safety first: always respect max retries\n // We check retries provided regardless of the shouldRetry being provided so to avoid infinite loops.\n // It is a fail-safe so to prevent excessive retry attempts even if custom retry logic suggests a retry.\n if (attempt === maxRetries) {\n return true;\n }\n\n let customDecision: boolean | null = null;\n\n // Get custom decision if shouldRetry is provided\n if (shouldRetry) {\n const result = await shouldRetry(output, attempt);\n customDecision = result;\n\n // Decision cascade:\n if (customDecision !== null) {\n return !customDecision;\n }\n }\n\n return !(retryOn || []).includes(output.error?.status ?? 0);\n}\n","import type { RequestConfig, FetchResponse } from './types';\nimport { delayInvocation } from './utils';\n\n/**\n * Executes a request function with polling, stopping when shouldStopPolling returns true,\n * pollingInterval is not set, or maxAttempts is reached.\n *\n * @template Output The type of the output returned by the request function.\n * @param requestFn - The function that performs a single request (with retries).\n * @param pollingInterval - Interval in ms between polling attempts.\n * @param shouldStopPolling - Function to determine if polling should stop.\n * @param maxAttempts - Maximum number of polling attempts, default: 0 (unlimited).\n * @param pollingDelay - Delay in ms before each polling attempt, default: 0.\n * @returns The final output from the last request.\n */\nexport async function withPolling<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n requestFn: (\n isStaleRevalidation?: boolean,\n attempt?: number,\n ) => Promise<\n FetchResponse\n >,\n pollingInterval?: RequestConfig['pollingInterval'],\n shouldStopPolling?: RequestConfig['shouldStopPolling'],\n maxAttempts = 0,\n pollingDelay = 0,\n): Promise> {\n if (!pollingInterval) {\n return requestFn();\n }\n\n let pollingAttempt = 0;\n let output: FetchResponse;\n\n while (maxAttempts === 0 || pollingAttempt < maxAttempts) {\n if (pollingDelay > 0) {\n await delayInvocation(pollingDelay);\n }\n\n output = await requestFn();\n\n pollingAttempt++;\n\n if (\n (maxAttempts > 0 && pollingAttempt >= maxAttempts) ||\n !pollingInterval ||\n (shouldStopPolling && shouldStopPolling(output, pollingAttempt))\n ) {\n break;\n }\n\n await delayInvocation(pollingInterval);\n }\n\n return output!;\n}\n","import type { ResponseError } from './errors/response-error';\nimport type {\n DefaultResponse,\n FetchResponse,\n RequestConfig,\n} from './types/request-handler';\nimport { applyInterceptors } from './interceptor-manager';\nimport { handleResponseCache } from './cache-manager';\nimport { ABORT_ERROR, REJECT } from './constants';\nimport { DefaultParams, DefaultUrlParams, DefaultPayload } from './types';\n\n/**\n * Handles final processing for both success and error responses\n * Applies error interceptors, caching, notifications, and error strategy\n */\nexport async function withErrorHandling<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n isStaleRevalidation: boolean,\n requestFn: (\n isStaleRevalidation: boolean,\n ) => Promise<\n FetchResponse\n >,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): Promise> {\n const output = await requestFn(isStaleRevalidation);\n const error = output.error;\n\n if (!error) {\n // SUCCESS PATH\n handleResponseCache(output, requestConfig);\n\n return output;\n }\n\n // ERROR PATH\n\n if (requestConfig.onError) {\n await applyInterceptors(requestConfig.onError, error);\n }\n\n // Timeouts and request cancellations using AbortController do not throw any errors unless rejectCancelled is true.\n // Only handle the error if the request was not cancelled, or if it was cancelled and rejectCancelled is true.\n const isCancelled = error.isCancelled;\n\n if (!isCancelled && requestConfig.logger) {\n logger(requestConfig, 'FETCH ERROR', error as ResponseError);\n }\n\n // Handle cache and notifications FIRST (before strategy)\n handleResponseCache(output, requestConfig, true);\n\n // handle error strategy as the last part\n const shouldHandleError = !isCancelled || requestConfig.rejectCancelled;\n\n if (shouldHandleError) {\n const strategy = requestConfig.strategy;\n // Reject the promise\n if (strategy === REJECT) {\n return Promise.reject(error);\n }\n\n // Hang the promise\n if (strategy === 'silent') {\n await new Promise(() => null);\n }\n }\n\n return output;\n}\n\nexport function enhanceError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n error: any,\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): void {\n error.status = error.status || response?.status || 0;\n error.statusText = error.statusText || response?.statusText || '';\n error.config = error.request = requestConfig;\n error.response = response;\n error.isCancelled = error.name === ABORT_ERROR;\n}\n\n/**\n * Logs messages or errors using the configured logger's `warn` method.\n *\n * @param {RequestConfig} reqConfig - Request config passed when making the request\n * @param {...(string | ResponseError)} args - Messages or errors to log.\n */\nfunction logger(\n reqConfig: RequestConfig,\n ...args: (string | ResponseError)[]\n): void {\n const logger = reqConfig.logger;\n\n if (logger && logger.warn) {\n logger.warn(...args);\n }\n}\n","import type {\n DefaultResponse,\n RequestConfig,\n FetchResponse,\n} from './types/request-handler';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultUrlParams,\n} from './types/api-handler';\nimport { applyInterceptors } from './interceptor-manager';\nimport { ResponseError } from './errors/response-error';\nimport { isObject } from './utils';\nimport {\n markInFlight,\n setInFlightPromise,\n getInFlightPromise,\n} from './inflight-manager';\nimport { parseResponseData, prepareResponse } from './response-parser';\nimport { generateCacheKey, getCachedResponse, setCache } from './cache-manager';\nimport { withRetry } from './retry-handler';\nimport { withPolling } from './polling-handler';\nimport { notifySubscribers } from './pubsub-manager';\nimport { addRevalidator } from './revalidator-manager';\nimport { enhanceError, withErrorHandling } from './error-handler';\nimport { FUNCTION } from './constants';\nimport { buildConfig } from './config-handler';\n\nconst inFlightResponse = Object.freeze({\n isFetching: true,\n});\n\n/**\n * Sends an HTTP request to the specified URL using the provided configuration and returns a typed response.\n *\n * @typeParam ResponseData - The expected shape of the response data. Defaults to `DefaultResponse`.\n * @typeParam RequestBody - The type of the request payload/body. Defaults to `DefaultPayload`.\n * @typeParam QueryParams - The type of the query parameters. Defaults to `DefaultParams`.\n * @typeParam PathParams - The type of the path parameters. Defaults to `DefaultUrlParams`.\n *\n * @param url - The endpoint URL to which the request will be sent.\n * @param config - Optional configuration object for the request, including headers, method, body, query, and path parameters.\n *\n * @returns A promise that resolves to a `FetchResponse` containing the typed response data and request metadata.\n *\n * @example\n * ```typescript\n * const { data } = await fetchf('/api/user', { method: 'GET' });\n * console.log(data);\n * ```\n */\nexport async function fetchf<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n url: string,\n reqConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > | null = null,\n): Promise> {\n // Ultra-fast early cache check if cacheKey is provided as a string\n // For workloads dominated by repeated requests, this string caching optimization\n // can potentially support millions of requests per second with minimal CPU overhead\n if (reqConfig && typeof reqConfig.cacheKey === 'string') {\n const cached = getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(reqConfig.cacheKey, reqConfig.cacheTime, reqConfig);\n\n if (cached) {\n return cached;\n }\n }\n\n const fetcherConfig = buildConfig<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(url, reqConfig);\n\n const {\n timeout,\n cancellable,\n cacheKey,\n dedupeTime,\n cacheTime,\n staleTime,\n refetchOnFocus,\n refetchOnReconnect,\n pollingInterval = 0,\n } = fetcherConfig;\n const isCacheEnabled = cacheTime !== undefined || staleTime !== undefined;\n\n const needsCacheKey = !!(\n cacheKey ||\n timeout ||\n dedupeTime ||\n isCacheEnabled ||\n cancellable ||\n refetchOnFocus ||\n refetchOnReconnect\n );\n\n let _cacheKey: string | null = null;\n\n // Generate cache key if required\n if (needsCacheKey) {\n _cacheKey = generateCacheKey(fetcherConfig);\n }\n\n // Cache handling logic\n if (_cacheKey && isCacheEnabled) {\n const cached = getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(_cacheKey, cacheTime, fetcherConfig);\n\n if (cached) {\n return cached;\n }\n }\n\n // Deduplication logic\n if (_cacheKey && dedupeTime) {\n const inflight = getInFlightPromise<\n FetchResponse\n >(_cacheKey, dedupeTime);\n\n if (inflight) {\n return inflight;\n }\n }\n\n const retryConfig = fetcherConfig.retry || {};\n const { retries = 0, resetTimeout } = retryConfig;\n\n // The actual request logic as a function (one poll attempt, with retries)\n const doRequestOnce = async (isStaleRevalidation = false, attempt = 0) => {\n // If cache key is specified, we will handle optimistic updates\n // and mark the request as in-flight, so to catch \"fetching\" state.\n // This is useful for Optimistic UI updates (e.g., showing loading spinners).\n if (!attempt) {\n if (_cacheKey && !isStaleRevalidation) {\n if (staleTime) {\n const existingCache = getCachedResponse(\n _cacheKey,\n cacheTime,\n fetcherConfig,\n );\n\n // Don't notify subscribers when cache exists\n // Let them continue showing stale data during background revalidation\n if (!existingCache) {\n setCache(_cacheKey, inFlightResponse, cacheTime, staleTime);\n notifySubscribers(_cacheKey, inFlightResponse);\n }\n } else {\n notifySubscribers(_cacheKey, inFlightResponse);\n }\n }\n\n // Attach cache key so that it can be reused in interceptors or in the final response\n fetcherConfig.cacheKey = _cacheKey;\n }\n\n const url = fetcherConfig.url as string;\n\n // Add the request to the queue. Make sure to handle deduplication, cancellation, timeouts in accordance to retry settings\n const controller = markInFlight(\n _cacheKey,\n url,\n timeout,\n dedupeTime || 0,\n !!cancellable,\n // Enable timeout either by default or when retries & resetTimeout are enabled\n !!(timeout && (!attempt || resetTimeout)),\n );\n\n // Do not create a shallow copy to maintain idempotency here.\n // This ensures the original object is mutated by interceptors whenever needed, including retry logic.\n const requestConfig = fetcherConfig;\n\n requestConfig.signal = controller.signal;\n\n let output: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n let response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null = null;\n\n try {\n if (fetcherConfig.onRequest) {\n // Zero-allocation yield to microtask queue so the outer fetchf() can call setInFlightPromise()\n // before onRequest interceptors run. This ensures that if onRequest triggers\n // another fetchf() with the same cacheKey, getInFlightPromise() finds item[4].\n // On retries (attempt > 0), setInFlightPromise() was already called during the first attempt.\n // The promise stored in item[4] is the outer doRequestPromise which covers all retries.\n // So the race only matters on the very first attempt when the outer scope hasn't had a chance to call setInFlightPromise() yet.\n if (_cacheKey && dedupeTime && !attempt) {\n await null;\n }\n\n await applyInterceptors(fetcherConfig.onRequest, requestConfig);\n }\n\n // Custom fetcher\n const fn = fetcherConfig.fetcher;\n\n response = (fn\n ? await fn(\n url,\n requestConfig,\n )\n : await fetch(\n url,\n requestConfig as RequestInit,\n )) as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n\n // Custom fetcher may return a raw data object instead of a Response instance\n if (isObject(response)) {\n // Case 1: Native Response instance\n if (typeof Response === FUNCTION && response instanceof Response) {\n response.data = await parseResponseData(response);\n } else if (fn) {\n // Case 2: Custom fetcher that returns a response object\n if (!('data' in response && 'body' in response)) {\n // Case 3: Raw data, wrap it\n response = { data: response } as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }\n }\n\n // Attach config and data to the response\n // This is useful for custom fetchers that do not return a Response instance\n // and for interceptors that may need to access the request config\n response.config = requestConfig;\n\n // Check if the response status is not outside the range 200-299 and if so, output error\n // This is the pattern for fetch responses as per spec, but custom fetchers may not follow it so we check for `ok` property\n if (response.ok !== undefined && !response.ok) {\n throw new ResponseError(\n `${requestConfig.method} to ${url} failed! Status: ${response.status || null}`,\n requestConfig,\n response,\n );\n }\n }\n\n output = prepareResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(response, requestConfig);\n\n const onResponse = fetcherConfig.onResponse;\n\n if (onResponse) {\n await applyInterceptors(onResponse, output);\n }\n } catch (_error) {\n const error = _error as ResponseError<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n\n // Append additional information to Network, CORS or any other fetch() errors\n enhanceError(\n error,\n response,\n requestConfig,\n );\n\n // Prepare Extended Response\n output = prepareResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(response, requestConfig, error);\n }\n\n return output;\n };\n\n // Inline and minimize function wrappers for performance\n // When retries are enabled, forward isStaleRevalidation so the first attempt\n // of a background SWR revalidation doesn't incorrectly mark the request as in-flight\n const baseRequest =\n retries > 0\n ? (isStaleRevalidation = false) =>\n withRetry(\n (_, attempt) => doRequestOnce(isStaleRevalidation, attempt),\n retryConfig,\n )\n : doRequestOnce;\n\n const requestWithErrorHandling = (isStaleRevalidation = false) =>\n withErrorHandling(\n isStaleRevalidation,\n baseRequest,\n fetcherConfig,\n );\n\n // Avoid unnecessary function wrapping if polling is not enabled\n const doRequestPromise = pollingInterval\n ? withPolling(\n requestWithErrorHandling,\n pollingInterval,\n fetcherConfig.shouldStopPolling,\n fetcherConfig.maxPollingAttempts,\n fetcherConfig.pollingDelay,\n )\n : requestWithErrorHandling();\n\n // If deduplication is enabled, store the in-flight promise immediately\n if (_cacheKey) {\n if (dedupeTime) {\n setInFlightPromise(_cacheKey, doRequestPromise);\n }\n\n // Only register revalidator when revalidation features are actually requested\n if (staleTime || refetchOnFocus || refetchOnReconnect) {\n addRevalidator(\n _cacheKey,\n requestWithErrorHandling,\n undefined,\n staleTime,\n requestWithErrorHandling,\n !!refetchOnFocus,\n !!refetchOnReconnect,\n );\n }\n }\n\n return doRequestPromise;\n}\n","import type {\n ApiHandlerConfig,\n ApiHandlerDefaultMethods,\n ApiHandlerMethods,\n RequestConfigUrlRequired,\n} from './types/api-handler';\nimport { fetchf } from '.';\nimport { mergeConfigs } from './config-handler';\nimport { isAbsoluteUrl } from './utils';\n\n/**\n * Creates an instance of API Handler.\n * It creates an API fetcher function using native fetch() or a custom fetcher if passed as \"fetcher\".\n * @see https://github.com/MattCCC/fetchff#configuration\n *\n * @param {Object} config - Configuration object for the API fetcher (see link above for full options).\n * @param {Object} config.endpoints - An object containing endpoint definitions.\n * @param {string} [config.baseURL] - The base URL for the API.\n * @param {Object} [config.headers] - Optional default headers to include in every request.\n * @param {Function} [config.onError] - Optional callback function for handling errors.\n * @returns API handler functions and endpoints to call\n *\n * @example\n * // Define endpoint paths\n * const endpoints = {\n * getUser: '/user',\n * createPost: '/post',\n * };\n *\n * // Create the API fetcher with configuration\n * const api = createApiFetcher({\n * endpoints,\n * apiUrl: 'https://example.com/api',\n * onError(error) {\n * console.log('Request failed', error);\n * },\n * headers: {\n * 'my-auth-key': 'example-auth-key-32rjjfa',\n * },\n * });\n *\n * // Fetch user data\n * const response = await api.getUser({ userId: 1, ratings: [1, 2] })\n */\nfunction createApiFetcher<\n EndpointTypes extends object,\n EndpointsSettings = never,\n>(config: ApiHandlerConfig) {\n const endpoints = config.endpoints;\n\n /**\n * Triggered when trying to use non-existent endpoints\n *\n * @param endpointName Endpoint Name\n * @returns {Promise}\n */\n function handleNonImplemented(endpointName: string): Promise {\n console.error(`Add ${endpointName} to 'endpoints'.`);\n\n return Promise.resolve(null);\n }\n\n const apiHandler: ApiHandlerDefaultMethods = {\n config,\n endpoints,\n /**\n * Handle Single API Request\n * It considers settings in following order: per-request settings, global per-endpoint settings, global settings.\n *\n * @param endpointName - The name of the API endpoint to call.\n * @param requestConfig - Additional configuration for the request.\n * @returns A promise that resolves with the response from the API provider.\n */\n async request(endpointName, requestConfig = {}) {\n // Use global and per-endpoint settings\n const endpointConfig = endpoints[endpointName];\n const _endpointConfig =\n endpointConfig ||\n ({ url: String(endpointName) } as RequestConfigUrlRequired);\n const url = _endpointConfig.url;\n\n // Block Protocol-relative URLs as they could lead to SSRF (Server-Side Request Forgery)\n if (url.startsWith('//')) {\n throw new Error('Protocol-relative URLs are not allowed.');\n }\n\n // Prevent potential Server-Side Request Forgery attack and leakage of credentials when same instance is used for external requests\n const mergedConfig = isAbsoluteUrl(url)\n ? // Merge endpoints configs for absolute URLs only if urls match\n endpointConfig?.url === url\n ? mergeConfigs(_endpointConfig, requestConfig)\n : requestConfig\n : mergeConfigs(mergeConfigs(config, _endpointConfig), requestConfig);\n\n // We prevent potential Server-Side Request Forgery attack and leakage of credentials as the same instance is not used for external requests\n // Retrigger fetch to ensure completely new instance of handler being triggered for external URLs\n return fetchf(url, mergedConfig);\n },\n };\n\n /**\n * Maps all API requests using native Proxy\n *\n * @param {*} prop Caller\n */\n return new Proxy>(\n apiHandler as ApiHandlerMethods,\n {\n get(_target, prop: string) {\n if (prop in apiHandler) {\n return apiHandler[prop as unknown as keyof typeof apiHandler];\n }\n\n // Prevent handler from triggering non-existent endpoints\n if (endpoints[prop]) {\n return apiHandler.request.bind(null, prop);\n }\n\n return handleNonImplemented.bind(null, prop);\n },\n },\n );\n}\n\nexport { createApiFetcher };\n"]} \ No newline at end of file diff --git a/dist/node/index.js b/dist/node/index.js index 3da4d12f..a340480b 100644 --- a/dist/node/index.js +++ b/dist/node/index.js @@ -1,3 +1,3 @@ -'use strict';var x="application/",L=x+"json",Qe="charset=utf-8",C="Content-Type",h="undefined",j="object",b="string",g="function",X="AbortError",Ne="TimeoutError",O="GET",Se="HEAD",ee="reject";var _e=10;function te(e){return e instanceof URLSearchParams}function p(e){return e!==null&&typeof e===j}function K(e){let t={...e};return delete t.__proto__,delete t.constructor,delete t.prototype,t}function Ue(e){let t=Object.keys(e);t.sort();let r={};for(let a=0,n=t.length;a{i=typeof i===g?i():i,i=i===null||i===void 0?"":i,r[r.length]=a(l)+"="+a(i);},s=(l,i,m=0)=>{if(m>=_e)return r;let c,R,P;if(l)if(Array.isArray(i))for(c=0,R=i.length;c{if(Object.prototype.hasOwnProperty.call(r,n)){let s=r[n];if(s!=null)return encodeURIComponent(String(s))}return a})}function re(e){return e.includes("://")}var y=()=>Date.now(),Q=()=>{};function he(e){let t=typeof e;return e==null?false:t===b||t==="number"||t==="boolean"||Array.isArray(e)?true:typeof globalThis!==h&&typeof globalThis.Buffer!==h&&globalThis.Buffer.isBuffer(e)||e instanceof Date||te(e)?false:!!(p(e)&&(Object.getPrototypeOf(e)===Object.prototype||typeof e.toJSON===g))}async function N(e){return new Promise(t=>setTimeout(()=>t(true),e))}function ge(e,t=0){return t>=_e?e:e&&p(e)&&typeof e.data!==h?ge(e.data,t+1):e}function ae(e){if(!e)return {};let t={};if(e instanceof Headers)e.forEach((r,a)=>{t[a]=r;});else if(p(e))for(let[r,a]of Object.entries(e))t[r.toLowerCase()]=a;return t}function ne(){return typeof window!==h&&typeof window.addEventListener===g}var De=()=>{if(!ne())return false;let e=navigator&&navigator.connection;return e&&["slow-2g","2g","3g"].includes(e.effectiveType)};async function w(e,t,...r){if(e){if(typeof e===g){let a=await e(t,...r);a&&p(t)&&p(a)&&Object.assign(t,a);}else if(Array.isArray(e))for(let a of e){let n=await a(t,...r);n&&p(t)&&p(n)&&Object.assign(t,n);}}}var se=class extends Error{constructor(r,a,n){super(r);this.request=a;this.response=n;this.name="FetchError",this.status=n?n.status:0,this.statusText=n?n.statusText:"",this.config=a,this.isCancelled=false;}status;statusText;config;isCancelled};var oe=class extends se{constructor(t,r,a){super(t,r,a),this.name="ResponseError";}};var ue=600,ie=1e3,lt=ue*ie,z=Array(ue).fill(0).map(()=>[]),q=new Map,J=0,E=null,Le=([e,t])=>{q.delete(e);try{let r=t();r&&r instanceof Promise&&r.catch(Q);}catch{}},I=(e,t,r)=>{if(S(e),r>lt||r%ie!==0){q.set(e,[setTimeout(Le.bind(null,[e,t]),r)]);return}let a=r/ie,n=(J+a)%ue;z[n].push([e,t]),q.set(e,n),E||(E=setInterval(()=>{J=(J+1)%ue,z[J].forEach(Le),z[J]=[],!q.size&&E&&(clearInterval(E),E=null);},ie));},S=e=>{let t=q.get(e);t!==void 0&&(Array.isArray(t)?clearTimeout(t[0]):z[t].splice(z[t].findIndex(([r])=>r===e),1),q.delete(e),!q.size&&E&&(clearInterval(E),E=null));};var A=new Map;function je(e,t,r,a,n,s){if(!e)return new AbortController;let o=A.get(e),u=null;if(o){let i=o[0],m=o[3];if(!m&&y()-o[2]{Ke(e,new DOMException(t+" aborted due to timeout",Ne));},r),l}async function Ke(e,t=null){if(e){let r=A.get(e);r&&(t&&r[0].abort(t),le(e));}}function le(e){S(e),A.delete(e);}function Je(e,t){let r=A.get(e);r&&(r[4]=t,A.set(e,r));}function Te(e,t){if(!e)return null;let r=A.get(e);return r&&r[4]&&!r[3]&&y()-r[2]{if(!n[r])return;n[1]=a;let s=t?n[4]:n[0];s&&Promise.resolve(s(t)).catch(Q);});}async function fe(e,t=false){if(!e)return null;let r=G.get(e);if(r){r[1]=y();let a=t?r[4]:r[0];if(a)return await a(t)}return null}function ft(e){mt(e);let t=e==="focus"?5:6;G.forEach((r,a)=>{r[t]&&pt(a);});}function ze(e){if(!ne()||ce.has(e))return;let t=ke.bind(null,e,true);ce.set(e,t),window.addEventListener(e,t);}function mt(e){if(!ne())return;let t=ce.get(e);t&&(window.removeEventListener(e,t),ce.delete(e));}function Ge(e,t,r,a,n,s,o){G.set(e,[t,y(),ct,a,n,s,o]),s&&ze("focus"),o&&ze("online"),a&&I("s:"+e,fe.bind(null,e,true),a*1e3);}function pt(e){G.delete(e),S("s:"+e);}var v=new Map;function dt(e){return v.has(e)||v.set(e,new Set),v.get(e)}function Rt(e,t){dt(e).add(t);}function yt(e,t){let r=v.get(e);r&&(r.delete(t),r.size===0&&v.delete(e));}function _(e,t){let r=v.get(e);if(r)if(r.size===1){let a=r.values().next().value;a(t);}else r.forEach(a=>a(t));}function Pt(e,t){return e?(Rt(e,t),()=>{yt(e,t);}):Q}var be=(De()?60:30)*1e3,U={strategy:ee,timeout:be,headers:{Accept:L+", text/plain, */*","Accept-Encoding":"gzip, deflate, br"},retry:{delay:be/30,maxDelay:be,resetTimeout:true,backoff:1.5,retryOn:[408,409,425,429,500,502,503,504]}};function ht(e){let t=K(e);return Object.assign(U,t),U}function $e(){return {...U}}function xe(e,t){if(!t)return We(e,$e());let r=K(t),a=W(U,r);return We(e,a)}function We(e,t){let r=t.method;r=r?r.toUpperCase():O;let a;r!==O&&r!==Se&&(a=t.body??t.data,a&&typeof a!==b&&he(a)&&(a=JSON.stringify(a))),gt(t.headers,a);let n=t.withCredentials?"include":t.credentials,s=Me(e,t.urlPathParams),o=He(s,t.params),l=re(e)?"":t.baseURL||t.apiUrl||"";return t.url=l+o,t.method=r,t.credentials=n,t.body=a,t}function gt(e,t){if(!e||!t||t instanceof FormData||typeof Blob!==h&&t instanceof Blob||typeof File!==h&&t instanceof File||typeof ReadableStream!==h&&t instanceof ReadableStream)return;let r;if(te(t))r=x+"x-www-form-urlencoded";else if(t instanceof ArrayBuffer||ArrayBuffer.isView(t))r=x+"octet-stream";else if(he(t))r=L+";"+Qe;else return;e instanceof Headers?e.has(C)||e.set(C,r):p(e)&&!Array.isArray(e)&&!e[C]&&(e[C]=r);}function W(e,t){let r=Object.assign({},e,t);return Ye("retry",r,e,t),Ye("headers",r,e,t),Ee("onRequest",r,e,t),Ee("onResponse",r,e,t),Ee("onError",r,e,t),r}function Ee(e,t,r,a){let n=r[e],s=a[e];if(!n&&!s)return;if(!n){t[e]=s;return}if(!s){t[e]=n;return}let o=Array.isArray(n)?n:[n],u=Array.isArray(s)?s:[s];t[e]=e==="onResponse"?u.concat(o):o.concat(u);}function Ye(e,t,r,a){a[e]&&(t[e]={...r[e],...a[e]});}var pe=new Map,B="|",Ce=64,Ve=new RegExp("[^\\w\\-_|]","g"),Dt=new Set(["accept","accept-language","accept-encoding","authorization","content-type","referer","origin","user-agent","cookie","x-api-key","x-requested-with","x-client-id","x-tenant-id","x-user-id","x-app-version","x-feature-flag","x-device-id","x-platform","x-session-id","x-locale"]);function Y(e,t=true){let r=e.cacheKey;if(r&&t)return typeof r===b?r:r(e);let{url:a="",method:n=O,headers:s=null,body:o=null,credentials:u="same-origin"}=e,l="";if(s){let m;s instanceof Headers?m=ae(s):m=s;let c=Object.keys(m),R=c.length;R>1&&c.sort();let P="";for(let f=0;f{i+=c+"="+m+"&";}),i.length>Ce&&(i=k(i));else if(typeof Blob!==h&&o instanceof Blob||typeof File!==h&&o instanceof File)i="BF"+o.size+o.type;else if(o instanceof ArrayBuffer||ArrayBuffer.isView(o))i="AB"+o.byteLength;else {let m=p(o)?JSON.stringify(Ue(o)):String(o);i=m.length>Ce?k(m):m;}return (n+B+a+B+u+B+l+B+i).replace(Ve,"")}function Ze(e){return e.expiry?y()>e.expiry:false}function Tt(e){return e.stale?y()>e.stale:false}function de(e){return pe.get(e)}function Re(e,t,r,a){if(r===0){me(e);return}let n=y(),s=r?r*1e3:0;pe.set(e,{data:t,time:n,stale:a&&a>0?n+a*1e3:a,expiry:r===-1?void 0:n+s}),s>0&&I("c:"+e,()=>{me(e,true);},s);}function me(e,t=false){if(t){let r=de(e);if(!r||!Ze(r))return}pe.delete(e);}async function we(e,t,r){if(!e)return null;let a=de(e);if(!a)return null;let n=p(t)?K(t):t,s={...a.data,data:n},o={...a,data:s};return pe.set(e,o),_(e,s),r&&r.refetch?await fe(e):null}function ye(e,t,r){if(!e||t===void 0||t===null)return null;let a=r.cacheBuster||U.cacheBuster;if(a&&a(r)||r.cache&&r.cache==="reload")return null;let n=de(e);if(!n)return null;let s=Ze(n),o=Tt(n);return s?(me(e),null):!o||o&&!s?n.data:null}function qe(e,t,r=false){let a=t.cacheKey;if(a){let n=t.cacheTime,s=t.skipCache;n&&(!r||t.cacheErrors)&&!(s&&s(e,t))&&Re(a,e,n,t.staleTime),_(a,e),le(a);let o=t._prevKey;o&&le(o);}}async function Xe(e){if(!e)return null;let t=e.headers?.get(C);t?t=t.toLowerCase().trim():t="";let r=t.split(";",1)[0],a;try{if(r.includes(L)||r.includes("+json"))a=await e.json();else if((r.includes("multipart/form-data")||r.includes(x+"x-www-form-urlencoded"))&&typeof e.formData===g)a=await e.formData();else if(r.includes(x+"octet-stream")&&typeof e.blob===g)a=await e.blob();else if(a=await e.text(),typeof a===b){let n=a.trim();if(n.startsWith("{")&&n.endsWith("}")||n.startsWith("[")&&n.endsWith("]"))try{a=JSON.parse(n);}catch{}}}catch{a=null;}return a}var Ie=(e,t,r=null)=>{let a=t.defaultResponse,n=t.cacheKey,s=we.bind(null,n);if(!e)return {ok:false,error:r,data:a??null,headers:null,config:t,mutate:s,isFetching:false,isSuccess:false,isError:true};let o=typeof Response===g&&e instanceof Response,u=e.data;a!==void 0&&(u==null||typeof u===j&&Object.keys(u).length===0)&&(e.data=u=a),t.flattenResponse&&(e.data=u=ge(u)),t.select&&(e.data=u=t.select(u));let l=ae(e.headers);return o?{body:e.body,bodyUsed:e.bodyUsed,ok:e.ok,redirected:e.redirected,type:e.type,url:e.url,status:e.status,statusText:e.statusText,blob:()=>e.blob(),json:()=>e.json(),text:()=>e.text(),clone:()=>e.clone(),arrayBuffer:()=>e.arrayBuffer(),formData:()=>e.formData(),bytes:()=>e.bytes(),error:r,data:u,headers:l,config:t,mutate:s,isFetching:false,isSuccess:e.ok&&!r,isError:!!r}:(p(e)&&(e.error=r,e.headers=l,e.isFetching=false,e.mutate=s,e.isSuccess=e.ok&&!r,e.isError=!!r),e)};function et(e){let t=Date.parse(e)-y();return isNaN(t)?null:Math.max(0,Math.floor(t))}function bt(e){if(!e)return null;let t=e.headers||{},r=t["retry-after"];if(r){let o=Number(r);if(!isNaN(o)&&o>=0)return o*1e3;let u=et(r);if(u!==null)return u}let a="ratelimit-reset",n=t[a+"-after"]||t["x-"+a+"-after"];if(n){let o=Number(n);if(!isNaN(o))return o*1e3}let s=t[a+"-at"]||t["x-"+a+"-at"];return s?et(s):null}async function tt(e,t){let{retries:r=0,delay:a=0,backoff:n=1,maxDelay:s,retryOn:o=[],shouldRetry:u}=t,l=0,i=a,m=r>0?r:0,c;for(;l<=m;){if(l>0&&c){let f=c.config,H=f.onRetry;H&&(await w(H,c,l),f._isAutoKey&&(f._prevKey=f.cacheKey,f.cacheKey=Y(f,false)));}c=await e(l>0,l);let R=c.error;if(!R){if(u&&l0&&await N(n),o=await e(),s++,!(a>0&&s>=a||!t||r&&r(o,s)));)await N(t);return o}async function at(e,t,r){let a=await t(e),n=a.error;if(!n)return qe(a,r),a;r.onError&&await w(r.onError,n);let s=n.isCancelled;if(!s&&r.logger&&xt(r,"FETCH ERROR",n),qe(a,r,true),!s||r.rejectCancelled){let u=r.strategy;if(u===ee)return Promise.reject(n);u==="silent"&&await new Promise(()=>null);}return a}function nt(e,t,r){e.status=e.status||t?.status||0,e.statusText=e.statusText||t?.statusText||"",e.config=e.request=r,e.response=t,e.isCancelled=e.name===X;}function xt(e,...t){let r=e.logger;r&&r.warn&&r.warn(...t);}var Ae={isFetching:true};async function Pe(e,t=null){let r=xe(e,t),{timeout:a,cancellable:n,cacheKey:s,dedupeTime:o,cacheTime:u,staleTime:l,refetchOnFocus:i,refetchOnReconnect:m,pollingInterval:c=0}=r,R=u!==void 0||l!==void 0,P=!!(s||a||o||R||n||i||m),f=null;if(P&&(f=Y(r)),f&&R){let T=ye(f,u,r);if(T)return T}if(f&&o){let T=Te(f,o);if(T)return T}let H=r.retry||{},{retries:st=0,resetTimeout:ot}=H,Be=async(T=false,Oe=0)=>{Oe||(f&&!T&&(l?ye(f,u,r)||(Re(f,Ae,u,l),_(f,Ae)):_(f,Ae)),r.cacheKey=f);let V=r.url,ut=je(f,V,a,o||0,!!n,!!(a&&(!Oe||ot))),D=r;D.signal=ut.signal;let Z,d=null;try{r.onRequest&&await w(r.onRequest,D);let F=r.fetcher;if(d=F?await F(V,D):await fetch(V,D),p(d)&&(typeof Response===g&&d instanceof Response?d.data=await Xe(d):F&&("data"in d&&"body"in d||(d={data:d})),d.config=D,d.ok!==void 0&&!d.ok))throw new oe(`${D.method} to ${V} failed! Status: ${d.status||null}`,D,d);Z=Ie(d,D);let M=r.onResponse;M&&await w(M,Z);}catch(F){let M=F;nt(M,d,D),Z=Ie(d,D,M);}return Z},it=st>0?()=>tt(Be,H):Be,$=(T=false)=>at(T,it,r),Fe=c?rt($,c,r.shouldStopPolling,r.maxPollingAttempts,r.pollingDelay):$();return f&&(o&&Je(f,Fe),Ge(f,$,void 0,l,$,!!i,!!m)),Fe}function Ct(e){let t=e.endpoints;function r(n){return console.error(`Add ${n} to 'endpoints'.`),Promise.resolve(null)}let a={config:e,endpoints:t,async request(n,s={}){let o=t[n],u=o||{url:String(n)},l=u.url;if(l.startsWith("//"))throw new Error("Protocol-relative URLs are not allowed.");let i=re(l)?o?.url===l?W(u,s):s:W(W(e,u),s);return Pe(l,i)}};return new Proxy(a,{get(n,s){return s in a?a[s]:t[s]?a.request.bind(null,s):r.bind(null,s)}})} -exports.abortRequest=Ke;exports.addTimeout=I;exports.buildConfig=xe;exports.createApiFetcher=Ct;exports.deleteCache=me;exports.fetchf=Pe;exports.fetchff=Pe;exports.generateCacheKey=Y;exports.getCache=de;exports.getCachedResponse=ye;exports.getDefaultConfig=$e;exports.getInFlightPromise=Te;exports.isSlowConnection=De;exports.mutate=we;exports.removeRevalidators=ft;exports.revalidate=fe;exports.revalidateAll=ke;exports.setCache=Re;exports.setDefaultConfig=ht;exports.subscribe=Pt;//# sourceMappingURL=index.js.map +'use strict';var w="application/",z=w+"json",Qe="charset=utf-8",C="Content-Type",P="undefined",J="object",b="string",D="function",re="AbortError",Ne="TimeoutError",Q="GET",Se="HEAD",ae="reject";var He=10;function ne(e){return e instanceof URLSearchParams}function d(e){return e!==null&&typeof e===J}function k(e){let t=Object.prototype.hasOwnProperty.call(e,"__proto__"),r=Object.prototype.hasOwnProperty.call(e,"constructor"),a=Object.prototype.hasOwnProperty.call(e,"prototype");if(!t&&!r&&!a)return e;let n={...e};return t&&delete n.__proto__,r&&delete n.constructor,a&&delete n.prototype,n}function Ue(e){let t=Object.keys(e);t.sort();let r={};for(let a=0,n=t.length;a{i=typeof i===D?i():i,i=i===null||i===void 0?"":i,r[r.length]=a(c)+"="+a(i);},s=(c,i,m=0)=>{if(m>=He)return r;let l,p,g;if(c)if(Array.isArray(i))for(l=0,p=i.length;l{if(Object.prototype.hasOwnProperty.call(r,n)){let s=r[n];if(s!=null)return encodeURIComponent(String(s))}return a})}function se(e){return e.includes("://")}var h=()=>Date.now(),N=()=>{};function he(e){let t=typeof e;return e==null?false:t===b||t==="number"||t==="boolean"||Array.isArray(e)?true:typeof globalThis!==P&&typeof globalThis.Buffer!==P&&globalThis.Buffer.isBuffer(e)||e instanceof Date||ne(e)?false:!!(d(e)&&(Object.getPrototypeOf(e)===Object.prototype||typeof e.toJSON===D))}async function S(e){return new Promise(t=>setTimeout(()=>t(true),e))}function ge(e,t=0){return t>=He?e:e&&d(e)&&typeof e.data!==P?ge(e.data,t+1):e}function A(e){if(!e)return {};let t={};if(e instanceof Headers)e.forEach((r,a)=>{t[a.toLowerCase()]=r;});else if(d(e))for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r.toLowerCase()]=e[r]);return t}function je(){return typeof window!==P&&typeof window.addEventListener===D}function oe(e,t){if(typeof DOMException!==P)return new DOMException(e,t);let r=new Error(e);return r.name=t,r}var De=()=>{let e=typeof navigator!==P&&navigator.connection;return e&&["slow-2g","2g","3g"].includes(e.effectiveType)};async function I(e,t,...r){if(e){if(typeof e===D){let a=await e(t,...r);a&&d(t)&&d(a)&&Object.assign(t,a);}else if(Array.isArray(e))for(let a of e){let n=await a(t,...r);n&&d(t)&&d(n)&&Object.assign(t,n);}}}var ie=class extends Error{constructor(r,a,n){super(r);this.request=a;this.response=n;this.name="FetchError",this.status=n?n.status:0,this.statusText=n?n.statusText:"",this.config=a,this.isCancelled=false;}status;statusText;config;isCancelled};var ue=class extends ie{constructor(t,r,a){super(t,r,a),this.name="ResponseError";}};var ce=600,G=1e3,dt=ce*G,Ee=Array(ce).fill(0).map(()=>[]),q=new Map,le=0,x=null,Ke=([e,t])=>{q.delete(e);try{let r=t();r&&r instanceof Promise&&r.catch(N);}catch{}},B=(e,t,r)=>{if(_(e),rdt||r%G!==0){q.set(e,[setTimeout(Ke.bind(null,[e,t]),r)]);return}let a=r/G,n=(le+a)%ce;Ee[n].push([e,t]),q.set(e,n),x||(x=setInterval(()=>{le=(le+1)%ce;let s=Ee[le];for(let o=0;o{let t=q.get(e);if(t!==void 0){if(Array.isArray(t))clearTimeout(t[0]);else {let r=Ee[t],a=r.findIndex(([n])=>n===e);a!==-1&&r.splice(a,1);}q.delete(e),!q.size&&x&&(clearInterval(x),x=null);}};var H=new Map;function ze(e,t,r,a,n,s){if(!e)return new AbortController;let o=h(),u=H.get(e),c=null;if(u){let m=u[0],l=u[3];if(!l&&o-u[2]{Je(e,oe(t+" aborted due to timeout",Ne));},r),i}async function Je(e,t=null){if(e){let r=H.get(e);r&&(t&&r[0].abort(t),fe(e));}}function fe(e){_(e),H.delete(e);}function ke(e,t){let r=H.get(e);r&&(r[4]=t);}function Te(e,t){if(!e)return null;let r=H.get(e);return r&&r[4]&&!r[3]&&h()-r[2]{if(!n[r])return;n[1]=a;let s=t?n[4]:n[0];s&&Promise.resolve(s(t)).catch(N);});}async function me(e,t=false){if(!e)return null;let r=M.get(e);if(r){r[1]=h();let a=t?r[4]:r[0];if(a)return await a(t)}return null}function Rt(e){$e(e);let t=e==="focus"?5:6;M.forEach((r,a)=>{r[t]&&Pt(a);});}function be(e){if(U.has(e))return;let t=Ye.bind(null,e,true),r=We.get(e);if(r){let a=r(t);U.set(e,a);return}je()&&(window.addEventListener(e,t),U.set(e,()=>window.removeEventListener(e,t)));}function $e(e){let t=U.get(e);t&&(t(),U.delete(e));}function Ze(e,t,r,a,n,s,o){let u=M.get(e);u?(u[0]=t,u[1]=h(),u[2]=Ge,u[3]=a,u[4]=n,u[5]=s,u[6]=o):M.set(e,[t,h(),Ge,a,n,s,o]),s&&be("focus"),o&&be("online"),a&&B("s:"+e,me.bind(null,e,true),a*1e3);}function Pt(e){M.delete(e),_("s:"+e);}var Y=new Map;function ht(e){let t=Y.get(e);return t||(t=new Set,Y.set(e,t)),t}function gt(e,t){ht(e).add(t);}function Dt(e,t){let r=Y.get(e);r&&(r.delete(t),r.size===0&&Y.delete(e));}function L(e,t){let r=Y.get(e);if(r)if(r.size===1){let a=r.values().next().value;a(t);}else r.forEach(a=>a(t));}function Et(e,t){return e?(gt(e,t),()=>{Dt(e,t);}):N}var xe=(De()?60:30)*1e3,$={strategy:ae,timeout:xe,headers:{Accept:z+", text/plain, */*","Accept-Encoding":"gzip, deflate, br"},retry:{delay:xe/30,maxDelay:xe,resetTimeout:true,backoff:1.5,retryOn:[408,409,425,429,500,502,503,504]}};function Tt(e){let t=k(e);return j({},t,$)}function et(){return {...$}}function Ce(e,t){if(!t)return Ve(e,et());let r=k(t),a=j($,r);return Ve(e,a)}function Ve(e,t){let r=t.method;r=r?r.toUpperCase():Q;let a;r!==Q&&r!==Se&&(a=t.body??t.data,a&&typeof a!==b&&he(a)&&(a=JSON.stringify(a))),bt(t.headers,a);let n=t.withCredentials?"include":t.credentials,s=Le(e,t.urlPathParams),o=Me(s,t.params),c=se(e)?"":t.baseURL||t.apiUrl||"";return t.url=c+o,t.method=r,t.credentials=n,t.body=a,t}function bt(e,t){if(!e||!t||t instanceof FormData||typeof Blob!==P&&t instanceof Blob||typeof File!==P&&t instanceof File||typeof ReadableStream!==P&&t instanceof ReadableStream)return;let r;if(ne(t))r=w+"x-www-form-urlencoded";else if(t instanceof ArrayBuffer||ArrayBuffer.isView(t))r=w+"octet-stream";else if(he(t))r=z+";"+Qe;else return;e instanceof Headers?e.has(C)||e.set(C,r):d(e)&&!Array.isArray(e)&&!e[C]&&(e[C]=r);}function j(e,t,r={}){return Object.assign(r,e,t),Xe("retry",e,t,r),Xe("headers",e,t,r),we("onRequest",e,t,r),we("onResponse",e,t,r),we("onError",e,t,r),r}function we(e,t,r,a){let n=t[e],s=r[e];if(!n&&!s)return;if(!n){a[e]=s;return}if(!s){a[e]=n;return}let o=Array.isArray(n)?n:[n],u=Array.isArray(s)?s:[s];a[e]=e==="onResponse"?u.concat(o):o.concat(u);}function Xe(e,t,r,a){if(r[e]){let n=t[e],s=r[e];if(e==="headers"&&(n instanceof Headers||s instanceof Headers)){let o=A(n),u=A(s);a[e]={...o,...u};}else a[e]={...n,...s};}}var de=new Map,F="|",Ae=64,tt=/[^\w\-_|/:@.?=&~%#]/g,rt=/[^\w\-_|/:@.?=&~%#]/,xt=new Set(["accept","accept-language","accept-encoding","authorization","content-type","referer","origin","user-agent","cookie","x-api-key","x-requested-with","x-client-id","x-tenant-id","x-user-id","x-app-version","x-feature-flag","x-device-id","x-platform","x-session-id","x-locale"]);function Z(e,t=true){let r=e.cacheKey;if(r&&t)return typeof r===b?r:r(e);let{url:a="",method:n=Q,headers:s=null,body:o=null,credentials:u="same-origin"}=e,c="";if(s){let l;s instanceof Headers?l=A(s):l=s;let p=Object.keys(l),g=p.length;g>1&&p.sort();let f="";for(let E=0;E{i+=p+"="+l+"&";}),i.length>Ae&&(i=W(i));else if(typeof Blob!==P&&o instanceof Blob||typeof File!==P&&o instanceof File)i="BF"+o.size+o.type;else if(o instanceof ArrayBuffer||ArrayBuffer.isView(o))i="AB"+o.byteLength;else {let l=d(o)?JSON.stringify(Ue(o)):String(o);i=l.length>Ae?W(l):l;}let m=n+F+a+F+u+F+c+F+i;return rt.test(m)?m.replace(tt,""):m}function at(e){return e.expiry?h()>e.expiry:false}function ye(e){return de.get(e)}function Re(e,t,r,a){if(r===0){pe(e);return}let n=h(),s=r?r*1e3:0,o=a?a*1e3:0;de.set(e,{data:t,time:n,stale:o>0?n+o:void 0,expiry:r===-1?void 0:n+s}),s>0&&B("c:"+e,()=>{pe(e,true);},s);}function pe(e,t=false){if(t){let r=ye(e);if(!r||!at(r))return}de.delete(e);}async function Ie(e,t,r){if(!e)return null;let a=ye(e);if(!a)return null;let n=d(t)?k(t):t,s={...a.data,data:n},o={...a,data:s};return de.set(e,o),L(e,s),r&&r.refetch?await me(e):null}function V(e,t,r){if(!e||t===void 0||t===null)return null;let a=r.cacheBuster||$.cacheBuster;if(a&&a(r)||r.cache&&r.cache==="reload")return null;let n=ye(e);return n?at(n)?(pe(e),null):n.data:null}function qe(e,t,r=false){let a=t.cacheKey;if(a){let n=t.cacheTime,s=t.skipCache;n&&(!r||t.cacheErrors)&&!(s&&s(e,t))&&Re(a,e,n,t.staleTime),L(a,e),fe(a);let o=t._prevKey;o&&fe(o);}}async function nt(e){if(!e)return null;let t=e.headers?.get(C);t?t=t.toLowerCase().trim():t="";let r=t.split(";",1)[0],a;try{if(r.includes(z)||r.includes("+json"))a=await e.json();else if((r.includes("multipart/form-data")||r.includes(w+"x-www-form-urlencoded"))&&typeof e.formData===D)a=await e.formData();else if(r.includes(w+"octet-stream")&&typeof e.blob===D)a=await e.blob();else if(a=await e.text(),typeof a===b){let n=a.trim();if(n.startsWith("{")&&n.endsWith("}")||n.startsWith("[")&&n.endsWith("]"))try{a=JSON.parse(n);}catch{}}}catch{a=null;}return a}var Be=(e,t,r=null)=>{let a=t.defaultResponse,n=t.cacheKey,s=Ie.bind(null,n);if(!e)return {ok:false,error:r,data:a??null,headers:null,config:t,mutate:s,isFetching:false,isSuccess:false,isError:true};let o=typeof Response===D&&e instanceof Response,u=e.data;a!==void 0&&(u==null||typeof u===J&&Object.keys(u).length===0)&&(e.data=u=a),t.flattenResponse&&(e.data=u=ge(u)),t.select&&(e.data=u=t.select(u));let c=A(e.headers);return o?{body:e.body,bodyUsed:e.bodyUsed,ok:e.ok,redirected:e.redirected,type:e.type,url:e.url,status:e.status,statusText:e.statusText,blob:()=>e.blob(),json:()=>e.json(),text:()=>e.text(),clone:()=>e.clone(),arrayBuffer:()=>e.arrayBuffer(),formData:()=>e.formData(),bytes:()=>e.bytes(),error:r,data:u,headers:c,config:t,mutate:s,isFetching:false,isSuccess:e.ok&&!r,isError:!!r}:(d(e)&&(e.error=r,e.headers=c,e.isFetching=false,e.mutate=s,e.isSuccess=e.ok&&!r,e.isError=!!r),e)};function st(e){let t=Date.parse(e)-h();return isNaN(t)?null:Math.max(0,Math.floor(t))}function wt(e){if(!e)return null;let t=e.headers||{},r=t["retry-after"];if(r){let o=Number(r);if(!isNaN(o)&&o>=0)return o*1e3;let u=st(r);if(u!==null)return u}let a="ratelimit-reset",n=t[a+"-after"]||t["x-"+a+"-after"];if(n){let o=Number(n);if(!isNaN(o))return o*1e3}let s=t[a+"-at"]||t["x-"+a+"-at"];return s?st(s):null}async function ot(e,t){let{retries:r=0,delay:a=0,backoff:n=1,maxDelay:s,retryOn:o=[],shouldRetry:u}=t,c=0,i=a,m=r>0?r:0,l;for(;c<=m;){if(c>0&&l){let f=l.config,E=f.onRetry;E&&(await I(E,l,c),f._isAutoKey&&(f._prevKey=f.cacheKey,f.cacheKey=Z(f,false)));}l=await e(c>0,c);let p=l.error;if(!p){if(u&&c0&&await S(n),o=await e(),s++,!(a>0&&s>=a||!t||r&&r(o,s)));)await S(t);return o}async function ut(e,t,r){let a=await t(e),n=a.error;if(!n)return qe(a,r),a;r.onError&&await I(r.onError,n);let s=n.isCancelled;if(!s&&r.logger&&At(r,"FETCH ERROR",n),qe(a,r,true),!s||r.rejectCancelled){let u=r.strategy;if(u===ae)return Promise.reject(n);u==="silent"&&await new Promise(()=>null);}return a}function lt(e,t,r){e.status=e.status||t?.status||0,e.statusText=e.statusText||t?.statusText||"",e.config=e.request=r,e.response=t,e.isCancelled=e.name===re;}function At(e,...t){let r=e.logger;r&&r.warn&&r.warn(...t);}var Fe=Object.freeze({isFetching:true});async function Pe(e,t=null){if(t&&typeof t.cacheKey=="string"){let R=V(t.cacheKey,t.cacheTime,t);if(R)return R}let r=Ce(e,t),{timeout:a,cancellable:n,cacheKey:s,dedupeTime:o,cacheTime:u,staleTime:c,refetchOnFocus:i,refetchOnReconnect:m,pollingInterval:l=0}=r,p=u!==void 0||c!==void 0,g=!!(s||a||o||p||n||i||m),f=null;if(g&&(f=Z(r)),f&&p){let R=V(f,u,r);if(R)return R}if(f&&o){let R=Te(f,o);if(R)return R}let E=r.retry||{},{retries:ct=0,resetTimeout:ft}=E,Oe=async(R=false,ee=0)=>{ee||(f&&!R&&(c?V(f,u,r)||(Re(f,Fe,u,c),L(f,Fe)):L(f,Fe)),r.cacheKey=f);let O=r.url,pt=ze(f,O,a,o||0,!!n,!!(a&&(!ee||ft))),T=r;T.signal=pt.signal;let te,y=null;try{r.onRequest&&(f&&o&&!ee&&await null,await I(r.onRequest,T));let v=r.fetcher;if(y=v?await v(O,T):await fetch(O,T),d(y)&&(typeof Response===D&&y instanceof Response?y.data=await nt(y):v&&("data"in y&&"body"in y||(y={data:y})),y.config=T,y.ok!==void 0&&!y.ok))throw new ue(`${T.method} to ${O} failed! Status: ${y.status||null}`,T,y);te=Be(y,T);let K=r.onResponse;K&&await I(K,te);}catch(v){let K=v;lt(K,y,T),te=Be(y,T,K);}return te},mt=ct>0?(R=false)=>ot((ee,O)=>Oe(R,O),E):Oe,X=(R=false)=>ut(R,mt,r),ve=l?it(X,l,r.shouldStopPolling,r.maxPollingAttempts,r.pollingDelay):X();return f&&(o&&ke(f,ve),(c||i||m)&&Ze(f,X,void 0,c,X,!!i,!!m)),ve}function It(e){let t=e.endpoints;function r(n){return console.error(`Add ${n} to 'endpoints'.`),Promise.resolve(null)}let a={config:e,endpoints:t,async request(n,s={}){let o=t[n],u=o||{url:String(n)},c=u.url;if(c.startsWith("//"))throw new Error("Protocol-relative URLs are not allowed.");let i=se(c)?o?.url===c?j(u,s):s:j(j(e,u),s);return Pe(c,i)}};return new Proxy(a,{get(n,s){return s in a?a[s]:t[s]?a.request.bind(null,s):r.bind(null,s)}})} +exports.abortRequest=Je;exports.addTimeout=B;exports.buildConfig=Ce;exports.createAbortError=oe;exports.createApiFetcher=It;exports.deleteCache=pe;exports.fetchf=Pe;exports.fetchff=Pe;exports.generateCacheKey=Z;exports.getCache=ye;exports.getCachedResponse=V;exports.getDefaultConfig=et;exports.getInFlightPromise=Te;exports.isSlowConnection=De;exports.mutate=Ie;exports.removeRevalidators=Rt;exports.revalidate=me;exports.revalidateAll=Ye;exports.setCache=Re;exports.setDefaultConfig=Tt;exports.setEventProvider=yt;exports.subscribe=Et;//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/node/index.js.map b/dist/node/index.js.map index 48153c1d..b68d3441 100644 --- a/dist/node/index.js.map +++ b/dist/node/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../src/constants.ts","../../src/utils.ts","../../src/interceptor-manager.ts","../../src/errors/fetch-error.ts","../../src/errors/response-error.ts","../../src/timeout-wheel.ts","../../src/inflight-manager.ts","../../src/hash.ts","../../src/revalidator-manager.ts","../../src/pubsub-manager.ts","../../src/config-handler.ts","../../src/cache-manager.ts","../../src/response-parser.ts","../../src/retry-handler.ts","../../src/polling-handler.ts","../../src/error-handler.ts","../../src/request-handler.ts","../../src/api-handler.ts"],"names":["APPLICATION_CONTENT_TYPE","APPLICATION_JSON","CHARSET_UTF_8","CONTENT_TYPE","UNDEFINED","OBJECT","STRING","FUNCTION","ABORT_ERROR","TIMEOUT_ERROR","GET","HEAD","REJECT","MAX_DEPTH","isSearchParams","data","isObject","value","sanitizeObject","obj","safeObj","sortObject","keys","sortedObj","i","len","key","appendQueryStringToUrl","baseUrl","queryString","appendQueryParams","url","params","encodedQueryString","s","encode","add","k","v","buildParams","prefix","depth","replaceUrlPathParams","urlPathParams","match","isAbsoluteUrl","timeNow","noop","isJSONSerializable","delayInvocation","ms","resolve","flattenData","processHeaders","headers","headersObject","isBrowser","isSlowConnection","conn","applyInterceptors","interceptors","args","interceptor","FetchError","message","request","response","ResponseError","WHEEL_SIZE","SECOND","MAX_WHEEL_MS","wheel","keyMap","position","timer","handleCallback","callback","result","addTimeout","cb","removeTimeout","seconds","slot","slotOrTimeout","inFlight","markInFlight","timeout","dedupeTime","isCancellable","isTimeoutEnabled","item","prevPromise","prevController","prevIsCancellable","controller","abortRequest","error","removeInFlight","setInFlightPromise","promise","getInFlightPromise","prevReq","hash","str","char","DEFAULT_TTL","revalidators","eventHandlers","revalidateAll","type","isStaleRevalidation","flagIndex","now","entry","revalidator","revalidate","removeRevalidators","removeEventHandler","removeRevalidator","addEventHandler","event","handler","addRevalidator","revalidatorFn","ttl","staleTime","bgRevalidatorFn","refetchOnFocus","refetchOnReconnect","listeners","ensureListenerSet","addListener","fn","removeListener","set","notifySubscribers","fns","subscribe","defaultTimeoutMs","defaultConfig","setDefaultConfig","customConfig","sanitized","getDefaultConfig","buildConfig","reqConfig","buildFetcherConfig","merged","mergeConfigs","requestConfig","method","body","setContentTypeIfNeeded","credentials","dynamicUrl","urlPath","baseURL","contentTypeValue","baseConfig","overrideConfig","mergedConfig","mergeConfig","mergeInterceptors","property","targetConfig","baseInterceptor","newInterceptor","baseArr","newArr","_cache","DELIMITER","MIN_LENGTH_TO_HASH","CACHE_KEY_SANITIZE_PATTERN","CACHE_KEY_HEADER_WHITELIST","generateCacheKey","config","cacheKeyCheck","headersString","bodyString","o","isCacheExpired","isCacheStale","getCache","setCache","deleteCache","time","ttlMs","removeExpired","mutate","newData","settings","updatedData","updatedResponse","updatedEntry","getCachedResponse","cacheKey","cacheTime","buster","isExpired","isStale","handleResponseCache","output","isError","skipCache","prevCacheKey","parseResponseData","contentType","mimeType","trimmed","prepareResponse","defaultResponse","mutatator","isNativeResponse","getMsFromHttpDate","dateString","getRetryAfterMs","extendedResponse","retryAfter","RATELIMIT_RESET","rateLimitResetAfter","rateLimitResetAt","withRetry","requestFn","retries","delay","backoff","maxDelay","retryOn","shouldRetry","attempt","waitTime","maxRetries","cfg","onRetry","getShouldStopRetrying","retryAfterMs","customDecision","withPolling","pollingInterval","shouldStopPolling","maxAttempts","pollingDelay","pollingAttempt","withErrorHandling","isCancelled","logger","strategy","enhanceError","inFlightResponse","fetchf","fetcherConfig","cancellable","isCacheEnabled","needsCacheKey","_cacheKey","cached","inflight","retryConfig","resetTimeout","doRequestOnce","onResponse","_error","baseRequest","requestWithErrorHandling","doRequestPromise","createApiFetcher","endpoints","handleNonImplemented","endpointName","apiHandler","endpointConfig","_endpointConfig","_target","prop"],"mappings":"aAAO,IAAMA,CAAAA,CAA2B,cAAA,CAE3BC,CAAAA,CAAmBD,CAAAA,CAA2B,MAAA,CAC9CE,GAAgB,eAAA,CAChBC,CAAAA,CAAe,cAAA,CAEfC,CAAAA,CAAY,WAAA,CACZC,CAAAA,CAAS,SACTC,CAAAA,CAAS,QAAA,CACTC,CAAAA,CAAW,UAAA,CAEXC,CAAAA,CAAc,YAAA,CACdC,EAAAA,CAAgB,cAAA,CAEhBC,CAAAA,CAAM,KAAA,CACNC,EAAAA,CAAO,MAAA,CAEPC,EAAAA,CAAS,QAAA,CCPtB,IAAMC,EAAAA,CAAY,EAAA,CAEX,SAASC,EAAAA,CAAeC,CAAAA,CAAwB,CACrD,OAAOA,CAAAA,YAAgB,eACzB,CAQO,SAASC,CAAAA,CAASC,CAAAA,CAA0C,CACjE,OAAOA,CAAAA,GAAU,IAAA,EAAQ,OAAOA,CAAAA,GAAUZ,CAC5C,CA8BO,SAASa,CAAAA,CAA8CC,CAAAA,CAAW,CACvE,IAAMC,CAAAA,CAAU,CAAE,GAAGD,CAAI,CAAA,CAEzB,OAAA,OAAOC,CAAAA,CAAQ,SAAA,CACf,OAAQA,CAAAA,CAAgB,WAAA,CACxB,OAAOA,CAAAA,CAAQ,SAAA,CAERA,CACT,CAWO,SAASC,EAAAA,CAAWF,EAAkC,CAC3D,IAAMG,CAAAA,CAAO,MAAA,CAAO,IAAA,CAAKH,CAAG,CAAA,CAE5BG,CAAAA,CAAK,IAAA,EAAK,CAEV,IAAMC,CAAAA,CAAY,EAAC,CAEnB,QAASC,CAAAA,CAAI,CAAA,CAAGC,CAAAA,CAAMH,CAAAA,CAAK,MAAA,CAAQE,CAAAA,CAAIC,CAAAA,CAAKD,CAAAA,EAAAA,CAAK,CAC/C,IAAME,CAAAA,CAAMJ,CAAAA,CAAKE,CAAC,CAAA,CAElBD,EAAUG,CAAG,CAAA,CAAIP,CAAAA,CAAIO,CAAG,EAC1B,CAEA,OAAOH,CACT,CASA,SAASI,EAAAA,CAAuBC,CAAAA,CAAiBC,CAAAA,CAA6B,CAC5E,OAAKA,CAAAA,CAIED,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,CACvB,CAAA,EAAGA,CAAO,CAAA,CAAA,EAAIC,CAAW,CAAA,CAAA,CACzB,CAAA,EAAGD,CAAO,CAAA,CAAA,EAAIC,CAAW,GALpBD,CAMX,CASO,SAASE,EAAAA,CAAkBC,CAAAA,CAAaC,CAAAA,CAA6B,CAC1E,GAAI,CAACA,CAAAA,CACH,OAAOD,CAAAA,CAIT,GAAIjB,EAAAA,CAAekB,CAAM,CAAA,CAAG,CAC1B,IAAMC,CAAAA,CAAqBD,CAAAA,CAAO,QAAA,EAAS,CAE3C,OAAOL,EAAAA,CAAuBI,CAAAA,CAAKE,CAAkB,CACvD,CAGA,IAAMC,EAAc,EAAC,CACfC,CAAAA,CAAS,kBAAA,CACTC,CAAAA,CAAM,CAACC,CAAAA,CAAWC,CAAAA,GAAW,CACjCA,CAAAA,CAAI,OAAOA,CAAAA,GAAM/B,CAAAA,CAAW+B,CAAAA,GAAMA,CAAAA,CAClCA,CAAAA,CAAIA,CAAAA,GAAM,IAAA,EAAYA,CAAAA,GAAM,MAAA,CAAX,EAAA,CAA4BA,CAAAA,CAC7CJ,CAAAA,CAAEA,CAAAA,CAAE,MAAM,CAAA,CAAIC,CAAAA,CAAOE,CAAC,EAAI,GAAA,CAAMF,CAAAA,CAAOG,CAAC,EAC1C,CAAA,CAEMC,CAAAA,CAAc,CAACC,CAAAA,CAAgBrB,CAAAA,CAAUsB,CAAAA,CAAQ,CAAA,GAAM,CAE3D,GAAIA,CAAAA,EAAS5B,GACX,OAAOqB,CAAAA,CAGT,IAAIV,CAAAA,CAAWC,CAAAA,CAAaC,CAAAA,CAE5B,GAAIc,CAAAA,CACF,GAAI,KAAA,CAAM,OAAA,CAAQrB,CAAG,CAAA,CACnB,IAAKK,EAAI,CAAA,CAAGC,CAAAA,CAAMN,CAAAA,CAAI,MAAA,CAAQK,CAAAA,CAAIC,CAAAA,CAAKD,CAAAA,EAAAA,CACrCe,CAAAA,CACEC,CAAAA,CAAS,GAAA,EAAO,OAAOrB,CAAAA,CAAIK,CAAC,CAAA,GAAMnB,GAAUc,CAAAA,CAAIK,CAAC,CAAA,CAAIA,CAAAA,CAAI,EAAA,CAAA,CAAM,GAAA,CAC/DL,CAAAA,CAAIK,CAAC,CAAA,CACLiB,CAAAA,CAAQ,CACV,CAAA,CAAA,KAAA,GAEOzB,CAAAA,CAASG,CAAG,EACrB,IAAKO,CAAAA,IAAOP,CAAAA,CACVoB,CAAAA,CAAYC,CAAAA,CAAS,GAAA,CAAMd,CAAAA,CAAM,GAAA,CAAKP,CAAAA,CAAIO,CAAG,CAAA,CAAGe,CAAAA,CAAQ,CAAC,CAAA,CAAA,KAG3DL,EAAII,CAAAA,CAAQrB,CAAG,CAAA,CAAA,KAAA,GAER,KAAA,CAAM,OAAA,CAAQA,CAAG,CAAA,CAC1B,IAAKK,CAAAA,CAAI,CAAA,CAAGC,CAAAA,CAAMN,CAAAA,CAAI,MAAA,CAAQK,CAAAA,CAAIC,EAAKD,CAAAA,EAAAA,CACrCY,CAAAA,CAAIjB,CAAAA,CAAIK,CAAC,CAAA,CAAE,IAAA,CAAML,CAAAA,CAAIK,CAAC,CAAA,CAAE,KAAK,CAAA,CAAA,KAG/B,IAAKE,CAAAA,IAAOP,CAAAA,CACVoB,EAAYb,CAAAA,CAAKP,CAAAA,CAAIO,CAAG,CAAA,CAAGe,CAAAA,CAAQ,CAAC,CAAA,CAGxC,OAAOP,CACT,CAAA,CAMMD,CAAAA,CAJmBM,CAAAA,CAAY,EAAA,CAAIP,CAAM,EAAE,IAAA,CAAK,GAAG,CAAA,CAIb,OAAA,CAAQ,SAAA,CAAW,IAAI,CAAA,CAEnE,OAAOL,EAAAA,CAAuBI,CAAAA,CAAKE,CAAkB,CACvD,CAWO,SAASS,GACdX,CAAAA,CACAY,CAAAA,CACQ,CACR,GAAI,CAACA,CAAAA,EAAiBZ,CAAAA,CAAI,OAAA,CAAQ,GAAG,CAAA,GAAM,EAAA,CACzC,OAAOA,CAAAA,CAKT,IAAMC,EAASW,CAAAA,CAGf,OAAOZ,CAAAA,CAAI,OAAA,CAAQ,mBAAA,CAAqB,CAACa,CAAAA,CAAOlB,CAAAA,GAAQ,CAEtD,GAAI,MAAA,CAAO,SAAA,CAAU,cAAA,CAAe,IAAA,CAAKM,EAAQN,CAAG,CAAA,CAAG,CACrD,IAAMT,CAAAA,CAAQe,CAAAA,CAAON,CAAG,CAAA,CAGxB,GAA2BT,CAAAA,EAAU,IAAA,CACnC,OAAO,kBAAA,CAAmB,MAAA,CAAOA,CAAK,CAAC,CAE3C,CAEA,OAAO2B,CACT,CAAC,CACH,CAUO,SAASC,EAAAA,CAAcd,CAAAA,CAAsB,CAClD,OAAOA,CAAAA,CAAI,SAAS,KAAK,CAC3B,CAEO,IAAMe,CAAAA,CAAU,IAAM,IAAA,CAAK,GAAA,EAAI,CAEzBC,CAAAA,CAAO,IAAM,CAAC,CAAA,CAcpB,SAASC,GAAmB/B,CAAAA,CAAqB,CACtD,IAAM,CAAA,CAAI,OAAOA,CAAAA,CAEjB,OAA2BA,CAAAA,EAAU,IAAA,CAC5B,KAAA,CAGL,CAAA,GAAMX,CAAAA,EAAU,CAAA,GAAM,QAAA,EAAY,IAAM,SAAA,EAIxC,KAAA,CAAM,OAAA,CAAQW,CAAK,CAAA,CACd,IAAA,CAIP,OAAO,UAAA,GAAeb,CAAAA,EACtB,OAAO,UAAA,CAAW,MAAA,GAAWA,CAAAA,EAC7B,UAAA,CAAW,OAAO,QAAA,CAASa,CAAK,CAAA,EAK9BA,CAAAA,YAAiB,IAAA,EAAQH,EAAAA,CAAeG,CAAK,CAAA,CACxC,KAAA,CAGL,CAAA,EAAAD,CAAAA,CAASC,CAAK,CAAA,GACF,MAAA,CAAO,eAAeA,CAAK,CAAA,GAG3B,MAAA,CAAO,SAAA,EAKjB,OAAOA,CAAAA,CAAM,MAAA,GAAWV,CAAAA,CAAAA,CAMhC,CAEA,eAAsB0C,CAAAA,CAAgBC,CAAAA,CAA8B,CAClE,OAAO,IAAI,OAAA,CAASC,CAAAA,EAClB,UAAA,CAAW,IACFA,CAAAA,CAAQ,IAAI,CAAA,CAClBD,CAAE,CACP,CACF,CAWO,SAASE,EAAAA,CAAYrC,CAAAA,CAAW0B,EAAQ,CAAA,CAAQ,CACrD,OAAIA,CAAAA,EAAS5B,EAAAA,CACJE,CAAAA,CAGLA,CAAAA,EAAQC,CAAAA,CAASD,CAAI,CAAA,EAAK,OAAOA,CAAAA,CAAK,IAAA,GAASX,CAAAA,CAC1CgD,GAAYrC,CAAAA,CAAK,IAAA,CAAM0B,CAAAA,CAAQ,CAAC,CAAA,CAGlC1B,CACT,CAYO,SAASsC,EAAAA,CACdC,CAAAA,CACe,CACf,GAAI,CAACA,CAAAA,CACH,OAAO,EAAC,CAGV,IAAMC,CAAAA,CAA+B,EAAC,CAGtC,GAAID,CAAAA,YAAmB,OAAA,CACrBA,CAAAA,CAAQ,OAAA,CAAQ,CAACrC,CAAAA,CAAOS,CAAAA,GAAQ,CAC9B6B,CAAAA,CAAc7B,CAAG,CAAA,CAAIT,EACvB,CAAC,CAAA,CAAA,KAAA,GACQD,CAAAA,CAASsC,CAAO,CAAA,CAEzB,IAAA,GAAW,CAAC5B,CAAAA,CAAKT,CAAK,CAAA,GAAK,OAAO,OAAA,CAAQqC,CAAO,CAAA,CAG/CC,CAAAA,CAAc7B,CAAAA,CAAI,WAAA,EAAa,CAAA,CAAIT,CAAAA,CAIvC,OAAOsC,CACT,CAOO,SAASC,EAAAA,EAAqB,CAEnC,OACE,OAAO,MAAA,GAAWpD,CAAAA,EAAa,OAAO,MAAA,CAAO,gBAAA,GAAqBG,CAEtE,CAMO,IAAMkD,EAAAA,CAAmB,IAAe,CAE7C,GAAI,CAACD,EAAAA,EAAU,CACb,OAAO,MAAA,CAGT,IAAME,CAAAA,CAAO,SAAA,EAAc,SAAA,CAAkB,UAAA,CAE7C,OAAOA,CAAAA,EAAQ,CAAC,SAAA,CAAW,IAAA,CAAM,IAAI,CAAA,CAAE,QAAA,CAASA,CAAAA,CAAK,aAAa,CACpE,ECzWA,eAAsBC,CAAAA,CAKpBC,CAAAA,CAA6B7C,CAAAA,CAAAA,GAAY8C,CAAAA,CAA2B,CACpE,GAAKD,CAAAA,CAAAA,CAIL,GAAI,OAAOA,CAAAA,GAAiBrD,CAAAA,CAAU,CACpC,IAAMU,CAAAA,CAAQ,MAAO2C,CAAAA,CACnB7C,CAAAA,CACA,GAAG8C,CACL,CAAA,CAEI5C,CAAAA,EAASD,CAAAA,CAASD,CAAI,CAAA,EAAKC,CAAAA,CAASC,CAAK,CAAA,EAC3C,MAAA,CAAO,MAAA,CAAOF,CAAAA,CAAME,CAAK,EAE7B,CAAA,KAAA,GAAW,KAAA,CAAM,OAAA,CAAQ2C,CAAY,CAAA,CACnC,QAAWE,CAAAA,IAAeF,CAAAA,CAAc,CACtC,IAAM3C,CAAAA,CAAQ,MAAM6C,CAAAA,CAAY/C,CAAAA,CAAM,GAAG8C,CAAI,CAAA,CAEzC5C,CAAAA,EAASD,CAAAA,CAASD,CAAI,GAAKC,CAAAA,CAASC,CAAK,CAAA,EAC3C,MAAA,CAAO,MAAA,CAAOF,CAAAA,CAAME,CAAK,EAE7B,CAAA,CAEJ,CCjCO,IAAM8C,EAAAA,CAAN,cAKG,KAAM,CAMd,WAAA,CACEC,CAAAA,CACOC,CAAAA,CAMAC,CAAAA,CAMP,CACA,KAAA,CAAMF,CAAO,CAAA,CAbN,IAAA,CAAA,OAAA,CAAAC,CAAAA,CAMA,IAAA,CAAA,QAAA,CAAAC,CAAAA,CASP,IAAA,CAAK,IAAA,CAAO,aACZ,IAAA,CAAK,MAAA,CAASA,CAAAA,CAAWA,CAAAA,CAAS,MAAA,CAAS,CAAA,CAC3C,IAAA,CAAK,UAAA,CAAaA,CAAAA,CAAWA,CAAAA,CAAS,UAAA,CAAa,EAAA,CACnD,IAAA,CAAK,MAAA,CAASD,EACd,IAAA,CAAK,WAAA,CAAc,MACrB,CA3BA,MAAA,CACA,UAAA,CACA,MAAA,CACA,WAyBF,CAAA,CCpCO,IAAME,EAAAA,CAAN,cAKGJ,EAA+D,CACvE,YACEC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CAMA,CACA,KAAA,CAAMF,CAAAA,CAASC,CAAAA,CAASC,CAAQ,CAAA,CAEhC,IAAA,CAAK,IAAA,CAAO,gBACd,CACF,CAAA,KCHME,EAAAA,CAAa,GAAA,CACbC,EAAAA,CAAS,GAAA,CACTC,EAAAA,CAAeF,EAAAA,CAAaC,EAAAA,CAC5BE,CAAAA,CAAyB,KAAA,CAAMH,EAAU,CAAA,CAC5C,IAAA,CAAK,CAAC,CAAA,CACN,IAAI,IAAM,EAAE,CAAA,CAETI,CAAAA,CAAS,IAAI,GAAA,CACfC,CAAAA,CAAW,CAAA,CACXC,CAAAA,CAA+B,IAAA,CAE7BC,EAAAA,CAAiB,CAAC,CAACjD,EAAKkD,CAAQ,CAAA,GAAyB,CAC7DJ,CAAAA,CAAO,MAAA,CAAO9C,CAAG,CAAA,CAEjB,GAAI,CACF,IAAMmD,CAAAA,CAASD,CAAAA,EAAS,CACpBC,CAAAA,EAAUA,aAAkB,OAAA,EAE9BA,CAAAA,CAAO,KAAA,CAAM9B,CAAI,EAErB,CAAA,KAAQ,CAER,CACF,CAAA,CAEa+B,CAAAA,CAAa,CACxBpD,CAAAA,CACAqD,CAAAA,CACA7B,CAAAA,GACS,CAIT,GAHA8B,CAAAA,CAActD,CAAG,CAAA,CAGbwB,CAAAA,CAAKoB,EAAAA,EAAgBpB,CAAAA,CAAKmB,EAAAA,GAAW,CAAA,CAAG,CAC1CG,CAAAA,CAAO,GAAA,CAAI9C,CAAAA,CAAK,CAAC,WAAWiD,EAAAA,CAAe,IAAA,CAAK,IAAA,CAAM,CAACjD,CAAAA,CAAKqD,CAAE,CAAC,CAAA,CAAG7B,CAAE,CAAC,CAAC,CAAA,CAEtE,MACF,CAGA,IAAM+B,CAAAA,CAAU/B,CAAAA,CAAKmB,EAAAA,CACfa,CAAAA,CAAAA,CAAQT,CAAAA,CAAWQ,CAAAA,EAAWb,EAAAA,CAEpCG,CAAAA,CAAMW,CAAI,CAAA,CAAE,IAAA,CAAK,CAACxD,CAAAA,CAAKqD,CAAE,CAAC,CAAA,CAC1BP,CAAAA,CAAO,GAAA,CAAI9C,CAAAA,CAAKwD,CAAI,CAAA,CAEfR,CAAAA,GACHA,CAAAA,CAAQ,WAAA,CAAY,IAAM,CACxBD,CAAAA,CAAAA,CAAYA,CAAAA,CAAW,CAAA,EAAKL,GAC5BG,CAAAA,CAAME,CAAQ,CAAA,CAAE,OAAA,CAAQE,EAAc,CAAA,CACtCJ,CAAAA,CAAME,CAAQ,CAAA,CAAI,EAAC,CAEf,CAACD,CAAAA,CAAO,IAAA,EAAQE,IAClB,aAAA,CAAcA,CAAK,CAAA,CACnBA,CAAAA,CAAQ,IAAA,EAEZ,CAAA,CAAGL,EAAM,CAAA,EAEb,CAAA,CAEaW,CAAAA,CAAiBtD,CAAAA,EAAsB,CAClD,IAAMyD,CAAAA,CAAgBX,EAAO,GAAA,CAAI9C,CAAG,CAAA,CAEhCyD,CAAAA,GAAkB,MAAA,GAEhB,KAAA,CAAM,OAAA,CAAQA,CAAa,CAAA,CAC7B,YAAA,CAAaA,CAAAA,CAAc,CAAC,CAAC,CAAA,CAE7BZ,EAAMY,CAAa,CAAA,CAAE,MAAA,CACnBZ,CAAAA,CAAMY,CAAa,CAAA,CAAE,SAAA,CAAU,CAAC,CAAC9C,CAAC,CAAA,GAAMA,CAAAA,GAAMX,CAAG,CAAA,CACjD,CACF,CAAA,CAGF8C,CAAAA,CAAO,MAAA,CAAO9C,CAAG,CAAA,CAEb,CAAC8C,CAAAA,CAAO,IAAA,EAAQE,CAAAA,GAClB,aAAA,CAAcA,CAAK,CAAA,CACnBA,CAAAA,CAAQ,IAAA,CAAA,EAGd,EC5EA,IAAMU,CAAAA,CAAsC,IAAI,GAAA,CAazC,SAASC,EAAAA,CACd3D,CAAAA,CACAK,CAAAA,CACAuD,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACiB,CACjB,GAAI,CAAC/D,CAAAA,CACH,OAAO,IAAI,eAAA,CAGb,IAAMgE,CAAAA,CAAON,CAAAA,CAAS,GAAA,CAAI1D,CAAG,CAAA,CACzBiE,CAAAA,CAAuC,IAAA,CAG3C,GAAID,CAAAA,CAAM,CACR,IAAME,CAAAA,CAAiBF,CAAAA,CAAK,CAAC,CAAA,CACvBG,CAAAA,CAAoBH,CAAAA,CAAK,CAAC,CAAA,CAGhC,GACE,CAACG,CAAAA,EACD/C,CAAAA,EAAQ,CAAI4C,EAAK,CAAC,CAAA,CAAIH,CAAAA,EACtB,CAACK,CAAAA,CAAe,MAAA,CAAO,OAAA,CAEvB,OAAOA,CAAAA,CAKLC,CAAAA,EACFD,CAAAA,CAAe,KAAA,CACb,IAAI,YAAA,CAAa,6BAA8BpF,CAAW,CAC5D,CAAA,CAGFwE,CAAAA,CAActD,CAAG,CAAA,CACjBiE,CAAAA,CAAcD,CAAAA,CAAK,CAAC,EACtB,CAEA,IAAMI,CAAAA,CAAa,IAAI,gBAEvB,OAAAV,CAAAA,CAAS,GAAA,CAAI1D,CAAAA,CAAK,CAChBoE,CAAAA,CACAL,CAAAA,CACA3C,CAAAA,EAAQ,CACR0C,CAAAA,CACAG,CACF,CAAC,CAAA,CAEGF,CAAAA,EACFX,EACEpD,CAAAA,CACA,IAAM,CACJqE,EAAAA,CACErE,CAAAA,CACA,IAAI,YAAA,CAAaK,CAAAA,CAAM,yBAAA,CAA2BtB,EAAa,CACjE,EACF,CAAA,CACA6E,CACF,EAGKQ,CACT,CASA,eAAsBC,EAAAA,CACpBrE,CAAAA,CACAsE,CAAAA,CAAsC,IAAA,CACvB,CAEf,GAAItE,CAAAA,CAAK,CACP,IAAMgE,CAAAA,CAAON,CAAAA,CAAS,IAAI1D,CAAG,CAAA,CAEzBgE,CAAAA,GAEEM,CAAAA,EACiBN,CAAAA,CAAK,CAAC,CAAA,CACd,KAAA,CAAMM,CAAK,CAAA,CAGxBC,EAAAA,CAAevE,CAAG,CAAA,EAEtB,CACF,CAOO,SAASuE,EAAAA,CAAevE,CAAAA,CAA0B,CACvDsD,CAAAA,CAActD,CAAI,CAAA,CAClB0D,CAAAA,CAAS,MAAA,CAAO1D,CAAI,EACtB,CAsBO,SAASwE,EAAAA,CACdxE,EACAyE,CAAAA,CACM,CACN,IAAMT,CAAAA,CAAON,CAAAA,CAAS,GAAA,CAAI1D,CAAG,CAAA,CACzBgE,CAAAA,GAEFA,CAAAA,CAAK,CAAC,CAAA,CAAIS,CAAAA,CAEVf,CAAAA,CAAS,IAAI1D,CAAAA,CAAKgE,CAAI,CAAA,EAE1B,CASO,SAASU,EAAAA,CACd1E,CAAAA,CACA6D,CAAAA,CACmB,CACnB,GAAI,CAAC7D,CAAAA,CACH,OAAO,IAAA,CAGT,IAAM2E,CAAAA,CAAUjB,CAAAA,CAAS,GAAA,CAAI1D,CAAG,CAAA,CAEhC,OACE2E,CAAAA,EAEAA,CAAAA,CAAQ,CAAC,CAAA,EAET,CAACA,CAAAA,CAAQ,CAAC,CAAA,EAEVvD,GAAQ,CAAIuD,CAAAA,CAAQ,CAAC,CAAA,CAAId,CAAAA,EAEzB,CAACc,CAAAA,CAAQ,CAAC,CAAA,CAAE,MAAA,CAAO,OAAA,CAEZA,CAAAA,CAAQ,CAAC,CAAA,CAGX,IACT,CC5MO,SAASC,CAAAA,CAAKC,CAAAA,CAAqB,CACxC,IAAID,CAAAA,CAAO,CAAA,CAEX,IAAA,IAAS9E,CAAAA,CAAI,CAAA,CAAGC,CAAAA,CAAM8E,CAAAA,CAAI,MAAA,CAAQ/E,EAAIC,CAAAA,CAAKD,CAAAA,EAAAA,CAAK,CAC9C,IAAMgF,CAAAA,CAAOD,CAAAA,CAAI,UAAA,CAAW/E,CAAC,CAAA,CAC7B8E,CAAAA,CAAQA,CAAAA,CAAO,EAAA,CAAmBE,CAAAA,CAAQ,EAC5C,CAEA,OAAO,MAAA,CAAOF,CAAI,CACpB,CCmBA,IAAMG,EAAAA,CAAc,GAAA,CAAS,GAAA,CACvBC,CAAAA,CAAe,IAAI,GAAA,CAUnBC,EAAAA,CAAgB,IAAI,IAUnB,SAASC,EAAAA,CACdC,CAAAA,CACAC,CAAAA,CAA+B,IAAA,CAC/B,CACA,IAAMC,CAAAA,CAAYF,CAAAA,GAAS,OAAA,CAAU,CAAA,CAAI,CAAA,CACnCG,CAAAA,CAAMlE,CAAAA,GAEZ4D,CAAAA,CAAa,OAAA,CAASO,CAAAA,EAAU,CAC9B,GAAI,CAACA,CAAAA,CAAMF,CAAS,CAAA,CAClB,OAGFE,CAAAA,CAAM,CAAC,CAAA,CAAID,CAAAA,CAGX,IAAME,CAAAA,CAAcJ,CAAAA,CAAsBG,CAAAA,CAAM,CAAC,CAAA,CAAIA,CAAAA,CAAM,CAAC,CAAA,CAExDC,CAAAA,EACF,OAAA,CAAQ,OAAA,CAAQA,CAAAA,CAAYJ,CAAmB,CAAC,EAAE,KAAA,CAAM/D,CAAI,EAEhE,CAAC,EACH,CAUA,eAAsBoE,EAAAA,CACpBzF,CAAAA,CACAoF,CAAAA,CAA+B,KAAA,CACI,CAEnC,GAAI,CAACpF,EACH,OAAO,IAAA,CAGT,IAAMuF,CAAAA,CAAQP,CAAAA,CAAa,GAAA,CAAIhF,CAAG,CAAA,CAElC,GAAIuF,CAAAA,CAAO,CAETA,CAAAA,CAAM,CAAC,CAAA,CAAInE,GAAQ,CAEnB,IAAMoE,CAAAA,CAAcJ,CAAAA,CAAsBG,CAAAA,CAAM,CAAC,CAAA,CAAIA,CAAAA,CAAM,CAAC,CAAA,CAG5D,GAAIC,CAAAA,CACF,OAAO,MAAMA,EAAYJ,CAAmB,CAEhD,CAGA,OAAO,IACT,CAOO,SAASM,EAAAA,CAAmBP,CAAAA,CAAiB,CAClDQ,EAAAA,CAAmBR,CAAI,CAAA,CAEvB,IAAME,EAAYF,CAAAA,GAAS,OAAA,CAAU,CAAA,CAAI,CAAA,CAGzCH,CAAAA,CAAa,OAAA,CAAQ,CAACO,CAAAA,CAAOvF,CAAAA,GAAQ,CAC/BuF,CAAAA,CAAMF,CAAS,CAAA,EACjBO,EAAAA,CAAkB5F,CAAG,EAEzB,CAAC,EACH,CAQA,SAAS6F,EAAAA,CAAgBC,CAAAA,CAAkB,CACzC,GAAI,CAAChE,EAAAA,EAAU,EAAKmD,EAAAA,CAAc,GAAA,CAAIa,CAAK,CAAA,CACzC,OAGF,IAAMC,CAAAA,CAAUb,EAAAA,CAAc,IAAA,CAAK,IAAA,CAAMY,CAAAA,CAAO,IAAI,CAAA,CAEpDb,EAAAA,CAAc,GAAA,CAAIa,CAAAA,CAAOC,CAAO,EAChC,MAAA,CAAO,gBAAA,CAAiBD,CAAAA,CAAOC,CAAO,EACxC,CAOA,SAASJ,EAAAA,CAAmBG,CAAAA,CAAkB,CAC5C,GAAI,CAAChE,EAAAA,EAAU,CACb,OAGF,IAAMiE,CAAAA,CAAUd,EAAAA,CAAc,GAAA,CAAIa,CAAK,CAAA,CAEnCC,CAAAA,GACF,MAAA,CAAO,mBAAA,CAAoBD,CAAAA,CAAOC,CAAO,CAAA,CAEzCd,EAAAA,CAAc,MAAA,CAAOa,CAAK,CAAA,EAE9B,CAaO,SAASE,EAAAA,CACdhG,CAAAA,CACAiG,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACA,CACAtB,CAAAA,CAAa,GAAA,CAAIhF,EAAK,CACpBiG,CAAAA,CACA7E,CAAAA,EAAQ,CACD2D,EAAAA,CACPoB,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CACF,CAAC,CAAA,CAEGD,CAAAA,EACFR,EAAAA,CAAgB,OAAO,CAAA,CAGrBS,CAAAA,EACFT,EAAAA,CAAgB,QAAQ,CAAA,CAGtBM,CAAAA,EACF/C,CAAAA,CAAW,IAAA,CAAOpD,CAAAA,CAAKyF,EAAAA,CAAW,IAAA,CAAK,IAAA,CAAMzF,CAAAA,CAAK,IAAI,EAAGmG,CAAAA,CAAY,GAAI,EAE7E,CAEO,SAASP,EAAAA,CAAkB5F,CAAAA,CAAa,CAC7CgF,CAAAA,CAAa,MAAA,CAAOhF,CAAG,CAAA,CAGvBsD,CAAAA,CAAc,IAAA,CAAOtD,CAAG,EAC1B,CChMA,IAAMuG,CAAAA,CAAY,IAAI,GAAA,CAEtB,SAASC,EAAAA,CAAkBxG,CAAAA,CAAa,CACtC,OAAKuG,CAAAA,CAAU,GAAA,CAAIvG,CAAG,GACpBuG,CAAAA,CAAU,GAAA,CAAIvG,CAAAA,CAAK,IAAI,GAAK,CAAA,CAGvBuG,CAAAA,CAAU,GAAA,CAAIvG,CAAG,CAC1B,CAGO,SAASyG,EAAAA,CAAqBzG,CAAAA,CAAa0G,EAAuB,CACvEF,EAAAA,CAAkBxG,CAAG,CAAA,CAAE,GAAA,CAAI0G,CAAE,EAC/B,CAEO,SAASC,EAAAA,CAAkB3G,CAAAA,CAAa0G,CAAAA,CAAiB,CAC9D,IAAME,EAAML,CAAAA,CAAU,GAAA,CAAIvG,CAAG,CAAA,CAEzB4G,CAAAA,GACFA,CAAAA,CAAI,MAAA,CAAOF,CAAE,CAAA,CAGTE,CAAAA,CAAI,IAAA,GAAS,CAAA,EACfL,CAAAA,CAAU,MAAA,CAAOvG,CAAG,CAAA,EAG1B,CAEO,SAAS6G,CAAAA,CAAqB7G,CAAAA,CAAawC,CAAAA,CAAa,CAC7D,IAAMsE,CAAAA,CAAMP,CAAAA,CAAU,GAAA,CAAIvG,CAAG,CAAA,CAE7B,GAAI8G,EACF,GAAIA,CAAAA,CAAI,IAAA,GAAS,CAAA,CAAG,CAElB,IAAMJ,CAAAA,CAAKI,CAAAA,CAAI,MAAA,EAAO,CAAE,IAAA,EAAK,CAAE,KAAA,CAC/BJ,CAAAA,CAAIlE,CAAQ,EACd,CAAA,KACEsE,CAAAA,CAAI,OAAA,CAASJ,CAAAA,EAAOA,CAAAA,CAAGlE,CAAQ,CAAC,EAGtC,CAEO,SAASuE,EAAAA,CAAa/G,CAAAA,CAAoB0G,CAAAA,CAA2B,CAC1E,OAAK1G,CAAAA,EAKLyG,EAAAA,CAAezG,CAAAA,CAAK0G,CAAE,CAAA,CAGf,IAAM,CACXC,EAAAA,CAAe3G,CAAAA,CAAK0G,CAAE,EACxB,CAAA,EARSrF,CASX,CCtDA,IAAM2F,EAAAA,CAAAA,CAAoBjF,EAAAA,EAAiB,CAAI,EAAA,CAAK,EAAA,EAAM,GAAA,CAE7CkF,CAAAA,CAA+B,CAC1C,QAAA,CAAU/H,EAAAA,CACV,OAAA,CAAS8H,EAAAA,CACT,OAAA,CAAS,CACP,MAAA,CAAQzI,CAAAA,CAAmB,mBAAA,CAC3B,iBAAA,CAAmB,mBACrB,CAAA,CACA,KAAA,CAAO,CACL,KAAA,CAAOyI,EAAAA,CAAmB,EAAA,CAC1B,QAAA,CAAUA,EAAAA,CACV,YAAA,CAAc,KACd,OAAA,CAAS,GAAA,CAGT,OAAA,CAAS,CACP,GAAA,CACA,GAAA,CACA,GAAA,CACA,GAAA,CACA,GAAA,CACA,GAAA,CACA,GAAA,CACA,GACF,CACF,CACF,EAQO,SAASE,EAAAA,CACdC,CAAAA,CACwB,CACxB,IAAMC,CAAAA,CAAY5H,CAAAA,CAAe2H,CAAY,CAAA,CAE7C,OAAA,MAAA,CAAO,MAAA,CAAOF,CAAAA,CAAeG,CAAS,CAAA,CAE/BH,CACT,CAOO,SAASI,EAAAA,EAAkC,CAChD,OAAO,CAAE,GAAGJ,CAAc,CAC5B,CASO,SAASK,EAAAA,CACdjH,CAAAA,CACAkH,CAAAA,CAMmE,CACnE,GAAI,CAACA,CAAAA,CACH,OAAOC,EAAAA,CAAmBnH,CAAAA,CAAKgH,EAAAA,EAAkB,CAAA,CAGnD,IAAMD,CAAAA,CAAY5H,CAAAA,CAAe+H,CAAS,CAAA,CACpCE,EAASC,CAAAA,CAAaT,CAAAA,CAAeG,CAAS,CAAA,CAEpD,OAAOI,EAAAA,CAAmBnH,CAAAA,CAAKoH,CAAM,CACvC,CASO,SAASD,EAAAA,CACdnH,CAAAA,CACAsH,CAAAA,CACe,CACf,IAAIC,CAAAA,CAASD,CAAAA,CAAc,MAAA,CAC3BC,CAAAA,CAASA,CAAAA,CAAUA,CAAAA,CAAO,WAAA,EAAY,CAAe5I,CAAAA,CAErD,IAAI6I,CAAAA,CAGAD,CAAAA,GAAW5I,CAAAA,EAAO4I,IAAW3I,EAAAA,GAC/B4I,CAAAA,CAAOF,CAAAA,CAAc,IAAA,EAAQA,CAAAA,CAAc,IAAA,CAGvCE,CAAAA,EAAQ,OAAOA,CAAAA,GAASjJ,CAAAA,EAAU0C,EAAAA,CAAmBuG,CAAI,CAAA,GAC3DA,CAAAA,CAAO,KAAK,SAAA,CAAUA,CAAI,CAAA,CAAA,CAAA,CAI9BC,EAAAA,CAAuBH,CAAAA,CAAc,OAAA,CAASE,CAAI,CAAA,CAGlD,IAAME,CAAAA,CAAcJ,CAAAA,CAAc,eAAA,CAC9B,SAAA,CACAA,CAAAA,CAAc,YAGZK,CAAAA,CAAahH,EAAAA,CAAqBX,CAAAA,CAAKsH,CAAAA,CAAc,aAAa,CAAA,CAClEM,CAAAA,CAAU7H,EAAAA,CAAkB4H,CAAAA,CAAYL,CAAAA,CAAc,MAAM,CAAA,CAE5DO,CAAAA,CADY/G,EAAAA,CAAcd,CAAG,CAAA,CAE/B,EAAA,CACAsH,CAAAA,CAAc,OAAA,EAAWA,CAAAA,CAAc,MAAA,EAAU,EAAA,CAErD,OAAAA,CAAAA,CAAc,GAAA,CAAMO,CAAAA,CAAUD,CAAAA,CAC9BN,CAAAA,CAAc,MAAA,CAASC,EACvBD,CAAAA,CAAc,WAAA,CAAcI,CAAAA,CAC5BJ,CAAAA,CAAc,IAAA,CAAOE,CAAAA,CAEdF,CACT,CAWA,SAASG,EAAAA,CACPlG,CAAAA,CACAiG,CAAAA,CACM,CAON,GALI,CAACjG,CAAAA,EAAW,CAACiG,CAAAA,EAMfA,CAAAA,YAAgB,QAAA,EACf,OAAO,IAAA,GAASnJ,CAAAA,EAAamJ,CAAAA,YAAgB,IAAA,EAC7C,OAAO,IAAA,GAASnJ,CAAAA,EAAamJ,CAAAA,YAAgB,MAC7C,OAAO,cAAA,GAAmBnJ,CAAAA,EAAamJ,CAAAA,YAAgB,cAAA,CAExD,OAGF,IAAIM,CAAAA,CAEJ,GAAI/I,EAAAA,CAAeyI,CAAI,CAAA,CACrBM,CAAAA,CAAmB7J,CAAAA,CAA2B,gCACrCuJ,CAAAA,YAAgB,WAAA,EAAe,WAAA,CAAY,MAAA,CAAOA,CAAI,CAAA,CAC/DM,CAAAA,CAAmB7J,CAAAA,CAA2B,cAAA,CAAA,KAAA,GACrCgD,EAAAA,CAAmBuG,CAAI,CAAA,CAChCM,CAAAA,CAAmB5J,CAAAA,CAAmB,IAAMC,EAAAA,CAAAA,KAG5C,OAGEoD,CAAAA,YAAmB,OAAA,CAChBA,CAAAA,CAAQ,GAAA,CAAInD,CAAY,CAAA,EAC3BmD,CAAAA,CAAQ,GAAA,CAAInD,CAAAA,CAAc0J,CAAgB,CAAA,CAG5C7I,CAAAA,CAASsC,CAAO,CAAA,EAChB,CAAC,KAAA,CAAM,OAAA,CAAQA,CAAO,CAAA,EACtB,CAACA,CAAAA,CAAQnD,CAAY,CAAA,GAErBmD,CAAAA,CAAQnD,CAAY,CAAA,CAAI0J,CAAAA,EAE5B,CAEO,SAAST,CAAAA,CACdU,CAAAA,CACAC,CAAAA,CACe,CACf,IAAMC,CAAAA,CAA8B,MAAA,CAAO,MAAA,CACzC,EAAC,CACDF,CAAAA,CACAC,CACF,CAAA,CAGA,OAAAE,EAAAA,CAAY,OAAA,CAASD,CAAAA,CAAcF,CAAAA,CAAYC,CAAc,CAAA,CAC7DE,EAAAA,CAAY,SAAA,CAAWD,CAAAA,CAAcF,CAAAA,CAAYC,CAAc,CAAA,CAG/DG,EAAAA,CAAkB,WAAA,CAAaF,EAAcF,CAAAA,CAAYC,CAAc,CAAA,CACvEG,EAAAA,CAAkB,YAAA,CAAcF,CAAAA,CAAcF,CAAAA,CAAYC,CAAc,CAAA,CACxEG,EAAAA,CAAkB,SAAA,CAAWF,CAAAA,CAAcF,CAAAA,CAAYC,CAAc,EAE9DC,CACT,CAKA,SAASE,EAAAA,CAGPC,CAAAA,CACAC,CAAAA,CACAN,CAAAA,CACAC,CAAAA,CACM,CACN,IAAMM,CAAAA,CAAkBP,CAAAA,CAAWK,CAAQ,CAAA,CACrCG,EAAiBP,CAAAA,CAAeI,CAAQ,CAAA,CAE9C,GAAI,CAACE,CAAAA,EAAmB,CAACC,CAAAA,CACvB,OAGF,GAAI,CAACD,CAAAA,CAAiB,CACpBD,CAAAA,CAAaD,CAAQ,CAAA,CAAIG,CAAAA,CACzB,MACF,CAEA,GAAI,CAACA,CAAAA,CAAgB,CACnBF,CAAAA,CAAaD,CAAQ,CAAA,CAAIE,CAAAA,CACzB,MACF,CAEA,IAAME,CAAAA,CAAU,KAAA,CAAM,OAAA,CAAQF,CAAe,CAAA,CACzCA,CAAAA,CACA,CAACA,CAAe,CAAA,CACdG,CAAAA,CAAS,KAAA,CAAM,OAAA,CAAQF,CAAc,CAAA,CACvCA,EACA,CAACA,CAAc,CAAA,CAGnBF,CAAAA,CAAaD,CAAQ,CAAA,CACnBA,CAAAA,GAAa,YAAA,CAAeK,CAAAA,CAAO,MAAA,CAAOD,CAAO,CAAA,CAAIA,CAAAA,CAAQ,MAAA,CAAOC,CAAM,EAC9E,CAUO,SAASP,EAAAA,CACdE,CAAAA,CACAC,CAAAA,CACAN,EACAC,CAAAA,CACM,CACFA,CAAAA,CAAeI,CAAQ,CAAA,GACzBC,CAAAA,CAAaD,CAAQ,CAAA,CAAI,CACvB,GAAGL,CAAAA,CAAWK,CAAQ,CAAA,CACtB,GAAGJ,CAAAA,CAAeI,CAAQ,CAC5B,CAAA,EAEJ,CC9QA,IAAMM,EAAAA,CAAS,IAAI,GAAA,CACbC,CAAAA,CAAY,GAAA,CACZC,EAAAA,CAAqB,EAAA,CACrBC,EAAAA,CAA6B,IAAI,MAAA,CAAO,aAAA,CAAe,GAAG,CAAA,CAM1DC,EAAAA,CAA6B,IAAI,GAAA,CAAI,CAEzC,QAAA,CACA,iBAAA,CACA,iBAAA,CAGA,eAAA,CAGA,cAAA,CAGA,SAAA,CACA,QAAA,CACA,YAAA,CAGA,QAAA,CAGA,WAAA,CACA,kBAAA,CACA,aAAA,CACA,aAAA,CACA,WAAA,CAEA,gBACA,gBAAA,CACA,aAAA,CACA,YAAA,CAEA,cAAA,CACA,UACF,CAAC,CAAA,CA0BM,SAASC,CAAAA,CACdC,CAAAA,CACAC,CAAAA,CAAgB,IAAA,CACR,CAGR,IAAMtJ,EAAMqJ,CAAAA,CAAO,QAAA,CAEnB,GAAIrJ,CAAAA,EAAOsJ,CAAAA,CACT,OAAO,OAAOtJ,CAAAA,GAAQpB,CAAAA,CACjBoB,CAAAA,CACAA,CAAAA,CAAyBqJ,CAAM,CAAA,CAGtC,GAAM,CACJ,GAAA,CAAAhJ,CAAAA,CAAM,EAAA,CACN,MAAA,CAAAuH,CAAAA,CAAS5I,CAAAA,CACT,OAAA,CAAA4C,CAAAA,CAAU,IAAA,CACV,IAAA,CAAAiG,CAAAA,CAAO,IAAA,CACP,WAAA,CAAAE,CAAAA,CAAc,aAChB,CAAA,CAAIsB,CAAAA,CAIAE,CAAAA,CAAgB,EAAA,CACpB,GAAI3H,CAAAA,CAAS,CACX,IAAInC,CAAAA,CAEAmC,CAAAA,YAAmB,OAAA,CACrBnC,CAAAA,CAAMkC,EAAAA,CAAeC,CAAO,EAE5BnC,CAAAA,CAAMmC,CAAAA,CAKR,IAAMhC,CAAAA,CAAO,MAAA,CAAO,IAAA,CAAKH,CAAG,CAAA,CACtBM,CAAAA,CAAMH,CAAAA,CAAK,MAAA,CAGbG,CAAAA,CAAM,CAAA,EACRH,CAAAA,CAAK,MAAK,CAGZ,IAAIiF,CAAAA,CAAM,EAAA,CACV,IAAA,IAAS/E,CAAAA,CAAI,CAAA,CAAGA,CAAAA,CAAIC,CAAAA,CAAK,EAAED,CAAAA,CACrBqJ,EAAAA,CAA2B,GAAA,CAAIvJ,CAAAA,CAAKE,CAAC,CAAA,CAAE,WAAA,EAAa,CAAA,GACtD+E,CAAAA,EAAOjF,CAAAA,CAAKE,CAAC,CAAA,CAAI,GAAA,CAAML,CAAAA,CAAIG,CAAAA,CAAKE,CAAC,CAAC,CAAA,CAAI,KAI1CyJ,CAAAA,CAAgB3E,CAAAA,CAAKC,CAAG,EAC1B,CAGA,GAAI+C,CAAAA,GAAW5I,CAAAA,CACb,OAAA,CACE4I,CAAAA,CACAoB,CAAAA,CACA3I,CAAAA,CACA2I,CAAAA,CACAjB,CAAAA,CACAiB,EACAO,CAAAA,EACA,OAAA,CAAQL,EAAAA,CAA4B,EAAE,CAAA,CAG1C,IAAIM,CAAAA,CAAa,EAAA,CACjB,GAAI3B,CAAAA,CACF,GAAI,OAAOA,CAAAA,GAASjJ,CAAAA,CAClB4K,EAAa3B,CAAAA,CAAK,MAAA,CAASoB,EAAAA,CAAqBpB,CAAAA,CAAOjD,CAAAA,CAAKiD,CAAI,CAAA,CAAA,KAAA,GACvDA,CAAAA,YAAgB,QAAA,CACzBA,CAAAA,CAAK,OAAA,CAAQ,CAACtI,CAAAA,CAAOS,CAAAA,GAAQ,CAE3BwJ,CAAAA,EAAcxJ,CAAAA,CAAM,GAAA,CAAMT,CAAAA,CAAQ,IACpC,CAAC,CAAA,CAEGiK,CAAAA,CAAW,MAAA,CAASP,EAAAA,GACtBO,CAAAA,CAAa5E,CAAAA,CAAK4E,CAAU,CAAA,CAAA,CAAA,KAAA,GAG7B,OAAO,IAAA,GAAS9K,CAAAA,EAAamJ,CAAAA,YAAgB,IAAA,EAC7C,OAAO,IAAA,GAASnJ,CAAAA,EAAamJ,CAAAA,YAAgB,IAAA,CAE9C2B,CAAAA,CAAa,IAAA,CAAO3B,CAAAA,CAAK,IAAA,CAAOA,CAAAA,CAAK,aAC5BA,CAAAA,YAAgB,WAAA,EAAe,WAAA,CAAY,MAAA,CAAOA,CAAI,CAAA,CAC/D2B,CAAAA,CAAa,IAAA,CAAO3B,CAAAA,CAAK,UAAA,CAAA,KACpB,CACL,IAAM4B,CAAAA,CAAInK,CAAAA,CAASuI,CAAI,CAAA,CACnB,IAAA,CAAK,SAAA,CAAUlI,EAAAA,CAAWkI,CAAI,CAAC,CAAA,CAC/B,MAAA,CAAOA,CAAI,CAAA,CAEf2B,CAAAA,CAAaC,CAAAA,CAAE,MAAA,CAASR,EAAAA,CAAqBrE,EAAK6E,CAAC,CAAA,CAAIA,EACzD,CAKF,OAAA,CACE7B,CAAAA,CACAoB,CAAAA,CACA3I,CAAAA,CACA2I,CAAAA,CACAjB,CAAAA,CACAiB,CAAAA,CACAO,CAAAA,CACAP,CAAAA,CACAQ,CAAAA,EACA,QAAQN,EAAAA,CAA4B,EAAE,CAC1C,CAQA,SAASQ,EAAAA,CAAenE,CAAAA,CAAiC,CAEvD,OAAKA,CAAAA,CAAM,MAAA,CAIJnE,CAAAA,EAAQ,CAAImE,CAAAA,CAAM,OAHhB,KAIX,CAQA,SAASoE,EAAAA,CAAapE,CAAAA,CAAiC,CACrD,OAAKA,CAAAA,CAAM,KAAA,CAIJnE,CAAAA,EAAQ,CAAImE,CAAAA,CAAM,KAAA,CAHhB,KAIX,CA+BO,SAASqE,EAAAA,CACd5J,CAAAA,CAMY,CACZ,OAAO+I,EAAAA,CAAO,GAAA,CAAI/I,CAAa,CACjC,CAUO,SAAS6J,EAAAA,CACd7J,CAAAA,CACAX,CAAAA,CACA6G,EACAC,CAAAA,CACM,CACN,GAAID,CAAAA,GAAQ,CAAA,CAAG,CACb4D,EAAAA,CAAY9J,CAAG,CAAA,CACf,MACF,CAEA,IAAM+J,CAAAA,CAAO3I,CAAAA,GACP4I,CAAAA,CAAQ9D,CAAAA,CAAMA,CAAAA,CAAM,GAAA,CAAO,CAAA,CAEjC6C,EAAAA,CAAO,GAAA,CAAI/I,CAAAA,CAAK,CACd,IAAA,CAAAX,CAAAA,CACA,IAAA,CAAA0K,CAAAA,CACA,KAAA,CAAO5D,GAAaA,CAAAA,CAAY,CAAA,CAAI4D,CAAAA,CAAO5D,CAAAA,CAAY,GAAA,CAAOA,CAAAA,CAC9D,MAAA,CAAQD,CAAAA,GAAQ,EAAA,CAAK,MAAA,CAAY6D,CAAAA,CAAOC,CAC1C,CAAC,CAAA,CAEGA,EAAQ,CAAA,EACV5G,CAAAA,CACE,IAAA,CAAOpD,CAAAA,CACP,IAAM,CACJ8J,EAAAA,CAAY9J,CAAAA,CAAK,IAAI,EACvB,CAAA,CACAgK,CACF,EAEJ,CAQO,SAASF,EAAAA,CAAY9J,CAAAA,CAAaiK,CAAAA,CAAyB,KAAA,CAAa,CAC7E,GAAIA,CAAAA,CAAe,CACjB,IAAM1E,CAAAA,CAAQqE,EAAAA,CAAS5J,CAAG,CAAA,CAG1B,GAAI,CAACuF,CAAAA,EAAS,CAACmE,EAAAA,CAAenE,CAAK,CAAA,CACjC,MAEJ,CAEAwD,EAAAA,CAAO,MAAA,CAAO/I,CAAG,EACnB,CAgBA,eAAsBkK,EAAAA,CAMpBlK,EACAmK,CAAAA,CACAC,CAAAA,CAMQ,CAER,GAAI,CAACpK,CAAAA,CACH,OAAO,IAAA,CAGT,IAAMuF,CAAAA,CAAQqE,EAAAA,CACZ5J,CACF,CAAA,CAEA,GAAI,CAACuF,CAAAA,CACH,OAAO,IAAA,CAGT,IAAM8E,CAAAA,CAAc/K,CAAAA,CAAS6K,CAAO,CAAA,CAAI3K,CAAAA,CAAe2K,CAAO,CAAA,CAAIA,CAAAA,CAE5DG,CAAAA,CAAkB,CACtB,GAAG/E,CAAAA,CAAM,IAAA,CACT,IAAA,CAAM8E,CACR,CAAA,CAEME,CAAAA,CAAe,CACnB,GAAGhF,CAAAA,CACH,IAAA,CAAM+E,CACR,CAAA,CAKA,OAHAvB,EAAAA,CAAO,IAAI/I,CAAAA,CAAKuK,CAAY,CAAA,CAC5B1D,CAAAA,CAAkB7G,CAAAA,CAAKsK,CAAe,CAAA,CAElCF,CAAAA,EAAYA,CAAAA,CAAS,OAAA,CAChB,MAAM3E,EAAAA,CAAWzF,CAAG,CAAA,CAGtB,IACT,CAcO,SAASwK,EAAAA,CAMdC,CAAAA,CACAC,CAAAA,CACA/C,CAAAA,CAM0E,CAE1E,GAAI,CAAC8C,CAAAA,EAAYC,CAAAA,GAAc,MAAA,EAAaA,CAAAA,GAAc,IAAA,CACxD,OAAO,IAAA,CAIT,IAAMC,CAAAA,CAAShD,CAAAA,CAAc,WAAA,EAAeV,CAAAA,CAAc,WAAA,CAK1D,GAJI0D,CAAAA,EAAUA,CAAAA,CAAOhD,CAAa,CAAA,EAI9BA,CAAAA,CAAc,KAAA,EAASA,EAAc,KAAA,GAAU,QAAA,CACjD,OAAO,IAAA,CAIT,IAAMpC,CAAAA,CAAQqE,EAAAA,CACZa,CACF,CAAA,CAEA,GAAI,CAAClF,CAAAA,CACH,OAAO,IAAA,CAGT,IAAMqF,CAAAA,CAAYlB,EAAAA,CAAenE,CAAK,CAAA,CAChCsF,CAAAA,CAAUlB,EAAAA,CAAapE,CAAK,CAAA,CAGlC,OAAIqF,CAAAA,EACFd,EAAAA,CAAYW,CAAQ,CAAA,CACb,IAAA,EAIL,CAACI,CAAAA,EAKDA,CAAAA,EAAW,CAACD,CAAAA,CAGPrF,CAAAA,CAAM,IAAA,CAGR,IACT,CASO,SAASuF,EAAAA,CAMdC,CAAAA,CACApD,CAAAA,CAMAqD,CAAAA,CAAmB,KAAA,CACb,CAEN,IAAMP,CAAAA,CAAW9C,CAAAA,CAAc,QAAA,CAE/B,GAAI8C,CAAAA,CAAU,CACZ,IAAMC,CAAAA,CAAY/C,CAAAA,CAAc,SAAA,CAC1BsD,CAAAA,CAAYtD,CAAAA,CAAc,SAAA,CAI9B+C,IACC,CAACM,CAAAA,EAAWrD,CAAAA,CAAc,WAAA,CAAA,EAC3B,EAAEsD,CAAAA,EAAaA,CAAAA,CAAUF,CAAAA,CAAQpD,CAAa,CAAA,CAAA,EAE9CkC,EAAAA,CAASY,CAAAA,CAAUM,CAAAA,CAAQL,CAAAA,CAAW/C,EAAc,SAAS,CAAA,CAG/Dd,CAAAA,CAAkB4D,CAAAA,CAAUM,CAAM,CAAA,CAClCxG,EAAAA,CAAekG,CAAQ,CAAA,CAEvB,IAAMS,CAAAA,CAAevD,CAAAA,CAAc,QAAA,CAE/BuD,CAAAA,EACF3G,GAAe2G,CAAY,EAE/B,CACF,CCzeA,eAAsBC,EAAAA,CAMpB3I,CAAAA,CACc,CAEd,GAAI,CAACA,CAAAA,CACH,OAAO,IAAA,CAIT,IAAI4I,EAAe5I,CAAAA,CAAsB,OAAA,EAAS,GAAA,CAAI/D,CAAY,CAAA,CAE9D2M,CAAAA,CAEFA,CAAAA,CAAcA,CAAAA,CAAY,WAAA,EAAY,CAAE,IAAA,EAAK,CAE7CA,CAAAA,CAAc,EAAA,CAIhB,IAAMC,CAAAA,CAAWD,CAAAA,CAAY,KAAA,CAAM,GAAA,CAAK,CAAC,CAAA,CAAE,CAAC,CAAA,CAExC/L,CAAAA,CAEJ,GAAI,CACF,GAAIgM,CAAAA,CAAS,QAAA,CAAS9M,CAAgB,CAAA,EAAK8M,CAAAA,CAAS,QAAA,CAAS,OAAO,CAAA,CAClEhM,CAAAA,CAAO,MAAMmD,CAAAA,CAAS,IAAA,EAAK,CAAA,KAAA,GAAA,CAE1B6I,CAAAA,CAAS,QAAA,CAAS,qBAAqB,CAAA,EACtCA,EAAS,QAAA,CACP/M,CAAAA,CAA2B,uBAC7B,CAAA,GACF,OAAOkE,CAAAA,CAAS,QAAA,GAAa3D,CAAAA,CAE7BQ,CAAAA,CAAO,MAAMmD,CAAAA,CAAS,QAAA,EAAS,CAAA,KAAA,GAE/B6I,CAAAA,CAAS,SAAS/M,CAAAA,CAA2B,cAAc,CAAA,EAC3D,OAAOkE,CAAAA,CAAS,IAAA,GAAS3D,CAAAA,CAEzBQ,CAAAA,CAAO,MAAMmD,CAAAA,CAAS,IAAA,EAAK,CAAA,KAAA,GAE3BnD,CAAAA,CAAO,MAAMmD,EAAS,IAAA,EAAK,CAEvB,OAAOnD,CAAAA,GAAST,CAAAA,CAAQ,CAC1B,IAAM0M,CAAAA,CAAUjM,CAAAA,CAAK,IAAA,EAAK,CAC1B,GACGiM,CAAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,EAAKA,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,EAC/CA,CAAAA,CAAQ,UAAA,CAAW,GAAG,CAAA,EAAKA,CAAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,CAEhD,GAAI,CACFjM,CAAAA,CAAO,IAAA,CAAK,KAAA,CAAMiM,CAAO,EAC3B,CAAA,KAAQ,CAER,CAEJ,CAGJ,CAAA,KAAiB,CAEfjM,CAAAA,CAAO,KACT,CAEA,OAAOA,CACT,CAUO,IAAMkM,EAAAA,CAAkB,CAM7B/I,CAAAA,CAMA6G,CAAAA,CACA/E,CAAAA,CAKW,IAAA,GAC2D,CACtE,IAAMkH,CAAAA,CAAkBnC,CAAAA,CAAO,eAAA,CACzBoB,EAAWpB,CAAAA,CAAO,QAAA,CAClBoC,CAAAA,CAAYvB,EAAAA,CAAO,IAAA,CAAK,IAAA,CAAMO,CAAkB,CAAA,CAQtD,GAAI,CAACjI,CAAAA,CACH,OAAO,CACL,EAAA,CAAI,MAEJ,KAAA,CAAA8B,CAAAA,CACA,IAAA,CAAMkH,CAAAA,EAAmB,IAAA,CACzB,OAAA,CAAS,IAAA,CACT,MAAA,CAAAnC,CAAAA,CACA,MAAA,CAAQoC,CAAAA,CACR,UAAA,CAAY,KAAA,CACZ,SAAA,CAAW,MACX,OAAA,CAAS,IACX,CAAA,CAQF,IAAMC,CAAAA,CACJ,OAAO,QAAA,GAAa7M,CAAAA,EAAY2D,CAAAA,YAAoB,QAAA,CAElDnD,CAAAA,CAAOmD,CAAAA,CAAS,IAAA,CAIlBgJ,CAAAA,GAAoB,SAElBnM,CAAAA,EAAS,IAAA,EACR,OAAOA,CAAAA,GAASV,CAAAA,EAAU,MAAA,CAAO,IAAA,CAAKU,CAAI,CAAA,CAAE,MAAA,GAAW,CAAA,CAAA,GAE1DmD,CAAAA,CAAS,IAAA,CAAOnD,CAAAA,CAAOmM,GAGrBnC,CAAAA,CAAO,eAAA,GACT7G,CAAAA,CAAS,IAAA,CAAOnD,CAAAA,CAAOqC,EAAAA,CAAYrC,CAAI,CAAA,CAAA,CAGrCgK,CAAAA,CAAO,MAAA,GACT7G,CAAAA,CAAS,IAAA,CAAOnD,CAAAA,CAAOgK,CAAAA,CAAO,OAAOhK,CAAI,CAAA,CAAA,CAG3C,IAAMuC,CAAAA,CAAUD,EAAAA,CAAea,CAAAA,CAAS,OAAO,CAAA,CAG/C,OAAIkJ,CAAAA,CACK,CACL,IAAA,CAAMlJ,CAAAA,CAAS,IAAA,CACf,SAAUA,CAAAA,CAAS,QAAA,CACnB,EAAA,CAAIA,CAAAA,CAAS,EAAA,CACb,UAAA,CAAYA,CAAAA,CAAS,UAAA,CACrB,IAAA,CAAMA,CAAAA,CAAS,IAAA,CACf,GAAA,CAAKA,CAAAA,CAAS,GAAA,CACd,OAAQA,CAAAA,CAAS,MAAA,CACjB,UAAA,CAAYA,CAAAA,CAAS,UAAA,CAGrB,IAAA,CAAM,IAAMA,CAAAA,CAAS,IAAA,EAAK,CAC1B,IAAA,CAAM,IAAMA,CAAAA,CAAS,IAAA,GACrB,IAAA,CAAM,IAAMA,CAAAA,CAAS,IAAA,EAAK,CAC1B,KAAA,CAAO,IAAMA,CAAAA,CAAS,KAAA,EAAM,CAC5B,WAAA,CAAa,IAAMA,CAAAA,CAAS,WAAA,GAC5B,QAAA,CAAU,IAAMA,CAAAA,CAAS,QAAA,EAAS,CAClC,KAAA,CAAO,IAAMA,CAAAA,CAAS,KAAA,EAAM,CAG5B,KAAA,CAAA8B,CAAAA,CACA,IAAA,CAAAjF,CAAAA,CACA,QAAAuC,CAAAA,CACA,MAAA,CAAAyH,CAAAA,CACA,MAAA,CAAQoC,CAAAA,CACR,UAAA,CAAY,KAAA,CACZ,SAAA,CAAWjJ,CAAAA,CAAS,EAAA,EAAM,CAAC8B,CAAAA,CAC3B,OAAA,CAAS,CAAC,CAACA,CACb,CAAA,EAIEhF,CAAAA,CAASkD,CAAQ,CAAA,GACnBA,CAAAA,CAAS,KAAA,CAAQ8B,CAAAA,CACjB9B,CAAAA,CAAS,OAAA,CAAUZ,CAAAA,CACnBY,CAAAA,CAAS,UAAA,CAAa,KAAA,CACtBA,EAAS,MAAA,CAASiJ,CAAAA,CAClBjJ,CAAAA,CAAS,SAAA,CAAYA,CAAAA,CAAS,EAAA,EAAM,CAAC8B,CAAAA,CACrC9B,CAAAA,CAAS,OAAA,CAAU,CAAC,CAAC8B,CAAAA,CAAAA,CAGhB9B,CAAAA,CACT,EC3NA,SAASmJ,EAAAA,CAAkBC,CAAAA,CAAmC,CAC5D,IAAMpK,CAAAA,CAAK,IAAA,CAAK,KAAA,CAAMoK,CAAU,CAAA,CAAIxK,CAAAA,EAAQ,CAE5C,OAAK,KAAA,CAAMI,CAAE,CAAA,CAGN,IAAA,CAFE,IAAA,CAAK,GAAA,CAAI,CAAA,CAAG,IAAA,CAAK,KAAA,CAAMA,CAAE,CAAC,CAGrC,CAaO,SAASqK,EAAAA,CACdC,CAAAA,CACe,CACf,GAAI,CAACA,CAAAA,CACH,OAAO,IAAA,CAGT,IAAMlK,CAAAA,CAAUkK,CAAAA,CAAiB,OAAA,EAAW,EAAC,CACvCC,CAAAA,CAAanK,CAAAA,CAAQ,aAAa,EAExC,GAAImK,CAAAA,CAAY,CAEd,IAAMxI,CAAAA,CAAU,MAAA,CAAOwI,CAAU,CAAA,CAEjC,GAAI,CAAC,KAAA,CAAMxI,CAAO,CAAA,EAAKA,CAAAA,EAAW,EAChC,OAAOA,CAAAA,CAAU,GAAA,CAGnB,IAAM/B,CAAAA,CAAKmK,EAAAA,CAAkBI,CAAU,CAAA,CAEvC,GAAIvK,CAAAA,GAAO,IAAA,CACT,OAAOA,CAEX,CAGA,IAAMwK,CAAAA,CAAkB,iBAAA,CAIlBC,CAAAA,CACJrK,CAAAA,CAAQoK,CAAAA,CAAkB,QAAQ,CAAA,EAClCpK,CAAAA,CAAQ,IAAA,CAAOoK,CAAAA,CAAkB,QAAQ,CAAA,CAE3C,GAAIC,CAAAA,CAAqB,CACvB,IAAM1I,CAAAA,CAAU,MAAA,CAAO0I,CAAmB,CAAA,CAE1C,GAAI,CAAC,KAAA,CAAM1I,CAAO,CAAA,CAChB,OAAOA,CAAAA,CAAU,GAErB,CAIA,IAAM2I,CAAAA,CACJtK,CAAAA,CAAQoK,CAAAA,CAAkB,KAAK,CAAA,EAAKpK,CAAAA,CAAQ,IAAA,CAAOoK,CAAAA,CAAkB,KAAK,CAAA,CAE5E,OAAIE,CAAAA,CACKP,EAAAA,CAAkBO,CAAgB,EAGpC,IACT,CAkBA,eAAsBC,EAAAA,CAMpBC,CAAAA,CAMA/C,CAAAA,CAC4E,CAC5E,GAAM,CACJ,OAAA,CAAAgD,CAAAA,CAAU,CAAA,CACV,KAAA,CAAAC,CAAAA,CAAQ,EACR,OAAA,CAAAC,CAAAA,CAAU,CAAA,CACV,QAAA,CAAAC,CAAAA,CACA,OAAA,CAAAC,CAAAA,CAAU,EAAC,CACX,WAAA,CAAAC,CACF,CAAA,CAAIrD,CAAAA,CAEAsD,CAAAA,CAAU,EACVC,CAAAA,CAAWN,CAAAA,CACTO,CAAAA,CAAaR,CAAAA,CAAU,CAAA,CAAIA,CAAAA,CAAU,CAAA,CACvCtB,CAAAA,CAEJ,KAAO4B,CAAAA,EAAWE,CAAAA,EAAY,CAG5B,GAAIF,CAAAA,CAAU,GAAK5B,CAAAA,CAAS,CAC1B,IAAM+B,CAAAA,CAAM/B,CAAAA,CAAO,MAAA,CACbgC,CAAAA,CAAUD,CAAAA,CAAI,OAAA,CAEhBC,CAAAA,GACF,MAAM9K,CAAAA,CAAkB8K,CAAAA,CAAShC,CAAAA,CAAQ4B,CAAO,CAAA,CAI5CG,CAAAA,CAAI,UAAA,GACNA,CAAAA,CAAI,QAAA,CAAWA,CAAAA,CAAI,QAAA,CACnBA,CAAAA,CAAI,QAAA,CAAW1D,CAAAA,CAAiB0D,CAAAA,CAAK,KAAK,CAAA,CAAA,EAGhD,CAKA/B,EAAS,MAAMqB,CAAAA,CAAUO,CAAAA,CAAU,CAAA,CAAGA,CAAO,CAAA,CAC7C,IAAMrI,CAAAA,CAAQyG,CAAAA,CAAO,KAAA,CAGrB,GAAI,CAACzG,CAAAA,CAAO,CACV,GAAIoI,CAAAA,EAAeC,CAAAA,CAAUE,CAAAA,EACD,MAAMH,CAAAA,CAAY3B,CAAAA,CAAQ4B,CAAO,CAAA,CAEpC,CACrB,MAAMpL,CAAAA,CAAgBqL,CAAQ,CAAA,CAC9BA,CAAAA,EAAYL,GAAW,CAAA,CACvBK,CAAAA,CAAW,IAAA,CAAK,GAAA,CAAIA,CAAAA,CAAUJ,CAAAA,EAAYI,CAAQ,CAAA,CAClDD,CAAAA,EAAAA,CACA,QACF,CAGF,KACF,CAWA,GAR2B,MAAMK,EAAAA,CAC/BjC,CAAAA,CACA4B,CAAAA,CACAE,CAAAA,CACAH,CAAAA,CACAD,CACF,CAAA,CAGE,MAKF,GAAInI,CAAAA,CAAM,MAAA,GAAW,GAAA,EAAOA,CAAAA,CAAM,MAAA,GAAW,IAAK,CAEhD,IAAM2I,CAAAA,CAAepB,EAAAA,CAAgBd,CAAM,CAAA,CAGvCkC,CAAAA,GAAiB,IAAA,GACnBL,CAAAA,CAAWK,CAAAA,EAEf,CAEA,MAAM1L,CAAAA,CAAgBqL,CAAQ,EAC9BA,CAAAA,EAAYL,CAAAA,EAAW,CAAA,CACvBK,CAAAA,CAAW,IAAA,CAAK,GAAA,CAAIA,CAAAA,CAAUJ,CAAAA,EAAYI,CAAQ,CAAA,CAClDD,CAAAA,GACF,CAEA,OAAO5B,CACT,CAqBA,eAAsBiC,EAAAA,CAMpBjC,CAAAA,CACA4B,CAAAA,CACAE,CAAAA,CACAH,CAAAA,CAMAD,CAAAA,CAAoB,EAAC,CACH,CAIlB,GAAIE,CAAAA,GAAYE,CAAAA,CACd,OAAO,MAGT,IAAIK,CAAAA,CAAiC,IAAA,CAGrC,OAAIR,CAAAA,GAEFQ,CAAAA,CADe,MAAMR,CAAAA,CAAY3B,CAAAA,CAAQ4B,CAAO,CAAA,CAI5CO,CAAAA,GAAmB,IAAA,CAAA,CACd,CAACA,EAIL,CAAA,CAAET,CAAAA,EAAW,EAAC,EAAG,QAAA,CAAS1B,CAAAA,CAAO,KAAA,EAAO,MAAA,EAAU,CAAC,CAC5D,CCjPA,eAAsBoC,EAAAA,CAMpBf,CAAAA,CAMAgB,EACAC,CAAAA,CACAC,CAAAA,CAAc,CAAA,CACdC,CAAAA,CAAe,CAAA,CAC6D,CAC5E,GAAI,CAACH,CAAAA,CACH,OAAOhB,CAAAA,EAAU,CAGnB,IAAIoB,CAAAA,CAAiB,EACjBzC,CAAAA,CAEJ,KAAA,CAAOuC,CAAAA,GAAgB,CAAA,EAAKE,CAAAA,CAAiBF,CAAAA,IACvCC,CAAAA,CAAe,CAAA,EACjB,MAAMhM,CAAAA,CAAgBgM,CAAY,CAAA,CAGpCxC,CAAAA,CAAS,MAAMqB,GAAU,CAEzBoB,CAAAA,EAAAA,CAGG,EAAAF,CAAAA,CAAc,CAAA,EAAKE,CAAAA,EAAkBF,CAAAA,EACtC,CAACF,CAAAA,EACAC,CAAAA,EAAqBA,CAAAA,CAAkBtC,CAAAA,CAAQyC,CAAc,CAAA,CAAA,CAAA,EAKhE,MAAMjM,CAAAA,CAAgB6L,CAAe,CAAA,CAGvC,OAAOrC,CACT,CC7CA,eAAsB0C,EAAAA,CAMpBrI,CAAAA,CACAgH,CAAAA,CAKAzE,CAAAA,CAM4E,CAC5E,IAAMoD,CAAAA,CAAS,MAAMqB,CAAAA,CAAUhH,CAAmB,CAAA,CAC5Cd,CAAAA,CAAQyG,CAAAA,CAAO,KAAA,CAErB,GAAI,CAACzG,CAAAA,CAEH,OAAAwG,EAAAA,CAAoBC,CAAAA,CAAQpD,CAAa,CAAA,CAElCoD,EAKLpD,CAAAA,CAAc,OAAA,EAChB,MAAM1F,CAAAA,CAAkB0F,CAAAA,CAAc,OAAA,CAASrD,CAAK,CAAA,CAKtD,IAAMoJ,CAAAA,CAAcpJ,CAAAA,CAAM,WAAA,CAY1B,GAVI,CAACoJ,GAAe/F,CAAAA,CAAc,MAAA,EAChCgG,EAAAA,CAAOhG,CAAAA,CAAe,aAAA,CAAerD,CAAsB,CAAA,CAI7DwG,EAAAA,CAAoBC,CAAAA,CAAQpD,CAAAA,CAAe,IAAI,CAAA,CAGrB,CAAC+F,CAAAA,EAAe/F,EAAc,eAAA,CAEjC,CACrB,IAAMiG,CAAAA,CAAWjG,CAAAA,CAAc,QAAA,CAE/B,GAAIiG,CAAAA,GAAa1O,EAAAA,CACf,OAAO,OAAA,CAAQ,MAAA,CAAOoF,CAAK,CAAA,CAIzBsJ,IAAa,QAAA,EACf,MAAM,IAAI,OAAA,CAAQ,IAAM,IAAI,EAEhC,CAEA,OAAO7C,CACT,CAEO,SAAS8C,EAAAA,CAOdvJ,CAAAA,CACA9B,EAMAmF,CAAAA,CAMM,CACNrD,CAAAA,CAAM,MAAA,CAASA,CAAAA,CAAM,MAAA,EAAU9B,CAAAA,EAAU,MAAA,EAAU,CAAA,CACnD8B,CAAAA,CAAM,UAAA,CAAaA,CAAAA,CAAM,UAAA,EAAc9B,CAAAA,EAAU,YAAc,EAAA,CAC/D8B,CAAAA,CAAM,MAAA,CAASA,CAAAA,CAAM,OAAA,CAAUqD,CAAAA,CAC/BrD,CAAAA,CAAM,QAAA,CAAW9B,CAAAA,CACjB8B,CAAAA,CAAM,WAAA,CAAcA,CAAAA,CAAM,IAAA,GAASxF,EACrC,CAQA,SAAS6O,EAAAA,CACPpG,CAAAA,CAAAA,GACGpF,CAAAA,CACG,CACN,IAAMwL,CAAAA,CAASpG,CAAAA,CAAU,MAAA,CAErBoG,CAAAA,EAAUA,CAAAA,CAAO,IAAA,EACnBA,CAAAA,CAAO,IAAA,CAAK,GAAGxL,CAAI,EAEvB,CC/FA,IAAM2L,EAAAA,CAAmB,CACvB,UAAA,CAAY,IACd,CAAA,CAqBA,eAAsBC,EAAAA,CAMpB1N,CAAAA,CACAkH,CAAAA,CAKW,IAAA,CACiE,CAC5E,IAAMyG,CAAAA,CAAgB1G,EAAAA,CAKpBjH,CAAAA,CAAKkH,CAAS,CAAA,CAEV,CACJ,OAAA,CAAA3D,CAAAA,CACA,WAAA,CAAAqK,CAAAA,CACA,QAAA,CAAAxD,CAAAA,CACA,UAAA,CAAA5G,EACA,SAAA,CAAA6G,CAAAA,CACA,SAAA,CAAAvE,CAAAA,CACA,cAAA,CAAAE,CAAAA,CACA,kBAAA,CAAAC,CAAAA,CACA,eAAA,CAAA8G,CAAAA,CAAkB,CACpB,CAAA,CAAIY,CAAAA,CACEE,CAAAA,CAAiBxD,IAAc,MAAA,EAAavE,CAAAA,GAAc,MAAA,CAE1DgI,CAAAA,CAAgB,CAAC,EACrB1D,CAAAA,EACA7G,CAAAA,EACAC,CAAAA,EACAqK,CAAAA,EACAD,CAAAA,EACA5H,CAAAA,EACAC,CAAAA,CAAAA,CAGE8H,CAAAA,CAA2B,KAQ/B,GALID,CAAAA,GACFC,CAAAA,CAAYhF,CAAAA,CAAiB4E,CAAa,CAAA,CAAA,CAIxCI,CAAAA,EAAaF,CAAAA,CAAgB,CAC/B,IAAMG,CAAAA,CAAS7D,EAAAA,CAKb4D,CAAAA,CAAW1D,CAAAA,CAAWsD,CAAa,CAAA,CAErC,GAAIK,CAAAA,CACF,OAAOA,CAEX,CAGA,GAAID,CAAAA,EAAavK,CAAAA,CAAY,CAC3B,IAAMyK,CAAAA,CAAW5J,EAAAA,CAEf0J,CAAAA,CAAWvK,CAAU,CAAA,CAEvB,GAAIyK,CAAAA,CACF,OAAOA,CAEX,CAEA,IAAMC,CAAAA,CAAcP,CAAAA,CAAc,KAAA,EAAS,EAAC,CACtC,CAAE,OAAA,CAAA3B,GAAU,CAAA,CAAG,YAAA,CAAAmC,EAAa,CAAA,CAAID,CAAAA,CAGhCE,EAAAA,CAAgB,MAAOrJ,CAAAA,CAAsB,KAAA,CAAOuH,EAAAA,CAAU,CAAA,GAAM,CAInEA,EAAAA,GACCyB,CAAAA,EAAa,CAAChJ,CAAAA,GACZe,CAAAA,CACoBqE,EAAAA,CACpB4D,CAAAA,CACA1D,CAAAA,CACAsD,CACF,CAAA,GAKEnE,EAAAA,CAASuE,CAAAA,CAAWN,EAAAA,CAAkBpD,CAAAA,CAAWvE,CAAS,CAAA,CAC1DU,CAAAA,CAAkBuH,EAAWN,EAAgB,CAAA,CAAA,CAG/CjH,CAAAA,CAAkBuH,CAAAA,CAAWN,EAAgB,CAAA,CAAA,CAKjDE,CAAAA,CAAc,QAAA,CAAWI,CAAAA,CAAAA,CAG3B,IAAM/N,CAAAA,CAAM2N,CAAAA,CAAc,GAAA,CAGpB5J,EAAAA,CAAaT,GACjByK,CAAAA,CACA/N,CAAAA,CACAuD,CAAAA,CACAC,CAAAA,EAAc,CAAA,CACd,CAAC,CAACoK,CAAAA,CAEF,CAAC,EAAErK,CAAAA,GAAY,CAAC+I,EAAAA,EAAW6B,EAAAA,CAAAA,CAC7B,EAIM7G,CAAAA,CAAgBqG,CAAAA,CAEtBrG,CAAAA,CAAc,MAAA,CAASvD,EAAAA,CAAW,MAAA,CAElC,IAAI2G,CAAAA,CAMAvI,CAAAA,CAKO,IAAA,CAEX,GAAI,CACEwL,CAAAA,CAAc,SAAA,EAChB,MAAM/L,CAAAA,CAAkB+L,CAAAA,CAAc,SAAA,CAAWrG,CAAa,CAAA,CAIhE,IAAMjB,CAAAA,CAAKsH,CAAAA,CAAc,OAAA,CAkBzB,GAhBAxL,CAAAA,CAAYkE,CAAAA,CACR,MAAMA,CAAAA,CACJrG,EACAsH,CACF,CAAA,CACA,MAAM,KAAA,CACJtH,CAAAA,CACAsH,CACF,CAAA,CAQArI,CAAAA,CAASkD,CAAQ,CAAA,GAEf,OAAO,QAAA,GAAa3D,CAAAA,EAAY2D,CAAAA,YAAoB,SACtDA,CAAAA,CAAS,IAAA,CAAO,MAAM2I,EAAAA,CAAkB3I,CAAQ,CAAA,CACvCkE,CAAAA,GAEH,MAAA,GAAUlE,CAAAA,EAAY,MAAA,GAAUA,CAAAA,GAEpCA,CAAAA,CAAW,CAAE,IAAA,CAAMA,CAAS,CAAA,CAAA,CAAA,CAYhCA,CAAAA,CAAS,MAAA,CAASmF,CAAAA,CAIdnF,CAAAA,CAAS,EAAA,GAAO,KAAA,CAAA,EAAa,CAACA,CAAAA,CAAS,EAAA,CAAA,CACzC,MAAM,IAAIC,EAAAA,CACR,CAAA,EAAGkF,EAAc,MAAM,CAAA,IAAA,EAAOtH,CAAG,CAAA,iBAAA,EAAoBmC,CAAAA,CAAS,MAAA,EAAU,IAAI,CAAA,CAAA,CAC5EmF,CAAAA,CACAnF,CACF,CAAA,CAIJuI,CAAAA,CAASQ,EAAAA,CAKP/I,CAAAA,CAAUmF,CAAa,CAAA,CAEzB,IAAM+G,CAAAA,CAAaV,CAAAA,CAAc,UAAA,CAE7BU,CAAAA,EACF,MAAMzM,CAAAA,CAAkByM,CAAAA,CAAY3D,CAAM,EAE9C,CAAA,MAAS4D,CAAAA,CAAQ,CACf,IAAMrK,CAAAA,CAAQqK,CAAAA,CAQdd,EAAAA,CACEvJ,CAAAA,CACA9B,CAAAA,CACAmF,CACF,CAAA,CAGAoD,CAAAA,CAASQ,EAAAA,CAKP/I,CAAAA,CAAUmF,CAAAA,CAAerD,CAAK,EAClC,CAEA,OAAOyG,CACT,CAAA,CAGM6D,EAAAA,CACJvC,EAAAA,CAAU,CAAA,CAAI,IAAMF,EAAAA,CAAUsC,EAAAA,CAAeF,CAAW,CAAA,CAAIE,EAAAA,CAExDI,CAAAA,CAA2B,CAACzJ,CAAAA,CAAsB,QACtDqI,EAAAA,CACErI,CAAAA,CACAwJ,EAAAA,CACAZ,CACF,CAAA,CAGIc,EAAAA,CAAmB1B,CAAAA,CACrBD,EAAAA,CACE0B,CAAAA,CACAzB,CAAAA,CACAY,CAAAA,CAAc,iBAAA,CACdA,CAAAA,CAAc,kBAAA,CACdA,EAAc,YAChB,CAAA,CACAa,CAAAA,EAAyB,CAG7B,OAAIT,CAAAA,GACEvK,CAAAA,EACFW,EAAAA,CAAmB4J,CAAAA,CAAWU,EAAgB,CAAA,CAGhD9I,EAAAA,CACEoI,CAAAA,CACAS,CAAAA,CACA,OACA1I,CAAAA,CACA0I,CAAAA,CACA,CAAC,CAACxI,CAAAA,CACF,CAAC,CAACC,CACJ,CAAA,CAAA,CAGKwI,EACT,CC3RA,SAASC,EAAAA,CAGP1F,CAAAA,CAAyC,CACzC,IAAM2F,CAAAA,CAAY3F,CAAAA,CAAO,SAAA,CAQzB,SAAS4F,CAAAA,CAAqBC,CAAAA,CAAqC,CACjE,OAAA,OAAA,CAAQ,KAAA,CAAM,CAAA,IAAA,EAAOA,CAAY,CAAA,gBAAA,CAAkB,CAAA,CAE5C,QAAQ,OAAA,CAAQ,IAAI,CAC7B,CAEA,IAAMC,CAAAA,CAAsD,CAC1D,MAAA,CAAA9F,CAAAA,CACA,SAAA,CAAA2F,CAAAA,CASA,MAAM,OAAA,CAAQE,CAAAA,CAAcvH,EAAgB,EAAC,CAAG,CAE9C,IAAMyH,CAAAA,CAAiBJ,CAAAA,CAAUE,CAAY,CAAA,CACvCG,CAAAA,CACJD,CAAAA,EACC,CAAE,GAAA,CAAK,MAAA,CAAOF,CAAY,CAAE,CAAA,CACzB7O,CAAAA,CAAMgP,CAAAA,CAAgB,GAAA,CAG5B,GAAIhP,CAAAA,CAAI,UAAA,CAAW,IAAI,CAAA,CACrB,MAAM,IAAI,KAAA,CAAM,yCAAyC,CAAA,CAI3D,IAAMiI,CAAAA,CAAenH,EAAAA,CAAcd,CAAG,CAAA,CAElC+O,CAAAA,EAAgB,GAAA,GAAQ/O,CAAAA,CACtBqH,CAAAA,CAAa2H,CAAAA,CAAiB1H,CAAa,CAAA,CAC3CA,CAAAA,CACFD,CAAAA,CAAaA,CAAAA,CAAa2B,EAAQgG,CAAe,CAAA,CAAG1H,CAAa,CAAA,CAIrE,OAAOoG,EAAAA,CAAO1N,CAAAA,CAAKiI,CAAY,CACjC,CACF,CAAA,CAOA,OAAO,IAAI,KAAA,CACT6G,EACA,CACE,GAAA,CAAIG,CAAAA,CAASC,CAAAA,CAAc,CACzB,OAAIA,CAAAA,IAAQJ,CAAAA,CACHA,CAAAA,CAAWI,CAA0C,CAAA,CAI1DP,CAAAA,CAAUO,CAAI,CAAA,CACTJ,EAAW,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAMI,CAAI,CAAA,CAGpCN,CAAAA,CAAqB,IAAA,CAAK,IAAA,CAAMM,CAAI,CAC7C,CACF,CACF,CACF","file":"index.js","sourcesContent":["export const APPLICATION_CONTENT_TYPE = 'application/';\n\nexport const APPLICATION_JSON = APPLICATION_CONTENT_TYPE + 'json';\nexport const CHARSET_UTF_8 = 'charset=utf-8';\nexport const CONTENT_TYPE = 'Content-Type';\n\nexport const UNDEFINED = 'undefined';\nexport const OBJECT = 'object';\nexport const STRING = 'string';\nexport const FUNCTION = 'function';\n\nexport const ABORT_ERROR = 'AbortError';\nexport const TIMEOUT_ERROR = 'TimeoutError';\n\nexport const GET = 'GET';\nexport const HEAD = 'HEAD';\n\nexport const REJECT = 'reject';\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { FUNCTION, OBJECT, STRING, UNDEFINED } from './constants';\nimport type {\n DefaultUrlParams,\n HeadersObject,\n QueryParams,\n UrlPathParams,\n} from './types';\n\n// Prevent stack overflow with recursion depth limit\nconst MAX_DEPTH = 10;\n\nexport function isSearchParams(data: unknown): boolean {\n return data instanceof URLSearchParams;\n}\n\n/**\n * Determines if a value is a non-null object.\n *\n * @param {any} value - The value to check.\n * @returns {boolean} - True if the value is a non-null object.\n */\nexport function isObject(value: any): value is Record {\n return value !== null && typeof value === OBJECT;\n}\n\n/**\n * Shallowly serializes an object by converting its key-value pairs into a string representation.\n * This function does not recursively serialize nested objects.\n *\n * @param obj - The object to serialize.\n * @returns A string representation of the object's top-level properties.\n */\nexport function shallowSerialize(obj: Record): string {\n let result = '';\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n result += key + ':' + obj[key];\n }\n }\n\n return result;\n}\n\n/**\n * Removes properties that could lead to prototype pollution from an object.\n *\n * This function creates a shallow copy of the input object with dangerous\n * properties like '__proto__', 'constructor', and 'prototype' removed.\n *\n * @param obj - The object to sanitize\n * @returns A new object without dangerous properties\n */\nexport function sanitizeObject>(obj: T): T {\n const safeObj = { ...obj };\n\n delete safeObj.__proto__;\n delete (safeObj as any).constructor;\n delete safeObj.prototype;\n\n return safeObj;\n}\n\n/**\n * Sorts the keys of an object and returns a new object with sorted keys.\n *\n * This function is optimized for performance by minimizing the number of object operations\n * and using a single pass to create the sorted object.\n *\n * @param {Object} obj - The object to be sorted by keys.\n * @returns {Object} - A new object with keys sorted in ascending order.\n */\nexport function sortObject(obj: Record): object {\n const keys = Object.keys(obj);\n\n keys.sort();\n\n const sortedObj = {} as Record;\n\n for (let i = 0, len = keys.length; i < len; i++) {\n const key = keys[i];\n\n sortedObj[key] = obj[key];\n }\n\n return sortedObj;\n}\n\n/**\n * Appends a query string to a URL, ensuring proper handling of existing query parameters.\n *\n * @param baseUrl - The base URL to which the query string will be appended.\n * @param queryString - The encoded query string to append.\n * @returns The URL with the appended query string, or the original URL if no query string is provided.\n */\nfunction appendQueryStringToUrl(baseUrl: string, queryString: string): string {\n if (!queryString) {\n return baseUrl;\n }\n\n return baseUrl.includes('?')\n ? `${baseUrl}&${queryString}`\n : `${baseUrl}?${queryString}`;\n}\n\n/**\n * Appends query parameters to a given URL.\n *\n * @param {string} url - The base URL to which query parameters will be appended.\n * @param {QueryParams} params - An object containing the query parameters to append.\n * @returns {string} - The URL with the appended query parameters.\n */\nexport function appendQueryParams(url: string, params: QueryParams): string {\n if (!params) {\n return url;\n }\n\n // Check if `params` is an instance of URLSearchParams and bail early if it is\n if (isSearchParams(params)) {\n const encodedQueryString = params.toString();\n\n return appendQueryStringToUrl(url, encodedQueryString);\n }\n\n // This is exact copy of what JQ used to do. It works much better than URLSearchParams\n const s: string[] = [];\n const encode = encodeURIComponent;\n const add = (k: string, v: any) => {\n v = typeof v === FUNCTION ? v() : v;\n v = v === null ? '' : v === undefined ? '' : v;\n s[s.length] = encode(k) + '=' + encode(v);\n };\n\n const buildParams = (prefix: string, obj: any, depth = 0) => {\n // Stop recursion if maximum depth is reached\n if (depth >= MAX_DEPTH) {\n return s;\n }\n\n let i: number, len: number, key: string;\n\n if (prefix) {\n if (Array.isArray(obj)) {\n for (i = 0, len = obj.length; i < len; i++) {\n buildParams(\n prefix + '[' + (typeof obj[i] === OBJECT && obj[i] ? i : '') + ']',\n obj[i],\n depth + 1,\n );\n }\n } else if (isObject(obj)) {\n for (key in obj) {\n buildParams(prefix + '[' + key + ']', obj[key], depth + 1);\n }\n } else {\n add(prefix, obj);\n }\n } else if (Array.isArray(obj)) {\n for (i = 0, len = obj.length; i < len; i++) {\n add(obj[i].name, obj[i].value);\n }\n } else {\n for (key in obj) {\n buildParams(key, obj[key], depth + 1);\n }\n }\n return s;\n };\n\n const queryStringParts = buildParams('', params).join('&');\n\n // Encode special characters as per RFC 3986, https://datatracker.ietf.org/doc/html/rfc3986\n // This is for compatibility with server frameworks that expect the literal notation\n const encodedQueryString = queryStringParts.replace(/%5B%5D/g, '[]'); // Keep '[]' for arrays\n\n return appendQueryStringToUrl(url, encodedQueryString);\n}\n\n/**\n * Replaces dynamic URI parameters in a URL string with values from the provided `urlPathParams` object.\n * Parameters in the URL are denoted by `:`, where `` is a key in `urlPathParams`.\n *\n * @param {string} url - The URL string containing placeholders in the format `:`.\n * @param {Object} urlPathParams - An object containing the parameter values to replace placeholders.\n * @param {string} urlPathParams.paramName - The value to replace the placeholder `:` in the URL.\n * @returns {string} - The URL string with placeholders replaced by corresponding values from `urlPathParams`.\n */\nexport function replaceUrlPathParams(\n url: string,\n urlPathParams: UrlPathParams,\n): string {\n if (!urlPathParams || url.indexOf(':') === -1) {\n return url;\n }\n\n // Use a single RegExp and avoid unnecessary casts and function calls\n // Precompute keys for faster lookup\n const params = urlPathParams as DefaultUrlParams;\n\n // Use a replacer function that avoids extra work\n return url.replace(/:([a-zA-Z0-9_]+)/g, (match, key) => {\n // Use hasOwnProperty for strict key existence check\n if (Object.prototype.hasOwnProperty.call(params, key)) {\n const value = params[key];\n\n // Only replace if value is not undefined or null\n if (value !== undefined && value !== null) {\n return encodeURIComponent(String(value));\n }\n }\n\n return match;\n });\n}\n\n/**\n * Determines whether the provided URL is absolute.\n *\n * An absolute URL contains a scheme (e.g., \"http://\", \"https://\").\n *\n * @param url - The URL string to check.\n * @returns `true` if the URL is absolute, otherwise `false`.\n */\nexport function isAbsoluteUrl(url: string): boolean {\n return url.includes('://');\n}\n\nexport const timeNow = () => Date.now();\n\nexport const noop = () => {};\n\n/**\n * Checks if a value is JSON serializable.\n *\n * JSON serializable values include:\n * - Primitive types: string, number, boolean, null\n * - Arrays\n * - Plain objects (i.e., objects without special methods)\n * - Values with a `toJSON` method\n *\n * @param {any} value - The value to check for JSON serializability.\n * @returns {boolean} - Returns `true` if the value is JSON serializable, otherwise `false`.\n */\nexport function isJSONSerializable(value: any): boolean {\n const t = typeof value;\n\n if (value === undefined || value === null) {\n return false;\n }\n\n if (t === STRING || t === 'number' || t === 'boolean') {\n return true;\n }\n\n if (Array.isArray(value)) {\n return true;\n }\n\n if (\n typeof globalThis !== UNDEFINED &&\n typeof globalThis.Buffer !== UNDEFINED &&\n globalThis.Buffer.isBuffer(value)\n ) {\n return false;\n }\n\n if (value instanceof Date || isSearchParams(value)) {\n return false;\n }\n\n if (isObject(value)) {\n const proto = Object.getPrototypeOf(value);\n\n // Check if the prototype is `Object.prototype` (plain object)\n if (proto === Object.prototype) {\n return true;\n }\n\n // Check if the object has a toJSON method\n if (typeof value.toJSON === FUNCTION) {\n return true;\n }\n }\n\n return false;\n}\n\nexport async function delayInvocation(ms: number): Promise {\n return new Promise((resolve) =>\n setTimeout(() => {\n return resolve(true);\n }, ms),\n );\n}\n\n/**\n * Recursively flattens the data object if it meets specific criteria.\n *\n * The method checks if the provided `data` is an object with exactly one property named `data`.\n * If so, it recursively flattens the `data` property. Otherwise, it returns the `data` as-is.\n *\n * @param {any} data - The data to be flattened. Can be of any type, including objects, arrays, or primitives.\n * @returns {any} - The flattened data if the criteria are met; otherwise, the original `data`.\n */\nexport function flattenData(data: any, depth = 0): any {\n if (depth >= MAX_DEPTH) {\n return data;\n }\n\n if (data && isObject(data) && typeof data.data !== UNDEFINED) {\n return flattenData(data.data, depth + 1);\n }\n\n return data;\n}\n\n/**\n * Processes headers and returns them as a normalized object.\n *\n * Handles both `Headers` instances and plain objects. Normalizes header keys to lowercase\n * as per RFC 2616 section 4.2.\n *\n * @param headers - The headers to process. Can be an instance of `Headers`, a plain object,\n * or `null`. If `null`, an empty object is returned.\n * @returns {HeadersObject} - A normalized headers object with lowercase keys.\n */\nexport function processHeaders(\n headers?: (HeadersObject & HeadersInit) | null | Headers,\n): HeadersObject {\n if (!headers) {\n return {};\n }\n\n const headersObject: HeadersObject = {};\n\n // Handle Headers object with entries() method\n if (headers instanceof Headers) {\n headers.forEach((value, key) => {\n headersObject[key] = value;\n });\n } else if (isObject(headers)) {\n // Handle plain object\n for (const [key, value] of Object.entries(headers)) {\n // Normalize keys to lowercase as per RFC 2616 4.2\n // https://datatracker.ietf.org/doc/html/rfc2616#section-4.2\n headersObject[key.toLowerCase()] = value;\n }\n }\n\n return headersObject;\n}\n\n/**\n * Determines if the current environment is a browser.\n *\n * @returns {boolean} - True if running in a browser environment, false otherwise.\n */\nexport function isBrowser(): boolean {\n // For node and and some mobile frameworks like React Native, `add/removeEventListener` doesn't exist on window!\n return (\n typeof window !== UNDEFINED && typeof window.addEventListener === FUNCTION\n );\n}\n\n/**\n * Detects if the user is on a slow network connection\n * @returns {boolean} True if connection is slow, false otherwise or if detection unavailable\n */\nexport const isSlowConnection = (): boolean => {\n // Only works in browser environments\n if (!isBrowser()) {\n return false;\n }\n\n const conn = navigator && (navigator as any).connection;\n\n return conn && ['slow-2g', '2g', '3g'].includes(conn.effectiveType);\n};\n","import { FUNCTION } from './constants';\nimport type { InterceptorFunction } from './types/interceptor-manager';\nimport { isObject } from './utils';\n\n/**\n * Applies interceptors to the object. Interceptors can be a single function or an array of functions.\n *\n * @template T - Type of the object.\n * @template Args - Type of additional arguments.\n * @template I - Type of interceptors.\n *\n * @param {InterceptorFunction | InterceptorFunction[]} [interceptors] - Interceptor function(s).\n * @param {T} data - The data object to process.\n * @param {...Args} args - Additional arguments to pass to interceptors.\n *\n * @returns {Promise} - Nothing as the function is non-idempotent.\n */\nexport async function applyInterceptors<\n T extends object,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Args extends any[] = any[],\n I = InterceptorFunction | InterceptorFunction[],\n>(interceptors: I | undefined, data: T, ...args: Args): Promise {\n if (!interceptors) {\n return;\n }\n\n if (typeof interceptors === FUNCTION) {\n const value = await (interceptors as InterceptorFunction)(\n data,\n ...args,\n );\n\n if (value && isObject(data) && isObject(value)) {\n Object.assign(data, value);\n }\n } else if (Array.isArray(interceptors)) {\n for (const interceptor of interceptors) {\n const value = await interceptor(data, ...args);\n\n if (value && isObject(data) && isObject(value)) {\n Object.assign(data, value);\n }\n }\n }\n}\n","import type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '../types';\n\n/**\n * This is a base error class\n */\nexport class FetchError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n> extends Error {\n status: number;\n statusText: string;\n config: RequestConfig;\n isCancelled: boolean;\n\n constructor(\n message: string,\n public request: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n public response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n ) {\n super(message);\n\n this.name = 'FetchError';\n this.status = response ? response.status : 0;\n this.statusText = response ? response.statusText : '';\n this.config = request;\n this.isCancelled = false;\n }\n}\n","import { FetchError } from './fetch-error';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '../types';\n\nexport class ResponseError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n> extends FetchError {\n constructor(\n message: string,\n request: RequestConfig,\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n ) {\n super(message, request, response);\n\n this.name = 'ResponseError';\n }\n}\n","/**\n * @module timeout-wheel\n * @description\n * Ultra-minimal timing wheel implementation optimized for max performance & many requests.\n * For most of the cases it's 4-100x faster than setTimeout and setInterval alone.\n * Provides efficient scheduling and cancellation of timeouts using a circular array.\n *\n * Position 0 → 1 → 2 → ... → 599 → 0 → 1 → 2 ...\n * Time: 0s 1s 2s 599s 600s 601s 602s\n *\n * The timing wheel consists of 600 slots (one per second for 10 min).\n * Each slot contains a list of timeout items, each associated with a unique key and callback.\n * Timeouts are scheduled by placing them in the appropriate slot based on the delay in seconds.\n * The wheel advances every second, executing and removing callbacks as their timeouts expire.\n * Defaults to setTimeout if the delay exceeds 10 minutes or is not divisible by 1000.\n *\n * @remarks\n * - Designed for minimal footprint and simplicity.\n * - Only supports second-level granularity (minimum timeout: 1 second).\n * - Automatically stops the internal timer when no timeouts remain.\n */\n\nimport { noop } from './utils';\n\ntype TimeoutCallback = () => unknown | Promise;\ntype TimeoutItem = [string, TimeoutCallback]; // [key, callback]\n\nconst WHEEL_SIZE = 600; // 600 slots for 10 min (1 slot per second)\nconst SECOND = 1000; // 1 second in milliseconds\nconst MAX_WHEEL_MS = WHEEL_SIZE * SECOND;\nconst wheel: TimeoutItem[][] = Array(WHEEL_SIZE)\n .fill(0)\n .map(() => []);\n\nconst keyMap = new Map();\nlet position = 0;\nlet timer: NodeJS.Timeout | null = null;\n\nconst handleCallback = ([key, callback]: TimeoutItem): void => {\n keyMap.delete(key);\n\n try {\n const result = callback();\n if (result && result instanceof Promise) {\n // Silently ignore async errors to prevent wheel from stopping\n result.catch(noop);\n }\n } catch {\n // Ignore callback errors to prevent wheel from stopping\n }\n};\n\nexport const addTimeout = (\n key: string,\n cb: TimeoutCallback,\n ms: number,\n): void => {\n removeTimeout(key);\n\n // Fallback to setTimeout if wheel size is exceeded or ms is not divisible by SECOND\n if (ms > MAX_WHEEL_MS || ms % SECOND !== 0) {\n keyMap.set(key, [setTimeout(handleCallback.bind(null, [key, cb]), ms)]); // Store timeout ID instead of slot\n\n return;\n }\n\n // No need for Math.ceil here since ms is guaranteed by modulo above\n const seconds = ms / SECOND;\n const slot = (position + seconds) % WHEEL_SIZE;\n\n wheel[slot].push([key, cb]);\n keyMap.set(key, slot);\n\n if (!timer) {\n timer = setInterval(() => {\n position = (position + 1) % WHEEL_SIZE;\n wheel[position].forEach(handleCallback);\n wheel[position] = [];\n\n if (!keyMap.size && timer) {\n clearInterval(timer);\n timer = null;\n }\n }, SECOND);\n }\n};\n\nexport const removeTimeout = (key: string): void => {\n const slotOrTimeout = keyMap.get(key);\n\n if (slotOrTimeout !== undefined) {\n // It's a Timeout object from setTimeout\n if (Array.isArray(slotOrTimeout)) {\n clearTimeout(slotOrTimeout[0]);\n } else {\n wheel[slotOrTimeout].splice(\n wheel[slotOrTimeout].findIndex(([k]) => k === key),\n 1,\n );\n }\n\n keyMap.delete(key);\n\n if (!keyMap.size && timer) {\n clearInterval(timer);\n timer = null;\n }\n }\n};\n\nexport const clearAllTimeouts = () => {\n // Clear native setTimeout timeouts first!\n keyMap.forEach((value) => {\n if (Array.isArray(value)) {\n clearTimeout(value[0]);\n }\n });\n\n if (timer) {\n clearInterval(timer);\n timer = null;\n }\n\n keyMap.clear();\n wheel.forEach((slot) => (slot.length = 0));\n position = 0;\n};\n","/**\n * @module inflight-manager\n *\n * Manages in-flight asynchronous requests using unique keys to enable deduplication and cancellation.\n *\n * Provides utilities for:\n * - Deduplication of requests within a configurable time window (`dedupeTime`)\n * - Timeout management and automatic request abortion\n * - AbortController lifecycle and cancellation logic\n * - Concurrency control and request state tracking\n * - In-flight promise deduplication to prevent duplicate network calls\n *\n * @remarks\n * - Requests with the same key within the deduplication interval share the same AbortController and in-flight promise.\n * - Supports cancellation of previous requests when a new one with the same key is issued, if `isCancellable` is enabled.\n * - Timeout logic ensures requests are aborted after a specified duration, if enabled.\n * - Internal queue state is managed via a Map, keyed by request identifier.\n * - Polled requests are also marked as \"in-flight\" to prevent duplicate requests.\n */\n\nimport { ABORT_ERROR, TIMEOUT_ERROR } from './constants';\nimport { addTimeout, removeTimeout } from './timeout-wheel';\nimport { timeNow } from './utils';\n\nexport type InFlightItem = [\n AbortController, // AbortController for the request\n boolean, // Whether timeout is enabled for the request\n number, // Timestamp when the request was marked in-flight\n boolean, // isCancellable - whether the request can be cancelled\n Promise | null, // Optional in-flight promise for deduplication\n];\n\nconst inFlight: Map = new Map();\n\n/**\n * Adds a request to the queue if it's not already being processed within the dedupeTime interval.\n *\n * @param {string | null} key - Unique key for the request (e.g. cache key).\n * @param {string} url - The request URL (for error messages/timeouts).\n * @param {number} timeout - Timeout in milliseconds for the request.\n * @param {number} dedupeTime - Deduplication time in milliseconds.\n * @param {boolean} isCancellable - If true, then the previous request with same configuration should be aborted.\n * @param {boolean} isTimeoutEnabled - Whether timeout is enabled.\n * @returns {AbortController} - A promise that resolves to an AbortController.\n */\nexport function markInFlight(\n key: string | null,\n url: string,\n timeout: number | undefined,\n dedupeTime: number,\n isCancellable: boolean,\n isTimeoutEnabled: boolean,\n): AbortController {\n if (!key) {\n return new AbortController();\n }\n\n const item = inFlight.get(key);\n let prevPromise: Promise | null = null;\n\n // Previous request is in-flight, check if we can reuse it\n if (item) {\n const prevController = item[0];\n const prevIsCancellable = item[3];\n\n // If the request is already in the queue and within the dedupeTime, reuse the existing controller\n if (\n !prevIsCancellable &&\n timeNow() - item[2] < dedupeTime &&\n !prevController.signal.aborted\n ) {\n return prevController;\n }\n\n // If the request is too old, remove it and proceed to add a new one\n // Abort previous request, if applicable, and continue as usual\n if (prevIsCancellable) {\n prevController.abort(\n new DOMException('Aborted due to new request', ABORT_ERROR),\n );\n }\n\n removeTimeout(key);\n prevPromise = item[4];\n }\n\n const controller = new AbortController();\n\n inFlight.set(key, [\n controller,\n isTimeoutEnabled,\n timeNow(),\n isCancellable,\n prevPromise,\n ]);\n\n if (isTimeoutEnabled) {\n addTimeout(\n key,\n () => {\n abortRequest(\n key,\n new DOMException(url + ' aborted due to timeout', TIMEOUT_ERROR),\n );\n },\n timeout as number,\n );\n }\n\n return controller;\n}\n\n/**\n * Removes a request from the queue and clears its timeout.\n *\n * @param key - Unique key for the request.\n * @param {boolean} error - Optional error to abort the request with. If null, the request is simply removed but no abort sent.\n * @returns {Promise} - A promise that resolves when the request is aborted and removed.\n */\nexport async function abortRequest(\n key: string | null,\n error: DOMException | null | string = null,\n): Promise {\n // If the key is not in the queue, there's nothing to remove\n if (key) {\n const item = inFlight.get(key);\n\n if (item) {\n // If the request is not yet aborted, abort it with the provided error\n if (error) {\n const controller = item[0];\n controller.abort(error);\n }\n\n removeInFlight(key);\n }\n }\n}\n\n/**\n * Removes a request from the in-flight queue without aborting or clearing timeout.\n *\n * @param key - Unique key for the request.\n */\nexport function removeInFlight(key: string | null): void {\n removeTimeout(key!);\n inFlight.delete(key!);\n}\n\n/**\n * Gets the AbortController for a request key.\n *\n * @param key - Unique key for the request.\n * @returns {AbortController | undefined} - The AbortController or undefined.\n */\nexport async function getController(\n key: string,\n): Promise {\n const item = inFlight.get(key);\n\n return item?.[0];\n}\n\n/**\n * Adds helpers for in-flight promise deduplication.\n *\n * @param key - Unique key for the request.\n * @param promise - The promise to store.\n */\nexport function setInFlightPromise(\n key: string,\n promise: Promise,\n): void {\n const item = inFlight.get(key);\n if (item) {\n // store the promise at index 4\n item[4] = promise;\n\n inFlight.set(key, item);\n }\n}\n\n/**\n * Retrieves the in-flight promise for a request key if it exists and is within the dedupeTime interval.\n *\n * @param key - Unique key for the request.\n * @param dedupeTime - Deduplication time in milliseconds.\n * @returns {Promise | null} - The in-flight promise or null.\n */\nexport function getInFlightPromise(\n key: string | null,\n dedupeTime: number,\n): Promise | null {\n if (!key) {\n return null;\n }\n\n const prevReq = inFlight.get(key);\n\n if (\n prevReq &&\n // If the request is in-flight and has a promise\n prevReq[4] &&\n // If the request is cancellable, we will not reuse it\n !prevReq[3] &&\n // If the request is within the dedupeTime\n timeNow() - prevReq[2] < dedupeTime &&\n // If one request is cancelled, ALL deduped requests get cancelled\n !prevReq[0].signal.aborted\n ) {\n return prevReq[4] as Promise;\n }\n\n return null;\n}\n","const PRIME_MULTIPLIER = 31;\n\n/**\n * Computes a hash value for a given string using the variant of djb2 hash function.\n * This hash function is non-cryptographic and designed for speed.\n * @author Daniel J. Bernstein (of djb2)\n *\n * @param str Input string to hash\n * @returns {string} Hash\n */\nexport function hash(str: string): string {\n let hash = 0;\n\n for (let i = 0, len = str.length; i < len; i++) {\n const char = str.charCodeAt(i);\n hash = (hash * PRIME_MULTIPLIER + char) | 0;\n }\n\n return String(hash);\n}\n","/**\n * @module revalidator-manager\n *\n * Provides utilities for managing cache revalidation functions, including:\n * - Registering and unregistering revalidators for specific cache keys.\n * - Triggering revalidation for a given key.\n * - Enabling or disabling automatic revalidation on window focus and if user comes back online for specific keys.\n * - Attaching and removing global focus and online event handlers to trigger revalidation.\n *\n * Revalidators are functions that can be registered to revalidate cache entries when needed.\n * They are typically used to refresh data in the cache when the window gains focus or when specific actions occur.\n * @performance O(1) lookup by key makes it blazing fast to register, unregister, and revalidate cache entries.\n * - Designed for high performance: minimizes unnecessary re-renders and leverages fast cache key generation.\n * - Integrates with a global cache and pub/sub system for efficient state updates across contexts.\n * - Handles automatic revalidation, deduplication, retries, and cache management out of the box.\n * @remarks\n * - Designed to be used in various environments (Deno, Node.js, Bun, Browser, etc.) to ensure cache consistency and freshness.\n */\nimport { addTimeout, removeTimeout } from './timeout-wheel';\nimport { FetchResponse } from './types';\nimport { isBrowser, noop, timeNow } from './utils';\n\nexport type RevalidatorFn = (\n isStaleRevalidation?: boolean,\n) => Promise;\n\ntype EventType = 'focus' | 'online';\n\ntype RevalidatorEntry = [\n RevalidatorFn, // main revalidator\n number, // lastUsed\n number, // ttl\n number?, // staleTime\n RevalidatorFn?, // bgRevalidator\n boolean?, // refetchOnFocus\n boolean?, // refetchOnReconnect\n];\n\nconst DEFAULT_TTL = 3 * 60 * 1000; // Default TTL of 3 minutes\nconst revalidators = new Map();\n\n/**\n * Stores global event handlers for cache revalidation events (e.g., focus, online).\n * This avoids attaching multiple event listeners by maintaining a single handler per event type.\n * Event handlers are registered as needed when revalidators are registered with the corresponding flags.\n * @remarks\n * - Improves performance by reducing the number of event listeners.\n * - Enables efficient O(1) lookup and management of event handlers for revalidation.\n */\nconst eventHandlers = new Map void>();\n\n/**\n * Triggers revalidation for all registered entries based on the given event type.\n * For example, if it's a 'focus' event, it will revalidate entries that have the `refetchOnFocus` flag set.\n * Updates the timestamp and invokes the revalidator function for each applicable entry.\n *\n * @param type - The type of event that caused the revalidation (e.g., 'focus' or 'online').\n * @param isStaleRevalidation - If `true`, uses background revalidator and doesn't mark as in-flight.\n */\nexport function revalidateAll(\n type: EventType,\n isStaleRevalidation: boolean = true,\n) {\n const flagIndex = type === 'focus' ? 5 : 6;\n const now = timeNow();\n\n revalidators.forEach((entry) => {\n if (!entry[flagIndex]) {\n return;\n }\n\n entry[1] = now;\n\n // If it's a stale revalidation, use the background revalidator function\n const revalidator = isStaleRevalidation ? entry[4] : entry[0];\n\n if (revalidator) {\n Promise.resolve(revalidator(isStaleRevalidation)).catch(noop);\n }\n });\n}\n\n/**\n * Revalidates an entry by executing the registered revalidation function.\n *\n * @param key The unique identifier for the cache entry to revalidate. If `null`, no revalidation occurs.\n * @param isStaleRevalidation - If `true`, it does not mark revalidated requests as in-flight.\n * @returns A promise that resolves to the result of the revalidator function, or\n * `null` if no key or revalidator is found, or a `FetchResponse` if applicable.\n */\nexport async function revalidate(\n key: string | null,\n isStaleRevalidation: boolean = false,\n): Promise {\n // If no key is provided, no revalidation occurs\n if (!key) {\n return null;\n }\n\n const entry = revalidators.get(key);\n\n if (entry) {\n // Update only the lastUsed timestamp without resetting the whole array\n entry[1] = timeNow();\n\n const revalidator = isStaleRevalidation ? entry[4] : entry[0];\n\n // If no revalidator function is registered, return null\n if (revalidator) {\n return await revalidator(isStaleRevalidation);\n }\n }\n\n // If no revalidator is registered for the key, return null\n return null;\n}\n\n/**\n * Removes all revalidators associated with the specified event type.\n *\n * @param type - The event type whose revalidators should be removed.\n */\nexport function removeRevalidators(type: EventType) {\n removeEventHandler(type);\n\n const flagIndex = type === 'focus' ? 5 : 6;\n\n // Clear all revalidators with this flag\n revalidators.forEach((entry, key) => {\n if (entry[flagIndex]) {\n removeRevalidator(key);\n }\n });\n}\n\n/**\n * Registers a generic revalidation event handler for the specified event type.\n * Ensures the handler is only added once and only in browser environments.\n *\n * @param event - The type of event to listen for (e.g., 'focus', 'visibilitychange').\n */\nfunction addEventHandler(event: EventType) {\n if (!isBrowser() || eventHandlers.has(event)) {\n return;\n }\n\n const handler = revalidateAll.bind(null, event, true);\n\n eventHandlers.set(event, handler);\n window.addEventListener(event, handler);\n}\n\n/**\n * Removes the generic event handler for the specified event type from the window object.\n *\n * @param event - The type of event whose handler should be removed.\n */\nfunction removeEventHandler(event: EventType) {\n if (!isBrowser()) {\n return;\n }\n\n const handler = eventHandlers.get(event);\n\n if (handler) {\n window.removeEventListener(event, handler);\n\n eventHandlers.delete(event);\n }\n}\n\n/**\n * Registers a revalidation functions for a specific cache key.\n *\n * @param {string} key Cache key to utilize\n * @param {RevalidatorFn} revalidatorFn Main revalidation function (marks in-flight requests)\n * @param {number} [ttl] Time to live in milliseconds (default: 3 minutes)\n * @param {number} [staleTime] Time (in seconds) after which the cache entry is considered stale\n * @param {RevalidatorFn} [bgRevalidatorFn] For stale revalidation (does not mark in-flight requests)\n * @param {boolean} [refetchOnFocus] Whether to revalidate on window focus\n * @param {boolean} [refetchOnReconnect] Whether to revalidate on network reconnect\n */\nexport function addRevalidator(\n key: string,\n revalidatorFn: RevalidatorFn, // Main revalidation function (marks in-flight requests)\n ttl?: number,\n staleTime?: number,\n bgRevalidatorFn?: RevalidatorFn, // For stale revalidation (does not mark in-flight requests)\n refetchOnFocus?: boolean,\n refetchOnReconnect?: boolean,\n) {\n revalidators.set(key, [\n revalidatorFn,\n timeNow(),\n ttl ?? DEFAULT_TTL,\n staleTime,\n bgRevalidatorFn,\n refetchOnFocus,\n refetchOnReconnect,\n ]);\n\n if (refetchOnFocus) {\n addEventHandler('focus');\n }\n\n if (refetchOnReconnect) {\n addEventHandler('online');\n }\n\n if (staleTime) {\n addTimeout('s:' + key, revalidate.bind(null, key, true), staleTime * 1000);\n }\n}\n\nexport function removeRevalidator(key: string) {\n revalidators.delete(key);\n\n // Clean up stale timer\n removeTimeout('s:' + key);\n}\n\n/**\n * Periodically cleans up expired revalidators from the registry.\n * Removes any revalidator whose TTL has expired.\n *\n * @param {number} intervalMs How often to run cleanup (default: 3 minutes)\n * @returns {() => void} A function to stop the periodic cleanup\n */\nexport function startRevalidatorCleanup(\n intervalMs: number = DEFAULT_TTL,\n): () => void {\n const intervalId = setInterval(() => {\n const now = timeNow();\n\n revalidators.forEach(\n ([, lastUsed, ttl, , , refetchOnFocus, refetchOnReconnect], key) => {\n // Skip focus-only or reconnect-only revalidators to keep them alive\n if (refetchOnFocus || refetchOnReconnect) {\n return;\n }\n\n if (ttl > 0 && now - lastUsed > ttl) {\n removeRevalidator(key);\n }\n },\n );\n }, intervalMs);\n\n return () => clearInterval(intervalId);\n}\n","/**\n * Manages a set of listeners (subscribers) for arbitrary string keys, allowing cross-context or cross-component\n * cache updates and synchronization. Provides functions to add, remove, and notify listeners, as well as a\n * convenient subscribe/unsubscribe API.\n *\n * @template T - The type of the response object passed to listeners.\n *\n * @remarks\n * - Listeners are grouped by a string key, which typically represents a cache key or resource identifier.\n * - When `notifySubscribers` is called for a key, all listeners registered for that key are invoked with the provided response.\n * - The `subscribe` function returns an unsubscribe function for convenient cleanup.\n *\n * @example\n * ```ts\n * const unsubscribe = subscribe('user:123', (response) => {\n * // handle updated data\n * });\n * // Later, to stop listening:\n * unsubscribe();\n * ```\n */\n\nimport { noop } from './utils';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Listener = (response: T) => void;\n\nconst listeners = new Map>();\n\nfunction ensureListenerSet(key: string) {\n if (!listeners.has(key)) {\n listeners.set(key, new Set());\n }\n\n return listeners.get(key)!;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function addListener(key: string, fn: Listener): void {\n ensureListenerSet(key).add(fn);\n}\n\nexport function removeListener(key: string, fn: Listener) {\n const set = listeners.get(key);\n\n if (set) {\n set.delete(fn);\n\n // If the set is empty, remove the key from the listeners map\n if (set.size === 0) {\n listeners.delete(key);\n }\n }\n}\n\nexport function notifySubscribers(key: string, response: T) {\n const fns = listeners.get(key);\n\n if (fns) {\n if (fns.size === 1) {\n // If there's only one listener, call it directly\n const fn = fns.values().next().value;\n fn!(response);\n } else {\n fns.forEach((fn) => fn(response));\n }\n }\n}\n\nexport function subscribe(key: string | null, fn: (response: T) => void) {\n if (!key) {\n // No op if no key is provided\n return noop;\n }\n\n addListener(key, fn);\n\n // Return an unsubscribe function\n return () => {\n removeListener(key, fn);\n };\n}\n","import {\n GET,\n APPLICATION_JSON,\n HEAD,\n STRING,\n CHARSET_UTF_8,\n CONTENT_TYPE,\n REJECT,\n UNDEFINED,\n APPLICATION_CONTENT_TYPE,\n} from './constants';\nimport type {\n HeadersObject,\n Method,\n RequestConfig,\n} from './types/request-handler';\nimport {\n replaceUrlPathParams,\n appendQueryParams,\n isSearchParams,\n isJSONSerializable,\n isSlowConnection,\n isAbsoluteUrl,\n sanitizeObject,\n isObject,\n} from './utils';\n\nconst defaultTimeoutMs = (isSlowConnection() ? 60 : 30) * 1000;\n\nexport const defaultConfig: RequestConfig = {\n strategy: REJECT,\n timeout: defaultTimeoutMs, // 30 seconds (60 on slow connections)\n headers: {\n Accept: APPLICATION_JSON + ', text/plain, */*',\n 'Accept-Encoding': 'gzip, deflate, br',\n },\n retry: {\n delay: defaultTimeoutMs / 30, // 1 second (2 on slow connections)\n maxDelay: defaultTimeoutMs, // 30 seconds (60 on slow connections)\n resetTimeout: true,\n backoff: 1.5,\n\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status\n retryOn: [\n 408, // Request Timeout\n 409, // Conflict\n 425, // Too Early\n 429, // Too Many Requests\n 500, // Internal Server Error\n 502, // Bad Gateway\n 503, // Service Unavailable\n 504, // Gateway Timeout\n ],\n },\n};\n\n/**\n * Overwrites the default configuration with the provided custom configuration.\n *\n * @param {Partial} customConfig - The custom configuration to merge into the default config.\n * @returns {Partial} - The updated default configuration object.\n */\nexport function setDefaultConfig(\n customConfig: Partial,\n): Partial {\n const sanitized = sanitizeObject(customConfig);\n\n Object.assign(defaultConfig, sanitized);\n\n return defaultConfig;\n}\n\n/**\n * Returns a shallow copy of the current default configuration.\n *\n * @returns {RequestConfig} - The current default configuration.\n */\nexport function getDefaultConfig(): RequestConfig {\n return { ...defaultConfig };\n}\n\n/**\n * Build request configuration from defaults and overrides.\n * This function merges the default configuration with the provided request configuration,\n * @param {string} url - Request url\n * @param {RequestConfig | null | undefined} reqConfig - Request configuration\n * @return {RequestConfig} - Merged request configuration\n */\nexport function buildConfig(\n url: string,\n reqConfig?: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > | null,\n): RequestConfig {\n if (!reqConfig) {\n return buildFetcherConfig(url, getDefaultConfig());\n }\n\n const sanitized = sanitizeObject(reqConfig);\n const merged = mergeConfigs(defaultConfig, sanitized);\n\n return buildFetcherConfig(url, merged);\n}\n\n/**\n * Builds the fetcher configuration by setting the method, body, headers, and URL.\n * It also handles query parameters and path parameters. This fn mutates the passed `requestConfig` object.\n * @param {string} url - The endpoint URL to which the request will be sent.\n * @param {RequestConfig} requestConfig - The request configuration object containing method, body, headers, and other options.\n * @return {RequestConfig} - The modified request configuration object with the URL, method, body, and headers set appropriately.\n **/\nexport function buildFetcherConfig(\n url: string,\n requestConfig: RequestConfig,\n): RequestConfig {\n let method = requestConfig.method as Method;\n method = method ? (method.toUpperCase() as Method) : GET;\n\n let body: RequestConfig['data'] | undefined;\n\n // Only applicable for request methods 'PUT', 'POST', 'DELETE', and 'PATCH'\n if (method !== GET && method !== HEAD) {\n body = requestConfig.body ?? requestConfig.data;\n\n // Automatically stringify request body, if possible and when not dealing with strings\n if (body && typeof body !== STRING && isJSONSerializable(body)) {\n body = JSON.stringify(body);\n }\n }\n\n setContentTypeIfNeeded(requestConfig.headers, body);\n\n // Native fetch compatible settings\n const credentials = requestConfig.withCredentials\n ? 'include'\n : requestConfig.credentials;\n\n // The explicitly passed query params\n const dynamicUrl = replaceUrlPathParams(url, requestConfig.urlPathParams);\n const urlPath = appendQueryParams(dynamicUrl, requestConfig.params);\n const isFullUrl = isAbsoluteUrl(url);\n const baseURL = isFullUrl\n ? ''\n : requestConfig.baseURL || requestConfig.apiUrl || '';\n\n requestConfig.url = baseURL + urlPath;\n requestConfig.method = method;\n requestConfig.credentials = credentials;\n requestConfig.body = body;\n\n return requestConfig;\n}\n\n/**\n * Ensures the `Content-Type` header is set to `application/json; charset=utf-8`\n * if it is not already present and the request method and body meet specific conditions.\n *\n * @param headers - The headers object to modify. Can be an instance of `Headers`\n * or a plain object conforming to `HeadersInit`.\n * @param body - The optional body of the request. If no body is provided and the\n * method is 'GET' or 'HEAD', the function exits without modifying headers.\n */\nfunction setContentTypeIfNeeded(\n headers?: HeadersInit | HeadersObject,\n body?: unknown,\n): void {\n // If no headers are provided, or if the body is not set and the method is PUT or DELETE, do nothing\n if (!headers || !body) {\n return;\n }\n\n // Types that should not have Content-Type set (browser handles these)\n if (\n body instanceof FormData || // Browser automatically sets multipart/form-data with boundary\n (typeof Blob !== UNDEFINED && body instanceof Blob) || // Blob/File already have their own MIME types, don't override\n (typeof File !== UNDEFINED && body instanceof File) ||\n (typeof ReadableStream !== UNDEFINED && body instanceof ReadableStream) // Stream type should be determined by the stream source\n ) {\n return;\n }\n\n let contentTypeValue: string;\n\n if (isSearchParams(body)) {\n contentTypeValue = APPLICATION_CONTENT_TYPE + 'x-www-form-urlencoded';\n } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {\n contentTypeValue = APPLICATION_CONTENT_TYPE + 'octet-stream';\n } else if (isJSONSerializable(body)) {\n contentTypeValue = APPLICATION_JSON + ';' + CHARSET_UTF_8;\n } else {\n // Do not set Content-Type if content is not recognizable\n return;\n }\n\n if (headers instanceof Headers) {\n if (!headers.has(CONTENT_TYPE)) {\n headers.set(CONTENT_TYPE, contentTypeValue);\n }\n } else if (\n isObject(headers) &&\n !Array.isArray(headers) &&\n !headers[CONTENT_TYPE]\n ) {\n headers[CONTENT_TYPE] = contentTypeValue;\n }\n}\n\nexport function mergeConfigs(\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n): RequestConfig {\n const mergedConfig: RequestConfig = Object.assign(\n {},\n baseConfig,\n overrideConfig,\n );\n\n // Ensure that retry and headers are merged correctly\n mergeConfig('retry', mergedConfig, baseConfig, overrideConfig);\n mergeConfig('headers', mergedConfig, baseConfig, overrideConfig);\n\n // Merge interceptors efficiently\n mergeInterceptors('onRequest', mergedConfig, baseConfig, overrideConfig);\n mergeInterceptors('onResponse', mergedConfig, baseConfig, overrideConfig);\n mergeInterceptors('onError', mergedConfig, baseConfig, overrideConfig);\n\n return mergedConfig;\n}\n\n/**\n * Efficiently merges interceptor functions from base and new configs\n */\nfunction mergeInterceptors<\n K extends 'onRequest' | 'onResponse' | 'onError' | 'onRetry',\n>(\n property: K,\n targetConfig: RequestConfig,\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n): void {\n const baseInterceptor = baseConfig[property];\n const newInterceptor = overrideConfig[property];\n\n if (!baseInterceptor && !newInterceptor) {\n return;\n }\n\n if (!baseInterceptor) {\n targetConfig[property] = newInterceptor;\n return;\n }\n\n if (!newInterceptor) {\n targetConfig[property] = baseInterceptor;\n return;\n }\n\n const baseArr = Array.isArray(baseInterceptor)\n ? baseInterceptor\n : [baseInterceptor];\n const newArr = Array.isArray(newInterceptor)\n ? newInterceptor\n : [newInterceptor];\n\n // This is the only LIFO interceptor, so we apply it after the response is prepared\n targetConfig[property] =\n property === 'onResponse' ? newArr.concat(baseArr) : baseArr.concat(newArr);\n}\n\n/**\n * Merges the specified property from the base configuration and the override configuration into the target configuration.\n *\n * @param {K} property - The property key to merge from the base and override configurations. Must be a key of RequestConfig.\n * @param {RequestConfig} targetConfig - The configuration object that will receive the merged properties.\n * @param {RequestConfig} baseConfig - The base configuration object that provides default values.\n * @param {RequestConfig} overrideConfig - The override configuration object that contains user-specific settings to merge.\n */\nexport function mergeConfig(\n property: K,\n targetConfig: RequestConfig,\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n): void {\n if (overrideConfig[property]) {\n targetConfig[property] = {\n ...baseConfig[property],\n ...overrideConfig[property],\n };\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { hash } from './hash';\nimport type {\n CacheKeyFunction,\n DefaultResponse,\n FetchResponse,\n MutationSettings,\n RequestConfig,\n} from './types/request-handler';\nimport type { CacheEntry } from './types/cache-manager';\nimport { GET, STRING, UNDEFINED } from './constants';\nimport { isObject, sanitizeObject, sortObject, timeNow } from './utils';\nimport { revalidate } from './revalidator-manager';\nimport { notifySubscribers } from './pubsub-manager';\nimport type { DefaultPayload, DefaultParams, DefaultUrlParams } from './types';\nimport { removeInFlight } from './inflight-manager';\nimport { addTimeout } from './timeout-wheel';\nimport { defaultConfig } from './config-handler';\nimport { processHeaders } from './utils';\n\nexport const IMMEDIATE_DISCARD_CACHE_TIME = 0; // Use it for cache entries that need to be persistent until unused by components or manually deleted\n\nconst _cache = new Map>();\nconst DELIMITER = '|';\nconst MIN_LENGTH_TO_HASH = 64;\nconst CACHE_KEY_SANITIZE_PATTERN = new RegExp('[^\\\\w\\\\-_|]', 'g');\n\n/**\n * Headers that may affect HTTP response content and should be included in cache key generation.\n * All header names must be lowercase to match normalized request headers.\n */\nconst CACHE_KEY_HEADER_WHITELIST = new Set([\n // Content negotiation\n 'accept', // Affects response format (e.g. JSON, HTML)\n 'accept-language', // Affects localization of the response\n 'accept-encoding', // Affects response compression (e.g. gzip, br)\n\n // Authentication\n 'authorization', // Affects access to protected resources\n\n // Request body metadata\n 'content-type', // Affects how the request body is interpreted\n\n // Optional headers\n 'referer', // May influence behavior in some APIs\n 'origin', // Relevant in CORS or tenant-specific APIs\n 'user-agent', // Included only for reason if server returns client-specific content\n\n // Cookies — only if server uses session-based responses\n 'cookie', // Can fragment cache heavily; use only if necessary\n\n // Custom headers that may affect response content\n 'x-api-key', // Token-based access, often affects authorization\n 'x-requested-with', // AJAX requests (used historically for distinguishing frontend calls)\n 'x-client-id', // Per-client/partner identity; often used in multi-tenant APIs\n 'x-tenant-id', // Multi-tenant segmentation; often changes response per tenant\n 'x-user-id', // Explicit user context (less common, but may exist)\n\n 'x-app-version', // Used for version-specific behavior (e.g. mobile apps)\n 'x-feature-flag', // Controls feature rollout behavior server-side\n 'x-device-id', // Used when response varies per device/app instance\n 'x-platform', // e.g. 'ios', 'android', 'web' — used in apps that serve different content\n\n 'x-session-id', // Only if backend uses it to affect the response directly (rare)\n 'x-locale', // Sometimes used in addition to or instead of `accept-language`\n]);\n\n/**\n * Generates a unique cache key for a given URL and fetch options, ensuring that key factors\n * like method, headers, body, and other options are included in the cache key.\n * Headers and other objects are sorted by key to ensure consistent cache keys.\n *\n * @param {RequestConfig} config - The fetch options that may affect the request. The most important are:\n * @property {string} [method=\"GET\"] - The HTTP method (GET, POST, etc.).\n * @property {HeadersInit} [headers={}] - The request headers.\n * @property {BodyInit | null} [body=\"\"] - The body of the request (only for methods like POST, PUT).\n * @property {RequestCredentials} [credentials=\"same-origin\"] - Whether to include credentials (include, same-origin, omit).\n * @property {RequestCache} [cache=\"default\"] - The cache mode (e.g., default, no-store, reload).\n * @returns {string} - A unique cache key string based on the provided options.\n *\n * @example\n * const cacheKey = generateCacheKey({\n * url: 'https://api.example.com/data',\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ name: 'Alice' }),\n * mode: 'cors',\n * credentials: 'include',\n * });\n * console.log(cacheKey);\n */\nexport function generateCacheKey(\n config: RequestConfig,\n cacheKeyCheck = true,\n): string {\n // This is super fast. Effectively a no-op if cacheKey is\n // a string or a function that returns a string.\n const key = config.cacheKey;\n\n if (key && cacheKeyCheck) {\n return typeof key === STRING\n ? (key as string)\n : (key as CacheKeyFunction)(config);\n }\n\n const {\n url = '',\n method = GET,\n headers = null,\n body = null,\n credentials = 'same-origin',\n } = config;\n\n // Sort headers and body + convert sorted to strings for hashing purposes\n // Native serializer is on avg. 3.5x faster than a Fast Hash or FNV-1a\n let headersString = '';\n if (headers) {\n let obj: Record;\n\n if (headers instanceof Headers) {\n obj = processHeaders(headers);\n } else {\n obj = headers as Record;\n }\n\n // Filter headers to only include those that affect request identity\n // Include only headers that affect request identity, not execution behavior\n const keys = Object.keys(obj);\n const len = keys.length;\n\n // Sort keys manually for fastest deterministic output\n if (len > 1) {\n keys.sort();\n }\n\n let str = '';\n for (let i = 0; i < len; ++i) {\n if (CACHE_KEY_HEADER_WHITELIST.has(keys[i].toLowerCase())) {\n str += keys[i] + ':' + obj[keys[i]] + ';';\n }\n }\n\n headersString = hash(str);\n }\n\n // For GET requests, return early with shorter cache key\n if (method === GET) {\n return (\n method +\n DELIMITER +\n url +\n DELIMITER +\n credentials +\n DELIMITER +\n headersString\n ).replace(CACHE_KEY_SANITIZE_PATTERN, '');\n }\n\n let bodyString = '';\n if (body) {\n if (typeof body === STRING) {\n bodyString = body.length < MIN_LENGTH_TO_HASH ? body : hash(body); // hash only if large\n } else if (body instanceof FormData) {\n body.forEach((value, key) => {\n // Append key=value and '&' directly to the result\n bodyString += key + '=' + value + '&';\n });\n\n if (bodyString.length > MIN_LENGTH_TO_HASH) {\n bodyString = hash(bodyString);\n }\n } else if (\n (typeof Blob !== UNDEFINED && body instanceof Blob) ||\n (typeof File !== UNDEFINED && body instanceof File)\n ) {\n bodyString = 'BF' + body.size + body.type;\n } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {\n bodyString = 'AB' + body.byteLength;\n } else {\n const o = isObject(body)\n ? JSON.stringify(sortObject(body))\n : String(body);\n\n bodyString = o.length > MIN_LENGTH_TO_HASH ? hash(o) : o;\n }\n }\n\n // Concatenate all key parts into a cache key string\n // Template literals are apparently slower\n return (\n method +\n DELIMITER +\n url +\n DELIMITER +\n credentials +\n DELIMITER +\n headersString +\n DELIMITER +\n bodyString\n ).replace(CACHE_KEY_SANITIZE_PATTERN, ''); // Prevent cache poisoning by removal of anything that isn't letters, numbers, -, _, or |\n}\n\n/**\n * Checks if the cache entry is expired based on its timestamp and the expiry time.\n *\n * @param {CacheEntry} entry - The cache entry to check.\n * @returns {boolean} - Returns true if the cache entry is expired, false otherwise.\n */\nfunction isCacheExpired(entry: CacheEntry): boolean {\n // No expiry time means the entry never expires\n if (!entry.expiry) {\n return false;\n }\n\n return timeNow() > entry.expiry;\n}\n\n/**\n * Checks if the cache entry is stale based on its timestamp and the stale time.\n *\n * @param {CacheEntry} entry - The cache entry to check.\n * @returns {boolean} - Returns true if the cache entry is stale, false otherwise.\n */\nfunction isCacheStale(entry: CacheEntry): boolean {\n if (!entry.stale) {\n return false;\n }\n\n return timeNow() > entry.stale;\n}\n\n/**\n * Retrieves a cached response from the internal cache using the provided key.\n *\n * @param key - The unique key identifying the cached entry. If null, returns null.\n * @returns The cached {@link FetchResponse} if found, otherwise null.\n */\nexport function getCacheData<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n key: string | null,\n): FetchResponse | null {\n if (!key) {\n return null;\n }\n\n const entry = _cache.get(key);\n\n return entry ? entry.data : null;\n}\n\n/**\n * Retrieves a cache entry if it exists and is not expired.\n *\n * @param {string} key Cache key to utilize\n * @returns {CacheEntry | null} - The cache entry if it exists and is not expired, null otherwise.\n */\nexport function getCache(\n key: string | null,\n):\n | CacheEntry<\n FetchResponse\n >\n | null\n | undefined {\n return _cache.get(key as string);\n}\n\n/**\n * Sets a new cache entry or updates an existing one, with optional TTL (time-to-live).\n *\n * @param {string} key Cache key to utilize\n * @param {T} data - The data to be cached.\n * @param {number} [ttl] - Optional TTL in seconds. If not provided, the cache entry will not expire.\n * @param {number} [staleTime] - Optional stale time in seconds. If provided, the cache entry will be considered stale after this time.\n */\nexport function setCache(\n key: string,\n data: T,\n ttl?: number,\n staleTime?: number,\n): void {\n if (ttl === 0) {\n deleteCache(key);\n return;\n }\n\n const time = timeNow();\n const ttlMs = ttl ? ttl * 1000 : 0;\n\n _cache.set(key, {\n data,\n time,\n stale: staleTime && staleTime > 0 ? time + staleTime * 1000 : staleTime,\n expiry: ttl === -1 ? undefined : time + ttlMs,\n });\n\n if (ttlMs > 0) {\n addTimeout(\n 'c:' + key,\n () => {\n deleteCache(key, true);\n },\n ttlMs,\n );\n }\n}\n\n/**\n * Invalidates (deletes) a cache entry.\n *\n * @param {string} key Cache key to utilize\n * @param {boolean} [removeExpired=false] - If true, only deletes the cache entry if it is expired or stale.\n */\nexport function deleteCache(key: string, removeExpired: boolean = false): void {\n if (removeExpired) {\n const entry = getCache(key);\n\n // If the entry does not exist, or it is neither expired nor stale, do not delete\n if (!entry || !isCacheExpired(entry)) {\n return;\n }\n }\n\n _cache.delete(key);\n}\n\n/**\n * Prunes the cache by removing entries that have expired based on the provided cache time.\n */\nexport function pruneCache(): void {\n _cache.clear();\n}\n\n/**\n * Mutates a cache entry with new data and optionally revalidates it.\n *\n * @param {string | null} key Cache key to utilize. If null, no mutation occurs.\n * @param {ResponseData} newData - The new data to be cached.\n * @param {MutationSettings|undefined} settings - Mutation settings.\n */\nexport async function mutate<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n key: string | null,\n newData: ResponseData,\n settings?: MutationSettings,\n): Promise | null> {\n // If no key is provided, do nothing\n if (!key) {\n return null;\n }\n\n const entry = getCache(\n key,\n );\n\n if (!entry) {\n return null;\n }\n\n const updatedData = isObject(newData) ? sanitizeObject(newData) : newData;\n\n const updatedResponse = {\n ...entry.data,\n data: updatedData,\n };\n\n const updatedEntry = {\n ...entry,\n data: updatedResponse,\n };\n\n _cache.set(key, updatedEntry);\n notifySubscribers(key, updatedResponse);\n\n if (settings && settings.refetch) {\n return await revalidate(key);\n }\n\n return null;\n}\n\n/**\n * Retrieves a cached response if available and valid, otherwise returns null.\n *\n * @template ResponseData - The type of the response data.\n * @template RequestBody - The type of the request body.\n * @template QueryParams - The type of the query parameters.\n * @template PathParams - The type of the path parameters.\n * @param {string | null} cacheKey - The cache key to look up.\n * @param {number | undefined} cacheTime - The maximum time to cache entry.\n * @param {RequestConfig} requestConfig - The fetcher configuration.\n * @returns {FetchResponse | null} - The cached response or null.\n */\nexport function getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n cacheKey: string | null,\n cacheTime: number | undefined,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): FetchResponse | null {\n // If cache key or time is not provided, return null\n if (!cacheKey || cacheTime === undefined || cacheTime === null) {\n return null;\n }\n\n // Check if cache should be bypassed\n const buster = requestConfig.cacheBuster || defaultConfig.cacheBuster;\n if (buster && buster(requestConfig)) {\n return null;\n }\n\n if (requestConfig.cache && requestConfig.cache === 'reload') {\n return null; // Skip cache lookup entirely\n }\n\n // Retrieve the cached entry\n const entry = getCache(\n cacheKey,\n );\n\n if (!entry) {\n return null;\n }\n\n const isExpired = isCacheExpired(entry);\n const isStale = isCacheStale(entry);\n\n // If completely expired, delete and return null\n if (isExpired) {\n deleteCache(cacheKey);\n return null;\n }\n\n // If fresh (not stale), return immediately\n if (!isStale) {\n return entry.data;\n }\n\n // SWR: Data is stale but not expired\n if (isStale && !isExpired) {\n // Triggering background revalidation here could cause race conditions\n // So we return stale data immediately and leave it up to implementers to handle revalidation\n return entry.data;\n }\n\n return null;\n}\n\n/**\n * Sets or deletes the response cache based on cache settings and notifies subscribers.\n *\n * @param {FetchResponse} output - The response to cache.\n * @param {RequestConfig} requestConfig - The request configuration.\n * @param {boolean} [isError=false] - Whether the response is an error.\n */\nexport function handleResponseCache<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n output: FetchResponse,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n isError: boolean = false,\n): void {\n // It is string as it is called once request is made\n const cacheKey = requestConfig.cacheKey as string;\n\n if (cacheKey) {\n const cacheTime = requestConfig.cacheTime;\n const skipCache = requestConfig.skipCache;\n\n // Fast path: only set cache if cacheTime is positive and not skipping cache\n if (\n cacheTime &&\n (!isError || requestConfig.cacheErrors) &&\n !(skipCache && skipCache(output, requestConfig))\n ) {\n setCache(cacheKey, output, cacheTime, requestConfig.staleTime);\n }\n\n notifySubscribers(cacheKey, output);\n removeInFlight(cacheKey);\n\n const prevCacheKey = requestConfig._prevKey;\n\n if (prevCacheKey) {\n removeInFlight(prevCacheKey);\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { mutate } from './cache-manager';\nimport {\n APPLICATION_CONTENT_TYPE,\n APPLICATION_JSON,\n CONTENT_TYPE,\n FUNCTION,\n OBJECT,\n STRING,\n} from './constants';\nimport {\n DefaultResponse,\n FetchResponse,\n RequestConfig,\n ResponseError,\n DefaultParams,\n DefaultUrlParams,\n DefaultPayload,\n} from './types';\nimport { flattenData, isObject, processHeaders } from './utils';\n\n/**\n * Parses the response data based on the Content-Type header.\n *\n * @param response - The Response object to parse.\n * @returns A Promise that resolves to the parsed data.\n */\nexport async function parseResponseData<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n response: FetchResponse,\n): Promise {\n // Bail early if response is null or undefined\n if (!response) {\n return null;\n }\n\n // Get the content-type header once\n let contentType = (response as Response).headers?.get(CONTENT_TYPE);\n\n if (contentType) {\n // Lowercase and trim for consistent matching\n contentType = contentType.toLowerCase().trim();\n } else {\n contentType = '';\n }\n\n // Split for mime type without charset\n const mimeType = contentType.split(';', 1)[0];\n\n let data;\n\n try {\n if (mimeType.includes(APPLICATION_JSON) || mimeType.includes('+json')) {\n data = await response.json(); // Parse JSON response\n } else if (\n (mimeType.includes('multipart/form-data') || // Parse as FormData\n mimeType.includes(\n APPLICATION_CONTENT_TYPE + 'x-www-form-urlencoded', // Handle URL-encoded forms\n )) &&\n typeof response.formData === FUNCTION\n ) {\n data = await response.formData();\n } else if (\n mimeType.includes(APPLICATION_CONTENT_TYPE + 'octet-stream') &&\n typeof response.blob === FUNCTION\n ) {\n data = await response.blob(); // Parse as blob\n } else {\n data = await response.text();\n\n if (typeof data === STRING) {\n const trimmed = data.trim();\n if (\n (trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))\n ) {\n try {\n data = JSON.parse(trimmed);\n } catch {\n // leave as text if parsing fails\n }\n }\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (_error) {\n // Parsing failed, fallback to null\n data = null;\n }\n\n return data;\n}\n\n/**\n * Prepare response object with additional information.\n *\n * @param Response. It may be \"null\" in case of request being aborted.\n * @param {RequestConfig} config - Request config\n * @param error - whether the response is erroneous\n * @returns {FetchResponse} Response data\n */\nexport const prepareResponse = <\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n config: RequestConfig,\n error: ResponseError<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null = null,\n): FetchResponse => {\n const defaultResponse = config.defaultResponse;\n const cacheKey = config.cacheKey;\n const mutatator = mutate.bind(null, cacheKey as string) as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >['mutate'];\n\n // This may happen when request is cancelled.\n if (!response) {\n return {\n ok: false,\n // Enhance the response with extra information\n error,\n data: defaultResponse ?? null,\n headers: null,\n config,\n mutate: mutatator,\n isFetching: false,\n isSuccess: false,\n isError: true,\n } as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }\n\n const isNativeResponse =\n typeof Response === FUNCTION && response instanceof Response;\n\n let data = response.data;\n\n // Set the default response if the provided data is an empty object\n if (\n defaultResponse !== undefined &&\n (data === undefined ||\n data === null ||\n (typeof data === OBJECT && Object.keys(data).length === 0))\n ) {\n response.data = data = defaultResponse;\n }\n\n if (config.flattenResponse) {\n response.data = data = flattenData(data);\n }\n\n if (config.select) {\n response.data = data = config.select(data);\n }\n\n const headers = processHeaders(response.headers);\n\n // Native fetch Response extended by extra information\n if (isNativeResponse) {\n return {\n body: response.body,\n bodyUsed: response.bodyUsed,\n ok: response.ok,\n redirected: response.redirected,\n type: response.type,\n url: response.url,\n status: response.status,\n statusText: response.statusText,\n\n // Convert methods to use arrow functions to preserve correct return types\n blob: () => response.blob(),\n json: () => response.json(),\n text: () => response.text(),\n clone: () => response.clone(),\n arrayBuffer: () => response.arrayBuffer(),\n formData: () => response.formData(),\n bytes: () => response.bytes(),\n\n // Enhance the response with extra information\n error,\n data,\n headers,\n config,\n mutate: mutatator,\n isFetching: false,\n isSuccess: response.ok && !error,\n isError: !!error,\n };\n }\n\n // If it's a custom fetcher, and it does not return any Response instance, it may have its own internal handler\n if (isObject(response)) {\n response.error = error;\n response.headers = headers;\n response.isFetching = false;\n response.mutate = mutatator;\n response.isSuccess = response.ok && !error;\n response.isError = !!error;\n }\n\n return response;\n};\n","import { applyInterceptors } from './interceptor-manager';\nimport type { FetchResponse, RetryConfig, RetryFunction } from './types';\nimport { delayInvocation, timeNow } from './utils';\nimport { generateCacheKey } from './cache-manager';\n\nfunction getMsFromHttpDate(dateString: string): number | null {\n const ms = Date.parse(dateString) - timeNow();\n\n if (!isNaN(ms)) {\n return Math.max(0, Math.floor(ms));\n }\n return null;\n}\n\n/**\n * Calculates the number of milliseconds to wait before retrying a request,\n * based on the `Retry-After` HTTP header in the provided response.\n *\n * The function supports both numeric (seconds) and HTTP-date formats for the `Retry-After` header.\n * - If the header is a number, it is interpreted as seconds and converted to milliseconds.\n * - If the header is a date, the function calculates the difference between the date and the current time.\n *\n * @param extendedResponse - The response object containing headers, or `null`.\n * @returns The number of milliseconds to wait before retrying, or `null` if the header is not present or invalid.\n */\nexport function getRetryAfterMs(\n extendedResponse: FetchResponse | null,\n): number | null {\n if (!extendedResponse) {\n return null;\n }\n\n const headers = extendedResponse.headers || {};\n const retryAfter = headers['retry-after'];\n\n if (retryAfter) {\n // Try parsing as seconds\n const seconds = Number(retryAfter);\n\n if (!isNaN(seconds) && seconds >= 0) {\n return seconds * 1000;\n }\n\n const ms = getMsFromHttpDate(retryAfter);\n\n if (ms !== null) {\n return ms;\n }\n }\n\n // Headers are already in lowercase\n const RATELIMIT_RESET = 'ratelimit-reset';\n\n // Unix timestamp when the rate limit window resets (relative to current time)\n // Fallback to checking 'ratelimit-reset-after' OR 'x-ratelimit-reset-after' headers\n const rateLimitResetAfter =\n headers[RATELIMIT_RESET + '-after'] ||\n headers['x-' + RATELIMIT_RESET + '-after'];\n\n if (rateLimitResetAfter) {\n const seconds = Number(rateLimitResetAfter);\n\n if (!isNaN(seconds)) {\n return seconds * 1000;\n }\n }\n\n // ISO 8601 datetime when the rate limit resets\n // Fallback to checking 'ratelimit-reset-at' 'x-ratelimit-reset-at' headers\n const rateLimitResetAt =\n headers[RATELIMIT_RESET + '-at'] || headers['x-' + RATELIMIT_RESET + '-at'];\n\n if (rateLimitResetAt) {\n return getMsFromHttpDate(rateLimitResetAt);\n }\n\n return null;\n}\n\n/**\n * Executes a request function with retry logic according to the provided configuration.\n *\n * The function attempts the request up to the specified number of retries, applying delay and backoff strategies.\n * Retries can be triggered based on response status codes, custom logic, or the presence of a `Retry-After` header.\n * Optionally, an `onRetry` interceptor can be invoked before each retry attempt.\n *\n * @typeParam ResponseData - The type of the response data.\n * @typeParam RequestBody - The type of the request body.\n * @typeParam QueryParams - The type of the query parameters.\n * @typeParam PathParams - The type of the path parameters.\n * @param requestFn - The function that performs the request. Receives `isStaleRevalidation` and `attempt` as arguments.\n * @param config - The retry configuration, including retry count, delay, backoff, retry conditions, and hooks.\n * @returns A promise resolving to the fetch response, or rejecting if all retries are exhausted.\n * @throws Error if the maximum number of retries is exceeded or a non-retriable error occurs.\n */\nexport async function withRetry<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n requestFn: (\n isStaleRevalidation: boolean,\n attempt: number,\n ) => Promise<\n FetchResponse\n >,\n config: RetryConfig,\n): Promise> {\n const {\n retries = 0,\n delay = 0,\n backoff = 1,\n maxDelay,\n retryOn = [],\n shouldRetry,\n } = config;\n\n let attempt = 0;\n let waitTime = delay;\n const maxRetries = retries > 0 ? retries : 0;\n let output: FetchResponse;\n\n while (attempt <= maxRetries) {\n // Subsequent attempts will have output defined, but the first attempt may not.\n // Let's apply onRetry interceptor and regenerate cache key if ot really changes.\n if (attempt > 0 && output!) {\n const cfg = output.config;\n const onRetry = cfg.onRetry;\n\n if (onRetry) {\n await applyInterceptors(onRetry, output, attempt);\n\n // If the key was automatically generated, we need to regenerate it as config may change.\n // We don't detect whether config changed for performance reasons.\n if (cfg._isAutoKey) {\n cfg._prevKey = cfg.cacheKey as string;\n cfg.cacheKey = generateCacheKey(cfg, false);\n }\n }\n }\n\n // Performance optimization: Call the request function with the current attempt number\n // If this is the first attempt, we pass `isStaleRevalidation` as `false`,\n // otherwise we pass `true` to indicate that this is a stale revalidation (no cache hit).\n output = await requestFn(attempt > 0, attempt);\n const error = output.error;\n\n // Check if we should retry based on successful response\n if (!error) {\n if (shouldRetry && attempt < maxRetries) {\n const shouldRetryResult = await shouldRetry(output, attempt);\n\n if (shouldRetryResult) {\n await delayInvocation(waitTime);\n waitTime *= backoff || 1;\n waitTime = Math.min(waitTime, maxDelay || waitTime);\n attempt++;\n continue;\n }\n }\n\n break;\n }\n\n // Determine if we should stop retrying\n const shouldStopRetrying = await getShouldStopRetrying(\n output,\n attempt,\n maxRetries,\n shouldRetry,\n retryOn,\n );\n\n if (shouldStopRetrying) {\n break;\n }\n\n // If we should not stop retrying, continue to the next attempt\n // Handle rate limiting if the error status is 429 (Too Many Requests) or 503 (Service Unavailable)\n if (error.status === 429 || error.status === 503) {\n // Try to extract the \"Retry-After\" value from the response headers\n const retryAfterMs = getRetryAfterMs(output);\n\n // If a valid retry-after value is found, override the wait time before next retry\n if (retryAfterMs !== null) {\n waitTime = retryAfterMs;\n }\n }\n\n await delayInvocation(waitTime);\n waitTime *= backoff || 1;\n waitTime = Math.min(waitTime, maxDelay || waitTime);\n attempt++;\n }\n\n return output!;\n}\n\n/**\n * Determines whether to stop retrying based on the error, current attempt count, and retry configuration.\n *\n * This function checks:\n * - If the maximum number of retries has been reached.\n * - If a custom `shouldRetry` callback is provided, its result is used to decide.\n * - If no custom logic is provided, falls back to checking if the error status is included in the `retryOn` list.\n *\n * @typeParam ResponseData - The type of the response data.\n * @typeParam RequestBody - The type of the request body.\n * @typeParam QueryParams - The type of the query parameters.\n * @typeParam PathParams - The type of the path parameters.\n * @param output - The response object containing the error and request configuration.\n * @param attempt - The current retry attempt number.\n * @param maxRetries - The maximum number of retry attempts allowed.\n * @param shouldRetry - Optional custom function to determine if a retry should occur.\n * @param retryOn - Optional list of HTTP status codes that should trigger a retry.\n * @returns A promise resolving to `true` if retrying should stop, or `false` to continue retrying.\n */\nexport async function getShouldStopRetrying<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n output: FetchResponse,\n attempt: number,\n maxRetries: number,\n shouldRetry?: RetryFunction<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n retryOn: number[] = [],\n): Promise {\n // Safety first: always respect max retries\n // We check retries provided regardless of the shouldRetry being provided so to avoid infinite loops.\n // It is a fail-safe so to prevent excessive retry attempts even if custom retry logic suggests a retry.\n if (attempt === maxRetries) {\n return true;\n }\n\n let customDecision: boolean | null = null;\n\n // Get custom decision if shouldRetry is provided\n if (shouldRetry) {\n const result = await shouldRetry(output, attempt);\n customDecision = result;\n\n // Decision cascade:\n if (customDecision !== null) {\n return !customDecision;\n }\n }\n\n return !(retryOn || []).includes(output.error?.status ?? 0);\n}\n","import type { RequestConfig, FetchResponse } from './types';\nimport { delayInvocation } from './utils';\n\n/**\n * Executes a request function with polling, stopping when shouldStopPolling returns true,\n * pollingInterval is not set, or maxAttempts is reached.\n *\n * @template Output The type of the output returned by the request function.\n * @param requestFn - The function that performs a single request (with retries).\n * @param pollingInterval - Interval in ms between polling attempts.\n * @param shouldStopPolling - Function to determine if polling should stop.\n * @param maxAttempts - Maximum number of polling attempts, default: 0 (unlimited).\n * @param pollingDelay - Delay in ms before each polling attempt, default: 0.\n * @returns The final output from the last request.\n */\nexport async function withPolling<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n requestFn: (\n isStaleRevalidation?: boolean,\n attempt?: number,\n ) => Promise<\n FetchResponse\n >,\n pollingInterval?: RequestConfig['pollingInterval'],\n shouldStopPolling?: RequestConfig['shouldStopPolling'],\n maxAttempts = 0,\n pollingDelay = 0,\n): Promise> {\n if (!pollingInterval) {\n return requestFn();\n }\n\n let pollingAttempt = 0;\n let output: FetchResponse;\n\n while (maxAttempts === 0 || pollingAttempt < maxAttempts) {\n if (pollingDelay > 0) {\n await delayInvocation(pollingDelay);\n }\n\n output = await requestFn();\n\n pollingAttempt++;\n\n if (\n (maxAttempts > 0 && pollingAttempt >= maxAttempts) ||\n !pollingInterval ||\n (shouldStopPolling && shouldStopPolling(output, pollingAttempt))\n ) {\n break;\n }\n\n await delayInvocation(pollingInterval);\n }\n\n return output!;\n}\n","import type { ResponseError } from './errors/response-error';\nimport type {\n DefaultResponse,\n FetchResponse,\n RequestConfig,\n} from './types/request-handler';\nimport { applyInterceptors } from './interceptor-manager';\nimport { handleResponseCache } from './cache-manager';\nimport { ABORT_ERROR, REJECT } from './constants';\nimport { DefaultParams, DefaultUrlParams, DefaultPayload } from './types';\n\n/**\n * Handles final processing for both success and error responses\n * Applies error interceptors, caching, notifications, and error strategy\n */\nexport async function withErrorHandling<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n isStaleRevalidation: boolean,\n requestFn: (\n isStaleRevalidation: boolean,\n ) => Promise<\n FetchResponse\n >,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): Promise> {\n const output = await requestFn(isStaleRevalidation);\n const error = output.error;\n\n if (!error) {\n // SUCCESS PATH\n handleResponseCache(output, requestConfig);\n\n return output;\n }\n\n // ERROR PATH\n\n if (requestConfig.onError) {\n await applyInterceptors(requestConfig.onError, error);\n }\n\n // Timeouts and request cancellations using AbortController do not throw any errors unless rejectCancelled is true.\n // Only handle the error if the request was not cancelled, or if it was cancelled and rejectCancelled is true.\n const isCancelled = error.isCancelled;\n\n if (!isCancelled && requestConfig.logger) {\n logger(requestConfig, 'FETCH ERROR', error as ResponseError);\n }\n\n // Handle cache and notifications FIRST (before strategy)\n handleResponseCache(output, requestConfig, true);\n\n // handle error strategy as the last part\n const shouldHandleError = !isCancelled || requestConfig.rejectCancelled;\n\n if (shouldHandleError) {\n const strategy = requestConfig.strategy;\n // Reject the promise\n if (strategy === REJECT) {\n return Promise.reject(error);\n }\n\n // Hang the promise\n if (strategy === 'silent') {\n await new Promise(() => null);\n }\n }\n\n return output;\n}\n\nexport function enhanceError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n error: any,\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): void {\n error.status = error.status || response?.status || 0;\n error.statusText = error.statusText || response?.statusText || '';\n error.config = error.request = requestConfig;\n error.response = response;\n error.isCancelled = error.name === ABORT_ERROR;\n}\n\n/**\n * Logs messages or errors using the configured logger's `warn` method.\n *\n * @param {RequestConfig} reqConfig - Request config passed when making the request\n * @param {...(string | ResponseError)} args - Messages or errors to log.\n */\nfunction logger(\n reqConfig: RequestConfig,\n ...args: (string | ResponseError)[]\n): void {\n const logger = reqConfig.logger;\n\n if (logger && logger.warn) {\n logger.warn(...args);\n }\n}\n","import type {\n DefaultResponse,\n RequestConfig,\n FetchResponse,\n} from './types/request-handler';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultUrlParams,\n} from './types/api-handler';\nimport { applyInterceptors } from './interceptor-manager';\nimport { ResponseError } from './errors/response-error';\nimport { isObject } from './utils';\nimport {\n markInFlight,\n setInFlightPromise,\n getInFlightPromise,\n} from './inflight-manager';\nimport { parseResponseData, prepareResponse } from './response-parser';\nimport { generateCacheKey, getCachedResponse, setCache } from './cache-manager';\nimport { withRetry } from './retry-handler';\nimport { withPolling } from './polling-handler';\nimport { notifySubscribers } from './pubsub-manager';\nimport { addRevalidator } from './revalidator-manager';\nimport { enhanceError, withErrorHandling } from './error-handler';\nimport { FUNCTION } from './constants';\nimport { buildConfig } from './config-handler';\n\nconst inFlightResponse = {\n isFetching: true,\n};\n\n/**\n * Sends an HTTP request to the specified URL using the provided configuration and returns a typed response.\n *\n * @typeParam ResponseData - The expected shape of the response data. Defaults to `DefaultResponse`.\n * @typeParam RequestBody - The type of the request payload/body. Defaults to `DefaultPayload`.\n * @typeParam QueryParams - The type of the query parameters. Defaults to `DefaultParams`.\n * @typeParam PathParams - The type of the path parameters. Defaults to `DefaultUrlParams`.\n *\n * @param url - The endpoint URL to which the request will be sent.\n * @param config - Optional configuration object for the request, including headers, method, body, query, and path parameters.\n *\n * @returns A promise that resolves to a `FetchResponse` containing the typed response data and request metadata.\n *\n * @example\n * ```typescript\n * const { data } = await fetchf('/api/user', { method: 'GET' });\n * console.log(data);\n * ```\n */\nexport async function fetchf<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n url: string,\n reqConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > | null = null,\n): Promise> {\n const fetcherConfig = buildConfig<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(url, reqConfig);\n\n const {\n timeout,\n cancellable,\n cacheKey,\n dedupeTime,\n cacheTime,\n staleTime,\n refetchOnFocus,\n refetchOnReconnect,\n pollingInterval = 0,\n } = fetcherConfig;\n const isCacheEnabled = cacheTime !== undefined || staleTime !== undefined;\n\n const needsCacheKey = !!(\n cacheKey ||\n timeout ||\n dedupeTime ||\n isCacheEnabled ||\n cancellable ||\n refetchOnFocus ||\n refetchOnReconnect\n );\n\n let _cacheKey: string | null = null;\n\n // Generate cache key if required\n if (needsCacheKey) {\n _cacheKey = generateCacheKey(fetcherConfig);\n }\n\n // Cache handling logic\n if (_cacheKey && isCacheEnabled) {\n const cached = getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(_cacheKey, cacheTime, fetcherConfig);\n\n if (cached) {\n return cached;\n }\n }\n\n // Deduplication logic\n if (_cacheKey && dedupeTime) {\n const inflight = getInFlightPromise<\n FetchResponse\n >(_cacheKey, dedupeTime);\n\n if (inflight) {\n return inflight;\n }\n }\n\n const retryConfig = fetcherConfig.retry || {};\n const { retries = 0, resetTimeout } = retryConfig;\n\n // The actual request logic as a function (one poll attempt, with retries)\n const doRequestOnce = async (isStaleRevalidation = false, attempt = 0) => {\n // If cache key is specified, we will handle optimistic updates\n // and mark the request as in-flight, so to catch \"fetching\" state.\n // This is useful for Optimistic UI updates (e.g., showing loading spinners).\n if (!attempt) {\n if (_cacheKey && !isStaleRevalidation) {\n if (staleTime) {\n const existingCache = getCachedResponse(\n _cacheKey,\n cacheTime,\n fetcherConfig,\n );\n\n // Don't notify subscribers when cache exists\n // Let them continue showing stale data during background revalidation\n if (!existingCache) {\n setCache(_cacheKey, inFlightResponse, cacheTime, staleTime);\n notifySubscribers(_cacheKey, inFlightResponse);\n }\n } else {\n notifySubscribers(_cacheKey, inFlightResponse);\n }\n }\n\n // Attach cache key so that it can be reused in interceptors or in the final response\n fetcherConfig.cacheKey = _cacheKey;\n }\n\n const url = fetcherConfig.url as string;\n\n // Add the request to the queue. Make sure to handle deduplication, cancellation, timeouts in accordance to retry settings\n const controller = markInFlight(\n _cacheKey,\n url,\n timeout,\n dedupeTime || 0,\n !!cancellable,\n // Enable timeout either by default or when retries & resetTimeout are enabled\n !!(timeout && (!attempt || resetTimeout)),\n );\n\n // Do not create a shallow copy to maintain idempotency here.\n // This ensures the original object is mutated by interceptors whenever needed, including retry logic.\n const requestConfig = fetcherConfig;\n\n requestConfig.signal = controller.signal;\n\n let output: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n let response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null = null;\n\n try {\n if (fetcherConfig.onRequest) {\n await applyInterceptors(fetcherConfig.onRequest, requestConfig);\n }\n\n // Custom fetcher\n const fn = fetcherConfig.fetcher;\n\n response = (fn\n ? await fn(\n url,\n requestConfig,\n )\n : await fetch(\n url,\n requestConfig as RequestInit,\n )) as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n\n // Custom fetcher may return a raw data object instead of a Response instance\n if (isObject(response)) {\n // Case 1: Native Response instance\n if (typeof Response === FUNCTION && response instanceof Response) {\n response.data = await parseResponseData(response);\n } else if (fn) {\n // Case 2: Custom fetcher that returns a response object\n if (!('data' in response && 'body' in response)) {\n // Case 3: Raw data, wrap it\n response = { data: response } as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }\n }\n\n // Attach config and data to the response\n // This is useful for custom fetchers that do not return a Response instance\n // and for interceptors that may need to access the request config\n response.config = requestConfig;\n\n // Check if the response status is not outside the range 200-299 and if so, output error\n // This is the pattern for fetch responses as per spec, but custom fetchers may not follow it so we check for `ok` property\n if (response.ok !== undefined && !response.ok) {\n throw new ResponseError(\n `${requestConfig.method} to ${url} failed! Status: ${response.status || null}`,\n requestConfig,\n response,\n );\n }\n }\n\n output = prepareResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(response, requestConfig);\n\n const onResponse = fetcherConfig.onResponse;\n\n if (onResponse) {\n await applyInterceptors(onResponse, output);\n }\n } catch (_error) {\n const error = _error as ResponseError<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n\n // Append additional information to Network, CORS or any other fetch() errors\n enhanceError(\n error,\n response,\n requestConfig,\n );\n\n // Prepare Extended Response\n output = prepareResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(response, requestConfig, error);\n }\n\n return output;\n };\n\n // Inline and minimize function wrappers for performance\n const baseRequest =\n retries > 0 ? () => withRetry(doRequestOnce, retryConfig) : doRequestOnce;\n\n const requestWithErrorHandling = (isStaleRevalidation = false) =>\n withErrorHandling(\n isStaleRevalidation,\n baseRequest,\n fetcherConfig,\n );\n\n // Avoid unnecessary function wrapping if polling is not enabled\n const doRequestPromise = pollingInterval\n ? withPolling(\n requestWithErrorHandling,\n pollingInterval,\n fetcherConfig.shouldStopPolling,\n fetcherConfig.maxPollingAttempts,\n fetcherConfig.pollingDelay,\n )\n : requestWithErrorHandling();\n\n // If deduplication is enabled, store the in-flight promise immediately\n if (_cacheKey) {\n if (dedupeTime) {\n setInFlightPromise(_cacheKey, doRequestPromise);\n }\n\n addRevalidator(\n _cacheKey,\n requestWithErrorHandling,\n undefined,\n staleTime,\n requestWithErrorHandling,\n !!refetchOnFocus,\n !!refetchOnReconnect,\n );\n }\n\n return doRequestPromise;\n}\n","import type {\n ApiHandlerConfig,\n ApiHandlerDefaultMethods,\n ApiHandlerMethods,\n RequestConfigUrlRequired,\n} from './types/api-handler';\nimport { fetchf } from '.';\nimport { mergeConfigs } from './config-handler';\nimport { isAbsoluteUrl } from './utils';\n\n/**\n * Creates an instance of API Handler.\n * It creates an API fetcher function using native fetch() or a custom fetcher if passed as \"fetcher\".\n * @see https://github.com/MattCCC/fetchff#configuration\n *\n * @param {Object} config - Configuration object for the API fetcher (see link above for full options).\n * @param {Object} config.endpoints - An object containing endpoint definitions.\n * @param {string} [config.baseURL] - The base URL for the API.\n * @param {Object} [config.headers] - Optional default headers to include in every request.\n * @param {Function} [config.onError] - Optional callback function for handling errors.\n * @returns API handler functions and endpoints to call\n *\n * @example\n * // Define endpoint paths\n * const endpoints = {\n * getUser: '/user',\n * createPost: '/post',\n * };\n *\n * // Create the API fetcher with configuration\n * const api = createApiFetcher({\n * endpoints,\n * apiUrl: 'https://example.com/api',\n * onError(error) {\n * console.log('Request failed', error);\n * },\n * headers: {\n * 'my-auth-key': 'example-auth-key-32rjjfa',\n * },\n * });\n *\n * // Fetch user data\n * const response = await api.getUser({ userId: 1, ratings: [1, 2] })\n */\nfunction createApiFetcher<\n EndpointTypes extends object,\n EndpointsSettings = never,\n>(config: ApiHandlerConfig) {\n const endpoints = config.endpoints;\n\n /**\n * Triggered when trying to use non-existent endpoints\n *\n * @param endpointName Endpoint Name\n * @returns {Promise}\n */\n function handleNonImplemented(endpointName: string): Promise {\n console.error(`Add ${endpointName} to 'endpoints'.`);\n\n return Promise.resolve(null);\n }\n\n const apiHandler: ApiHandlerDefaultMethods = {\n config,\n endpoints,\n /**\n * Handle Single API Request\n * It considers settings in following order: per-request settings, global per-endpoint settings, global settings.\n *\n * @param endpointName - The name of the API endpoint to call.\n * @param requestConfig - Additional configuration for the request.\n * @returns A promise that resolves with the response from the API provider.\n */\n async request(endpointName, requestConfig = {}) {\n // Use global and per-endpoint settings\n const endpointConfig = endpoints[endpointName];\n const _endpointConfig =\n endpointConfig ||\n ({ url: String(endpointName) } as RequestConfigUrlRequired);\n const url = _endpointConfig.url;\n\n // Block Protocol-relative URLs as they could lead to SSRF (Server-Side Request Forgery)\n if (url.startsWith('//')) {\n throw new Error('Protocol-relative URLs are not allowed.');\n }\n\n // Prevent potential Server-Side Request Forgery attack and leakage of credentials when same instance is used for external requests\n const mergedConfig = isAbsoluteUrl(url)\n ? // Merge endpoints configs for absolute URLs only if urls match\n endpointConfig?.url === url\n ? mergeConfigs(_endpointConfig, requestConfig)\n : requestConfig\n : mergeConfigs(mergeConfigs(config, _endpointConfig), requestConfig);\n\n // We prevent potential Server-Side Request Forgery attack and leakage of credentials as the same instance is not used for external requests\n // Retrigger fetch to ensure completely new instance of handler being triggered for external URLs\n return fetchf(url, mergedConfig);\n },\n };\n\n /**\n * Maps all API requests using native Proxy\n *\n * @param {*} prop Caller\n */\n return new Proxy>(\n apiHandler as ApiHandlerMethods,\n {\n get(_target, prop: string) {\n if (prop in apiHandler) {\n return apiHandler[prop as unknown as keyof typeof apiHandler];\n }\n\n // Prevent handler from triggering non-existent endpoints\n if (endpoints[prop]) {\n return apiHandler.request.bind(null, prop);\n }\n\n return handleNonImplemented.bind(null, prop);\n },\n },\n );\n}\n\nexport { createApiFetcher };\n"]} \ No newline at end of file +{"version":3,"sources":["../../src/constants.ts","../../src/utils.ts","../../src/interceptor-manager.ts","../../src/errors/fetch-error.ts","../../src/errors/response-error.ts","../../src/timeout-wheel.ts","../../src/inflight-manager.ts","../../src/hash.ts","../../src/revalidator-manager.ts","../../src/pubsub-manager.ts","../../src/config-handler.ts","../../src/cache-manager.ts","../../src/response-parser.ts","../../src/retry-handler.ts","../../src/polling-handler.ts","../../src/error-handler.ts","../../src/request-handler.ts","../../src/api-handler.ts"],"names":["APPLICATION_CONTENT_TYPE","APPLICATION_JSON","CHARSET_UTF_8","CONTENT_TYPE","UNDEFINED","OBJECT","STRING","FUNCTION","ABORT_ERROR","TIMEOUT_ERROR","GET","HEAD","REJECT","MAX_DEPTH","isSearchParams","data","isObject","value","sanitizeObject","obj","hasProto","hasCtor","hasPrototype","safeObj","sortObject","keys","sortedObj","i","len","key","appendQueryStringToUrl","baseUrl","queryString","appendQueryParams","url","params","encodedQueryString","s","encode","add","k","v","buildParams","prefix","depth","replaceUrlPathParams","urlPathParams","match","isAbsoluteUrl","timeNow","noop","isJSONSerializable","delayInvocation","ms","resolve","flattenData","processHeaders","headers","headersObject","isBrowser","createAbortError","message","name","error","isSlowConnection","conn","applyInterceptors","interceptors","args","interceptor","FetchError","request","response","ResponseError","WHEEL_SIZE","SECOND","MAX_WHEEL_MS","wheel","keyMap","position","timer","handleCallback","callback","result","addTimeout","cb","removeTimeout","seconds","slot","slotOrTimeout","slotArr","idx","inFlight","markInFlight","timeout","dedupeTime","isCancellable","isTimeoutEnabled","now","item","prevPromise","prevController","prevIsCancellable","controller","abortRequest","removeInFlight","setInFlightPromise","promise","getInFlightPromise","prevReq","hash","str","char","DEFAULT_TTL","revalidators","eventHandlers","customEventProviders","setEventProvider","type","provider","removeEventHandler","addEventHandler","revalidateAll","isStaleRevalidation","flagIndex","entry","revalidator","revalidate","removeRevalidators","removeRevalidator","event","handler","customProvider","cleanup","addRevalidator","revalidatorFn","ttl","staleTime","bgRevalidatorFn","refetchOnFocus","refetchOnReconnect","existing","listeners","ensureListenerSet","set","addListener","fn","removeListener","notifySubscribers","fns","subscribe","defaultTimeoutMs","defaultConfig","setDefaultConfig","customConfig","sanitized","mergeConfigs","getDefaultConfig","buildConfig","reqConfig","buildFetcherConfig","merged","requestConfig","method","body","setContentTypeIfNeeded","credentials","dynamicUrl","urlPath","baseURL","contentTypeValue","baseConfig","overrideConfig","targetConfig","mergeConfig","mergeInterceptors","property","baseInterceptor","newInterceptor","baseArr","newArr","base","override","baseNormalized","overrideNormalized","_cache","DELIMITER","MIN_LENGTH_TO_HASH","CACHE_KEY_SANITIZE_PATTERN","CACHE_KEY_NEEDS_SANITIZE","CACHE_KEY_HEADER_WHITELIST","generateCacheKey","config","cacheKeyCheck","headersString","cacheStr","bodyString","o","isCacheExpired","getCache","setCache","deleteCache","time","ttlMs","staleTimeMs","removeExpired","mutate","newData","settings","updatedData","updatedResponse","updatedEntry","getCachedResponse","cacheKey","cacheTime","buster","handleResponseCache","output","isError","skipCache","prevCacheKey","parseResponseData","contentType","mimeType","trimmed","prepareResponse","defaultResponse","mutatator","isNativeResponse","getMsFromHttpDate","dateString","getRetryAfterMs","extendedResponse","retryAfter","RATELIMIT_RESET","rateLimitResetAfter","rateLimitResetAt","withRetry","requestFn","retries","delay","backoff","maxDelay","retryOn","shouldRetry","attempt","waitTime","maxRetries","cfg","onRetry","getShouldStopRetrying","retryAfterMs","customDecision","withPolling","pollingInterval","shouldStopPolling","maxAttempts","pollingDelay","pollingAttempt","withErrorHandling","isCancelled","logger","strategy","enhanceError","inFlightResponse","fetchf","cached","fetcherConfig","cancellable","isCacheEnabled","needsCacheKey","_cacheKey","inflight","retryConfig","resetTimeout","doRequestOnce","onResponse","_error","baseRequest","_","requestWithErrorHandling","doRequestPromise","createApiFetcher","endpoints","handleNonImplemented","endpointName","apiHandler","endpointConfig","_endpointConfig","mergedConfig","_target","prop"],"mappings":"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","file":"index.js","sourcesContent":["export const APPLICATION_CONTENT_TYPE = 'application/';\n\nexport const APPLICATION_JSON = APPLICATION_CONTENT_TYPE + 'json';\nexport const CHARSET_UTF_8 = 'charset=utf-8';\nexport const CONTENT_TYPE = 'Content-Type';\n\nexport const UNDEFINED = 'undefined';\nexport const OBJECT = 'object';\nexport const STRING = 'string';\nexport const FUNCTION = 'function';\n\nexport const ABORT_ERROR = 'AbortError';\nexport const TIMEOUT_ERROR = 'TimeoutError';\n\nexport const GET = 'GET';\nexport const HEAD = 'HEAD';\n\nexport const REJECT = 'reject';\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { FUNCTION, OBJECT, STRING, UNDEFINED } from './constants';\nimport type {\n DefaultUrlParams,\n HeadersObject,\n QueryParams,\n UrlPathParams,\n} from './types';\n\n// Prevent stack overflow with recursion depth limit\nconst MAX_DEPTH = 10;\n\nexport function isSearchParams(data: unknown): boolean {\n return data instanceof URLSearchParams;\n}\n\n/**\n * Determines if a value is a non-null object.\n *\n * @param {any} value - The value to check.\n * @returns {boolean} - True if the value is a non-null object.\n */\nexport function isObject(value: any): value is Record {\n return value !== null && typeof value === OBJECT;\n}\n\n/**\n * Shallowly serializes an object by converting its key-value pairs into a string representation.\n * This function does not recursively serialize nested objects.\n *\n * @param obj - The object to serialize.\n * @returns A string representation of the object's top-level properties.\n */\nexport function shallowSerialize(obj: Record): string {\n let result = '';\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n result += key + ':' + obj[key];\n }\n }\n\n return result;\n}\n\n/**\n * Removes properties that could lead to prototype pollution from an object.\n *\n * This function checks for dangerous properties like '__proto__', 'constructor',\n * and 'prototype'. If none are present, the object is returned as-is (zero-copy fast path).\n * Otherwise, a shallow copy is created with the dangerous properties removed.\n *\n * @param obj - The object to sanitize\n * @returns A safe object without dangerous properties\n */\nexport function sanitizeObject>(obj: T): T {\n const hasProto = Object.prototype.hasOwnProperty.call(obj, '__proto__');\n const hasCtor = Object.prototype.hasOwnProperty.call(obj, 'constructor');\n const hasPrototype = Object.prototype.hasOwnProperty.call(obj, 'prototype');\n\n if (!hasProto && !hasCtor && !hasPrototype) {\n return obj;\n }\n\n const safeObj = { ...obj };\n\n if (hasProto) delete safeObj.__proto__;\n if (hasCtor) delete (safeObj as any).constructor;\n if (hasPrototype) delete safeObj.prototype;\n\n return safeObj;\n}\n\n/**\n * Sorts the keys of an object and returns a new object with sorted keys.\n *\n * This function is optimized for performance by minimizing the number of object operations\n * and using a single pass to create the sorted object.\n *\n * @param {Object} obj - The object to be sorted by keys.\n * @returns {Object} - A new object with keys sorted in ascending order.\n */\nexport function sortObject(obj: Record): object {\n const keys = Object.keys(obj);\n\n keys.sort();\n\n const sortedObj = {} as Record;\n\n for (let i = 0, len = keys.length; i < len; i++) {\n const key = keys[i];\n\n sortedObj[key] = obj[key];\n }\n\n return sortedObj;\n}\n\n/**\n * Appends a query string to a URL, ensuring proper handling of existing query parameters.\n *\n * @param baseUrl - The base URL to which the query string will be appended.\n * @param queryString - The encoded query string to append.\n * @returns The URL with the appended query string, or the original URL if no query string is provided.\n */\nfunction appendQueryStringToUrl(baseUrl: string, queryString: string): string {\n if (!queryString) {\n return baseUrl;\n }\n\n return baseUrl.includes('?')\n ? `${baseUrl}&${queryString}`\n : `${baseUrl}?${queryString}`;\n}\n\n/**\n * Appends query parameters to a given URL.\n *\n * @param {string} url - The base URL to which query parameters will be appended.\n * @param {QueryParams} params - An object containing the query parameters to append.\n * @returns {string} - The URL with the appended query parameters.\n */\nexport function appendQueryParams(url: string, params: QueryParams): string {\n if (!params) {\n return url;\n }\n\n // Check if `params` is an instance of URLSearchParams and bail early if it is\n if (isSearchParams(params)) {\n const encodedQueryString = params.toString();\n\n return appendQueryStringToUrl(url, encodedQueryString);\n }\n\n // This is exact copy of what JQ used to do. It works much better than URLSearchParams\n const s: string[] = [];\n const encode = encodeURIComponent;\n const add = (k: string, v: any) => {\n v = typeof v === FUNCTION ? v() : v;\n v = v === null ? '' : v === undefined ? '' : v;\n s[s.length] = encode(k) + '=' + encode(v);\n };\n\n const buildParams = (prefix: string, obj: any, depth = 0) => {\n // Stop recursion if maximum depth is reached\n if (depth >= MAX_DEPTH) {\n return s;\n }\n\n let i: number, len: number, key: string;\n\n if (prefix) {\n if (Array.isArray(obj)) {\n for (i = 0, len = obj.length; i < len; i++) {\n buildParams(\n prefix + '[' + (typeof obj[i] === OBJECT && obj[i] ? i : '') + ']',\n obj[i],\n depth + 1,\n );\n }\n } else if (isObject(obj)) {\n for (key in obj) {\n buildParams(prefix + '[' + key + ']', obj[key], depth + 1);\n }\n } else {\n add(prefix, obj);\n }\n } else if (Array.isArray(obj)) {\n for (i = 0, len = obj.length; i < len; i++) {\n add(obj[i].name, obj[i].value);\n }\n } else {\n for (key in obj) {\n buildParams(key, obj[key], depth + 1);\n }\n }\n return s;\n };\n\n const queryStringParts = buildParams('', params).join('&');\n\n // Encode special characters as per RFC 3986, https://datatracker.ietf.org/doc/html/rfc3986\n // This is for compatibility with server frameworks that expect the literal notation\n const encodedQueryString = queryStringParts.replace(/%5B%5D/g, '[]'); // Keep '[]' for arrays\n\n return appendQueryStringToUrl(url, encodedQueryString);\n}\n\n/**\n * Replaces dynamic URI parameters in a URL string with values from the provided `urlPathParams` object.\n * Parameters in the URL are denoted by `:`, where `` is a key in `urlPathParams`.\n *\n * @param {string} url - The URL string containing placeholders in the format `:`.\n * @param {Object} urlPathParams - An object containing the parameter values to replace placeholders.\n * @param {string} urlPathParams.paramName - The value to replace the placeholder `:` in the URL.\n * @returns {string} - The URL string with placeholders replaced by corresponding values from `urlPathParams`.\n */\nexport function replaceUrlPathParams(\n url: string,\n urlPathParams: UrlPathParams,\n): string {\n if (!urlPathParams || url.indexOf(':') === -1) {\n return url;\n }\n\n // Use a single RegExp and avoid unnecessary casts and function calls\n // Precompute keys for faster lookup\n const params = urlPathParams as DefaultUrlParams;\n\n // Use a replacer function that avoids extra work\n return url.replace(/:([a-zA-Z0-9_]+)/g, (match, key) => {\n // Use hasOwnProperty for strict key existence check\n if (Object.prototype.hasOwnProperty.call(params, key)) {\n const value = params[key];\n\n // Only replace if value is not undefined or null\n if (value !== undefined && value !== null) {\n return encodeURIComponent(String(value));\n }\n }\n\n return match;\n });\n}\n\n/**\n * Determines whether the provided URL is absolute.\n *\n * An absolute URL contains a scheme (e.g., \"http://\", \"https://\").\n *\n * @param url - The URL string to check.\n * @returns `true` if the URL is absolute, otherwise `false`.\n */\nexport function isAbsoluteUrl(url: string): boolean {\n return url.includes('://');\n}\n\nexport const timeNow = () => Date.now();\n\nexport const noop = () => {};\n\n/**\n * Checks if a value is JSON serializable.\n *\n * JSON serializable values include:\n * - Primitive types: string, number, boolean, null\n * - Arrays\n * - Plain objects (i.e., objects without special methods)\n * - Values with a `toJSON` method\n *\n * @param {any} value - The value to check for JSON serializability.\n * @returns {boolean} - Returns `true` if the value is JSON serializable, otherwise `false`.\n */\nexport function isJSONSerializable(value: any): boolean {\n const t = typeof value;\n\n if (value === undefined || value === null) {\n return false;\n }\n\n if (t === STRING || t === 'number' || t === 'boolean') {\n return true;\n }\n\n if (Array.isArray(value)) {\n return true;\n }\n\n if (\n typeof globalThis !== UNDEFINED &&\n typeof globalThis.Buffer !== UNDEFINED &&\n globalThis.Buffer.isBuffer(value)\n ) {\n return false;\n }\n\n if (value instanceof Date || isSearchParams(value)) {\n return false;\n }\n\n if (isObject(value)) {\n const proto = Object.getPrototypeOf(value);\n\n // Check if the prototype is `Object.prototype` (plain object)\n if (proto === Object.prototype) {\n return true;\n }\n\n // Check if the object has a toJSON method\n if (typeof value.toJSON === FUNCTION) {\n return true;\n }\n }\n\n return false;\n}\n\nexport async function delayInvocation(ms: number): Promise {\n return new Promise((resolve) =>\n setTimeout(() => {\n return resolve(true);\n }, ms),\n );\n}\n\n/**\n * Recursively flattens the data object if it meets specific criteria.\n *\n * The method checks if the provided `data` is an object with exactly one property named `data`.\n * If so, it recursively flattens the `data` property. Otherwise, it returns the `data` as-is.\n *\n * @param {any} data - The data to be flattened. Can be of any type, including objects, arrays, or primitives.\n * @returns {any} - The flattened data if the criteria are met; otherwise, the original `data`.\n */\nexport function flattenData(data: any, depth = 0): any {\n if (depth >= MAX_DEPTH) {\n return data;\n }\n\n if (data && isObject(data) && typeof data.data !== UNDEFINED) {\n return flattenData(data.data, depth + 1);\n }\n\n return data;\n}\n\n/**\n * Processes headers and returns them as a normalized object.\n *\n * Handles both `Headers` instances and plain objects. Normalizes header keys to lowercase\n * as per RFC 2616 section 4.2.\n *\n * @param headers - The headers to process. Can be an instance of `Headers`, a plain object,\n * or `null`. If `null`, an empty object is returned.\n * @returns {HeadersObject} - A normalized headers object with lowercase keys.\n */\nexport function processHeaders(\n headers?: (HeadersObject & HeadersInit) | null | Headers,\n): HeadersObject {\n if (!headers) {\n return {};\n }\n\n const headersObject: HeadersObject = {};\n\n // Normalize keys to lowercase as per RFC 2616 4.2\n // https://datatracker.ietf.org/doc/html/rfc2616#section-4.2\n if (headers instanceof Headers) {\n headers.forEach((value, key) => {\n headersObject[key.toLowerCase()] = value;\n });\n } else if (isObject(headers)) {\n // Handle plain object — use for...in to avoid Object.entries() allocation\n for (const key in headers) {\n if (Object.prototype.hasOwnProperty.call(headers, key)) {\n headersObject[key.toLowerCase()] = headers[key];\n }\n }\n }\n\n return headersObject;\n}\n\n/**\n * Determines if the current environment is a browser.\n *\n * @returns {boolean} - True if running in a browser environment, false otherwise.\n */\nexport function isBrowser(): boolean {\n // For node and some mobile frameworks like React Native, `add/removeEventListener` doesn't exist on window!\n return (\n typeof window !== UNDEFINED && typeof window.addEventListener === FUNCTION\n );\n}\n\n/**\n * Creates an abort/timeout error compatible with all JS runtimes.\n * Falls back to a plain Error with the correct `name` when DOMException is unavailable (e.g. React Native).\n *\n * @param {string} message - The error message.\n * @param {string} name - The error name (e.g. 'AbortError', 'TimeoutError').\n * @returns {DOMException | Error} - An error object with the specified name.\n */\nexport function createAbortError(\n message: string,\n name: string,\n): DOMException | Error {\n if (typeof DOMException !== UNDEFINED) {\n return new DOMException(message, name);\n }\n\n const error = new Error(message);\n error.name = name;\n\n return error;\n}\n\n/**\n * Detects if the user is on a slow network connection\n * @returns {boolean} True if connection is slow, false otherwise or if detection unavailable\n */\nexport const isSlowConnection = (): boolean => {\n const conn = typeof navigator !== UNDEFINED && (navigator as any).connection;\n\n return conn && ['slow-2g', '2g', '3g'].includes(conn.effectiveType);\n};\n","import { FUNCTION } from './constants';\nimport type { InterceptorFunction } from './types/interceptor-manager';\nimport { isObject } from './utils';\n\n/**\n * Applies interceptors to the object. Interceptors can be a single function or an array of functions.\n *\n * @template T - Type of the object.\n * @template Args - Type of additional arguments.\n * @template I - Type of interceptors.\n *\n * @param {InterceptorFunction | InterceptorFunction[]} [interceptors] - Interceptor function(s).\n * @param {T} data - The data object to process.\n * @param {...Args} args - Additional arguments to pass to interceptors.\n *\n * @returns {Promise} - Nothing as the function is non-idempotent.\n */\nexport async function applyInterceptors<\n T extends object,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n Args extends any[] = any[],\n I = InterceptorFunction | InterceptorFunction[],\n>(interceptors: I | undefined, data: T, ...args: Args): Promise {\n if (!interceptors) {\n return;\n }\n\n if (typeof interceptors === FUNCTION) {\n const value = await (interceptors as InterceptorFunction)(\n data,\n ...args,\n );\n\n if (value && isObject(data) && isObject(value)) {\n Object.assign(data, value);\n }\n } else if (Array.isArray(interceptors)) {\n for (const interceptor of interceptors) {\n const value = await interceptor(data, ...args);\n\n if (value && isObject(data) && isObject(value)) {\n Object.assign(data, value);\n }\n }\n }\n}\n","import type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '../types';\n\n/**\n * This is a base error class\n */\nexport class FetchError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n> extends Error {\n status: number;\n statusText: string;\n config: RequestConfig;\n isCancelled: boolean;\n\n constructor(\n message: string,\n public request: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n public response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n ) {\n super(message);\n\n this.name = 'FetchError';\n this.status = response ? response.status : 0;\n this.statusText = response ? response.statusText : '';\n this.config = request;\n this.isCancelled = false;\n }\n}\n","import { FetchError } from './fetch-error';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '../types';\n\nexport class ResponseError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n> extends FetchError {\n constructor(\n message: string,\n request: RequestConfig,\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n ) {\n super(message, request, response);\n\n this.name = 'ResponseError';\n }\n}\n","/**\n * @module timeout-wheel\n * @description\n * Ultra-minimal timing wheel implementation optimized for max performance & many requests.\n * For most of the cases it's 4-100x faster than setTimeout and setInterval alone.\n * Provides efficient scheduling and cancellation of timeouts using a circular array.\n *\n * Position 0 → 1 → 2 → ... → 599 → 0 → 1 → 2 ...\n * Time: 0s 1s 2s 599s 600s 601s 602s\n *\n * The timing wheel consists of 600 slots (one per second for 10 min).\n * Each slot contains a list of timeout items, each associated with a unique key and callback.\n * Timeouts are scheduled by placing them in the appropriate slot based on the delay in seconds.\n * The wheel advances every second, executing and removing callbacks as their timeouts expire.\n * Defaults to setTimeout if the delay exceeds 10 minutes or is not divisible by 1000.\n *\n * @remarks\n * - Designed for minimal footprint and simplicity.\n * - Only supports second-level granularity (minimum timeout: 1 second).\n * - Automatically stops the internal timer when no timeouts remain.\n */\n\nimport { noop } from './utils';\n\ntype TimeoutCallback = () => unknown | Promise;\ntype TimeoutItem = [string, TimeoutCallback]; // [key, callback]\n\nconst WHEEL_SIZE = 600; // 600 slots for 10 min (1 slot per second)\nconst SECOND = 1000; // 1 second in milliseconds\nconst MAX_WHEEL_MS = WHEEL_SIZE * SECOND;\nconst wheel: TimeoutItem[][] = Array(WHEEL_SIZE)\n .fill(0)\n .map(() => []);\n\nconst keyMap = new Map();\nlet position = 0;\nlet timer: NodeJS.Timeout | null = null;\n\nconst handleCallback = ([key, callback]: TimeoutItem): void => {\n keyMap.delete(key);\n\n try {\n const result = callback();\n if (result && result instanceof Promise) {\n // Silently ignore async errors to prevent wheel from stopping\n result.catch(noop);\n }\n } catch {\n // Ignore callback errors to prevent wheel from stopping\n }\n};\n\nexport const addTimeout = (\n key: string,\n cb: TimeoutCallback,\n ms: number,\n): void => {\n removeTimeout(key);\n\n // Fallback to setTimeout if wheel size is exceeded, ms is sub-second, or ms is not divisible by SECOND\n if (ms < SECOND || ms > MAX_WHEEL_MS || ms % SECOND !== 0) {\n keyMap.set(key, [setTimeout(handleCallback.bind(null, [key, cb]), ms)]); // Store timeout ID instead of slot\n\n return;\n }\n\n // No need for Math.ceil here since ms is guaranteed by modulo above\n const seconds = ms / SECOND;\n const slot = (position + seconds) % WHEEL_SIZE;\n\n wheel[slot].push([key, cb]);\n keyMap.set(key, slot);\n\n if (!timer) {\n timer = setInterval(() => {\n position = (position + 1) % WHEEL_SIZE;\n const slot = wheel[position];\n\n // Use slot.length directly (not cached) so mid-iteration mutations\n // from callbacks (e.g. removeTimeout) are handled correctly\n for (let i = 0; i < slot.length; i++) {\n handleCallback(slot[i]);\n }\n\n slot.length = 0; // Reuse array, avoid GC allocation\n\n if (!keyMap.size && timer) {\n clearInterval(timer);\n timer = null;\n }\n }, SECOND);\n }\n};\n\nexport const removeTimeout = (key: string): void => {\n const slotOrTimeout = keyMap.get(key);\n\n if (slotOrTimeout !== undefined) {\n // It's a Timeout object from setTimeout\n if (Array.isArray(slotOrTimeout)) {\n clearTimeout(slotOrTimeout[0]);\n } else {\n const slotArr = wheel[slotOrTimeout];\n const idx = slotArr.findIndex(([k]) => k === key);\n\n if (idx !== -1) {\n slotArr.splice(idx, 1);\n }\n }\n\n keyMap.delete(key);\n\n if (!keyMap.size && timer) {\n clearInterval(timer);\n timer = null;\n }\n }\n};\n\nexport const clearAllTimeouts = () => {\n // Clear native setTimeout timeouts first!\n keyMap.forEach((value) => {\n if (Array.isArray(value)) {\n clearTimeout(value[0]);\n }\n });\n\n if (timer) {\n clearInterval(timer);\n timer = null;\n }\n\n keyMap.clear();\n\n for (let i = 0; i < WHEEL_SIZE; i++) {\n wheel[i].length = 0;\n }\n\n position = 0;\n};\n","/**\n * @module inflight-manager\n *\n * Manages in-flight asynchronous requests using unique keys to enable deduplication and cancellation.\n *\n * Provides utilities for:\n * - Deduplication of requests within a configurable time window (`dedupeTime`)\n * - Timeout management and automatic request abortion\n * - AbortController lifecycle and cancellation logic\n * - Concurrency control and request state tracking\n * - In-flight promise deduplication to prevent duplicate network calls\n *\n * @remarks\n * - Requests with the same key within the deduplication interval share the same AbortController and in-flight promise.\n * - Supports cancellation of previous requests when a new one with the same key is issued, if `isCancellable` is enabled.\n * - Timeout logic ensures requests are aborted after a specified duration, if enabled.\n * - Internal queue state is managed via a Map, keyed by request identifier.\n * - Polled requests are also marked as \"in-flight\" to prevent duplicate requests.\n */\n\nimport { ABORT_ERROR, TIMEOUT_ERROR } from './constants';\nimport { addTimeout, removeTimeout } from './timeout-wheel';\nimport { createAbortError, timeNow } from './utils';\n\nexport type InFlightItem = [\n AbortController, // AbortController for the request\n boolean, // Whether timeout is enabled for the request\n number, // Timestamp when the request was marked in-flight\n boolean, // isCancellable - whether the request can be cancelled\n Promise | null, // Optional in-flight promise for deduplication\n];\n\nconst inFlight: Map = new Map();\n\n/**\n * Adds a request to the queue if it's not already being processed within the dedupeTime interval.\n *\n * @param {string | null} key - Unique key for the request (e.g. cache key).\n * @param {string} url - The request URL (for error messages/timeouts).\n * @param {number} timeout - Timeout in milliseconds for the request.\n * @param {number} dedupeTime - Deduplication time in milliseconds.\n * @param {boolean} isCancellable - If true, then the previous request with same configuration should be aborted.\n * @param {boolean} isTimeoutEnabled - Whether timeout is enabled.\n * @returns {AbortController} - A promise that resolves to an AbortController.\n */\nexport function markInFlight(\n key: string | null,\n url: string,\n timeout: number | undefined,\n dedupeTime: number,\n isCancellable: boolean,\n isTimeoutEnabled: boolean,\n): AbortController {\n if (!key) {\n return new AbortController();\n }\n\n const now = timeNow();\n const item = inFlight.get(key);\n let prevPromise: Promise | null = null;\n\n // Previous request is in-flight, check if we can reuse it\n if (item) {\n const prevController = item[0];\n const prevIsCancellable = item[3];\n\n // If the request is already in the queue and within the dedupeTime, reuse the existing controller\n if (\n !prevIsCancellable &&\n now - item[2] < dedupeTime &&\n !prevController.signal.aborted\n ) {\n return prevController;\n }\n\n // If the request is too old, remove it and proceed to add a new one\n // Abort previous request, if applicable, and continue as usual\n if (prevIsCancellable) {\n prevController.abort(\n createAbortError('Aborted due to new request', ABORT_ERROR),\n );\n }\n\n removeTimeout(key);\n prevPromise = item[4];\n }\n\n const controller = new AbortController();\n\n inFlight.set(key, [\n controller,\n isTimeoutEnabled,\n now,\n isCancellable,\n prevPromise,\n ]);\n\n if (isTimeoutEnabled) {\n addTimeout(\n key,\n () => {\n abortRequest(\n key,\n createAbortError(url + ' aborted due to timeout', TIMEOUT_ERROR),\n );\n },\n timeout as number,\n );\n }\n\n return controller;\n}\n\n/**\n * Removes a request from the queue and clears its timeout.\n *\n * @param key - Unique key for the request.\n * @param {boolean} error - Optional error to abort the request with. If null, the request is simply removed but no abort sent.\n * @returns {Promise} - A promise that resolves when the request is aborted and removed.\n */\nexport async function abortRequest(\n key: string | null,\n error: DOMException | Error | null | string = null,\n): Promise {\n // If the key is not in the queue, there's nothing to remove\n if (key) {\n const item = inFlight.get(key);\n\n if (item) {\n // If the request is not yet aborted, abort it with the provided error\n if (error) {\n const controller = item[0];\n controller.abort(error);\n }\n\n removeInFlight(key);\n }\n }\n}\n\n/**\n * Removes a request from the in-flight queue without aborting or clearing timeout.\n *\n * @param key - Unique key for the request.\n */\nexport function removeInFlight(key: string | null): void {\n removeTimeout(key!);\n inFlight.delete(key!);\n}\n\n/**\n * Gets the AbortController for a request key.\n *\n * @param key - Unique key for the request.\n * @returns {AbortController | undefined} - The AbortController or undefined.\n */\nexport async function getController(\n key: string,\n): Promise {\n const item = inFlight.get(key);\n\n return item?.[0];\n}\n\n/**\n * Adds helpers for in-flight promise deduplication.\n *\n * @param key - Unique key for the request.\n * @param promise - The promise to store.\n */\nexport function setInFlightPromise(\n key: string,\n promise: Promise,\n): void {\n const item = inFlight.get(key);\n if (item) {\n // store the promise at index 4 — item is already the Map's reference, no need to re-set\n item[4] = promise;\n }\n}\n\n/**\n * Retrieves the in-flight promise for a request key if it exists and is within the dedupeTime interval.\n *\n * @param key - Unique key for the request.\n * @param dedupeTime - Deduplication time in milliseconds.\n * @returns {Promise | null} - The in-flight promise or null.\n */\nexport function getInFlightPromise(\n key: string | null,\n dedupeTime: number,\n): Promise | null {\n if (!key) {\n return null;\n }\n\n const prevReq = inFlight.get(key);\n\n if (\n prevReq &&\n // If the request is in-flight and has a promise\n prevReq[4] &&\n // If the request is cancellable, we will not reuse it\n !prevReq[3] &&\n // If the request is within the dedupeTime\n timeNow() - prevReq[2] < dedupeTime &&\n // If one request is cancelled, ALL deduped requests get cancelled\n !prevReq[0].signal.aborted\n ) {\n return prevReq[4] as Promise;\n }\n\n return null;\n}\n","const PRIME_MULTIPLIER = 31;\n\n/**\n * Computes a hash value for a given string using the variant of djb2 hash function.\n * This hash function is non-cryptographic and designed for speed.\n * @author Daniel J. Bernstein (of djb2)\n *\n * @param str Input string to hash\n * @returns {string} Hash\n */\nexport function hash(str: string): string {\n let hash = 0;\n\n for (let i = 0, len = str.length; i < len; i++) {\n const char = str.charCodeAt(i);\n hash = (hash * PRIME_MULTIPLIER + char) | 0;\n }\n\n return String(hash);\n}\n","/**\n * @module revalidator-manager\n *\n * Provides utilities for managing cache revalidation functions, including:\n * - Registering and unregistering revalidators for specific cache keys.\n * - Triggering revalidation for a given key.\n * - Enabling or disabling automatic revalidation on window focus and if user comes back online for specific keys.\n * - Attaching and removing global focus and online event handlers to trigger revalidation.\n *\n * Revalidators are functions that can be registered to revalidate cache entries when needed.\n * They are typically used to refresh data in the cache when the window gains focus or when specific actions occur.\n * @performance O(1) lookup by key makes it blazing fast to register, unregister, and revalidate cache entries.\n * - Designed for high performance: minimizes unnecessary re-renders and leverages fast cache key generation.\n * - Integrates with a global cache and pub/sub system for efficient state updates across contexts.\n * - Handles automatic revalidation, deduplication, retries, and cache management out of the box.\n * @remarks\n * - Designed to be used in various environments (Deno, Node.js, Bun, Browser, etc.) to ensure cache consistency and freshness.\n */\nimport { addTimeout, removeTimeout } from './timeout-wheel';\nimport { FetchResponse } from './types';\nimport { isBrowser, noop, timeNow } from './utils';\n\nexport type RevalidatorFn = (\n isStaleRevalidation?: boolean,\n) => Promise;\n\ntype EventType = 'focus' | 'online';\n\ntype RevalidatorEntry = [\n RevalidatorFn, // main revalidator\n number, // lastUsed\n number, // ttl\n number?, // staleTime\n RevalidatorFn?, // bgRevalidator\n boolean?, // refetchOnFocus\n boolean?, // refetchOnReconnect\n];\n\nconst DEFAULT_TTL = 3 * 60 * 1000; // Default TTL of 3 minutes\nconst revalidators = new Map();\n\n/**\n * Stores cleanup functions for active event handlers (browser or custom providers).\n * Each entry removes the corresponding event listener when called.\n * @remarks\n * - Improves performance by reducing the number of event listeners.\n * - Enables efficient O(1) lookup and management of event handlers for revalidation.\n */\nconst eventHandlers = new Map void>();\n\n/** Subscribe to an event and return a cleanup function */\nexport type EventProvider = (handler: () => void) => () => void;\n\nconst customEventProviders = new Map();\n\n/**\n * Registers a custom event provider for 'focus' or 'online' events.\n * Useful for non-browser environments like React Native.\n *\n * @param type - The event type ('focus' or 'online').\n * @param provider - A function that subscribes to the event and returns a cleanup function.\n */\nexport function setEventProvider(\n type: EventType,\n provider: EventProvider,\n): void {\n customEventProviders.set(type, provider);\n\n // Re-register if already active\n if (eventHandlers.has(type)) {\n removeEventHandler(type);\n addEventHandler(type);\n }\n}\n\n/**\n * Triggers revalidation for all registered entries based on the given event type.\n * For example, if it's a 'focus' event, it will revalidate entries that have the `refetchOnFocus` flag set.\n * Updates the timestamp and invokes the revalidator function for each applicable entry.\n *\n * @param type - The type of event that caused the revalidation (e.g., 'focus' or 'online').\n * @param isStaleRevalidation - If `true`, uses background revalidator and doesn't mark as in-flight.\n */\nexport function revalidateAll(\n type: EventType,\n isStaleRevalidation: boolean = true,\n) {\n const flagIndex = type === 'focus' ? 5 : 6;\n const now = timeNow();\n\n revalidators.forEach((entry) => {\n if (!entry[flagIndex]) {\n return;\n }\n\n entry[1] = now;\n\n // If it's a stale revalidation, use the background revalidator function\n const revalidator = isStaleRevalidation ? entry[4] : entry[0];\n\n if (revalidator) {\n Promise.resolve(revalidator(isStaleRevalidation)).catch(noop);\n }\n });\n}\n\n/**\n * Revalidates an entry by executing the registered revalidation function.\n *\n * @param key The unique identifier for the cache entry to revalidate. If `null`, no revalidation occurs.\n * @param isStaleRevalidation - If `true`, it does not mark revalidated requests as in-flight.\n * @returns A promise that resolves to the result of the revalidator function, or\n * `null` if no key or revalidator is found, or a `FetchResponse` if applicable.\n */\nexport async function revalidate(\n key: string | null,\n isStaleRevalidation: boolean = false,\n): Promise {\n // If no key is provided, no revalidation occurs\n if (!key) {\n return null;\n }\n\n const entry = revalidators.get(key);\n\n if (entry) {\n // Update only the lastUsed timestamp without resetting the whole array\n entry[1] = timeNow();\n\n const revalidator = isStaleRevalidation ? entry[4] : entry[0];\n\n // If no revalidator function is registered, return null\n if (revalidator) {\n return await revalidator(isStaleRevalidation);\n }\n }\n\n // If no revalidator is registered for the key, return null\n return null;\n}\n\n/**\n * Removes all revalidators associated with the specified event type.\n *\n * @param type - The event type whose revalidators should be removed.\n */\nexport function removeRevalidators(type: EventType) {\n removeEventHandler(type);\n\n const flagIndex = type === 'focus' ? 5 : 6;\n\n // Clear all revalidators with this flag\n revalidators.forEach((entry, key) => {\n if (entry[flagIndex]) {\n removeRevalidator(key);\n }\n });\n}\n\n/**\n * Registers a generic revalidation event handler for the specified event type.\n * Supports browser window events and custom event providers (e.g. for React Native).\n * Ensures the handler is only added once.\n *\n * @param event - The type of event to listen for (e.g., 'focus', 'online').\n */\nfunction addEventHandler(event: EventType) {\n if (eventHandlers.has(event)) {\n return;\n }\n\n const handler = revalidateAll.bind(null, event, true);\n\n // Priority 1: Custom event provider (works in any environment including React Native)\n const customProvider = customEventProviders.get(event);\n\n if (customProvider) {\n const cleanup = customProvider(handler);\n\n eventHandlers.set(event, cleanup);\n\n return;\n }\n\n // Priority 2: Browser window events\n if (isBrowser()) {\n window.addEventListener(event, handler);\n\n eventHandlers.set(event, () => window.removeEventListener(event, handler));\n }\n}\n\n/**\n * Removes the event handler for the specified event type.\n *\n * @param event - The type of event whose handler should be removed.\n */\nfunction removeEventHandler(event: EventType) {\n const cleanup = eventHandlers.get(event);\n\n if (cleanup) {\n cleanup();\n eventHandlers.delete(event);\n }\n}\n\n/**\n * Registers a revalidation functions for a specific cache key.\n *\n * @param {string} key Cache key to utilize\n * @param {RevalidatorFn} revalidatorFn Main revalidation function (marks in-flight requests)\n * @param {number} [ttl] Time to live in milliseconds (default: 3 minutes)\n * @param {number} [staleTime] Time (in seconds) after which the cache entry is considered stale\n * @param {RevalidatorFn} [bgRevalidatorFn] For stale revalidation (does not mark in-flight requests)\n * @param {boolean} [refetchOnFocus] Whether to revalidate on window focus\n * @param {boolean} [refetchOnReconnect] Whether to revalidate on network reconnect\n */\nexport function addRevalidator(\n key: string,\n revalidatorFn: RevalidatorFn, // Main revalidation function (marks in-flight requests)\n ttl?: number,\n staleTime?: number,\n bgRevalidatorFn?: RevalidatorFn, // For stale revalidation (does not mark in-flight requests)\n refetchOnFocus?: boolean,\n refetchOnReconnect?: boolean,\n) {\n const existing = revalidators.get(key);\n\n if (existing) {\n // Update in-place to avoid allocating a new tuple array\n existing[0] = revalidatorFn;\n existing[1] = timeNow();\n existing[2] = ttl ?? DEFAULT_TTL;\n existing[3] = staleTime;\n existing[4] = bgRevalidatorFn;\n existing[5] = refetchOnFocus;\n existing[6] = refetchOnReconnect;\n } else {\n revalidators.set(key, [\n revalidatorFn,\n timeNow(),\n ttl ?? DEFAULT_TTL,\n staleTime,\n bgRevalidatorFn,\n refetchOnFocus,\n refetchOnReconnect,\n ]);\n }\n\n if (refetchOnFocus) {\n addEventHandler('focus');\n }\n\n if (refetchOnReconnect) {\n addEventHandler('online');\n }\n\n if (staleTime) {\n addTimeout('s:' + key, revalidate.bind(null, key, true), staleTime * 1000);\n }\n}\n\nexport function removeRevalidator(key: string) {\n revalidators.delete(key);\n\n // Clean up stale timer\n removeTimeout('s:' + key);\n}\n\n/**\n * Periodically cleans up expired revalidators from the registry.\n * Removes any revalidator whose TTL has expired.\n *\n * @param {number} intervalMs How often to run cleanup (default: 3 minutes)\n * @returns {() => void} A function to stop the periodic cleanup\n */\nexport function startRevalidatorCleanup(\n intervalMs: number = DEFAULT_TTL,\n): () => void {\n const intervalId = setInterval(() => {\n const now = timeNow();\n\n revalidators.forEach(\n ([, lastUsed, ttl, , , refetchOnFocus, refetchOnReconnect], key) => {\n // Skip focus-only or reconnect-only revalidators to keep them alive\n if (refetchOnFocus || refetchOnReconnect) {\n return;\n }\n\n if (ttl > 0 && now - lastUsed > ttl) {\n removeRevalidator(key);\n }\n },\n );\n }, intervalMs);\n\n return () => clearInterval(intervalId);\n}\n","/**\n * Manages a set of listeners (subscribers) for arbitrary string keys, allowing cross-context or cross-component\n * cache updates and synchronization. Provides functions to add, remove, and notify listeners, as well as a\n * convenient subscribe/unsubscribe API.\n *\n * @template T - The type of the response object passed to listeners.\n *\n * @remarks\n * - Listeners are grouped by a string key, which typically represents a cache key or resource identifier.\n * - When `notifySubscribers` is called for a key, all listeners registered for that key are invoked with the provided response.\n * - The `subscribe` function returns an unsubscribe function for convenient cleanup.\n *\n * @example\n * ```ts\n * const unsubscribe = subscribe('user:123', (response) => {\n * // handle updated data\n * });\n * // Later, to stop listening:\n * unsubscribe();\n * ```\n */\n\nimport { noop } from './utils';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Listener = (response: T) => void;\n\nconst listeners = new Map>();\n\nfunction ensureListenerSet(key: string) {\n let set = listeners.get(key);\n\n if (!set) {\n set = new Set();\n listeners.set(key, set);\n }\n\n return set;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function addListener(key: string, fn: Listener): void {\n ensureListenerSet(key).add(fn);\n}\n\nexport function removeListener(key: string, fn: Listener) {\n const set = listeners.get(key);\n\n if (set) {\n set.delete(fn);\n\n // If the set is empty, remove the key from the listeners map\n if (set.size === 0) {\n listeners.delete(key);\n }\n }\n}\n\nexport function notifySubscribers(key: string, response: T) {\n const fns = listeners.get(key);\n\n if (fns) {\n if (fns.size === 1) {\n // If there's only one listener, call it directly\n const fn = fns.values().next().value;\n fn!(response);\n } else {\n fns.forEach((fn) => fn(response));\n }\n }\n}\n\nexport function subscribe(key: string | null, fn: (response: T) => void) {\n if (!key) {\n // No op if no key is provided\n return noop;\n }\n\n addListener(key, fn);\n\n // Return an unsubscribe function\n return () => {\n removeListener(key, fn);\n };\n}\n","import { processHeaders } from './utils';\nimport {\n GET,\n APPLICATION_JSON,\n HEAD,\n STRING,\n CHARSET_UTF_8,\n CONTENT_TYPE,\n REJECT,\n UNDEFINED,\n APPLICATION_CONTENT_TYPE,\n} from './constants';\nimport type {\n HeadersObject,\n Method,\n RequestConfig,\n} from './types/request-handler';\nimport {\n replaceUrlPathParams,\n appendQueryParams,\n isSearchParams,\n isJSONSerializable,\n isSlowConnection,\n isAbsoluteUrl,\n sanitizeObject,\n isObject,\n} from './utils';\n\nconst defaultTimeoutMs = (isSlowConnection() ? 60 : 30) * 1000;\n\nexport const defaultConfig: RequestConfig = {\n strategy: REJECT,\n timeout: defaultTimeoutMs, // 30 seconds (60 on slow connections)\n headers: {\n Accept: APPLICATION_JSON + ', text/plain, */*',\n 'Accept-Encoding': 'gzip, deflate, br',\n },\n retry: {\n delay: defaultTimeoutMs / 30, // 1 second (2 on slow connections)\n maxDelay: defaultTimeoutMs, // 30 seconds (60 on slow connections)\n resetTimeout: true,\n backoff: 1.5,\n\n // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status\n retryOn: [\n 408, // Request Timeout\n 409, // Conflict\n 425, // Too Early\n 429, // Too Many Requests\n 500, // Internal Server Error\n 502, // Bad Gateway\n 503, // Service Unavailable\n 504, // Gateway Timeout\n ],\n },\n};\n\n/**\n * Overwrites the default configuration with the provided custom configuration.\n *\n * @param {Partial} customConfig - The custom configuration to merge into the default config.\n * @returns {Partial} - The updated default configuration object.\n */\nexport function setDefaultConfig(\n customConfig: Partial,\n): Partial {\n const sanitized = sanitizeObject(customConfig);\n\n return mergeConfigs({}, sanitized, defaultConfig);\n}\n\n/**\n * Returns a shallow copy of the current default configuration.\n *\n * @returns {RequestConfig} - The current default configuration.\n */\nexport function getDefaultConfig(): RequestConfig {\n return { ...defaultConfig };\n}\n\n/**\n * Build request configuration from defaults and overrides.\n * This function merges the default configuration with the provided request configuration,\n * @param {string} url - Request url\n * @param {RequestConfig | null | undefined} reqConfig - Request configuration\n * @return {RequestConfig} - Merged request configuration\n */\nexport function buildConfig(\n url: string,\n reqConfig?: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > | null,\n): RequestConfig {\n if (!reqConfig) {\n return buildFetcherConfig(url, getDefaultConfig());\n }\n\n const sanitized = sanitizeObject(reqConfig);\n const merged = mergeConfigs(defaultConfig, sanitized);\n\n return buildFetcherConfig(url, merged);\n}\n\n/**\n * Builds the fetcher configuration by setting the method, body, headers, and URL.\n * It also handles query parameters and path parameters. This fn mutates the passed `requestConfig` object.\n * @param {string} url - The endpoint URL to which the request will be sent.\n * @param {RequestConfig} requestConfig - The request configuration object containing method, body, headers, and other options.\n * @return {RequestConfig} - The modified request configuration object with the URL, method, body, and headers set appropriately.\n **/\nexport function buildFetcherConfig(\n url: string,\n requestConfig: RequestConfig,\n): RequestConfig {\n let method = requestConfig.method as Method;\n method = method ? (method.toUpperCase() as Method) : GET;\n\n let body: RequestConfig['data'] | undefined;\n\n // Only applicable for request methods 'PUT', 'POST', 'DELETE', and 'PATCH'\n if (method !== GET && method !== HEAD) {\n body = requestConfig.body ?? requestConfig.data;\n\n // Automatically stringify request body, if possible and when not dealing with strings\n if (body && typeof body !== STRING && isJSONSerializable(body)) {\n body = JSON.stringify(body);\n }\n }\n\n setContentTypeIfNeeded(requestConfig.headers, body);\n\n // Native fetch compatible settings\n const credentials = requestConfig.withCredentials\n ? 'include'\n : requestConfig.credentials;\n\n // The explicitly passed query params\n const dynamicUrl = replaceUrlPathParams(url, requestConfig.urlPathParams);\n const urlPath = appendQueryParams(dynamicUrl, requestConfig.params);\n const isFullUrl = isAbsoluteUrl(url);\n const baseURL = isFullUrl\n ? ''\n : requestConfig.baseURL || requestConfig.apiUrl || '';\n\n requestConfig.url = baseURL + urlPath;\n requestConfig.method = method;\n requestConfig.credentials = credentials;\n requestConfig.body = body;\n\n return requestConfig;\n}\n\n/**\n * Ensures the `Content-Type` header is set to `application/json; charset=utf-8`\n * if it is not already present and the request method and body meet specific conditions.\n *\n * @param headers - The headers object to modify. Can be an instance of `Headers`\n * or a plain object conforming to `HeadersInit`.\n * @param body - The optional body of the request. If no body is provided and the\n * method is 'GET' or 'HEAD', the function exits without modifying headers.\n */\nfunction setContentTypeIfNeeded(\n headers?: HeadersInit | HeadersObject,\n body?: unknown,\n): void {\n // If no headers are provided, or if the body is not set and the method is PUT or DELETE, do nothing\n if (!headers || !body) {\n return;\n }\n\n // Types that should not have Content-Type set (browser handles these)\n if (\n body instanceof FormData || // Browser automatically sets multipart/form-data with boundary\n (typeof Blob !== UNDEFINED && body instanceof Blob) || // Blob/File already have their own MIME types, don't override\n (typeof File !== UNDEFINED && body instanceof File) ||\n (typeof ReadableStream !== UNDEFINED && body instanceof ReadableStream) // Stream type should be determined by the stream source\n ) {\n return;\n }\n\n let contentTypeValue: string;\n\n if (isSearchParams(body)) {\n contentTypeValue = APPLICATION_CONTENT_TYPE + 'x-www-form-urlencoded';\n } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {\n contentTypeValue = APPLICATION_CONTENT_TYPE + 'octet-stream';\n } else if (isJSONSerializable(body)) {\n contentTypeValue = APPLICATION_JSON + ';' + CHARSET_UTF_8;\n } else {\n // Do not set Content-Type if content is not recognizable\n return;\n }\n\n if (headers instanceof Headers) {\n if (!headers.has(CONTENT_TYPE)) {\n headers.set(CONTENT_TYPE, contentTypeValue);\n }\n } else if (\n isObject(headers) &&\n !Array.isArray(headers) &&\n !headers[CONTENT_TYPE]\n ) {\n headers[CONTENT_TYPE] = contentTypeValue;\n }\n}\n\n/**\n * Merges two request configurations, applying overrides from the second config to the first.\n * Handles special merging for nested properties like 'retry' and 'headers' (deep merge),\n * and concatenates interceptor arrays for 'onRequest', 'onResponse', and 'onError'.\n * If a target config is provided, it mutates that object; otherwise, creates a new one.\n *\n * @param {RequestConfig} baseConfig - The base configuration object to merge from.\n * @param {RequestConfig} overrideConfig - The override configuration object to apply on top of the base.\n * @param {RequestConfig} [targetConfig={}] - Optional target configuration object to merge into (mutated in place).\n * @returns {RequestConfig} The merged configuration object.\n *\n * @example\n * const base = { timeout: 5000, headers: { 'Accept': 'application/json' } };\n * const override = { timeout: 10000, headers: { 'Authorization': 'Bearer token' } };\n * const merged = mergeConfigs(base, override);\n * // Result: { timeout: 10000, headers: { Accept: 'application/json', Authorization: 'Bearer token' } }\n */\nexport function mergeConfigs(\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n targetConfig: RequestConfig = {},\n): RequestConfig {\n Object.assign(targetConfig, baseConfig, overrideConfig);\n\n // Ensure that retry and headers are merged correctly\n mergeConfig('retry', baseConfig, overrideConfig, targetConfig);\n mergeConfig('headers', baseConfig, overrideConfig, targetConfig);\n\n // Merge interceptors efficiently\n mergeInterceptors('onRequest', baseConfig, overrideConfig, targetConfig);\n mergeInterceptors('onResponse', baseConfig, overrideConfig, targetConfig);\n mergeInterceptors('onError', baseConfig, overrideConfig, targetConfig);\n\n return targetConfig;\n}\n\n/**\n * Efficiently merges interceptor functions from base and new configs\n */\nfunction mergeInterceptors<\n K extends 'onRequest' | 'onResponse' | 'onError' | 'onRetry',\n>(\n property: K,\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n targetConfig: RequestConfig,\n): void {\n const baseInterceptor = baseConfig[property];\n const newInterceptor = overrideConfig[property];\n\n if (!baseInterceptor && !newInterceptor) {\n return;\n }\n\n if (!baseInterceptor) {\n targetConfig[property] = newInterceptor;\n return;\n }\n\n if (!newInterceptor) {\n targetConfig[property] = baseInterceptor;\n return;\n }\n\n const baseArr = Array.isArray(baseInterceptor)\n ? baseInterceptor\n : [baseInterceptor];\n const newArr = Array.isArray(newInterceptor)\n ? newInterceptor\n : [newInterceptor];\n\n // This is the only LIFO interceptor, so we apply it after the response is prepared\n targetConfig[property] =\n property === 'onResponse' ? newArr.concat(baseArr) : baseArr.concat(newArr);\n}\n\n/**\n * Merges the specified property from the base configuration and the override configuration into the target configuration.\n *\n * @param {K} property - The property key to merge from the base and override configurations. Must be a key of RequestConfig.\n * @param {RequestConfig} baseConfig - The base configuration object that provides default values.\n * @param {RequestConfig} overrideConfig - The override configuration object that contains user-specific settings to merge.\n * @param {RequestConfig} targetConfig - The configuration object that will receive the merged properties.\n */\nexport function mergeConfig(\n property: K,\n baseConfig: RequestConfig,\n overrideConfig: RequestConfig,\n targetConfig: RequestConfig,\n): void {\n if (overrideConfig[property]) {\n const base = baseConfig[property];\n const override = overrideConfig[property];\n\n // Handle Headers instances which don't expose entries as own enumerable properties\n if (\n property === 'headers' &&\n ((base as Headers | (HeadersObject & HeadersInit)) instanceof Headers ||\n (override as Headers | (HeadersObject & HeadersInit)) instanceof\n Headers)\n ) {\n const baseNormalized = processHeaders(base);\n const overrideNormalized = processHeaders(override);\n targetConfig[property] = {\n ...baseNormalized,\n ...overrideNormalized,\n } as RequestConfig[K];\n } else {\n targetConfig[property] = {\n ...base,\n ...override,\n };\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { hash } from './hash';\nimport type {\n CacheKeyFunction,\n DefaultResponse,\n FetchResponse,\n MutationSettings,\n RequestConfig,\n} from './types/request-handler';\nimport type { CacheEntry } from './types/cache-manager';\nimport { GET, STRING, UNDEFINED } from './constants';\nimport { isObject, sanitizeObject, sortObject, timeNow } from './utils';\nimport { revalidate } from './revalidator-manager';\nimport { notifySubscribers } from './pubsub-manager';\nimport type { DefaultPayload, DefaultParams, DefaultUrlParams } from './types';\nimport { removeInFlight } from './inflight-manager';\nimport { addTimeout } from './timeout-wheel';\nimport { defaultConfig } from './config-handler';\nimport { processHeaders } from './utils';\n\nexport const IMMEDIATE_DISCARD_CACHE_TIME = 0; // Use it for cache entries that need to be persistent until unused by components or manually deleted\n\nconst _cache = new Map>();\nconst DELIMITER = '|';\nconst MIN_LENGTH_TO_HASH = 64;\nconst CACHE_KEY_SANITIZE_PATTERN = /[^\\w\\-_|/:@.?=&~%#]/g;\nconst CACHE_KEY_NEEDS_SANITIZE = /[^\\w\\-_|/:@.?=&~%#]/; // Non-global for fast test\n\n/**\n * Headers that may affect HTTP response content and should be included in cache key generation.\n * All header names must be lowercase to match normalized request headers.\n */\nconst CACHE_KEY_HEADER_WHITELIST = new Set([\n // Content negotiation\n 'accept', // Affects response format (e.g. JSON, HTML)\n 'accept-language', // Affects localization of the response\n 'accept-encoding', // Affects response compression (e.g. gzip, br)\n\n // Authentication\n 'authorization', // Affects access to protected resources\n\n // Request body metadata\n 'content-type', // Affects how the request body is interpreted\n\n // Optional headers\n 'referer', // May influence behavior in some APIs\n 'origin', // Relevant in CORS or tenant-specific APIs\n 'user-agent', // Included only for reason if server returns client-specific content\n\n // Cookies — only if server uses session-based responses\n 'cookie', // Can fragment cache heavily; use only if necessary\n\n // Custom headers that may affect response content\n 'x-api-key', // Token-based access, often affects authorization\n 'x-requested-with', // AJAX requests (used historically for distinguishing frontend calls)\n 'x-client-id', // Per-client/partner identity; often used in multi-tenant APIs\n 'x-tenant-id', // Multi-tenant segmentation; often changes response per tenant\n 'x-user-id', // Explicit user context (less common, but may exist)\n\n 'x-app-version', // Used for version-specific behavior (e.g. mobile apps)\n 'x-feature-flag', // Controls feature rollout behavior server-side\n 'x-device-id', // Used when response varies per device/app instance\n 'x-platform', // e.g. 'ios', 'android', 'web' — used in apps that serve different content\n\n 'x-session-id', // Only if backend uses it to affect the response directly (rare)\n 'x-locale', // Sometimes used in addition to or instead of `accept-language`\n]);\n\n/**\n * Generates a unique cache key for a given URL and fetch options, ensuring that key factors\n * like method, headers, body, and other options are included in the cache key.\n * Headers and other objects are sorted by key to ensure consistent cache keys.\n *\n * @param {RequestConfig} config - The fetch options that may affect the request. The most important are:\n * @property {string} [method=\"GET\"] - The HTTP method (GET, POST, etc.).\n * @property {HeadersInit} [headers={}] - The request headers.\n * @property {BodyInit | null} [body=\"\"] - The body of the request (only for methods like POST, PUT).\n * @property {RequestCredentials} [credentials=\"same-origin\"] - Whether to include credentials (include, same-origin, omit).\n * @property {RequestCache} [cache=\"default\"] - The cache mode (e.g., default, no-store, reload).\n * @returns {string} - A unique cache key string based on the provided options.\n *\n * @example\n * const cacheKey = generateCacheKey({\n * url: 'https://api.example.com/data',\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ name: 'Alice' }),\n * mode: 'cors',\n * credentials: 'include',\n * });\n * console.log(cacheKey);\n */\nexport function generateCacheKey(\n config: RequestConfig,\n cacheKeyCheck = true,\n): string {\n // This is super fast. Effectively a no-op if cacheKey is\n // a string or a function that returns a string.\n const key = config.cacheKey;\n\n if (key && cacheKeyCheck) {\n return typeof key === STRING\n ? (key as string)\n : (key as CacheKeyFunction)(config);\n }\n\n const {\n url = '',\n method = GET,\n headers = null,\n body = null,\n credentials = 'same-origin',\n } = config;\n\n // Sort headers and body + convert sorted to strings for hashing purposes\n // Native serializer is on avg. 3.5x faster than a Fast Hash or FNV-1a\n let headersString = '';\n if (headers) {\n let obj: Record;\n\n if (headers instanceof Headers) {\n obj = processHeaders(headers);\n } else {\n obj = headers as Record;\n }\n\n // Filter headers to only include those that affect request identity\n // Include only headers that affect request identity, not execution behavior\n const keys = Object.keys(obj);\n const len = keys.length;\n\n // Sort keys manually for fastest deterministic output\n if (len > 1) {\n keys.sort();\n }\n\n let str = '';\n for (let i = 0; i < len; ++i) {\n if (CACHE_KEY_HEADER_WHITELIST.has(keys[i].toLowerCase())) {\n str += keys[i] + ':' + obj[keys[i]] + ';';\n }\n }\n\n headersString = hash(str);\n }\n\n // For GET requests, return early with shorter cache key\n if (method === GET) {\n const cacheStr =\n method +\n DELIMITER +\n url +\n DELIMITER +\n credentials +\n DELIMITER +\n headersString;\n\n return CACHE_KEY_NEEDS_SANITIZE.test(cacheStr)\n ? cacheStr.replace(CACHE_KEY_SANITIZE_PATTERN, '')\n : cacheStr;\n }\n\n let bodyString = '';\n if (body) {\n if (typeof body === STRING) {\n bodyString = body.length < MIN_LENGTH_TO_HASH ? body : hash(body); // hash only if large\n } else if (body instanceof FormData) {\n body.forEach((value, key) => {\n // Append key=value and '&' directly to the result\n bodyString += key + '=' + value + '&';\n });\n\n if (bodyString.length > MIN_LENGTH_TO_HASH) {\n bodyString = hash(bodyString);\n }\n } else if (\n (typeof Blob !== UNDEFINED && body instanceof Blob) ||\n (typeof File !== UNDEFINED && body instanceof File)\n ) {\n bodyString = 'BF' + body.size + body.type;\n } else if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) {\n bodyString = 'AB' + body.byteLength;\n } else {\n const o = isObject(body)\n ? JSON.stringify(sortObject(body))\n : String(body);\n\n bodyString = o.length > MIN_LENGTH_TO_HASH ? hash(o) : o;\n }\n }\n\n // Concatenate all key parts into a cache key string\n // Template literals are apparently slower\n const cacheStr =\n method +\n DELIMITER +\n url +\n DELIMITER +\n credentials +\n DELIMITER +\n headersString +\n DELIMITER +\n bodyString;\n\n // Prevent cache poisoning by removal of control chars and unusual characters\n return CACHE_KEY_NEEDS_SANITIZE.test(cacheStr)\n ? cacheStr.replace(CACHE_KEY_SANITIZE_PATTERN, '')\n : cacheStr;\n}\n\n/**\n * Checks if the cache entry is expired based on its timestamp and the expiry time.\n *\n * @param {CacheEntry} entry - The cache entry to check.\n * @returns {boolean} - Returns true if the cache entry is expired, false otherwise.\n */\nfunction isCacheExpired(entry: CacheEntry): boolean {\n // No expiry time means the entry never expires\n if (!entry.expiry) {\n return false;\n }\n\n return timeNow() > entry.expiry;\n}\n\n/**\n * Retrieves a cached response from the internal cache using the provided key.\n *\n * @param key - The unique key identifying the cached entry. If null, returns null.\n * @returns The cached {@link FetchResponse} if found, otherwise null.\n */\nexport function getCacheData<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n key: string | null,\n): FetchResponse | null {\n if (!key) {\n return null;\n }\n\n const entry = _cache.get(key);\n\n return entry ? entry.data : null;\n}\n\n/**\n * Retrieves a cache entry if it exists and is not expired.\n *\n * @param {string} key Cache key to utilize\n * @returns {CacheEntry | null} - The cache entry if it exists and is not expired, null otherwise.\n */\nexport function getCache(\n key: string | null,\n):\n | CacheEntry<\n FetchResponse\n >\n | null\n | undefined {\n return _cache.get(key as string);\n}\n\n/**\n * Sets a new cache entry or updates an existing one, with optional TTL (time-to-live).\n *\n * @param {string} key Cache key to utilize\n * @param {T} data - The data to be cached.\n * @param {number} [ttl] - Optional TTL in seconds. If not provided, the cache entry will not expire.\n * @param {number} [staleTime] - Optional stale time in seconds. If provided, the cache entry will be considered stale after this time.\n */\nexport function setCache(\n key: string,\n data: T,\n ttl?: number,\n staleTime?: number,\n): void {\n if (ttl === 0) {\n deleteCache(key);\n return;\n }\n\n const time = timeNow();\n const ttlMs = ttl ? ttl * 1000 : 0;\n const staleTimeMs = staleTime ? staleTime * 1000 : 0; // Ensure default value for staleTime\n\n _cache.set(key, {\n data,\n time,\n stale: staleTimeMs > 0 ? time + staleTimeMs : undefined, // Use undefined if staleTime is not set\n expiry: ttl === -1 ? undefined : time + ttlMs,\n });\n\n if (ttlMs > 0) {\n addTimeout(\n 'c:' + key,\n () => {\n deleteCache(key, true);\n },\n ttlMs,\n );\n }\n}\n\n/**\n * Invalidates (deletes) a cache entry.\n *\n * @param {string} key Cache key to utilize\n * @param {boolean} [removeExpired=false] - If true, only deletes the cache entry if it is expired or stale.\n */\nexport function deleteCache(key: string, removeExpired: boolean = false): void {\n if (removeExpired) {\n const entry = getCache(key);\n\n // If the entry does not exist, or it is neither expired nor stale, do not delete\n if (!entry || !isCacheExpired(entry)) {\n return;\n }\n }\n\n _cache.delete(key);\n}\n\n/**\n * Prunes the cache by removing entries that have expired based on the provided cache time.\n */\nexport function pruneCache(): void {\n _cache.clear();\n}\n\n/**\n * Mutates a cache entry with new data and optionally revalidates it.\n *\n * @param {string | null} key Cache key to utilize. If null, no mutation occurs.\n * @param {ResponseData} newData - The new data to be cached.\n * @param {MutationSettings|undefined} settings - Mutation settings.\n */\nexport async function mutate<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n key: string | null,\n newData: ResponseData,\n settings?: MutationSettings,\n): Promise | null> {\n // If no key is provided, do nothing\n if (!key) {\n return null;\n }\n\n const entry = getCache(\n key,\n );\n\n if (!entry) {\n return null;\n }\n\n const updatedData = isObject(newData) ? sanitizeObject(newData) : newData;\n\n const updatedResponse = {\n ...entry.data,\n data: updatedData,\n };\n\n const updatedEntry = {\n ...entry,\n data: updatedResponse,\n };\n\n _cache.set(key, updatedEntry);\n notifySubscribers(key, updatedResponse);\n\n if (settings && settings.refetch) {\n return await revalidate(key);\n }\n\n return null;\n}\n\n/**\n * Retrieves a cached response if available and valid, otherwise returns null.\n *\n * @template ResponseData - The type of the response data.\n * @template RequestBody - The type of the request body.\n * @template QueryParams - The type of the query parameters.\n * @template PathParams - The type of the path parameters.\n * @param {string | null} cacheKey - The cache key to look up.\n * @param {number | undefined} cacheTime - The maximum time to cache entry.\n * @param {RequestConfig} requestConfig - The fetcher configuration.\n * @returns {FetchResponse | null} - The cached response or null.\n */\nexport function getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n cacheKey: string | null,\n cacheTime: number | undefined,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): FetchResponse | null {\n // If cache key or time is not provided, return null\n if (!cacheKey || cacheTime === undefined || cacheTime === null) {\n return null;\n }\n\n // Check if cache should be bypassed\n const buster = requestConfig.cacheBuster || defaultConfig.cacheBuster;\n if (buster && buster(requestConfig)) {\n return null;\n }\n\n if (requestConfig.cache && requestConfig.cache === 'reload') {\n return null; // Skip cache lookup entirely\n }\n\n // Retrieve the cached entry\n const entry = getCache(\n cacheKey,\n );\n\n if (!entry) {\n return null;\n }\n\n const isExpired = isCacheExpired(entry);\n\n // If completely expired, delete and return null\n if (isExpired) {\n deleteCache(cacheKey);\n return null;\n }\n\n // Return data whether fresh or stale (SWR: serve stale, revalidation is timer-driven)\n return entry.data;\n}\n\n/**\n * Sets or deletes the response cache based on cache settings and notifies subscribers.\n *\n * @param {FetchResponse} output - The response to cache.\n * @param {RequestConfig} requestConfig - The request configuration.\n * @param {boolean} [isError=false] - Whether the response is an error.\n */\nexport function handleResponseCache<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n output: FetchResponse,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n isError: boolean = false,\n): void {\n // It is string as it is called once request is made\n const cacheKey = requestConfig.cacheKey as string;\n\n if (cacheKey) {\n const cacheTime = requestConfig.cacheTime;\n const skipCache = requestConfig.skipCache;\n\n // Fast path: only set cache if cacheTime is positive and not skipping cache\n if (\n cacheTime &&\n (!isError || requestConfig.cacheErrors) &&\n !(skipCache && skipCache(output, requestConfig))\n ) {\n setCache(cacheKey, output, cacheTime, requestConfig.staleTime);\n }\n\n notifySubscribers(cacheKey, output);\n removeInFlight(cacheKey);\n\n const prevCacheKey = requestConfig._prevKey;\n\n if (prevCacheKey) {\n removeInFlight(prevCacheKey);\n }\n }\n}\n","/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { mutate } from './cache-manager';\nimport {\n APPLICATION_CONTENT_TYPE,\n APPLICATION_JSON,\n CONTENT_TYPE,\n FUNCTION,\n OBJECT,\n STRING,\n} from './constants';\nimport {\n DefaultResponse,\n FetchResponse,\n RequestConfig,\n ResponseError,\n DefaultParams,\n DefaultUrlParams,\n DefaultPayload,\n} from './types';\nimport { flattenData, isObject, processHeaders } from './utils';\n\n/**\n * Parses the response data based on the Content-Type header.\n *\n * @param response - The Response object to parse.\n * @returns A Promise that resolves to the parsed data.\n */\nexport async function parseResponseData<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n response: FetchResponse,\n): Promise {\n // Bail early if response is null or undefined\n if (!response) {\n return null;\n }\n\n // Get the content-type header once\n let contentType = (response as Response).headers?.get(CONTENT_TYPE);\n\n if (contentType) {\n // Lowercase and trim for consistent matching\n contentType = contentType.toLowerCase().trim();\n } else {\n contentType = '';\n }\n\n // Split for mime type without charset\n const mimeType = contentType.split(';', 1)[0];\n\n let data;\n\n try {\n if (mimeType.includes(APPLICATION_JSON) || mimeType.includes('+json')) {\n data = await response.json(); // Parse JSON response\n } else if (\n (mimeType.includes('multipart/form-data') || // Parse as FormData\n mimeType.includes(\n APPLICATION_CONTENT_TYPE + 'x-www-form-urlencoded', // Handle URL-encoded forms\n )) &&\n typeof response.formData === FUNCTION\n ) {\n data = await response.formData();\n } else if (\n mimeType.includes(APPLICATION_CONTENT_TYPE + 'octet-stream') &&\n typeof response.blob === FUNCTION\n ) {\n data = await response.blob(); // Parse as blob\n } else {\n data = await response.text();\n\n if (typeof data === STRING) {\n const trimmed = data.trim();\n if (\n (trimmed.startsWith('{') && trimmed.endsWith('}')) ||\n (trimmed.startsWith('[') && trimmed.endsWith(']'))\n ) {\n try {\n data = JSON.parse(trimmed);\n } catch {\n // leave as text if parsing fails\n }\n }\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (_error) {\n // Parsing failed, fallback to null\n data = null;\n }\n\n return data;\n}\n\n/**\n * Prepare response object with additional information.\n *\n * @param Response. It may be \"null\" in case of request being aborted.\n * @param {RequestConfig} config - Request config\n * @param error - whether the response is erroneous\n * @returns {FetchResponse} Response data\n */\nexport const prepareResponse = <\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n config: RequestConfig,\n error: ResponseError<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null = null,\n): FetchResponse => {\n const defaultResponse = config.defaultResponse;\n const cacheKey = config.cacheKey;\n const mutatator = mutate.bind(null, cacheKey as string) as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >['mutate'];\n\n // This may happen when request is cancelled.\n if (!response) {\n return {\n ok: false,\n // Enhance the response with extra information\n error,\n data: defaultResponse ?? null,\n headers: null,\n config,\n mutate: mutatator,\n isFetching: false,\n isSuccess: false,\n isError: true,\n } as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }\n\n const isNativeResponse =\n typeof Response === FUNCTION && response instanceof Response;\n\n let data = response.data;\n\n // Set the default response if the provided data is an empty object\n if (\n defaultResponse !== undefined &&\n (data === undefined ||\n data === null ||\n (typeof data === OBJECT && Object.keys(data).length === 0))\n ) {\n response.data = data = defaultResponse;\n }\n\n if (config.flattenResponse) {\n response.data = data = flattenData(data);\n }\n\n if (config.select) {\n response.data = data = config.select(data);\n }\n\n const headers = processHeaders(response.headers);\n\n // Native fetch Response extended by extra information\n if (isNativeResponse) {\n return {\n body: response.body,\n bodyUsed: response.bodyUsed,\n ok: response.ok,\n redirected: response.redirected,\n type: response.type,\n url: response.url,\n status: response.status,\n statusText: response.statusText,\n\n // Convert methods to use arrow functions to preserve correct return types\n blob: () => response.blob(),\n json: () => response.json(),\n text: () => response.text(),\n clone: () => response.clone(),\n arrayBuffer: () => response.arrayBuffer(),\n formData: () => response.formData(),\n bytes: () => response.bytes(),\n\n // Enhance the response with extra information\n error,\n data,\n headers,\n config,\n mutate: mutatator,\n isFetching: false,\n isSuccess: response.ok && !error,\n isError: !!error,\n };\n }\n\n // If it's a custom fetcher, and it does not return any Response instance, it may have its own internal handler\n if (isObject(response)) {\n response.error = error;\n response.headers = headers;\n response.isFetching = false;\n response.mutate = mutatator;\n response.isSuccess = response.ok && !error;\n response.isError = !!error;\n }\n\n return response;\n};\n","import { applyInterceptors } from './interceptor-manager';\nimport type { FetchResponse, RetryConfig, RetryFunction } from './types';\nimport { delayInvocation, timeNow } from './utils';\nimport { generateCacheKey } from './cache-manager';\n\nfunction getMsFromHttpDate(dateString: string): number | null {\n const ms = Date.parse(dateString) - timeNow();\n\n if (!isNaN(ms)) {\n return Math.max(0, Math.floor(ms));\n }\n return null;\n}\n\n/**\n * Calculates the number of milliseconds to wait before retrying a request,\n * based on the `Retry-After` HTTP header in the provided response.\n *\n * The function supports both numeric (seconds) and HTTP-date formats for the `Retry-After` header.\n * - If the header is a number, it is interpreted as seconds and converted to milliseconds.\n * - If the header is a date, the function calculates the difference between the date and the current time.\n *\n * @param extendedResponse - The response object containing headers, or `null`.\n * @returns The number of milliseconds to wait before retrying, or `null` if the header is not present or invalid.\n */\nexport function getRetryAfterMs(\n extendedResponse: FetchResponse | null,\n): number | null {\n if (!extendedResponse) {\n return null;\n }\n\n const headers = extendedResponse.headers || {};\n const retryAfter = headers['retry-after'];\n\n if (retryAfter) {\n // Try parsing as seconds\n const seconds = Number(retryAfter);\n\n if (!isNaN(seconds) && seconds >= 0) {\n return seconds * 1000;\n }\n\n const ms = getMsFromHttpDate(retryAfter);\n\n if (ms !== null) {\n return ms;\n }\n }\n\n // Headers are already in lowercase\n const RATELIMIT_RESET = 'ratelimit-reset';\n\n // Unix timestamp when the rate limit window resets (relative to current time)\n // Fallback to checking 'ratelimit-reset-after' OR 'x-ratelimit-reset-after' headers\n const rateLimitResetAfter =\n headers[RATELIMIT_RESET + '-after'] ||\n headers['x-' + RATELIMIT_RESET + '-after'];\n\n if (rateLimitResetAfter) {\n const seconds = Number(rateLimitResetAfter);\n\n if (!isNaN(seconds)) {\n return seconds * 1000;\n }\n }\n\n // ISO 8601 datetime when the rate limit resets\n // Fallback to checking 'ratelimit-reset-at' 'x-ratelimit-reset-at' headers\n const rateLimitResetAt =\n headers[RATELIMIT_RESET + '-at'] || headers['x-' + RATELIMIT_RESET + '-at'];\n\n if (rateLimitResetAt) {\n return getMsFromHttpDate(rateLimitResetAt);\n }\n\n return null;\n}\n\n/**\n * Executes a request function with retry logic according to the provided configuration.\n *\n * The function attempts the request up to the specified number of retries, applying delay and backoff strategies.\n * Retries can be triggered based on response status codes, custom logic, or the presence of a `Retry-After` header.\n * Optionally, an `onRetry` interceptor can be invoked before each retry attempt.\n *\n * @typeParam ResponseData - The type of the response data.\n * @typeParam RequestBody - The type of the request body.\n * @typeParam QueryParams - The type of the query parameters.\n * @typeParam PathParams - The type of the path parameters.\n * @param requestFn - The function that performs the request. Receives `isStaleRevalidation` and `attempt` as arguments.\n * @param config - The retry configuration, including retry count, delay, backoff, retry conditions, and hooks.\n * @returns A promise resolving to the fetch response, or rejecting if all retries are exhausted.\n * @throws Error if the maximum number of retries is exceeded or a non-retriable error occurs.\n */\nexport async function withRetry<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n requestFn: (\n isStaleRevalidation: boolean,\n attempt: number,\n ) => Promise<\n FetchResponse\n >,\n config: RetryConfig,\n): Promise> {\n const {\n retries = 0,\n delay = 0,\n backoff = 1,\n maxDelay,\n retryOn = [],\n shouldRetry,\n } = config;\n\n let attempt = 0;\n let waitTime = delay;\n const maxRetries = retries > 0 ? retries : 0;\n let output: FetchResponse;\n\n while (attempt <= maxRetries) {\n // Subsequent attempts will have output defined, but the first attempt may not.\n // Let's apply onRetry interceptor and regenerate cache key if ot really changes.\n if (attempt > 0 && output!) {\n const cfg = output.config;\n const onRetry = cfg.onRetry;\n\n if (onRetry) {\n await applyInterceptors(onRetry, output, attempt);\n\n // If the key was automatically generated, we need to regenerate it as config may change.\n // We don't detect whether config changed for performance reasons.\n if (cfg._isAutoKey) {\n cfg._prevKey = cfg.cacheKey as string;\n cfg.cacheKey = generateCacheKey(cfg, false);\n }\n }\n }\n\n // Performance optimization: Call the request function with the current attempt number\n // If this is the first attempt, we pass `isStaleRevalidation` as `false`,\n // otherwise we pass `true` to indicate that this is a stale revalidation (no cache hit).\n output = await requestFn(attempt > 0, attempt);\n const error = output.error;\n\n // Check if we should retry based on successful response\n if (!error) {\n if (shouldRetry && attempt < maxRetries) {\n const shouldRetryResult = await shouldRetry(output, attempt);\n\n if (shouldRetryResult) {\n await delayInvocation(waitTime);\n waitTime *= backoff || 1;\n waitTime = Math.min(waitTime, maxDelay || waitTime);\n attempt++;\n continue;\n }\n }\n\n break;\n }\n\n // Determine if we should stop retrying\n const shouldStopRetrying = await getShouldStopRetrying(\n output,\n attempt,\n maxRetries,\n shouldRetry,\n retryOn,\n );\n\n if (shouldStopRetrying) {\n break;\n }\n\n // If we should not stop retrying, continue to the next attempt\n // Handle rate limiting if the error status is 429 (Too Many Requests) or 503 (Service Unavailable)\n if (error.status === 429 || error.status === 503) {\n // Try to extract the \"Retry-After\" value from the response headers\n const retryAfterMs = getRetryAfterMs(output);\n\n // If a valid retry-after value is found, override the wait time before next retry\n if (retryAfterMs !== null) {\n waitTime = retryAfterMs;\n }\n }\n\n await delayInvocation(waitTime);\n waitTime *= backoff || 1;\n waitTime = Math.min(waitTime, maxDelay || waitTime);\n attempt++;\n }\n\n return output!;\n}\n\n/**\n * Determines whether to stop retrying based on the error, current attempt count, and retry configuration.\n *\n * This function checks:\n * - If the maximum number of retries has been reached.\n * - If a custom `shouldRetry` callback is provided, its result is used to decide.\n * - If no custom logic is provided, falls back to checking if the error status is included in the `retryOn` list.\n *\n * @typeParam ResponseData - The type of the response data.\n * @typeParam RequestBody - The type of the request body.\n * @typeParam QueryParams - The type of the query parameters.\n * @typeParam PathParams - The type of the path parameters.\n * @param output - The response object containing the error and request configuration.\n * @param attempt - The current retry attempt number.\n * @param maxRetries - The maximum number of retry attempts allowed.\n * @param shouldRetry - Optional custom function to determine if a retry should occur.\n * @param retryOn - Optional list of HTTP status codes that should trigger a retry.\n * @returns A promise resolving to `true` if retrying should stop, or `false` to continue retrying.\n */\nexport async function getShouldStopRetrying<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n output: FetchResponse,\n attempt: number,\n maxRetries: number,\n shouldRetry?: RetryFunction<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n retryOn: number[] = [],\n): Promise {\n // Safety first: always respect max retries\n // We check retries provided regardless of the shouldRetry being provided so to avoid infinite loops.\n // It is a fail-safe so to prevent excessive retry attempts even if custom retry logic suggests a retry.\n if (attempt === maxRetries) {\n return true;\n }\n\n let customDecision: boolean | null = null;\n\n // Get custom decision if shouldRetry is provided\n if (shouldRetry) {\n const result = await shouldRetry(output, attempt);\n customDecision = result;\n\n // Decision cascade:\n if (customDecision !== null) {\n return !customDecision;\n }\n }\n\n return !(retryOn || []).includes(output.error?.status ?? 0);\n}\n","import type { RequestConfig, FetchResponse } from './types';\nimport { delayInvocation } from './utils';\n\n/**\n * Executes a request function with polling, stopping when shouldStopPolling returns true,\n * pollingInterval is not set, or maxAttempts is reached.\n *\n * @template Output The type of the output returned by the request function.\n * @param requestFn - The function that performs a single request (with retries).\n * @param pollingInterval - Interval in ms between polling attempts.\n * @param shouldStopPolling - Function to determine if polling should stop.\n * @param maxAttempts - Maximum number of polling attempts, default: 0 (unlimited).\n * @param pollingDelay - Delay in ms before each polling attempt, default: 0.\n * @returns The final output from the last request.\n */\nexport async function withPolling<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams,\n>(\n requestFn: (\n isStaleRevalidation?: boolean,\n attempt?: number,\n ) => Promise<\n FetchResponse\n >,\n pollingInterval?: RequestConfig['pollingInterval'],\n shouldStopPolling?: RequestConfig['shouldStopPolling'],\n maxAttempts = 0,\n pollingDelay = 0,\n): Promise> {\n if (!pollingInterval) {\n return requestFn();\n }\n\n let pollingAttempt = 0;\n let output: FetchResponse;\n\n while (maxAttempts === 0 || pollingAttempt < maxAttempts) {\n if (pollingDelay > 0) {\n await delayInvocation(pollingDelay);\n }\n\n output = await requestFn();\n\n pollingAttempt++;\n\n if (\n (maxAttempts > 0 && pollingAttempt >= maxAttempts) ||\n !pollingInterval ||\n (shouldStopPolling && shouldStopPolling(output, pollingAttempt))\n ) {\n break;\n }\n\n await delayInvocation(pollingInterval);\n }\n\n return output!;\n}\n","import type { ResponseError } from './errors/response-error';\nimport type {\n DefaultResponse,\n FetchResponse,\n RequestConfig,\n} from './types/request-handler';\nimport { applyInterceptors } from './interceptor-manager';\nimport { handleResponseCache } from './cache-manager';\nimport { ABORT_ERROR, REJECT } from './constants';\nimport { DefaultParams, DefaultUrlParams, DefaultPayload } from './types';\n\n/**\n * Handles final processing for both success and error responses\n * Applies error interceptors, caching, notifications, and error strategy\n */\nexport async function withErrorHandling<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n isStaleRevalidation: boolean,\n requestFn: (\n isStaleRevalidation: boolean,\n ) => Promise<\n FetchResponse\n >,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): Promise> {\n const output = await requestFn(isStaleRevalidation);\n const error = output.error;\n\n if (!error) {\n // SUCCESS PATH\n handleResponseCache(output, requestConfig);\n\n return output;\n }\n\n // ERROR PATH\n\n if (requestConfig.onError) {\n await applyInterceptors(requestConfig.onError, error);\n }\n\n // Timeouts and request cancellations using AbortController do not throw any errors unless rejectCancelled is true.\n // Only handle the error if the request was not cancelled, or if it was cancelled and rejectCancelled is true.\n const isCancelled = error.isCancelled;\n\n if (!isCancelled && requestConfig.logger) {\n logger(requestConfig, 'FETCH ERROR', error as ResponseError);\n }\n\n // Handle cache and notifications FIRST (before strategy)\n handleResponseCache(output, requestConfig, true);\n\n // handle error strategy as the last part\n const shouldHandleError = !isCancelled || requestConfig.rejectCancelled;\n\n if (shouldHandleError) {\n const strategy = requestConfig.strategy;\n // Reject the promise\n if (strategy === REJECT) {\n return Promise.reject(error);\n }\n\n // Hang the promise\n if (strategy === 'silent') {\n await new Promise(() => null);\n }\n }\n\n return output;\n}\n\nexport function enhanceError<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n error: any,\n response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null,\n requestConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n >,\n): void {\n error.status = error.status || response?.status || 0;\n error.statusText = error.statusText || response?.statusText || '';\n error.config = error.request = requestConfig;\n error.response = response;\n error.isCancelled = error.name === ABORT_ERROR;\n}\n\n/**\n * Logs messages or errors using the configured logger's `warn` method.\n *\n * @param {RequestConfig} reqConfig - Request config passed when making the request\n * @param {...(string | ResponseError)} args - Messages or errors to log.\n */\nfunction logger(\n reqConfig: RequestConfig,\n ...args: (string | ResponseError)[]\n): void {\n const logger = reqConfig.logger;\n\n if (logger && logger.warn) {\n logger.warn(...args);\n }\n}\n","import type {\n DefaultResponse,\n RequestConfig,\n FetchResponse,\n} from './types/request-handler';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultUrlParams,\n} from './types/api-handler';\nimport { applyInterceptors } from './interceptor-manager';\nimport { ResponseError } from './errors/response-error';\nimport { isObject } from './utils';\nimport {\n markInFlight,\n setInFlightPromise,\n getInFlightPromise,\n} from './inflight-manager';\nimport { parseResponseData, prepareResponse } from './response-parser';\nimport { generateCacheKey, getCachedResponse, setCache } from './cache-manager';\nimport { withRetry } from './retry-handler';\nimport { withPolling } from './polling-handler';\nimport { notifySubscribers } from './pubsub-manager';\nimport { addRevalidator } from './revalidator-manager';\nimport { enhanceError, withErrorHandling } from './error-handler';\nimport { FUNCTION } from './constants';\nimport { buildConfig } from './config-handler';\n\nconst inFlightResponse = Object.freeze({\n isFetching: true,\n});\n\n/**\n * Sends an HTTP request to the specified URL using the provided configuration and returns a typed response.\n *\n * @typeParam ResponseData - The expected shape of the response data. Defaults to `DefaultResponse`.\n * @typeParam RequestBody - The type of the request payload/body. Defaults to `DefaultPayload`.\n * @typeParam QueryParams - The type of the query parameters. Defaults to `DefaultParams`.\n * @typeParam PathParams - The type of the path parameters. Defaults to `DefaultUrlParams`.\n *\n * @param url - The endpoint URL to which the request will be sent.\n * @param config - Optional configuration object for the request, including headers, method, body, query, and path parameters.\n *\n * @returns A promise that resolves to a `FetchResponse` containing the typed response data and request metadata.\n *\n * @example\n * ```typescript\n * const { data } = await fetchf('/api/user', { method: 'GET' });\n * console.log(data);\n * ```\n */\nexport async function fetchf<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n url: string,\n reqConfig: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > | null = null,\n): Promise> {\n // Ultra-fast early cache check if cacheKey is provided as a string\n // For workloads dominated by repeated requests, this string caching optimization\n // can potentially support millions of requests per second with minimal CPU overhead\n if (reqConfig && typeof reqConfig.cacheKey === 'string') {\n const cached = getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(reqConfig.cacheKey, reqConfig.cacheTime, reqConfig);\n\n if (cached) {\n return cached;\n }\n }\n\n const fetcherConfig = buildConfig<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(url, reqConfig);\n\n const {\n timeout,\n cancellable,\n cacheKey,\n dedupeTime,\n cacheTime,\n staleTime,\n refetchOnFocus,\n refetchOnReconnect,\n pollingInterval = 0,\n } = fetcherConfig;\n const isCacheEnabled = cacheTime !== undefined || staleTime !== undefined;\n\n const needsCacheKey = !!(\n cacheKey ||\n timeout ||\n dedupeTime ||\n isCacheEnabled ||\n cancellable ||\n refetchOnFocus ||\n refetchOnReconnect\n );\n\n let _cacheKey: string | null = null;\n\n // Generate cache key if required\n if (needsCacheKey) {\n _cacheKey = generateCacheKey(fetcherConfig);\n }\n\n // Cache handling logic\n if (_cacheKey && isCacheEnabled) {\n const cached = getCachedResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(_cacheKey, cacheTime, fetcherConfig);\n\n if (cached) {\n return cached;\n }\n }\n\n // Deduplication logic\n if (_cacheKey && dedupeTime) {\n const inflight = getInFlightPromise<\n FetchResponse\n >(_cacheKey, dedupeTime);\n\n if (inflight) {\n return inflight;\n }\n }\n\n const retryConfig = fetcherConfig.retry || {};\n const { retries = 0, resetTimeout } = retryConfig;\n\n // The actual request logic as a function (one poll attempt, with retries)\n const doRequestOnce = async (isStaleRevalidation = false, attempt = 0) => {\n // If cache key is specified, we will handle optimistic updates\n // and mark the request as in-flight, so to catch \"fetching\" state.\n // This is useful for Optimistic UI updates (e.g., showing loading spinners).\n if (!attempt) {\n if (_cacheKey && !isStaleRevalidation) {\n if (staleTime) {\n const existingCache = getCachedResponse(\n _cacheKey,\n cacheTime,\n fetcherConfig,\n );\n\n // Don't notify subscribers when cache exists\n // Let them continue showing stale data during background revalidation\n if (!existingCache) {\n setCache(_cacheKey, inFlightResponse, cacheTime, staleTime);\n notifySubscribers(_cacheKey, inFlightResponse);\n }\n } else {\n notifySubscribers(_cacheKey, inFlightResponse);\n }\n }\n\n // Attach cache key so that it can be reused in interceptors or in the final response\n fetcherConfig.cacheKey = _cacheKey;\n }\n\n const url = fetcherConfig.url as string;\n\n // Add the request to the queue. Make sure to handle deduplication, cancellation, timeouts in accordance to retry settings\n const controller = markInFlight(\n _cacheKey,\n url,\n timeout,\n dedupeTime || 0,\n !!cancellable,\n // Enable timeout either by default or when retries & resetTimeout are enabled\n !!(timeout && (!attempt || resetTimeout)),\n );\n\n // Do not create a shallow copy to maintain idempotency here.\n // This ensures the original object is mutated by interceptors whenever needed, including retry logic.\n const requestConfig = fetcherConfig;\n\n requestConfig.signal = controller.signal;\n\n let output: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n let response: FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n > | null = null;\n\n try {\n if (fetcherConfig.onRequest) {\n // Zero-allocation yield to microtask queue so the outer fetchf() can call setInFlightPromise()\n // before onRequest interceptors run. This ensures that if onRequest triggers\n // another fetchf() with the same cacheKey, getInFlightPromise() finds item[4].\n // On retries (attempt > 0), setInFlightPromise() was already called during the first attempt.\n // The promise stored in item[4] is the outer doRequestPromise which covers all retries.\n // So the race only matters on the very first attempt when the outer scope hasn't had a chance to call setInFlightPromise() yet.\n if (_cacheKey && dedupeTime && !attempt) {\n await null;\n }\n\n await applyInterceptors(fetcherConfig.onRequest, requestConfig);\n }\n\n // Custom fetcher\n const fn = fetcherConfig.fetcher;\n\n response = (fn\n ? await fn(\n url,\n requestConfig,\n )\n : await fetch(\n url,\n requestConfig as RequestInit,\n )) as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n\n // Custom fetcher may return a raw data object instead of a Response instance\n if (isObject(response)) {\n // Case 1: Native Response instance\n if (typeof Response === FUNCTION && response instanceof Response) {\n response.data = await parseResponseData(response);\n } else if (fn) {\n // Case 2: Custom fetcher that returns a response object\n if (!('data' in response && 'body' in response)) {\n // Case 3: Raw data, wrap it\n response = { data: response } as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }\n }\n\n // Attach config and data to the response\n // This is useful for custom fetchers that do not return a Response instance\n // and for interceptors that may need to access the request config\n response.config = requestConfig;\n\n // Check if the response status is not outside the range 200-299 and if so, output error\n // This is the pattern for fetch responses as per spec, but custom fetchers may not follow it so we check for `ok` property\n if (response.ok !== undefined && !response.ok) {\n throw new ResponseError(\n `${requestConfig.method} to ${url} failed! Status: ${response.status || null}`,\n requestConfig,\n response,\n );\n }\n }\n\n output = prepareResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(response, requestConfig);\n\n const onResponse = fetcherConfig.onResponse;\n\n if (onResponse) {\n await applyInterceptors(onResponse, output);\n }\n } catch (_error) {\n const error = _error as ResponseError<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n\n // Append additional information to Network, CORS or any other fetch() errors\n enhanceError(\n error,\n response,\n requestConfig,\n );\n\n // Prepare Extended Response\n output = prepareResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >(response, requestConfig, error);\n }\n\n return output;\n };\n\n // Inline and minimize function wrappers for performance\n // When retries are enabled, forward isStaleRevalidation so the first attempt\n // of a background SWR revalidation doesn't incorrectly mark the request as in-flight\n const baseRequest =\n retries > 0\n ? (isStaleRevalidation = false) =>\n withRetry(\n (_, attempt) => doRequestOnce(isStaleRevalidation, attempt),\n retryConfig,\n )\n : doRequestOnce;\n\n const requestWithErrorHandling = (isStaleRevalidation = false) =>\n withErrorHandling(\n isStaleRevalidation,\n baseRequest,\n fetcherConfig,\n );\n\n // Avoid unnecessary function wrapping if polling is not enabled\n const doRequestPromise = pollingInterval\n ? withPolling(\n requestWithErrorHandling,\n pollingInterval,\n fetcherConfig.shouldStopPolling,\n fetcherConfig.maxPollingAttempts,\n fetcherConfig.pollingDelay,\n )\n : requestWithErrorHandling();\n\n // If deduplication is enabled, store the in-flight promise immediately\n if (_cacheKey) {\n if (dedupeTime) {\n setInFlightPromise(_cacheKey, doRequestPromise);\n }\n\n // Only register revalidator when revalidation features are actually requested\n if (staleTime || refetchOnFocus || refetchOnReconnect) {\n addRevalidator(\n _cacheKey,\n requestWithErrorHandling,\n undefined,\n staleTime,\n requestWithErrorHandling,\n !!refetchOnFocus,\n !!refetchOnReconnect,\n );\n }\n }\n\n return doRequestPromise;\n}\n","import type {\n ApiHandlerConfig,\n ApiHandlerDefaultMethods,\n ApiHandlerMethods,\n RequestConfigUrlRequired,\n} from './types/api-handler';\nimport { fetchf } from '.';\nimport { mergeConfigs } from './config-handler';\nimport { isAbsoluteUrl } from './utils';\n\n/**\n * Creates an instance of API Handler.\n * It creates an API fetcher function using native fetch() or a custom fetcher if passed as \"fetcher\".\n * @see https://github.com/MattCCC/fetchff#configuration\n *\n * @param {Object} config - Configuration object for the API fetcher (see link above for full options).\n * @param {Object} config.endpoints - An object containing endpoint definitions.\n * @param {string} [config.baseURL] - The base URL for the API.\n * @param {Object} [config.headers] - Optional default headers to include in every request.\n * @param {Function} [config.onError] - Optional callback function for handling errors.\n * @returns API handler functions and endpoints to call\n *\n * @example\n * // Define endpoint paths\n * const endpoints = {\n * getUser: '/user',\n * createPost: '/post',\n * };\n *\n * // Create the API fetcher with configuration\n * const api = createApiFetcher({\n * endpoints,\n * apiUrl: 'https://example.com/api',\n * onError(error) {\n * console.log('Request failed', error);\n * },\n * headers: {\n * 'my-auth-key': 'example-auth-key-32rjjfa',\n * },\n * });\n *\n * // Fetch user data\n * const response = await api.getUser({ userId: 1, ratings: [1, 2] })\n */\nfunction createApiFetcher<\n EndpointTypes extends object,\n EndpointsSettings = never,\n>(config: ApiHandlerConfig) {\n const endpoints = config.endpoints;\n\n /**\n * Triggered when trying to use non-existent endpoints\n *\n * @param endpointName Endpoint Name\n * @returns {Promise}\n */\n function handleNonImplemented(endpointName: string): Promise {\n console.error(`Add ${endpointName} to 'endpoints'.`);\n\n return Promise.resolve(null);\n }\n\n const apiHandler: ApiHandlerDefaultMethods = {\n config,\n endpoints,\n /**\n * Handle Single API Request\n * It considers settings in following order: per-request settings, global per-endpoint settings, global settings.\n *\n * @param endpointName - The name of the API endpoint to call.\n * @param requestConfig - Additional configuration for the request.\n * @returns A promise that resolves with the response from the API provider.\n */\n async request(endpointName, requestConfig = {}) {\n // Use global and per-endpoint settings\n const endpointConfig = endpoints[endpointName];\n const _endpointConfig =\n endpointConfig ||\n ({ url: String(endpointName) } as RequestConfigUrlRequired);\n const url = _endpointConfig.url;\n\n // Block Protocol-relative URLs as they could lead to SSRF (Server-Side Request Forgery)\n if (url.startsWith('//')) {\n throw new Error('Protocol-relative URLs are not allowed.');\n }\n\n // Prevent potential Server-Side Request Forgery attack and leakage of credentials when same instance is used for external requests\n const mergedConfig = isAbsoluteUrl(url)\n ? // Merge endpoints configs for absolute URLs only if urls match\n endpointConfig?.url === url\n ? mergeConfigs(_endpointConfig, requestConfig)\n : requestConfig\n : mergeConfigs(mergeConfigs(config, _endpointConfig), requestConfig);\n\n // We prevent potential Server-Side Request Forgery attack and leakage of credentials as the same instance is not used for external requests\n // Retrigger fetch to ensure completely new instance of handler being triggered for external URLs\n return fetchf(url, mergedConfig);\n },\n };\n\n /**\n * Maps all API requests using native Proxy\n *\n * @param {*} prop Caller\n */\n return new Proxy>(\n apiHandler as ApiHandlerMethods,\n {\n get(_target, prop: string) {\n if (prop in apiHandler) {\n return apiHandler[prop as unknown as keyof typeof apiHandler];\n }\n\n // Prevent handler from triggering non-existent endpoints\n if (endpoints[prop]) {\n return apiHandler.request.bind(null, prop);\n }\n\n return handleNonImplemented.bind(null, prop);\n },\n },\n );\n}\n\nexport { createApiFetcher };\n"]} \ No newline at end of file diff --git a/dist/react/index.js b/dist/react/index.js index d2f10ebb..cb755278 100644 --- a/dist/react/index.js +++ b/dist/react/index.js @@ -1,2 +1,2 @@ -'use strict';var react=require('react'),fetchff=require('fetchff');var F=-1,D=2e3,m=new Map,q=e=>{e&&m.set(e,(m.get(e)||0)+1);},A=(e,t,s,o)=>{if(!e)return;let a=f(e);if(!a)return;let i=a-1;i<=0?(m.delete(e),t===F&&fetchff.addTimeout("r:"+e,()=>{fetchff.abortRequest(e,new DOMException("Request to "+o+" aborted","AbortError")),f(e)||fetchff.deleteCache(e,true);},s!=null?s:D)):m.set(e,i);},f=e=>e&&m.get(e)||0;var Y=300,x=Object.freeze({data:null,error:null,isFetching:false,mutate:()=>Promise.resolve(null),config:{},headers:{}}),K=Object.freeze({...x,isFetching:true}),Z=[null,{},null],$=new Set(["GET","HEAD","get","head"]);function ae(e,t={}){var b,U,_;let s=react.useMemo(()=>e===null?null:fetchff.generateCacheKey(fetchff.buildConfig(e,t)),[t.cacheKey,e,t.url,t.method,t.headers,t.body,t.params,t.urlPathParams,t.apiUrl,t.baseURL,t.withCredentials,t.credentials]),o=(b=t.dedupeTime)!=null?b:D,a=t.cacheTime||F,i=(U=t.staleTime)!=null?U:Y,R=(_=t.immediate)!=null?_:$.has(t.method||"GET"),P=react.useRef(Z);P.current=[e,t,s];let g=react.useCallback(()=>{let r=fetchff.getCache(s);if(t.strategy==="reject"&&s&&(!r||!r.data.data&&!r.data.error)){let h=fetchff.getInFlightPromise(s,o);if(h)throw h;if(!r){let[u,c,l]=P.current;if(u)throw fetchff.fetchf(u,{...c,cacheKey:l,dedupeTime:o,cacheTime:a,staleTime:i,strategy:"softFail",cacheErrors:true,_isAutoKey:!c.cacheKey})}}return r?r.data.isFetching&&!t.keepPreviousData?K:r.data:R?K:x},[s]),B=react.useCallback(r=>{q(s),R&&e&&s&&f(s)===1&&(fetchff.getCachedResponse(s,a,t)||C(false));let u=fetchff.subscribe(s,r);return ()=>{A(s,a,o,e),u();}},[s,R,e,o,a]),n=react.useSyncExternalStore(B,g,g),C=react.useCallback(async(r=true,h={})=>{let[u,c,l]=P.current;if(!u)return Promise.resolve(null);let E=!!r;if(!E&&l){let S=fetchff.getCachedResponse(l,a,c);if(S)return Promise.resolve(S)}let Q=E?()=>true:c.cacheBuster;return fetchff.fetchf(u,{...c,cacheKey:l,...h,dedupeTime:o,cacheTime:a,staleTime:i,cacheBuster:Q,strategy:"softFail",cacheErrors:true,_isAutoKey:!c.cacheKey})},[a,o]),T=n.data,p=!T&&!n.error,d=!!e&&(n.isFetching||p&&R),L=d&&p,w=d&&!p;return {data:T,error:n.error,config:n.config,headers:n.headers,isFirstFetch:L,isFetching:d,isLoading:d,isRefetching:w,isError:n.isError,isSuccess:n.isSuccess,mutate:n.mutate,refetch:C}}exports.useFetcher=ae;//# sourceMappingURL=index.js.map +'use strict';var react=require('react'),fetchff=require('fetchff');var F=-1,y=2e3,m=new Map,S=e=>{e&&m.set(e,(m.get(e)||0)+1);},q=(e,t,r,o)=>{if(!e)return;let a=f(e);if(!a)return;let i=a-1;i<=0?(m.delete(e),t===F&&fetchff.addTimeout("r:"+e,()=>{fetchff.abortRequest(e,fetchff.createAbortError("Request to "+o+" aborted","AbortError")),f(e)||fetchff.deleteCache(e,true);},r!=null?r:y)):m.set(e,i);},f=e=>e&&m.get(e)||0;var Z=300,B=Object.freeze({data:null,error:null,isFetching:false,mutate:()=>Promise.resolve(null),config:{},headers:{}}),K=Object.freeze({...B,isFetching:true}),$=[null,{},null],k=new Set(["GET","HEAD","get","head"]);function ne(e,t={}){var b,U,_;let r=react.useMemo(()=>e===null?null:fetchff.generateCacheKey(fetchff.buildConfig(e,t)),[t.cacheKey,e,t.url,t.method,t.headers,t.body,t.params,t.urlPathParams,t.apiUrl,t.baseURL,t.withCredentials,t.credentials]),o=(b=t.dedupeTime)!=null?b:y,a=t.cacheTime||F,i=(U=t.staleTime)!=null?U:Z,R=(_=t.immediate)!=null?_:k.has(t.method||"GET"),P=react.useRef($);P.current=[e,t,r];let g=react.useCallback(()=>{let s=fetchff.getCache(r);if(t.strategy==="reject"&&r&&(!s||!s.data.data&&!s.data.error)){let h=fetchff.getInFlightPromise(r,o);if(h)throw h;if(!s){let[u,c,l]=P.current;if(u)throw fetchff.fetchf(u,{...c,cacheKey:l,dedupeTime:o,cacheTime:a,staleTime:i,strategy:"softFail",cacheErrors:true,_isAutoKey:!c.cacheKey})}}return s?s.data.isFetching&&!t.keepPreviousData?K:s.data:R?K:B},[r]),L=react.useCallback(s=>{S(r),R&&e&&r&&f(r)===1&&(fetchff.getCachedResponse(r,a,t)||C(false));let u=fetchff.subscribe(r,s);return ()=>{q(r,a,o,e),u();}},[r,R,e,o,a]),n=react.useSyncExternalStore(L,g,g),C=react.useCallback(async(s=true,h={})=>{let[u,c,l]=P.current;if(!u)return Promise.resolve(null);let E=!!s;if(!E&&l){let A=fetchff.getCachedResponse(l,a,c);if(A)return Promise.resolve(A)}let Q=E?()=>true:c.cacheBuster;return fetchff.fetchf(u,{...c,cacheKey:l,...h,dedupeTime:o,cacheTime:a,staleTime:i,cacheBuster:Q,strategy:"softFail",cacheErrors:true,_isAutoKey:!c.cacheKey})},[a,o]),T=n.data,p=!T&&!n.error,d=!!e&&(n.isFetching||p&&R),x=d&&p,w=d&&!p;return {data:T,error:n.error,config:n.config,headers:n.headers,isFirstFetch:x,isFetching:d,isLoading:d,isRefetching:w,isError:n.isError,isSuccess:n.isSuccess,mutate:n.mutate,refetch:C}}exports.useFetcher=ne;//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/react/index.js.map b/dist/react/index.js.map index 35e5dcf4..511bf205 100644 --- a/dist/react/index.js.map +++ b/dist/react/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["../../src/react/cache-ref.ts","../../src/react/index.ts"],"names":["INFINITE_CACHE_TIME","DEFAULT_DEDUPE_TIME_MS","refs","incrementRef","key","decrementRef","cacheTime","dedupeTime","url","current","getRefCount","newCount","addTimeout","abortRequest","deleteCache","DEFAULT_STALE_TIME","DEFAULT_RESULT","FETCHING_RESULT","DEFAULT_REF","SAFE_METHODS","useFetcher","config","_a","_b","_c","cacheKey","useMemo","generateCacheKey","buildConfig","staleTime","shouldTriggerOnMount","currentValuesRef","useRef","getSnapshot","useCallback","cached","getCache","pendingPromise","getInFlightPromise","currUrl","currConfig","currCacheKey","fetchf","doSubscribe","cb","getCachedResponse","refetch","unsubscribe","subscribe","state","useSyncExternalStore","forceRefresh","requestConfig","shouldRefresh","cacheBuster","data","isUnresolved","isFetching","isFirstFetch","isRefetching"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @module cache-ref\n *\n * Provides reference counting utilities for cache management in React applications.\n *\n * This module maintains an internal reference count for cache keys, allowing for\n * precise control over when cache entries should be deleted. It exports functions\n * to increment and decrement reference counts, retrieve the current count, and clear\n * all reference counts. When a reference count drops to zero and certain conditions\n * are met, the corresponding cache entry is scheduled for deletion.\n *\n * @see deleteCache\n */\n\nimport { addTimeout, abortRequest, deleteCache } from 'fetchff';\n\nexport const INFINITE_CACHE_TIME = -1;\nexport const DEFAULT_DEDUPE_TIME_MS = 2000;\n\nconst refs = new Map();\n\nexport const incrementRef = (key: string | null) => {\n if (key) {\n refs.set(key, (refs.get(key) || 0) + 1);\n }\n};\n\nexport const decrementRef = (\n key: string | null,\n cacheTime?: number,\n dedupeTime?: number,\n url?: string | null,\n) => {\n if (!key) {\n return;\n }\n\n const current = getRefCount(key);\n\n if (!current) {\n return;\n }\n\n const newCount = current - 1;\n\n // If the current reference count is less than 2, we can consider deleting the global cache entry\n // The infinite cache time is a special case where we never delete the cache entry unless the reference count drops to zero.\n // This allows for long-lived cache entries that are only deleted when explicitly no longer needed.\n if (newCount <= 0) {\n refs.delete(key);\n\n if (cacheTime && cacheTime === INFINITE_CACHE_TIME) {\n // Delay to ensure all operations are complete before deletion\n addTimeout(\n 'r:' + key,\n () => {\n // Abort any ongoing requests associated with this cache key\n abortRequest(\n key,\n new DOMException('Request to ' + url + ' aborted', 'AbortError'),\n );\n\n // Check if the reference count is still zero before deleting the cache as it might have been incremented again\n // This is to ensure that if another increment happens during the timeout, we don't delete the cache prematurely\n // This is particularly useful in scenarios where multiple components might be using the same cache\n // entry and we want to avoid unnecessary cache deletions.\n if (!getRefCount(key)) {\n deleteCache(key, true);\n }\n },\n dedupeTime ?? DEFAULT_DEDUPE_TIME_MS,\n );\n }\n } else {\n refs.set(key, newCount);\n }\n};\n\nexport const getRefCount = (key: string | null): number => {\n if (!key) {\n return 0;\n }\n\n return refs.get(key) || 0;\n};\n\nexport const getRefs = (): Map => {\n return refs;\n};\n\nexport const clearRefCache = () => {\n refs.clear();\n};\n","import { useCallback, useSyncExternalStore, useMemo, useRef } from 'react';\nimport {\n fetchf,\n subscribe,\n buildConfig,\n generateCacheKey,\n getCachedResponse,\n getInFlightPromise,\n getCache,\n} from 'fetchff';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '..';\nimport type { RefetchFunction, UseFetcherResult } from '../types/react-hooks';\n\nimport {\n decrementRef,\n DEFAULT_DEDUPE_TIME_MS,\n getRefCount,\n incrementRef,\n INFINITE_CACHE_TIME,\n} from './cache-ref';\n\n// In React, we use a default stale time of 5 minutes (SWR)\nconst DEFAULT_STALE_TIME = 300; // 5 minutes\n\n// Pre-allocate objects to avoid GC pressure\nconst DEFAULT_RESULT = Object.freeze({\n data: null,\n error: null,\n isFetching: false,\n mutate: () => Promise.resolve(null),\n config: {},\n headers: {},\n});\n\nconst FETCHING_RESULT = Object.freeze({\n ...DEFAULT_RESULT,\n isFetching: true,\n});\n\nconst DEFAULT_REF = [null, {}, null] as [\n string | null,\n RequestConfig,\n string | null,\n];\n\n// RFC 7231: GET and HEAD are \"safe methods\" with no side effects\nconst SAFE_METHODS = new Set(['GET', 'HEAD', 'get', 'head']);\n\n/**\n * High-performance React hook for fetching data with caching, deduplication, revalidation etc.\n *\n * @template ResponseData - The expected response data type.\n * @template RequestBody - The request payload type.\n * @template QueryParams - The query parameters type.\n * @template PathParams - The URL path parameters type.\n *\n * @param {string|null} url - The endpoint URL to fetch data from. Pass null to skip fetching.\n * If the URL is null, the hook will not perform any fetch operation.\n * If the URL is an empty string, it will default to the base URL configured in fetchff.\n * If the URL is a full URL, it will be used as is.\n * @param {RequestConfig} [config={}] - fetchff and native fetch compatible configuration.\n *\n * @returns {UseFetcherResult} An object containing:\n * - `data`: The fetched data or `null` if not yet available.\n * - `error`: Any error encountered during fetching or `null`.\n * - `isLoading`: Boolean indicating if the request is in progress.\n * - `mutate`: Function to update the cached data and optionally trigger revalidation.\n *\n * @remarks\n * - Designed for high performance: minimizes unnecessary re-renders and leverages fast cache key generation.\n * - Integrates with a global cache and pub/sub system for efficient state updates across contexts.\n * - Handles automatic revalidation, deduplication, retries, and cache management out of the box.\n *\n * @example\n * ```tsx\n * const { data, error, isLoading, mutate } = useFetcher('/api/data', {\n * refetchOnFocus: true,\n * cacheTime: 5,\n * dedupeTime: 2000,\n * cacheKey: (config) => `custom-cache-key-${config.url}`,\n * });\n * ```\n */\nexport function useFetcher<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n url: string | null,\n config: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > = {},\n): UseFetcherResult {\n // Efficient cache key generation based on URL and request parameters.\n // Optimized for speed: minimizes unnecessary function calls when possible\n const cacheKey = useMemo(\n () => (url === null ? null : generateCacheKey(buildConfig(url, config))),\n [\n config.cacheKey,\n url,\n config.url,\n config.method,\n config.headers,\n config.body,\n config.params,\n config.urlPathParams,\n config.apiUrl,\n config.baseURL,\n config.withCredentials,\n config.credentials,\n ],\n );\n const dedupeTime = config.dedupeTime ?? DEFAULT_DEDUPE_TIME_MS;\n const cacheTime = config.cacheTime || INFINITE_CACHE_TIME;\n const staleTime = config.staleTime ?? DEFAULT_STALE_TIME;\n\n // Determine if the fetch should be triggered immediately on mount\n const shouldTriggerOnMount =\n config.immediate ?? SAFE_METHODS.has(config.method || 'GET');\n\n const currentValuesRef = useRef(DEFAULT_REF);\n currentValuesRef.current = [url, config, cacheKey];\n\n // Attempt to get the cached response immediately and if not available, return null\n const getSnapshot = useCallback(() => {\n const cached = getCache(\n cacheKey,\n );\n\n // Only throw for Suspense if we're in 'reject' mode and have no data\n if (\n config.strategy === 'reject' &&\n cacheKey &&\n (!cached || (!cached.data.data && !cached.data.error))\n ) {\n const pendingPromise = getInFlightPromise(cacheKey, dedupeTime);\n\n if (pendingPromise) {\n throw pendingPromise;\n }\n\n // If no pending promise but we need to fetch, start fetch and throw the promise\n if (!cached) {\n const [currUrl, currConfig, currCacheKey] = currentValuesRef.current;\n\n if (currUrl) {\n const fetchPromise = fetchf(currUrl, {\n ...currConfig,\n cacheKey: currCacheKey,\n dedupeTime,\n cacheTime,\n staleTime,\n strategy: 'softFail',\n cacheErrors: true,\n _isAutoKey: !currConfig.cacheKey,\n });\n\n throw fetchPromise;\n }\n }\n }\n\n if (cached) {\n return cached.data.isFetching && !config.keepPreviousData\n ? (FETCHING_RESULT as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >)\n : cached.data;\n }\n\n return (shouldTriggerOnMount\n ? FETCHING_RESULT\n : DEFAULT_RESULT) as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }, [cacheKey]);\n\n // Subscribe to cache updates for the specific cache key\n const doSubscribe = useCallback(\n (cb: () => void) => {\n incrementRef(cacheKey);\n\n // When the component mounts, we want to fetch data if:\n // 1. URL is provided\n // 2. shouldTriggerOnMount is true (so the \"immediate\" isn't specified or is true)\n // 3. There is no cached data\n // 4. There is no error\n // 5. There is no ongoing fetch operation\n const shouldFetch =\n shouldTriggerOnMount && url && cacheKey && getRefCount(cacheKey) === 1; // Check if no existing refs\n\n // Initial fetch logic\n if (shouldFetch) {\n // Stale-While-Revalidate Pattern: Check for both fresh and stale data\n const cached = getCachedResponse(cacheKey, cacheTime, config);\n\n if (!cached) {\n refetch(false);\n }\n }\n\n const unsubscribe = subscribe(cacheKey, cb);\n\n return () => {\n decrementRef(cacheKey, cacheTime, dedupeTime, url);\n unsubscribe();\n };\n },\n [cacheKey, shouldTriggerOnMount, url, dedupeTime, cacheTime],\n );\n\n const state = useSyncExternalStore<\n FetchResponse\n >(doSubscribe, getSnapshot, getSnapshot);\n\n const refetch = useCallback<\n RefetchFunction\n >(\n async (forceRefresh = true, requestConfig = {}) => {\n const [currUrl, currConfig, currCacheKey] = currentValuesRef.current;\n\n if (!currUrl) {\n return Promise.resolve(null);\n }\n\n // Truthy check for forceRefresh to ensure it's a boolean. It is useful in onClick handlers so to avoid additional annonymous function calls.\n const shouldRefresh = !!forceRefresh;\n\n // Fast path: check cache first if not forcing refresh\n if (!shouldRefresh && currCacheKey) {\n const cached = getCachedResponse(currCacheKey, cacheTime, currConfig);\n\n if (cached) {\n return Promise.resolve(cached);\n }\n }\n\n // When manual refetch is triggered, we want to ensure that the cache is busted\n // This can be disabled by passing `refetch(false)`\n const cacheBuster = shouldRefresh ? () => true : currConfig.cacheBuster;\n\n return fetchf(currUrl, {\n ...currConfig,\n cacheKey: currCacheKey,\n ...requestConfig,\n dedupeTime,\n cacheTime,\n staleTime,\n cacheBuster,\n // Ensure that errors are handled gracefully and not thrown by default\n strategy: 'softFail',\n cacheErrors: true,\n _isAutoKey: !currConfig.cacheKey,\n });\n },\n [cacheTime, dedupeTime],\n );\n\n const data = state.data;\n const isUnresolved = !data && !state.error;\n\n // This indicates if the request is in progress or if it is about to start on first mount\n // It is true when:\n // - The request is currently ongoing, and it is not background revalidation\n // - The request is unresolved (no data and no error) and shouldTriggerOnMount\n // is true (which means the request is about to start on mount)\n const isFetching =\n !!url && (state.isFetching || (isUnresolved && shouldTriggerOnMount));\n const isFirstFetch = isFetching && isUnresolved;\n const isRefetching = isFetching && !isUnresolved;\n\n // Consumers always destructure the return value and use the fields directly, so\n // memoizing the object doesn't change rerender behavior nor improve any performance here\n return {\n data,\n error: state.error,\n config: state.config,\n headers: state.headers,\n isFirstFetch,\n isFetching,\n isLoading: isFetching,\n isRefetching,\n isError: state.isError,\n isSuccess: state.isSuccess,\n mutate: state.mutate,\n refetch,\n };\n}\n"]} \ No newline at end of file +{"version":3,"sources":["../../src/react/cache-ref.ts","../../src/react/index.ts"],"names":["INFINITE_CACHE_TIME","DEFAULT_DEDUPE_TIME_MS","refs","incrementRef","key","decrementRef","cacheTime","dedupeTime","url","current","getRefCount","newCount","addTimeout","abortRequest","createAbortError","deleteCache","DEFAULT_STALE_TIME","DEFAULT_RESULT","FETCHING_RESULT","DEFAULT_REF","SAFE_METHODS","useFetcher","config","_a","_b","_c","cacheKey","useMemo","generateCacheKey","buildConfig","staleTime","shouldTriggerOnMount","currentValuesRef","useRef","getSnapshot","useCallback","cached","getCache","pendingPromise","getInFlightPromise","currUrl","currConfig","currCacheKey","fetchf","doSubscribe","cb","getCachedResponse","refetch","unsubscribe","subscribe","state","useSyncExternalStore","forceRefresh","requestConfig","shouldRefresh","cacheBuster","data","isUnresolved","isFetching","isFirstFetch","isRefetching"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @module cache-ref\n *\n * Provides reference counting utilities for cache management in React applications.\n *\n * This module maintains an internal reference count for cache keys, allowing for\n * precise control over when cache entries should be deleted. It exports functions\n * to increment and decrement reference counts, retrieve the current count, and clear\n * all reference counts. When a reference count drops to zero and certain conditions\n * are met, the corresponding cache entry is scheduled for deletion.\n *\n * @see deleteCache\n */\n\nimport {\n addTimeout,\n abortRequest,\n deleteCache,\n createAbortError,\n} from 'fetchff';\n\nexport const INFINITE_CACHE_TIME = -1;\nexport const DEFAULT_DEDUPE_TIME_MS = 2000;\n\nconst refs = new Map();\n\nexport const incrementRef = (key: string | null) => {\n if (key) {\n refs.set(key, (refs.get(key) || 0) + 1);\n }\n};\n\nexport const decrementRef = (\n key: string | null,\n cacheTime?: number,\n dedupeTime?: number,\n url?: string | null,\n) => {\n if (!key) {\n return;\n }\n\n const current = getRefCount(key);\n\n if (!current) {\n return;\n }\n\n const newCount = current - 1;\n\n // If the current reference count is less than 2, we can consider deleting the global cache entry\n // The infinite cache time is a special case where we never delete the cache entry unless the reference count drops to zero.\n // This allows for long-lived cache entries that are only deleted when explicitly no longer needed.\n if (newCount <= 0) {\n refs.delete(key);\n\n if (cacheTime && cacheTime === INFINITE_CACHE_TIME) {\n // Delay to ensure all operations are complete before deletion\n addTimeout(\n 'r:' + key,\n () => {\n // Abort any ongoing requests associated with this cache key\n abortRequest(\n key,\n createAbortError('Request to ' + url + ' aborted', 'AbortError'),\n );\n\n // Check if the reference count is still zero before deleting the cache as it might have been incremented again\n // This is to ensure that if another increment happens during the timeout, we don't delete the cache prematurely\n // This is particularly useful in scenarios where multiple components might be using the same cache\n // entry and we want to avoid unnecessary cache deletions.\n if (!getRefCount(key)) {\n deleteCache(key, true);\n }\n },\n dedupeTime ?? DEFAULT_DEDUPE_TIME_MS,\n );\n }\n } else {\n refs.set(key, newCount);\n }\n};\n\nexport const getRefCount = (key: string | null): number => {\n if (!key) {\n return 0;\n }\n\n return refs.get(key) || 0;\n};\n\nexport const getRefs = (): Map => {\n return refs;\n};\n\nexport const clearRefCache = () => {\n refs.clear();\n};\n","import { useCallback, useSyncExternalStore, useMemo, useRef } from 'react';\nimport {\n fetchf,\n subscribe,\n buildConfig,\n generateCacheKey,\n getCachedResponse,\n getInFlightPromise,\n getCache,\n} from 'fetchff';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '..';\nimport type { RefetchFunction, UseFetcherResult } from '../types/react-hooks';\n\nimport {\n decrementRef,\n DEFAULT_DEDUPE_TIME_MS,\n getRefCount,\n incrementRef,\n INFINITE_CACHE_TIME,\n} from './cache-ref';\n\n// In React, we use a default stale time of 5 minutes (SWR)\nconst DEFAULT_STALE_TIME = 300; // 5 minutes\n\n// Pre-allocate objects to avoid GC pressure\nconst DEFAULT_RESULT = Object.freeze({\n data: null,\n error: null,\n isFetching: false,\n mutate: () => Promise.resolve(null),\n config: {},\n headers: {},\n});\n\nconst FETCHING_RESULT = Object.freeze({\n ...DEFAULT_RESULT,\n isFetching: true,\n});\n\nconst DEFAULT_REF = [null, {}, null] as [\n string | null,\n RequestConfig,\n string | null,\n];\n\n// RFC 7231: GET and HEAD are \"safe methods\" with no side effects\nconst SAFE_METHODS = new Set(['GET', 'HEAD', 'get', 'head']);\n\n/**\n * High-performance React hook for fetching data with caching, deduplication, revalidation etc.\n *\n * @template ResponseData - The expected response data type.\n * @template RequestBody - The request payload type.\n * @template QueryParams - The query parameters type.\n * @template PathParams - The URL path parameters type.\n *\n * @param {string|null} url - The endpoint URL to fetch data from. Pass null to skip fetching.\n * If the URL is null, the hook will not perform any fetch operation.\n * If the URL is an empty string, it will default to the base URL configured in fetchff.\n * If the URL is a full URL, it will be used as is.\n * @param {RequestConfig} [config={}] - fetchff and native fetch compatible configuration.\n *\n * @returns {UseFetcherResult} An object containing:\n * - `data`: The fetched data or `null` if not yet available.\n * - `error`: Any error encountered during fetching or `null`.\n * - `isLoading`: Boolean indicating if the request is in progress.\n * - `mutate`: Function to update the cached data and optionally trigger revalidation.\n *\n * @remarks\n * - Designed for high performance: minimizes unnecessary re-renders and leverages fast cache key generation.\n * - Integrates with a global cache and pub/sub system for efficient state updates across contexts.\n * - Handles automatic revalidation, deduplication, retries, and cache management out of the box.\n *\n * @example\n * ```tsx\n * const { data, error, isLoading, mutate } = useFetcher('/api/data', {\n * refetchOnFocus: true,\n * cacheTime: 5,\n * dedupeTime: 2000,\n * cacheKey: (config) => `custom-cache-key-${config.url}`,\n * });\n * ```\n */\nexport function useFetcher<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n url: string | null,\n config: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > = {},\n): UseFetcherResult {\n // Efficient cache key generation based on URL and request parameters.\n // Optimized for speed: minimizes unnecessary function calls when possible\n const cacheKey = useMemo(\n () => (url === null ? null : generateCacheKey(buildConfig(url, config))),\n [\n config.cacheKey,\n url,\n config.url,\n config.method,\n config.headers,\n config.body,\n config.params,\n config.urlPathParams,\n config.apiUrl,\n config.baseURL,\n config.withCredentials,\n config.credentials,\n ],\n );\n const dedupeTime = config.dedupeTime ?? DEFAULT_DEDUPE_TIME_MS;\n const cacheTime = config.cacheTime || INFINITE_CACHE_TIME;\n const staleTime = config.staleTime ?? DEFAULT_STALE_TIME;\n\n // Determine if the fetch should be triggered immediately on mount\n const shouldTriggerOnMount =\n config.immediate ?? SAFE_METHODS.has(config.method || 'GET');\n\n const currentValuesRef = useRef(DEFAULT_REF);\n currentValuesRef.current = [url, config, cacheKey];\n\n // Attempt to get the cached response immediately and if not available, return null\n const getSnapshot = useCallback(() => {\n const cached = getCache(\n cacheKey,\n );\n\n // Only throw for Suspense if we're in 'reject' mode and have no data\n if (\n config.strategy === 'reject' &&\n cacheKey &&\n (!cached || (!cached.data.data && !cached.data.error))\n ) {\n const pendingPromise = getInFlightPromise(cacheKey, dedupeTime);\n\n if (pendingPromise) {\n throw pendingPromise;\n }\n\n // If no pending promise but we need to fetch, start fetch and throw the promise\n if (!cached) {\n const [currUrl, currConfig, currCacheKey] = currentValuesRef.current;\n\n if (currUrl) {\n const fetchPromise = fetchf(currUrl, {\n ...currConfig,\n cacheKey: currCacheKey,\n dedupeTime,\n cacheTime,\n staleTime,\n strategy: 'softFail',\n cacheErrors: true,\n _isAutoKey: !currConfig.cacheKey,\n });\n\n throw fetchPromise;\n }\n }\n }\n\n if (cached) {\n return cached.data.isFetching && !config.keepPreviousData\n ? (FETCHING_RESULT as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >)\n : cached.data;\n }\n\n return (shouldTriggerOnMount\n ? FETCHING_RESULT\n : DEFAULT_RESULT) as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }, [cacheKey]);\n\n // Subscribe to cache updates for the specific cache key\n const doSubscribe = useCallback(\n (cb: () => void) => {\n incrementRef(cacheKey);\n\n // When the component mounts, we want to fetch data if:\n // 1. URL is provided\n // 2. shouldTriggerOnMount is true (so the \"immediate\" isn't specified or is true)\n // 3. There is no cached data\n // 4. There is no error\n // 5. There is no ongoing fetch operation\n const shouldFetch =\n shouldTriggerOnMount && url && cacheKey && getRefCount(cacheKey) === 1; // Check if no existing refs\n\n // Initial fetch logic\n if (shouldFetch) {\n // Stale-While-Revalidate Pattern: Check for both fresh and stale data\n const cached = getCachedResponse(cacheKey, cacheTime, config);\n\n if (!cached) {\n refetch(false);\n }\n }\n\n const unsubscribe = subscribe(cacheKey, cb);\n\n return () => {\n decrementRef(cacheKey, cacheTime, dedupeTime, url);\n unsubscribe();\n };\n },\n [cacheKey, shouldTriggerOnMount, url, dedupeTime, cacheTime],\n );\n\n const state = useSyncExternalStore<\n FetchResponse\n >(doSubscribe, getSnapshot, getSnapshot);\n\n const refetch = useCallback<\n RefetchFunction\n >(\n async (forceRefresh = true, requestConfig = {}) => {\n const [currUrl, currConfig, currCacheKey] = currentValuesRef.current;\n\n if (!currUrl) {\n return Promise.resolve(null);\n }\n\n // Truthy check for forceRefresh to ensure it's a boolean. It is useful in onClick handlers so to avoid additional annonymous function calls.\n const shouldRefresh = !!forceRefresh;\n\n // Fast path: check cache first if not forcing refresh\n if (!shouldRefresh && currCacheKey) {\n const cached = getCachedResponse(currCacheKey, cacheTime, currConfig);\n\n if (cached) {\n return Promise.resolve(cached);\n }\n }\n\n // When manual refetch is triggered, we want to ensure that the cache is busted\n // This can be disabled by passing `refetch(false)`\n const cacheBuster = shouldRefresh ? () => true : currConfig.cacheBuster;\n\n return fetchf(currUrl, {\n ...currConfig,\n cacheKey: currCacheKey,\n ...requestConfig,\n dedupeTime,\n cacheTime,\n staleTime,\n cacheBuster,\n // Ensure that errors are handled gracefully and not thrown by default\n strategy: 'softFail',\n cacheErrors: true,\n _isAutoKey: !currConfig.cacheKey,\n });\n },\n [cacheTime, dedupeTime],\n );\n\n const data = state.data;\n const isUnresolved = !data && !state.error;\n\n // This indicates if the request is in progress or if it is about to start on first mount\n // It is true when:\n // - The request is currently ongoing, and it is not background revalidation\n // - The request is unresolved (no data and no error) and shouldTriggerOnMount\n // is true (which means the request is about to start on mount)\n const isFetching =\n !!url && (state.isFetching || (isUnresolved && shouldTriggerOnMount));\n const isFirstFetch = isFetching && isUnresolved;\n const isRefetching = isFetching && !isUnresolved;\n\n // Consumers always destructure the return value and use the fields directly, so\n // memoizing the object doesn't change rerender behavior nor improve any performance here\n return {\n data,\n error: state.error,\n config: state.config,\n headers: state.headers,\n isFirstFetch,\n isFetching,\n isLoading: isFetching,\n isRefetching,\n isError: state.isError,\n isSuccess: state.isSuccess,\n mutate: state.mutate,\n refetch,\n };\n}\n"]} \ No newline at end of file diff --git a/dist/react/index.mjs b/dist/react/index.mjs index 450fd2e3..f83dd041 100644 --- a/dist/react/index.mjs +++ b/dist/react/index.mjs @@ -1,2 +1,2 @@ -import {useMemo,useRef,useCallback,useSyncExternalStore}from'react';import {generateCacheKey,buildConfig,getCache,getInFlightPromise,fetchf,getCachedResponse,subscribe,addTimeout,abortRequest,deleteCache}from'fetchff';var F=-1,D=2e3,m=new Map,q=e=>{e&&m.set(e,(m.get(e)||0)+1);},A=(e,t,s,o)=>{if(!e)return;let a=f(e);if(!a)return;let i=a-1;i<=0?(m.delete(e),t===F&&addTimeout("r:"+e,()=>{abortRequest(e,new DOMException("Request to "+o+" aborted","AbortError")),f(e)||deleteCache(e,true);},s!=null?s:D)):m.set(e,i);},f=e=>e&&m.get(e)||0;var Y=300,x=Object.freeze({data:null,error:null,isFetching:false,mutate:()=>Promise.resolve(null),config:{},headers:{}}),K=Object.freeze({...x,isFetching:true}),Z=[null,{},null],$=new Set(["GET","HEAD","get","head"]);function ae(e,t={}){var b,U,_;let s=useMemo(()=>e===null?null:generateCacheKey(buildConfig(e,t)),[t.cacheKey,e,t.url,t.method,t.headers,t.body,t.params,t.urlPathParams,t.apiUrl,t.baseURL,t.withCredentials,t.credentials]),o=(b=t.dedupeTime)!=null?b:D,a=t.cacheTime||F,i=(U=t.staleTime)!=null?U:Y,R=(_=t.immediate)!=null?_:$.has(t.method||"GET"),P=useRef(Z);P.current=[e,t,s];let g=useCallback(()=>{let r=getCache(s);if(t.strategy==="reject"&&s&&(!r||!r.data.data&&!r.data.error)){let h=getInFlightPromise(s,o);if(h)throw h;if(!r){let[u,c,l]=P.current;if(u)throw fetchf(u,{...c,cacheKey:l,dedupeTime:o,cacheTime:a,staleTime:i,strategy:"softFail",cacheErrors:true,_isAutoKey:!c.cacheKey})}}return r?r.data.isFetching&&!t.keepPreviousData?K:r.data:R?K:x},[s]),B=useCallback(r=>{q(s),R&&e&&s&&f(s)===1&&(getCachedResponse(s,a,t)||C(false));let u=subscribe(s,r);return ()=>{A(s,a,o,e),u();}},[s,R,e,o,a]),n=useSyncExternalStore(B,g,g),C=useCallback(async(r=true,h={})=>{let[u,c,l]=P.current;if(!u)return Promise.resolve(null);let E=!!r;if(!E&&l){let S=getCachedResponse(l,a,c);if(S)return Promise.resolve(S)}let Q=E?()=>true:c.cacheBuster;return fetchf(u,{...c,cacheKey:l,...h,dedupeTime:o,cacheTime:a,staleTime:i,cacheBuster:Q,strategy:"softFail",cacheErrors:true,_isAutoKey:!c.cacheKey})},[a,o]),T=n.data,p=!T&&!n.error,d=!!e&&(n.isFetching||p&&R),L=d&&p,w=d&&!p;return {data:T,error:n.error,config:n.config,headers:n.headers,isFirstFetch:L,isFetching:d,isLoading:d,isRefetching:w,isError:n.isError,isSuccess:n.isSuccess,mutate:n.mutate,refetch:C}}export{ae as useFetcher};//# sourceMappingURL=index.mjs.map +import {useMemo,useRef,useCallback,useSyncExternalStore}from'react';import {generateCacheKey,buildConfig,getCache,getInFlightPromise,fetchf,getCachedResponse,subscribe,addTimeout,abortRequest,createAbortError,deleteCache}from'fetchff';var F=-1,y=2e3,m=new Map,S=e=>{e&&m.set(e,(m.get(e)||0)+1);},q=(e,t,r,o)=>{if(!e)return;let a=f(e);if(!a)return;let i=a-1;i<=0?(m.delete(e),t===F&&addTimeout("r:"+e,()=>{abortRequest(e,createAbortError("Request to "+o+" aborted","AbortError")),f(e)||deleteCache(e,true);},r!=null?r:y)):m.set(e,i);},f=e=>e&&m.get(e)||0;var Z=300,B=Object.freeze({data:null,error:null,isFetching:false,mutate:()=>Promise.resolve(null),config:{},headers:{}}),K=Object.freeze({...B,isFetching:true}),$=[null,{},null],k=new Set(["GET","HEAD","get","head"]);function ne(e,t={}){var b,U,_;let r=useMemo(()=>e===null?null:generateCacheKey(buildConfig(e,t)),[t.cacheKey,e,t.url,t.method,t.headers,t.body,t.params,t.urlPathParams,t.apiUrl,t.baseURL,t.withCredentials,t.credentials]),o=(b=t.dedupeTime)!=null?b:y,a=t.cacheTime||F,i=(U=t.staleTime)!=null?U:Z,R=(_=t.immediate)!=null?_:k.has(t.method||"GET"),P=useRef($);P.current=[e,t,r];let g=useCallback(()=>{let s=getCache(r);if(t.strategy==="reject"&&r&&(!s||!s.data.data&&!s.data.error)){let h=getInFlightPromise(r,o);if(h)throw h;if(!s){let[u,c,l]=P.current;if(u)throw fetchf(u,{...c,cacheKey:l,dedupeTime:o,cacheTime:a,staleTime:i,strategy:"softFail",cacheErrors:true,_isAutoKey:!c.cacheKey})}}return s?s.data.isFetching&&!t.keepPreviousData?K:s.data:R?K:B},[r]),L=useCallback(s=>{S(r),R&&e&&r&&f(r)===1&&(getCachedResponse(r,a,t)||C(false));let u=subscribe(r,s);return ()=>{q(r,a,o,e),u();}},[r,R,e,o,a]),n=useSyncExternalStore(L,g,g),C=useCallback(async(s=true,h={})=>{let[u,c,l]=P.current;if(!u)return Promise.resolve(null);let E=!!s;if(!E&&l){let A=getCachedResponse(l,a,c);if(A)return Promise.resolve(A)}let Q=E?()=>true:c.cacheBuster;return fetchf(u,{...c,cacheKey:l,...h,dedupeTime:o,cacheTime:a,staleTime:i,cacheBuster:Q,strategy:"softFail",cacheErrors:true,_isAutoKey:!c.cacheKey})},[a,o]),T=n.data,p=!T&&!n.error,d=!!e&&(n.isFetching||p&&R),x=d&&p,w=d&&!p;return {data:T,error:n.error,config:n.config,headers:n.headers,isFirstFetch:x,isFetching:d,isLoading:d,isRefetching:w,isError:n.isError,isSuccess:n.isSuccess,mutate:n.mutate,refetch:C}}export{ne as useFetcher};//# sourceMappingURL=index.mjs.map //# sourceMappingURL=index.mjs.map \ No newline at end of file diff --git a/dist/react/index.mjs.map b/dist/react/index.mjs.map index 624fec04..e7f0930c 100644 --- a/dist/react/index.mjs.map +++ b/dist/react/index.mjs.map @@ -1 +1 @@ -{"version":3,"sources":["../../src/react/cache-ref.ts","../../src/react/index.ts"],"names":["INFINITE_CACHE_TIME","DEFAULT_DEDUPE_TIME_MS","refs","incrementRef","key","decrementRef","cacheTime","dedupeTime","url","current","getRefCount","newCount","addTimeout","abortRequest","deleteCache","DEFAULT_STALE_TIME","DEFAULT_RESULT","FETCHING_RESULT","DEFAULT_REF","SAFE_METHODS","useFetcher","config","_a","_b","_c","cacheKey","useMemo","generateCacheKey","buildConfig","staleTime","shouldTriggerOnMount","currentValuesRef","useRef","getSnapshot","useCallback","cached","getCache","pendingPromise","getInFlightPromise","currUrl","currConfig","currCacheKey","fetchf","doSubscribe","cb","getCachedResponse","refetch","unsubscribe","subscribe","state","useSyncExternalStore","forceRefresh","requestConfig","shouldRefresh","cacheBuster","data","isUnresolved","isFetching","isFirstFetch","isRefetching"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @module cache-ref\n *\n * Provides reference counting utilities for cache management in React applications.\n *\n * This module maintains an internal reference count for cache keys, allowing for\n * precise control over when cache entries should be deleted. It exports functions\n * to increment and decrement reference counts, retrieve the current count, and clear\n * all reference counts. When a reference count drops to zero and certain conditions\n * are met, the corresponding cache entry is scheduled for deletion.\n *\n * @see deleteCache\n */\n\nimport { addTimeout, abortRequest, deleteCache } from 'fetchff';\n\nexport const INFINITE_CACHE_TIME = -1;\nexport const DEFAULT_DEDUPE_TIME_MS = 2000;\n\nconst refs = new Map();\n\nexport const incrementRef = (key: string | null) => {\n if (key) {\n refs.set(key, (refs.get(key) || 0) + 1);\n }\n};\n\nexport const decrementRef = (\n key: string | null,\n cacheTime?: number,\n dedupeTime?: number,\n url?: string | null,\n) => {\n if (!key) {\n return;\n }\n\n const current = getRefCount(key);\n\n if (!current) {\n return;\n }\n\n const newCount = current - 1;\n\n // If the current reference count is less than 2, we can consider deleting the global cache entry\n // The infinite cache time is a special case where we never delete the cache entry unless the reference count drops to zero.\n // This allows for long-lived cache entries that are only deleted when explicitly no longer needed.\n if (newCount <= 0) {\n refs.delete(key);\n\n if (cacheTime && cacheTime === INFINITE_CACHE_TIME) {\n // Delay to ensure all operations are complete before deletion\n addTimeout(\n 'r:' + key,\n () => {\n // Abort any ongoing requests associated with this cache key\n abortRequest(\n key,\n new DOMException('Request to ' + url + ' aborted', 'AbortError'),\n );\n\n // Check if the reference count is still zero before deleting the cache as it might have been incremented again\n // This is to ensure that if another increment happens during the timeout, we don't delete the cache prematurely\n // This is particularly useful in scenarios where multiple components might be using the same cache\n // entry and we want to avoid unnecessary cache deletions.\n if (!getRefCount(key)) {\n deleteCache(key, true);\n }\n },\n dedupeTime ?? DEFAULT_DEDUPE_TIME_MS,\n );\n }\n } else {\n refs.set(key, newCount);\n }\n};\n\nexport const getRefCount = (key: string | null): number => {\n if (!key) {\n return 0;\n }\n\n return refs.get(key) || 0;\n};\n\nexport const getRefs = (): Map => {\n return refs;\n};\n\nexport const clearRefCache = () => {\n refs.clear();\n};\n","import { useCallback, useSyncExternalStore, useMemo, useRef } from 'react';\nimport {\n fetchf,\n subscribe,\n buildConfig,\n generateCacheKey,\n getCachedResponse,\n getInFlightPromise,\n getCache,\n} from 'fetchff';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '..';\nimport type { RefetchFunction, UseFetcherResult } from '../types/react-hooks';\n\nimport {\n decrementRef,\n DEFAULT_DEDUPE_TIME_MS,\n getRefCount,\n incrementRef,\n INFINITE_CACHE_TIME,\n} from './cache-ref';\n\n// In React, we use a default stale time of 5 minutes (SWR)\nconst DEFAULT_STALE_TIME = 300; // 5 minutes\n\n// Pre-allocate objects to avoid GC pressure\nconst DEFAULT_RESULT = Object.freeze({\n data: null,\n error: null,\n isFetching: false,\n mutate: () => Promise.resolve(null),\n config: {},\n headers: {},\n});\n\nconst FETCHING_RESULT = Object.freeze({\n ...DEFAULT_RESULT,\n isFetching: true,\n});\n\nconst DEFAULT_REF = [null, {}, null] as [\n string | null,\n RequestConfig,\n string | null,\n];\n\n// RFC 7231: GET and HEAD are \"safe methods\" with no side effects\nconst SAFE_METHODS = new Set(['GET', 'HEAD', 'get', 'head']);\n\n/**\n * High-performance React hook for fetching data with caching, deduplication, revalidation etc.\n *\n * @template ResponseData - The expected response data type.\n * @template RequestBody - The request payload type.\n * @template QueryParams - The query parameters type.\n * @template PathParams - The URL path parameters type.\n *\n * @param {string|null} url - The endpoint URL to fetch data from. Pass null to skip fetching.\n * If the URL is null, the hook will not perform any fetch operation.\n * If the URL is an empty string, it will default to the base URL configured in fetchff.\n * If the URL is a full URL, it will be used as is.\n * @param {RequestConfig} [config={}] - fetchff and native fetch compatible configuration.\n *\n * @returns {UseFetcherResult} An object containing:\n * - `data`: The fetched data or `null` if not yet available.\n * - `error`: Any error encountered during fetching or `null`.\n * - `isLoading`: Boolean indicating if the request is in progress.\n * - `mutate`: Function to update the cached data and optionally trigger revalidation.\n *\n * @remarks\n * - Designed for high performance: minimizes unnecessary re-renders and leverages fast cache key generation.\n * - Integrates with a global cache and pub/sub system for efficient state updates across contexts.\n * - Handles automatic revalidation, deduplication, retries, and cache management out of the box.\n *\n * @example\n * ```tsx\n * const { data, error, isLoading, mutate } = useFetcher('/api/data', {\n * refetchOnFocus: true,\n * cacheTime: 5,\n * dedupeTime: 2000,\n * cacheKey: (config) => `custom-cache-key-${config.url}`,\n * });\n * ```\n */\nexport function useFetcher<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n url: string | null,\n config: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > = {},\n): UseFetcherResult {\n // Efficient cache key generation based on URL and request parameters.\n // Optimized for speed: minimizes unnecessary function calls when possible\n const cacheKey = useMemo(\n () => (url === null ? null : generateCacheKey(buildConfig(url, config))),\n [\n config.cacheKey,\n url,\n config.url,\n config.method,\n config.headers,\n config.body,\n config.params,\n config.urlPathParams,\n config.apiUrl,\n config.baseURL,\n config.withCredentials,\n config.credentials,\n ],\n );\n const dedupeTime = config.dedupeTime ?? DEFAULT_DEDUPE_TIME_MS;\n const cacheTime = config.cacheTime || INFINITE_CACHE_TIME;\n const staleTime = config.staleTime ?? DEFAULT_STALE_TIME;\n\n // Determine if the fetch should be triggered immediately on mount\n const shouldTriggerOnMount =\n config.immediate ?? SAFE_METHODS.has(config.method || 'GET');\n\n const currentValuesRef = useRef(DEFAULT_REF);\n currentValuesRef.current = [url, config, cacheKey];\n\n // Attempt to get the cached response immediately and if not available, return null\n const getSnapshot = useCallback(() => {\n const cached = getCache(\n cacheKey,\n );\n\n // Only throw for Suspense if we're in 'reject' mode and have no data\n if (\n config.strategy === 'reject' &&\n cacheKey &&\n (!cached || (!cached.data.data && !cached.data.error))\n ) {\n const pendingPromise = getInFlightPromise(cacheKey, dedupeTime);\n\n if (pendingPromise) {\n throw pendingPromise;\n }\n\n // If no pending promise but we need to fetch, start fetch and throw the promise\n if (!cached) {\n const [currUrl, currConfig, currCacheKey] = currentValuesRef.current;\n\n if (currUrl) {\n const fetchPromise = fetchf(currUrl, {\n ...currConfig,\n cacheKey: currCacheKey,\n dedupeTime,\n cacheTime,\n staleTime,\n strategy: 'softFail',\n cacheErrors: true,\n _isAutoKey: !currConfig.cacheKey,\n });\n\n throw fetchPromise;\n }\n }\n }\n\n if (cached) {\n return cached.data.isFetching && !config.keepPreviousData\n ? (FETCHING_RESULT as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >)\n : cached.data;\n }\n\n return (shouldTriggerOnMount\n ? FETCHING_RESULT\n : DEFAULT_RESULT) as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }, [cacheKey]);\n\n // Subscribe to cache updates for the specific cache key\n const doSubscribe = useCallback(\n (cb: () => void) => {\n incrementRef(cacheKey);\n\n // When the component mounts, we want to fetch data if:\n // 1. URL is provided\n // 2. shouldTriggerOnMount is true (so the \"immediate\" isn't specified or is true)\n // 3. There is no cached data\n // 4. There is no error\n // 5. There is no ongoing fetch operation\n const shouldFetch =\n shouldTriggerOnMount && url && cacheKey && getRefCount(cacheKey) === 1; // Check if no existing refs\n\n // Initial fetch logic\n if (shouldFetch) {\n // Stale-While-Revalidate Pattern: Check for both fresh and stale data\n const cached = getCachedResponse(cacheKey, cacheTime, config);\n\n if (!cached) {\n refetch(false);\n }\n }\n\n const unsubscribe = subscribe(cacheKey, cb);\n\n return () => {\n decrementRef(cacheKey, cacheTime, dedupeTime, url);\n unsubscribe();\n };\n },\n [cacheKey, shouldTriggerOnMount, url, dedupeTime, cacheTime],\n );\n\n const state = useSyncExternalStore<\n FetchResponse\n >(doSubscribe, getSnapshot, getSnapshot);\n\n const refetch = useCallback<\n RefetchFunction\n >(\n async (forceRefresh = true, requestConfig = {}) => {\n const [currUrl, currConfig, currCacheKey] = currentValuesRef.current;\n\n if (!currUrl) {\n return Promise.resolve(null);\n }\n\n // Truthy check for forceRefresh to ensure it's a boolean. It is useful in onClick handlers so to avoid additional annonymous function calls.\n const shouldRefresh = !!forceRefresh;\n\n // Fast path: check cache first if not forcing refresh\n if (!shouldRefresh && currCacheKey) {\n const cached = getCachedResponse(currCacheKey, cacheTime, currConfig);\n\n if (cached) {\n return Promise.resolve(cached);\n }\n }\n\n // When manual refetch is triggered, we want to ensure that the cache is busted\n // This can be disabled by passing `refetch(false)`\n const cacheBuster = shouldRefresh ? () => true : currConfig.cacheBuster;\n\n return fetchf(currUrl, {\n ...currConfig,\n cacheKey: currCacheKey,\n ...requestConfig,\n dedupeTime,\n cacheTime,\n staleTime,\n cacheBuster,\n // Ensure that errors are handled gracefully and not thrown by default\n strategy: 'softFail',\n cacheErrors: true,\n _isAutoKey: !currConfig.cacheKey,\n });\n },\n [cacheTime, dedupeTime],\n );\n\n const data = state.data;\n const isUnresolved = !data && !state.error;\n\n // This indicates if the request is in progress or if it is about to start on first mount\n // It is true when:\n // - The request is currently ongoing, and it is not background revalidation\n // - The request is unresolved (no data and no error) and shouldTriggerOnMount\n // is true (which means the request is about to start on mount)\n const isFetching =\n !!url && (state.isFetching || (isUnresolved && shouldTriggerOnMount));\n const isFirstFetch = isFetching && isUnresolved;\n const isRefetching = isFetching && !isUnresolved;\n\n // Consumers always destructure the return value and use the fields directly, so\n // memoizing the object doesn't change rerender behavior nor improve any performance here\n return {\n data,\n error: state.error,\n config: state.config,\n headers: state.headers,\n isFirstFetch,\n isFetching,\n isLoading: isFetching,\n isRefetching,\n isError: state.isError,\n isSuccess: state.isSuccess,\n mutate: state.mutate,\n refetch,\n };\n}\n"]} \ No newline at end of file +{"version":3,"sources":["../../src/react/cache-ref.ts","../../src/react/index.ts"],"names":["INFINITE_CACHE_TIME","DEFAULT_DEDUPE_TIME_MS","refs","incrementRef","key","decrementRef","cacheTime","dedupeTime","url","current","getRefCount","newCount","addTimeout","abortRequest","createAbortError","deleteCache","DEFAULT_STALE_TIME","DEFAULT_RESULT","FETCHING_RESULT","DEFAULT_REF","SAFE_METHODS","useFetcher","config","_a","_b","_c","cacheKey","useMemo","generateCacheKey","buildConfig","staleTime","shouldTriggerOnMount","currentValuesRef","useRef","getSnapshot","useCallback","cached","getCache","pendingPromise","getInFlightPromise","currUrl","currConfig","currCacheKey","fetchf","doSubscribe","cb","getCachedResponse","refetch","unsubscribe","subscribe","state","useSyncExternalStore","forceRefresh","requestConfig","shouldRefresh","cacheBuster","data","isUnresolved","isFetching","isFirstFetch","isRefetching"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @module cache-ref\n *\n * Provides reference counting utilities for cache management in React applications.\n *\n * This module maintains an internal reference count for cache keys, allowing for\n * precise control over when cache entries should be deleted. It exports functions\n * to increment and decrement reference counts, retrieve the current count, and clear\n * all reference counts. When a reference count drops to zero and certain conditions\n * are met, the corresponding cache entry is scheduled for deletion.\n *\n * @see deleteCache\n */\n\nimport {\n addTimeout,\n abortRequest,\n deleteCache,\n createAbortError,\n} from 'fetchff';\n\nexport const INFINITE_CACHE_TIME = -1;\nexport const DEFAULT_DEDUPE_TIME_MS = 2000;\n\nconst refs = new Map();\n\nexport const incrementRef = (key: string | null) => {\n if (key) {\n refs.set(key, (refs.get(key) || 0) + 1);\n }\n};\n\nexport const decrementRef = (\n key: string | null,\n cacheTime?: number,\n dedupeTime?: number,\n url?: string | null,\n) => {\n if (!key) {\n return;\n }\n\n const current = getRefCount(key);\n\n if (!current) {\n return;\n }\n\n const newCount = current - 1;\n\n // If the current reference count is less than 2, we can consider deleting the global cache entry\n // The infinite cache time is a special case where we never delete the cache entry unless the reference count drops to zero.\n // This allows for long-lived cache entries that are only deleted when explicitly no longer needed.\n if (newCount <= 0) {\n refs.delete(key);\n\n if (cacheTime && cacheTime === INFINITE_CACHE_TIME) {\n // Delay to ensure all operations are complete before deletion\n addTimeout(\n 'r:' + key,\n () => {\n // Abort any ongoing requests associated with this cache key\n abortRequest(\n key,\n createAbortError('Request to ' + url + ' aborted', 'AbortError'),\n );\n\n // Check if the reference count is still zero before deleting the cache as it might have been incremented again\n // This is to ensure that if another increment happens during the timeout, we don't delete the cache prematurely\n // This is particularly useful in scenarios where multiple components might be using the same cache\n // entry and we want to avoid unnecessary cache deletions.\n if (!getRefCount(key)) {\n deleteCache(key, true);\n }\n },\n dedupeTime ?? DEFAULT_DEDUPE_TIME_MS,\n );\n }\n } else {\n refs.set(key, newCount);\n }\n};\n\nexport const getRefCount = (key: string | null): number => {\n if (!key) {\n return 0;\n }\n\n return refs.get(key) || 0;\n};\n\nexport const getRefs = (): Map => {\n return refs;\n};\n\nexport const clearRefCache = () => {\n refs.clear();\n};\n","import { useCallback, useSyncExternalStore, useMemo, useRef } from 'react';\nimport {\n fetchf,\n subscribe,\n buildConfig,\n generateCacheKey,\n getCachedResponse,\n getInFlightPromise,\n getCache,\n} from 'fetchff';\nimport type {\n DefaultParams,\n DefaultPayload,\n DefaultResponse,\n DefaultUrlParams,\n FetchResponse,\n RequestConfig,\n} from '..';\nimport type { RefetchFunction, UseFetcherResult } from '../types/react-hooks';\n\nimport {\n decrementRef,\n DEFAULT_DEDUPE_TIME_MS,\n getRefCount,\n incrementRef,\n INFINITE_CACHE_TIME,\n} from './cache-ref';\n\n// In React, we use a default stale time of 5 minutes (SWR)\nconst DEFAULT_STALE_TIME = 300; // 5 minutes\n\n// Pre-allocate objects to avoid GC pressure\nconst DEFAULT_RESULT = Object.freeze({\n data: null,\n error: null,\n isFetching: false,\n mutate: () => Promise.resolve(null),\n config: {},\n headers: {},\n});\n\nconst FETCHING_RESULT = Object.freeze({\n ...DEFAULT_RESULT,\n isFetching: true,\n});\n\nconst DEFAULT_REF = [null, {}, null] as [\n string | null,\n RequestConfig,\n string | null,\n];\n\n// RFC 7231: GET and HEAD are \"safe methods\" with no side effects\nconst SAFE_METHODS = new Set(['GET', 'HEAD', 'get', 'head']);\n\n/**\n * High-performance React hook for fetching data with caching, deduplication, revalidation etc.\n *\n * @template ResponseData - The expected response data type.\n * @template RequestBody - The request payload type.\n * @template QueryParams - The query parameters type.\n * @template PathParams - The URL path parameters type.\n *\n * @param {string|null} url - The endpoint URL to fetch data from. Pass null to skip fetching.\n * If the URL is null, the hook will not perform any fetch operation.\n * If the URL is an empty string, it will default to the base URL configured in fetchff.\n * If the URL is a full URL, it will be used as is.\n * @param {RequestConfig} [config={}] - fetchff and native fetch compatible configuration.\n *\n * @returns {UseFetcherResult} An object containing:\n * - `data`: The fetched data or `null` if not yet available.\n * - `error`: Any error encountered during fetching or `null`.\n * - `isLoading`: Boolean indicating if the request is in progress.\n * - `mutate`: Function to update the cached data and optionally trigger revalidation.\n *\n * @remarks\n * - Designed for high performance: minimizes unnecessary re-renders and leverages fast cache key generation.\n * - Integrates with a global cache and pub/sub system for efficient state updates across contexts.\n * - Handles automatic revalidation, deduplication, retries, and cache management out of the box.\n *\n * @example\n * ```tsx\n * const { data, error, isLoading, mutate } = useFetcher('/api/data', {\n * refetchOnFocus: true,\n * cacheTime: 5,\n * dedupeTime: 2000,\n * cacheKey: (config) => `custom-cache-key-${config.url}`,\n * });\n * ```\n */\nexport function useFetcher<\n ResponseData = DefaultResponse,\n RequestBody = DefaultPayload,\n QueryParams = DefaultParams,\n PathParams = DefaultUrlParams,\n>(\n url: string | null,\n config: RequestConfig<\n ResponseData,\n QueryParams,\n PathParams,\n RequestBody\n > = {},\n): UseFetcherResult {\n // Efficient cache key generation based on URL and request parameters.\n // Optimized for speed: minimizes unnecessary function calls when possible\n const cacheKey = useMemo(\n () => (url === null ? null : generateCacheKey(buildConfig(url, config))),\n [\n config.cacheKey,\n url,\n config.url,\n config.method,\n config.headers,\n config.body,\n config.params,\n config.urlPathParams,\n config.apiUrl,\n config.baseURL,\n config.withCredentials,\n config.credentials,\n ],\n );\n const dedupeTime = config.dedupeTime ?? DEFAULT_DEDUPE_TIME_MS;\n const cacheTime = config.cacheTime || INFINITE_CACHE_TIME;\n const staleTime = config.staleTime ?? DEFAULT_STALE_TIME;\n\n // Determine if the fetch should be triggered immediately on mount\n const shouldTriggerOnMount =\n config.immediate ?? SAFE_METHODS.has(config.method || 'GET');\n\n const currentValuesRef = useRef(DEFAULT_REF);\n currentValuesRef.current = [url, config, cacheKey];\n\n // Attempt to get the cached response immediately and if not available, return null\n const getSnapshot = useCallback(() => {\n const cached = getCache(\n cacheKey,\n );\n\n // Only throw for Suspense if we're in 'reject' mode and have no data\n if (\n config.strategy === 'reject' &&\n cacheKey &&\n (!cached || (!cached.data.data && !cached.data.error))\n ) {\n const pendingPromise = getInFlightPromise(cacheKey, dedupeTime);\n\n if (pendingPromise) {\n throw pendingPromise;\n }\n\n // If no pending promise but we need to fetch, start fetch and throw the promise\n if (!cached) {\n const [currUrl, currConfig, currCacheKey] = currentValuesRef.current;\n\n if (currUrl) {\n const fetchPromise = fetchf(currUrl, {\n ...currConfig,\n cacheKey: currCacheKey,\n dedupeTime,\n cacheTime,\n staleTime,\n strategy: 'softFail',\n cacheErrors: true,\n _isAutoKey: !currConfig.cacheKey,\n });\n\n throw fetchPromise;\n }\n }\n }\n\n if (cached) {\n return cached.data.isFetching && !config.keepPreviousData\n ? (FETCHING_RESULT as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >)\n : cached.data;\n }\n\n return (shouldTriggerOnMount\n ? FETCHING_RESULT\n : DEFAULT_RESULT) as unknown as FetchResponse<\n ResponseData,\n RequestBody,\n QueryParams,\n PathParams\n >;\n }, [cacheKey]);\n\n // Subscribe to cache updates for the specific cache key\n const doSubscribe = useCallback(\n (cb: () => void) => {\n incrementRef(cacheKey);\n\n // When the component mounts, we want to fetch data if:\n // 1. URL is provided\n // 2. shouldTriggerOnMount is true (so the \"immediate\" isn't specified or is true)\n // 3. There is no cached data\n // 4. There is no error\n // 5. There is no ongoing fetch operation\n const shouldFetch =\n shouldTriggerOnMount && url && cacheKey && getRefCount(cacheKey) === 1; // Check if no existing refs\n\n // Initial fetch logic\n if (shouldFetch) {\n // Stale-While-Revalidate Pattern: Check for both fresh and stale data\n const cached = getCachedResponse(cacheKey, cacheTime, config);\n\n if (!cached) {\n refetch(false);\n }\n }\n\n const unsubscribe = subscribe(cacheKey, cb);\n\n return () => {\n decrementRef(cacheKey, cacheTime, dedupeTime, url);\n unsubscribe();\n };\n },\n [cacheKey, shouldTriggerOnMount, url, dedupeTime, cacheTime],\n );\n\n const state = useSyncExternalStore<\n FetchResponse\n >(doSubscribe, getSnapshot, getSnapshot);\n\n const refetch = useCallback<\n RefetchFunction\n >(\n async (forceRefresh = true, requestConfig = {}) => {\n const [currUrl, currConfig, currCacheKey] = currentValuesRef.current;\n\n if (!currUrl) {\n return Promise.resolve(null);\n }\n\n // Truthy check for forceRefresh to ensure it's a boolean. It is useful in onClick handlers so to avoid additional annonymous function calls.\n const shouldRefresh = !!forceRefresh;\n\n // Fast path: check cache first if not forcing refresh\n if (!shouldRefresh && currCacheKey) {\n const cached = getCachedResponse(currCacheKey, cacheTime, currConfig);\n\n if (cached) {\n return Promise.resolve(cached);\n }\n }\n\n // When manual refetch is triggered, we want to ensure that the cache is busted\n // This can be disabled by passing `refetch(false)`\n const cacheBuster = shouldRefresh ? () => true : currConfig.cacheBuster;\n\n return fetchf(currUrl, {\n ...currConfig,\n cacheKey: currCacheKey,\n ...requestConfig,\n dedupeTime,\n cacheTime,\n staleTime,\n cacheBuster,\n // Ensure that errors are handled gracefully and not thrown by default\n strategy: 'softFail',\n cacheErrors: true,\n _isAutoKey: !currConfig.cacheKey,\n });\n },\n [cacheTime, dedupeTime],\n );\n\n const data = state.data;\n const isUnresolved = !data && !state.error;\n\n // This indicates if the request is in progress or if it is about to start on first mount\n // It is true when:\n // - The request is currently ongoing, and it is not background revalidation\n // - The request is unresolved (no data and no error) and shouldTriggerOnMount\n // is true (which means the request is about to start on mount)\n const isFetching =\n !!url && (state.isFetching || (isUnresolved && shouldTriggerOnMount));\n const isFirstFetch = isFetching && isUnresolved;\n const isRefetching = isFetching && !isUnresolved;\n\n // Consumers always destructure the return value and use the fields directly, so\n // memoizing the object doesn't change rerender behavior nor improve any performance here\n return {\n data,\n error: state.error,\n config: state.config,\n headers: state.headers,\n isFirstFetch,\n isFetching,\n isLoading: isFetching,\n isRefetching,\n isError: state.isError,\n isSuccess: state.isSuccess,\n mutate: state.mutate,\n refetch,\n };\n}\n"]} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index b1efd141..3f2be16b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,26 +11,26 @@ "devDependencies": { "@size-limit/preset-small-lib": "12.0.0", "@testing-library/jest-dom": "6.9.1", - "@testing-library/react": "16.3.0", + "@testing-library/react": "16.3.2", "@types/jest": "30.0.0", - "@types/react": "19.2.7", + "@types/react": "19.2.13", "benchmark": "2.1.4", "eslint": "9.39.1", "eslint-config-prettier": "10.1.8", - "eslint-plugin-prettier": "5.5.4", + "eslint-plugin-prettier": "5.5.5", "fetch-mock": "12.6.0", - "globals": "16.5.0", + "globals": "17.3.0", "jest": "30.2.0", "jest-environment-jsdom": "30.2.0", - "prettier": "3.7.4", - "react": "19.2.1", - "react-dom": "19.2.1", + "prettier": "3.8.1", + "react": "19.2.4", + "react-dom": "19.2.4", "size-limit": "12.0.0", "ts-jest": "29.4.6", "tslib": "2.8.1", "tsup": "8.5.1", "typescript": "5.9.3", - "typescript-eslint": "8.48.1" + "typescript-eslint": "8.54.0" }, "engines": { "node": ">=18" @@ -1165,9 +1165,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2428,9 +2428,9 @@ "license": "MIT" }, "node_modules/@testing-library/react": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz", - "integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==", + "version": "16.3.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", "dev": true, "license": "MIT", "dependencies": { @@ -2636,9 +2636,9 @@ } }, "node_modules/@types/react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", - "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", + "version": "19.2.13", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.13.tgz", + "integrity": "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2677,21 +2677,20 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.1.tgz", - "integrity": "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz", + "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.48.1", - "@typescript-eslint/type-utils": "8.48.1", - "@typescript-eslint/utils": "8.48.1", - "@typescript-eslint/visitor-keys": "8.48.1", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/type-utils": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2701,7 +2700,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.48.1", + "@typescript-eslint/parser": "^8.54.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -2717,17 +2716,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz", - "integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz", + "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.48.1", - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/typescript-estree": "8.48.1", - "@typescript-eslint/visitor-keys": "8.48.1", - "debug": "^4.3.4" + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2742,15 +2741,15 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.1.tgz", - "integrity": "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", + "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.48.1", - "@typescript-eslint/types": "^8.48.1", - "debug": "^4.3.4" + "@typescript-eslint/tsconfig-utils": "^8.54.0", + "@typescript-eslint/types": "^8.54.0", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2764,14 +2763,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.1.tgz", - "integrity": "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", + "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/visitor-keys": "8.48.1" + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2782,9 +2781,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.1.tgz", - "integrity": "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", + "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", "dev": true, "license": "MIT", "engines": { @@ -2799,17 +2798,17 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.1.tgz", - "integrity": "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz", + "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/typescript-estree": "8.48.1", - "@typescript-eslint/utils": "8.48.1", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2824,9 +2823,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz", - "integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", + "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", "dev": true, "license": "MIT", "engines": { @@ -2838,21 +2837,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.1.tgz", - "integrity": "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", + "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.48.1", - "@typescript-eslint/tsconfig-utils": "8.48.1", - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/visitor-keys": "8.48.1", - "debug": "^4.3.4", - "minimatch": "^9.0.4", - "semver": "^7.6.0", + "@typescript-eslint/project-service": "8.54.0", + "@typescript-eslint/tsconfig-utils": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2892,9 +2891,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "dev": true, "license": "ISC", "bin": { @@ -2905,16 +2904,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.1.tgz", - "integrity": "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", + "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.48.1", - "@typescript-eslint/types": "8.48.1", - "@typescript-eslint/typescript-estree": "8.48.1" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2929,13 +2928,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.1.tgz", - "integrity": "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", + "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -4198,14 +4197,14 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", - "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", + "version": "5.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", + "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", "dev": true, "license": "MIT", "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.11.7" + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.12" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -4675,9 +4674,9 @@ } }, "node_modules/globals": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", - "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.3.0.tgz", + "integrity": "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==", "dev": true, "license": "MIT", "engines": { @@ -4694,13 +4693,6 @@ "dev": true, "license": "ISC" }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, "node_modules/handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", @@ -6228,9 +6220,9 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", "dev": true, "license": "MIT" }, @@ -6915,9 +6907,9 @@ } }, "node_modules/prettier": { - "version": "3.7.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz", - "integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", "bin": { @@ -6931,9 +6923,9 @@ } }, "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", "dev": true, "license": "MIT", "dependencies": { @@ -7001,9 +6993,9 @@ "license": "MIT" }, "node_modules/react": { - "version": "19.2.1", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz", - "integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==", + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", + "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "dev": true, "license": "MIT", "engines": { @@ -7011,16 +7003,16 @@ } }, "node_modules/react-dom": { - "version": "19.2.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz", - "integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==", + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "dev": true, "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.1" + "react": "^19.2.4" } }, "node_modules/react-is": { @@ -7551,9 +7543,9 @@ "license": "MIT" }, "node_modules/synckit": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", - "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7758,9 +7750,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", "dev": true, "license": "MIT", "engines": { @@ -7987,16 +7979,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.48.1", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.1.tgz", - "integrity": "sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.54.0.tgz", + "integrity": "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.48.1", - "@typescript-eslint/parser": "8.48.1", - "@typescript-eslint/typescript-estree": "8.48.1", - "@typescript-eslint/utils": "8.48.1" + "@typescript-eslint/eslint-plugin": "8.54.0", + "@typescript-eslint/parser": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/utils": "8.54.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/package.json b/package.json index a3ffd9e9..b5df3e42 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "exports": { ".": { "types": "./dist/index.d.ts", + "react-native": "./dist/browser/index.mjs", "import": { "node": "./dist/node/index.js", "default": "./dist/browser/index.mjs" @@ -45,7 +46,8 @@ "http-client", "browser", "node", - "nodejs" + "nodejs", + "react-native" ], "engines": { "node": ">=18" @@ -87,32 +89,32 @@ }, { "path": "dist/react/index.js", - "limit": "9.5 KB" + "limit": "10 KB" } ], "devDependencies": { "@size-limit/preset-small-lib": "12.0.0", "@testing-library/jest-dom": "6.9.1", - "@testing-library/react": "16.3.0", + "@testing-library/react": "16.3.2", "@types/jest": "30.0.0", - "@types/react": "19.2.7", + "@types/react": "19.2.13", "benchmark": "2.1.4", "eslint": "9.39.1", "eslint-config-prettier": "10.1.8", - "eslint-plugin-prettier": "5.5.4", + "eslint-plugin-prettier": "5.5.5", "fetch-mock": "12.6.0", - "globals": "16.5.0", + "globals": "17.3.0", "jest": "30.2.0", "jest-environment-jsdom": "30.2.0", - "prettier": "3.7.4", - "react": "19.2.1", - "react-dom": "19.2.1", + "prettier": "3.8.1", + "react": "19.2.4", + "react-dom": "19.2.4", "size-limit": "12.0.0", "ts-jest": "29.4.6", "tslib": "2.8.1", "tsup": "8.5.1", "typescript": "5.9.3", - "typescript-eslint": "8.48.1" + "typescript-eslint": "8.54.0" }, "optionalDependencies": { "@rollup/rollup-linux-x64-gnu": "4.38.0" diff --git a/src/cache-manager.ts b/src/cache-manager.ts index 02b0bbdd..1942b1e4 100644 --- a/src/cache-manager.ts +++ b/src/cache-manager.ts @@ -23,7 +23,8 @@ export const IMMEDIATE_DISCARD_CACHE_TIME = 0; // Use it for cache entries that const _cache = new Map>(); const DELIMITER = '|'; const MIN_LENGTH_TO_HASH = 64; -const CACHE_KEY_SANITIZE_PATTERN = new RegExp('[^\\w\\-_|]', 'g'); +const CACHE_KEY_SANITIZE_PATTERN = /[^\w\-_|/:@.?=&~%#]/g; +const CACHE_KEY_NEEDS_SANITIZE = /[^\w\-_|/:@.?=&~%#]/; // Non-global for fast test /** * Headers that may affect HTTP response content and should be included in cache key generation. @@ -145,15 +146,18 @@ export function generateCacheKey( // For GET requests, return early with shorter cache key if (method === GET) { - return ( + const cacheStr = method + DELIMITER + url + DELIMITER + credentials + DELIMITER + - headersString - ).replace(CACHE_KEY_SANITIZE_PATTERN, ''); + headersString; + + return CACHE_KEY_NEEDS_SANITIZE.test(cacheStr) + ? cacheStr.replace(CACHE_KEY_SANITIZE_PATTERN, '') + : cacheStr; } let bodyString = ''; @@ -187,7 +191,7 @@ export function generateCacheKey( // Concatenate all key parts into a cache key string // Template literals are apparently slower - return ( + const cacheStr = method + DELIMITER + url + @@ -196,8 +200,12 @@ export function generateCacheKey( DELIMITER + headersString + DELIMITER + - bodyString - ).replace(CACHE_KEY_SANITIZE_PATTERN, ''); // Prevent cache poisoning by removal of anything that isn't letters, numbers, -, _, or | + bodyString; + + // Prevent cache poisoning by removal of control chars and unusual characters + return CACHE_KEY_NEEDS_SANITIZE.test(cacheStr) + ? cacheStr.replace(CACHE_KEY_SANITIZE_PATTERN, '') + : cacheStr; } /** @@ -215,20 +223,6 @@ function isCacheExpired(entry: CacheEntry): boolean { return timeNow() > entry.expiry; } -/** - * Checks if the cache entry is stale based on its timestamp and the stale time. - * - * @param {CacheEntry} entry - The cache entry to check. - * @returns {boolean} - Returns true if the cache entry is stale, false otherwise. - */ -function isCacheStale(entry: CacheEntry): boolean { - if (!entry.stale) { - return false; - } - - return timeNow() > entry.stale; -} - /** * Retrieves a cached response from the internal cache using the provided key. * @@ -290,11 +284,12 @@ export function setCache( const time = timeNow(); const ttlMs = ttl ? ttl * 1000 : 0; + const staleTimeMs = staleTime ? staleTime * 1000 : 0; // Ensure default value for staleTime _cache.set(key, { data, time, - stale: staleTime && staleTime > 0 ? time + staleTime * 1000 : staleTime, + stale: staleTimeMs > 0 ? time + staleTimeMs : undefined, // Use undefined if staleTime is not set expiry: ttl === -1 ? undefined : time + ttlMs, }); @@ -444,7 +439,6 @@ export function getCachedResponse< } const isExpired = isCacheExpired(entry); - const isStale = isCacheStale(entry); // If completely expired, delete and return null if (isExpired) { @@ -452,19 +446,8 @@ export function getCachedResponse< return null; } - // If fresh (not stale), return immediately - if (!isStale) { - return entry.data; - } - - // SWR: Data is stale but not expired - if (isStale && !isExpired) { - // Triggering background revalidation here could cause race conditions - // So we return stale data immediately and leave it up to implementers to handle revalidation - return entry.data; - } - - return null; + // Return data whether fresh or stale (SWR: serve stale, revalidation is timer-driven) + return entry.data; } /** diff --git a/src/config-handler.ts b/src/config-handler.ts index f2534cdd..89dad4ee 100644 --- a/src/config-handler.ts +++ b/src/config-handler.ts @@ -1,3 +1,4 @@ +import { processHeaders } from './utils'; import { GET, APPLICATION_JSON, @@ -65,9 +66,7 @@ export function setDefaultConfig( ): Partial { const sanitized = sanitizeObject(customConfig); - Object.assign(defaultConfig, sanitized); - - return defaultConfig; + return mergeConfigs({}, sanitized, defaultConfig); } /** @@ -208,26 +207,40 @@ function setContentTypeIfNeeded( } } +/** + * Merges two request configurations, applying overrides from the second config to the first. + * Handles special merging for nested properties like 'retry' and 'headers' (deep merge), + * and concatenates interceptor arrays for 'onRequest', 'onResponse', and 'onError'. + * If a target config is provided, it mutates that object; otherwise, creates a new one. + * + * @param {RequestConfig} baseConfig - The base configuration object to merge from. + * @param {RequestConfig} overrideConfig - The override configuration object to apply on top of the base. + * @param {RequestConfig} [targetConfig={}] - Optional target configuration object to merge into (mutated in place). + * @returns {RequestConfig} The merged configuration object. + * + * @example + * const base = { timeout: 5000, headers: { 'Accept': 'application/json' } }; + * const override = { timeout: 10000, headers: { 'Authorization': 'Bearer token' } }; + * const merged = mergeConfigs(base, override); + * // Result: { timeout: 10000, headers: { Accept: 'application/json', Authorization: 'Bearer token' } } + */ export function mergeConfigs( baseConfig: RequestConfig, overrideConfig: RequestConfig, + targetConfig: RequestConfig = {}, ): RequestConfig { - const mergedConfig: RequestConfig = Object.assign( - {}, - baseConfig, - overrideConfig, - ); + Object.assign(targetConfig, baseConfig, overrideConfig); // Ensure that retry and headers are merged correctly - mergeConfig('retry', mergedConfig, baseConfig, overrideConfig); - mergeConfig('headers', mergedConfig, baseConfig, overrideConfig); + mergeConfig('retry', baseConfig, overrideConfig, targetConfig); + mergeConfig('headers', baseConfig, overrideConfig, targetConfig); // Merge interceptors efficiently - mergeInterceptors('onRequest', mergedConfig, baseConfig, overrideConfig); - mergeInterceptors('onResponse', mergedConfig, baseConfig, overrideConfig); - mergeInterceptors('onError', mergedConfig, baseConfig, overrideConfig); + mergeInterceptors('onRequest', baseConfig, overrideConfig, targetConfig); + mergeInterceptors('onResponse', baseConfig, overrideConfig, targetConfig); + mergeInterceptors('onError', baseConfig, overrideConfig, targetConfig); - return mergedConfig; + return targetConfig; } /** @@ -237,9 +250,9 @@ function mergeInterceptors< K extends 'onRequest' | 'onResponse' | 'onError' | 'onRetry', >( property: K, - targetConfig: RequestConfig, baseConfig: RequestConfig, overrideConfig: RequestConfig, + targetConfig: RequestConfig, ): void { const baseInterceptor = baseConfig[property]; const newInterceptor = overrideConfig[property]; @@ -274,20 +287,38 @@ function mergeInterceptors< * Merges the specified property from the base configuration and the override configuration into the target configuration. * * @param {K} property - The property key to merge from the base and override configurations. Must be a key of RequestConfig. - * @param {RequestConfig} targetConfig - The configuration object that will receive the merged properties. * @param {RequestConfig} baseConfig - The base configuration object that provides default values. * @param {RequestConfig} overrideConfig - The override configuration object that contains user-specific settings to merge. + * @param {RequestConfig} targetConfig - The configuration object that will receive the merged properties. */ export function mergeConfig( property: K, - targetConfig: RequestConfig, baseConfig: RequestConfig, overrideConfig: RequestConfig, + targetConfig: RequestConfig, ): void { if (overrideConfig[property]) { - targetConfig[property] = { - ...baseConfig[property], - ...overrideConfig[property], - }; + const base = baseConfig[property]; + const override = overrideConfig[property]; + + // Handle Headers instances which don't expose entries as own enumerable properties + if ( + property === 'headers' && + ((base as Headers | (HeadersObject & HeadersInit)) instanceof Headers || + (override as Headers | (HeadersObject & HeadersInit)) instanceof + Headers) + ) { + const baseNormalized = processHeaders(base); + const overrideNormalized = processHeaders(override); + targetConfig[property] = { + ...baseNormalized, + ...overrideNormalized, + } as RequestConfig[K]; + } else { + targetConfig[property] = { + ...base, + ...override, + }; + } } } diff --git a/src/index.ts b/src/index.ts index b3c39351..fee9c4af 100644 --- a/src/index.ts +++ b/src/index.ts @@ -29,16 +29,19 @@ export { revalidate, // Revalidate specific cache entry revalidateAll, // Revalidate all entries by event type removeRevalidators, // Clean up all revalidators by type + setEventProvider, // Register custom event provider for focus/online events (e.g. React Native) } from './revalidator-manager'; +export type { EventProvider } from './revalidator-manager'; + /** Subscribe to cache updates via pub/sub */ export { subscribe } from './pubsub-manager'; /** Abort in-flight requests and check request status */ export { abortRequest, getInFlightPromise } from './inflight-manager'; -/** Network and environment utilities (Browser Only) */ -export { isSlowConnection } from './utils'; +/** Network and environment utilities */ +export { isSlowConnection, createAbortError } from './utils'; /** Timeout management for delayed operations */ export { addTimeout } from './timeout-wheel'; diff --git a/src/inflight-manager.ts b/src/inflight-manager.ts index dc70cbfa..4f5744ac 100644 --- a/src/inflight-manager.ts +++ b/src/inflight-manager.ts @@ -20,7 +20,7 @@ import { ABORT_ERROR, TIMEOUT_ERROR } from './constants'; import { addTimeout, removeTimeout } from './timeout-wheel'; -import { timeNow } from './utils'; +import { createAbortError, timeNow } from './utils'; export type InFlightItem = [ AbortController, // AbortController for the request @@ -55,6 +55,7 @@ export function markInFlight( return new AbortController(); } + const now = timeNow(); const item = inFlight.get(key); let prevPromise: Promise | null = null; @@ -66,7 +67,7 @@ export function markInFlight( // If the request is already in the queue and within the dedupeTime, reuse the existing controller if ( !prevIsCancellable && - timeNow() - item[2] < dedupeTime && + now - item[2] < dedupeTime && !prevController.signal.aborted ) { return prevController; @@ -76,7 +77,7 @@ export function markInFlight( // Abort previous request, if applicable, and continue as usual if (prevIsCancellable) { prevController.abort( - new DOMException('Aborted due to new request', ABORT_ERROR), + createAbortError('Aborted due to new request', ABORT_ERROR), ); } @@ -89,7 +90,7 @@ export function markInFlight( inFlight.set(key, [ controller, isTimeoutEnabled, - timeNow(), + now, isCancellable, prevPromise, ]); @@ -100,7 +101,7 @@ export function markInFlight( () => { abortRequest( key, - new DOMException(url + ' aborted due to timeout', TIMEOUT_ERROR), + createAbortError(url + ' aborted due to timeout', TIMEOUT_ERROR), ); }, timeout as number, @@ -119,7 +120,7 @@ export function markInFlight( */ export async function abortRequest( key: string | null, - error: DOMException | null | string = null, + error: DOMException | Error | null | string = null, ): Promise { // If the key is not in the queue, there's nothing to remove if (key) { @@ -173,10 +174,8 @@ export function setInFlightPromise( ): void { const item = inFlight.get(key); if (item) { - // store the promise at index 4 + // store the promise at index 4 — item is already the Map's reference, no need to re-set item[4] = promise; - - inFlight.set(key, item); } } diff --git a/src/pubsub-manager.ts b/src/pubsub-manager.ts index bbf0a0ec..3c5a218f 100644 --- a/src/pubsub-manager.ts +++ b/src/pubsub-manager.ts @@ -28,11 +28,14 @@ type Listener = (response: T) => void; const listeners = new Map>(); function ensureListenerSet(key: string) { - if (!listeners.has(key)) { - listeners.set(key, new Set()); + let set = listeners.get(key); + + if (!set) { + set = new Set(); + listeners.set(key, set); } - return listeners.get(key)!; + return set; } // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/src/react/cache-ref.ts b/src/react/cache-ref.ts index 1dacf322..d005a366 100644 --- a/src/react/cache-ref.ts +++ b/src/react/cache-ref.ts @@ -12,7 +12,12 @@ * @see deleteCache */ -import { addTimeout, abortRequest, deleteCache } from 'fetchff'; +import { + addTimeout, + abortRequest, + deleteCache, + createAbortError, +} from 'fetchff'; export const INFINITE_CACHE_TIME = -1; export const DEFAULT_DEDUPE_TIME_MS = 2000; @@ -57,7 +62,7 @@ export const decrementRef = ( // Abort any ongoing requests associated with this cache key abortRequest( key, - new DOMException('Request to ' + url + ' aborted', 'AbortError'), + createAbortError('Request to ' + url + ' aborted', 'AbortError'), ); // Check if the reference count is still zero before deleting the cache as it might have been incremented again diff --git a/src/request-handler.ts b/src/request-handler.ts index 8d1c74a0..d4fb8673 100644 --- a/src/request-handler.ts +++ b/src/request-handler.ts @@ -26,9 +26,9 @@ import { enhanceError, withErrorHandling } from './error-handler'; import { FUNCTION } from './constants'; import { buildConfig } from './config-handler'; -const inFlightResponse = { +const inFlightResponse = Object.freeze({ isFetching: true, -}; +}); /** * Sends an HTTP request to the specified URL using the provided configuration and returns a typed response. @@ -63,6 +63,22 @@ export async function fetchf< RequestBody > | null = null, ): Promise> { + // Ultra-fast early cache check if cacheKey is provided as a string + // For workloads dominated by repeated requests, this string caching optimization + // can potentially support millions of requests per second with minimal CPU overhead + if (reqConfig && typeof reqConfig.cacheKey === 'string') { + const cached = getCachedResponse< + ResponseData, + RequestBody, + QueryParams, + PathParams + >(reqConfig.cacheKey, reqConfig.cacheTime, reqConfig); + + if (cached) { + return cached; + } + } + const fetcherConfig = buildConfig< ResponseData, RequestBody, @@ -191,6 +207,16 @@ export async function fetchf< try { if (fetcherConfig.onRequest) { + // Zero-allocation yield to microtask queue so the outer fetchf() can call setInFlightPromise() + // before onRequest interceptors run. This ensures that if onRequest triggers + // another fetchf() with the same cacheKey, getInFlightPromise() finds item[4]. + // On retries (attempt > 0), setInFlightPromise() was already called during the first attempt. + // The promise stored in item[4] is the outer doRequestPromise which covers all retries. + // So the race only matters on the very first attempt when the outer scope hasn't had a chance to call setInFlightPromise() yet. + if (_cacheKey && dedupeTime && !attempt) { + await null; + } + await applyInterceptors(fetcherConfig.onRequest, requestConfig); } @@ -286,8 +312,16 @@ export async function fetchf< }; // Inline and minimize function wrappers for performance + // When retries are enabled, forward isStaleRevalidation so the first attempt + // of a background SWR revalidation doesn't incorrectly mark the request as in-flight const baseRequest = - retries > 0 ? () => withRetry(doRequestOnce, retryConfig) : doRequestOnce; + retries > 0 + ? (isStaleRevalidation = false) => + withRetry( + (_, attempt) => doRequestOnce(isStaleRevalidation, attempt), + retryConfig, + ) + : doRequestOnce; const requestWithErrorHandling = (isStaleRevalidation = false) => withErrorHandling( @@ -313,15 +347,18 @@ export async function fetchf< setInFlightPromise(_cacheKey, doRequestPromise); } - addRevalidator( - _cacheKey, - requestWithErrorHandling, - undefined, - staleTime, - requestWithErrorHandling, - !!refetchOnFocus, - !!refetchOnReconnect, - ); + // Only register revalidator when revalidation features are actually requested + if (staleTime || refetchOnFocus || refetchOnReconnect) { + addRevalidator( + _cacheKey, + requestWithErrorHandling, + undefined, + staleTime, + requestWithErrorHandling, + !!refetchOnFocus, + !!refetchOnReconnect, + ); + } } return doRequestPromise; diff --git a/src/revalidator-manager.ts b/src/revalidator-manager.ts index 18781647..ebab3c0d 100644 --- a/src/revalidator-manager.ts +++ b/src/revalidator-manager.ts @@ -40,15 +40,39 @@ const DEFAULT_TTL = 3 * 60 * 1000; // Default TTL of 3 minutes const revalidators = new Map(); /** - * Stores global event handlers for cache revalidation events (e.g., focus, online). - * This avoids attaching multiple event listeners by maintaining a single handler per event type. - * Event handlers are registered as needed when revalidators are registered with the corresponding flags. + * Stores cleanup functions for active event handlers (browser or custom providers). + * Each entry removes the corresponding event listener when called. * @remarks * - Improves performance by reducing the number of event listeners. * - Enables efficient O(1) lookup and management of event handlers for revalidation. */ const eventHandlers = new Map void>(); +/** Subscribe to an event and return a cleanup function */ +export type EventProvider = (handler: () => void) => () => void; + +const customEventProviders = new Map(); + +/** + * Registers a custom event provider for 'focus' or 'online' events. + * Useful for non-browser environments like React Native. + * + * @param type - The event type ('focus' or 'online'). + * @param provider - A function that subscribes to the event and returns a cleanup function. + */ +export function setEventProvider( + type: EventType, + provider: EventProvider, +): void { + customEventProviders.set(type, provider); + + // Re-register if already active + if (eventHandlers.has(type)) { + removeEventHandler(type); + addEventHandler(type); + } +} + /** * Triggers revalidation for all registered entries based on the given event type. * For example, if it's a 'focus' event, it will revalidate entries that have the `refetchOnFocus` flag set. @@ -135,36 +159,47 @@ export function removeRevalidators(type: EventType) { /** * Registers a generic revalidation event handler for the specified event type. - * Ensures the handler is only added once and only in browser environments. + * Supports browser window events and custom event providers (e.g. for React Native). + * Ensures the handler is only added once. * - * @param event - The type of event to listen for (e.g., 'focus', 'visibilitychange'). + * @param event - The type of event to listen for (e.g., 'focus', 'online'). */ function addEventHandler(event: EventType) { - if (!isBrowser() || eventHandlers.has(event)) { + if (eventHandlers.has(event)) { return; } const handler = revalidateAll.bind(null, event, true); - eventHandlers.set(event, handler); - window.addEventListener(event, handler); + // Priority 1: Custom event provider (works in any environment including React Native) + const customProvider = customEventProviders.get(event); + + if (customProvider) { + const cleanup = customProvider(handler); + + eventHandlers.set(event, cleanup); + + return; + } + + // Priority 2: Browser window events + if (isBrowser()) { + window.addEventListener(event, handler); + + eventHandlers.set(event, () => window.removeEventListener(event, handler)); + } } /** - * Removes the generic event handler for the specified event type from the window object. + * Removes the event handler for the specified event type. * * @param event - The type of event whose handler should be removed. */ function removeEventHandler(event: EventType) { - if (!isBrowser()) { - return; - } - - const handler = eventHandlers.get(event); - - if (handler) { - window.removeEventListener(event, handler); + const cleanup = eventHandlers.get(event); + if (cleanup) { + cleanup(); eventHandlers.delete(event); } } @@ -189,15 +224,28 @@ export function addRevalidator( refetchOnFocus?: boolean, refetchOnReconnect?: boolean, ) { - revalidators.set(key, [ - revalidatorFn, - timeNow(), - ttl ?? DEFAULT_TTL, - staleTime, - bgRevalidatorFn, - refetchOnFocus, - refetchOnReconnect, - ]); + const existing = revalidators.get(key); + + if (existing) { + // Update in-place to avoid allocating a new tuple array + existing[0] = revalidatorFn; + existing[1] = timeNow(); + existing[2] = ttl ?? DEFAULT_TTL; + existing[3] = staleTime; + existing[4] = bgRevalidatorFn; + existing[5] = refetchOnFocus; + existing[6] = refetchOnReconnect; + } else { + revalidators.set(key, [ + revalidatorFn, + timeNow(), + ttl ?? DEFAULT_TTL, + staleTime, + bgRevalidatorFn, + refetchOnFocus, + refetchOnReconnect, + ]); + } if (refetchOnFocus) { addEventHandler('focus'); diff --git a/src/timeout-wheel.ts b/src/timeout-wheel.ts index e78cea54..c94e9ded 100644 --- a/src/timeout-wheel.ts +++ b/src/timeout-wheel.ts @@ -57,8 +57,8 @@ export const addTimeout = ( ): void => { removeTimeout(key); - // Fallback to setTimeout if wheel size is exceeded or ms is not divisible by SECOND - if (ms > MAX_WHEEL_MS || ms % SECOND !== 0) { + // Fallback to setTimeout if wheel size is exceeded, ms is sub-second, or ms is not divisible by SECOND + if (ms < SECOND || ms > MAX_WHEEL_MS || ms % SECOND !== 0) { keyMap.set(key, [setTimeout(handleCallback.bind(null, [key, cb]), ms)]); // Store timeout ID instead of slot return; @@ -74,8 +74,15 @@ export const addTimeout = ( if (!timer) { timer = setInterval(() => { position = (position + 1) % WHEEL_SIZE; - wheel[position].forEach(handleCallback); - wheel[position] = []; + const slot = wheel[position]; + + // Use slot.length directly (not cached) so mid-iteration mutations + // from callbacks (e.g. removeTimeout) are handled correctly + for (let i = 0; i < slot.length; i++) { + handleCallback(slot[i]); + } + + slot.length = 0; // Reuse array, avoid GC allocation if (!keyMap.size && timer) { clearInterval(timer); @@ -93,10 +100,12 @@ export const removeTimeout = (key: string): void => { if (Array.isArray(slotOrTimeout)) { clearTimeout(slotOrTimeout[0]); } else { - wheel[slotOrTimeout].splice( - wheel[slotOrTimeout].findIndex(([k]) => k === key), - 1, - ); + const slotArr = wheel[slotOrTimeout]; + const idx = slotArr.findIndex(([k]) => k === key); + + if (idx !== -1) { + slotArr.splice(idx, 1); + } } keyMap.delete(key); @@ -122,6 +131,10 @@ export const clearAllTimeouts = () => { } keyMap.clear(); - wheel.forEach((slot) => (slot.length = 0)); + + for (let i = 0; i < WHEEL_SIZE; i++) { + wheel[i].length = 0; + } + position = 0; }; diff --git a/src/types/request-handler.ts b/src/types/request-handler.ts index 463d66fb..59e6dc12 100644 --- a/src/types/request-handler.ts +++ b/src/types/request-handler.ts @@ -497,12 +497,16 @@ export interface ExtendedRequestConfig< /** * If true, automatically revalidates the request when the window regains focus. + * In browsers, listens for the 'focus' window event. + * Custom providers can be registered via `setEventProvider('focus', provider)`. * @default false */ refetchOnFocus?: boolean; /** - * If true, automatically revalidates the request when the browser regains network connectivity. + * If true, automatically revalidates the request when network connectivity is restored. + * In browsers, listens for the 'online' window event. + * Otherwise, requires a custom event provider via `setEventProvider('online', provider)`. * @default false */ refetchOnReconnect?: boolean; diff --git a/src/utils.ts b/src/utils.ts index 79cdebda..b64a59b2 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -46,18 +46,27 @@ export function shallowSerialize(obj: Record): string { /** * Removes properties that could lead to prototype pollution from an object. * - * This function creates a shallow copy of the input object with dangerous - * properties like '__proto__', 'constructor', and 'prototype' removed. + * This function checks for dangerous properties like '__proto__', 'constructor', + * and 'prototype'. If none are present, the object is returned as-is (zero-copy fast path). + * Otherwise, a shallow copy is created with the dangerous properties removed. * * @param obj - The object to sanitize - * @returns A new object without dangerous properties + * @returns A safe object without dangerous properties */ export function sanitizeObject>(obj: T): T { + const hasProto = Object.prototype.hasOwnProperty.call(obj, '__proto__'); + const hasCtor = Object.prototype.hasOwnProperty.call(obj, 'constructor'); + const hasPrototype = Object.prototype.hasOwnProperty.call(obj, 'prototype'); + + if (!hasProto && !hasCtor && !hasPrototype) { + return obj; + } + const safeObj = { ...obj }; - delete safeObj.__proto__; - delete (safeObj as any).constructor; - delete safeObj.prototype; + if (hasProto) delete safeObj.__proto__; + if (hasCtor) delete (safeObj as any).constructor; + if (hasPrototype) delete safeObj.prototype; return safeObj; } @@ -334,17 +343,18 @@ export function processHeaders( const headersObject: HeadersObject = {}; - // Handle Headers object with entries() method + // Normalize keys to lowercase as per RFC 2616 4.2 + // https://datatracker.ietf.org/doc/html/rfc2616#section-4.2 if (headers instanceof Headers) { headers.forEach((value, key) => { - headersObject[key] = value; + headersObject[key.toLowerCase()] = value; }); } else if (isObject(headers)) { - // Handle plain object - for (const [key, value] of Object.entries(headers)) { - // Normalize keys to lowercase as per RFC 2616 4.2 - // https://datatracker.ietf.org/doc/html/rfc2616#section-4.2 - headersObject[key.toLowerCase()] = value; + // Handle plain object — use for...in to avoid Object.entries() allocation + for (const key in headers) { + if (Object.prototype.hasOwnProperty.call(headers, key)) { + headersObject[key.toLowerCase()] = headers[key]; + } } } @@ -357,23 +367,40 @@ export function processHeaders( * @returns {boolean} - True if running in a browser environment, false otherwise. */ export function isBrowser(): boolean { - // For node and and some mobile frameworks like React Native, `add/removeEventListener` doesn't exist on window! + // For node and some mobile frameworks like React Native, `add/removeEventListener` doesn't exist on window! return ( typeof window !== UNDEFINED && typeof window.addEventListener === FUNCTION ); } +/** + * Creates an abort/timeout error compatible with all JS runtimes. + * Falls back to a plain Error with the correct `name` when DOMException is unavailable (e.g. React Native). + * + * @param {string} message - The error message. + * @param {string} name - The error name (e.g. 'AbortError', 'TimeoutError'). + * @returns {DOMException | Error} - An error object with the specified name. + */ +export function createAbortError( + message: string, + name: string, +): DOMException | Error { + if (typeof DOMException !== UNDEFINED) { + return new DOMException(message, name); + } + + const error = new Error(message); + error.name = name; + + return error; +} + /** * Detects if the user is on a slow network connection * @returns {boolean} True if connection is slow, false otherwise or if detection unavailable */ export const isSlowConnection = (): boolean => { - // Only works in browser environments - if (!isBrowser()) { - return false; - } - - const conn = navigator && (navigator as any).connection; + const conn = typeof navigator !== UNDEFINED && (navigator as any).connection; return conn && ['slow-2g', '2g', '3g'].includes(conn.effectiveType); }; diff --git a/test/benchmarks/fetchf.bench.mjs b/test/benchmarks/fetchf.bench.mjs index ed59701c..29167461 100644 --- a/test/benchmarks/fetchf.bench.mjs +++ b/test/benchmarks/fetchf.bench.mjs @@ -1,5 +1,5 @@ // To run this benchmark, use the following command: -// npx tsx test/benchmarks/generic.bench.mjs +// npx tsx test/benchmarks/fetchf.bench.mjs import Benchmark from 'benchmark'; import { fetchf } from '../../dist/browser/index.mjs'; import { onComplete } from './utils.mjs'; @@ -37,6 +37,13 @@ const requestWithCache = () => strategy: 'softFail', }); +const requestWithStringCache = () => + fetchf('https://api.example.com/posts/1', { + cacheKey: 'post-1', + cacheTime: 300, + strategy: 'softFail', + }); + suite .add('Simple fetchf request', () => { return simpleRequest(); @@ -47,6 +54,9 @@ suite .add('fetchf with caching enabled', () => { return requestWithCache(); }) + .add('fetchf with string cache key', () => { + return requestWithStringCache(); + }) .on('cycle', (event) => { console.log(String(event.target)); }) diff --git a/test/cache-manager.spec.ts b/test/cache-manager.spec.ts index d88c2ed3..8c07fd6b 100644 --- a/test/cache-manager.spec.ts +++ b/test/cache-manager.spec.ts @@ -1,6 +1,7 @@ import { generateCacheKey, getCache, + getCacheData, setCache, deleteCache, getCachedResponse, @@ -47,7 +48,7 @@ describe('Cache Manager', () => { 'Accept-Encoding': 'gzip, deflate, br', }, }); - expect(key).toContain('GET|httpsapiexamplecomdata'); + expect(key).toContain('GET|https://api.example.com/data'); }); it('should generate a cache key for basic GET request with empty url', () => { @@ -83,7 +84,7 @@ describe('Cache Manager', () => { } as never); expect(key).toContain( - 'GET|httpsapiexamplecomdata|same-origin|1306150308', + 'GET|https://api.example.com/data|same-origin|1306150308', ); }); @@ -94,7 +95,7 @@ describe('Cache Manager', () => { headers: { 'Content-Type': 'application/json' }, }); expect(key).toContain( - 'POST|httpsapiexamplecomdata|same-origin|395078312|', + 'POST|https://api.example.com/data|same-origin|395078312|', ); }); @@ -108,7 +109,7 @@ describe('Cache Manager', () => { }); expect(spy).toHaveBeenCalled(); expect(key).toContain( - 'POST|httpsapiexamplecomdata|same-origin||655859486', + 'POST|https://api.example.com/data|same-origin||655859486', ); }); @@ -122,7 +123,7 @@ describe('Cache Manager', () => { }); expect(spy).toHaveBeenCalled(); expect(key).toContain( - 'POST|httpsapiexamplecomdata|same-origin||-1171129837', + 'POST|https://api.example.com/data|same-origin||-1171129837', ); }); @@ -136,7 +137,7 @@ describe('Cache Manager', () => { }); expect(spy).not.toHaveBeenCalled(); expect(key).toContain( - 'POST|httpsapiexamplecomdata|same-origin||nameAlice', + 'POST|https://api.example.com/data|same-origin||name:Alice', ); }); @@ -150,7 +151,7 @@ describe('Cache Manager', () => { body: formData, }); expect(key).toContain( - 'POST|httpsapiexamplecomdata|same-origin||1870802307', + 'POST|https://api.example.com/data|same-origin||1870802307', ); }); @@ -162,7 +163,7 @@ describe('Cache Manager', () => { body: blob, }); expect(key).toContain( - 'POST|httpsapiexamplecomdata|same-origin||BF4textplain', + 'POST|https://api.example.com/data|same-origin||BF4text/plain', ); }); @@ -182,7 +183,9 @@ describe('Cache Manager', () => { method: 'POST', body: 10, }); - expect(key).toContain('POST|httpsapiexamplecomdata|same-origin||10'); + expect(key).toContain( + 'POST|https://api.example.com/data|same-origin||10', + ); }); it('should handle Array body', () => { @@ -192,7 +195,9 @@ describe('Cache Manager', () => { method: 'POST', body: arrayBody, }); - expect(key).toContain('POST|httpsapiexamplecomdata|same-origin||011223'); + expect(key).toContain( + 'POST|https://api.example.com/data|same-origin||0:11:22:3', + ); }); it('should handle Object body and sort properties', () => { @@ -203,7 +208,9 @@ describe('Cache Manager', () => { body: objectBody, }); - expect(key).toContain('POST|httpsapiexamplecomdata|same-origin||a1b2'); + expect(key).toContain( + 'POST|https://api.example.com/data|same-origin||a:1b:2', + ); }); }); @@ -340,6 +347,30 @@ describe('Cache Manager', () => { ); expect(result).toBeNull(); }); + + it('should return null when cache mode is reload', () => { + setCache(cacheKey, responseObj, cacheTime); + fetcherConfig.cache = 'reload'; + const result = getCachedResponse(cacheKey, cacheTime, fetcherConfig); + expect(result).toBeNull(); + delete fetcherConfig.cache; + }); + }); + + describe('getCacheData', () => { + it('should return cached data for existing key', () => { + setCache('data-key', { data: 'test-value' }); + const result = getCacheData('data-key'); + expect(result).toEqual({ data: 'test-value' }); + }); + + it('should return null for non-existent key', () => { + expect(getCacheData('missing-key')).toBeNull(); + }); + + it('should return null for null key', () => { + expect(getCacheData(null)).toBeNull(); + }); }); describe('mutate', () => { diff --git a/test/config-handler.spec.ts b/test/config-handler.spec.ts index 8db40140..d57c6a8c 100644 --- a/test/config-handler.spec.ts +++ b/test/config-handler.spec.ts @@ -283,4 +283,53 @@ describe('request() Content-Type', () => { }); }, ); + + it('should set Content-Type on Headers instance when not already set', () => { + const headers = new Headers(); + headers.set('Accept', 'application/json'); + const result = buildFetcherConfig(apiUrl, { + method: 'POST', + body: { foo: 'bar' }, + headers, + }); + expect((result.headers as Headers).get('Content-Type')).toContain( + 'application/json', + ); + }); + + it('should not override Content-Type on Headers instance when already set', () => { + const headers = new Headers(); + headers.set('Content-Type', 'text/plain'); + const result = buildFetcherConfig(apiUrl, { + method: 'POST', + body: { foo: 'bar' }, + headers, + }); + expect((result.headers as Headers).get('Content-Type')).toBe('text/plain'); + }); + + it('should set Content-Type to application/x-www-form-urlencoded for URLSearchParams body', () => { + const params = new URLSearchParams(); + params.set('key', 'value'); + const result = buildFetcherConfig(apiUrl, { + method: 'POST', + body: params, + headers: {}, + }); + expect((result.headers as Record)['Content-Type']).toContain( + 'x-www-form-urlencoded', + ); + }); + + it('should set Content-Type to application/octet-stream for ArrayBuffer body', () => { + const buffer = new ArrayBuffer(8); + const result = buildFetcherConfig(apiUrl, { + method: 'POST', + body: buffer, + headers: {}, + }); + expect((result.headers as Record)['Content-Type']).toContain( + 'octet-stream', + ); + }); }); diff --git a/test/react/index.spec.ts b/test/react/index.spec.ts index 5d3aa3fd..ece7b3a3 100644 --- a/test/react/index.spec.ts +++ b/test/react/index.spec.ts @@ -285,9 +285,11 @@ describe('useFetcher', () => { it('should show loading when no state and URL exists', async () => { const { result } = renderHook(() => useFetcher(testUrl)); - await waitFor(() => { - expect(result.current.isLoading).toBe(true); - }); + // isLoading is true synchronously before the fetch resolves + expect(result.current.isLoading).toBe(true); + + // Drain pending microtasks from await null in request-handler + await act(async () => {}); }); it('should not show loading when no URL', () => { diff --git a/test/react/integration/error-handling.spec.tsx b/test/react/integration/error-handling.spec.tsx index bf45f318..ca9701f0 100644 --- a/test/react/integration/error-handling.spec.tsx +++ b/test/react/integration/error-handling.spec.tsx @@ -2,7 +2,13 @@ * @jest-environment jsdom */ import '@testing-library/jest-dom'; -import { render, screen, waitFor, fireEvent } from '@testing-library/react'; +import { + render, + screen, + waitFor, + fireEvent, + act, +} from '@testing-library/react'; import React from 'react'; import { clearMockResponses, @@ -127,11 +133,15 @@ describe('Error Handling Integration Tests', () => { }); // Test retry functionality - fireEvent.click(screen.getByTestId('retry-button')); + await act(async () => { + fireEvent.click(screen.getByTestId('retry-button')); + }); expect(screen.getByTestId('connection-loading')).toHaveTextContent( 'Loading...', ); - jest.runAllTimers(); + await act(async () => { + jest.runAllTimers(); + }); await waitFor(() => { expect(abortSignal).not.toBeNull(); diff --git a/test/react/integration/fetchf-deduplication.spec.tsx b/test/react/integration/fetchf-deduplication.spec.tsx new file mode 100644 index 00000000..8933e7de --- /dev/null +++ b/test/react/integration/fetchf-deduplication.spec.tsx @@ -0,0 +1,199 @@ +/** + * @jest-environment jsdom + */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import '@testing-library/jest-dom'; +import { act, render, screen, waitFor, cleanup } from '@testing-library/react'; +import { fetchf } from '../../../src/index'; +import { useFetcher } from '../../../src/react/index'; +import { clearAllTimeouts } from '../../../src/timeout-wheel'; + +describe('fetchf deduplication and parking with jsdom and onRequest', () => { + afterEach(() => { + cleanup(); + jest.restoreAllMocks(); + clearAllTimeouts(); + delete (window as any).__dedupeTriggered; + }); + + it('deduplicates and parks requests when onRequest triggers a second identical fetchf call', async () => { + const testUrl = '/api/onrequest-dedupe'; + const cacheKey = 'onrequest-dedupe-key'; + let resolveFetch: ((value: Response) => void) | undefined; + let fetchCallCount = 0; + + // Mock global.fetch to simulate slow network + global.fetch = jest.fn().mockImplementation(() => { + fetchCallCount++; + return new Promise((resolve) => { + resolveFetch = resolve; + }); + }); + + // Track results from both calls + let onRequestResult: any = undefined; + + // Set up onRequest interceptor that triggers a second fetchf call + const onRequest = async (config: any) => { + if (!onRequestResult) { + // Trigger a second fetchf with the same cacheKey while the first is in-flight + onRequestResult = fetchf(testUrl, { + cacheKey, + dedupeTime: 2000, + }); + } + return config; + }; + + // Start first request with onRequest interceptor + const promise1 = fetchf(testUrl, { + cacheKey, + dedupeTime: 2000, + onRequest, + }); + + expect(promise1).not.toBeUndefined(); + + // Allow microtasks to flush so onRequest fires and the first doRequestOnce calls fetch() + await act(async () => { + await new Promise((r) => setTimeout(r, 0)); + }); + + // onRequest triggered a second fetchf that was deduped + expect(onRequestResult).not.toBeUndefined(); + expect(promise1).not.toBe(onRequestResult); // Different promise objects, but parked + + // Only one actual fetch call should have been made (the second was deduped) + expect(fetchCallCount).toBe(1); + + // Resolve the fetch with a proper mock response + await act(async () => { + if (resolveFetch) { + resolveFetch({ + ok: true, + status: 200, + data: { result: 'deduped-onrequest' }, + body: JSON.stringify({ result: 'deduped-onrequest' }), + headers: { 'content-type': 'application/json' }, + } as unknown as Response); + } + }); + + // Both promises should resolve to the same result + const [result1, result2] = await Promise.all([promise1, onRequestResult]); + expect(result1.data).toEqual({ result: 'deduped-onrequest' }); + expect(result2.data).toEqual({ result: 'deduped-onrequest' }); + expect(fetchCallCount).toBe(1); + }); + + it('useFetcher deduplication: onRequest triggers fetchf with same cacheKey, other useFetcher waits for it', async () => { + const testUrl = '/api/component-dedupe'; + const cacheKey = 'component-dedupe-key'; + let resolveFetch: ((value: Response) => void) | undefined; + let fetchCallCount = 0; + + // Mock global.fetch to simulate slow network + global.fetch = jest.fn().mockImplementation(() => { + fetchCallCount++; + return new Promise((resolve) => { + resolveFetch = resolve; + }); + }); + + // React test component that triggers the fetch + function DedupeComponent() { + const { data, isLoading } = useFetcher(testUrl, { + cacheKey, + dedupeTime: 2000, + immediate: true, + onRequest: async (config: any) => { + // Only trigger once to avoid infinite loop + if (!(window as any).__dedupeTriggered) { + (window as any).__dedupeTriggered = true; + // This fetchf call uses the same cacheKey and should be deduped + fetchf(testUrl, { cacheKey, dedupeTime: 2000 }); + } + return config; + }, + }); + return ( +
+
+ {data ? JSON.stringify(data) : 'No Data'} +
+
+ {isLoading ? 'Loading' : 'Not Loading'} +
+
+ ); + } + + // Another useFetcher instance that relies on the same cacheKey + function WaitingComponent() { + const { data, isLoading } = useFetcher(testUrl, { + cacheKey, + dedupeTime: 2000, + immediate: true, + }); + return ( +
+
+ {data ? JSON.stringify(data) : 'No Data'} +
+
+ {isLoading ? 'Loading' : 'Not Loading'} +
+
+ ); + } + + // Render both components + render( + <> + + + , + ); + + // Both should be loading initially + expect(screen.getByTestId('loading').textContent).toBe('Loading'); + expect(screen.getByTestId('waiting-loading').textContent).toBe('Loading'); + + // Allow microtasks to flush so the fetch is actually called + await act(async () => { + await new Promise((r) => setTimeout(r, 0)); + }); + + expect(fetchCallCount).toBe(1); + + // Resolve the fetch with a proper mock response + await act(async () => { + if (resolveFetch) { + resolveFetch({ + ok: true, + status: 200, + data: { result: 'deduped-component' }, + body: JSON.stringify({ result: 'deduped-component' }), + headers: { 'content-type': 'application/json' }, + } as unknown as Response); + } + }); + + // Both should show the result and not loading + await waitFor(() => { + expect(screen.getByTestId('data').textContent).toContain( + 'deduped-component', + ); + expect(screen.getByTestId('loading').textContent).toBe('Not Loading'); + expect(screen.getByTestId('waiting-data').textContent).toContain( + 'deduped-component', + ); + expect(screen.getByTestId('waiting-loading').textContent).toBe( + 'Not Loading', + ); + }); + + // Only one network request should have been made + expect(fetchCallCount).toBe(1); + }); +}); diff --git a/test/react/integration/hook.spec.tsx b/test/react/integration/hook.spec.tsx index 76aa5157..d08ddd8a 100644 --- a/test/react/integration/hook.spec.tsx +++ b/test/react/integration/hook.spec.tsx @@ -36,7 +36,10 @@ describe('React Integration Tests', () => { jest.useFakeTimers(); }); - afterEach(() => { + afterEach(async () => { + await act(async () => { + cleanup(); + }); jest.useRealTimers(); jest.resetAllMocks(); clearAllTimeouts(); @@ -1030,7 +1033,10 @@ describe('React Integration Tests', () => { ); }; - const { rerender } = render(); + let rerender!: ReturnType['rerender']; + await act(async () => { + ({ rerender } = render()); + }); await waitFor(() => { expect(screen.getByTestId('overlap-data1')).toHaveTextContent( @@ -1038,10 +1044,14 @@ describe('React Integration Tests', () => { ); }); - rerender(); - fireEvent.click(screen.getByTestId('overlap-refetch')); + await act(async () => { + rerender(); + fireEvent.click(screen.getByTestId('overlap-refetch')); + }); - rerender(); + await act(async () => { + rerender(); + }); expect(screen.getByTestId('overlap-phase')).toHaveTextContent('3'); }); @@ -1556,9 +1566,12 @@ describe('React Integration Tests', () => { const testCase = testCases[index]; mockFetchResponse(`/api/types-${index}`, testCase); - const { unmount } = render( - , - ); + let unmount!: ReturnType['unmount']; + await act(async () => { + ({ unmount } = render( + , + )); + }); await waitFor(() => { const dataText = screen.getByTestId('data').textContent; @@ -1570,7 +1583,9 @@ describe('React Integration Tests', () => { }); // Clean up between iterations to avoid multiple elements - unmount(); + await act(async () => { + unmount(); + }); } }); diff --git a/test/react/integration/performance-caching.spec.tsx b/test/react/integration/performance-caching.spec.tsx index f0676d87..26f73e81 100644 --- a/test/react/integration/performance-caching.spec.tsx +++ b/test/react/integration/performance-caching.spec.tsx @@ -847,7 +847,7 @@ describe('Performance & Caching Integration Tests', () => { }); // Should start loading non-critical data - act(() => { + await act(async () => { jest.advanceTimersByTime(600); }); diff --git a/test/request-parser.spec.ts b/test/request-parser.spec.ts index 4c7b3c04..0b72d422 100644 --- a/test/request-parser.spec.ts +++ b/test/request-parser.spec.ts @@ -1,5 +1,8 @@ -import { parseResponseData } from '../src/response-parser'; -import type { FetchResponse } from '../src/types/request-handler'; +import { parseResponseData, prepareResponse } from '../src/response-parser'; +import type { + FetchResponse, + RequestConfig, +} from '../src/types/request-handler'; describe('parseData()', () => { let mockResponse: FetchResponse; @@ -119,4 +122,109 @@ describe('parseData()', () => { const data = await parseResponseData(mockResponse); expect(data).toEqual(streamContent); }); + + it('should return null for null response', async () => { + const data = await parseResponseData(null as any); + expect(data).toBeNull(); + }); + + it('should auto-parse JSON-like text when content type is missing', async () => { + (mockResponse.headers.get as jest.Mock).mockReturnValue(''); + (mockResponse.text as jest.Mock).mockResolvedValue('{"key":"value"}'); + + const data = await parseResponseData(mockResponse); + expect(data).toEqual({ key: 'value' }); + }); + + it('should auto-parse JSON array text when content type is missing', async () => { + (mockResponse.headers.get as jest.Mock).mockReturnValue(''); + (mockResponse.text as jest.Mock).mockResolvedValue('[1,2,3]'); + + const data = await parseResponseData(mockResponse); + expect(data).toEqual([1, 2, 3]); + }); +}); + +describe('prepareResponse()', () => { + const baseConfig: RequestConfig = { + method: 'GET', + url: '/test', + cacheKey: 'test-key', + }; + + it('should return error response when response is null', () => { + const result = prepareResponse(null, baseConfig); + + expect(result.ok).toBe(false); + expect(result.data).toBeNull(); + expect(result.isFetching).toBe(false); + expect(result.isSuccess).toBe(false); + expect(result.isError).toBe(true); + expect(result.headers).toBeNull(); + expect(typeof result.mutate).toBe('function'); + }); + + it('should use defaultResponse when response is null and defaultResponse is set', () => { + const config = { ...baseConfig, defaultResponse: { fallback: true } }; + const result = prepareResponse(null, config); + + expect(result.data).toEqual({ fallback: true }); + }); + + it('should apply flattenResponse when enabled', () => { + const response = { + data: { data: 'nested-value' }, + ok: true, + headers: {}, + } as unknown as FetchResponse; + const config = { ...baseConfig, flattenResponse: true }; + + const result = prepareResponse(response, config); + + expect(result.data).toBe('nested-value'); + }); + + it('should apply select function when provided', () => { + const response = { + data: { items: [1, 2, 3], total: 3 }, + ok: true, + headers: {}, + } as unknown as FetchResponse; + const config = { + ...baseConfig, + select: (data: any) => data.items, + }; + + const result = prepareResponse(response, config); + + expect(result.data).toEqual([1, 2, 3]); + }); + + it('should handle custom fetcher response (non-native Response)', () => { + const response = { + data: { id: 1 }, + ok: true, + headers: {}, + } as unknown as FetchResponse; + + const result = prepareResponse(response, baseConfig); + + expect(result.isFetching).toBe(false); + expect(result.isSuccess).toBe(true); + expect(result.isError).toBe(false); + expect(typeof result.mutate).toBe('function'); + }); + + it('should set defaultResponse when data is empty object', () => { + const response = { + data: {}, + ok: true, + headers: {}, + } as unknown as FetchResponse; + const config = { ...baseConfig, defaultResponse: [] }; + + const result = prepareResponse(response, config); + + expect(result.data).toEqual([]); + }); }); diff --git a/test/retry-handler.spec.ts b/test/retry-handler.spec.ts index 9eca5b0e..af57a230 100644 --- a/test/retry-handler.spec.ts +++ b/test/retry-handler.spec.ts @@ -43,4 +43,42 @@ describe('getRetryAfterMs', () => { getRetryAfterMs({ headers: { 'retry-after': 'not-a-date' } } as any), ).toBeNull(); }); + + it('parses ratelimit-reset-after header', () => { + expect( + getRetryAfterMs({ headers: { 'ratelimit-reset-after': '5' } } as any), + ).toBe(5000); + }); + + it('parses x-ratelimit-reset-after header', () => { + expect( + getRetryAfterMs({ headers: { 'x-ratelimit-reset-after': '3' } } as any), + ).toBe(3000); + }); + + it('parses ratelimit-reset-at header with future date', () => { + const future = new Date(Date.now() + 5000).toUTCString(); + const ms = getRetryAfterMs({ + headers: { 'ratelimit-reset-at': future }, + } as any); + expect(ms).toBeGreaterThanOrEqual(0); + expect(ms).toBeLessThanOrEqual(5000); + }); + + it('parses x-ratelimit-reset-at header with future date', () => { + const future = new Date(Date.now() + 5000).toUTCString(); + const ms = getRetryAfterMs({ + headers: { 'x-ratelimit-reset-at': future }, + } as any); + expect(ms).toBeGreaterThanOrEqual(0); + expect(ms).toBeLessThanOrEqual(5000); + }); + + it('returns null for invalid ratelimit-reset-at value', () => { + expect( + getRetryAfterMs({ + headers: { 'ratelimit-reset-at': 'not-a-date' }, + } as any), + ).toBeNull(); + }); }); diff --git a/test/revalidator-manager.spec.ts b/test/revalidator-manager.spec.ts index e13024bf..fb97aa38 100644 --- a/test/revalidator-manager.spec.ts +++ b/test/revalidator-manager.spec.ts @@ -7,6 +7,7 @@ import { revalidate, startRevalidatorCleanup, removeRevalidators, + setEventProvider, } from '../src/revalidator-manager'; describe('Revalidator Manager', () => { @@ -1257,4 +1258,120 @@ describe('Revalidator Manager', () => { jest.useFakeTimers(); // Restore fake timers }); }); + + describe('setEventProvider', () => { + afterEach(() => { + removeRevalidators('focus'); + removeRevalidators('online'); + }); + + it('should use custom provider instead of window events for focus', () => { + const cleanup = jest.fn(); + let capturedHandler: (() => void) | undefined; + + setEventProvider('focus', (handler) => { + capturedHandler = handler; + return cleanup; + }); + + addRevalidator( + testKey, + mockRevalidatorFn, + undefined, + undefined, + mockRevalidatorFn, + true, + ); + + // Trigger focus via custom provider + capturedHandler!(); + + expect(mockRevalidatorFn).toHaveBeenCalledTimes(1); + }); + + it('should use custom provider for online events', () => { + const cleanup = jest.fn(); + let capturedHandler: (() => void) | undefined; + + setEventProvider('online', (handler) => { + capturedHandler = handler; + return cleanup; + }); + + addRevalidator( + testKey, + mockRevalidatorFn, + undefined, + undefined, + mockRevalidatorFn, + false, + true, + ); + + capturedHandler!(); + + expect(mockRevalidatorFn).toHaveBeenCalledTimes(1); + }); + + it('should call cleanup when removing revalidators', () => { + const cleanup = jest.fn(); + + setEventProvider('focus', () => cleanup); + + addRevalidator( + testKey, + mockRevalidatorFn, + undefined, + undefined, + undefined, + true, + ); + + removeRevalidators('focus'); + + expect(cleanup).toHaveBeenCalledTimes(1); + }); + + it('should re-register handler when provider is set after revalidators', () => { + const cleanup = jest.fn(); + let capturedHandler: (() => void) | undefined; + + // First register with browser events + addRevalidator( + testKey, + mockRevalidatorFn, + undefined, + undefined, + mockRevalidatorFn, + true, + ); + + // Then set a custom provider — should re-register + setEventProvider('focus', (handler) => { + capturedHandler = handler; + return cleanup; + }); + + // Custom provider should now be active + capturedHandler!(); + + expect(mockRevalidatorFn).toHaveBeenCalledTimes(1); + }); + + it('should not trigger revalidators without the matching flag', () => { + let capturedHandler: (() => void) | undefined; + + setEventProvider('focus', (handler) => { + capturedHandler = handler; + return jest.fn(); + }); + + // Register without refetchOnFocus + addRevalidator(testKey, mockRevalidatorFn); + + capturedHandler?.(); + + expect(mockRevalidatorFn).not.toHaveBeenCalled(); + }); + }); }); diff --git a/test/timeout-wheel.spec.ts b/test/timeout-wheel.spec.ts index 1139c8b9..fe0447cd 100644 --- a/test/timeout-wheel.spec.ts +++ b/test/timeout-wheel.spec.ts @@ -265,13 +265,13 @@ describe('Timeout Wheel', () => { }); describe('Edge Cases', () => { - it('should handle zero timeout', () => { + it('should handle zero timeout via setTimeout fallback', () => { const callback = jest.fn(); addTimeout('zero', callback, 0); jest.advanceTimersByTime(1); - expect(callback).toHaveBeenCalledTimes(0); // Should not execute immediately + expect(callback).toHaveBeenCalledTimes(1); // Fires via setTimeout(cb, 0) }); it('should handle timeout at wheel boundary', () => { diff --git a/test/utils.spec.ts b/test/utils.spec.ts index 6aa21471..4dc3e15b 100644 --- a/test/utils.spec.ts +++ b/test/utils.spec.ts @@ -6,6 +6,9 @@ import { processHeaders, sortObject, sanitizeObject, + createAbortError, + shallowSerialize, + flattenData, } from '../src/utils'; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -48,33 +51,20 @@ describe('Utils', () => { ); }); - it('should return a new object reference', () => { + it('should return same reference when no dangerous properties exist', () => { const input = { a: 1, b: 2 }; const output = sanitizeObject(input); - expect(output).not.toBe(input); // Different reference + expect(output).toBe(input); // Same reference (zero-copy fast path) expect(output).toEqual(input); // Same content }); - xit('should handle null and undefined inputs', () => { - // @ts-expect-error Null and undefined are not objects - expect(sanitizeObject(null)).toBeNull(); - // @ts-expect-error Null and undefined are not objects - expect(sanitizeObject(undefined)).toBeUndefined(); - }); - - xit('should handle array inputs without modification', () => { - const input = [1, 2, 3]; - expect(sanitizeObject(input)).toEqual(input); - }); + it('should return a new object reference when dangerous properties exist', () => { + const input = { a: 1, b: 2, constructor: 'unsafe' }; + const output = sanitizeObject(input); - xit('should handle primitive inputs without modification', () => { - // @ts-expect-error String, number, and boolean are not objects - expect(sanitizeObject('string')).toBe('string'); - // @ts-expect-error String, number, and boolean are not objects - expect(sanitizeObject(123)).toBe(123); - // @ts-expect-error String, number, and boolean are not objects - expect(sanitizeObject(true)).toBe(true); + expect(output).not.toBe(input); // Different reference + expect(output).toEqual({ a: 1, b: 2 }); // Dangerous props removed }); it('should preserve all safe properties', () => { @@ -696,4 +686,111 @@ describe('Utils', () => { expect(result).toEqual({}); }); }); + + describe('createAbortError()', () => { + it('should create a DOMException when DOMException is available', () => { + const error = createAbortError('test message', 'AbortError'); + + expect(error.message).toBe('test message'); + expect(error.name).toBe('AbortError'); + expect(error).toBeInstanceOf(DOMException); + }); + + it('should create a DOMException with TimeoutError name', () => { + const error = createAbortError('timeout message', 'TimeoutError'); + + expect(error.message).toBe('timeout message'); + expect(error.name).toBe('TimeoutError'); + }); + + it('should fall back to a plain Error when DOMException is unavailable (e.g. React Native)', () => { + const OriginalDOMException = globalThis.DOMException; + + try { + // Simulate React Native environment where DOMException is not defined + // eslint-disable-next-line @typescript-eslint/no-explicit-any + delete (globalThis as any).DOMException; + + const error = createAbortError('timeout', 'TimeoutError'); + + expect(error.message).toBe('timeout'); + expect(error.name).toBe('TimeoutError'); + expect(error).toBeInstanceOf(Error); + } finally { + globalThis.DOMException = OriginalDOMException; + } + }); + + it('should create errors usable with AbortController.abort()', () => { + const controller = new AbortController(); + const error = createAbortError('aborted', 'AbortError'); + + controller.abort(error); + + expect(controller.signal.aborted).toBe(true); + expect(controller.signal.reason).toBe(error); + }); + }); + + describe('shallowSerialize()', () => { + it('should serialize object properties to a string', () => { + const result = shallowSerialize({ a: 1, b: 'test' }); + expect(result).toBe('a:1b:test'); + }); + + it('should return empty string for empty object', () => { + expect(shallowSerialize({})).toBe(''); + }); + + it('should skip inherited properties', () => { + const parent = { inherited: true }; + const child = Object.create(parent); + child.own = 'value'; + expect(shallowSerialize(child)).toBe('own:value'); + }); + }); + + describe('flattenData()', () => { + it('should flatten nested data property', () => { + expect(flattenData({ data: 'value' })).toBe('value'); + }); + + it('should recursively flatten deeply nested data', () => { + expect(flattenData({ data: { data: 'deep' } })).toBe('deep'); + }); + + it('should return non-object data as-is', () => { + expect(flattenData('string')).toBe('string'); + expect(flattenData(42)).toBe(42); + expect(flattenData(null)).toBe(null); + }); + + it('should return object without data property as-is', () => { + const obj = { foo: 'bar' }; + expect(flattenData(obj)).toEqual(obj); + }); + + it('should stop at max recursion depth', () => { + // Build a deeply nested structure beyond MAX_DEPTH (10) + let nested: any = 'bottom'; + for (let i = 0; i < 15; i++) { + nested = { data: nested }; + } + const result = flattenData(nested); + // Should not reach 'bottom' due to depth limit + expect(result).toHaveProperty('data'); + }); + }); + + describe('appendQueryParams() - max depth', () => { + it('should stop recursion at max depth for deeply nested params', () => { + let nested: any = 'value'; + for (let i = 0; i < 15; i++) { + nested = { a: nested }; + } + const result = appendQueryParams('https://example.com', nested); + // Should not throw — recursion stops before stack overflow + expect(result).toContain('https://example.com'); + }); + }); });