UNPKG

axios-retryer

Version:

TypeScript-first Axios retry library with concurrency limits, request priority, token refresh, response caching, and circuit breaker plugins.

2 lines (1 loc) 21.3 kB
"use strict";var e=require("axios");const t=new Set(["retryAttempt","requestRetries","requestMode","requestId","correlationId","isRetrying","priority","timestamp","backoffType","retryableStatuses","extra","isRetryRefreshRequest","manualReplayAttempt","retryAfterMs","silentlyCancelled","cachingOptions"]);function s(e){return t.has(e)&&"__proto__"!==e&&"constructor"!==e&&"prototype"!==e}function r(e){const t={};if(Object.defineProperty(t,"toJSON",{value:()=>{},enumerable:!1,writable:!1,configurable:!1}),e)for(const r of Object.keys(e))s(r)&&(t[r]=e[r]);return t}function i(e){const t=e;return t.__axiosRetryer?"function"!=typeof t.__axiosRetryer.toJSON&&(t.__axiosRetryer=r(t.__axiosRetryer)):t.__axiosRetryer=r(),t.__axiosRetryer}function o(e){if(e)return e.__axiosRetryer}function a(e,t){const r=i(e);for(const e of Object.keys(t)){if(!s(e))continue;const i=t[e];void 0===i?delete r[e]:r[e]=i}return r}class n extends Error{constructor(e,t){super(e),this.name=new.target.name,this.code=t,Object.setPrototypeOf(this,new.target.prototype)}}class c extends n{constructor(e,t,s){super(e,"EINVALID_CONFIG"),this.optionName=t,this.optionValue=s}}const u=[{name:"nested quantifier",test:e=>/\([^)]*[+*][^)]*\)[+*{]/.test(e)},{name:"alternation with quantifier",test:e=>/\([^)]*\|[^)]*\)[+*{]/.test(e)}];class l{constructor(e){this.responseMetrics={},this.percentile=e.percentile,this.sampleSize=e.sampleSize,this.multiplier=e.multiplier,this.maxTrackedScopes=e.maxTrackedScopes}trackResponseTime(e,t,s,r){var i,a;if(!e.config.url)return;let n=0;if(e.headers&&e.headers["x-response-time"]?n=parseInt(e.headers["x-response-time"],10):(null===(i=o(e.config))||void 0===i?void 0:i.timestamp)&&(n=Date.now()-((null===(a=o(e.config))||void 0===a?void 0:a.timestamp)||0)),n<=0&&(n=100),!this.responseMetrics[t]){const e=Object.keys(this.responseMetrics);e.length>=this.maxTrackedScopes&&delete this.responseMetrics[e[0]],this.responseMetrics[t]={times:[],sampleSize:this.sampleSize,lastCalculated:0,currentPercentileMs:0,scopeKey:t,normalizedUrl:s,host:r}}const c=this.responseMetrics[t];c.times.push(n),c.times.length>c.sampleSize&&c.times.shift(),this.updatePercentile(t)}getComputedTimeout(e){const t=this.responseMetrics[e];if(t&&this.isActive(t))return Math.round(t.currentPercentileMs*this.multiplier)}isActive(e){return e.times.length>=e.sampleSize&&e.currentPercentileMs>0}getAdaptiveTimeoutMetrics(){return Object.values(this.responseMetrics).map(e=>({scopeKey:e.scopeKey,url:e.normalizedUrl,host:e.host,timeoutMs:Math.round(e.currentPercentileMs*this.multiplier),p95ResponseTimeMs:e.currentPercentileMs,samplesCount:e.times.length}))}reset(){this.responseMetrics={}}updatePercentile(e){const t=this.responseMetrics[e];if(!t||0===t.times.length)return;if(t.times.length<t.sampleSize)return void(t.currentPercentileMs=0);const s=[...t.times].sort((e,t)=>e-t),r=Math.max(0,Math.min(Math.ceil(s.length*this.percentile)-1,s.length-1));t.currentPercentileMs=s[r],t.lastCalculated=Date.now()}}const p={CLOSED:"CLOSED",OPEN:"OPEN",HALF_OPEN:"HALF_OPEN"},h={HOST:"host",URL:"url",HOST_AND_URL:"host+url"};function d(e){return{...e,recentFailures:e.recentFailures.map(e=>({...e}))}}function g(e){return!!e&&"function"==typeof e.then}const f={log:()=>{},error:()=>{},warn:()=>{},debug:()=>{}};class m{constructor(){this.state=new Map}get(e){const t=this.state.get(e);return t?d(t):void 0}set(e,t){this.state.set(e,d(t))}delete(e){this.state.delete(e)}clear(){this.state.clear()}}class _{constructor(e){this.scopeStateCache=new Map,this.knownScopes=new Map,this.scopeLocks=new Map,this.logger=f,this.scope=e.scope,this.stateAdapter=e.stateAdapter,this.maxTrackedScopes=e.maxTrackedScopes}setLogger(e){this.logger=e}createInitialState(){return{state:p.CLOSED,failureCount:0,successCount:0,halfOpenCount:0,nextAttempt:Date.now(),recentFailures:[],lastFailureStatus:void 0,lastFailureCode:void 0}}withLock(e,t){var s;const r=(null!==(s=this.scopeLocks.get(e))&&void 0!==s?s:Promise.resolve()).then(t,t);return this.scopeLocks.set(e,r.then(()=>{},()=>{})),r}async readState(e){let t;try{t=await this.stateAdapter.get(e)}catch(t){this.handleAdapterError("get",e,t)}const s=this.scopeStateCache.get(e),r=t?d(t):s?d(s):this.createInitialState();return this.scopeStateCache.set(e,r),r}async writeState(e,t){const s=this.scopeStateCache.get(e),r=d(t);this.scopeStateCache.set(e,r);try{await this.stateAdapter.set(e,r)}catch(t){s?this.scopeStateCache.set(e,s):this.scopeStateCache.delete(e),this.handleAdapterError("set",e,t)}}getScopeDetails(e){const t=this.normalizeUrl(this.extractPath(e)),s=this.extractHost(e),r=this.resolveScopeKey(e,t,s);if(!this.knownScopes.has(r)){if(this.knownScopes.size>=this.maxTrackedScopes){const e=this.knownScopes.keys().next().value;this.knownScopes.delete(e),this.scopeStateCache.delete(e)}this.knownScopes.set(r,{scopeKey:r,normalizedUrl:t,host:s})}return this.knownScopes.get(r)}getKnownScopes(){return this.knownScopes.values()}getTrackedScopeKeys(e){return e?[e]:Array.from(new Set([...this.knownScopes.keys(),...this.scopeStateCache.keys()]))}deleteDistributedScope(e){try{const t=this.stateAdapter.delete(e);g(t)&&t.catch(t=>{this.handleAdapterError("delete",e,t),this.restoreDistributedClosedState([e])})}catch(t){this.handleAdapterError("delete",e,t),this.restoreDistributedClosedState([e])}}clearDistributedState(e){try{const t=this.stateAdapter.clear();g(t)&&t.catch(t=>{this.handleAdapterError("clear","*",t),this.restoreDistributedClosedState(e)})}catch(t){this.handleAdapterError("clear","*",t),this.restoreDistributedClosedState(e)}}restoreDistributedClosedState(e){e.forEach(e=>{const t=this.stateAdapter.set(e,this.createInitialState());g(t)&&t.catch(t=>{this.handleAdapterError("set",e,t)})})}resolveScopeKey(e,t,s){const r=s?`${s}${t}`:t||"unknown";if("function"==typeof this.scope)try{const t=this.scope(e);return"string"==typeof t&&t.length>0?t:(this.logger.warn("CircuitBreakerPlugin: Custom scope callback returned an empty scope key; using default",{url:e.url}),r)}catch(t){return this.logger.warn("CircuitBreakerPlugin: Custom scope callback threw; using default scope",{error:t instanceof Error?t.message:t,url:e.url}),r}switch(this.scope){case h.HOST:return s||t||"unknown";case h.URL:return t||s||"unknown";default:return r}}normalizeUrl(e){let t=e.split("?")[0].split("#")[0];return t=t.replace(/\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|\d+)(\/|$)/gi,"/:id$2"),t}resolveScopeKeyPublic(e,t,s){return this.resolveScopeKey(e,t,s)}extractPath(e){const t=this.resolveUrl(e);return t?`${t.pathname}${t.search}${t.hash}`||"/":e.url||"/"}extractHost(e){var t;return null===(t=this.resolveUrl(e))||void 0===t?void 0:t.host}resolveUrl(e){var t,s;if(!e.url)return null;const r=null!==(t=e.baseURL)&&void 0!==t?t:null===(s=this.baseURLGetter)||void 0===s?void 0:s.call(this);if(!/^[a-z][a-z\d+\-.]*:\/\//i.test(e.url)&&!r)return null;try{return new URL(e.url,r)}catch(e){return null}}handleAdapterError(e,t,s){this.logger.warn(`CircuitBreakerPlugin: State adapter ${e} failed; continuing with local circuit state`,{scopeKey:t,error:s instanceof Error?s.message:s})}}const S={failureThreshold:5,openTimeout:3e4,halfOpenMax:1,successThreshold:1,useSlidingWindow:!1,slidingWindowSize:6e4,adaptiveTimeout:!1,adaptiveTimeoutPercentile:.95,adaptiveTimeoutSampleSize:100,adaptiveTimeoutMultiplier:1.5,maxTrackedScopes:500,excludeUrls:[]};class C extends e.AxiosError{constructor(e,t,s,r,i){super(e,null!=r?r:"ECIRCUIT_BREAKER_STATE",s,void 0,i),this.name="CircuitBreakerStateError",this.circuitState=t,Object.setPrototypeOf(this,new.target.prototype)}}class v{constructor(e){this.options=e}rememberLast(e,t){var s;e.lastFailureStatus=null===(s=t.response)||void 0===s?void 0:s.status,e.lastFailureCode=t.code}add(e,t){var s,r;e.recentFailures.push({timestamp:Date.now(),url:(null===(s=t.config)||void 0===s?void 0:s.url)||"unknown",status:null===(r=t.response)||void 0===r?void 0:r.status,errorCode:t.code}),e.failureCount++,this.cleanup(e)}cleanup(e){if(!this.options.useSlidingWindow)return;const t=Date.now()-this.options.slidingWindowSize,s=e.recentFailures.length;e.recentFailures=e.recentFailures.filter(e=>e.timestamp>=t);const r=s-e.recentFailures.length;r>0&&(e.failureCount=Math.max(0,e.failureCount-r))}count(e){return this.options.useSlidingWindow?(this.cleanup(e),e.recentFailures.length):e.failureCount}countSince(e,t){return this.cleanup(e),e.recentFailures.filter(e=>e.timestamp>=t).length}}class w{constructor(e={}){this.name="CircuitBreakerPlugin",this.version="2.0.0",this._metricBaselines=new Map,this._options=function(e={}){var t,s;const r={...S,...e,scope:null!==(t=e.scope)&&void 0!==t?t:h.HOST_AND_URL,stateAdapter:null!==(s=e.stateAdapter)&&void 0!==s?s:new m};return function(e){if(!Number.isInteger(e.failureThreshold)||e.failureThreshold<1)throw new c("failureThreshold must be a positive integer","failureThreshold",e.failureThreshold);if(!Number.isInteger(e.openTimeout)||e.openTimeout<0)throw new c("openTimeout must be a non-negative integer","openTimeout",e.openTimeout);if(!Number.isInteger(e.halfOpenMax)||e.halfOpenMax<1)throw new c("halfOpenMax must be a positive integer","halfOpenMax",e.halfOpenMax);if(void 0!==e.successThreshold&&(!Number.isInteger(e.successThreshold)||e.successThreshold<1))throw new c("successThreshold must be a positive integer","successThreshold",e.successThreshold);if(e.successThreshold>e.halfOpenMax&&(e.successThreshold=e.halfOpenMax),0===e.excludeUrls.length)return;const t=function(e){const t=[];for(let s=0;s<e.length;s++){const r=e[s];if(r instanceof RegExp)for(const e of u)if(e.test(r.source)){t.push({index:s,pattern:r,reason:`Potentially catastrophic backtracking detected (${e.name}): ${r}. Use a string for exact-match exclusions, or simplify the pattern to avoid nested quantifiers.`});break}}return t}(e.excludeUrls);if(0!==t.length)throw new c(t.map(e=>e.reason).join("\n"),"excludeUrls",t.map(e=>e.pattern))}(r),r}(e),this._adaptiveTimeoutTracker=new l({percentile:this._options.adaptiveTimeoutPercentile,sampleSize:this._options.adaptiveTimeoutSampleSize,multiplier:this._options.adaptiveTimeoutMultiplier,maxTrackedScopes:this._options.maxTrackedScopes}),this._scopeManager=new _({scope:this._options.scope,stateAdapter:this._options.stateAdapter,maxTrackedScopes:this._options.maxTrackedScopes}),this._failureWindow=new v({useSlidingWindow:this._options.useSlidingWindow,slidingWindowSize:this._options.slidingWindowSize})}get _responseMetrics(){return this._adaptiveTimeoutTracker.responseMetrics}get _scopeStateCache(){return this._scopeManager.scopeStateCache}get _knownScopes(){return this._scopeManager.knownScopes}_normalizeUrl(e){return this._scopeManager.normalizeUrl(e)}_resolveScopeKey(e,t,s){return this._scopeManager.resolveScopeKeyPublic(e,t,s)}_getScopeDetails(e){return this._scopeManager.getScopeDetails(e)}async _writeScopeState(e,t){return this._scopeManager.writeState(e,t)}initialize(e){this._context=e;const t=e.getLogger();this._scopeManager.setLogger(t),this._scopeManager.baseURLGetter=()=>e.axiosInstance.defaults.baseURL,t.debug("CircuitBreakerPlugin: Initializing with options:",{...this._options});const s=e.axiosInstance;this._requestInterceptorId=s.interceptors.request.use(async e=>{const s=i(e);if(this._options.adaptiveTimeout&&e.url&&!s.timestamp&&a(e,{timestamp:Date.now()}),this._isUrlExcluded(e))return t.debug(`CircuitBreakerPlugin: URL excluded from circuit breaking: ${e.url}`),e;const r=this._scopeManager.getScopeDetails(e),o=await this._scopeManager.withLock(r.scopeKey,async()=>{let e=await this._scopeManager.readState(r.scopeKey);if(e.state===p.OPEN){if(!(Date.now()>=e.nextAttempt))return{action:"reject-open",scopeState:e};e=await this._transitionToHalfOpen(r.scopeKey,e)}if(e.state===p.HALF_OPEN){if(e.halfOpenCount>=this._options.halfOpenMax)return{action:"reject-half-open",scopeState:e};e.halfOpenCount++,await this._scopeManager.writeState(r.scopeKey,e),t.debug(`CircuitBreakerPlugin: HALF_OPEN test request #${e.halfOpenCount} of ${this._options.halfOpenMax} for ${r.scopeKey}`)}return{action:"allow",scopeState:e}});if("reject-open"===o.action){const s=o.scopeState.nextAttempt-Date.now();return t.debug(`CircuitBreakerPlugin: Circuit is OPEN for ${r.scopeKey}: failing fast. Will retry in ${s}ms`),Promise.reject(this._createCircuitStateError(e,o.scopeState,"Circuit is open: failing fast."))}if("reject-half-open"===o.action)return t.debug(`CircuitBreakerPlugin: Circuit is HALF_OPEN for ${r.scopeKey}: too many test requests.`),Promise.reject(this._createCircuitStateError(e,o.scopeState,"Circuit is half-open: too many test requests."));if(this._options.adaptiveTimeout){const s=this._adaptiveTimeoutTracker.getComputedTimeout(r.scopeKey);void 0!==s&&(e.timeout=s,t.debug(`CircuitBreakerPlugin: Setting adaptive timeout for ${r.scopeKey}: ${s}ms`))}return e}),this._responseInterceptorId=s.interceptors.response.use(async e=>{if(this._options.adaptiveTimeout&&e.config.url){const t=this._scopeManager.getScopeDetails(e.config);this._adaptiveTimeoutTracker.trackResponseTime(e,t.scopeKey,t.normalizedUrl,t.host)}if(this._isUrlExcluded(e.config))return e;const s=this._scopeManager.getScopeDetails(e.config);return await this._scopeManager.withLock(s.scopeKey,async()=>{const e=await this._scopeManager.readState(s.scopeKey);if(e.state===p.HALF_OPEN){e.successCount++;const r=this._options.successThreshold||1;e.successCount>=r?(t.debug(`CircuitBreakerPlugin: HALF_OPEN success threshold reached (${e.successCount}/${r}) for ${s.scopeKey}`),await this._resetScope(s.scopeKey)):(await this._scopeManager.writeState(s.scopeKey,e),t.debug(`CircuitBreakerPlugin: HALF_OPEN success: ${e.successCount}/${r} successful test requests for ${s.scopeKey}`))}else e.state===p.CLOSED&&e.failureCount>0&&(e.failureCount=0,e.lastFailureStatus=void 0,e.lastFailureCode=void 0,await this._scopeManager.writeState(s.scopeKey,e))}),e},async e=>{if(!e.config)return Promise.reject(e);if(this._isUrlExcluded(e.config))return Promise.reject(e);if(!this._shouldCountError(e))return t.debug("CircuitBreakerPlugin: Error excluded from circuit breaking by shouldCountError"),Promise.reject(e);const s=this._scopeManager.getScopeDetails(e.config);return await this._scopeManager.withLock(s.scopeKey,async()=>{const r=await this._scopeManager.readState(s.scopeKey);if(this._failureWindow.rememberLast(r,e),this._options.useSlidingWindow){this._failureWindow.add(r,e);const i=this._failureWindow.count(r);i>=this._options.failureThreshold?(t.debug(`CircuitBreakerPlugin: Sliding window failure threshold reached for ${s.scopeKey}: ${i} failures in window`),await this._tripScope(s.scopeKey,r)):await this._scopeManager.writeState(s.scopeKey,r)}else r.failureCount++,t.debug(`CircuitBreakerPlugin: Failure count increased for ${s.scopeKey}: ${r.failureCount}/${this._options.failureThreshold}`),r.state===p.HALF_OPEN||r.failureCount>=this._options.failureThreshold?await this._tripScope(s.scopeKey,r):await this._scopeManager.writeState(s.scopeKey,r)}),Promise.reject(e)})}onBeforeDestroyed(e){e.getLogger().debug("CircuitBreakerPlugin: Removing CircuitBreakerPlugin");const t=e.axiosInstance;void 0!==this._requestInterceptorId&&t.interceptors.request.eject(this._requestInterceptorId),void 0!==this._responseInterceptorId&&t.interceptors.response.eject(this._responseInterceptorId)}getState(e){var t,s;if(e)return null!==(s=null===(t=this._scopeManager.scopeStateCache.get(e))||void 0===t?void 0:t.state)&&void 0!==s?s:p.CLOSED;const r=Array.from(this._scopeManager.scopeStateCache.values()).map(e=>e.state);return r.includes(p.OPEN)?p.OPEN:r.includes(p.HALF_OPEN)?p.HALF_OPEN:p.CLOSED}manualReset(e){var t,s;const r=this._scopeManager.getTrackedScopeKeys(e);if(r.forEach(e=>{var t,s;const r=null!==(s=null===(t=this._scopeManager.scopeStateCache.get(e))||void 0===t?void 0:t.state)&&void 0!==s?s:p.CLOSED;this._scopeManager.scopeStateCache.set(e,this._scopeManager.createInitialState()),this._metricBaselines.delete(e),r!==p.CLOSED&&this._emitStateChange(e,r,p.CLOSED,"manual-reset")}),e)return this._scopeManager.deleteDistributedScope(e),void(null===(t=this._context)||void 0===t||t.getLogger().debug(`CircuitBreakerPlugin: Circuit reset for ${e}`));this._scopeManager.clearDistributedState(r),null===(s=this._context)||void 0===s||s.getLogger().debug("CircuitBreakerPlugin: Circuit reset: entering CLOSED state")}_reset(e){this.manualReset(e)}_trackResponseTime(e){if(!e.config.url||!this._options.adaptiveTimeout)return;const t=this._scopeManager.getScopeDetails(e.config);this._adaptiveTimeoutTracker.trackResponseTime(e,t.scopeKey,t.normalizedUrl,t.host)}resetMetrics(){var e;const t=Date.now();this._metricBaselines.clear(),this._scopeManager.getTrackedScopeKeys().forEach(e=>{var s;const r=null!==(s=this._scopeManager.scopeStateCache.get(e))&&void 0!==s?s:this._scopeManager.createInitialState();this._metricBaselines.set(e,{failureCount:r.failureCount,successCount:r.successCount,halfOpenCount:r.halfOpenCount,resetAt:t})}),this._adaptiveTimeoutTracker.reset(),null===(e=this._context)||void 0===e||e.getLogger().debug("CircuitBreakerPlugin: Circuit metrics reset.")}getAdaptiveTimeoutMetrics(){return this._options.adaptiveTimeout?this._adaptiveTimeoutTracker.getAdaptiveTimeoutMetrics():[]}getMetrics(){const e=this._getScopeMetrics();return{state:this.getState(),failureCount:e.reduce((e,t)=>e+t.failureCount,0),halfOpenCount:e.reduce((e,t)=>e+t.halfOpenCount,0),successCount:e.reduce((e,t)=>e+t.successCount,0),nextAttemptIn:e.reduce((e,t)=>Math.max(e,t.nextAttemptIn),0),failuresInWindow:e.reduce((e,t)=>e+t.failuresInWindow,0),adaptiveTimeouts:this.getAdaptiveTimeoutMetrics(),scopeMetrics:e}}async _tripScope(e,t){var s;if(t.state!==p.OPEN){const r=t.state;t.state=p.OPEN,t.nextAttempt=Date.now()+this._options.openTimeout,t.successCount=0,t.halfOpenCount=0,await this._scopeManager.writeState(e,t),this._emitStateChange(e,r,p.OPEN,r===p.HALF_OPEN?"half-open-failure":"failure-threshold",Math.max(0,t.nextAttempt-Date.now())),null===(s=this._context)||void 0===s||s.getLogger().error(`CircuitBreakerPlugin: Circuit tripped: entering OPEN state for ${e} until ${new Date(t.nextAttempt).toISOString()}`)}}async _resetScope(e){var t,s,r;const i=null!==(s=null===(t=this._scopeManager.scopeStateCache.get(e))||void 0===t?void 0:t.state)&&void 0!==s?s:p.CLOSED;await this._scopeManager.writeState(e,this._scopeManager.createInitialState()),i!==p.CLOSED&&this._emitStateChange(e,i,p.CLOSED,"success-threshold-reached"),null===(r=this._context)||void 0===r||r.getLogger().debug(`CircuitBreakerPlugin: Circuit reset: entering CLOSED state for ${e}.`)}async _transitionToHalfOpen(e,t){var s;const r=t.state;return t.state=p.HALF_OPEN,t.halfOpenCount=0,t.successCount=0,await this._scopeManager.writeState(e,t),this._emitStateChange(e,r,p.HALF_OPEN,"open-timeout-elapsed"),null===(s=this._context)||void 0===s||s.getLogger().debug(`CircuitBreakerPlugin: Transitioning to HALF_OPEN for ${e}.`),t}_emitStateChange(e,t,s,r,i){var o,a;t!==s&&(null===(a=null===(o=this._context)||void 0===o?void 0:o.triggerAndEmit)||void 0===a||a.call(o,"onCircuitStateChanged",{scopeKey:e,from:t,to:s,reason:r,...void 0!==i?{nextAttemptIn:i}:{}}))}_shouldCountError(e){var t;if(!this._options.shouldCountError)return!0;try{return this._options.shouldCountError(e)}catch(e){return null===(t=this._context)||void 0===t||t.getLogger().warn("CircuitBreakerPlugin: shouldCountError callback threw; counting error by default",{error:e instanceof Error?e.message:e}),!0}}_isUrlExcluded(e){return!(!e.url||!this._options.excludeUrls||0===this._options.excludeUrls.length)&&this._options.excludeUrls.some(t=>t instanceof RegExp?t.test(e.url||""):e.url===t)}_createCircuitStateError(e,t,s){const r={...e};return a(r,{requestRetries:0}),new C(s,t.state,r,t.lastFailureCode,void 0!==t.lastFailureStatus?{status:t.lastFailureStatus,statusText:"Circuit Open",config:r,headers:{},data:{error:s}}:void 0)}_getScopeMetrics(){const e=Date.now();return Array.from(this._scopeManager.getKnownScopes()).map(t=>{var s;const r=null!==(s=this._scopeManager.scopeStateCache.get(t.scopeKey))&&void 0!==s?s:this._scopeManager.createInitialState();return{scopeKey:t.scopeKey,url:t.normalizedUrl,host:t.host,state:r.state,failureCount:this._getVisibleCounter(t.scopeKey,"failureCount",r.failureCount),halfOpenCount:this._getVisibleCounter(t.scopeKey,"halfOpenCount",r.halfOpenCount),successCount:this._getVisibleCounter(t.scopeKey,"successCount",r.successCount),nextAttemptIn:Math.max(0,r.nextAttempt-e),failuresInWindow:this._getVisibleFailuresInWindow(t.scopeKey,r)}})}_getVisibleCounter(e,t,s){var r;const i=this._metricBaselines.get(e);return Math.max(0,s-(null!==(r=null==i?void 0:i[t])&&void 0!==r?r:0))}_getVisibleFailuresInWindow(e,t){var s,r;if(!this._options.useSlidingWindow)return this._getVisibleCounter(e,"failureCount",t.failureCount);const i=null!==(r=null===(s=this._metricBaselines.get(e))||void 0===s?void 0:s.resetAt)&&void 0!==r?r:0;return this._failureWindow.countSince(t,i)}}w.STATES=p,exports.CIRCUIT_BREAKER_SCOPES=h,exports.CIRCUIT_BREAKER_STATES=p,exports.CircuitBreakerPlugin=w,exports.CircuitBreakerStateError=C,exports.InMemoryCircuitBreakerStateAdapter=m,exports.createCircuitBreaker=function(e={}){return new w(e)};