tryo 0.13.6 → 0.13.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -5
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +63 -43
- package/dist/index.d.ts +63 -43
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -169,11 +169,9 @@ Add hooks for logging or monitoring:
|
|
|
169
169
|
|
|
170
170
|
```typescript
|
|
171
171
|
const ex = tryo({
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
console.log(`Breaker moved: ${from} -> ${to}`),
|
|
176
|
-
},
|
|
172
|
+
onRetry: (attempt, error, delay) => console.log(`Retry ${attempt}...`),
|
|
173
|
+
onCircuitStateChange: (from, to) =>
|
|
174
|
+
console.log(`Breaker moved: ${from} -> ${to}`),
|
|
177
175
|
})
|
|
178
176
|
```
|
|
179
177
|
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var D=Object.defineProperty;var fe=Object.getOwnPropertyDescriptor;var Ee=Object.getOwnPropertyNames;var Te=Object.prototype.hasOwnProperty;var we=(e,r,t)=>r in e?D(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t;var be=(e,r)=>{for(var t in r)D(e,t,{get:r[t],enumerable:!0})},he=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of Ee(r))!Te.call(e,o)&&o!==t&&D(e,o,{get:()=>r[o],enumerable:!(n=fe(r,o))||n.enumerable});return e};var Re=e=>he(D({},"__esModule",{value:!0}),e);var d=(e,r,t)=>we(e,typeof r!="symbol"?r+"":r,t);var De={};be(De,{RetryStrategies:()=>ee,TypedError:()=>f,all:()=>le,allOrThrow:()=>ce,asMilliseconds:()=>b,asRetryCount:()=>h,default:()=>S,errorRule:()=>X,orThrow:()=>ue,run:()=>ae,runOrThrow:()=>ie,tryo:()=>S});module.exports=Re(De);var f=class extends Error{constructor(t,n){var o,i;super(t);d(this,"cause");d(this,"title");d(this,"meta");d(this,"status");d(this,"raw");d(this,"path");d(this,"timestamp");d(this,"retryable");this.timestamp=Date.now(),this.retryable=(o=n.retryable)!=null?o:!0,this.name=this.constructor.name,this.cause=n.cause,this.title=n.title,this.meta=(i=n.meta)!=null?i:{},this.status=n.status,this.raw=n.raw,this.path=n.path,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}is(t){return this.code===t}withMeta(t){return Object.assign(this,{meta:t})}withStatus(t){return Object.assign(this,{status:t})}withCause(t){return Object.assign(this,{cause:t})}withPath(t){return this.path=t,this}withRaw(t){return Object.assign(this,{raw:t})}withRetryable(t){return this.retryable=t,this}toJSON(){return{name:this.name,code:this.code,title:this.title,message:this.message,timestamp:this.timestamp,retryable:this.retryable,cause:this.cause,raw:this.raw,path:this.path,stack:this.stack}}},P=class extends f{constructor(t,n){super(`Operation timed out after ${t}ms`,{cause:n,retryable:!0});d(this,"code","TIMEOUT")}};var F=class extends f{constructor(t,n){super(`Circuit breaker is open, reset after ${t}ms`,{cause:n,retryable:!1});d(this,"code","CIRCUIT_OPEN")}};var B=class extends f{constructor(t,n){super(t,{cause:n});d(this,"code","UNKNOWN")}};var b=e=>{if(e<0||!Number.isFinite(e))throw new Error(`Invalid milliseconds: must be a non-negative finite number, got ${e}`);return e},h=e=>{if(e<0||!Number.isInteger(e))throw new Error(`Invalid retry count: must be a non-negative integer, got ${e}`);return e},H=e=>{if(e<1||!Number.isInteger(e))throw new Error(`Invalid concurrency limit: must be a positive integer, got ${e}`);return e},Y=e=>{if(e<0||e>100||!Number.isFinite(e))throw new Error(`Invalid percentage: must be between 0 and 100, got ${e}`);return e};var _=class{constructor(r){d(this,"state");d(this,"config");this.config={failureThreshold:h(r.failureThreshold),resetTimeout:b(r.resetTimeout),halfOpenRequests:h(r.halfOpenRequests),shouldCountAsFailure:r.shouldCountAsFailure},this.state={state:"closed",failureCount:0,halfOpenCount:0}}async canExecute(){if(this.updateStateIfNeeded(),this.state.state==="open")return!1;if(this.state.state==="half-open"){if(this.state.halfOpenCount>=this.config.halfOpenRequests)return!1;this.state={...this.state,halfOpenCount:this.state.halfOpenCount+1}}return!0}async recordSuccess(){switch(this.state.state){case"closed":this.state={...this.state,failureCount:0};break;case"half-open":this.state={state:"closed",failureCount:0,halfOpenCount:0};break;case"open":break}}async recordFailure(r){var o,i,s;if(!((s=(i=(o=this.config).shouldCountAsFailure)==null?void 0:i.call(o,r))!=null?s:!0))return;let n=new Date;switch(this.state.state){case"closed":{let a=this.state.failureCount+1;a>=this.config.failureThreshold?this.state={state:"open",failureCount:a,halfOpenCount:0,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)}:this.state={...this.state,failureCount:a,lastFailureTime:n};break}case"half-open":this.state={state:"open",failureCount:this.state.failureCount+1,halfOpenCount:0,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)};break;case"open":this.state={...this.state,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)};break}}getState(){return this.updateStateIfNeeded(),{...this.state,canExecute:this.state.state!=="open"}}createOpenError(){let r=this.state.nextAttemptTime?b(Math.max(0,this.state.nextAttemptTime.getTime()-Date.now())):this.config.resetTimeout;return new F(r)}forceState(r){this.state={state:r,failureCount:0,halfOpenCount:0}}reset(){this.state={state:"closed",failureCount:0,halfOpenCount:0}}updateStateIfNeeded(){this.state.state==="open"&&this.state.nextAttemptTime&&new Date>=this.state.nextAttemptTime&&(this.state={...this.state,state:"half-open",halfOpenCount:0})}};var G=(e,r)=>t=>{for(let n of e){let o=n(t);if(o!==null)return o}return r(t)},Q=e=>r=>r instanceof f?r:r instanceof Error?new e(r.message,r):typeof r=="string"?new e(r):new e("Unknown error occurred",r);var Ce=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.status=="number"||typeof r.statusCode=="number"},xe=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.code=="string"&&r.code.length>0},ge=e=>{var r;if(e instanceof Error){let t=e.message.toLowerCase();if(e.name==="TypeError"&&(t.includes("fetch")&&t.includes("failed")||t.includes("network"))||t.includes("fetch")&&t.includes("failed")||t.includes("network"))return!0}if(xe(e)){let t=((r=e.code)!=null?r:"").toUpperCase();return t==="ECONNRESET"||t==="ECONNREFUSED"||t==="ETIMEDOUT"||t==="ENOTFOUND"||t==="EAI_AGAIN"}return!1},ke=e=>typeof e=="object"&&e!==null,U=class{constructor(r){this.predicate=r}toCode(r){return new q(this.predicate,r)}toError(r){return t=>{var l;if(!this.predicate(t))return null;let n=r(t),o=n.code,i=Object.hasOwn(n,"cause")?n.cause:t,s=(l=n.meta)!=null?l:{};class a extends f{constructor(){let c=Object.hasOwn(n,"raw")?n.raw:t;super(n.message,{title:n.title,cause:i,meta:s,status:n.status,retryable:n.retryable,raw:c,path:n.path});d(this,"code",o)}}return new a}}};function Oe(e,r){let t=new U(i=>i instanceof e);if(r)return t.toError(r);let o=i=>{if(!(i instanceof e))return null;if(i instanceof f)return i;let s=i,a=typeof s.code=="string"&&s.code.length>0?s.code:"UNKNOWN",l=Object.hasOwn(s,"cause"),u=Object.hasOwn(s,"raw");class y extends f{constructor(){super(s.message||a,{title:typeof s.title=="string"?s.title:void 0,cause:l?s.cause:i,meta:ke(s.meta)?s.meta:{},status:typeof s.status=="number"?s.status:void 0,retryable:typeof s.retryable=="boolean"?s.retryable:void 0,raw:u?s.raw:i,path:typeof s.path=="string"?s.path:void 0});d(this,"code",a)}}return new y};return o.toCode=t.toCode.bind(t),o.toError=t.toError.bind(t),o}var q=class{constructor(r,t){this.predicate=r;this.errorCode=t}with(r){return t=>{var l;if(!this.predicate(t))return null;let n=r(t),o=Object.hasOwn(n,"cause")?n.cause:t,i=(l=n.meta)!=null?l:{},s=this.errorCode;class a extends f{constructor(){let p=Object.hasOwn(n,"raw")?n.raw:t;super(n.message,{title:n.title,cause:o,meta:i,status:n.status,retryable:n.retryable,raw:p,path:n.path});d(this,"code",s)}}return new a}}},R={when:e=>new U(e),instance:Oe},x={typed:(e=>e instanceof f?e:null),abort:R.when(e=>e instanceof Error&&e.name==="AbortError").toCode("ABORTED").with(e=>({message:e.message||"Operation was aborted",cause:e,retryable:!1,raw:e})),timeout:R.when(e=>e instanceof Error&&e.name==="TimeoutError").toCode("TIMEOUT").with(e=>({message:e.message||"Operation timed out",cause:e,raw:e})),network:R.when(e=>ge(e)).toCode("NETWORK").with(e=>({message:(e instanceof Error,e.message||"Network error"),cause:e,raw:e})),http:R.when(e=>{var n;if(!Ce(e))return!1;let r=e,t=(n=r.status)!=null?n:r.statusCode;return typeof t=="number"&&t>=400}).toCode("HTTP").with(e=>{var n;let r=(n=e.status)!=null?n:e.statusCode,t=typeof r=="number"&&(r>=500||r===429);return{message:e.message||`HTTP ${r!=null?r:"error"} error`,cause:e,status:typeof r=="number"?r:void 0,retryable:t,raw:e}}),unknown:R.when(e=>e instanceof Error&&!(e instanceof f)).toCode("UNKNOWN").with(e=>({message:e.message||"Unknown error occurred",cause:e,raw:e}))};var Ae=[x.typed,x.abort,x.timeout,x.http,x.network,x.unknown];var X={when:e=>R.when(e),instance:R.instance},Z=Ae;var ee={fixed:e=>({type:"fixed",delay:e}),exponential:(e,r=2,t)=>({type:"exponential",base:e,factor:r,maxDelay:t}),fibonacci:(e,r)=>({type:"fibonacci",base:e,maxDelay:r}),custom:e=>({type:"custom",calculate:e})},re=(e,r,t)=>{switch(e.type){case"fixed":return e.delay;case"exponential":{let n=e.base*e.factor**(Number(r)-1);return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"fibonacci":{let n=e.base*Se(Number(r));return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"custom":return e.calculate(r,t);default:return e}},Se=e=>{if(e<=1)return 1;let r=1,t=1;for(let n=2;n<=e;n++){let o=r+t;r=t,t=o}return t},te=e=>{switch(e.type){case"fixed":{if(e.delay<0)throw new Error("Fixed delay must be non-negative");break}case"exponential":if(e.base<=0)throw new Error("Exponential base delay must be positive");if(e.factor<=1)throw new Error("Exponential factor must be greater than 1");if(e.maxDelay!==void 0&&e.maxDelay<=0)throw new Error("Exponential max delay must be positive");break;case"fibonacci":if(e.base<=0)throw new Error("Fibonacci base delay must be positive");if(e.maxDelay!==void 0&&e.maxDelay<=0)throw new Error("Fibonacci max delay must be positive");break;case"custom":break;default:{let r=e;throw new Error(`Unknown strategy type: ${r}`)}}};var ne=(e,r)=>new Promise((t,n)=>{if(r!=null&&r.aborted){n(new DOMException("Aborted","AbortError"));return}let o=a=>{r&&a&&r.removeEventListener("abort",a)},i,s=()=>{i&&clearTimeout(i),o(s),n(new DOMException("Aborted","AbortError"))};i=setTimeout(()=>{o(s),t()},e),r==null||r.addEventListener("abort",s,{once:!0})}),oe=(e,r,t,n)=>new Promise((o,i)=>{if(t!=null&&t.aborted){i(new DOMException("Aborted","AbortError"));return}let s=!1,a=setTimeout(()=>{var y;s=!0,u(),i((y=n==null?void 0:n())!=null?y:new Error(`Operation timed out after ${r}ms`))},r),l=()=>{s||(s=!0,u(),i(new DOMException("Aborted","AbortError")))},u=()=>{clearTimeout(a),t==null||t.removeEventListener("abort",l)};t==null||t.addEventListener("abort",l,{once:!0}),e.then(y=>{s||(s=!0,u(),o(y))},y=>{s||(s=!0,u(),i(y))})});var Ne=e=>{var s,a,l;if(e.toError)return e.toError;let r=(s=e.rulesMode)!=null?s:"extend",t=(a=e.rules)!=null?a:[],n=Z,o=(l=e.fallback)!=null?l:(u=>Q(B)(u)),i=r==="replace"?t:[...t,...n];return G(i,o)},Me=e=>{if(e)switch(e.type){case"none":return;case"full":case"equal":Y(e.ratio);return;case"custom":return;default:{let r=e;throw new Error(`Unsupported jitter configuration: ${r}`)}}},$=e=>{let r=e;return r.timeout!==void 0&&(r={...r,timeout:Number(b(r.timeout))}),r.concurrency!==void 0&&(r={...r,concurrency:Number.isFinite(r.concurrency)?Number(H(r.concurrency)):r.concurrency}),r.retry&&(te(r.retry.strategy),Me(r.retry.jitter),r={...r,retry:{...r.retry,maxRetries:Number(h(r.retry.maxRetries))}}),r},W=class e{constructor(r={}){d(this,"circuitBreaker");d(this,"config");d(this,"lastCircuitState");let{rules:t,rulesMode:n,fallback:o,toError:i,mapError:s,...a}=r,l=Ne(r),u={...a,errorHandling:{normalizer:l,mapError:s}};this.config=$(u),u.circuitBreaker&&(this.circuitBreaker=new _(u.circuitBreaker),this.lastCircuitState=this.circuitBreaker.getState().state)}async run(r,t={}){var i,s,a,l,u,y;let n=$({...this.config,...t});if(this.circuitBreaker){let c=(i=this.lastCircuitState)!=null?i:this.circuitBreaker.getState().state,p=await this.circuitBreaker.canExecute(),T=this.circuitBreaker.getState().state;if(c!==T)try{(a=(s=n.hooks)==null?void 0:s.onCircuitStateChange)==null||a.call(s,c,T)}catch{}if(this.lastCircuitState=T,!p)return{type:"failure",ok:!1,data:null,error:this.circuitBreaker.createOpenError(),metrics:{totalAttempts:0,totalRetries:0,totalDuration:0,retryHistory:[]}}}let o=await Ie(r,n);if(this.circuitBreaker){let c=(l=this.lastCircuitState)!=null?l:this.circuitBreaker.getState().state;o.ok?await this.circuitBreaker.recordSuccess():await this.circuitBreaker.recordFailure(o.error);let p=this.circuitBreaker.getState().state;if(c!==p)try{(y=(u=n.hooks)==null?void 0:u.onCircuitStateChange)==null||y.call(u,c,p)}catch{}this.lastCircuitState=p}return o}async runOrThrow(r,t={}){return this.orThrow(r,t)}async orThrow(r,t={}){let n=await this.run(r,t);if(n.ok)return n.data;throw n.error}async all(r,t={}){var y;let n=$({...this.config,...t}),o=(y=n.concurrency)!=null?y:Number.POSITIVE_INFINITY,i=Number.isFinite(o)?Number(H(o)):Number.POSITIVE_INFINITY;if(i===Number.POSITIVE_INFINITY)return Promise.all(r.map(c=>this.run(c,n)));let s=new Array(r.length),a=0,l=async()=>{var c;for(;a<r.length&&!((c=n.signal)!=null&&c.aborted);){let p=a++;if(p>=r.length)break;let T=r[p];T&&(s[p]=await this.run(T,n))}},u=Array.from({length:Math.min(i,r.length)},()=>l());await Promise.all(u);for(let c=0;c<r.length;c++)if(!(c in s)){let p=r[c];p&&(s[c]=await this.run(p,n))}return s}async allOrThrow(r,t={}){return(await this.all(r,t)).map(o=>{if(!o.ok)throw o.error;return o.data})}partitionAll(r){let t=[],n=[],o=[],i=[],s=[];for(let a of r){if(a.type==="success"){t.push(a);continue}switch(n.push(a),a.type){case"failure":o.push(a);break;case"aborted":i.push(a);break;case"timeout":s.push(a);break}}return{ok:t,errors:n,failure:o,aborted:i,timeout:s}}getCircuitBreakerState(){var r;return(r=this.circuitBreaker)==null?void 0:r.getState()}resetCircuitBreaker(){var r;(r=this.circuitBreaker)==null||r.reset()}getConfig(){return{...this.config}}withConfig(r){var l,u;let{errorHandling:t,...n}=this.config,{errorHandling:o,...i}=r,s=(l=o==null?void 0:o.normalizer)!=null?l:t.normalizer,a=(u=o==null?void 0:o.mapError)!=null?u:t.mapError;return new e({...n,...i,toError:s,mapError:a})}};function S(e={}){let r=new W(e);return{run:(t,n)=>r.run(t,n),orThrow:(t,n)=>r.orThrow(t,n),runOrThrow:(t,n)=>r.runOrThrow(t,n),all:(t,n)=>r.all(t,n),allOrThrow:(t,n)=>r.allOrThrow(t,n),partitionAll:t=>r.partitionAll(t),withConfig:t=>r.withConfig(t)}}async function Ie(e,r){let{signal:t,ignoreAbort:n=!0,timeout:o,retry:i,errorHandling:s,hooks:a,logger:l}=r,u=(C,...m)=>{try{C==null||C(...m)}catch{}},y,c=0,p=0,T=[],k=Date.now(),{signal:O,cleanup:de}=se(t),M=C=>({totalAttempts:c,totalRetries:c>0?Number(c)-1:0,totalDuration:Date.now()-k,lastError:C,retryHistory:T});try{if(O.aborted){u(a==null?void 0:a.onAbort,O);let m=s.normalizer(new DOMException("Aborted","AbortError")),w=s.mapError?s.mapError(m):m;return{type:"aborted",ok:!1,data:null,error:w,metrics:{totalAttempts:c,totalRetries:p,totalDuration:Date.now()-k,lastError:w,retryHistory:T}}}let C=async()=>{var I,g,K;let m=1,w=h((I=i==null?void 0:i.maxRetries)!=null?I:0);for(;;){c=m;let V=new AbortController,{signal:L,cleanup:ye}=se(O,V.signal);try{let v=Promise.resolve(e({signal:L})),A=o?await oe(v,o,L,()=>(V.abort(),new P(b(o)))):await v;return u(a==null?void 0:a.onSuccess,A,M()),u(l==null?void 0:l.info,`Task succeeded on attempt ${m}`),A}catch(v){let A=s.normalizer(v),E=s.mapError?s.mapError(A):A;if(y=E,E.code==="ABORTED"&&u(a==null?void 0:a.onAbort,L),n&&E.code==="ABORTED"||(u(a==null?void 0:a.onError,E,M(E)),u(l==null?void 0:l.error,`Task failed on attempt ${m}`,E)),E.code==="ABORTED"||E.retryable===!1)throw E;if(m<=Number(w)){let J=i==null?void 0:i.shouldRetry,pe={totalAttempts:Number(c),elapsedTime:Date.now()-k,startTime:new Date(k),lastDelay:(g=T[T.length-1])!=null&&g.delay?Number((K=T[T.length-1])==null?void 0:K.delay):void 0};if(!J||J(m,E,pe)){let me=i?re(i.strategy,m,E):0,z=ve(me,i==null?void 0:i.jitter),j=b(z);T.push({attempt:m,error:E,delay:j,timestamp:new Date}),u(a==null?void 0:a.onRetry,m,E,z),u(l==null?void 0:l.info,`Retrying in ${z}ms (attempt ${m+1})`),m+=1,await ne(j,O);continue}}throw E}finally{ye()}}};try{let m=await C(),w=M();return p=w.totalRetries,u(a==null?void 0:a.onFinally,w),{type:"success",ok:!0,data:m,error:null,metrics:w}}catch(m){let w=y!=null?y:s.normalizer(m),I=w.code==="TIMEOUT"?"timeout":w.code==="ABORTED"?"aborted":"failure",g=M(w);return p=g.totalRetries,u(a==null?void 0:a.onFinally,g),{type:I,ok:!1,data:null,error:w,metrics:g}}}finally{de()}}function se(...e){let r=new AbortController,t=e.filter(o=>o!==void 0);if(t.length===0)return{signal:r.signal,cleanup:()=>{}};if(t.some(o=>o.aborted))return r.abort(),{signal:r.signal,cleanup:()=>{}};let n=[];for(let o of t){let i=()=>r.abort();o.addEventListener("abort",i,{once:!0}),n.push({signal:o,abort:i})}return{signal:r.signal,cleanup:()=>{for(let o of n)o.signal.removeEventListener("abort",o.abort)}}}function ve(e,r){if(!r||r.type==="none"||e<=0)return e;switch(r.type){case"full":{let t=Number(r.ratio)/100,n=Math.max(0,Number(e)*(1-t)),o=Number(e);return n+Math.random()*(o-n)}case"equal":{let t=Number(r.ratio)/100,n=Number(e)*t/2;return Number(e)-n+Math.random()*n}case"custom":return r.calculate(e);default:return r}}var N=S(),ae=N.run,ie=N.runOrThrow,ue=N.orThrow,le=N.all,ce=N.allOrThrow;0&&(module.exports={RetryStrategies,TypedError,all,allOrThrow,asMilliseconds,asRetryCount,errorRule,orThrow,run,runOrThrow,tryo});
|
|
1
|
+
"use strict";var B=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var he=Object.getOwnPropertyNames;var Re=Object.prototype.hasOwnProperty;var Ce=(e,r,t)=>r in e?B(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t;var xe=(e,r)=>{for(var t in r)B(e,t,{get:r[t],enumerable:!0})},ge=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of he(r))!Re.call(e,o)&&o!==t&&B(e,o,{get:()=>r[o],enumerable:!(n=be(r,o))||n.enumerable});return e};var ke=e=>ge(B({},"__esModule",{value:!0}),e);var l=(e,r,t)=>Ce(e,typeof r!="symbol"?r+"":r,t);var _e={};xe(_e,{RetryStrategies:()=>oe,TypedError:()=>m,all:()=>pe,allOrThrow:()=>me,asMilliseconds:()=>b,asRetryCount:()=>h,default:()=>S,errorRule:()=>te,orThrow:()=>ye,run:()=>le,runOrThrow:()=>de,tryo:()=>S});module.exports=ke(_e);var m=class extends Error{constructor(t,n){var o,a;super(t);l(this,"cause");l(this,"title");l(this,"meta");l(this,"status");l(this,"raw");l(this,"path");l(this,"timestamp");l(this,"retryable");this.timestamp=Date.now(),this.retryable=(o=n.retryable)!=null?o:!0,this.name=this.constructor.name,this.cause=n.cause,this.title=n.title,this.meta=(a=n.meta)!=null?a:{},this.status=n.status,this.raw=n.raw,this.path=n.path,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}is(t){return this.code===t}withMeta(t){return Object.assign(this,{meta:t})}withStatus(t){return Object.assign(this,{status:t})}withCause(t){return Object.assign(this,{cause:t})}withPath(t){return this.path=t,this}withRaw(t){return Object.assign(this,{raw:t})}withRetryable(t){return this.retryable=t,this}toJSON(){return{name:this.name,code:this.code,title:this.title,message:this.message,timestamp:this.timestamp,retryable:this.retryable,cause:this.cause,raw:this.raw,path:this.path,stack:this.stack}}},_=class extends m{constructor(t,n){super(`Operation timed out after ${t}ms`,{cause:n,retryable:!0});l(this,"code","TIMEOUT")}};var U=class extends m{constructor(t,n){super(`Circuit breaker is open, reset after ${t}ms`,{cause:n,retryable:!1});l(this,"code","CIRCUIT_OPEN")}};var L=class extends m{constructor(t,n){super(t,{cause:n});l(this,"code","UNKNOWN")}};var b=e=>{if(e<0||!Number.isFinite(e))throw new Error(`Invalid milliseconds: must be a non-negative finite number, got ${e}`);return e},h=e=>{if(e<0||!Number.isInteger(e))throw new Error(`Invalid retry count: must be a non-negative integer, got ${e}`);return e},K=e=>{if(e<1||!Number.isInteger(e))throw new Error(`Invalid concurrency limit: must be a positive integer, got ${e}`);return e},Z=e=>{if(e<0||e>100||!Number.isFinite(e))throw new Error(`Invalid percentage: must be between 0 and 100, got ${e}`);return e};var z=class{constructor(r){l(this,"state");l(this,"config");this.config={failureThreshold:h(r.failureThreshold),resetTimeout:b(r.resetTimeout),halfOpenRequests:h(r.halfOpenRequests),shouldCountAsFailure:r.shouldCountAsFailure},this.state={state:"closed",failureCount:0,halfOpenCount:0}}async canExecute(){if(this.updateStateIfNeeded(),this.state.state==="open")return!1;if(this.state.state==="half-open"){if(this.state.halfOpenCount>=this.config.halfOpenRequests)return!1;this.state={...this.state,halfOpenCount:this.state.halfOpenCount+1}}return!0}async recordSuccess(){switch(this.state.state){case"closed":this.state={...this.state,failureCount:0};break;case"half-open":this.state={state:"closed",failureCount:0,halfOpenCount:0};break;case"open":break}}async recordFailure(r){var o,a,s;if(!((s=(a=(o=this.config).shouldCountAsFailure)==null?void 0:a.call(o,r))!=null?s:!0))return;let n=new Date;switch(this.state.state){case"closed":{let i=this.state.failureCount+1;i>=this.config.failureThreshold?this.state={state:"open",failureCount:i,halfOpenCount:0,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)}:this.state={...this.state,failureCount:i,lastFailureTime:n};break}case"half-open":this.state={state:"open",failureCount:this.state.failureCount+1,halfOpenCount:0,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)};break;case"open":this.state={...this.state,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)};break}}getState(){return this.updateStateIfNeeded(),{...this.state,canExecute:this.state.state!=="open"}}createOpenError(){let r=this.state.nextAttemptTime?b(Math.max(0,this.state.nextAttemptTime.getTime()-Date.now())):this.config.resetTimeout;return new U(r)}forceState(r){this.state={state:r,failureCount:0,halfOpenCount:0}}reset(){this.state={state:"closed",failureCount:0,halfOpenCount:0}}updateStateIfNeeded(){this.state.state==="open"&&this.state.nextAttemptTime&&new Date>=this.state.nextAttemptTime&&(this.state={...this.state,state:"half-open",halfOpenCount:0})}};var ee=(e,r)=>t=>{for(let n of e){let o=n(t);if(o!==null)return o}return r(t)},re=e=>r=>r instanceof m?r:r instanceof Error?new e(r.message,r):typeof r=="string"?new e(r):new e("Unknown error occurred",r);var Oe=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.status=="number"||typeof r.statusCode=="number"},Ae=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.code=="string"&&r.code.length>0},Se=e=>{var r;if(e instanceof Error){let t=e.message.toLowerCase();if(e.name==="TypeError"&&(t.includes("fetch")&&t.includes("failed")||t.includes("network"))||t.includes("fetch")&&t.includes("failed")||t.includes("network"))return!0}if(Ae(e)){let t=((r=e.code)!=null?r:"").toUpperCase();return t==="ECONNRESET"||t==="ECONNREFUSED"||t==="ETIMEDOUT"||t==="ENOTFOUND"||t==="EAI_AGAIN"}return!1},Ne=e=>typeof e=="object"&&e!==null,H=class{constructor(r){this.predicate=r}toCode(r){return new V(this.predicate,r)}toError(r){return t=>{var c;if(!this.predicate(t))return null;let n=r(t),o=n.code,a=Object.hasOwn(n,"cause")?n.cause:t,s=(c=n.meta)!=null?c:{};class i extends m{constructor(){let y=Object.hasOwn(n,"raw")?n.raw:t;super(n.message,{title:n.title,cause:a,meta:s,status:n.status,retryable:n.retryable,raw:y,path:n.path});l(this,"code",o)}}return new i}}};function Me(e,r){let t=new H(a=>a instanceof e);if(r)return t.toError(r);let o=a=>{if(!(a instanceof e))return null;if(a instanceof m)return a;let s=a,i=typeof s.code=="string"&&s.code.length>0?s.code:"UNKNOWN",c=Object.hasOwn(s,"cause"),u=Object.hasOwn(s,"raw");class d extends m{constructor(){super(s.message||i,{title:typeof s.title=="string"?s.title:void 0,cause:c?s.cause:a,meta:Ne(s.meta)?s.meta:{},status:typeof s.status=="number"?s.status:void 0,retryable:typeof s.retryable=="boolean"?s.retryable:void 0,raw:u?s.raw:a,path:typeof s.path=="string"?s.path:void 0});l(this,"code",i)}}return new d};return o.toCode=t.toCode.bind(t),o.toError=t.toError.bind(t),o}var V=class{constructor(r,t){this.predicate=r;this.errorCode=t}with(r){return t=>{var c;if(!this.predicate(t))return null;let n=r(t),o=Object.hasOwn(n,"cause")?n.cause:t,a=(c=n.meta)!=null?c:{},s=this.errorCode;class i extends m{constructor(){let T=Object.hasOwn(n,"raw")?n.raw:t;super(n.message,{title:n.title,cause:o,meta:a,status:n.status,retryable:n.retryable,raw:T,path:n.path});l(this,"code",s)}}return new i}}},R={when:e=>new H(e),instance:Me},g={typed:(e=>e instanceof m?e:null),abort:R.when(e=>e instanceof Error&&e.name==="AbortError").toCode("ABORTED").with(e=>({message:e.message||"Operation was aborted",cause:e,retryable:!1,raw:e})),timeout:R.when(e=>e instanceof Error&&e.name==="TimeoutError").toCode("TIMEOUT").with(e=>({message:e.message||"Operation timed out",cause:e,raw:e})),network:R.when(e=>Se(e)).toCode("NETWORK").with(e=>({message:(e instanceof Error,e.message||"Network error"),cause:e,raw:e})),http:R.when(e=>{var n;if(!Oe(e))return!1;let r=e,t=(n=r.status)!=null?n:r.statusCode;return typeof t=="number"&&t>=400}).toCode("HTTP").with(e=>{var n;let r=(n=e.status)!=null?n:e.statusCode,t=typeof r=="number"&&(r>=500||r===429);return{message:e.message||`HTTP ${r!=null?r:"error"} error`,cause:e,status:typeof r=="number"?r:void 0,retryable:t,raw:e}}),unknown:R.when(e=>e instanceof Error&&!(e instanceof m)).toCode("UNKNOWN").with(e=>({message:e.message||"Unknown error occurred",cause:e,raw:e}))};var Ie=[g.typed,g.abort,g.timeout,g.http,g.network,g.unknown];var te={when:e=>R.when(e),instance:R.instance},ne=Ie;var oe={fixed:e=>({type:"fixed",delay:e}),exponential:(e,r=2,t)=>({type:"exponential",base:e,factor:r,maxDelay:t}),fibonacci:(e,r)=>({type:"fibonacci",base:e,maxDelay:r}),custom:e=>({type:"custom",calculate:e})},se=(e,r,t)=>{switch(e.type){case"fixed":return e.delay;case"exponential":{let n=e.base*e.factor**(Number(r)-1);return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"fibonacci":{let n=e.base*ve(Number(r));return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"custom":return e.calculate(r,t);default:return e}},ve=e=>{if(e<=1)return 1;let r=1,t=1;for(let n=2;n<=e;n++){let o=r+t;r=t,t=o}return t},ae=e=>{switch(e.type){case"fixed":{if(e.delay<0)throw new Error("Fixed delay must be non-negative");break}case"exponential":if(e.base<=0)throw new Error("Exponential base delay must be positive");if(e.factor<=1)throw new Error("Exponential factor must be greater than 1");if(e.maxDelay!==void 0&&e.maxDelay<=0)throw new Error("Exponential max delay must be positive");break;case"fibonacci":if(e.base<=0)throw new Error("Fibonacci base delay must be positive");if(e.maxDelay!==void 0&&e.maxDelay<=0)throw new Error("Fibonacci max delay must be positive");break;case"custom":break;default:{let r=e;throw new Error(`Unknown strategy type: ${r}`)}}};var ie=(e,r)=>new Promise((t,n)=>{if(r!=null&&r.aborted){n(new DOMException("Aborted","AbortError"));return}let o=i=>{r&&i&&r.removeEventListener("abort",i)},a,s=()=>{a&&clearTimeout(a),o(s),n(new DOMException("Aborted","AbortError"))};a=setTimeout(()=>{o(s),t()},e),r==null||r.addEventListener("abort",s,{once:!0})}),ue=(e,r,t,n)=>new Promise((o,a)=>{if(t!=null&&t.aborted){a(new DOMException("Aborted","AbortError"));return}let s=!1,i=setTimeout(()=>{var d;s=!0,u(),a((d=n==null?void 0:n())!=null?d:new Error(`Operation timed out after ${r}ms`))},r),c=()=>{s||(s=!0,u(),a(new DOMException("Aborted","AbortError")))},u=()=>{clearTimeout(i),t==null||t.removeEventListener("abort",c)};t==null||t.addEventListener("abort",c,{once:!0}),e.then(d=>{s||(s=!0,u(),o(d))},d=>{s||(s=!0,u(),a(d))})});var De=e=>{var s,i,c;if(e.toError)return e.toError;let r=(s=e.rulesMode)!=null?s:"extend",t=(i=e.rules)!=null?i:[],n=ne,o=(c=e.fallback)!=null?c:(u=>re(L)(u)),a=r==="replace"?t:[...t,...n];return ee(a,o)},Pe=e=>{if(e)switch(e.type){case"none":return;case"full":case"equal":Z(e.ratio);return;case"custom":return;default:{let r=e;throw new Error(`Unsupported jitter configuration: ${r}`)}}},J=e=>{let r=e;return r.timeout!==void 0&&(r={...r,timeout:Number(b(r.timeout))}),r.concurrency!==void 0&&(r={...r,concurrency:Number.isFinite(r.concurrency)?Number(K(r.concurrency)):r.concurrency}),r.retry&&(ae(r.retry.strategy),Pe(r.retry.jitter),r={...r,retry:{...r.retry,maxRetries:Number(h(r.retry.maxRetries))}}),r},j=class e{constructor(r={}){l(this,"circuitBreaker");l(this,"config");l(this,"lastCircuitState");let{rules:t,rulesMode:n,fallback:o,toError:a,mapError:s,...i}=r,c=De(r),u={...i,errorHandling:{normalizer:c,mapError:s}};this.config=J(u),u.circuitBreaker&&(this.circuitBreaker=new z(u.circuitBreaker),this.lastCircuitState=this.circuitBreaker.getState().state)}async run(r,t={}){var a,s,i,c;let n=J({...this.config,...t});if(this.circuitBreaker){let u=(a=this.lastCircuitState)!=null?a:this.circuitBreaker.getState().state,d=await this.circuitBreaker.canExecute(),y=this.circuitBreaker.getState().state;if(u!==y)try{(s=n.onCircuitStateChange)==null||s.call(n,u,y)}catch{}if(this.lastCircuitState=y,!d)return{type:"failure",ok:!1,data:null,error:this.circuitBreaker.createOpenError(),metrics:{totalAttempts:0,totalRetries:0,totalDuration:0,retryHistory:[]}}}let o=await Fe(r,n);if(this.circuitBreaker){let u=(i=this.lastCircuitState)!=null?i:this.circuitBreaker.getState().state;o.ok?await this.circuitBreaker.recordSuccess():await this.circuitBreaker.recordFailure(o.error);let d=this.circuitBreaker.getState().state;if(u!==d)try{(c=n.onCircuitStateChange)==null||c.call(n,u,d)}catch{}this.lastCircuitState=d}return o}async runOrThrow(r,t={}){return this.orThrow(r,t)}async orThrow(r,t={}){let n=await this.run(r,t);if(n.ok)return n.data;throw n.error}async all(r,t={}){var d;let n=J({...this.config,...t}),o=(d=n.concurrency)!=null?d:Number.POSITIVE_INFINITY,a=Number.isFinite(o)?Number(K(o)):Number.POSITIVE_INFINITY;if(a===Number.POSITIVE_INFINITY)return Promise.all(r.map(y=>this.run(y,n)));let s=new Array(r.length),i=0,c=async()=>{var y;for(;i<r.length&&!((y=n.signal)!=null&&y.aborted);){let T=i++;if(T>=r.length)break;let E=r[T];E&&(s[T]=await this.run(E,n))}},u=Array.from({length:Math.min(a,r.length)},()=>c());await Promise.all(u);for(let y=0;y<r.length;y++)if(!(y in s)){let T=r[y];T&&(s[y]=await this.run(T,n))}return s}async allOrThrow(r,t={}){return(await this.all(r,t)).map(o=>{if(!o.ok)throw o.error;return o.data})}partitionAll(r){let t=[],n=[],o=[],a=[],s=[];for(let i of r){if(i.type==="success"){t.push(i);continue}switch(n.push(i),i.type){case"failure":o.push(i);break;case"aborted":a.push(i);break;case"timeout":s.push(i);break}}return{ok:t,errors:n,failure:o,aborted:a,timeout:s}}getCircuitBreakerState(){var r;return(r=this.circuitBreaker)==null?void 0:r.getState()}resetCircuitBreaker(){var r;(r=this.circuitBreaker)==null||r.reset()}getConfig(){return{...this.config}}withConfig(r){var c,u;let{errorHandling:t,...n}=this.config,{errorHandling:o,...a}=r,s=(c=o==null?void 0:o.normalizer)!=null?c:t.normalizer,i=(u=o==null?void 0:o.mapError)!=null?u:t.mapError;return new e({...n,...a,toError:s,mapError:i})}};function S(e={}){let r=new j(e);return{run:(t,n)=>r.run(t,n),orThrow:(t,n)=>r.orThrow(t,n),runOrThrow:(t,n)=>r.runOrThrow(t,n),all:(t,n)=>r.all(t,n),allOrThrow:(t,n)=>r.allOrThrow(t,n),partitionAll:t=>r.partitionAll(t),withConfig:t=>r.withConfig(t)}}async function Fe(e,r){let{signal:t,ignoreAbort:n=!0,timeout:o,retry:a,errorHandling:s,logger:i,onSuccess:c,onError:u,onFinally:d,onAbort:y,onRetry:T}=r,E=(x,...p)=>{try{x==null||x(...p)}catch{}},M,k=0,q=0,C=[],I=Date.now(),{signal:v,cleanup:fe}=ce(t),D=x=>({totalAttempts:k,totalRetries:k>0?Number(k)-1:0,totalDuration:Date.now()-I,lastError:x,retryHistory:C});try{if(v.aborted){E(y,v);let p=s.normalizer(new DOMException("Aborted","AbortError")),w=s.mapError?s.mapError(p):p;return{type:"aborted",ok:!1,data:null,error:w,metrics:{totalAttempts:k,totalRetries:q,totalDuration:Date.now()-I,lastError:w,retryHistory:C}}}let x=async()=>{var P,O,Y;let p=1,w=h((P=a==null?void 0:a.maxRetries)!=null?P:0);for(;;){k=p;let G=new AbortController,{signal:$,cleanup:Ee}=ce(v,G.signal);try{let F=Promise.resolve(e({signal:$})),A=o?await ue(F,o,$,()=>(G.abort(),new _(b(o)))):await F;return E(c,A,D()),E(i==null?void 0:i.info,`Task succeeded on attempt ${p}`),A}catch(F){let A=s.normalizer(F),f=s.mapError?s.mapError(A):A;if(M=f,f.code==="ABORTED"&&E(y,$),n&&f.code==="ABORTED"||(E(u,f,D(f)),E(i==null?void 0:i.error,`Task failed on attempt ${p}`,f)),f.code==="ABORTED"||f.retryable===!1)throw f;if(p<=Number(w)){let Q=a==null?void 0:a.shouldRetry,we={totalAttempts:Number(k),elapsedTime:Date.now()-I,startTime:new Date(I),lastDelay:(O=C[C.length-1])!=null&&O.delay?Number((Y=C[C.length-1])==null?void 0:Y.delay):void 0};if(!Q||Q(p,f,we)){let Te=a?se(a.strategy,p,f):0,W=Be(Te,a==null?void 0:a.jitter),X=b(W);C.push({attempt:p,error:f,delay:X,timestamp:new Date}),E(T,p,f,W),E(i==null?void 0:i.info,`Retrying in ${W}ms (attempt ${p+1})`),p+=1,await ie(X,v);continue}}throw f}finally{Ee()}}};try{let p=await x(),w=D();return q=w.totalRetries,E(d,w),{type:"success",ok:!0,data:p,error:null,metrics:w}}catch(p){let w=M!=null?M:s.normalizer(p),P=w.code==="TIMEOUT"?"timeout":w.code==="ABORTED"?"aborted":"failure",O=D(w);return q=O.totalRetries,E(d,O),{type:P,ok:!1,data:null,error:w,metrics:O}}}finally{fe()}}function ce(...e){let r=new AbortController,t=e.filter(o=>o!==void 0);if(t.length===0)return{signal:r.signal,cleanup:()=>{}};if(t.some(o=>o.aborted))return r.abort(),{signal:r.signal,cleanup:()=>{}};let n=[];for(let o of t){let a=()=>r.abort();o.addEventListener("abort",a,{once:!0}),n.push({signal:o,abort:a})}return{signal:r.signal,cleanup:()=>{for(let o of n)o.signal.removeEventListener("abort",o.abort)}}}function Be(e,r){if(!r||r.type==="none"||e<=0)return e;switch(r.type){case"full":{let t=Number(r.ratio)/100,n=Math.max(0,Number(e)*(1-t)),o=Number(e);return n+Math.random()*(o-n)}case"equal":{let t=Number(r.ratio)/100,n=Number(e)*t/2;return Number(e)-n+Math.random()*n}case"custom":return r.calculate(e);default:return r}}var N=S(),le=N.run,de=N.runOrThrow,ye=N.orThrow,pe=N.all,me=N.allOrThrow;0&&(module.exports={RetryStrategies,TypedError,all,allOrThrow,asMilliseconds,asRetryCount,errorRule,orThrow,run,runOrThrow,tryo});
|
package/dist/index.d.cts
CHANGED
|
@@ -94,6 +94,23 @@ declare class UnknownError extends TypedError<'UNKNOWN', Record<string, unknown>
|
|
|
94
94
|
constructor(message: string, cause?: unknown);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Modern circuit breaker implementation with enhanced state management
|
|
99
|
+
* Provides circuit breaker pattern with type safety and observability
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
interface CircuitBreakerConfig<E extends AnyTypedError = AnyTypedError> {
|
|
103
|
+
/** Number of consecutive failures before opening circuit */
|
|
104
|
+
readonly failureThreshold: number;
|
|
105
|
+
/** How long to wait before attempting to close circuit */
|
|
106
|
+
readonly resetTimeout: number;
|
|
107
|
+
/** Number of requests allowed in half-open state */
|
|
108
|
+
readonly halfOpenRequests: number;
|
|
109
|
+
/** Optional function to determine if error should count as failure */
|
|
110
|
+
readonly shouldCountAsFailure?: (error: E) => boolean;
|
|
111
|
+
}
|
|
112
|
+
type CircuitState = 'closed' | 'open' | 'half-open';
|
|
113
|
+
|
|
97
114
|
/**
|
|
98
115
|
* Modern result types with enhanced discriminated unions
|
|
99
116
|
* Provides better type safety and more granular result categorization
|
|
@@ -141,23 +158,6 @@ interface TryoMetrics$1<E extends AnyTypedError> {
|
|
|
141
158
|
}>;
|
|
142
159
|
}
|
|
143
160
|
|
|
144
|
-
/**
|
|
145
|
-
* Modern circuit breaker implementation with enhanced state management
|
|
146
|
-
* Provides circuit breaker pattern with type safety and observability
|
|
147
|
-
*/
|
|
148
|
-
|
|
149
|
-
interface CircuitBreakerConfig<E extends AnyTypedError = AnyTypedError> {
|
|
150
|
-
/** Number of consecutive failures before opening circuit */
|
|
151
|
-
readonly failureThreshold: number;
|
|
152
|
-
/** How long to wait before attempting to close circuit */
|
|
153
|
-
readonly resetTimeout: number;
|
|
154
|
-
/** Number of requests allowed in half-open state */
|
|
155
|
-
readonly halfOpenRequests: number;
|
|
156
|
-
/** Optional function to determine if error should count as failure */
|
|
157
|
-
readonly shouldCountAsFailure?: (error: E) => boolean;
|
|
158
|
-
}
|
|
159
|
-
type CircuitState = 'closed' | 'open' | 'half-open';
|
|
160
|
-
|
|
161
161
|
/**
|
|
162
162
|
* Modern error normalization system
|
|
163
163
|
* Provides type-safe error transformation and normalization
|
|
@@ -215,8 +215,18 @@ interface TryoConfig<E extends AnyTypedError = AnyTypedError> {
|
|
|
215
215
|
readonly concurrency?: number;
|
|
216
216
|
/** Logging configuration */
|
|
217
217
|
readonly logger?: LoggerConfig<E>;
|
|
218
|
-
/**
|
|
219
|
-
readonly
|
|
218
|
+
/** Called on successful execution */
|
|
219
|
+
readonly onSuccess?: <T>(data: T, metrics?: TryoMetrics<E>) => void;
|
|
220
|
+
/** Called on failed execution */
|
|
221
|
+
readonly onError?: (error: E, metrics?: TryoMetrics<E>) => void;
|
|
222
|
+
/** Called always, success or failure */
|
|
223
|
+
readonly onFinally?: (metrics?: TryoMetrics<E>) => void;
|
|
224
|
+
/** Called on abort */
|
|
225
|
+
readonly onAbort?: (signal: AbortSignal) => void;
|
|
226
|
+
/** Called before retry attempt */
|
|
227
|
+
readonly onRetry?: (attempt: number, error: E, delay: number) => void;
|
|
228
|
+
/** Called when circuit breaker state changes */
|
|
229
|
+
readonly onCircuitStateChange?: (from: CircuitState, to: CircuitState) => void;
|
|
220
230
|
}
|
|
221
231
|
interface RetryConfig<E extends AnyTypedError> {
|
|
222
232
|
/** Maximum number of retry attempts */
|
|
@@ -255,20 +265,6 @@ interface LoggerConfig<E extends AnyTypedError> {
|
|
|
255
265
|
/** Warning logging function */
|
|
256
266
|
readonly warn?: (message: string, meta?: unknown) => void;
|
|
257
267
|
}
|
|
258
|
-
interface HookConfig<E extends AnyTypedError> {
|
|
259
|
-
/** Called on successful execution */
|
|
260
|
-
readonly onSuccess?: <T>(data: T, metrics?: TryoMetrics<E>) => void;
|
|
261
|
-
/** Called on failed execution */
|
|
262
|
-
readonly onError?: (error: E, metrics?: TryoMetrics<E>) => void;
|
|
263
|
-
/** Called always, success or failure */
|
|
264
|
-
readonly onFinally?: (metrics?: TryoMetrics<E>) => void;
|
|
265
|
-
/** Called on abort */
|
|
266
|
-
readonly onAbort?: (signal: AbortSignal) => void;
|
|
267
|
-
/** Called before retry attempt */
|
|
268
|
-
readonly onRetry?: (attempt: number, error: E, delay: number) => void;
|
|
269
|
-
/** Called when circuit breaker state changes */
|
|
270
|
-
readonly onCircuitStateChange?: (from: CircuitState, to: CircuitState) => void;
|
|
271
|
-
}
|
|
272
268
|
type TryoMetrics<E extends AnyTypedError> = TryoMetrics$1<E>;
|
|
273
269
|
type JitterConfig = {
|
|
274
270
|
type: 'none';
|
|
@@ -317,15 +313,14 @@ type CheckUniqueCodes<T extends readonly unknown[], Seen = never> = T extends re
|
|
|
317
313
|
type UniqueRulesConstraint<TRules extends readonly RuleLike[]> = CheckUniqueCodes<TRules> extends true ? unknown : {
|
|
318
314
|
__duplicate_error_codes__: CheckUniqueCodes<TRules>;
|
|
319
315
|
};
|
|
320
|
-
|
|
321
|
-
declare function tryo<const TRules extends readonly unknown[]>(options: Omit<TryoOptions<InferErrorFromRules<EnsureRuleTuple<TRules>>>, 'rules' | 'rulesMode'> & {
|
|
316
|
+
declare function tryo<const TRules extends readonly RuleLike[]>(options: Omit<TryoOptions<InferErrorFromRules<TRules>>, 'rules' | 'rulesMode'> & {
|
|
322
317
|
rules: TRules;
|
|
323
318
|
rulesMode: 'replace';
|
|
324
|
-
} & UniqueRulesConstraint<
|
|
325
|
-
declare function tryo<const TRules extends readonly
|
|
319
|
+
} & UniqueRulesConstraint<TRules>): Tryo<InferErrorFromRules<TRules>>;
|
|
320
|
+
declare function tryo<const TRules extends readonly RuleLike[]>(options: Omit<TryoOptions<InferErrorFromRules<TRules> | DefaultError>, 'rules'> & {
|
|
326
321
|
rules: TRules;
|
|
327
322
|
rulesMode?: 'extend';
|
|
328
|
-
} & UniqueRulesConstraint<
|
|
323
|
+
} & UniqueRulesConstraint<TRules>): Tryo<InferErrorFromRules<TRules> | DefaultError>;
|
|
329
324
|
declare function tryo<E extends AnyTypedError = DefaultError>(options?: TryoOptions<E>): Tryo<E>;
|
|
330
325
|
type Tryo<E extends AnyTypedError = AnyTypedError> = {
|
|
331
326
|
run: <T>(task: (ctx: {
|
|
@@ -363,7 +358,12 @@ declare const run: <T>(task: (ctx: {
|
|
|
363
358
|
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
364
359
|
readonly concurrency?: number | undefined;
|
|
365
360
|
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
366
|
-
readonly
|
|
361
|
+
readonly onSuccess?: (<T_1>(data: T_1, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
362
|
+
readonly onError?: ((error: DefaultError, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
363
|
+
readonly onFinally?: ((metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
364
|
+
readonly onAbort?: ((signal: AbortSignal) => void) | undefined;
|
|
365
|
+
readonly onRetry?: ((attempt: number, error: DefaultError, delay: number) => void) | undefined;
|
|
366
|
+
readonly onCircuitStateChange?: ((from: CircuitState, to: CircuitState) => void) | undefined;
|
|
367
367
|
} | undefined) => Promise<TryoResult<T, DefaultError>>;
|
|
368
368
|
declare const runOrThrow: <T>(task: (ctx: {
|
|
369
369
|
signal: AbortSignal;
|
|
@@ -375,7 +375,12 @@ declare const runOrThrow: <T>(task: (ctx: {
|
|
|
375
375
|
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
376
376
|
readonly concurrency?: number | undefined;
|
|
377
377
|
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
378
|
-
readonly
|
|
378
|
+
readonly onSuccess?: (<T_1>(data: T_1, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
379
|
+
readonly onError?: ((error: DefaultError, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
380
|
+
readonly onFinally?: ((metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
381
|
+
readonly onAbort?: ((signal: AbortSignal) => void) | undefined;
|
|
382
|
+
readonly onRetry?: ((attempt: number, error: DefaultError, delay: number) => void) | undefined;
|
|
383
|
+
readonly onCircuitStateChange?: ((from: CircuitState, to: CircuitState) => void) | undefined;
|
|
379
384
|
} | undefined) => Promise<T>;
|
|
380
385
|
declare const orThrow: <T>(task: (ctx: {
|
|
381
386
|
signal: AbortSignal;
|
|
@@ -387,7 +392,12 @@ declare const orThrow: <T>(task: (ctx: {
|
|
|
387
392
|
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
388
393
|
readonly concurrency?: number | undefined;
|
|
389
394
|
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
390
|
-
readonly
|
|
395
|
+
readonly onSuccess?: (<T_1>(data: T_1, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
396
|
+
readonly onError?: ((error: DefaultError, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
397
|
+
readonly onFinally?: ((metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
398
|
+
readonly onAbort?: ((signal: AbortSignal) => void) | undefined;
|
|
399
|
+
readonly onRetry?: ((attempt: number, error: DefaultError, delay: number) => void) | undefined;
|
|
400
|
+
readonly onCircuitStateChange?: ((from: CircuitState, to: CircuitState) => void) | undefined;
|
|
391
401
|
} | undefined) => Promise<T>;
|
|
392
402
|
declare const all: <T>(tasks: ((ctx: {
|
|
393
403
|
signal: AbortSignal;
|
|
@@ -399,7 +409,12 @@ declare const all: <T>(tasks: ((ctx: {
|
|
|
399
409
|
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
400
410
|
concurrency?: number | undefined;
|
|
401
411
|
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
402
|
-
readonly
|
|
412
|
+
readonly onSuccess?: (<T_1>(data: T_1, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
413
|
+
readonly onError?: ((error: DefaultError, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
414
|
+
readonly onFinally?: ((metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
415
|
+
readonly onAbort?: ((signal: AbortSignal) => void) | undefined;
|
|
416
|
+
readonly onRetry?: ((attempt: number, error: DefaultError, delay: number) => void) | undefined;
|
|
417
|
+
readonly onCircuitStateChange?: ((from: CircuitState, to: CircuitState) => void) | undefined;
|
|
403
418
|
} | undefined) => Promise<TryoResult<T, DefaultError>[]>;
|
|
404
419
|
declare const allOrThrow: <T>(tasks: ((ctx: {
|
|
405
420
|
signal: AbortSignal;
|
|
@@ -411,7 +426,12 @@ declare const allOrThrow: <T>(tasks: ((ctx: {
|
|
|
411
426
|
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
412
427
|
concurrency?: number | undefined;
|
|
413
428
|
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
414
|
-
readonly
|
|
429
|
+
readonly onSuccess?: (<T_1>(data: T_1, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
430
|
+
readonly onError?: ((error: DefaultError, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
431
|
+
readonly onFinally?: ((metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
432
|
+
readonly onAbort?: ((signal: AbortSignal) => void) | undefined;
|
|
433
|
+
readonly onRetry?: ((attempt: number, error: DefaultError, delay: number) => void) | undefined;
|
|
434
|
+
readonly onCircuitStateChange?: ((from: CircuitState, to: CircuitState) => void) | undefined;
|
|
415
435
|
} | undefined) => Promise<T[]>;
|
|
416
436
|
|
|
417
437
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -94,6 +94,23 @@ declare class UnknownError extends TypedError<'UNKNOWN', Record<string, unknown>
|
|
|
94
94
|
constructor(message: string, cause?: unknown);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/**
|
|
98
|
+
* Modern circuit breaker implementation with enhanced state management
|
|
99
|
+
* Provides circuit breaker pattern with type safety and observability
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
interface CircuitBreakerConfig<E extends AnyTypedError = AnyTypedError> {
|
|
103
|
+
/** Number of consecutive failures before opening circuit */
|
|
104
|
+
readonly failureThreshold: number;
|
|
105
|
+
/** How long to wait before attempting to close circuit */
|
|
106
|
+
readonly resetTimeout: number;
|
|
107
|
+
/** Number of requests allowed in half-open state */
|
|
108
|
+
readonly halfOpenRequests: number;
|
|
109
|
+
/** Optional function to determine if error should count as failure */
|
|
110
|
+
readonly shouldCountAsFailure?: (error: E) => boolean;
|
|
111
|
+
}
|
|
112
|
+
type CircuitState = 'closed' | 'open' | 'half-open';
|
|
113
|
+
|
|
97
114
|
/**
|
|
98
115
|
* Modern result types with enhanced discriminated unions
|
|
99
116
|
* Provides better type safety and more granular result categorization
|
|
@@ -141,23 +158,6 @@ interface TryoMetrics$1<E extends AnyTypedError> {
|
|
|
141
158
|
}>;
|
|
142
159
|
}
|
|
143
160
|
|
|
144
|
-
/**
|
|
145
|
-
* Modern circuit breaker implementation with enhanced state management
|
|
146
|
-
* Provides circuit breaker pattern with type safety and observability
|
|
147
|
-
*/
|
|
148
|
-
|
|
149
|
-
interface CircuitBreakerConfig<E extends AnyTypedError = AnyTypedError> {
|
|
150
|
-
/** Number of consecutive failures before opening circuit */
|
|
151
|
-
readonly failureThreshold: number;
|
|
152
|
-
/** How long to wait before attempting to close circuit */
|
|
153
|
-
readonly resetTimeout: number;
|
|
154
|
-
/** Number of requests allowed in half-open state */
|
|
155
|
-
readonly halfOpenRequests: number;
|
|
156
|
-
/** Optional function to determine if error should count as failure */
|
|
157
|
-
readonly shouldCountAsFailure?: (error: E) => boolean;
|
|
158
|
-
}
|
|
159
|
-
type CircuitState = 'closed' | 'open' | 'half-open';
|
|
160
|
-
|
|
161
161
|
/**
|
|
162
162
|
* Modern error normalization system
|
|
163
163
|
* Provides type-safe error transformation and normalization
|
|
@@ -215,8 +215,18 @@ interface TryoConfig<E extends AnyTypedError = AnyTypedError> {
|
|
|
215
215
|
readonly concurrency?: number;
|
|
216
216
|
/** Logging configuration */
|
|
217
217
|
readonly logger?: LoggerConfig<E>;
|
|
218
|
-
/**
|
|
219
|
-
readonly
|
|
218
|
+
/** Called on successful execution */
|
|
219
|
+
readonly onSuccess?: <T>(data: T, metrics?: TryoMetrics<E>) => void;
|
|
220
|
+
/** Called on failed execution */
|
|
221
|
+
readonly onError?: (error: E, metrics?: TryoMetrics<E>) => void;
|
|
222
|
+
/** Called always, success or failure */
|
|
223
|
+
readonly onFinally?: (metrics?: TryoMetrics<E>) => void;
|
|
224
|
+
/** Called on abort */
|
|
225
|
+
readonly onAbort?: (signal: AbortSignal) => void;
|
|
226
|
+
/** Called before retry attempt */
|
|
227
|
+
readonly onRetry?: (attempt: number, error: E, delay: number) => void;
|
|
228
|
+
/** Called when circuit breaker state changes */
|
|
229
|
+
readonly onCircuitStateChange?: (from: CircuitState, to: CircuitState) => void;
|
|
220
230
|
}
|
|
221
231
|
interface RetryConfig<E extends AnyTypedError> {
|
|
222
232
|
/** Maximum number of retry attempts */
|
|
@@ -255,20 +265,6 @@ interface LoggerConfig<E extends AnyTypedError> {
|
|
|
255
265
|
/** Warning logging function */
|
|
256
266
|
readonly warn?: (message: string, meta?: unknown) => void;
|
|
257
267
|
}
|
|
258
|
-
interface HookConfig<E extends AnyTypedError> {
|
|
259
|
-
/** Called on successful execution */
|
|
260
|
-
readonly onSuccess?: <T>(data: T, metrics?: TryoMetrics<E>) => void;
|
|
261
|
-
/** Called on failed execution */
|
|
262
|
-
readonly onError?: (error: E, metrics?: TryoMetrics<E>) => void;
|
|
263
|
-
/** Called always, success or failure */
|
|
264
|
-
readonly onFinally?: (metrics?: TryoMetrics<E>) => void;
|
|
265
|
-
/** Called on abort */
|
|
266
|
-
readonly onAbort?: (signal: AbortSignal) => void;
|
|
267
|
-
/** Called before retry attempt */
|
|
268
|
-
readonly onRetry?: (attempt: number, error: E, delay: number) => void;
|
|
269
|
-
/** Called when circuit breaker state changes */
|
|
270
|
-
readonly onCircuitStateChange?: (from: CircuitState, to: CircuitState) => void;
|
|
271
|
-
}
|
|
272
268
|
type TryoMetrics<E extends AnyTypedError> = TryoMetrics$1<E>;
|
|
273
269
|
type JitterConfig = {
|
|
274
270
|
type: 'none';
|
|
@@ -317,15 +313,14 @@ type CheckUniqueCodes<T extends readonly unknown[], Seen = never> = T extends re
|
|
|
317
313
|
type UniqueRulesConstraint<TRules extends readonly RuleLike[]> = CheckUniqueCodes<TRules> extends true ? unknown : {
|
|
318
314
|
__duplicate_error_codes__: CheckUniqueCodes<TRules>;
|
|
319
315
|
};
|
|
320
|
-
|
|
321
|
-
declare function tryo<const TRules extends readonly unknown[]>(options: Omit<TryoOptions<InferErrorFromRules<EnsureRuleTuple<TRules>>>, 'rules' | 'rulesMode'> & {
|
|
316
|
+
declare function tryo<const TRules extends readonly RuleLike[]>(options: Omit<TryoOptions<InferErrorFromRules<TRules>>, 'rules' | 'rulesMode'> & {
|
|
322
317
|
rules: TRules;
|
|
323
318
|
rulesMode: 'replace';
|
|
324
|
-
} & UniqueRulesConstraint<
|
|
325
|
-
declare function tryo<const TRules extends readonly
|
|
319
|
+
} & UniqueRulesConstraint<TRules>): Tryo<InferErrorFromRules<TRules>>;
|
|
320
|
+
declare function tryo<const TRules extends readonly RuleLike[]>(options: Omit<TryoOptions<InferErrorFromRules<TRules> | DefaultError>, 'rules'> & {
|
|
326
321
|
rules: TRules;
|
|
327
322
|
rulesMode?: 'extend';
|
|
328
|
-
} & UniqueRulesConstraint<
|
|
323
|
+
} & UniqueRulesConstraint<TRules>): Tryo<InferErrorFromRules<TRules> | DefaultError>;
|
|
329
324
|
declare function tryo<E extends AnyTypedError = DefaultError>(options?: TryoOptions<E>): Tryo<E>;
|
|
330
325
|
type Tryo<E extends AnyTypedError = AnyTypedError> = {
|
|
331
326
|
run: <T>(task: (ctx: {
|
|
@@ -363,7 +358,12 @@ declare const run: <T>(task: (ctx: {
|
|
|
363
358
|
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
364
359
|
readonly concurrency?: number | undefined;
|
|
365
360
|
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
366
|
-
readonly
|
|
361
|
+
readonly onSuccess?: (<T_1>(data: T_1, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
362
|
+
readonly onError?: ((error: DefaultError, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
363
|
+
readonly onFinally?: ((metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
364
|
+
readonly onAbort?: ((signal: AbortSignal) => void) | undefined;
|
|
365
|
+
readonly onRetry?: ((attempt: number, error: DefaultError, delay: number) => void) | undefined;
|
|
366
|
+
readonly onCircuitStateChange?: ((from: CircuitState, to: CircuitState) => void) | undefined;
|
|
367
367
|
} | undefined) => Promise<TryoResult<T, DefaultError>>;
|
|
368
368
|
declare const runOrThrow: <T>(task: (ctx: {
|
|
369
369
|
signal: AbortSignal;
|
|
@@ -375,7 +375,12 @@ declare const runOrThrow: <T>(task: (ctx: {
|
|
|
375
375
|
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
376
376
|
readonly concurrency?: number | undefined;
|
|
377
377
|
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
378
|
-
readonly
|
|
378
|
+
readonly onSuccess?: (<T_1>(data: T_1, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
379
|
+
readonly onError?: ((error: DefaultError, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
380
|
+
readonly onFinally?: ((metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
381
|
+
readonly onAbort?: ((signal: AbortSignal) => void) | undefined;
|
|
382
|
+
readonly onRetry?: ((attempt: number, error: DefaultError, delay: number) => void) | undefined;
|
|
383
|
+
readonly onCircuitStateChange?: ((from: CircuitState, to: CircuitState) => void) | undefined;
|
|
379
384
|
} | undefined) => Promise<T>;
|
|
380
385
|
declare const orThrow: <T>(task: (ctx: {
|
|
381
386
|
signal: AbortSignal;
|
|
@@ -387,7 +392,12 @@ declare const orThrow: <T>(task: (ctx: {
|
|
|
387
392
|
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
388
393
|
readonly concurrency?: number | undefined;
|
|
389
394
|
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
390
|
-
readonly
|
|
395
|
+
readonly onSuccess?: (<T_1>(data: T_1, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
396
|
+
readonly onError?: ((error: DefaultError, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
397
|
+
readonly onFinally?: ((metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
398
|
+
readonly onAbort?: ((signal: AbortSignal) => void) | undefined;
|
|
399
|
+
readonly onRetry?: ((attempt: number, error: DefaultError, delay: number) => void) | undefined;
|
|
400
|
+
readonly onCircuitStateChange?: ((from: CircuitState, to: CircuitState) => void) | undefined;
|
|
391
401
|
} | undefined) => Promise<T>;
|
|
392
402
|
declare const all: <T>(tasks: ((ctx: {
|
|
393
403
|
signal: AbortSignal;
|
|
@@ -399,7 +409,12 @@ declare const all: <T>(tasks: ((ctx: {
|
|
|
399
409
|
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
400
410
|
concurrency?: number | undefined;
|
|
401
411
|
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
402
|
-
readonly
|
|
412
|
+
readonly onSuccess?: (<T_1>(data: T_1, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
413
|
+
readonly onError?: ((error: DefaultError, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
414
|
+
readonly onFinally?: ((metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
415
|
+
readonly onAbort?: ((signal: AbortSignal) => void) | undefined;
|
|
416
|
+
readonly onRetry?: ((attempt: number, error: DefaultError, delay: number) => void) | undefined;
|
|
417
|
+
readonly onCircuitStateChange?: ((from: CircuitState, to: CircuitState) => void) | undefined;
|
|
403
418
|
} | undefined) => Promise<TryoResult<T, DefaultError>[]>;
|
|
404
419
|
declare const allOrThrow: <T>(tasks: ((ctx: {
|
|
405
420
|
signal: AbortSignal;
|
|
@@ -411,7 +426,12 @@ declare const allOrThrow: <T>(tasks: ((ctx: {
|
|
|
411
426
|
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
412
427
|
concurrency?: number | undefined;
|
|
413
428
|
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
414
|
-
readonly
|
|
429
|
+
readonly onSuccess?: (<T_1>(data: T_1, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
430
|
+
readonly onError?: ((error: DefaultError, metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
431
|
+
readonly onFinally?: ((metrics?: TryoMetrics$1<DefaultError> | undefined) => void) | undefined;
|
|
432
|
+
readonly onAbort?: ((signal: AbortSignal) => void) | undefined;
|
|
433
|
+
readonly onRetry?: ((attempt: number, error: DefaultError, delay: number) => void) | undefined;
|
|
434
|
+
readonly onCircuitStateChange?: ((from: CircuitState, to: CircuitState) => void) | undefined;
|
|
415
435
|
} | undefined) => Promise<T[]>;
|
|
416
436
|
|
|
417
437
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var ie=Object.defineProperty;var ue=(e,r,t)=>r in e?ie(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t;var d=(e,r,t)=>ue(e,typeof r!="symbol"?r+"":r,t);var E=class extends Error{constructor(t,n){var s,i;super(t);d(this,"cause");d(this,"title");d(this,"meta");d(this,"status");d(this,"raw");d(this,"path");d(this,"timestamp");d(this,"retryable");this.timestamp=Date.now(),this.retryable=(s=n.retryable)!=null?s:!0,this.name=this.constructor.name,this.cause=n.cause,this.title=n.title,this.meta=(i=n.meta)!=null?i:{},this.status=n.status,this.raw=n.raw,this.path=n.path,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}is(t){return this.code===t}withMeta(t){return Object.assign(this,{meta:t})}withStatus(t){return Object.assign(this,{status:t})}withCause(t){return Object.assign(this,{cause:t})}withPath(t){return this.path=t,this}withRaw(t){return Object.assign(this,{raw:t})}withRetryable(t){return this.retryable=t,this}toJSON(){return{name:this.name,code:this.code,title:this.title,message:this.message,timestamp:this.timestamp,retryable:this.retryable,cause:this.cause,raw:this.raw,path:this.path,stack:this.stack}}},v=class extends E{constructor(t,n){super(`Operation timed out after ${t}ms`,{cause:n,retryable:!0});d(this,"code","TIMEOUT")}};var D=class extends E{constructor(t,n){super(`Circuit breaker is open, reset after ${t}ms`,{cause:n,retryable:!1});d(this,"code","CIRCUIT_OPEN")}};var P=class extends E{constructor(t,n){super(t,{cause:n});d(this,"code","UNKNOWN")}};var b=e=>{if(e<0||!Number.isFinite(e))throw new Error(`Invalid milliseconds: must be a non-negative finite number, got ${e}`);return e},C=e=>{if(e<0||!Number.isInteger(e))throw new Error(`Invalid retry count: must be a non-negative integer, got ${e}`);return e},z=e=>{if(e<1||!Number.isInteger(e))throw new Error(`Invalid concurrency limit: must be a positive integer, got ${e}`);return e},j=e=>{if(e<0||e>100||!Number.isFinite(e))throw new Error(`Invalid percentage: must be between 0 and 100, got ${e}`);return e};var F=class{constructor(r){d(this,"state");d(this,"config");this.config={failureThreshold:C(r.failureThreshold),resetTimeout:b(r.resetTimeout),halfOpenRequests:C(r.halfOpenRequests),shouldCountAsFailure:r.shouldCountAsFailure},this.state={state:"closed",failureCount:0,halfOpenCount:0}}async canExecute(){if(this.updateStateIfNeeded(),this.state.state==="open")return!1;if(this.state.state==="half-open"){if(this.state.halfOpenCount>=this.config.halfOpenRequests)return!1;this.state={...this.state,halfOpenCount:this.state.halfOpenCount+1}}return!0}async recordSuccess(){switch(this.state.state){case"closed":this.state={...this.state,failureCount:0};break;case"half-open":this.state={state:"closed",failureCount:0,halfOpenCount:0};break;case"open":break}}async recordFailure(r){var s,i,o;if(!((o=(i=(s=this.config).shouldCountAsFailure)==null?void 0:i.call(s,r))!=null?o:!0))return;let n=new Date;switch(this.state.state){case"closed":{let a=this.state.failureCount+1;a>=this.config.failureThreshold?this.state={state:"open",failureCount:a,halfOpenCount:0,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)}:this.state={...this.state,failureCount:a,lastFailureTime:n};break}case"half-open":this.state={state:"open",failureCount:this.state.failureCount+1,halfOpenCount:0,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)};break;case"open":this.state={...this.state,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)};break}}getState(){return this.updateStateIfNeeded(),{...this.state,canExecute:this.state.state!=="open"}}createOpenError(){let r=this.state.nextAttemptTime?b(Math.max(0,this.state.nextAttemptTime.getTime()-Date.now())):this.config.resetTimeout;return new D(r)}forceState(r){this.state={state:r,failureCount:0,halfOpenCount:0}}reset(){this.state={state:"closed",failureCount:0,halfOpenCount:0}}updateStateIfNeeded(){this.state.state==="open"&&this.state.nextAttemptTime&&new Date>=this.state.nextAttemptTime&&(this.state={...this.state,state:"half-open",halfOpenCount:0})}};var Y=(e,r)=>t=>{for(let n of e){let s=n(t);if(s!==null)return s}return r(t)},G=e=>r=>r instanceof E?r:r instanceof Error?new e(r.message,r):typeof r=="string"?new e(r):new e("Unknown error occurred",r);var le=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.status=="number"||typeof r.statusCode=="number"},ce=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.code=="string"&&r.code.length>0},de=e=>{var r;if(e instanceof Error){let t=e.message.toLowerCase();if(e.name==="TypeError"&&(t.includes("fetch")&&t.includes("failed")||t.includes("network"))||t.includes("fetch")&&t.includes("failed")||t.includes("network"))return!0}if(ce(e)){let t=((r=e.code)!=null?r:"").toUpperCase();return t==="ECONNRESET"||t==="ECONNREFUSED"||t==="ETIMEDOUT"||t==="ENOTFOUND"||t==="EAI_AGAIN"}return!1},ye=e=>typeof e=="object"&&e!==null,B=class{constructor(r){this.predicate=r}toCode(r){return new H(this.predicate,r)}toError(r){return t=>{var l;if(!this.predicate(t))return null;let n=r(t),s=n.code,i=Object.hasOwn(n,"cause")?n.cause:t,o=(l=n.meta)!=null?l:{};class a extends E{constructor(){let c=Object.hasOwn(n,"raw")?n.raw:t;super(n.message,{title:n.title,cause:i,meta:o,status:n.status,retryable:n.retryable,raw:c,path:n.path});d(this,"code",s)}}return new a}}};function pe(e,r){let t=new B(i=>i instanceof e);if(r)return t.toError(r);let s=i=>{if(!(i instanceof e))return null;if(i instanceof E)return i;let o=i,a=typeof o.code=="string"&&o.code.length>0?o.code:"UNKNOWN",l=Object.hasOwn(o,"cause"),u=Object.hasOwn(o,"raw");class y extends E{constructor(){super(o.message||a,{title:typeof o.title=="string"?o.title:void 0,cause:l?o.cause:i,meta:ye(o.meta)?o.meta:{},status:typeof o.status=="number"?o.status:void 0,retryable:typeof o.retryable=="boolean"?o.retryable:void 0,raw:u?o.raw:i,path:typeof o.path=="string"?o.path:void 0});d(this,"code",a)}}return new y};return s.toCode=t.toCode.bind(t),s.toError=t.toError.bind(t),s}var H=class{constructor(r,t){this.predicate=r;this.errorCode=t}with(r){return t=>{var l;if(!this.predicate(t))return null;let n=r(t),s=Object.hasOwn(n,"cause")?n.cause:t,i=(l=n.meta)!=null?l:{},o=this.errorCode;class a extends E{constructor(){let p=Object.hasOwn(n,"raw")?n.raw:t;super(n.message,{title:n.title,cause:s,meta:i,status:n.status,retryable:n.retryable,raw:p,path:n.path});d(this,"code",o)}}return new a}}},h={when:e=>new B(e),instance:pe},x={typed:(e=>e instanceof E?e:null),abort:h.when(e=>e instanceof Error&&e.name==="AbortError").toCode("ABORTED").with(e=>({message:e.message||"Operation was aborted",cause:e,retryable:!1,raw:e})),timeout:h.when(e=>e instanceof Error&&e.name==="TimeoutError").toCode("TIMEOUT").with(e=>({message:e.message||"Operation timed out",cause:e,raw:e})),network:h.when(e=>de(e)).toCode("NETWORK").with(e=>({message:(e instanceof Error,e.message||"Network error"),cause:e,raw:e})),http:h.when(e=>{var n;if(!le(e))return!1;let r=e,t=(n=r.status)!=null?n:r.statusCode;return typeof t=="number"&&t>=400}).toCode("HTTP").with(e=>{var n;let r=(n=e.status)!=null?n:e.statusCode,t=typeof r=="number"&&(r>=500||r===429);return{message:e.message||`HTTP ${r!=null?r:"error"} error`,cause:e,status:typeof r=="number"?r:void 0,retryable:t,raw:e}}),unknown:h.when(e=>e instanceof Error&&!(e instanceof E)).toCode("UNKNOWN").with(e=>({message:e.message||"Unknown error occurred",cause:e,raw:e}))};var me=[x.typed,x.abort,x.timeout,x.http,x.network,x.unknown];var fe={when:e=>h.when(e),instance:h.instance},Q=me;var Ee={fixed:e=>({type:"fixed",delay:e}),exponential:(e,r=2,t)=>({type:"exponential",base:e,factor:r,maxDelay:t}),fibonacci:(e,r)=>({type:"fibonacci",base:e,maxDelay:r}),custom:e=>({type:"custom",calculate:e})},X=(e,r,t)=>{switch(e.type){case"fixed":return e.delay;case"exponential":{let n=e.base*e.factor**(Number(r)-1);return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"fibonacci":{let n=e.base*Te(Number(r));return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"custom":return e.calculate(r,t);default:return e}},Te=e=>{if(e<=1)return 1;let r=1,t=1;for(let n=2;n<=e;n++){let s=r+t;r=t,t=s}return t},Z=e=>{switch(e.type){case"fixed":{if(e.delay<0)throw new Error("Fixed delay must be non-negative");break}case"exponential":if(e.base<=0)throw new Error("Exponential base delay must be positive");if(e.factor<=1)throw new Error("Exponential factor must be greater than 1");if(e.maxDelay!==void 0&&e.maxDelay<=0)throw new Error("Exponential max delay must be positive");break;case"fibonacci":if(e.base<=0)throw new Error("Fibonacci base delay must be positive");if(e.maxDelay!==void 0&&e.maxDelay<=0)throw new Error("Fibonacci max delay must be positive");break;case"custom":break;default:{let r=e;throw new Error(`Unknown strategy type: ${r}`)}}};var ee=(e,r)=>new Promise((t,n)=>{if(r!=null&&r.aborted){n(new DOMException("Aborted","AbortError"));return}let s=a=>{r&&a&&r.removeEventListener("abort",a)},i,o=()=>{i&&clearTimeout(i),s(o),n(new DOMException("Aborted","AbortError"))};i=setTimeout(()=>{s(o),t()},e),r==null||r.addEventListener("abort",o,{once:!0})}),re=(e,r,t,n)=>new Promise((s,i)=>{if(t!=null&&t.aborted){i(new DOMException("Aborted","AbortError"));return}let o=!1,a=setTimeout(()=>{var y;o=!0,u(),i((y=n==null?void 0:n())!=null?y:new Error(`Operation timed out after ${r}ms`))},r),l=()=>{o||(o=!0,u(),i(new DOMException("Aborted","AbortError")))},u=()=>{clearTimeout(a),t==null||t.removeEventListener("abort",l)};t==null||t.addEventListener("abort",l,{once:!0}),e.then(y=>{o||(o=!0,u(),s(y))},y=>{o||(o=!0,u(),i(y))})});var we=e=>{var o,a,l;if(e.toError)return e.toError;let r=(o=e.rulesMode)!=null?o:"extend",t=(a=e.rules)!=null?a:[],n=Q,s=(l=e.fallback)!=null?l:(u=>G(P)(u)),i=r==="replace"?t:[...t,...n];return Y(i,s)},be=e=>{if(e)switch(e.type){case"none":return;case"full":case"equal":j(e.ratio);return;case"custom":return;default:{let r=e;throw new Error(`Unsupported jitter configuration: ${r}`)}}},q=e=>{let r=e;return r.timeout!==void 0&&(r={...r,timeout:Number(b(r.timeout))}),r.concurrency!==void 0&&(r={...r,concurrency:Number.isFinite(r.concurrency)?Number(z(r.concurrency)):r.concurrency}),r.retry&&(Z(r.retry.strategy),be(r.retry.jitter),r={...r,retry:{...r.retry,maxRetries:Number(C(r.retry.maxRetries))}}),r},$=class e{constructor(r={}){d(this,"circuitBreaker");d(this,"config");d(this,"lastCircuitState");let{rules:t,rulesMode:n,fallback:s,toError:i,mapError:o,...a}=r,l=we(r),u={...a,errorHandling:{normalizer:l,mapError:o}};this.config=q(u),u.circuitBreaker&&(this.circuitBreaker=new F(u.circuitBreaker),this.lastCircuitState=this.circuitBreaker.getState().state)}async run(r,t={}){var i,o,a,l,u,y;let n=q({...this.config,...t});if(this.circuitBreaker){let c=(i=this.lastCircuitState)!=null?i:this.circuitBreaker.getState().state,p=await this.circuitBreaker.canExecute(),T=this.circuitBreaker.getState().state;if(c!==T)try{(a=(o=n.hooks)==null?void 0:o.onCircuitStateChange)==null||a.call(o,c,T)}catch{}if(this.lastCircuitState=T,!p)return{type:"failure",ok:!1,data:null,error:this.circuitBreaker.createOpenError(),metrics:{totalAttempts:0,totalRetries:0,totalDuration:0,retryHistory:[]}}}let s=await he(r,n);if(this.circuitBreaker){let c=(l=this.lastCircuitState)!=null?l:this.circuitBreaker.getState().state;s.ok?await this.circuitBreaker.recordSuccess():await this.circuitBreaker.recordFailure(s.error);let p=this.circuitBreaker.getState().state;if(c!==p)try{(y=(u=n.hooks)==null?void 0:u.onCircuitStateChange)==null||y.call(u,c,p)}catch{}this.lastCircuitState=p}return s}async runOrThrow(r,t={}){return this.orThrow(r,t)}async orThrow(r,t={}){let n=await this.run(r,t);if(n.ok)return n.data;throw n.error}async all(r,t={}){var y;let n=q({...this.config,...t}),s=(y=n.concurrency)!=null?y:Number.POSITIVE_INFINITY,i=Number.isFinite(s)?Number(z(s)):Number.POSITIVE_INFINITY;if(i===Number.POSITIVE_INFINITY)return Promise.all(r.map(c=>this.run(c,n)));let o=new Array(r.length),a=0,l=async()=>{var c;for(;a<r.length&&!((c=n.signal)!=null&&c.aborted);){let p=a++;if(p>=r.length)break;let T=r[p];T&&(o[p]=await this.run(T,n))}},u=Array.from({length:Math.min(i,r.length)},()=>l());await Promise.all(u);for(let c=0;c<r.length;c++)if(!(c in o)){let p=r[c];p&&(o[c]=await this.run(p,n))}return o}async allOrThrow(r,t={}){return(await this.all(r,t)).map(s=>{if(!s.ok)throw s.error;return s.data})}partitionAll(r){let t=[],n=[],s=[],i=[],o=[];for(let a of r){if(a.type==="success"){t.push(a);continue}switch(n.push(a),a.type){case"failure":s.push(a);break;case"aborted":i.push(a);break;case"timeout":o.push(a);break}}return{ok:t,errors:n,failure:s,aborted:i,timeout:o}}getCircuitBreakerState(){var r;return(r=this.circuitBreaker)==null?void 0:r.getState()}resetCircuitBreaker(){var r;(r=this.circuitBreaker)==null||r.reset()}getConfig(){return{...this.config}}withConfig(r){var l,u;let{errorHandling:t,...n}=this.config,{errorHandling:s,...i}=r,o=(l=s==null?void 0:s.normalizer)!=null?l:t.normalizer,a=(u=s==null?void 0:s.mapError)!=null?u:t.mapError;return new e({...n,...i,toError:o,mapError:a})}};function _(e={}){let r=new $(e);return{run:(t,n)=>r.run(t,n),orThrow:(t,n)=>r.orThrow(t,n),runOrThrow:(t,n)=>r.runOrThrow(t,n),all:(t,n)=>r.all(t,n),allOrThrow:(t,n)=>r.allOrThrow(t,n),partitionAll:t=>r.partitionAll(t),withConfig:t=>r.withConfig(t)}}async function he(e,r){let{signal:t,ignoreAbort:n=!0,timeout:s,retry:i,errorHandling:o,hooks:a,logger:l}=r,u=(R,...m)=>{try{R==null||R(...m)}catch{}},y,c=0,p=0,T=[],k=Date.now(),{signal:O,cleanup:ne}=te(t),N=R=>({totalAttempts:c,totalRetries:c>0?Number(c)-1:0,totalDuration:Date.now()-k,lastError:R,retryHistory:T});try{if(O.aborted){u(a==null?void 0:a.onAbort,O);let m=o.normalizer(new DOMException("Aborted","AbortError")),w=o.mapError?o.mapError(m):m;return{type:"aborted",ok:!1,data:null,error:w,metrics:{totalAttempts:c,totalRetries:p,totalDuration:Date.now()-k,lastError:w,retryHistory:T}}}let R=async()=>{var M,g,W;let m=1,w=C((M=i==null?void 0:i.maxRetries)!=null?M:0);for(;;){c=m;let K=new AbortController,{signal:U,cleanup:oe}=te(O,K.signal);try{let I=Promise.resolve(e({signal:U})),A=s?await re(I,s,U,()=>(K.abort(),new v(b(s)))):await I;return u(a==null?void 0:a.onSuccess,A,N()),u(l==null?void 0:l.info,`Task succeeded on attempt ${m}`),A}catch(I){let A=o.normalizer(I),f=o.mapError?o.mapError(A):A;if(y=f,f.code==="ABORTED"&&u(a==null?void 0:a.onAbort,U),n&&f.code==="ABORTED"||(u(a==null?void 0:a.onError,f,N(f)),u(l==null?void 0:l.error,`Task failed on attempt ${m}`,f)),f.code==="ABORTED"||f.retryable===!1)throw f;if(m<=Number(w)){let V=i==null?void 0:i.shouldRetry,se={totalAttempts:Number(c),elapsedTime:Date.now()-k,startTime:new Date(k),lastDelay:(g=T[T.length-1])!=null&&g.delay?Number((W=T[T.length-1])==null?void 0:W.delay):void 0};if(!V||V(m,f,se)){let ae=i?X(i.strategy,m,f):0,L=Re(ae,i==null?void 0:i.jitter),J=b(L);T.push({attempt:m,error:f,delay:J,timestamp:new Date}),u(a==null?void 0:a.onRetry,m,f,L),u(l==null?void 0:l.info,`Retrying in ${L}ms (attempt ${m+1})`),m+=1,await ee(J,O);continue}}throw f}finally{oe()}}};try{let m=await R(),w=N();return p=w.totalRetries,u(a==null?void 0:a.onFinally,w),{type:"success",ok:!0,data:m,error:null,metrics:w}}catch(m){let w=y!=null?y:o.normalizer(m),M=w.code==="TIMEOUT"?"timeout":w.code==="ABORTED"?"aborted":"failure",g=N(w);return p=g.totalRetries,u(a==null?void 0:a.onFinally,g),{type:M,ok:!1,data:null,error:w,metrics:g}}}finally{ne()}}function te(...e){let r=new AbortController,t=e.filter(s=>s!==void 0);if(t.length===0)return{signal:r.signal,cleanup:()=>{}};if(t.some(s=>s.aborted))return r.abort(),{signal:r.signal,cleanup:()=>{}};let n=[];for(let s of t){let i=()=>r.abort();s.addEventListener("abort",i,{once:!0}),n.push({signal:s,abort:i})}return{signal:r.signal,cleanup:()=>{for(let s of n)s.signal.removeEventListener("abort",s.abort)}}}function Re(e,r){if(!r||r.type==="none"||e<=0)return e;switch(r.type){case"full":{let t=Number(r.ratio)/100,n=Math.max(0,Number(e)*(1-t)),s=Number(e);return n+Math.random()*(s-n)}case"equal":{let t=Number(r.ratio)/100,n=Number(e)*t/2;return Number(e)-n+Math.random()*n}case"custom":return r.calculate(e);default:return r}}var S=_(),Ce=S.run,xe=S.runOrThrow,ge=S.orThrow,ke=S.all,Oe=S.allOrThrow;export{Ee as RetryStrategies,E as TypedError,ke as all,Oe as allOrThrow,b as asMilliseconds,C as asRetryCount,_ as default,fe as errorRule,ge as orThrow,Ce as run,xe as runOrThrow,_ as tryo};
|
|
1
|
+
var de=Object.defineProperty;var ye=(e,r,t)=>r in e?de(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t;var l=(e,r,t)=>ye(e,typeof r!="symbol"?r+"":r,t);var f=class extends Error{constructor(t,n){var o,a;super(t);l(this,"cause");l(this,"title");l(this,"meta");l(this,"status");l(this,"raw");l(this,"path");l(this,"timestamp");l(this,"retryable");this.timestamp=Date.now(),this.retryable=(o=n.retryable)!=null?o:!0,this.name=this.constructor.name,this.cause=n.cause,this.title=n.title,this.meta=(a=n.meta)!=null?a:{},this.status=n.status,this.raw=n.raw,this.path=n.path,Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor)}is(t){return this.code===t}withMeta(t){return Object.assign(this,{meta:t})}withStatus(t){return Object.assign(this,{status:t})}withCause(t){return Object.assign(this,{cause:t})}withPath(t){return this.path=t,this}withRaw(t){return Object.assign(this,{raw:t})}withRetryable(t){return this.retryable=t,this}toJSON(){return{name:this.name,code:this.code,title:this.title,message:this.message,timestamp:this.timestamp,retryable:this.retryable,cause:this.cause,raw:this.raw,path:this.path,stack:this.stack}}},F=class extends f{constructor(t,n){super(`Operation timed out after ${t}ms`,{cause:n,retryable:!0});l(this,"code","TIMEOUT")}};var B=class extends f{constructor(t,n){super(`Circuit breaker is open, reset after ${t}ms`,{cause:n,retryable:!1});l(this,"code","CIRCUIT_OPEN")}};var _=class extends f{constructor(t,n){super(t,{cause:n});l(this,"code","UNKNOWN")}};var b=e=>{if(e<0||!Number.isFinite(e))throw new Error(`Invalid milliseconds: must be a non-negative finite number, got ${e}`);return e},x=e=>{if(e<0||!Number.isInteger(e))throw new Error(`Invalid retry count: must be a non-negative integer, got ${e}`);return e},W=e=>{if(e<1||!Number.isInteger(e))throw new Error(`Invalid concurrency limit: must be a positive integer, got ${e}`);return e},X=e=>{if(e<0||e>100||!Number.isFinite(e))throw new Error(`Invalid percentage: must be between 0 and 100, got ${e}`);return e};var U=class{constructor(r){l(this,"state");l(this,"config");this.config={failureThreshold:x(r.failureThreshold),resetTimeout:b(r.resetTimeout),halfOpenRequests:x(r.halfOpenRequests),shouldCountAsFailure:r.shouldCountAsFailure},this.state={state:"closed",failureCount:0,halfOpenCount:0}}async canExecute(){if(this.updateStateIfNeeded(),this.state.state==="open")return!1;if(this.state.state==="half-open"){if(this.state.halfOpenCount>=this.config.halfOpenRequests)return!1;this.state={...this.state,halfOpenCount:this.state.halfOpenCount+1}}return!0}async recordSuccess(){switch(this.state.state){case"closed":this.state={...this.state,failureCount:0};break;case"half-open":this.state={state:"closed",failureCount:0,halfOpenCount:0};break;case"open":break}}async recordFailure(r){var o,a,s;if(!((s=(a=(o=this.config).shouldCountAsFailure)==null?void 0:a.call(o,r))!=null?s:!0))return;let n=new Date;switch(this.state.state){case"closed":{let i=this.state.failureCount+1;i>=this.config.failureThreshold?this.state={state:"open",failureCount:i,halfOpenCount:0,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)}:this.state={...this.state,failureCount:i,lastFailureTime:n};break}case"half-open":this.state={state:"open",failureCount:this.state.failureCount+1,halfOpenCount:0,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)};break;case"open":this.state={...this.state,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)};break}}getState(){return this.updateStateIfNeeded(),{...this.state,canExecute:this.state.state!=="open"}}createOpenError(){let r=this.state.nextAttemptTime?b(Math.max(0,this.state.nextAttemptTime.getTime()-Date.now())):this.config.resetTimeout;return new B(r)}forceState(r){this.state={state:r,failureCount:0,halfOpenCount:0}}reset(){this.state={state:"closed",failureCount:0,halfOpenCount:0}}updateStateIfNeeded(){this.state.state==="open"&&this.state.nextAttemptTime&&new Date>=this.state.nextAttemptTime&&(this.state={...this.state,state:"half-open",halfOpenCount:0})}};var Z=(e,r)=>t=>{for(let n of e){let o=n(t);if(o!==null)return o}return r(t)},ee=e=>r=>r instanceof f?r:r instanceof Error?new e(r.message,r):typeof r=="string"?new e(r):new e("Unknown error occurred",r);var pe=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.status=="number"||typeof r.statusCode=="number"},me=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.code=="string"&&r.code.length>0},fe=e=>{var r;if(e instanceof Error){let t=e.message.toLowerCase();if(e.name==="TypeError"&&(t.includes("fetch")&&t.includes("failed")||t.includes("network"))||t.includes("fetch")&&t.includes("failed")||t.includes("network"))return!0}if(me(e)){let t=((r=e.code)!=null?r:"").toUpperCase();return t==="ECONNRESET"||t==="ECONNREFUSED"||t==="ETIMEDOUT"||t==="ENOTFOUND"||t==="EAI_AGAIN"}return!1},Ee=e=>typeof e=="object"&&e!==null,L=class{constructor(r){this.predicate=r}toCode(r){return new K(this.predicate,r)}toError(r){return t=>{var c;if(!this.predicate(t))return null;let n=r(t),o=n.code,a=Object.hasOwn(n,"cause")?n.cause:t,s=(c=n.meta)!=null?c:{};class i extends f{constructor(){let y=Object.hasOwn(n,"raw")?n.raw:t;super(n.message,{title:n.title,cause:a,meta:s,status:n.status,retryable:n.retryable,raw:y,path:n.path});l(this,"code",o)}}return new i}}};function we(e,r){let t=new L(a=>a instanceof e);if(r)return t.toError(r);let o=a=>{if(!(a instanceof e))return null;if(a instanceof f)return a;let s=a,i=typeof s.code=="string"&&s.code.length>0?s.code:"UNKNOWN",c=Object.hasOwn(s,"cause"),u=Object.hasOwn(s,"raw");class d extends f{constructor(){super(s.message||i,{title:typeof s.title=="string"?s.title:void 0,cause:c?s.cause:a,meta:Ee(s.meta)?s.meta:{},status:typeof s.status=="number"?s.status:void 0,retryable:typeof s.retryable=="boolean"?s.retryable:void 0,raw:u?s.raw:a,path:typeof s.path=="string"?s.path:void 0});l(this,"code",i)}}return new d};return o.toCode=t.toCode.bind(t),o.toError=t.toError.bind(t),o}var K=class{constructor(r,t){this.predicate=r;this.errorCode=t}with(r){return t=>{var c;if(!this.predicate(t))return null;let n=r(t),o=Object.hasOwn(n,"cause")?n.cause:t,a=(c=n.meta)!=null?c:{},s=this.errorCode;class i extends f{constructor(){let T=Object.hasOwn(n,"raw")?n.raw:t;super(n.message,{title:n.title,cause:o,meta:a,status:n.status,retryable:n.retryable,raw:T,path:n.path});l(this,"code",s)}}return new i}}},h={when:e=>new L(e),instance:we},g={typed:(e=>e instanceof f?e:null),abort:h.when(e=>e instanceof Error&&e.name==="AbortError").toCode("ABORTED").with(e=>({message:e.message||"Operation was aborted",cause:e,retryable:!1,raw:e})),timeout:h.when(e=>e instanceof Error&&e.name==="TimeoutError").toCode("TIMEOUT").with(e=>({message:e.message||"Operation timed out",cause:e,raw:e})),network:h.when(e=>fe(e)).toCode("NETWORK").with(e=>({message:(e instanceof Error,e.message||"Network error"),cause:e,raw:e})),http:h.when(e=>{var n;if(!pe(e))return!1;let r=e,t=(n=r.status)!=null?n:r.statusCode;return typeof t=="number"&&t>=400}).toCode("HTTP").with(e=>{var n;let r=(n=e.status)!=null?n:e.statusCode,t=typeof r=="number"&&(r>=500||r===429);return{message:e.message||`HTTP ${r!=null?r:"error"} error`,cause:e,status:typeof r=="number"?r:void 0,retryable:t,raw:e}}),unknown:h.when(e=>e instanceof Error&&!(e instanceof f)).toCode("UNKNOWN").with(e=>({message:e.message||"Unknown error occurred",cause:e,raw:e}))};var Te=[g.typed,g.abort,g.timeout,g.http,g.network,g.unknown];var be={when:e=>h.when(e),instance:h.instance},re=Te;var he={fixed:e=>({type:"fixed",delay:e}),exponential:(e,r=2,t)=>({type:"exponential",base:e,factor:r,maxDelay:t}),fibonacci:(e,r)=>({type:"fibonacci",base:e,maxDelay:r}),custom:e=>({type:"custom",calculate:e})},te=(e,r,t)=>{switch(e.type){case"fixed":return e.delay;case"exponential":{let n=e.base*e.factor**(Number(r)-1);return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"fibonacci":{let n=e.base*Re(Number(r));return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"custom":return e.calculate(r,t);default:return e}},Re=e=>{if(e<=1)return 1;let r=1,t=1;for(let n=2;n<=e;n++){let o=r+t;r=t,t=o}return t},ne=e=>{switch(e.type){case"fixed":{if(e.delay<0)throw new Error("Fixed delay must be non-negative");break}case"exponential":if(e.base<=0)throw new Error("Exponential base delay must be positive");if(e.factor<=1)throw new Error("Exponential factor must be greater than 1");if(e.maxDelay!==void 0&&e.maxDelay<=0)throw new Error("Exponential max delay must be positive");break;case"fibonacci":if(e.base<=0)throw new Error("Fibonacci base delay must be positive");if(e.maxDelay!==void 0&&e.maxDelay<=0)throw new Error("Fibonacci max delay must be positive");break;case"custom":break;default:{let r=e;throw new Error(`Unknown strategy type: ${r}`)}}};var oe=(e,r)=>new Promise((t,n)=>{if(r!=null&&r.aborted){n(new DOMException("Aborted","AbortError"));return}let o=i=>{r&&i&&r.removeEventListener("abort",i)},a,s=()=>{a&&clearTimeout(a),o(s),n(new DOMException("Aborted","AbortError"))};a=setTimeout(()=>{o(s),t()},e),r==null||r.addEventListener("abort",s,{once:!0})}),se=(e,r,t,n)=>new Promise((o,a)=>{if(t!=null&&t.aborted){a(new DOMException("Aborted","AbortError"));return}let s=!1,i=setTimeout(()=>{var d;s=!0,u(),a((d=n==null?void 0:n())!=null?d:new Error(`Operation timed out after ${r}ms`))},r),c=()=>{s||(s=!0,u(),a(new DOMException("Aborted","AbortError")))},u=()=>{clearTimeout(i),t==null||t.removeEventListener("abort",c)};t==null||t.addEventListener("abort",c,{once:!0}),e.then(d=>{s||(s=!0,u(),o(d))},d=>{s||(s=!0,u(),a(d))})});var Ce=e=>{var s,i,c;if(e.toError)return e.toError;let r=(s=e.rulesMode)!=null?s:"extend",t=(i=e.rules)!=null?i:[],n=re,o=(c=e.fallback)!=null?c:(u=>ee(_)(u)),a=r==="replace"?t:[...t,...n];return Z(a,o)},xe=e=>{if(e)switch(e.type){case"none":return;case"full":case"equal":X(e.ratio);return;case"custom":return;default:{let r=e;throw new Error(`Unsupported jitter configuration: ${r}`)}}},V=e=>{let r=e;return r.timeout!==void 0&&(r={...r,timeout:Number(b(r.timeout))}),r.concurrency!==void 0&&(r={...r,concurrency:Number.isFinite(r.concurrency)?Number(W(r.concurrency)):r.concurrency}),r.retry&&(ne(r.retry.strategy),xe(r.retry.jitter),r={...r,retry:{...r.retry,maxRetries:Number(x(r.retry.maxRetries))}}),r},J=class e{constructor(r={}){l(this,"circuitBreaker");l(this,"config");l(this,"lastCircuitState");let{rules:t,rulesMode:n,fallback:o,toError:a,mapError:s,...i}=r,c=Ce(r),u={...i,errorHandling:{normalizer:c,mapError:s}};this.config=V(u),u.circuitBreaker&&(this.circuitBreaker=new U(u.circuitBreaker),this.lastCircuitState=this.circuitBreaker.getState().state)}async run(r,t={}){var a,s,i,c;let n=V({...this.config,...t});if(this.circuitBreaker){let u=(a=this.lastCircuitState)!=null?a:this.circuitBreaker.getState().state,d=await this.circuitBreaker.canExecute(),y=this.circuitBreaker.getState().state;if(u!==y)try{(s=n.onCircuitStateChange)==null||s.call(n,u,y)}catch{}if(this.lastCircuitState=y,!d)return{type:"failure",ok:!1,data:null,error:this.circuitBreaker.createOpenError(),metrics:{totalAttempts:0,totalRetries:0,totalDuration:0,retryHistory:[]}}}let o=await ge(r,n);if(this.circuitBreaker){let u=(i=this.lastCircuitState)!=null?i:this.circuitBreaker.getState().state;o.ok?await this.circuitBreaker.recordSuccess():await this.circuitBreaker.recordFailure(o.error);let d=this.circuitBreaker.getState().state;if(u!==d)try{(c=n.onCircuitStateChange)==null||c.call(n,u,d)}catch{}this.lastCircuitState=d}return o}async runOrThrow(r,t={}){return this.orThrow(r,t)}async orThrow(r,t={}){let n=await this.run(r,t);if(n.ok)return n.data;throw n.error}async all(r,t={}){var d;let n=V({...this.config,...t}),o=(d=n.concurrency)!=null?d:Number.POSITIVE_INFINITY,a=Number.isFinite(o)?Number(W(o)):Number.POSITIVE_INFINITY;if(a===Number.POSITIVE_INFINITY)return Promise.all(r.map(y=>this.run(y,n)));let s=new Array(r.length),i=0,c=async()=>{var y;for(;i<r.length&&!((y=n.signal)!=null&&y.aborted);){let T=i++;if(T>=r.length)break;let E=r[T];E&&(s[T]=await this.run(E,n))}},u=Array.from({length:Math.min(a,r.length)},()=>c());await Promise.all(u);for(let y=0;y<r.length;y++)if(!(y in s)){let T=r[y];T&&(s[y]=await this.run(T,n))}return s}async allOrThrow(r,t={}){return(await this.all(r,t)).map(o=>{if(!o.ok)throw o.error;return o.data})}partitionAll(r){let t=[],n=[],o=[],a=[],s=[];for(let i of r){if(i.type==="success"){t.push(i);continue}switch(n.push(i),i.type){case"failure":o.push(i);break;case"aborted":a.push(i);break;case"timeout":s.push(i);break}}return{ok:t,errors:n,failure:o,aborted:a,timeout:s}}getCircuitBreakerState(){var r;return(r=this.circuitBreaker)==null?void 0:r.getState()}resetCircuitBreaker(){var r;(r=this.circuitBreaker)==null||r.reset()}getConfig(){return{...this.config}}withConfig(r){var c,u;let{errorHandling:t,...n}=this.config,{errorHandling:o,...a}=r,s=(c=o==null?void 0:o.normalizer)!=null?c:t.normalizer,i=(u=o==null?void 0:o.mapError)!=null?u:t.mapError;return new e({...n,...a,toError:s,mapError:i})}};function z(e={}){let r=new J(e);return{run:(t,n)=>r.run(t,n),orThrow:(t,n)=>r.orThrow(t,n),runOrThrow:(t,n)=>r.runOrThrow(t,n),all:(t,n)=>r.all(t,n),allOrThrow:(t,n)=>r.allOrThrow(t,n),partitionAll:t=>r.partitionAll(t),withConfig:t=>r.withConfig(t)}}async function ge(e,r){let{signal:t,ignoreAbort:n=!0,timeout:o,retry:a,errorHandling:s,logger:i,onSuccess:c,onError:u,onFinally:d,onAbort:y,onRetry:T}=r,E=(C,...p)=>{try{C==null||C(...p)}catch{}},N,k=0,H=0,R=[],M=Date.now(),{signal:I,cleanup:ie}=ae(t),v=C=>({totalAttempts:k,totalRetries:k>0?Number(k)-1:0,totalDuration:Date.now()-M,lastError:C,retryHistory:R});try{if(I.aborted){E(y,I);let p=s.normalizer(new DOMException("Aborted","AbortError")),w=s.mapError?s.mapError(p):p;return{type:"aborted",ok:!1,data:null,error:w,metrics:{totalAttempts:k,totalRetries:H,totalDuration:Date.now()-M,lastError:w,retryHistory:R}}}let C=async()=>{var D,O,j;let p=1,w=x((D=a==null?void 0:a.maxRetries)!=null?D:0);for(;;){k=p;let Y=new AbortController,{signal:q,cleanup:ue}=ae(I,Y.signal);try{let P=Promise.resolve(e({signal:q})),A=o?await se(P,o,q,()=>(Y.abort(),new F(b(o)))):await P;return E(c,A,v()),E(i==null?void 0:i.info,`Task succeeded on attempt ${p}`),A}catch(P){let A=s.normalizer(P),m=s.mapError?s.mapError(A):A;if(N=m,m.code==="ABORTED"&&E(y,q),n&&m.code==="ABORTED"||(E(u,m,v(m)),E(i==null?void 0:i.error,`Task failed on attempt ${p}`,m)),m.code==="ABORTED"||m.retryable===!1)throw m;if(p<=Number(w)){let G=a==null?void 0:a.shouldRetry,ce={totalAttempts:Number(k),elapsedTime:Date.now()-M,startTime:new Date(M),lastDelay:(O=R[R.length-1])!=null&&O.delay?Number((j=R[R.length-1])==null?void 0:j.delay):void 0};if(!G||G(p,m,ce)){let le=a?te(a.strategy,p,m):0,$=ke(le,a==null?void 0:a.jitter),Q=b($);R.push({attempt:p,error:m,delay:Q,timestamp:new Date}),E(T,p,m,$),E(i==null?void 0:i.info,`Retrying in ${$}ms (attempt ${p+1})`),p+=1,await oe(Q,I);continue}}throw m}finally{ue()}}};try{let p=await C(),w=v();return H=w.totalRetries,E(d,w),{type:"success",ok:!0,data:p,error:null,metrics:w}}catch(p){let w=N!=null?N:s.normalizer(p),D=w.code==="TIMEOUT"?"timeout":w.code==="ABORTED"?"aborted":"failure",O=v(w);return H=O.totalRetries,E(d,O),{type:D,ok:!1,data:null,error:w,metrics:O}}}finally{ie()}}function ae(...e){let r=new AbortController,t=e.filter(o=>o!==void 0);if(t.length===0)return{signal:r.signal,cleanup:()=>{}};if(t.some(o=>o.aborted))return r.abort(),{signal:r.signal,cleanup:()=>{}};let n=[];for(let o of t){let a=()=>r.abort();o.addEventListener("abort",a,{once:!0}),n.push({signal:o,abort:a})}return{signal:r.signal,cleanup:()=>{for(let o of n)o.signal.removeEventListener("abort",o.abort)}}}function ke(e,r){if(!r||r.type==="none"||e<=0)return e;switch(r.type){case"full":{let t=Number(r.ratio)/100,n=Math.max(0,Number(e)*(1-t)),o=Number(e);return n+Math.random()*(o-n)}case"equal":{let t=Number(r.ratio)/100,n=Number(e)*t/2;return Number(e)-n+Math.random()*n}case"custom":return r.calculate(e);default:return r}}var S=z(),Oe=S.run,Ae=S.runOrThrow,Se=S.orThrow,Ne=S.all,Me=S.allOrThrow;export{he as RetryStrategies,f as TypedError,Ne as all,Me as allOrThrow,b as asMilliseconds,x as asRetryCount,z as default,be as errorRule,Se as orThrow,Oe as run,Ae as runOrThrow,z as tryo};
|