axios-retryer
Version:
axios-retryer is an advanced Axios request manager offering intelligent retry logic with token refresh, concurrency control, priority queuing, and a flexible plugin architecture, all built with TypeScript for robust HTTP client integrations.
2 lines (1 loc) • 5.15 kB
JavaScript
class e{constructor(e){this.name="CachingPlugin",this.version="1.0.0",this.interceptorIdReq=null,this.interceptorIdRes=null,this.cache=new Map,this.cacheLock=new Map,this.cleanupTimer=null,this.options={compareHeaders:!1,timeToRevalidate:0,cacheMethods:["GET"],cleanupInterval:0,maxAge:0,maxItems:1e3,cacheOnlyRetriedRequests:!1,...e}}initialize(e){this.manager=e;const t=e.axiosInstance;this.interceptorIdReq=t.interceptors.request.use((e=>this.handleRequest(e)),(e=>Promise.reject(e))),this.interceptorIdRes=t.interceptors.response.use((e=>this.handleResponseSuccess(e)),(e=>Promise.reject(e))),this.options.cleanupInterval>0&&this.startPeriodicCleanup()}onBeforeDestroyed(){null!==this.interceptorIdReq&&this.manager.axiosInstance.interceptors.request.eject(this.interceptorIdReq),null!==this.interceptorIdRes&&this.manager.axiosInstance.interceptors.response.eject(this.interceptorIdRes),this.stopPeriodicCleanup()}handleRequest(e){var t,i,s,a,n,r;const c=(e.method||"GET").toUpperCase();if(!1===(null===(t=e.__cachingOptions)||void 0===t?void 0:t.cache))return null===(i=this.manager.getLogger())||void 0===i||i.debug("[CachingPlugin] Skipping cache for request (explicitly disabled)"),e;if(!0!==(null===(s=e.__cachingOptions)||void 0===s?void 0:s.cache)&&!this.options.cacheMethods.includes(c))return e;if(this.options.cacheOnlyRetriedRequests&&!e.__isRetrying)return e;const o=this.generateCacheKey(e),h=this.cache.get(o);if(h){const t=Date.now()-h.timestamp,i=null!==(a=h.ttr)&&void 0!==a?a:this.options.timeToRevalidate;if(0===i||i>t)return null===(n=this.manager.getLogger())||void 0===n||n.debug(`[CachingPlugin] Cache hit for ${o} (age: ${t}ms)`),{...e,adapter:()=>Promise.resolve({...h.response,config:e})};null===(r=this.manager.getLogger())||void 0===r||r.debug(`[CachingPlugin] Cache stale for ${o} (age: ${t}ms); removing entry.`),this.cache.delete(o)}return e}async handleResponseSuccess(e){var t,i,s,a,n,r,c,o;if(!1===(null===(i=null===(t=e.config)||void 0===t?void 0:t.__cachingOptions)||void 0===i?void 0:i.cache))return e;if(!0!==(null===(a=null===(s=e.config)||void 0===s?void 0:s.__cachingOptions)||void 0===a?void 0:a.cache)){const t=((null===(n=e.config)||void 0===n?void 0:n.method)||"GET").toUpperCase();if(!this.options.cacheMethods.includes(t))return e;if(this.options.cacheOnlyRetriedRequests&&e.config&&!e.config.__isRetrying)return e}if(e.status>=200&&300>e.status){const t=this.generateCacheKey(e.config);let i=this.cacheLock.get(t);i||(i=Promise.resolve(),this.cacheLock.set(t,i));try{if(await i,this.options.maxItems>0&&this.cache.size>=this.options.maxItems){const e=Array.from(this.cache.entries()).sort((([,e],[,t])=>e.timestamp-t.timestamp))[0][0];this.cache.delete(e)}const s=null===(c=null===(r=e.config)||void 0===r?void 0:r.__cachingOptions)||void 0===c?void 0:c.ttr;null===(o=this.manager.getLogger())||void 0===o||o.debug(`[CachingPlugin] Caching response for ${t}${s?` with custom TTR: ${s}ms`:""}`),this.cache.set(t,{response:e,timestamp:Date.now(),ttr:s})}finally{this.cacheLock.delete(t)}}return e}generateCacheKey(e){if(!e.url)throw Error("URL is required for cache key generation");const t=(e.method||"GET").toUpperCase(),i=e.params?"object"==typeof e.params?JSON.stringify(e.params):e.params+"":"",s=e.data?"object"==typeof e.data?JSON.stringify(e.data):e.data+"":"";let a="";return this.options.compareHeaders&&e.headers&&(a="object"==typeof e.headers?JSON.stringify(e.headers):e.headers+""),[t,e.url,i,s,a].join("|")}startPeriodicCleanup(){this.cleanupTimer||(this.cleanupTimer=setInterval((()=>{this.runCacheCleanup()}),this.options.cleanupInterval))}stopPeriodicCleanup(){this.cleanupTimer&&(clearInterval(this.cleanupTimer),this.cleanupTimer=null)}runCacheCleanup(){var e;const t=Date.now();let i=[];this.options.maxAge>0&&Array.from(this.cache.entries()).forEach((([e,s])=>{t-s.timestamp>this.options.maxAge&&i.push(e)})),this.options.maxItems>0&&this.cache.size>this.options.maxItems&&Array.from(this.cache.entries()).sort((([,e],[,t])=>e.timestamp-t.timestamp)).slice(0,this.cache.size-this.options.maxItems).map((([e])=>e)).forEach((e=>{i.includes(e)||i.push(e)})),i.length>0&&(i.forEach((e=>this.cache.delete(e))),null===(e=this.manager.getLogger())||void 0===e||e.debug(`[CachingPlugin] Cleaned up ${i.length} cached items`))}clearCache(){var e;this.cache.clear(),null===(e=this.manager.getLogger())||void 0===e||e.debug("[CachingPlugin] Cache cleared.")}invalidateCache(e){var t;let i=0;return Array.from(this.cache.keys()).forEach(e instanceof RegExp?t=>{e.test(t)&&(this.cache.delete(t),i++)}:t=>{(t===e||t.includes(e))&&(this.cache.delete(t),i++)}),i>0&&(null===(t=this.manager.getLogger())||void 0===t||t.debug(`[CachingPlugin] Invalidated ${i} cache entries matching pattern: ${e}`)),i}getCacheStats(){const e=Date.now(),t=Array.from(this.cache.values());if(0===t.length)return{size:0,oldestItemAge:0,newestItemAge:0,averageAge:0};const i=t.map((t=>e-t.timestamp));return{size:this.cache.size,oldestItemAge:Math.max(...i),newestItemAge:Math.min(...i),averageAge:i.reduce(((e,t)=>e+t),0)/i.length}}}function t(t){return new e(t)}export{e as CachingPlugin,t as createCachePlugin};