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 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
- declare abstract class TypedError<Code extends string = string, Meta extends Record<string, unknown> = Record<string, unknown>, Raw = unknown> extends Error {
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
- readonly cause?: unknown;
22
+ cause?: unknown;
22
23
  readonly title?: string;
23
- readonly meta: Meta;
24
- readonly status?: number;
25
- readonly raw?: Raw;
26
- readonly path?: string;
24
+ meta: Meta;
25
+ status?: number;
26
+ raw?: Raw;
27
+ path?: string;
27
28
  readonly timestamp: number;
28
- readonly retryable: boolean;
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<string, any, unknown>;
58
- declare class TimeoutError extends TypedError<'TIMEOUT', Record<string, unknown>, unknown> {
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', Record<string, unknown>, unknown> {
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', Record<string, unknown>, unknown> {
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 = Record<string, unknown> & {
71
+ type ValidationMeta = {
71
72
  validationErrors: unknown[];
72
73
  };
73
- declare class ValidationError extends TypedError<'VALIDATION', ValidationMeta, unknown> {
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', Record<string, unknown>, unknown> {
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 = Record<string, unknown> & {
84
+ type HttpMeta = {
84
85
  response?: unknown;
85
86
  };
86
- declare class HttpError extends TypedError<'HTTP', HttpMeta, unknown> {
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', Record<string, unknown>, 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$1<E>;
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$1<E>;
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$1<E>;
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$1<E>;
187
+ readonly metrics: TryoMetrics<E>;
147
188
  }
148
- interface TryoMetrics$1<E extends AnyTypedError> {
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
- * Modern error normalization system
163
- * Provides type-safe error transformation and normalization
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
- type AllOptions<E extends AnyTypedError> = Omit<Partial<TryoConfig<E> & {
292
- concurrency?: number;
293
- }>, 'circuitBreaker'>;
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
- readonly timeout?: number | undefined;
355
- readonly signal?: AbortSignal | undefined;
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
- readonly timeout?: number | undefined;
372
- readonly signal?: AbortSignal | undefined;
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
- readonly timeout?: number | undefined;
389
- readonly signal?: AbortSignal | undefined;
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
- readonly timeout?: number | undefined;
406
- readonly signal?: AbortSignal | undefined;
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
- readonly timeout?: number | undefined;
423
- readonly signal?: AbortSignal | undefined;
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 MappedTypedError<Out extends ErrorResponse, Input> = TypedError<Out['code'], Out['meta'] extends Record<string, unknown> ? Out['meta'] : Record<string, unknown>, Out['raw'] extends undefined ? Input : Out['raw']>;
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, T>>;
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, Out['meta'] extends Record<string, unknown> ? Out['meta'] : Record<string, unknown>, Out['raw'] extends undefined ? T : Out['raw']>>;
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 Record<string, unknown> ? Out["meta"] : Record<string, unknown>, Out["raw"] extends undefined ? InstanceType<T> : Out["raw"]>>;
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 Record<string, unknown> ? Out["meta"] : Record<string, unknown>, Out["raw"] extends undefined ? InstanceType<T> : Out["raw"]>>;
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$1 as TryoMetrics, type TryoOptions, type TryoResult, TypedError, all, allOrThrow, asMilliseconds, asRetryCount, tryo as default, errorRule, orThrow, run, runOrThrow, tryo };
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
- declare abstract class TypedError<Code extends string = string, Meta extends Record<string, unknown> = Record<string, unknown>, Raw = unknown> extends Error {
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
- readonly cause?: unknown;
22
+ cause?: unknown;
22
23
  readonly title?: string;
23
- readonly meta: Meta;
24
- readonly status?: number;
25
- readonly raw?: Raw;
26
- readonly path?: string;
24
+ meta: Meta;
25
+ status?: number;
26
+ raw?: Raw;
27
+ path?: string;
27
28
  readonly timestamp: number;
28
- readonly retryable: boolean;
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<string, any, unknown>;
58
- declare class TimeoutError extends TypedError<'TIMEOUT', Record<string, unknown>, unknown> {
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', Record<string, unknown>, unknown> {
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', Record<string, unknown>, unknown> {
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 = Record<string, unknown> & {
71
+ type ValidationMeta = {
71
72
  validationErrors: unknown[];
72
73
  };
73
- declare class ValidationError extends TypedError<'VALIDATION', ValidationMeta, unknown> {
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', Record<string, unknown>, unknown> {
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 = Record<string, unknown> & {
84
+ type HttpMeta = {
84
85
  response?: unknown;
85
86
  };
86
- declare class HttpError extends TypedError<'HTTP', HttpMeta, unknown> {
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', Record<string, unknown>, 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$1<E>;
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$1<E>;
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$1<E>;
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$1<E>;
187
+ readonly metrics: TryoMetrics<E>;
147
188
  }
148
- interface TryoMetrics$1<E extends AnyTypedError> {
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
- * Modern error normalization system
163
- * Provides type-safe error transformation and normalization
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
- type AllOptions<E extends AnyTypedError> = Omit<Partial<TryoConfig<E> & {
292
- concurrency?: number;
293
- }>, 'circuitBreaker'>;
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
- readonly timeout?: number | undefined;
355
- readonly signal?: AbortSignal | undefined;
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
- readonly timeout?: number | undefined;
372
- readonly signal?: AbortSignal | undefined;
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
- readonly timeout?: number | undefined;
389
- readonly signal?: AbortSignal | undefined;
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
- readonly timeout?: number | undefined;
406
- readonly signal?: AbortSignal | undefined;
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
- readonly timeout?: number | undefined;
423
- readonly signal?: AbortSignal | undefined;
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 MappedTypedError<Out extends ErrorResponse, Input> = TypedError<Out['code'], Out['meta'] extends Record<string, unknown> ? Out['meta'] : Record<string, unknown>, Out['raw'] extends undefined ? Input : Out['raw']>;
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, T>>;
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, Out['meta'] extends Record<string, unknown> ? Out['meta'] : Record<string, unknown>, Out['raw'] extends undefined ? T : Out['raw']>>;
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 Record<string, unknown> ? Out["meta"] : Record<string, unknown>, Out["raw"] extends undefined ? InstanceType<T> : Out["raw"]>>;
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 Record<string, unknown> ? Out["meta"] : Record<string, unknown>, Out["raw"] extends undefined ? InstanceType<T> : Out["raw"]>>;
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$1 as TryoMetrics, type TryoOptions, type TryoResult, TypedError, all, allOrThrow, asMilliseconds, asRetryCount, tryo as default, errorRule, orThrow, run, runOrThrow, tryo };
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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tryo",
3
- "version": "0.13.8",
3
+ "version": "0.13.10",
4
4
  "author": {
5
5
  "name": "sebasxsala",
6
6
  "url": "https://github.com/sebasxsala"