tryo 0.13.8 → 0.13.9
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/dist/index.cjs +1 -1
- package/dist/index.d.cts +80 -135
- package/dist/index.d.ts +80 -135
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
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});
|
|
1
|
+
"use strict";var F=Object.defineProperty;var we=Object.getOwnPropertyDescriptor;var be=Object.getOwnPropertyNames;var he=Object.prototype.hasOwnProperty;var Re=(e,r,t)=>r in e?F(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t;var Ce=(e,r)=>{for(var t in r)F(e,t,{get:r[t],enumerable:!0})},xe=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of be(r))!he.call(e,o)&&o!==t&&F(e,o,{get:()=>r[o],enumerable:!(n=we(r,o))||n.enumerable});return e};var ge=e=>xe(F({},"__esModule",{value:!0}),e);var d=(e,r,t)=>Re(e,typeof r!="symbol"?r+"":r,t);var Ue={};Ce(Ue,{RetryStrategies:()=>ne,TypedError:()=>f,all:()=>ye,allOrThrow:()=>pe,asMilliseconds:()=>b,asRetryCount:()=>h,default:()=>N,errorRule:()=>re,orThrow:()=>de,run:()=>ce,runOrThrow:()=>le,tryo:()=>N});module.exports=ge(Ue);var f=class extends Error{constructor(t,n){var o,s;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=(s=n.meta)!=null?s:{},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}}},B=class extends f{constructor(t,n){super(`Operation timed out after ${t}ms`,{cause:n,retryable:!0});d(this,"code","TIMEOUT")}};var _=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 U=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},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 L=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,s,a;if(!((a=(s=(o=this.config).shouldCountAsFailure)==null?void 0:s.call(o,r))!=null?a:!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 _(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 ke=e=>{let t=e.toString().match(/\bcode\s*:\s*['"`]([^'"`]+)['"`]/);return t==null?void 0:t[1]},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,z=class{constructor(r){this.predicate=r}toCode(r){return new K(this.predicate,r)}toError(r){let t=o=>{var c;if(!this.predicate(o))return null;let s=r(o),a=s.code,i=Object.hasOwn(s,"cause")?s.cause:o,l=(c=s.meta)!=null?c:{};class u extends f{constructor(){let m=Object.hasOwn(s,"raw")?s.raw:o;super(s.message,{title:s.title,cause:i,meta:l,status:s.status,retryable:s.retryable,raw:m,path:s.path});d(this,"code",a)}}return new u},n=ke(r);return n&&(t.__tryoCode=n),t}};function Me(e,r){let t=new z(s=>s instanceof e);if(r)return t.toError(r);let o=s=>{if(!(s instanceof e))return null;if(s instanceof f)return s;let a=s,i=typeof a.code=="string"&&a.code.length>0?a.code:"UNKNOWN",l=Object.hasOwn(a,"cause"),u=Object.hasOwn(a,"raw");class c extends f{constructor(){super(a.message||i,{title:typeof a.title=="string"?a.title:void 0,cause:l?a.cause:s,meta:Ne(a.meta)?a.meta:{},status:typeof a.status=="number"?a.status:void 0,retryable:typeof a.retryable=="boolean"?a.retryable:void 0,raw:u?a.raw:s,path:typeof a.path=="string"?a.path:void 0});d(this,"code",i)}}return new c};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){let t=n=>{var u;if(!this.predicate(n))return null;let o=r(n),s=Object.hasOwn(o,"cause")?o.cause:n,a=(u=o.meta)!=null?u:{},i=this.errorCode;class l extends f{constructor(){let m=Object.hasOwn(o,"raw")?o.raw:n;super(o.message,{title:o.title,cause:s,meta:a,status:o.status,retryable:o.retryable,raw:m,path:o.path});d(this,"code",i)}}return new l};return t.__tryoCode=this.errorCode,t}},R={when:e=>new z(e),instance:Me},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=>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 f)).toCode("UNKNOWN").with(e=>({message:e.message||"Unknown error occurred",cause:e,raw:e}))};var Ie=[x.typed,x.abort,x.timeout,x.http,x.network,x.unknown];var re={when:e=>R.when(e),instance:R.instance},te=Ie;var ne={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})},oe=(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},se=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 ae=(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)},s,a=()=>{s&&clearTimeout(s),o(a),n(new DOMException("Aborted","AbortError"))};s=setTimeout(()=>{o(a),t()},e),r==null||r.addEventListener("abort",a,{once:!0})}),ie=(e,r,t,n)=>new Promise((o,s)=>{if(t!=null&&t.aborted){s(new DOMException("Aborted","AbortError"));return}let a=!1,i=setTimeout(()=>{var c;a=!0,u(),s((c=n==null?void 0:n())!=null?c:new Error(`Operation timed out after ${r}ms`))},r),l=()=>{a||(a=!0,u(),s(new DOMException("Aborted","AbortError")))},u=()=>{clearTimeout(i),t==null||t.removeEventListener("abort",l)};t==null||t.addEventListener("abort",l,{once:!0}),e.then(c=>{a||(a=!0,u(),o(c))},c=>{a||(a=!0,u(),s(c))})});var De=e=>{var a,i,l;if(e.toError)return e.toError;let r=(a=e.rulesMode)!=null?a:"extend",t=(i=e.rules)!=null?i:[];Pe(t);let n=te,o=(l=e.fallback)!=null?l:(u=>ee(U)(u)),s=r==="replace"?t:[...t,...n];return Z(s,o)},Pe=e=>{let r=new Set;for(let t of e){let n=t.__tryoCode;if(n){if(r.has(n))throw new Error(`Duplicate rule code detected: ${n}`);r.add(n)}}},Fe=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&&(se(r.retry.strategy),Fe(r.retry.jitter),r={...r,retry:{...r.retry,maxRetries:Number(h(r.retry.maxRetries))}}),r},J=class e{constructor(r={}){d(this,"circuitBreaker");d(this,"config");d(this,"lastCircuitState");let{rules:t,rulesMode:n,fallback:o,toError:s,mapError:a,...i}=r,l=De(r),u={...i,errorHandling:{normalizer:l,mapError:a}};this.config=V(u),u.circuitBreaker&&(this.circuitBreaker=new L(u.circuitBreaker),this.lastCircuitState=this.circuitBreaker.getState().state)}async run(r,t={}){var s,a,i,l;let n=V({...this.config,...t});if(this.circuitBreaker){let u=(s=this.lastCircuitState)!=null?s:this.circuitBreaker.getState().state,c=await this.circuitBreaker.canExecute(),y=this.circuitBreaker.getState().state;if(u!==y)try{(a=n.onCircuitStateChange)==null||a.call(n,u,y)}catch{}if(this.lastCircuitState=y,!c)return{type:"failure",ok:!1,data:null,error:this.circuitBreaker.createOpenError(),metrics:{totalAttempts:0,totalRetries:0,totalDuration:0,retryHistory:[]}}}let o=await Be(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 c=this.circuitBreaker.getState().state;if(u!==c)try{(l=n.onCircuitStateChange)==null||l.call(n,u,c)}catch{}this.lastCircuitState=c}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 c;let n=V({...this.config,...t}),o=(c=n.concurrency)!=null?c:Number.POSITIVE_INFINITY,s=Number.isFinite(o)?Number(W(o)):Number.POSITIVE_INFINITY;if(s===Number.POSITIVE_INFINITY)return Promise.all(r.map(y=>this.run(y,n)));let a=new Array(r.length),i=0,l=async()=>{var y;for(;i<r.length&&!((y=n.signal)!=null&&y.aborted);){let T=i++;if(T>=r.length)break;let m=r[T];m&&(a[T]=await this.run(m,n))}},u=Array.from({length:Math.min(s,r.length)},()=>l());await Promise.all(u);for(let y=0;y<r.length;y++)if(!(y in a)){let T=r[y];T&&(a[y]=await this.run(T,n))}return a}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=[],s=[],a=[];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":s.push(i);break;case"timeout":a.push(i);break}}return{ok:t,errors:n,failure:o,aborted:s,timeout:a}}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,...s}=r,a=(l=o==null?void 0:o.normalizer)!=null?l:t.normalizer,i=(u=o==null?void 0:o.mapError)!=null?u:t.mapError;return new e({...n,...s,toError:a,mapError:i})}};function N(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 Be(e,r){let{signal:t,ignoreAbort:n=!0,timeout:o,retry:s,errorHandling:a,logger:i,onSuccess:l,onError:u,onFinally:c,onAbort:y,onRetry:T}=r,m=(C,...p)=>{try{C==null||C(...p)}catch{}},I,k=0,g=[],H=Date.now(),{signal:v,cleanup:me}=ue(t),O=C=>({totalAttempts:k,totalRetries:k>0?Number(k)-1:0,totalDuration:Date.now()-H,lastError:C,retryHistory:g});try{if(v.aborted){m(y,v);let p=a.normalizer(new DOMException("Aborted","AbortError")),w=a.mapError?a.mapError(p):p;return{type:"aborted",ok:!1,data:null,error:w,metrics:O(w)}}let C=async()=>{var D,A,j;let p=1,w=h((D=s==null?void 0:s.maxRetries)!=null?D:0);for(;;){k=p;let Y=new AbortController,{signal:$,cleanup:fe}=ue(v,Y.signal);try{let P=Promise.resolve(e({signal:$})),S=o?await ie(P,o,$,()=>(Y.abort(),new B(b(o)))):await P;return m(l,S,O()),m(i==null?void 0:i.info,`Task succeeded on attempt ${p}`),S}catch(P){let S=a.normalizer(P),E=a.mapError?a.mapError(S):S;if(I=E,E.code==="ABORTED"&&m(y,$),n&&E.code==="ABORTED"||(m(u,E,O(E)),m(i==null?void 0:i.error,`Task failed on attempt ${p}`,E)),E.code==="ABORTED"||E.retryable===!1)throw E;if(p<=Number(w)){let G=s==null?void 0:s.shouldRetry,Ee={totalAttempts:Number(k),elapsedTime:Date.now()-H,startTime:new Date(H),lastDelay:(A=g[g.length-1])!=null&&A.delay?Number((j=g[g.length-1])==null?void 0:j.delay):void 0};if(!G||G(p,E,Ee)){let Te=s?oe(s.strategy,p,E):0,q=_e(Te,s==null?void 0:s.jitter),Q=b(q);g.push({attempt:p,error:E,delay:Q,timestamp:new Date}),m(T,p,E,q),m(i==null?void 0:i.info,`Retrying in ${q}ms (attempt ${p+1})`),p+=1,await ae(Q,v);continue}}throw E}finally{fe()}}};try{let p=await C(),w=O();return m(c,w),{type:"success",ok:!0,data:p,error:null,metrics:w}}catch(p){let w=I!=null?I:a.normalizer(p),D=w.code==="TIMEOUT"?"timeout":w.code==="ABORTED"?"aborted":"failure",A=O(w);return m(c,A),{type:D,ok:!1,data:null,error:w,metrics:A}}}finally{me()}}function ue(...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 s=()=>r.abort();o.addEventListener("abort",s,{once:!0}),n.push({signal:o,abort:s})}return{signal:r.signal,cleanup:()=>{for(let o of n)o.signal.removeEventListener("abort",o.abort)}}}function _e(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 M=N(),ce=M.run,le=M.runOrThrow,de=M.orThrow,ye=M.all,pe=M.allOrThrow;0&&(module.exports={RetryStrategies,TypedError,all,allOrThrow,asMilliseconds,asRetryCount,errorRule,orThrow,run,runOrThrow,tryo});
|
package/dist/index.d.cts
CHANGED
|
@@ -111,6 +111,46 @@ interface CircuitBreakerConfig<E extends AnyTypedError = AnyTypedError> {
|
|
|
111
111
|
}
|
|
112
112
|
type CircuitState = 'closed' | 'open' | 'half-open';
|
|
113
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Modern error normalization system
|
|
116
|
+
* Provides type-safe error transformation and normalization
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
type ErrorNormalizer<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E;
|
|
120
|
+
type ErrorRule<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E | null;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Modern retry strategies with enhanced capabilities
|
|
124
|
+
* Provides various retry patterns with type safety
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
type RetryStrategy = FixedDelayStrategy | ExponentialBackoffStrategy | FibonacciBackoffStrategy | CustomDelayStrategy;
|
|
128
|
+
interface FixedDelayStrategy {
|
|
129
|
+
readonly type: 'fixed';
|
|
130
|
+
readonly delay: number;
|
|
131
|
+
}
|
|
132
|
+
interface ExponentialBackoffStrategy {
|
|
133
|
+
readonly type: 'exponential';
|
|
134
|
+
readonly base: number;
|
|
135
|
+
readonly factor: number;
|
|
136
|
+
readonly maxDelay?: number;
|
|
137
|
+
}
|
|
138
|
+
interface FibonacciBackoffStrategy {
|
|
139
|
+
readonly type: 'fibonacci';
|
|
140
|
+
readonly base: number;
|
|
141
|
+
readonly maxDelay?: number;
|
|
142
|
+
}
|
|
143
|
+
interface CustomDelayStrategy {
|
|
144
|
+
readonly type: 'custom';
|
|
145
|
+
readonly calculate: (attempt: RetryCount, error: unknown) => number;
|
|
146
|
+
}
|
|
147
|
+
declare const RetryStrategies: {
|
|
148
|
+
readonly fixed: (delay: number) => FixedDelayStrategy;
|
|
149
|
+
readonly exponential: (base: number, factor?: number, maxDelay?: number) => ExponentialBackoffStrategy;
|
|
150
|
+
readonly fibonacci: (base: number, maxDelay?: number) => FibonacciBackoffStrategy;
|
|
151
|
+
readonly custom: (calculate: (attempt: RetryCount, error: unknown) => number) => CustomDelayStrategy;
|
|
152
|
+
};
|
|
153
|
+
|
|
114
154
|
/**
|
|
115
155
|
* Modern result types with enhanced discriminated unions
|
|
116
156
|
* Provides better type safety and more granular result categorization
|
|
@@ -122,30 +162,30 @@ interface SuccessResult<T, E extends AnyTypedError> {
|
|
|
122
162
|
readonly ok: true;
|
|
123
163
|
readonly data: T;
|
|
124
164
|
readonly error: null;
|
|
125
|
-
readonly metrics: TryoMetrics
|
|
165
|
+
readonly metrics: TryoMetrics<E>;
|
|
126
166
|
}
|
|
127
167
|
interface FailureResult<E extends AnyTypedError> {
|
|
128
168
|
readonly type: 'failure';
|
|
129
169
|
readonly ok: false;
|
|
130
170
|
readonly data: null;
|
|
131
171
|
readonly error: E;
|
|
132
|
-
readonly metrics: TryoMetrics
|
|
172
|
+
readonly metrics: TryoMetrics<E>;
|
|
133
173
|
}
|
|
134
174
|
interface AbortedResult<E extends AnyTypedError> {
|
|
135
175
|
readonly type: 'aborted';
|
|
136
176
|
readonly ok: false;
|
|
137
177
|
readonly data: null;
|
|
138
178
|
readonly error: E;
|
|
139
|
-
readonly metrics: TryoMetrics
|
|
179
|
+
readonly metrics: TryoMetrics<E>;
|
|
140
180
|
}
|
|
141
181
|
interface TimeoutResult<E extends AnyTypedError> {
|
|
142
182
|
readonly type: 'timeout';
|
|
143
183
|
readonly ok: false;
|
|
144
184
|
readonly data: null;
|
|
145
185
|
readonly error: E;
|
|
146
|
-
readonly metrics: TryoMetrics
|
|
186
|
+
readonly metrics: TryoMetrics<E>;
|
|
147
187
|
}
|
|
148
|
-
interface TryoMetrics
|
|
188
|
+
interface TryoMetrics<E extends AnyTypedError> {
|
|
149
189
|
readonly totalAttempts: RetryCount;
|
|
150
190
|
readonly totalRetries: RetryCount;
|
|
151
191
|
readonly totalDuration: Milliseconds;
|
|
@@ -159,45 +199,10 @@ interface TryoMetrics$1<E extends AnyTypedError> {
|
|
|
159
199
|
}
|
|
160
200
|
|
|
161
201
|
/**
|
|
162
|
-
*
|
|
163
|
-
* Provides
|
|
164
|
-
*/
|
|
165
|
-
|
|
166
|
-
type ErrorNormalizer<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E;
|
|
167
|
-
type ErrorRule<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E | null;
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Modern retry strategies with enhanced capabilities
|
|
171
|
-
* Provides various retry patterns with type safety
|
|
202
|
+
* Configuration types for modern execution engine
|
|
203
|
+
* Provides comprehensive configuration with type safety
|
|
172
204
|
*/
|
|
173
205
|
|
|
174
|
-
type RetryStrategy = FixedDelayStrategy | ExponentialBackoffStrategy | FibonacciBackoffStrategy | CustomDelayStrategy;
|
|
175
|
-
interface FixedDelayStrategy {
|
|
176
|
-
readonly type: 'fixed';
|
|
177
|
-
readonly delay: number;
|
|
178
|
-
}
|
|
179
|
-
interface ExponentialBackoffStrategy {
|
|
180
|
-
readonly type: 'exponential';
|
|
181
|
-
readonly base: number;
|
|
182
|
-
readonly factor: number;
|
|
183
|
-
readonly maxDelay?: number;
|
|
184
|
-
}
|
|
185
|
-
interface FibonacciBackoffStrategy {
|
|
186
|
-
readonly type: 'fibonacci';
|
|
187
|
-
readonly base: number;
|
|
188
|
-
readonly maxDelay?: number;
|
|
189
|
-
}
|
|
190
|
-
interface CustomDelayStrategy {
|
|
191
|
-
readonly type: 'custom';
|
|
192
|
-
readonly calculate: (attempt: RetryCount, error: unknown) => number;
|
|
193
|
-
}
|
|
194
|
-
declare const RetryStrategies: {
|
|
195
|
-
readonly fixed: (delay: number) => FixedDelayStrategy;
|
|
196
|
-
readonly exponential: (base: number, factor?: number, maxDelay?: number) => ExponentialBackoffStrategy;
|
|
197
|
-
readonly fibonacci: (base: number, maxDelay?: number) => FibonacciBackoffStrategy;
|
|
198
|
-
readonly custom: (calculate: (attempt: RetryCount, error: unknown) => number) => CustomDelayStrategy;
|
|
199
|
-
};
|
|
200
|
-
|
|
201
206
|
interface TryoConfig<E extends AnyTypedError = AnyTypedError> {
|
|
202
207
|
/** Abort signal passed to tasks */
|
|
203
208
|
readonly signal?: AbortSignal;
|
|
@@ -265,7 +270,6 @@ interface LoggerConfig<E extends AnyTypedError> {
|
|
|
265
270
|
/** Warning logging function */
|
|
266
271
|
readonly warn?: (message: string, meta?: unknown) => void;
|
|
267
272
|
}
|
|
268
|
-
type TryoMetrics<E extends AnyTypedError> = TryoMetrics$1<E>;
|
|
269
273
|
type JitterConfig = {
|
|
270
274
|
type: 'none';
|
|
271
275
|
} | {
|
|
@@ -287,10 +291,17 @@ declare const JitterConfig: {
|
|
|
287
291
|
|
|
288
292
|
type RulesMode = 'extend' | 'replace';
|
|
289
293
|
type DefaultError = AbortedError | TimeoutError | NetworkError | HttpError | CircuitOpenError | ValidationError | UnknownError;
|
|
290
|
-
type RunOptions<E extends AnyTypedError> = Omit<Partial<TryoConfig<E>>, 'circuitBreaker'
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
+
type RunOptions<E extends AnyTypedError, TData = unknown> = Omit<Partial<TryoConfig<E>>, 'circuitBreaker' | 'onSuccess'> & {
|
|
295
|
+
onSuccess?: (data: TData, metrics?: TryoMetrics<E>) => void;
|
|
296
|
+
};
|
|
297
|
+
type AllOptions<E extends AnyTypedError, TData = unknown> = RunOptions<E, TData>;
|
|
298
|
+
type PartitionedResults<T, E extends AnyTypedError> = {
|
|
299
|
+
ok: Array<SuccessResult<T, E>>;
|
|
300
|
+
errors: Array<FailureResult<E> | AbortedResult<E> | TimeoutResult<E>>;
|
|
301
|
+
failure: Array<FailureResult<E>>;
|
|
302
|
+
aborted: Array<AbortedResult<E>>;
|
|
303
|
+
timeout: Array<TimeoutResult<E>>;
|
|
304
|
+
};
|
|
294
305
|
type MaybePromise<T> = T | Promise<T>;
|
|
295
306
|
type RuleLike = (error: unknown) => AnyTypedError | null;
|
|
296
307
|
type NonNull<T> = T extends null ? never : T;
|
|
@@ -325,114 +336,48 @@ declare function tryo<E extends AnyTypedError = DefaultError>(options?: TryoOpti
|
|
|
325
336
|
type Tryo<E extends AnyTypedError = AnyTypedError> = {
|
|
326
337
|
run: <T>(task: (ctx: {
|
|
327
338
|
signal: AbortSignal;
|
|
328
|
-
}) => MaybePromise<T>, options?: RunOptions<E>) => Promise<TryoResult<T, E>>;
|
|
339
|
+
}) => MaybePromise<T>, options?: RunOptions<E, T>) => Promise<TryoResult<T, E>>;
|
|
329
340
|
runOrThrow: <T>(task: (ctx: {
|
|
330
341
|
signal: AbortSignal;
|
|
331
|
-
}) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
|
|
342
|
+
}) => MaybePromise<T>, options?: RunOptions<E, T>) => Promise<T>;
|
|
332
343
|
orThrow: <T>(task: (ctx: {
|
|
333
344
|
signal: AbortSignal;
|
|
334
|
-
}) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
|
|
345
|
+
}) => MaybePromise<T>, options?: RunOptions<E, T>) => Promise<T>;
|
|
335
346
|
all: <T>(tasks: Array<(ctx: {
|
|
336
347
|
signal: AbortSignal;
|
|
337
|
-
}) => MaybePromise<T>>, options?: AllOptions<E>) => Promise<Array<TryoResult<T, E>>>;
|
|
348
|
+
}) => MaybePromise<T>>, options?: AllOptions<E, T>) => Promise<Array<TryoResult<T, E>>>;
|
|
338
349
|
allOrThrow: <T>(tasks: Array<(ctx: {
|
|
339
350
|
signal: AbortSignal;
|
|
340
|
-
}) => MaybePromise<T>>, options?: AllOptions<E>) => Promise<T[]>;
|
|
341
|
-
partitionAll: <T>(results: Array<TryoResult<T, E>>) =>
|
|
342
|
-
ok: Array<SuccessResult<T, E>>;
|
|
343
|
-
errors: Array<FailureResult<E> | AbortedResult<E> | TimeoutResult<E>>;
|
|
344
|
-
failure: Array<FailureResult<E>>;
|
|
345
|
-
aborted: Array<AbortedResult<E>>;
|
|
346
|
-
timeout: Array<TimeoutResult<E>>;
|
|
347
|
-
};
|
|
351
|
+
}) => MaybePromise<T>>, options?: AllOptions<E, T>) => Promise<T[]>;
|
|
352
|
+
partitionAll: <T>(results: Array<TryoResult<T, E>>) => PartitionedResults<T, E>;
|
|
348
353
|
withConfig: (additionalConfig: Omit<Partial<TryoConfig<E>>, 'signal'>) => Tryo<E>;
|
|
349
354
|
};
|
|
350
355
|
|
|
351
356
|
declare const run: <T>(task: (ctx: {
|
|
352
357
|
signal: AbortSignal;
|
|
353
|
-
}) => T | Promise<T>, options?: {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
readonly ignoreAbort?: boolean | undefined;
|
|
357
|
-
readonly retry?: RetryConfig<DefaultError> | undefined;
|
|
358
|
-
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
359
|
-
readonly concurrency?: number | undefined;
|
|
360
|
-
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
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
|
-
} | undefined) => Promise<TryoResult<T, DefaultError>>;
|
|
358
|
+
}) => T | Promise<T>, options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
359
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
360
|
+
}) | undefined) => Promise<TryoResult<T, DefaultError>>;
|
|
368
361
|
declare const runOrThrow: <T>(task: (ctx: {
|
|
369
362
|
signal: AbortSignal;
|
|
370
|
-
}) => T | Promise<T>, options?: {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
readonly ignoreAbort?: boolean | undefined;
|
|
374
|
-
readonly retry?: RetryConfig<DefaultError> | undefined;
|
|
375
|
-
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
376
|
-
readonly concurrency?: number | undefined;
|
|
377
|
-
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
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;
|
|
384
|
-
} | undefined) => Promise<T>;
|
|
363
|
+
}) => T | Promise<T>, options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
364
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
365
|
+
}) | undefined) => Promise<T>;
|
|
385
366
|
declare const orThrow: <T>(task: (ctx: {
|
|
386
367
|
signal: AbortSignal;
|
|
387
|
-
}) => T | Promise<T>, options?: {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
readonly ignoreAbort?: boolean | undefined;
|
|
391
|
-
readonly retry?: RetryConfig<DefaultError> | undefined;
|
|
392
|
-
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
393
|
-
readonly concurrency?: number | undefined;
|
|
394
|
-
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
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;
|
|
401
|
-
} | undefined) => Promise<T>;
|
|
368
|
+
}) => T | Promise<T>, options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
369
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
370
|
+
}) | undefined) => Promise<T>;
|
|
402
371
|
declare const all: <T>(tasks: ((ctx: {
|
|
403
372
|
signal: AbortSignal;
|
|
404
|
-
}) => T | Promise<T>)[], options?: {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
readonly ignoreAbort?: boolean | undefined;
|
|
408
|
-
readonly retry?: RetryConfig<DefaultError> | undefined;
|
|
409
|
-
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
410
|
-
concurrency?: number | undefined;
|
|
411
|
-
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
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;
|
|
418
|
-
} | undefined) => Promise<TryoResult<T, DefaultError>[]>;
|
|
373
|
+
}) => T | Promise<T>)[], options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
374
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
375
|
+
}) | undefined) => Promise<TryoResult<T, DefaultError>[]>;
|
|
419
376
|
declare const allOrThrow: <T>(tasks: ((ctx: {
|
|
420
377
|
signal: AbortSignal;
|
|
421
|
-
}) => T | Promise<T>)[], options?: {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
readonly ignoreAbort?: boolean | undefined;
|
|
425
|
-
readonly retry?: RetryConfig<DefaultError> | undefined;
|
|
426
|
-
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
427
|
-
concurrency?: number | undefined;
|
|
428
|
-
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
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;
|
|
435
|
-
} | undefined) => Promise<T[]>;
|
|
378
|
+
}) => T | Promise<T>)[], options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
379
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
380
|
+
}) | undefined) => Promise<T[]>;
|
|
436
381
|
|
|
437
382
|
/**
|
|
438
383
|
* Modern fluent error rule builder
|
|
@@ -497,4 +442,4 @@ declare const errorRule: {
|
|
|
497
442
|
};
|
|
498
443
|
};
|
|
499
444
|
|
|
500
|
-
export { type AbortedResult, type FailureResult, type Milliseconds, type RetryCount, RetryStrategies, type RulesMode, type SuccessResult, type TimeoutResult, type TryoConfig, type TryoMetrics
|
|
445
|
+
export { type AbortedResult, type FailureResult, type Milliseconds, type RetryCount, RetryStrategies, type RulesMode, type SuccessResult, type TimeoutResult, type TryoConfig, type TryoMetrics, type TryoOptions, type TryoResult, TypedError, all, allOrThrow, asMilliseconds, asRetryCount, tryo as default, errorRule, orThrow, run, runOrThrow, tryo };
|
package/dist/index.d.ts
CHANGED
|
@@ -111,6 +111,46 @@ interface CircuitBreakerConfig<E extends AnyTypedError = AnyTypedError> {
|
|
|
111
111
|
}
|
|
112
112
|
type CircuitState = 'closed' | 'open' | 'half-open';
|
|
113
113
|
|
|
114
|
+
/**
|
|
115
|
+
* Modern error normalization system
|
|
116
|
+
* Provides type-safe error transformation and normalization
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
type ErrorNormalizer<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E;
|
|
120
|
+
type ErrorRule<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E | null;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Modern retry strategies with enhanced capabilities
|
|
124
|
+
* Provides various retry patterns with type safety
|
|
125
|
+
*/
|
|
126
|
+
|
|
127
|
+
type RetryStrategy = FixedDelayStrategy | ExponentialBackoffStrategy | FibonacciBackoffStrategy | CustomDelayStrategy;
|
|
128
|
+
interface FixedDelayStrategy {
|
|
129
|
+
readonly type: 'fixed';
|
|
130
|
+
readonly delay: number;
|
|
131
|
+
}
|
|
132
|
+
interface ExponentialBackoffStrategy {
|
|
133
|
+
readonly type: 'exponential';
|
|
134
|
+
readonly base: number;
|
|
135
|
+
readonly factor: number;
|
|
136
|
+
readonly maxDelay?: number;
|
|
137
|
+
}
|
|
138
|
+
interface FibonacciBackoffStrategy {
|
|
139
|
+
readonly type: 'fibonacci';
|
|
140
|
+
readonly base: number;
|
|
141
|
+
readonly maxDelay?: number;
|
|
142
|
+
}
|
|
143
|
+
interface CustomDelayStrategy {
|
|
144
|
+
readonly type: 'custom';
|
|
145
|
+
readonly calculate: (attempt: RetryCount, error: unknown) => number;
|
|
146
|
+
}
|
|
147
|
+
declare const RetryStrategies: {
|
|
148
|
+
readonly fixed: (delay: number) => FixedDelayStrategy;
|
|
149
|
+
readonly exponential: (base: number, factor?: number, maxDelay?: number) => ExponentialBackoffStrategy;
|
|
150
|
+
readonly fibonacci: (base: number, maxDelay?: number) => FibonacciBackoffStrategy;
|
|
151
|
+
readonly custom: (calculate: (attempt: RetryCount, error: unknown) => number) => CustomDelayStrategy;
|
|
152
|
+
};
|
|
153
|
+
|
|
114
154
|
/**
|
|
115
155
|
* Modern result types with enhanced discriminated unions
|
|
116
156
|
* Provides better type safety and more granular result categorization
|
|
@@ -122,30 +162,30 @@ interface SuccessResult<T, E extends AnyTypedError> {
|
|
|
122
162
|
readonly ok: true;
|
|
123
163
|
readonly data: T;
|
|
124
164
|
readonly error: null;
|
|
125
|
-
readonly metrics: TryoMetrics
|
|
165
|
+
readonly metrics: TryoMetrics<E>;
|
|
126
166
|
}
|
|
127
167
|
interface FailureResult<E extends AnyTypedError> {
|
|
128
168
|
readonly type: 'failure';
|
|
129
169
|
readonly ok: false;
|
|
130
170
|
readonly data: null;
|
|
131
171
|
readonly error: E;
|
|
132
|
-
readonly metrics: TryoMetrics
|
|
172
|
+
readonly metrics: TryoMetrics<E>;
|
|
133
173
|
}
|
|
134
174
|
interface AbortedResult<E extends AnyTypedError> {
|
|
135
175
|
readonly type: 'aborted';
|
|
136
176
|
readonly ok: false;
|
|
137
177
|
readonly data: null;
|
|
138
178
|
readonly error: E;
|
|
139
|
-
readonly metrics: TryoMetrics
|
|
179
|
+
readonly metrics: TryoMetrics<E>;
|
|
140
180
|
}
|
|
141
181
|
interface TimeoutResult<E extends AnyTypedError> {
|
|
142
182
|
readonly type: 'timeout';
|
|
143
183
|
readonly ok: false;
|
|
144
184
|
readonly data: null;
|
|
145
185
|
readonly error: E;
|
|
146
|
-
readonly metrics: TryoMetrics
|
|
186
|
+
readonly metrics: TryoMetrics<E>;
|
|
147
187
|
}
|
|
148
|
-
interface TryoMetrics
|
|
188
|
+
interface TryoMetrics<E extends AnyTypedError> {
|
|
149
189
|
readonly totalAttempts: RetryCount;
|
|
150
190
|
readonly totalRetries: RetryCount;
|
|
151
191
|
readonly totalDuration: Milliseconds;
|
|
@@ -159,45 +199,10 @@ interface TryoMetrics$1<E extends AnyTypedError> {
|
|
|
159
199
|
}
|
|
160
200
|
|
|
161
201
|
/**
|
|
162
|
-
*
|
|
163
|
-
* Provides
|
|
164
|
-
*/
|
|
165
|
-
|
|
166
|
-
type ErrorNormalizer<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E;
|
|
167
|
-
type ErrorRule<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E | null;
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Modern retry strategies with enhanced capabilities
|
|
171
|
-
* Provides various retry patterns with type safety
|
|
202
|
+
* Configuration types for modern execution engine
|
|
203
|
+
* Provides comprehensive configuration with type safety
|
|
172
204
|
*/
|
|
173
205
|
|
|
174
|
-
type RetryStrategy = FixedDelayStrategy | ExponentialBackoffStrategy | FibonacciBackoffStrategy | CustomDelayStrategy;
|
|
175
|
-
interface FixedDelayStrategy {
|
|
176
|
-
readonly type: 'fixed';
|
|
177
|
-
readonly delay: number;
|
|
178
|
-
}
|
|
179
|
-
interface ExponentialBackoffStrategy {
|
|
180
|
-
readonly type: 'exponential';
|
|
181
|
-
readonly base: number;
|
|
182
|
-
readonly factor: number;
|
|
183
|
-
readonly maxDelay?: number;
|
|
184
|
-
}
|
|
185
|
-
interface FibonacciBackoffStrategy {
|
|
186
|
-
readonly type: 'fibonacci';
|
|
187
|
-
readonly base: number;
|
|
188
|
-
readonly maxDelay?: number;
|
|
189
|
-
}
|
|
190
|
-
interface CustomDelayStrategy {
|
|
191
|
-
readonly type: 'custom';
|
|
192
|
-
readonly calculate: (attempt: RetryCount, error: unknown) => number;
|
|
193
|
-
}
|
|
194
|
-
declare const RetryStrategies: {
|
|
195
|
-
readonly fixed: (delay: number) => FixedDelayStrategy;
|
|
196
|
-
readonly exponential: (base: number, factor?: number, maxDelay?: number) => ExponentialBackoffStrategy;
|
|
197
|
-
readonly fibonacci: (base: number, maxDelay?: number) => FibonacciBackoffStrategy;
|
|
198
|
-
readonly custom: (calculate: (attempt: RetryCount, error: unknown) => number) => CustomDelayStrategy;
|
|
199
|
-
};
|
|
200
|
-
|
|
201
206
|
interface TryoConfig<E extends AnyTypedError = AnyTypedError> {
|
|
202
207
|
/** Abort signal passed to tasks */
|
|
203
208
|
readonly signal?: AbortSignal;
|
|
@@ -265,7 +270,6 @@ interface LoggerConfig<E extends AnyTypedError> {
|
|
|
265
270
|
/** Warning logging function */
|
|
266
271
|
readonly warn?: (message: string, meta?: unknown) => void;
|
|
267
272
|
}
|
|
268
|
-
type TryoMetrics<E extends AnyTypedError> = TryoMetrics$1<E>;
|
|
269
273
|
type JitterConfig = {
|
|
270
274
|
type: 'none';
|
|
271
275
|
} | {
|
|
@@ -287,10 +291,17 @@ declare const JitterConfig: {
|
|
|
287
291
|
|
|
288
292
|
type RulesMode = 'extend' | 'replace';
|
|
289
293
|
type DefaultError = AbortedError | TimeoutError | NetworkError | HttpError | CircuitOpenError | ValidationError | UnknownError;
|
|
290
|
-
type RunOptions<E extends AnyTypedError> = Omit<Partial<TryoConfig<E>>, 'circuitBreaker'
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
+
type RunOptions<E extends AnyTypedError, TData = unknown> = Omit<Partial<TryoConfig<E>>, 'circuitBreaker' | 'onSuccess'> & {
|
|
295
|
+
onSuccess?: (data: TData, metrics?: TryoMetrics<E>) => void;
|
|
296
|
+
};
|
|
297
|
+
type AllOptions<E extends AnyTypedError, TData = unknown> = RunOptions<E, TData>;
|
|
298
|
+
type PartitionedResults<T, E extends AnyTypedError> = {
|
|
299
|
+
ok: Array<SuccessResult<T, E>>;
|
|
300
|
+
errors: Array<FailureResult<E> | AbortedResult<E> | TimeoutResult<E>>;
|
|
301
|
+
failure: Array<FailureResult<E>>;
|
|
302
|
+
aborted: Array<AbortedResult<E>>;
|
|
303
|
+
timeout: Array<TimeoutResult<E>>;
|
|
304
|
+
};
|
|
294
305
|
type MaybePromise<T> = T | Promise<T>;
|
|
295
306
|
type RuleLike = (error: unknown) => AnyTypedError | null;
|
|
296
307
|
type NonNull<T> = T extends null ? never : T;
|
|
@@ -325,114 +336,48 @@ declare function tryo<E extends AnyTypedError = DefaultError>(options?: TryoOpti
|
|
|
325
336
|
type Tryo<E extends AnyTypedError = AnyTypedError> = {
|
|
326
337
|
run: <T>(task: (ctx: {
|
|
327
338
|
signal: AbortSignal;
|
|
328
|
-
}) => MaybePromise<T>, options?: RunOptions<E>) => Promise<TryoResult<T, E>>;
|
|
339
|
+
}) => MaybePromise<T>, options?: RunOptions<E, T>) => Promise<TryoResult<T, E>>;
|
|
329
340
|
runOrThrow: <T>(task: (ctx: {
|
|
330
341
|
signal: AbortSignal;
|
|
331
|
-
}) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
|
|
342
|
+
}) => MaybePromise<T>, options?: RunOptions<E, T>) => Promise<T>;
|
|
332
343
|
orThrow: <T>(task: (ctx: {
|
|
333
344
|
signal: AbortSignal;
|
|
334
|
-
}) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
|
|
345
|
+
}) => MaybePromise<T>, options?: RunOptions<E, T>) => Promise<T>;
|
|
335
346
|
all: <T>(tasks: Array<(ctx: {
|
|
336
347
|
signal: AbortSignal;
|
|
337
|
-
}) => MaybePromise<T>>, options?: AllOptions<E>) => Promise<Array<TryoResult<T, E>>>;
|
|
348
|
+
}) => MaybePromise<T>>, options?: AllOptions<E, T>) => Promise<Array<TryoResult<T, E>>>;
|
|
338
349
|
allOrThrow: <T>(tasks: Array<(ctx: {
|
|
339
350
|
signal: AbortSignal;
|
|
340
|
-
}) => MaybePromise<T>>, options?: AllOptions<E>) => Promise<T[]>;
|
|
341
|
-
partitionAll: <T>(results: Array<TryoResult<T, E>>) =>
|
|
342
|
-
ok: Array<SuccessResult<T, E>>;
|
|
343
|
-
errors: Array<FailureResult<E> | AbortedResult<E> | TimeoutResult<E>>;
|
|
344
|
-
failure: Array<FailureResult<E>>;
|
|
345
|
-
aborted: Array<AbortedResult<E>>;
|
|
346
|
-
timeout: Array<TimeoutResult<E>>;
|
|
347
|
-
};
|
|
351
|
+
}) => MaybePromise<T>>, options?: AllOptions<E, T>) => Promise<T[]>;
|
|
352
|
+
partitionAll: <T>(results: Array<TryoResult<T, E>>) => PartitionedResults<T, E>;
|
|
348
353
|
withConfig: (additionalConfig: Omit<Partial<TryoConfig<E>>, 'signal'>) => Tryo<E>;
|
|
349
354
|
};
|
|
350
355
|
|
|
351
356
|
declare const run: <T>(task: (ctx: {
|
|
352
357
|
signal: AbortSignal;
|
|
353
|
-
}) => T | Promise<T>, options?: {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
readonly ignoreAbort?: boolean | undefined;
|
|
357
|
-
readonly retry?: RetryConfig<DefaultError> | undefined;
|
|
358
|
-
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
359
|
-
readonly concurrency?: number | undefined;
|
|
360
|
-
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
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
|
-
} | undefined) => Promise<TryoResult<T, DefaultError>>;
|
|
358
|
+
}) => T | Promise<T>, options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
359
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
360
|
+
}) | undefined) => Promise<TryoResult<T, DefaultError>>;
|
|
368
361
|
declare const runOrThrow: <T>(task: (ctx: {
|
|
369
362
|
signal: AbortSignal;
|
|
370
|
-
}) => T | Promise<T>, options?: {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
readonly ignoreAbort?: boolean | undefined;
|
|
374
|
-
readonly retry?: RetryConfig<DefaultError> | undefined;
|
|
375
|
-
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
376
|
-
readonly concurrency?: number | undefined;
|
|
377
|
-
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
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;
|
|
384
|
-
} | undefined) => Promise<T>;
|
|
363
|
+
}) => T | Promise<T>, options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
364
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
365
|
+
}) | undefined) => Promise<T>;
|
|
385
366
|
declare const orThrow: <T>(task: (ctx: {
|
|
386
367
|
signal: AbortSignal;
|
|
387
|
-
}) => T | Promise<T>, options?: {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
readonly ignoreAbort?: boolean | undefined;
|
|
391
|
-
readonly retry?: RetryConfig<DefaultError> | undefined;
|
|
392
|
-
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
393
|
-
readonly concurrency?: number | undefined;
|
|
394
|
-
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
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;
|
|
401
|
-
} | undefined) => Promise<T>;
|
|
368
|
+
}) => T | Promise<T>, options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
369
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
370
|
+
}) | undefined) => Promise<T>;
|
|
402
371
|
declare const all: <T>(tasks: ((ctx: {
|
|
403
372
|
signal: AbortSignal;
|
|
404
|
-
}) => T | Promise<T>)[], options?: {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
readonly ignoreAbort?: boolean | undefined;
|
|
408
|
-
readonly retry?: RetryConfig<DefaultError> | undefined;
|
|
409
|
-
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
410
|
-
concurrency?: number | undefined;
|
|
411
|
-
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
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;
|
|
418
|
-
} | undefined) => Promise<TryoResult<T, DefaultError>[]>;
|
|
373
|
+
}) => T | Promise<T>)[], options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
374
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
375
|
+
}) | undefined) => Promise<TryoResult<T, DefaultError>[]>;
|
|
419
376
|
declare const allOrThrow: <T>(tasks: ((ctx: {
|
|
420
377
|
signal: AbortSignal;
|
|
421
|
-
}) => T | Promise<T>)[], options?: {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
readonly ignoreAbort?: boolean | undefined;
|
|
425
|
-
readonly retry?: RetryConfig<DefaultError> | undefined;
|
|
426
|
-
readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
|
|
427
|
-
concurrency?: number | undefined;
|
|
428
|
-
readonly logger?: LoggerConfig<DefaultError> | undefined;
|
|
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;
|
|
435
|
-
} | undefined) => Promise<T[]>;
|
|
378
|
+
}) => T | Promise<T>)[], options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
379
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
380
|
+
}) | undefined) => Promise<T[]>;
|
|
436
381
|
|
|
437
382
|
/**
|
|
438
383
|
* Modern fluent error rule builder
|
|
@@ -497,4 +442,4 @@ declare const errorRule: {
|
|
|
497
442
|
};
|
|
498
443
|
};
|
|
499
444
|
|
|
500
|
-
export { type AbortedResult, type FailureResult, type Milliseconds, type RetryCount, RetryStrategies, type RulesMode, type SuccessResult, type TimeoutResult, type TryoConfig, type TryoMetrics
|
|
445
|
+
export { type AbortedResult, type FailureResult, type Milliseconds, type RetryCount, RetryStrategies, type RulesMode, type SuccessResult, type TimeoutResult, type TryoConfig, type TryoMetrics, type TryoOptions, type TryoResult, TypedError, all, allOrThrow, asMilliseconds, asRetryCount, tryo as default, errorRule, orThrow, run, runOrThrow, tryo };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
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};
|
|
1
|
+
var le=Object.defineProperty;var de=(e,r,t)=>r in e?le(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t;var d=(e,r,t)=>de(e,typeof r!="symbol"?r+"":r,t);var E=class extends Error{constructor(t,n){var o,s;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=(s=n.meta)!=null?s:{},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 E{constructor(t,n){super(`Operation timed out after ${t}ms`,{cause:n,retryable:!0});d(this,"code","TIMEOUT")}};var F=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 B=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},q=e=>{if(e<1||!Number.isInteger(e))throw new Error(`Invalid concurrency limit: must be a positive integer, got ${e}`);return e},Q=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: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 o,s,a;if(!((a=(s=(o=this.config).shouldCountAsFailure)==null?void 0:s.call(o,r))!=null?a:!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 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 X=(e,r)=>t=>{for(let n of e){let o=n(t);if(o!==null)return o}return r(t)},Z=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 ye=e=>{let t=e.toString().match(/\bcode\s*:\s*['"`]([^'"`]+)['"`]/);return t==null?void 0:t[1]},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,U=class{constructor(r){this.predicate=r}toCode(r){return new W(this.predicate,r)}toError(r){let t=o=>{var c;if(!this.predicate(o))return null;let s=r(o),a=s.code,i=Object.hasOwn(s,"cause")?s.cause:o,l=(c=s.meta)!=null?c:{};class u extends E{constructor(){let m=Object.hasOwn(s,"raw")?s.raw:o;super(s.message,{title:s.title,cause:i,meta:l,status:s.status,retryable:s.retryable,raw:m,path:s.path});d(this,"code",a)}}return new u},n=ye(r);return n&&(t.__tryoCode=n),t}};function Te(e,r){let t=new U(s=>s instanceof e);if(r)return t.toError(r);let o=s=>{if(!(s instanceof e))return null;if(s instanceof E)return s;let a=s,i=typeof a.code=="string"&&a.code.length>0?a.code:"UNKNOWN",l=Object.hasOwn(a,"cause"),u=Object.hasOwn(a,"raw");class c extends E{constructor(){super(a.message||i,{title:typeof a.title=="string"?a.title:void 0,cause:l?a.cause:s,meta:Ee(a.meta)?a.meta:{},status:typeof a.status=="number"?a.status:void 0,retryable:typeof a.retryable=="boolean"?a.retryable:void 0,raw:u?a.raw:s,path:typeof a.path=="string"?a.path:void 0});d(this,"code",i)}}return new c};return o.toCode=t.toCode.bind(t),o.toError=t.toError.bind(t),o}var W=class{constructor(r,t){this.predicate=r;this.errorCode=t}with(r){let t=n=>{var u;if(!this.predicate(n))return null;let o=r(n),s=Object.hasOwn(o,"cause")?o.cause:n,a=(u=o.meta)!=null?u:{},i=this.errorCode;class l extends E{constructor(){let m=Object.hasOwn(o,"raw")?o.raw:n;super(o.message,{title:o.title,cause:s,meta:a,status:o.status,retryable:o.retryable,raw:m,path:o.path});d(this,"code",i)}}return new l};return t.__tryoCode=this.errorCode,t}},h={when:e=>new U(e),instance:Te},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=>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 E)).toCode("UNKNOWN").with(e=>({message:e.message||"Unknown error occurred",cause:e,raw:e}))};var we=[x.typed,x.abort,x.timeout,x.http,x.network,x.unknown];var be={when:e=>h.when(e),instance:h.instance},ee=we;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})},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*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},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=i=>{r&&i&&r.removeEventListener("abort",i)},s,a=()=>{s&&clearTimeout(s),o(a),n(new DOMException("Aborted","AbortError"))};s=setTimeout(()=>{o(a),t()},e),r==null||r.addEventListener("abort",a,{once:!0})}),oe=(e,r,t,n)=>new Promise((o,s)=>{if(t!=null&&t.aborted){s(new DOMException("Aborted","AbortError"));return}let a=!1,i=setTimeout(()=>{var c;a=!0,u(),s((c=n==null?void 0:n())!=null?c:new Error(`Operation timed out after ${r}ms`))},r),l=()=>{a||(a=!0,u(),s(new DOMException("Aborted","AbortError")))},u=()=>{clearTimeout(i),t==null||t.removeEventListener("abort",l)};t==null||t.addEventListener("abort",l,{once:!0}),e.then(c=>{a||(a=!0,u(),o(c))},c=>{a||(a=!0,u(),s(c))})});var Ce=e=>{var a,i,l;if(e.toError)return e.toError;let r=(a=e.rulesMode)!=null?a:"extend",t=(i=e.rules)!=null?i:[];xe(t);let n=ee,o=(l=e.fallback)!=null?l:(u=>Z(B)(u)),s=r==="replace"?t:[...t,...n];return X(s,o)},xe=e=>{let r=new Set;for(let t of e){let n=t.__tryoCode;if(n){if(r.has(n))throw new Error(`Duplicate rule code detected: ${n}`);r.add(n)}}},ge=e=>{if(e)switch(e.type){case"none":return;case"full":case"equal":Q(e.ratio);return;case"custom":return;default:{let r=e;throw new Error(`Unsupported jitter configuration: ${r}`)}}},K=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(q(r.concurrency)):r.concurrency}),r.retry&&(te(r.retry.strategy),ge(r.retry.jitter),r={...r,retry:{...r.retry,maxRetries:Number(C(r.retry.maxRetries))}}),r},V=class e{constructor(r={}){d(this,"circuitBreaker");d(this,"config");d(this,"lastCircuitState");let{rules:t,rulesMode:n,fallback:o,toError:s,mapError:a,...i}=r,l=Ce(r),u={...i,errorHandling:{normalizer:l,mapError:a}};this.config=K(u),u.circuitBreaker&&(this.circuitBreaker=new _(u.circuitBreaker),this.lastCircuitState=this.circuitBreaker.getState().state)}async run(r,t={}){var s,a,i,l;let n=K({...this.config,...t});if(this.circuitBreaker){let u=(s=this.lastCircuitState)!=null?s:this.circuitBreaker.getState().state,c=await this.circuitBreaker.canExecute(),y=this.circuitBreaker.getState().state;if(u!==y)try{(a=n.onCircuitStateChange)==null||a.call(n,u,y)}catch{}if(this.lastCircuitState=y,!c)return{type:"failure",ok:!1,data:null,error:this.circuitBreaker.createOpenError(),metrics:{totalAttempts:0,totalRetries:0,totalDuration:0,retryHistory:[]}}}let o=await ke(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 c=this.circuitBreaker.getState().state;if(u!==c)try{(l=n.onCircuitStateChange)==null||l.call(n,u,c)}catch{}this.lastCircuitState=c}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 c;let n=K({...this.config,...t}),o=(c=n.concurrency)!=null?c:Number.POSITIVE_INFINITY,s=Number.isFinite(o)?Number(q(o)):Number.POSITIVE_INFINITY;if(s===Number.POSITIVE_INFINITY)return Promise.all(r.map(y=>this.run(y,n)));let a=new Array(r.length),i=0,l=async()=>{var y;for(;i<r.length&&!((y=n.signal)!=null&&y.aborted);){let T=i++;if(T>=r.length)break;let m=r[T];m&&(a[T]=await this.run(m,n))}},u=Array.from({length:Math.min(s,r.length)},()=>l());await Promise.all(u);for(let y=0;y<r.length;y++)if(!(y in a)){let T=r[y];T&&(a[y]=await this.run(T,n))}return a}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=[],s=[],a=[];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":s.push(i);break;case"timeout":a.push(i);break}}return{ok:t,errors:n,failure:o,aborted:s,timeout:a}}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,...s}=r,a=(l=o==null?void 0:o.normalizer)!=null?l:t.normalizer,i=(u=o==null?void 0:o.mapError)!=null?u:t.mapError;return new e({...n,...s,toError:a,mapError:i})}};function L(e={}){let r=new V(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 ke(e,r){let{signal:t,ignoreAbort:n=!0,timeout:o,retry:s,errorHandling:a,logger:i,onSuccess:l,onError:u,onFinally:c,onAbort:y,onRetry:T}=r,m=(R,...p)=>{try{R==null||R(...p)}catch{}},M,k=0,g=[],z=Date.now(),{signal:I,cleanup:ae}=se(t),O=R=>({totalAttempts:k,totalRetries:k>0?Number(k)-1:0,totalDuration:Date.now()-z,lastError:R,retryHistory:g});try{if(I.aborted){m(y,I);let p=a.normalizer(new DOMException("Aborted","AbortError")),w=a.mapError?a.mapError(p):p;return{type:"aborted",ok:!1,data:null,error:w,metrics:O(w)}}let R=async()=>{var v,A,J;let p=1,w=C((v=s==null?void 0:s.maxRetries)!=null?v:0);for(;;){k=p;let j=new AbortController,{signal:H,cleanup:ie}=se(I,j.signal);try{let D=Promise.resolve(e({signal:H})),S=o?await oe(D,o,H,()=>(j.abort(),new P(b(o)))):await D;return m(l,S,O()),m(i==null?void 0:i.info,`Task succeeded on attempt ${p}`),S}catch(D){let S=a.normalizer(D),f=a.mapError?a.mapError(S):S;if(M=f,f.code==="ABORTED"&&m(y,H),n&&f.code==="ABORTED"||(m(u,f,O(f)),m(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 Y=s==null?void 0:s.shouldRetry,ue={totalAttempts:Number(k),elapsedTime:Date.now()-z,startTime:new Date(z),lastDelay:(A=g[g.length-1])!=null&&A.delay?Number((J=g[g.length-1])==null?void 0:J.delay):void 0};if(!Y||Y(p,f,ue)){let ce=s?re(s.strategy,p,f):0,$=Oe(ce,s==null?void 0:s.jitter),G=b($);g.push({attempt:p,error:f,delay:G,timestamp:new Date}),m(T,p,f,$),m(i==null?void 0:i.info,`Retrying in ${$}ms (attempt ${p+1})`),p+=1,await ne(G,I);continue}}throw f}finally{ie()}}};try{let p=await R(),w=O();return m(c,w),{type:"success",ok:!0,data:p,error:null,metrics:w}}catch(p){let w=M!=null?M:a.normalizer(p),v=w.code==="TIMEOUT"?"timeout":w.code==="ABORTED"?"aborted":"failure",A=O(w);return m(c,A),{type:v,ok:!1,data:null,error:w,metrics:A}}}finally{ae()}}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 s=()=>r.abort();o.addEventListener("abort",s,{once:!0}),n.push({signal:o,abort:s})}return{signal:r.signal,cleanup:()=>{for(let o of n)o.signal.removeEventListener("abort",o.abort)}}}function Oe(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=L(),Ae=N.run,Se=N.runOrThrow,Ne=N.orThrow,Me=N.all,Ie=N.allOrThrow;export{he as RetryStrategies,E as TypedError,Me as all,Ie as allOrThrow,b as asMilliseconds,C as asRetryCount,L as default,be as errorRule,Ne as orThrow,Ae as run,Se as runOrThrow,L as tryo};
|