tryo 0.13.8 → 0.13.10
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 +115 -159
- package/dist/index.d.ts +115 -159
- 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 he=Object.getOwnPropertyDescriptor;var be=Object.getOwnPropertyNames;var we=Object.prototype.hasOwnProperty;var Re=(e,t,r)=>t in e?F(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var Ce=(e,t)=>{for(var r in t)F(e,r,{get:t[r],enumerable:!0})},xe=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of be(t))!we.call(e,o)&&o!==r&&F(e,o,{get:()=>t[o],enumerable:!(n=he(t,o))||n.enumerable});return e};var ge=e=>xe(F({},"__esModule",{value:!0}),e);var d=(e,t,r)=>Re(e,typeof t!="symbol"?t+"":t,r);var Ue={};Ce(Ue,{RetryStrategies:()=>ne,TypedError:()=>f,all:()=>ye,allOrThrow:()=>pe,asMilliseconds:()=>b,asRetryCount:()=>w,default:()=>M,errorRule:()=>te,orThrow:()=>de,run:()=>ce,runOrThrow:()=>le,tryo:()=>M});module.exports=ge(Ue);var f=class extends Error{constructor(r,n){var o,s;super(r);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(r){return this.code===r}withMeta(r){return this.meta=r,this}withStatus(r){return this.status=r,this}withCause(r){return this.cause=r,this}withPath(r){return this.path=r,this}withRaw(r){return this.raw=r,this}withRetryable(r){return this.retryable=r,this}toJSON(){return{name:this.name,code:this.code,title:this.title,message:this.message,meta:this.meta,status:this.status,timestamp:this.timestamp,retryable:this.retryable,cause:this.cause,raw:this.raw,path:this.path,stack:this.stack}}},B=class extends f{constructor(r,n){super(`Operation timed out after ${r}ms`,{cause:n,retryable:!0});d(this,"code","TIMEOUT")}};var _=class extends f{constructor(r,n){super(`Circuit breaker is open, reset after ${r}ms`,{cause:n,retryable:!1});d(this,"code","CIRCUIT_OPEN")}};var U=class extends f{constructor(r,n){super(r,{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},w=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(t){d(this,"state");d(this,"config");this.config={failureThreshold:w(t.failureThreshold),resetTimeout:b(t.resetTimeout),halfOpenRequests:w(t.halfOpenRequests),shouldCountAsFailure:t.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(t){var o,s,a;if(!((a=(s=(o=this.config).shouldCountAsFailure)==null?void 0:s.call(o,t))!=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 t=this.state.nextAttemptTime?b(Math.max(0,this.state.nextAttemptTime.getTime()-Date.now())):this.config.resetTimeout;return new _(t)}forceState(t){this.state={state:t,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,t)=>r=>{for(let n of e){let o=n(r);if(o!==null)return o}return t(r)},ee=e=>t=>t instanceof f?t:t instanceof Error?new e(t.message,t):typeof t=="string"?new e(t):new e("Unknown error occurred",t);var ke=e=>{let r=e.toString().match(/\bcode\s*:\s*['"`]([^'"`]+)['"`]/);return r==null?void 0:r[1]},Oe=e=>{if(typeof e!="object"||e===null)return!1;let t=e;return typeof t.status=="number"||typeof t.statusCode=="number"},Ae=e=>{if(typeof e!="object"||e===null)return!1;let t=e;return typeof t.code=="string"&&t.code.length>0},Se=e=>{var t;if(e instanceof Error){let r=e.message.toLowerCase();if(e.name==="TypeError"&&(r.includes("fetch")&&r.includes("failed")||r.includes("network"))||r.includes("fetch")&&r.includes("failed")||r.includes("network"))return!0}if(Ae(e)){let r=((t=e.code)!=null?t:"").toUpperCase();return r==="ECONNRESET"||r==="ECONNREFUSED"||r==="ETIMEDOUT"||r==="ENOTFOUND"||r==="EAI_AGAIN"}return!1},Me=e=>typeof e=="object"&&e!==null,z=class{constructor(t){this.predicate=t}toCode(t){return new K(this.predicate,t)}toError(t){let r=o=>{var c;if(!this.predicate(o))return null;let s=t(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(t);return n&&(r.__tryoCode=n),r}};function Ne(e,t){let r=new z(s=>s instanceof e);if(t)return r.toError(t);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:Me(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=r.toCode.bind(r),o.toError=r.toError.bind(r),o}var K=class{constructor(t,r){this.predicate=t;this.errorCode=r}with(t){let r=n=>{var u;if(!this.predicate(n))return null;let o=t(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 r.__tryoCode=this.errorCode,r}},R={when:e=>new z(e),instance:Ne},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 t=e,r=(n=t.status)!=null?n:t.statusCode;return typeof r=="number"&&r>=400}).toCode("HTTP").with(e=>{var n;let t=(n=e.status)!=null?n:e.statusCode,r=typeof t=="number"&&(t>=500||t===429);return{message:e.message||`HTTP ${t!=null?t:"error"} error`,cause:e,status:typeof t=="number"?t:void 0,retryable:r,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 ve=[x.typed,x.abort,x.timeout,x.http,x.network,x.unknown];var te={when:e=>R.when(e),instance:R.instance},re=ve;var ne={fixed:e=>({type:"fixed",delay:e}),exponential:(e,t=2,r)=>({type:"exponential",base:e,factor:t,maxDelay:r}),fibonacci:(e,t)=>({type:"fibonacci",base:e,maxDelay:t}),custom:e=>({type:"custom",calculate:e})},oe=(e,t,r)=>{switch(e.type){case"fixed":return e.delay;case"exponential":{let n=e.base*e.factor**(Number(t)-1);return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"fibonacci":{let n=e.base*Ie(Number(t));return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"custom":return e.calculate(t,r);default:return e}},Ie=e=>{if(e<=1)return 1;let t=1,r=1;for(let n=2;n<=e;n++){let o=t+r;t=r,r=o}return r},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 t=e;throw new Error(`Unknown strategy type: ${t}`)}}};var ae=(e,t)=>new Promise((r,n)=>{if(t!=null&&t.aborted){n(new DOMException("Aborted","AbortError"));return}let o=i=>{t&&i&&t.removeEventListener("abort",i)},s,a=()=>{s&&clearTimeout(s),o(a),n(new DOMException("Aborted","AbortError"))};s=setTimeout(()=>{o(a),r()},e),t==null||t.addEventListener("abort",a,{once:!0})}),ie=(e,t,r,n)=>new Promise((o,s)=>{if(r!=null&&r.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 ${t}ms`))},t),l=()=>{a||(a=!0,u(),s(new DOMException("Aborted","AbortError")))},u=()=>{clearTimeout(i),r==null||r.removeEventListener("abort",l)};r==null||r.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 t=(a=e.rulesMode)!=null?a:"extend",r=(i=e.rules)!=null?i:[];Pe(r);let n=re,o=(l=e.fallback)!=null?l:(u=>ee(U)(u)),s=t==="replace"?r:[...r,...n];return Z(s,o)},Pe=e=>{let t=new Set;for(let r of e){let n=r.__tryoCode;if(n){if(t.has(n))throw new Error(`Duplicate rule code detected: ${n}`);t.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 t=e;throw new Error(`Unsupported jitter configuration: ${t}`)}}},V=e=>{let t=e;return t.timeout!==void 0&&(t={...t,timeout:Number(b(t.timeout))}),t.concurrency!==void 0&&(t={...t,concurrency:Number.isFinite(t.concurrency)?Number(W(t.concurrency)):t.concurrency}),t.retry&&(se(t.retry.strategy),Fe(t.retry.jitter),t={...t,retry:{...t.retry,maxRetries:Number(w(t.retry.maxRetries))}}),t},J=class e{constructor(t={}){d(this,"circuitBreaker");d(this,"config");d(this,"lastCircuitState");let{rules:r,rulesMode:n,fallback:o,toError:s,mapError:a,...i}=t,l=De(t),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(t,r={}){var s,a,i,l;let n=V({...this.config,...r});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(t,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(t,r={}){return this.orThrow(t,r)}async orThrow(t,r={}){let n=await this.run(t,r);if(n.ok)return n.data;throw n.error}async all(t,r={}){var c;let n=V({...this.config,...r}),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(t.map(y=>this.run(y,n)));let a=new Array(t.length),i=0,l=async()=>{var y;for(;i<t.length&&!((y=n.signal)!=null&&y.aborted);){let T=i++;if(T>=t.length)break;let m=t[T];m&&(a[T]=await this.run(m,n))}},u=Array.from({length:Math.min(s,t.length)},()=>l());await Promise.all(u);for(let y=0;y<t.length;y++)if(!(y in a)){let T=t[y];T&&(a[y]=await this.run(T,n))}return a}async allOrThrow(t,r={}){return(await this.all(t,r)).map(o=>{if(!o.ok)throw o.error;return o.data})}partitionAll(t){let r=[],n=[],o=[],s=[],a=[];for(let i of t){if(i.type==="success"){r.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:r,errors:n,failure:o,aborted:s,timeout:a}}getCircuitBreakerState(){var t;return(t=this.circuitBreaker)==null?void 0:t.getState()}resetCircuitBreaker(){var t;(t=this.circuitBreaker)==null||t.reset()}getConfig(){return{...this.config}}withConfig(t){var l,u;let{errorHandling:r,...n}=this.config,{errorHandling:o,...s}=t,a=(l=o==null?void 0:o.normalizer)!=null?l:r.normalizer,i=(u=o==null?void 0:o.mapError)!=null?u:r.mapError;return new e({...n,...s,toError:a,mapError:i})}};function M(e={}){let t=new J(e);return{run:(r,n)=>t.run(r,n),orThrow:(r,n)=>t.orThrow(r,n),runOrThrow:(r,n)=>t.runOrThrow(r,n),all:(r,n)=>t.all(r,n),allOrThrow:(r,n)=>t.allOrThrow(r,n),partitionAll:r=>t.partitionAll(r),withConfig:r=>t.withConfig(r)}}async function Be(e,t){let{signal:r,ignoreAbort:n=!0,timeout:o,retry:s,errorHandling:a,logger:i,onSuccess:l,onError:u,onFinally:c,onAbort:y,onRetry:T}=t,m=(C,...p)=>{try{C==null||C(...p)}catch{}},v,k=0,g=[],H=Date.now(),{signal:I,cleanup:me}=ue(r),O=C=>({totalAttempts:k,totalRetries:k>0?Number(k)-1:0,totalDuration:Date.now()-H,lastError:C,retryHistory:g});try{if(I.aborted){m(y,I);let p=a.normalizer(new DOMException("Aborted","AbortError")),h=a.mapError?a.mapError(p):p;return{type:"aborted",ok:!1,data:null,error:h,metrics:O(h)}}let C=async()=>{var D,A,Y;let p=1,h=w((D=s==null?void 0:s.maxRetries)!=null?D:0);for(;;){k=p;let j=new AbortController,{signal:$,cleanup:fe}=ue(I,j.signal);try{let P=Promise.resolve(e({signal:$})),S=o?await ie(P,o,$,()=>(j.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(v=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(h)){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((Y=g[g.length-1])==null?void 0:Y.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,I);continue}}throw E}finally{fe()}}};try{let p=await C(),h=O();return m(c,h),{type:"success",ok:!0,data:p,error:null,metrics:h}}catch(p){let h=v!=null?v:a.normalizer(p),D=h.code==="TIMEOUT"?"timeout":h.code==="ABORTED"?"aborted":"failure",A=O(h);return m(c,A),{type:D,ok:!1,data:null,error:h,metrics:A}}}finally{me()}}function ue(...e){let t=new AbortController,r=e.filter(o=>o!==void 0);if(r.length===0)return{signal:t.signal,cleanup:()=>{}};if(r.some(o=>o.aborted))return t.abort(),{signal:t.signal,cleanup:()=>{}};let n=[];for(let o of r){let s=()=>t.abort();o.addEventListener("abort",s,{once:!0}),n.push({signal:o,abort:s})}return{signal:t.signal,cleanup:()=>{for(let o of n)o.signal.removeEventListener("abort",o.abort)}}}function _e(e,t){if(!t||t.type==="none"||e<=0)return e;switch(t.type){case"full":{let r=Number(t.ratio)/100,n=Math.max(0,Number(e)*(1-r)),o=Number(e);return n+Math.random()*(o-n)}case"equal":{let r=Number(t.ratio)/100,n=Number(e)*r/2;return Number(e)-n+Math.random()*n}case"custom":return t.calculate(e);default:return t}}var N=M(),ce=N.run,le=N.runOrThrow,de=N.orThrow,ye=N.all,pe=N.allOrThrow;0&&(module.exports={RetryStrategies,TypedError,all,allOrThrow,asMilliseconds,asRetryCount,errorRule,orThrow,run,runOrThrow,tryo});
|
package/dist/index.d.cts
CHANGED
|
@@ -16,16 +16,17 @@ declare const asRetryCount: (n: number) => RetryCount;
|
|
|
16
16
|
* Provides type-safe error handling with fluent API and metadata support
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
type DefaultErrorMeta = Record<string, unknown>;
|
|
20
|
+
declare abstract class TypedError<Code extends string = string, Meta extends object = DefaultErrorMeta, Raw = unknown> extends Error {
|
|
20
21
|
abstract readonly code: Code;
|
|
21
|
-
|
|
22
|
+
cause?: unknown;
|
|
22
23
|
readonly title?: string;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
meta: Meta;
|
|
25
|
+
status?: number;
|
|
26
|
+
raw?: Raw;
|
|
27
|
+
path?: string;
|
|
27
28
|
readonly timestamp: number;
|
|
28
|
-
|
|
29
|
+
retryable: boolean;
|
|
29
30
|
constructor(message: string, opts: {
|
|
30
31
|
title?: string;
|
|
31
32
|
cause?: unknown;
|
|
@@ -35,10 +36,10 @@ declare abstract class TypedError<Code extends string = string, Meta extends Rec
|
|
|
35
36
|
raw?: Raw;
|
|
36
37
|
path?: string;
|
|
37
38
|
});
|
|
38
|
-
is<C extends string>(code: C): this is TypedError<C> & {
|
|
39
|
+
is<C extends string>(code: C): this is TypedError<C, Meta, Raw> & {
|
|
39
40
|
code: C;
|
|
40
41
|
};
|
|
41
|
-
withMeta<const M>(meta: M): this & {
|
|
42
|
+
withMeta<const M extends object>(meta: M): this & {
|
|
42
43
|
meta: M;
|
|
43
44
|
};
|
|
44
45
|
withStatus(status: number): this & {
|
|
@@ -54,42 +55,42 @@ declare abstract class TypedError<Code extends string = string, Meta extends Rec
|
|
|
54
55
|
withRetryable(retryable: boolean): this;
|
|
55
56
|
toJSON(): Record<string, unknown>;
|
|
56
57
|
}
|
|
57
|
-
type AnyTypedError = TypedError
|
|
58
|
-
declare class TimeoutError extends TypedError<'TIMEOUT'
|
|
58
|
+
type AnyTypedError = TypedError;
|
|
59
|
+
declare class TimeoutError extends TypedError<'TIMEOUT'> {
|
|
59
60
|
readonly code: "TIMEOUT";
|
|
60
61
|
constructor(timeout: Milliseconds, cause?: unknown);
|
|
61
62
|
}
|
|
62
|
-
declare class AbortedError extends TypedError<'ABORTED'
|
|
63
|
+
declare class AbortedError extends TypedError<'ABORTED'> {
|
|
63
64
|
readonly code: "ABORTED";
|
|
64
65
|
constructor(reason?: string, cause?: unknown);
|
|
65
66
|
}
|
|
66
|
-
declare class CircuitOpenError extends TypedError<'CIRCUIT_OPEN'
|
|
67
|
+
declare class CircuitOpenError extends TypedError<'CIRCUIT_OPEN'> {
|
|
67
68
|
readonly code: "CIRCUIT_OPEN";
|
|
68
69
|
constructor(resetAfter: Milliseconds, cause?: unknown);
|
|
69
70
|
}
|
|
70
|
-
type ValidationMeta =
|
|
71
|
+
type ValidationMeta = {
|
|
71
72
|
validationErrors: unknown[];
|
|
72
73
|
};
|
|
73
|
-
declare class ValidationError extends TypedError<'VALIDATION', ValidationMeta
|
|
74
|
+
declare class ValidationError extends TypedError<'VALIDATION', ValidationMeta> {
|
|
74
75
|
readonly validationErrors: unknown[];
|
|
75
76
|
readonly code: "VALIDATION";
|
|
76
77
|
constructor(message: string, validationErrors: unknown[], cause?: unknown);
|
|
77
78
|
}
|
|
78
|
-
declare class NetworkError extends TypedError<'NETWORK'
|
|
79
|
+
declare class NetworkError extends TypedError<'NETWORK'> {
|
|
79
80
|
readonly statusCode?: number | undefined;
|
|
80
81
|
readonly code: "NETWORK";
|
|
81
82
|
constructor(message: string, statusCode?: number | undefined, cause?: unknown);
|
|
82
83
|
}
|
|
83
|
-
type HttpMeta =
|
|
84
|
+
type HttpMeta = {
|
|
84
85
|
response?: unknown;
|
|
85
86
|
};
|
|
86
|
-
declare class HttpError extends TypedError<'HTTP', HttpMeta
|
|
87
|
+
declare class HttpError extends TypedError<'HTTP', HttpMeta> {
|
|
87
88
|
readonly status: number;
|
|
88
89
|
readonly response?: unknown | undefined;
|
|
89
90
|
readonly code: "HTTP";
|
|
90
91
|
constructor(message: string, status: number, response?: unknown | undefined, cause?: unknown);
|
|
91
92
|
}
|
|
92
|
-
declare class UnknownError extends TypedError<'UNKNOWN'
|
|
93
|
+
declare class UnknownError extends TypedError<'UNKNOWN'> {
|
|
93
94
|
readonly code: "UNKNOWN";
|
|
94
95
|
constructor(message: string, cause?: unknown);
|
|
95
96
|
}
|
|
@@ -111,6 +112,46 @@ interface CircuitBreakerConfig<E extends AnyTypedError = AnyTypedError> {
|
|
|
111
112
|
}
|
|
112
113
|
type CircuitState = 'closed' | 'open' | 'half-open';
|
|
113
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Modern error normalization system
|
|
117
|
+
* Provides type-safe error transformation and normalization
|
|
118
|
+
*/
|
|
119
|
+
|
|
120
|
+
type ErrorNormalizer<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E;
|
|
121
|
+
type ErrorRule<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E | null;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Modern retry strategies with enhanced capabilities
|
|
125
|
+
* Provides various retry patterns with type safety
|
|
126
|
+
*/
|
|
127
|
+
|
|
128
|
+
type RetryStrategy = FixedDelayStrategy | ExponentialBackoffStrategy | FibonacciBackoffStrategy | CustomDelayStrategy;
|
|
129
|
+
interface FixedDelayStrategy {
|
|
130
|
+
readonly type: 'fixed';
|
|
131
|
+
readonly delay: number;
|
|
132
|
+
}
|
|
133
|
+
interface ExponentialBackoffStrategy {
|
|
134
|
+
readonly type: 'exponential';
|
|
135
|
+
readonly base: number;
|
|
136
|
+
readonly factor: number;
|
|
137
|
+
readonly maxDelay?: number;
|
|
138
|
+
}
|
|
139
|
+
interface FibonacciBackoffStrategy {
|
|
140
|
+
readonly type: 'fibonacci';
|
|
141
|
+
readonly base: number;
|
|
142
|
+
readonly maxDelay?: number;
|
|
143
|
+
}
|
|
144
|
+
interface CustomDelayStrategy {
|
|
145
|
+
readonly type: 'custom';
|
|
146
|
+
readonly calculate: (attempt: RetryCount, error: unknown) => number;
|
|
147
|
+
}
|
|
148
|
+
declare const RetryStrategies: {
|
|
149
|
+
readonly fixed: (delay: number) => FixedDelayStrategy;
|
|
150
|
+
readonly exponential: (base: number, factor?: number, maxDelay?: number) => ExponentialBackoffStrategy;
|
|
151
|
+
readonly fibonacci: (base: number, maxDelay?: number) => FibonacciBackoffStrategy;
|
|
152
|
+
readonly custom: (calculate: (attempt: RetryCount, error: unknown) => number) => CustomDelayStrategy;
|
|
153
|
+
};
|
|
154
|
+
|
|
114
155
|
/**
|
|
115
156
|
* Modern result types with enhanced discriminated unions
|
|
116
157
|
* Provides better type safety and more granular result categorization
|
|
@@ -122,30 +163,30 @@ interface SuccessResult<T, E extends AnyTypedError> {
|
|
|
122
163
|
readonly ok: true;
|
|
123
164
|
readonly data: T;
|
|
124
165
|
readonly error: null;
|
|
125
|
-
readonly metrics: TryoMetrics
|
|
166
|
+
readonly metrics: TryoMetrics<E>;
|
|
126
167
|
}
|
|
127
168
|
interface FailureResult<E extends AnyTypedError> {
|
|
128
169
|
readonly type: 'failure';
|
|
129
170
|
readonly ok: false;
|
|
130
171
|
readonly data: null;
|
|
131
172
|
readonly error: E;
|
|
132
|
-
readonly metrics: TryoMetrics
|
|
173
|
+
readonly metrics: TryoMetrics<E>;
|
|
133
174
|
}
|
|
134
175
|
interface AbortedResult<E extends AnyTypedError> {
|
|
135
176
|
readonly type: 'aborted';
|
|
136
177
|
readonly ok: false;
|
|
137
178
|
readonly data: null;
|
|
138
179
|
readonly error: E;
|
|
139
|
-
readonly metrics: TryoMetrics
|
|
180
|
+
readonly metrics: TryoMetrics<E>;
|
|
140
181
|
}
|
|
141
182
|
interface TimeoutResult<E extends AnyTypedError> {
|
|
142
183
|
readonly type: 'timeout';
|
|
143
184
|
readonly ok: false;
|
|
144
185
|
readonly data: null;
|
|
145
186
|
readonly error: E;
|
|
146
|
-
readonly metrics: TryoMetrics
|
|
187
|
+
readonly metrics: TryoMetrics<E>;
|
|
147
188
|
}
|
|
148
|
-
interface TryoMetrics
|
|
189
|
+
interface TryoMetrics<E extends AnyTypedError> {
|
|
149
190
|
readonly totalAttempts: RetryCount;
|
|
150
191
|
readonly totalRetries: RetryCount;
|
|
151
192
|
readonly totalDuration: Milliseconds;
|
|
@@ -159,45 +200,10 @@ interface TryoMetrics$1<E extends AnyTypedError> {
|
|
|
159
200
|
}
|
|
160
201
|
|
|
161
202
|
/**
|
|
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
|
|
203
|
+
* Configuration types for modern execution engine
|
|
204
|
+
* Provides comprehensive configuration with type safety
|
|
172
205
|
*/
|
|
173
206
|
|
|
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
207
|
interface TryoConfig<E extends AnyTypedError = AnyTypedError> {
|
|
202
208
|
/** Abort signal passed to tasks */
|
|
203
209
|
readonly signal?: AbortSignal;
|
|
@@ -265,7 +271,6 @@ interface LoggerConfig<E extends AnyTypedError> {
|
|
|
265
271
|
/** Warning logging function */
|
|
266
272
|
readonly warn?: (message: string, meta?: unknown) => void;
|
|
267
273
|
}
|
|
268
|
-
type TryoMetrics<E extends AnyTypedError> = TryoMetrics$1<E>;
|
|
269
274
|
type JitterConfig = {
|
|
270
275
|
type: 'none';
|
|
271
276
|
} | {
|
|
@@ -287,10 +292,17 @@ declare const JitterConfig: {
|
|
|
287
292
|
|
|
288
293
|
type RulesMode = 'extend' | 'replace';
|
|
289
294
|
type DefaultError = AbortedError | TimeoutError | NetworkError | HttpError | CircuitOpenError | ValidationError | UnknownError;
|
|
290
|
-
type RunOptions<E extends AnyTypedError> = Omit<Partial<TryoConfig<E>>, 'circuitBreaker'
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
295
|
+
type RunOptions<E extends AnyTypedError, TData = unknown> = Omit<Partial<TryoConfig<E>>, 'circuitBreaker' | 'onSuccess'> & {
|
|
296
|
+
onSuccess?: (data: TData, metrics?: TryoMetrics<E>) => void;
|
|
297
|
+
};
|
|
298
|
+
type AllOptions<E extends AnyTypedError, TData = unknown> = RunOptions<E, TData>;
|
|
299
|
+
type PartitionedResults<T, E extends AnyTypedError> = {
|
|
300
|
+
ok: Array<SuccessResult<T, E>>;
|
|
301
|
+
errors: Array<FailureResult<E> | AbortedResult<E> | TimeoutResult<E>>;
|
|
302
|
+
failure: Array<FailureResult<E>>;
|
|
303
|
+
aborted: Array<AbortedResult<E>>;
|
|
304
|
+
timeout: Array<TimeoutResult<E>>;
|
|
305
|
+
};
|
|
294
306
|
type MaybePromise<T> = T | Promise<T>;
|
|
295
307
|
type RuleLike = (error: unknown) => AnyTypedError | null;
|
|
296
308
|
type NonNull<T> = T extends null ? never : T;
|
|
@@ -325,114 +337,48 @@ declare function tryo<E extends AnyTypedError = DefaultError>(options?: TryoOpti
|
|
|
325
337
|
type Tryo<E extends AnyTypedError = AnyTypedError> = {
|
|
326
338
|
run: <T>(task: (ctx: {
|
|
327
339
|
signal: AbortSignal;
|
|
328
|
-
}) => MaybePromise<T>, options?: RunOptions<E>) => Promise<TryoResult<T, E>>;
|
|
340
|
+
}) => MaybePromise<T>, options?: RunOptions<E, T>) => Promise<TryoResult<T, E>>;
|
|
329
341
|
runOrThrow: <T>(task: (ctx: {
|
|
330
342
|
signal: AbortSignal;
|
|
331
|
-
}) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
|
|
343
|
+
}) => MaybePromise<T>, options?: RunOptions<E, T>) => Promise<T>;
|
|
332
344
|
orThrow: <T>(task: (ctx: {
|
|
333
345
|
signal: AbortSignal;
|
|
334
|
-
}) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
|
|
346
|
+
}) => MaybePromise<T>, options?: RunOptions<E, T>) => Promise<T>;
|
|
335
347
|
all: <T>(tasks: Array<(ctx: {
|
|
336
348
|
signal: AbortSignal;
|
|
337
|
-
}) => MaybePromise<T>>, options?: AllOptions<E>) => Promise<Array<TryoResult<T, E>>>;
|
|
349
|
+
}) => MaybePromise<T>>, options?: AllOptions<E, T>) => Promise<Array<TryoResult<T, E>>>;
|
|
338
350
|
allOrThrow: <T>(tasks: Array<(ctx: {
|
|
339
351
|
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
|
-
};
|
|
352
|
+
}) => MaybePromise<T>>, options?: AllOptions<E, T>) => Promise<T[]>;
|
|
353
|
+
partitionAll: <T>(results: Array<TryoResult<T, E>>) => PartitionedResults<T, E>;
|
|
348
354
|
withConfig: (additionalConfig: Omit<Partial<TryoConfig<E>>, 'signal'>) => Tryo<E>;
|
|
349
355
|
};
|
|
350
356
|
|
|
351
357
|
declare const run: <T>(task: (ctx: {
|
|
352
358
|
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>>;
|
|
359
|
+
}) => T | Promise<T>, options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
360
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
361
|
+
}) | undefined) => Promise<TryoResult<T, DefaultError>>;
|
|
368
362
|
declare const runOrThrow: <T>(task: (ctx: {
|
|
369
363
|
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>;
|
|
364
|
+
}) => T | Promise<T>, options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
365
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
366
|
+
}) | undefined) => Promise<T>;
|
|
385
367
|
declare const orThrow: <T>(task: (ctx: {
|
|
386
368
|
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>;
|
|
369
|
+
}) => T | Promise<T>, options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
370
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
371
|
+
}) | undefined) => Promise<T>;
|
|
402
372
|
declare const all: <T>(tasks: ((ctx: {
|
|
403
373
|
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>[]>;
|
|
374
|
+
}) => T | Promise<T>)[], options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
375
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
376
|
+
}) | undefined) => Promise<TryoResult<T, DefaultError>[]>;
|
|
419
377
|
declare const allOrThrow: <T>(tasks: ((ctx: {
|
|
420
378
|
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[]>;
|
|
379
|
+
}) => T | Promise<T>)[], options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
380
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
381
|
+
}) | undefined) => Promise<T[]>;
|
|
436
382
|
|
|
437
383
|
/**
|
|
438
384
|
* Modern fluent error rule builder
|
|
@@ -463,18 +409,24 @@ interface MapperResponse {
|
|
|
463
409
|
path?: string;
|
|
464
410
|
}
|
|
465
411
|
type Strict<T, Shape> = T & Record<Exclude<keyof T, keyof Shape>, never>;
|
|
466
|
-
type
|
|
412
|
+
type ResolvedMeta<TMeta> = TMeta extends Record<string, unknown> ? TMeta : Record<string, unknown>;
|
|
413
|
+
type ResolvedRaw<Out extends {
|
|
414
|
+
raw?: unknown;
|
|
415
|
+
}> = Out extends {
|
|
416
|
+
raw: infer TRaw;
|
|
417
|
+
} ? TRaw : unknown;
|
|
418
|
+
type MappedTypedError<Out extends ErrorResponse> = TypedError<Out['code'], ResolvedMeta<Out['meta']>, ResolvedRaw<Out>>;
|
|
467
419
|
declare class ErrorRuleBuilder<T> {
|
|
468
420
|
private readonly predicate;
|
|
469
421
|
constructor(predicate: (err: unknown) => err is T);
|
|
470
422
|
toCode<const C extends string>(code: C): ErrorMapper<T, C>;
|
|
471
|
-
toError<const Out extends ErrorResponse>(mapper: (err: T) => Strict<Out, ErrorResponse>): ErrorRule<MappedTypedError<Out
|
|
423
|
+
toError<const Out extends ErrorResponse>(mapper: (err: T) => Strict<Out, ErrorResponse>): ErrorRule<MappedTypedError<Out>>;
|
|
472
424
|
}
|
|
473
425
|
declare class ErrorMapper<T, C extends string> {
|
|
474
426
|
private readonly predicate;
|
|
475
427
|
private readonly errorCode;
|
|
476
428
|
constructor(predicate: (err: unknown) => err is T, errorCode: C);
|
|
477
|
-
with<const Out extends MapperResponse>(mapper: (err: T) => Strict<Out, ErrorResponse>): ErrorRule<TypedError<C,
|
|
429
|
+
with<const Out extends MapperResponse>(mapper: (err: T) => Strict<Out, ErrorResponse>): ErrorRule<TypedError<C, ResolvedMeta<Out['meta']>, ResolvedRaw<Out>>>;
|
|
478
430
|
}
|
|
479
431
|
|
|
480
432
|
declare const errorRule: {
|
|
@@ -491,10 +443,14 @@ declare const errorRule: {
|
|
|
491
443
|
readonly cause?: unknown;
|
|
492
444
|
} ? ErrorRule<AnyTypedError> & {
|
|
493
445
|
toCode: <const C extends string>(code: C) => ErrorMapper<InstanceType<T>, C>;
|
|
494
|
-
toError: <const Out extends ErrorResponse>(mapper: (err: InstanceType<T>) => Out & Record<Exclude<keyof Out, keyof ErrorResponse>, never>) => ErrorRule<TypedError<Out["code"], Out["meta"] extends
|
|
446
|
+
toError: <const Out extends ErrorResponse>(mapper: (err: InstanceType<T>) => Out & Record<Exclude<keyof Out, keyof ErrorResponse>, never>) => ErrorRule<TypedError<Out["code"], Out["meta"] extends infer T_1 ? T_1 extends Out["meta"] ? T_1 extends Record<string, unknown> ? T_1 : Record<string, unknown> : never : never, Out extends {
|
|
447
|
+
raw: infer TRaw;
|
|
448
|
+
} ? TRaw : unknown>>;
|
|
495
449
|
} : ErrorRuleBuilder<InstanceType<T>>;
|
|
496
|
-
<T extends abstract new (...args: never[]) => unknown, const Out extends ErrorResponse>(ErrorClass: T, mapper: (err: InstanceType<T>) => Out & Record<Exclude<keyof Out, keyof ErrorResponse>, never>): ErrorRule<TypedError<Out["code"], Out["meta"] extends
|
|
450
|
+
<T extends abstract new (...args: never[]) => unknown, const Out extends ErrorResponse>(ErrorClass: T, mapper: (err: InstanceType<T>) => Out & Record<Exclude<keyof Out, keyof ErrorResponse>, never>): ErrorRule<TypedError<Out["code"], Out["meta"] extends infer T_1 ? T_1 extends Out["meta"] ? T_1 extends Record<string, unknown> ? T_1 : Record<string, unknown> : never : never, Out extends {
|
|
451
|
+
raw: infer TRaw;
|
|
452
|
+
} ? TRaw : unknown>>;
|
|
497
453
|
};
|
|
498
454
|
};
|
|
499
455
|
|
|
500
|
-
export { type AbortedResult, type FailureResult, type Milliseconds, type RetryCount, RetryStrategies, type RulesMode, type SuccessResult, type TimeoutResult, type TryoConfig, type TryoMetrics
|
|
456
|
+
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
|
@@ -16,16 +16,17 @@ declare const asRetryCount: (n: number) => RetryCount;
|
|
|
16
16
|
* Provides type-safe error handling with fluent API and metadata support
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
type DefaultErrorMeta = Record<string, unknown>;
|
|
20
|
+
declare abstract class TypedError<Code extends string = string, Meta extends object = DefaultErrorMeta, Raw = unknown> extends Error {
|
|
20
21
|
abstract readonly code: Code;
|
|
21
|
-
|
|
22
|
+
cause?: unknown;
|
|
22
23
|
readonly title?: string;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
meta: Meta;
|
|
25
|
+
status?: number;
|
|
26
|
+
raw?: Raw;
|
|
27
|
+
path?: string;
|
|
27
28
|
readonly timestamp: number;
|
|
28
|
-
|
|
29
|
+
retryable: boolean;
|
|
29
30
|
constructor(message: string, opts: {
|
|
30
31
|
title?: string;
|
|
31
32
|
cause?: unknown;
|
|
@@ -35,10 +36,10 @@ declare abstract class TypedError<Code extends string = string, Meta extends Rec
|
|
|
35
36
|
raw?: Raw;
|
|
36
37
|
path?: string;
|
|
37
38
|
});
|
|
38
|
-
is<C extends string>(code: C): this is TypedError<C> & {
|
|
39
|
+
is<C extends string>(code: C): this is TypedError<C, Meta, Raw> & {
|
|
39
40
|
code: C;
|
|
40
41
|
};
|
|
41
|
-
withMeta<const M>(meta: M): this & {
|
|
42
|
+
withMeta<const M extends object>(meta: M): this & {
|
|
42
43
|
meta: M;
|
|
43
44
|
};
|
|
44
45
|
withStatus(status: number): this & {
|
|
@@ -54,42 +55,42 @@ declare abstract class TypedError<Code extends string = string, Meta extends Rec
|
|
|
54
55
|
withRetryable(retryable: boolean): this;
|
|
55
56
|
toJSON(): Record<string, unknown>;
|
|
56
57
|
}
|
|
57
|
-
type AnyTypedError = TypedError
|
|
58
|
-
declare class TimeoutError extends TypedError<'TIMEOUT'
|
|
58
|
+
type AnyTypedError = TypedError;
|
|
59
|
+
declare class TimeoutError extends TypedError<'TIMEOUT'> {
|
|
59
60
|
readonly code: "TIMEOUT";
|
|
60
61
|
constructor(timeout: Milliseconds, cause?: unknown);
|
|
61
62
|
}
|
|
62
|
-
declare class AbortedError extends TypedError<'ABORTED'
|
|
63
|
+
declare class AbortedError extends TypedError<'ABORTED'> {
|
|
63
64
|
readonly code: "ABORTED";
|
|
64
65
|
constructor(reason?: string, cause?: unknown);
|
|
65
66
|
}
|
|
66
|
-
declare class CircuitOpenError extends TypedError<'CIRCUIT_OPEN'
|
|
67
|
+
declare class CircuitOpenError extends TypedError<'CIRCUIT_OPEN'> {
|
|
67
68
|
readonly code: "CIRCUIT_OPEN";
|
|
68
69
|
constructor(resetAfter: Milliseconds, cause?: unknown);
|
|
69
70
|
}
|
|
70
|
-
type ValidationMeta =
|
|
71
|
+
type ValidationMeta = {
|
|
71
72
|
validationErrors: unknown[];
|
|
72
73
|
};
|
|
73
|
-
declare class ValidationError extends TypedError<'VALIDATION', ValidationMeta
|
|
74
|
+
declare class ValidationError extends TypedError<'VALIDATION', ValidationMeta> {
|
|
74
75
|
readonly validationErrors: unknown[];
|
|
75
76
|
readonly code: "VALIDATION";
|
|
76
77
|
constructor(message: string, validationErrors: unknown[], cause?: unknown);
|
|
77
78
|
}
|
|
78
|
-
declare class NetworkError extends TypedError<'NETWORK'
|
|
79
|
+
declare class NetworkError extends TypedError<'NETWORK'> {
|
|
79
80
|
readonly statusCode?: number | undefined;
|
|
80
81
|
readonly code: "NETWORK";
|
|
81
82
|
constructor(message: string, statusCode?: number | undefined, cause?: unknown);
|
|
82
83
|
}
|
|
83
|
-
type HttpMeta =
|
|
84
|
+
type HttpMeta = {
|
|
84
85
|
response?: unknown;
|
|
85
86
|
};
|
|
86
|
-
declare class HttpError extends TypedError<'HTTP', HttpMeta
|
|
87
|
+
declare class HttpError extends TypedError<'HTTP', HttpMeta> {
|
|
87
88
|
readonly status: number;
|
|
88
89
|
readonly response?: unknown | undefined;
|
|
89
90
|
readonly code: "HTTP";
|
|
90
91
|
constructor(message: string, status: number, response?: unknown | undefined, cause?: unknown);
|
|
91
92
|
}
|
|
92
|
-
declare class UnknownError extends TypedError<'UNKNOWN'
|
|
93
|
+
declare class UnknownError extends TypedError<'UNKNOWN'> {
|
|
93
94
|
readonly code: "UNKNOWN";
|
|
94
95
|
constructor(message: string, cause?: unknown);
|
|
95
96
|
}
|
|
@@ -111,6 +112,46 @@ interface CircuitBreakerConfig<E extends AnyTypedError = AnyTypedError> {
|
|
|
111
112
|
}
|
|
112
113
|
type CircuitState = 'closed' | 'open' | 'half-open';
|
|
113
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Modern error normalization system
|
|
117
|
+
* Provides type-safe error transformation and normalization
|
|
118
|
+
*/
|
|
119
|
+
|
|
120
|
+
type ErrorNormalizer<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E;
|
|
121
|
+
type ErrorRule<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E | null;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Modern retry strategies with enhanced capabilities
|
|
125
|
+
* Provides various retry patterns with type safety
|
|
126
|
+
*/
|
|
127
|
+
|
|
128
|
+
type RetryStrategy = FixedDelayStrategy | ExponentialBackoffStrategy | FibonacciBackoffStrategy | CustomDelayStrategy;
|
|
129
|
+
interface FixedDelayStrategy {
|
|
130
|
+
readonly type: 'fixed';
|
|
131
|
+
readonly delay: number;
|
|
132
|
+
}
|
|
133
|
+
interface ExponentialBackoffStrategy {
|
|
134
|
+
readonly type: 'exponential';
|
|
135
|
+
readonly base: number;
|
|
136
|
+
readonly factor: number;
|
|
137
|
+
readonly maxDelay?: number;
|
|
138
|
+
}
|
|
139
|
+
interface FibonacciBackoffStrategy {
|
|
140
|
+
readonly type: 'fibonacci';
|
|
141
|
+
readonly base: number;
|
|
142
|
+
readonly maxDelay?: number;
|
|
143
|
+
}
|
|
144
|
+
interface CustomDelayStrategy {
|
|
145
|
+
readonly type: 'custom';
|
|
146
|
+
readonly calculate: (attempt: RetryCount, error: unknown) => number;
|
|
147
|
+
}
|
|
148
|
+
declare const RetryStrategies: {
|
|
149
|
+
readonly fixed: (delay: number) => FixedDelayStrategy;
|
|
150
|
+
readonly exponential: (base: number, factor?: number, maxDelay?: number) => ExponentialBackoffStrategy;
|
|
151
|
+
readonly fibonacci: (base: number, maxDelay?: number) => FibonacciBackoffStrategy;
|
|
152
|
+
readonly custom: (calculate: (attempt: RetryCount, error: unknown) => number) => CustomDelayStrategy;
|
|
153
|
+
};
|
|
154
|
+
|
|
114
155
|
/**
|
|
115
156
|
* Modern result types with enhanced discriminated unions
|
|
116
157
|
* Provides better type safety and more granular result categorization
|
|
@@ -122,30 +163,30 @@ interface SuccessResult<T, E extends AnyTypedError> {
|
|
|
122
163
|
readonly ok: true;
|
|
123
164
|
readonly data: T;
|
|
124
165
|
readonly error: null;
|
|
125
|
-
readonly metrics: TryoMetrics
|
|
166
|
+
readonly metrics: TryoMetrics<E>;
|
|
126
167
|
}
|
|
127
168
|
interface FailureResult<E extends AnyTypedError> {
|
|
128
169
|
readonly type: 'failure';
|
|
129
170
|
readonly ok: false;
|
|
130
171
|
readonly data: null;
|
|
131
172
|
readonly error: E;
|
|
132
|
-
readonly metrics: TryoMetrics
|
|
173
|
+
readonly metrics: TryoMetrics<E>;
|
|
133
174
|
}
|
|
134
175
|
interface AbortedResult<E extends AnyTypedError> {
|
|
135
176
|
readonly type: 'aborted';
|
|
136
177
|
readonly ok: false;
|
|
137
178
|
readonly data: null;
|
|
138
179
|
readonly error: E;
|
|
139
|
-
readonly metrics: TryoMetrics
|
|
180
|
+
readonly metrics: TryoMetrics<E>;
|
|
140
181
|
}
|
|
141
182
|
interface TimeoutResult<E extends AnyTypedError> {
|
|
142
183
|
readonly type: 'timeout';
|
|
143
184
|
readonly ok: false;
|
|
144
185
|
readonly data: null;
|
|
145
186
|
readonly error: E;
|
|
146
|
-
readonly metrics: TryoMetrics
|
|
187
|
+
readonly metrics: TryoMetrics<E>;
|
|
147
188
|
}
|
|
148
|
-
interface TryoMetrics
|
|
189
|
+
interface TryoMetrics<E extends AnyTypedError> {
|
|
149
190
|
readonly totalAttempts: RetryCount;
|
|
150
191
|
readonly totalRetries: RetryCount;
|
|
151
192
|
readonly totalDuration: Milliseconds;
|
|
@@ -159,45 +200,10 @@ interface TryoMetrics$1<E extends AnyTypedError> {
|
|
|
159
200
|
}
|
|
160
201
|
|
|
161
202
|
/**
|
|
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
|
|
203
|
+
* Configuration types for modern execution engine
|
|
204
|
+
* Provides comprehensive configuration with type safety
|
|
172
205
|
*/
|
|
173
206
|
|
|
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
207
|
interface TryoConfig<E extends AnyTypedError = AnyTypedError> {
|
|
202
208
|
/** Abort signal passed to tasks */
|
|
203
209
|
readonly signal?: AbortSignal;
|
|
@@ -265,7 +271,6 @@ interface LoggerConfig<E extends AnyTypedError> {
|
|
|
265
271
|
/** Warning logging function */
|
|
266
272
|
readonly warn?: (message: string, meta?: unknown) => void;
|
|
267
273
|
}
|
|
268
|
-
type TryoMetrics<E extends AnyTypedError> = TryoMetrics$1<E>;
|
|
269
274
|
type JitterConfig = {
|
|
270
275
|
type: 'none';
|
|
271
276
|
} | {
|
|
@@ -287,10 +292,17 @@ declare const JitterConfig: {
|
|
|
287
292
|
|
|
288
293
|
type RulesMode = 'extend' | 'replace';
|
|
289
294
|
type DefaultError = AbortedError | TimeoutError | NetworkError | HttpError | CircuitOpenError | ValidationError | UnknownError;
|
|
290
|
-
type RunOptions<E extends AnyTypedError> = Omit<Partial<TryoConfig<E>>, 'circuitBreaker'
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
295
|
+
type RunOptions<E extends AnyTypedError, TData = unknown> = Omit<Partial<TryoConfig<E>>, 'circuitBreaker' | 'onSuccess'> & {
|
|
296
|
+
onSuccess?: (data: TData, metrics?: TryoMetrics<E>) => void;
|
|
297
|
+
};
|
|
298
|
+
type AllOptions<E extends AnyTypedError, TData = unknown> = RunOptions<E, TData>;
|
|
299
|
+
type PartitionedResults<T, E extends AnyTypedError> = {
|
|
300
|
+
ok: Array<SuccessResult<T, E>>;
|
|
301
|
+
errors: Array<FailureResult<E> | AbortedResult<E> | TimeoutResult<E>>;
|
|
302
|
+
failure: Array<FailureResult<E>>;
|
|
303
|
+
aborted: Array<AbortedResult<E>>;
|
|
304
|
+
timeout: Array<TimeoutResult<E>>;
|
|
305
|
+
};
|
|
294
306
|
type MaybePromise<T> = T | Promise<T>;
|
|
295
307
|
type RuleLike = (error: unknown) => AnyTypedError | null;
|
|
296
308
|
type NonNull<T> = T extends null ? never : T;
|
|
@@ -325,114 +337,48 @@ declare function tryo<E extends AnyTypedError = DefaultError>(options?: TryoOpti
|
|
|
325
337
|
type Tryo<E extends AnyTypedError = AnyTypedError> = {
|
|
326
338
|
run: <T>(task: (ctx: {
|
|
327
339
|
signal: AbortSignal;
|
|
328
|
-
}) => MaybePromise<T>, options?: RunOptions<E>) => Promise<TryoResult<T, E>>;
|
|
340
|
+
}) => MaybePromise<T>, options?: RunOptions<E, T>) => Promise<TryoResult<T, E>>;
|
|
329
341
|
runOrThrow: <T>(task: (ctx: {
|
|
330
342
|
signal: AbortSignal;
|
|
331
|
-
}) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
|
|
343
|
+
}) => MaybePromise<T>, options?: RunOptions<E, T>) => Promise<T>;
|
|
332
344
|
orThrow: <T>(task: (ctx: {
|
|
333
345
|
signal: AbortSignal;
|
|
334
|
-
}) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
|
|
346
|
+
}) => MaybePromise<T>, options?: RunOptions<E, T>) => Promise<T>;
|
|
335
347
|
all: <T>(tasks: Array<(ctx: {
|
|
336
348
|
signal: AbortSignal;
|
|
337
|
-
}) => MaybePromise<T>>, options?: AllOptions<E>) => Promise<Array<TryoResult<T, E>>>;
|
|
349
|
+
}) => MaybePromise<T>>, options?: AllOptions<E, T>) => Promise<Array<TryoResult<T, E>>>;
|
|
338
350
|
allOrThrow: <T>(tasks: Array<(ctx: {
|
|
339
351
|
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
|
-
};
|
|
352
|
+
}) => MaybePromise<T>>, options?: AllOptions<E, T>) => Promise<T[]>;
|
|
353
|
+
partitionAll: <T>(results: Array<TryoResult<T, E>>) => PartitionedResults<T, E>;
|
|
348
354
|
withConfig: (additionalConfig: Omit<Partial<TryoConfig<E>>, 'signal'>) => Tryo<E>;
|
|
349
355
|
};
|
|
350
356
|
|
|
351
357
|
declare const run: <T>(task: (ctx: {
|
|
352
358
|
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>>;
|
|
359
|
+
}) => T | Promise<T>, options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
360
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
361
|
+
}) | undefined) => Promise<TryoResult<T, DefaultError>>;
|
|
368
362
|
declare const runOrThrow: <T>(task: (ctx: {
|
|
369
363
|
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>;
|
|
364
|
+
}) => T | Promise<T>, options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
365
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
366
|
+
}) | undefined) => Promise<T>;
|
|
385
367
|
declare const orThrow: <T>(task: (ctx: {
|
|
386
368
|
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>;
|
|
369
|
+
}) => T | Promise<T>, options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
370
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
371
|
+
}) | undefined) => Promise<T>;
|
|
402
372
|
declare const all: <T>(tasks: ((ctx: {
|
|
403
373
|
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>[]>;
|
|
374
|
+
}) => T | Promise<T>)[], options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
375
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
376
|
+
}) | undefined) => Promise<TryoResult<T, DefaultError>[]>;
|
|
419
377
|
declare const allOrThrow: <T>(tasks: ((ctx: {
|
|
420
378
|
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[]>;
|
|
379
|
+
}) => T | Promise<T>)[], options?: (Omit<Partial<TryoConfig<DefaultError>>, "circuitBreaker" | "onSuccess"> & {
|
|
380
|
+
onSuccess?: ((data: T, metrics?: TryoMetrics<DefaultError> | undefined) => void) | undefined;
|
|
381
|
+
}) | undefined) => Promise<T[]>;
|
|
436
382
|
|
|
437
383
|
/**
|
|
438
384
|
* Modern fluent error rule builder
|
|
@@ -463,18 +409,24 @@ interface MapperResponse {
|
|
|
463
409
|
path?: string;
|
|
464
410
|
}
|
|
465
411
|
type Strict<T, Shape> = T & Record<Exclude<keyof T, keyof Shape>, never>;
|
|
466
|
-
type
|
|
412
|
+
type ResolvedMeta<TMeta> = TMeta extends Record<string, unknown> ? TMeta : Record<string, unknown>;
|
|
413
|
+
type ResolvedRaw<Out extends {
|
|
414
|
+
raw?: unknown;
|
|
415
|
+
}> = Out extends {
|
|
416
|
+
raw: infer TRaw;
|
|
417
|
+
} ? TRaw : unknown;
|
|
418
|
+
type MappedTypedError<Out extends ErrorResponse> = TypedError<Out['code'], ResolvedMeta<Out['meta']>, ResolvedRaw<Out>>;
|
|
467
419
|
declare class ErrorRuleBuilder<T> {
|
|
468
420
|
private readonly predicate;
|
|
469
421
|
constructor(predicate: (err: unknown) => err is T);
|
|
470
422
|
toCode<const C extends string>(code: C): ErrorMapper<T, C>;
|
|
471
|
-
toError<const Out extends ErrorResponse>(mapper: (err: T) => Strict<Out, ErrorResponse>): ErrorRule<MappedTypedError<Out
|
|
423
|
+
toError<const Out extends ErrorResponse>(mapper: (err: T) => Strict<Out, ErrorResponse>): ErrorRule<MappedTypedError<Out>>;
|
|
472
424
|
}
|
|
473
425
|
declare class ErrorMapper<T, C extends string> {
|
|
474
426
|
private readonly predicate;
|
|
475
427
|
private readonly errorCode;
|
|
476
428
|
constructor(predicate: (err: unknown) => err is T, errorCode: C);
|
|
477
|
-
with<const Out extends MapperResponse>(mapper: (err: T) => Strict<Out, ErrorResponse>): ErrorRule<TypedError<C,
|
|
429
|
+
with<const Out extends MapperResponse>(mapper: (err: T) => Strict<Out, ErrorResponse>): ErrorRule<TypedError<C, ResolvedMeta<Out['meta']>, ResolvedRaw<Out>>>;
|
|
478
430
|
}
|
|
479
431
|
|
|
480
432
|
declare const errorRule: {
|
|
@@ -491,10 +443,14 @@ declare const errorRule: {
|
|
|
491
443
|
readonly cause?: unknown;
|
|
492
444
|
} ? ErrorRule<AnyTypedError> & {
|
|
493
445
|
toCode: <const C extends string>(code: C) => ErrorMapper<InstanceType<T>, C>;
|
|
494
|
-
toError: <const Out extends ErrorResponse>(mapper: (err: InstanceType<T>) => Out & Record<Exclude<keyof Out, keyof ErrorResponse>, never>) => ErrorRule<TypedError<Out["code"], Out["meta"] extends
|
|
446
|
+
toError: <const Out extends ErrorResponse>(mapper: (err: InstanceType<T>) => Out & Record<Exclude<keyof Out, keyof ErrorResponse>, never>) => ErrorRule<TypedError<Out["code"], Out["meta"] extends infer T_1 ? T_1 extends Out["meta"] ? T_1 extends Record<string, unknown> ? T_1 : Record<string, unknown> : never : never, Out extends {
|
|
447
|
+
raw: infer TRaw;
|
|
448
|
+
} ? TRaw : unknown>>;
|
|
495
449
|
} : ErrorRuleBuilder<InstanceType<T>>;
|
|
496
|
-
<T extends abstract new (...args: never[]) => unknown, const Out extends ErrorResponse>(ErrorClass: T, mapper: (err: InstanceType<T>) => Out & Record<Exclude<keyof Out, keyof ErrorResponse>, never>): ErrorRule<TypedError<Out["code"], Out["meta"] extends
|
|
450
|
+
<T extends abstract new (...args: never[]) => unknown, const Out extends ErrorResponse>(ErrorClass: T, mapper: (err: InstanceType<T>) => Out & Record<Exclude<keyof Out, keyof ErrorResponse>, never>): ErrorRule<TypedError<Out["code"], Out["meta"] extends infer T_1 ? T_1 extends Out["meta"] ? T_1 extends Record<string, unknown> ? T_1 : Record<string, unknown> : never : never, Out extends {
|
|
451
|
+
raw: infer TRaw;
|
|
452
|
+
} ? TRaw : unknown>>;
|
|
497
453
|
};
|
|
498
454
|
};
|
|
499
455
|
|
|
500
|
-
export { type AbortedResult, type FailureResult, type Milliseconds, type RetryCount, RetryStrategies, type RulesMode, type SuccessResult, type TimeoutResult, type TryoConfig, type TryoMetrics
|
|
456
|
+
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,t,r)=>t in e?le(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var d=(e,t,r)=>de(e,typeof t!="symbol"?t+"":t,r);var E=class extends Error{constructor(r,n){var o,s;super(r);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(r){return this.code===r}withMeta(r){return this.meta=r,this}withStatus(r){return this.status=r,this}withCause(r){return this.cause=r,this}withPath(r){return this.path=r,this}withRaw(r){return this.raw=r,this}withRetryable(r){return this.retryable=r,this}toJSON(){return{name:this.name,code:this.code,title:this.title,message:this.message,meta:this.meta,status:this.status,timestamp:this.timestamp,retryable:this.retryable,cause:this.cause,raw:this.raw,path:this.path,stack:this.stack}}},P=class extends E{constructor(r,n){super(`Operation timed out after ${r}ms`,{cause:n,retryable:!0});d(this,"code","TIMEOUT")}};var F=class extends E{constructor(r,n){super(`Circuit breaker is open, reset after ${r}ms`,{cause:n,retryable:!1});d(this,"code","CIRCUIT_OPEN")}};var B=class extends E{constructor(r,n){super(r,{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(t){d(this,"state");d(this,"config");this.config={failureThreshold:C(t.failureThreshold),resetTimeout:b(t.resetTimeout),halfOpenRequests:C(t.halfOpenRequests),shouldCountAsFailure:t.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(t){var o,s,a;if(!((a=(s=(o=this.config).shouldCountAsFailure)==null?void 0:s.call(o,t))!=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 t=this.state.nextAttemptTime?b(Math.max(0,this.state.nextAttemptTime.getTime()-Date.now())):this.config.resetTimeout;return new F(t)}forceState(t){this.state={state:t,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,t)=>r=>{for(let n of e){let o=n(r);if(o!==null)return o}return t(r)},Z=e=>t=>t instanceof E?t:t instanceof Error?new e(t.message,t):typeof t=="string"?new e(t):new e("Unknown error occurred",t);var ye=e=>{let r=e.toString().match(/\bcode\s*:\s*['"`]([^'"`]+)['"`]/);return r==null?void 0:r[1]},pe=e=>{if(typeof e!="object"||e===null)return!1;let t=e;return typeof t.status=="number"||typeof t.statusCode=="number"},me=e=>{if(typeof e!="object"||e===null)return!1;let t=e;return typeof t.code=="string"&&t.code.length>0},fe=e=>{var t;if(e instanceof Error){let r=e.message.toLowerCase();if(e.name==="TypeError"&&(r.includes("fetch")&&r.includes("failed")||r.includes("network"))||r.includes("fetch")&&r.includes("failed")||r.includes("network"))return!0}if(me(e)){let r=((t=e.code)!=null?t:"").toUpperCase();return r==="ECONNRESET"||r==="ECONNREFUSED"||r==="ETIMEDOUT"||r==="ENOTFOUND"||r==="EAI_AGAIN"}return!1},Ee=e=>typeof e=="object"&&e!==null,U=class{constructor(t){this.predicate=t}toCode(t){return new W(this.predicate,t)}toError(t){let r=o=>{var c;if(!this.predicate(o))return null;let s=t(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(t);return n&&(r.__tryoCode=n),r}};function Te(e,t){let r=new U(s=>s instanceof e);if(t)return r.toError(t);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=r.toCode.bind(r),o.toError=r.toError.bind(r),o}var W=class{constructor(t,r){this.predicate=t;this.errorCode=r}with(t){let r=n=>{var u;if(!this.predicate(n))return null;let o=t(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 r.__tryoCode=this.errorCode,r}},w={when:e=>new U(e),instance:Te},x={typed:(e=>e instanceof E?e:null),abort:w.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:w.when(e=>e instanceof Error&&e.name==="TimeoutError").toCode("TIMEOUT").with(e=>({message:e.message||"Operation timed out",cause:e,raw:e})),network:w.when(e=>fe(e)).toCode("NETWORK").with(e=>({message:(e instanceof Error,e.message||"Network error"),cause:e,raw:e})),http:w.when(e=>{var n;if(!pe(e))return!1;let t=e,r=(n=t.status)!=null?n:t.statusCode;return typeof r=="number"&&r>=400}).toCode("HTTP").with(e=>{var n;let t=(n=e.status)!=null?n:e.statusCode,r=typeof t=="number"&&(t>=500||t===429);return{message:e.message||`HTTP ${t!=null?t:"error"} error`,cause:e,status:typeof t=="number"?t:void 0,retryable:r,raw:e}}),unknown:w.when(e=>e instanceof Error&&!(e instanceof E)).toCode("UNKNOWN").with(e=>({message:e.message||"Unknown error occurred",cause:e,raw:e}))};var he=[x.typed,x.abort,x.timeout,x.http,x.network,x.unknown];var be={when:e=>w.when(e),instance:w.instance},ee=he;var we={fixed:e=>({type:"fixed",delay:e}),exponential:(e,t=2,r)=>({type:"exponential",base:e,factor:t,maxDelay:r}),fibonacci:(e,t)=>({type:"fibonacci",base:e,maxDelay:t}),custom:e=>({type:"custom",calculate:e})},te=(e,t,r)=>{switch(e.type){case"fixed":return e.delay;case"exponential":{let n=e.base*e.factor**(Number(t)-1);return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"fibonacci":{let n=e.base*Re(Number(t));return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"custom":return e.calculate(t,r);default:return e}},Re=e=>{if(e<=1)return 1;let t=1,r=1;for(let n=2;n<=e;n++){let o=t+r;t=r,r=o}return r},re=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 t=e;throw new Error(`Unknown strategy type: ${t}`)}}};var ne=(e,t)=>new Promise((r,n)=>{if(t!=null&&t.aborted){n(new DOMException("Aborted","AbortError"));return}let o=i=>{t&&i&&t.removeEventListener("abort",i)},s,a=()=>{s&&clearTimeout(s),o(a),n(new DOMException("Aborted","AbortError"))};s=setTimeout(()=>{o(a),r()},e),t==null||t.addEventListener("abort",a,{once:!0})}),oe=(e,t,r,n)=>new Promise((o,s)=>{if(r!=null&&r.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 ${t}ms`))},t),l=()=>{a||(a=!0,u(),s(new DOMException("Aborted","AbortError")))},u=()=>{clearTimeout(i),r==null||r.removeEventListener("abort",l)};r==null||r.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 t=(a=e.rulesMode)!=null?a:"extend",r=(i=e.rules)!=null?i:[];xe(r);let n=ee,o=(l=e.fallback)!=null?l:(u=>Z(B)(u)),s=t==="replace"?r:[...r,...n];return X(s,o)},xe=e=>{let t=new Set;for(let r of e){let n=r.__tryoCode;if(n){if(t.has(n))throw new Error(`Duplicate rule code detected: ${n}`);t.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 t=e;throw new Error(`Unsupported jitter configuration: ${t}`)}}},K=e=>{let t=e;return t.timeout!==void 0&&(t={...t,timeout:Number(b(t.timeout))}),t.concurrency!==void 0&&(t={...t,concurrency:Number.isFinite(t.concurrency)?Number(q(t.concurrency)):t.concurrency}),t.retry&&(re(t.retry.strategy),ge(t.retry.jitter),t={...t,retry:{...t.retry,maxRetries:Number(C(t.retry.maxRetries))}}),t},V=class e{constructor(t={}){d(this,"circuitBreaker");d(this,"config");d(this,"lastCircuitState");let{rules:r,rulesMode:n,fallback:o,toError:s,mapError:a,...i}=t,l=Ce(t),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(t,r={}){var s,a,i,l;let n=K({...this.config,...r});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(t,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(t,r={}){return this.orThrow(t,r)}async orThrow(t,r={}){let n=await this.run(t,r);if(n.ok)return n.data;throw n.error}async all(t,r={}){var c;let n=K({...this.config,...r}),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(t.map(y=>this.run(y,n)));let a=new Array(t.length),i=0,l=async()=>{var y;for(;i<t.length&&!((y=n.signal)!=null&&y.aborted);){let T=i++;if(T>=t.length)break;let m=t[T];m&&(a[T]=await this.run(m,n))}},u=Array.from({length:Math.min(s,t.length)},()=>l());await Promise.all(u);for(let y=0;y<t.length;y++)if(!(y in a)){let T=t[y];T&&(a[y]=await this.run(T,n))}return a}async allOrThrow(t,r={}){return(await this.all(t,r)).map(o=>{if(!o.ok)throw o.error;return o.data})}partitionAll(t){let r=[],n=[],o=[],s=[],a=[];for(let i of t){if(i.type==="success"){r.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:r,errors:n,failure:o,aborted:s,timeout:a}}getCircuitBreakerState(){var t;return(t=this.circuitBreaker)==null?void 0:t.getState()}resetCircuitBreaker(){var t;(t=this.circuitBreaker)==null||t.reset()}getConfig(){return{...this.config}}withConfig(t){var l,u;let{errorHandling:r,...n}=this.config,{errorHandling:o,...s}=t,a=(l=o==null?void 0:o.normalizer)!=null?l:r.normalizer,i=(u=o==null?void 0:o.mapError)!=null?u:r.mapError;return new e({...n,...s,toError:a,mapError:i})}};function L(e={}){let t=new V(e);return{run:(r,n)=>t.run(r,n),orThrow:(r,n)=>t.orThrow(r,n),runOrThrow:(r,n)=>t.runOrThrow(r,n),all:(r,n)=>t.all(r,n),allOrThrow:(r,n)=>t.allOrThrow(r,n),partitionAll:r=>t.partitionAll(r),withConfig:r=>t.withConfig(r)}}async function ke(e,t){let{signal:r,ignoreAbort:n=!0,timeout:o,retry:s,errorHandling:a,logger:i,onSuccess:l,onError:u,onFinally:c,onAbort:y,onRetry:T}=t,m=(R,...p)=>{try{R==null||R(...p)}catch{}},N,k=0,g=[],z=Date.now(),{signal:v,cleanup:ae}=se(r),O=R=>({totalAttempts:k,totalRetries:k>0?Number(k)-1:0,totalDuration:Date.now()-z,lastError:R,retryHistory:g});try{if(v.aborted){m(y,v);let p=a.normalizer(new DOMException("Aborted","AbortError")),h=a.mapError?a.mapError(p):p;return{type:"aborted",ok:!1,data:null,error:h,metrics:O(h)}}let R=async()=>{var I,A,J;let p=1,h=C((I=s==null?void 0:s.maxRetries)!=null?I:0);for(;;){k=p;let Y=new AbortController,{signal:H,cleanup:ie}=se(v,Y.signal);try{let D=Promise.resolve(e({signal:H})),S=o?await oe(D,o,H,()=>(Y.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(N=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(h)){let j=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(!j||j(p,f,ue)){let ce=s?te(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,v);continue}}throw f}finally{ie()}}};try{let p=await R(),h=O();return m(c,h),{type:"success",ok:!0,data:p,error:null,metrics:h}}catch(p){let h=N!=null?N:a.normalizer(p),I=h.code==="TIMEOUT"?"timeout":h.code==="ABORTED"?"aborted":"failure",A=O(h);return m(c,A),{type:I,ok:!1,data:null,error:h,metrics:A}}}finally{ae()}}function se(...e){let t=new AbortController,r=e.filter(o=>o!==void 0);if(r.length===0)return{signal:t.signal,cleanup:()=>{}};if(r.some(o=>o.aborted))return t.abort(),{signal:t.signal,cleanup:()=>{}};let n=[];for(let o of r){let s=()=>t.abort();o.addEventListener("abort",s,{once:!0}),n.push({signal:o,abort:s})}return{signal:t.signal,cleanup:()=>{for(let o of n)o.signal.removeEventListener("abort",o.abort)}}}function Oe(e,t){if(!t||t.type==="none"||e<=0)return e;switch(t.type){case"full":{let r=Number(t.ratio)/100,n=Math.max(0,Number(e)*(1-r)),o=Number(e);return n+Math.random()*(o-n)}case"equal":{let r=Number(t.ratio)/100,n=Number(e)*r/2;return Number(e)-n+Math.random()*n}case"custom":return t.calculate(e);default:return t}}var M=L(),Ae=M.run,Se=M.runOrThrow,Me=M.orThrow,Ne=M.all,ve=M.allOrThrow;export{we as RetryStrategies,E as TypedError,Ne as all,ve as allOrThrow,b as asMilliseconds,C as asRetryCount,L as default,be as errorRule,Me as orThrow,Ae as run,Se as runOrThrow,L as tryo};
|