tryo 0.13.0 → 0.13.3

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 D=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var me=Object.prototype.hasOwnProperty;var de=(e,r,t)=>r in e?D(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t;var ye=(e,r)=>{for(var t in r)D(e,t,{get:r[t],enumerable:!0})},pe=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of le(r))!me.call(e,o)&&o!==t&&D(e,o,{get:()=>r[o],enumerable:!(n=ce(r,o))||n.enumerable});return e};var fe=e=>pe(D({},"__esModule",{value:!0}),e);var m=(e,r,t)=>de(e,typeof r!="symbol"?r+"":r,t);var Ae={};ye(Ae,{RetryStrategies:()=>X,all:()=>ne,allOrThrow:()=>oe,asConcurrencyLimit:()=>B,asMilliseconds:()=>C,asPercentage:()=>J,asRetryCount:()=>R,asStatusCode:()=>K,errorRule:()=>G,orThrow:()=>te,run:()=>ee,runOrThrow:()=>re,tryo:()=>z});module.exports=fe(Ae);var T=class extends Error{constructor(t,n){var o;super(t);m(this,"cause");m(this,"meta");m(this,"status");m(this,"timestamp");m(this,"retryable");this.timestamp=Date.now(),this.retryable=(o=n==null?void 0:n.retryable)!=null?o:!0,this.name=this.constructor.name,this.cause=n==null?void 0:n.cause,this.meta=n==null?void 0:n.meta,this.status=n==null?void 0:n.status,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})}withRetryable(t){return this.retryable=t,this}toJSON(){return{name:this.name,code:this.code,message:this.message,timestamp:this.timestamp,retryable:this.retryable,cause:this.cause,stack:this.stack}}},v=class extends T{constructor(t,n){super(`Operation timed out after ${t}ms`,{cause:n,retryable:!0});m(this,"code","TIMEOUT")}};var A=class extends T{constructor(t,n){super(`Circuit breaker is open, reset after ${t}ms`,{cause:n,retryable:!1});m(this,"code","CIRCUIT_OPEN")}},I=class extends T{constructor(t,n,o){super(t,{cause:o,meta:{validationErrors:n},retryable:!1});this.validationErrors=n;m(this,"code","VALIDATION")}};var F=class extends T{constructor(t,n){super(t,{cause:n});m(this,"code","UNKNOWN")}};var C=e=>{if(e<0||!Number.isFinite(e))throw new Error(`Invalid milliseconds: must be a non-negative finite number, got ${e}`);return e},R=e=>{if(e<0||!Number.isInteger(e))throw new Error(`Invalid retry count: must be a non-negative integer, got ${e}`);return e},B=e=>{if(e<1||!Number.isInteger(e))throw new Error(`Invalid concurrency limit: must be a positive integer, got ${e}`);return e},J=e=>{if(e<0||e>100||!Number.isFinite(e))throw new Error(`Invalid percentage: must be between 0 and 100, got ${e}`);return e},K=e=>{if(!Number.isInteger(e)||e<100||e>599)throw new Error(`Invalid status code: must be an integer between 100-599, got ${e}`);return e};var L=class{constructor(r){m(this,"state");m(this,"config");this.config={failureThreshold:R(r.failureThreshold),resetTimeout:C(r.resetTimeout),halfOpenRequests:R(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,i;if(!((i=(a=(o=this.config).shouldCountAsFailure)==null?void 0:a.call(o,r))!=null?i:!0))return;let n=new Date;switch(this.state.state){case"closed":{let s=this.state.failureCount+1;s>=this.config.failureThreshold?this.state={state:"open",failureCount:s,halfOpenCount:0,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)}:this.state={...this.state,failureCount:s,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?C(Math.max(0,this.state.nextAttemptTime.getTime()-Date.now())):this.config.resetTimeout;return new A(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 q=(e,r)=>t=>{for(let n of e){let o=n(t);if(o!==null)return o}return r(t)},Y=e=>r=>r instanceof T?r:r instanceof Error?new e(r.message,r):typeof r=="string"?new e(r):new e("Unknown error occurred",r);var Te=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.status=="number"||typeof r.statusCode=="number"},Ee=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.code=="string"&&r.code.length>0},we=e=>{var r;if(e instanceof Error){if(e.name==="TypeError")return!0;let t=e.message.toLowerCase();if(t.includes("fetch")&&t.includes("failed")||t.includes("network"))return!0}if(Ee(e)){let t=((r=e.code)!=null?r:"").toUpperCase();return t==="ECONNRESET"||t==="ECONNREFUSED"||t==="ETIMEDOUT"||t==="ENOTFOUND"||t==="EAI_AGAIN"}return!1},U=class{constructor(r){this.predicate=r}toCode(r){return new _(this.predicate,r)}toError(r){return t=>{if(!this.predicate(t))return null;let n=r(t),o=n.code;class a extends T{constructor(){var u;super(n.message,{cause:(u=n.cause)!=null?u:t,meta:n.meta,status:n.status,retryable:n.retryable});m(this,"code",o)}}return new a}}},_=class{constructor(r,t){this.predicate=r;this.errorCode=t}with(r){return t=>{if(!this.predicate(t))return null;let n=r(t),o=this.errorCode;class a extends T{constructor(){super(n.message,{cause:n.cause,meta:n.meta,status:n.status,retryable:n.retryable});m(this,"code",o)}}return new a}}},E={when:e=>new U(e),instance:e=>new U(r=>r instanceof e),code:e=>({for:r=>new _(r,e)}),string:(e,r)=>({when:t=>E.when(t).toCode(r).with(n=>({message:n===e?e:`${r}: ${n}`,cause:n}))}),httpStatus:(e,r)=>({for:t=>E.when(t).toCode(r!=null?r:`HTTP_${e}`).with(n=>({message:`HTTP ${e} error`,cause:n}))})};var w={typed:(e=>e instanceof T?e:null),abort:E.when(e=>e instanceof DOMException&&e.name==="AbortError").toCode("ABORTED").with(e=>({message:e.message||"Operation was aborted",cause:e,retryable:!1})),timeout:E.when(e=>e instanceof Error&&e.name==="TimeoutError").toCode("TIMEOUT").with(e=>({message:e.message||"Operation timed out",cause:e})),network:E.when(e=>we(e)).toCode("NETWORK").with(e=>({message:(e instanceof Error,e.message||"Network error"),cause:e})),http:E.when(e=>{var n;if(!Te(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}}),unknown:E.when(e=>e instanceof Error&&!(e instanceof T)).toCode("UNKNOWN").with(e=>({message:e.message||"Unknown error occurred",cause:e}))};var be=[w.typed,w.abort,w.timeout,w.http,w.network,w.unknown];var G={when:e=>E.when(e),instance:e=>E.instance(e)},Q=be,He=w.timeout,Ve=w.abort,We=w.network,Je=w.http,Ke=E.when(e=>e instanceof A).toCode("CIRCUIT_OPEN").with(e=>({message:e.message,cause:e})),qe=E.when(e=>e instanceof I).toCode("VALIDATION").with(e=>({message:e.message,cause:e}));var X={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})},Z=(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?Math.min(n,e.maxDelay):n}case"fibonacci":{let n=e.base*he(Number(r));return e.maxDelay?Math.min(n,e.maxDelay):n}case"custom":return e.calculate(r,t);default:return e}},he=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};var j=(e,r)=>new Promise((t,n)=>{if(r!=null&&r.aborted){n(new DOMException("Aborted","AbortError"));return}let o=s=>{r&&s&&r.removeEventListener("abort",s)},a,i=()=>{a&&clearTimeout(a),o(i),n(new DOMException("Aborted","AbortError"))};a=setTimeout(()=>{o(i),t()},e),r==null||r.addEventListener("abort",i,{once:!0})});var Ce=e=>{var i,s,u;if(e.toError)return e.toError;let r=(i=e.rulesMode)!=null?i:"extend",t=(s=e.rules)!=null?s:[],n=Q,o=(u=e.fallback)!=null?u:(c=>Y(F)(c)),a=r==="replace"?t:[...t,...n];return q(a,o)},H=class e{constructor(r={}){m(this,"circuitBreaker");m(this,"config");m(this,"lastCircuitState");let{rules:t,rulesMode:n,fallback:o,toError:a,mapError:i,...s}=r,u=Ce(r),c={...s,errorHandling:{normalizer:u,mapError:i}};this.config=c,c.circuitBreaker&&(this.circuitBreaker=new L(c.circuitBreaker),this.lastCircuitState=this.circuitBreaker.getState().state)}async run(r,t={}){var a,i,s,u,c,b;let n={...this.config,...t};if(this.circuitBreaker){let l=(a=this.lastCircuitState)!=null?a:this.circuitBreaker.getState().state,y=await this.circuitBreaker.canExecute(),p=this.circuitBreaker.getState().state;if(l!==p)try{(s=(i=n.hooks)==null?void 0:i.onCircuitStateChange)==null||s.call(i,l,p)}catch{}if(this.lastCircuitState=p,!y)return{type:"failure",ok:!1,data:null,error:this.circuitBreaker.createOpenError(),metrics:{totalAttempts:0,totalRetries:0,totalDuration:0,retryHistory:[]}}}let o=await xe(r,n);if(this.circuitBreaker){let l=(u=this.lastCircuitState)!=null?u:this.circuitBreaker.getState().state;o.ok?await this.circuitBreaker.recordSuccess():await this.circuitBreaker.recordFailure(o.error);let y=this.circuitBreaker.getState().state;if(l!==y)try{(b=(c=n.hooks)==null?void 0:c.onCircuitStateChange)==null||b.call(c,l,y)}catch{}this.lastCircuitState=y}return o}async runOrThrow(r,t={}){let n=await this.run(r,t);if(n.ok)return n.data;throw n.error}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 b;let n={...this.config,...t},o=(b=n.concurrency)!=null?b:Number.POSITIVE_INFINITY,a=Number.isFinite(o)?Number(B(o)):Number.POSITIVE_INFINITY,i=new Array(r.length),s=0,u=async()=>{var l;for(;s<r.length&&!((l=n.signal)!=null&&l.aborted);){let y=s++;if(y>=r.length)break;let p=r[y];p&&(i[y]=await this.run(p,n))}},c=Array.from({length:Math.min(a,r.length)},()=>u());await Promise.all(c);for(let l=0;l<r.length;l++)if(!(l in i)){let y=r[l];y&&(i[l]=await this.run(y,n))}return i}async allOrThrow(r,t={}){let n=await this.all(r,t);for(let o of n)if(!o.ok)throw o.error;return n.map(o=>{if(!o.ok)throw o.error;return o.data})}partitionAll(r){let t=[],n=[],o=[],a=[],i=[];for(let s of r){if(s.type==="success"){t.push(s);continue}switch(n.push(s),s.type){case"failure":o.push(s);break;case"aborted":a.push(s);break;case"timeout":i.push(s);break}}return{ok:t,errors:n,failure:o,aborted:a,timeout:i}}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 u,c;let{errorHandling:t,...n}=this.config,{errorHandling:o,...a}=r,i=(u=o==null?void 0:o.normalizer)!=null?u:t.normalizer,s=(c=o==null?void 0:o.mapError)!=null?c:t.mapError;return new e({...n,...a,toError:i,mapError:s})}withErrorType(r={}){return new e(r)}};function z(e={}){let r=new H(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 xe(e,r){let{signal:t,ignoreAbort:n=!0,timeout:o,retry:a,errorHandling:i,hooks:s,logger:u}=r,c=(g,...d)=>{try{g==null||g(...d)}catch{}},b,l=0,y=0,p=[],k=Date.now(),{signal:x,cleanup:se}=Re(t);try{if(x.aborted){c(s==null?void 0:s.onAbort,x);let d=i.normalizer(new DOMException("Aborted","AbortError")),f=i.mapError?i.mapError(d):d;return{type:"aborted",ok:!1,data:null,error:f,metrics:{totalAttempts:l,totalRetries:y,totalDuration:Date.now()-k,lastError:f,retryHistory:p}}}let g=async d=>{var f,P,O;l=d;try{let M=e({signal:x}),S=o?await ke(M,o,x):await M;return c(s==null?void 0:s.onSuccess,S),c(u==null?void 0:u.info,`Task succeeded on attempt ${d}`),S}catch(M){let S=i.normalizer(M),h=i.mapError?i.mapError(S):S;b=h,h.code==="ABORTED"&&c(s==null?void 0:s.onAbort,x),n&&h.code==="ABORTED"||(c(s==null?void 0:s.onError,h),c(u==null?void 0:u.error,`Task failed on attempt ${d}`,h));let ae=R((f=a==null?void 0:a.maxRetries)!=null?f:0);if(d<=Number(ae)){let V=a==null?void 0:a.shouldRetry,ie={totalAttempts:Number(l),elapsedTime:Date.now()-k,startTime:new Date(k),lastDelay:(P=p[p.length-1])!=null&&P.delay?Number((O=p[p.length-1])==null?void 0:O.delay):void 0};if(!V||V(d,h,ie)){let ue=a?Z(a.strategy,d,h):0,$=ge(ue,a==null?void 0:a.jitter),W=C($);return p.push({attempt:d,error:h,delay:W,timestamp:new Date}),c(s==null?void 0:s.onRetry,d,h,$),c(u==null?void 0:u.info,`Retrying in ${$}ms (attempt ${d+1})`),await j(W,x),g(d+1)}}throw h}};try{let d=await g(1);y=l>0?Number(l)-1:0;let f={totalAttempts:l,totalRetries:y,totalDuration:Date.now()-k,retryHistory:p};return c(s==null?void 0:s.onFinally,f),{type:"success",ok:!0,data:d,error:null,metrics:f}}catch(d){let f=b!=null?b:i.normalizer(d),P=f.code==="TIMEOUT"?"timeout":f.code==="ABORTED"?"aborted":"failure";y=l>0?Number(l)-1:0;let O={totalAttempts:l,totalRetries:y,totalDuration:Date.now()-k,lastError:f,retryHistory:p};return c(s==null?void 0:s.onFinally,O),{type:P,ok:!1,data:null,error:f,metrics:O}}}finally{se()}}function Re(e){let r=new AbortController;if(!e)return{signal:r.signal,cleanup:()=>{}};let t=()=>r.abort();return e.aborted?(t(),{signal:r.signal,cleanup:()=>{}}):(e.addEventListener("abort",t,{once:!0}),{signal:r.signal,cleanup:()=>e.removeEventListener("abort",t)})}async function ke(e,r,t){return new Promise((n,o)=>{if(t!=null&&t.aborted){o(new DOMException("Aborted","AbortError"));return}let a=!1,i=setTimeout(()=>{a=!0,u(),o(new v(C(r)))},r),s=()=>{a||(a=!0,u(),o(new DOMException("Aborted","AbortError")))},u=()=>{clearTimeout(i),t==null||t.removeEventListener("abort",s)};t==null||t.addEventListener("abort",s,{once:!0}),e.then(c=>{a||(a=!0,u(),n(c))},c=>{a||(a=!0,u(),o(c))})})}function ge(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=z(),ee=N.run,re=N.runOrThrow,te=N.orThrow,ne=N.all,oe=N.allOrThrow;0&&(module.exports={RetryStrategies,all,allOrThrow,asConcurrencyLimit,asMilliseconds,asPercentage,asRetryCount,asStatusCode,errorRule,orThrow,run,runOrThrow,tryo});
1
+ "use strict";var I=Object.defineProperty;var fe=Object.getOwnPropertyDescriptor;var Ee=Object.getOwnPropertyNames;var Te=Object.prototype.hasOwnProperty;var be=(e,r,t)=>r in e?I(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t;var we=(e,r)=>{for(var t in r)I(e,t,{get:r[t],enumerable:!0})},he=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of Ee(r))!Te.call(e,o)&&o!==t&&I(e,o,{get:()=>r[o],enumerable:!(n=fe(r,o))||n.enumerable});return e};var Ce=e=>he(I({},"__esModule",{value:!0}),e);var y=(e,r,t)=>be(e,typeof r!="symbol"?r+"":r,t);var ve={};we(ve,{RetryStrategies:()=>ee,TypedError:()=>T,all:()=>le,allOrThrow:()=>ce,asMilliseconds:()=>w,asRetryCount:()=>h,default:()=>S,errorRule:()=>Z,orThrow:()=>ue,run:()=>ae,runOrThrow:()=>ie,tryo:()=>S});module.exports=Ce(ve);var T=class extends Error{constructor(t,n){var o,a;super(t);y(this,"cause");y(this,"meta");y(this,"status");y(this,"raw");y(this,"path");y(this,"timestamp");y(this,"retryable");this.timestamp=Date.now(),this.retryable=(o=n.retryable)!=null?o:!0,this.name=this.constructor.name,this.cause=n.cause,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,message:this.message,timestamp:this.timestamp,retryable:this.retryable,cause:this.cause,raw:this.raw,path:this.path,stack:this.stack}}},P=class extends T{constructor(t,n){super(`Operation timed out after ${t}ms`,{cause:n,retryable:!0,raw:n});y(this,"code","TIMEOUT")}};var F=class extends T{constructor(t,n){super(`Circuit breaker is open, reset after ${t}ms`,{cause:n,retryable:!1,raw:n});y(this,"code","CIRCUIT_OPEN")}};var _=class extends T{constructor(t,n){super(t,{cause:n,raw:n});y(this,"code","UNKNOWN")}};var w=e=>{if(e<0||!Number.isFinite(e))throw new Error(`Invalid milliseconds: must be a non-negative finite number, got ${e}`);return e},h=e=>{if(e<0||!Number.isInteger(e))throw new Error(`Invalid retry count: must be a non-negative integer, got ${e}`);return e},H=e=>{if(e<1||!Number.isInteger(e))throw new Error(`Invalid concurrency limit: must be a positive integer, got ${e}`);return e},G=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 B=class{constructor(r){y(this,"state");y(this,"config");this.config={failureThreshold:h(r.failureThreshold),resetTimeout:w(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,i;if(!((i=(a=(o=this.config).shouldCountAsFailure)==null?void 0:a.call(o,r))!=null?i:!0))return;let n=new Date;switch(this.state.state){case"closed":{let s=this.state.failureCount+1;s>=this.config.failureThreshold?this.state={state:"open",failureCount:s,halfOpenCount:0,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)}:this.state={...this.state,failureCount:s,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?w(Math.max(0,this.state.nextAttemptTime.getTime()-Date.now())):this.config.resetTimeout;return new F(r)}forceState(r){this.state={state:r,failureCount:0,halfOpenCount:0}}reset(){this.state={state:"closed",failureCount:0,halfOpenCount:0}}updateStateIfNeeded(){this.state.state==="open"&&this.state.nextAttemptTime&&new Date>=this.state.nextAttemptTime&&(this.state={...this.state,state:"half-open",halfOpenCount:0})}};var Q=(e,r)=>t=>{for(let n of e){let o=n(t);if(o!==null)return o}return r(t)},X=e=>r=>r instanceof T?r:r instanceof Error?new e(r.message,r):typeof r=="string"?new e(r):new e("Unknown error occurred",r);var Re=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.status=="number"||typeof r.statusCode=="number"},xe=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.code=="string"&&r.code.length>0},ge=e=>{var r;if(e instanceof Error){let t=e.message.toLowerCase();if(e.name==="TypeError"&&(t.includes("fetch")&&t.includes("failed")||t.includes("network"))||t.includes("fetch")&&t.includes("failed")||t.includes("network"))return!0}if(xe(e)){let t=((r=e.code)!=null?r:"").toUpperCase();return t==="ECONNRESET"||t==="ECONNREFUSED"||t==="ETIMEDOUT"||t==="ENOTFOUND"||t==="EAI_AGAIN"}return!1},U=class{constructor(r){this.predicate=r}toCode(r){return new $(this.predicate,r)}toError(r){return t=>{if(!this.predicate(t))return null;let n=r(t),o=n.code;class a extends T{constructor(){var l,u,d;super(n.message,{cause:(l=n.cause)!=null?l:t,meta:(u=n.meta)!=null?u:{},status:n.status,retryable:n.retryable,raw:(d=n.raw)!=null?d:t,path:n.path});y(this,"code",o)}}return new a}}},$=class{constructor(r,t){this.predicate=r;this.errorCode=t}with(r){return t=>{if(!this.predicate(t))return null;let n=r(t),o=this.errorCode;class a extends T{constructor(){var u;let l=Object.hasOwn(n,"raw")?n.raw:t;super(n.message,{cause:n.cause,meta:(u=n.meta)!=null?u:{},status:n.status,retryable:n.retryable,raw:l,path:n.path});y(this,"code",o)}}return new a}}},C={when:e=>new U(e),instance:e=>new U(r=>r instanceof e)},x={typed:(e=>e instanceof T?e:null),abort:C.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:C.when(e=>e instanceof Error&&e.name==="TimeoutError").toCode("TIMEOUT").with(e=>({message:e.message||"Operation timed out",cause:e,raw:e})),network:C.when(e=>ge(e)).toCode("NETWORK").with(e=>({message:(e instanceof Error,e.message||"Network error"),cause:e,raw:e})),http:C.when(e=>{var n;if(!Re(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:C.when(e=>e instanceof Error&&!(e instanceof T)).toCode("UNKNOWN").with(e=>({message:e.message||"Unknown error occurred",cause:e,raw:e}))};var ke=[x.typed,x.abort,x.timeout,x.http,x.network,x.unknown];var Z={when:e=>C.when(e),instance:e=>C.instance(e)},j=ke;var ee={fixed:e=>({type:"fixed",delay:e}),exponential:(e,r=2,t)=>({type:"exponential",base:e,factor:r,maxDelay:t}),fibonacci:(e,r)=>({type:"fibonacci",base:e,maxDelay:r}),custom:e=>({type:"custom",calculate:e})},re=(e,r,t)=>{switch(e.type){case"fixed":return e.delay;case"exponential":{let n=e.base*e.factor**(Number(r)-1);return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"fibonacci":{let n=e.base*Ae(Number(r));return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"custom":return e.calculate(r,t);default:return e}},Ae=e=>{if(e<=1)return 1;let r=1,t=1;for(let n=2;n<=e;n++){let o=r+t;r=t,t=o}return t},te=e=>{switch(e.type){case"fixed":{if(e.delay<0)throw new Error("Fixed delay must be non-negative");break}case"exponential":if(e.base<=0)throw new Error("Exponential base delay must be positive");if(e.factor<=1)throw new Error("Exponential factor must be greater than 1");if(e.maxDelay!==void 0&&e.maxDelay<=0)throw new Error("Exponential max delay must be positive");break;case"fibonacci":if(e.base<=0)throw new Error("Fibonacci base delay must be positive");if(e.maxDelay!==void 0&&e.maxDelay<=0)throw new Error("Fibonacci max delay must be positive");break;case"custom":break;default:{let r=e;throw new Error(`Unknown strategy type: ${r}`)}}};var ne=(e,r)=>new Promise((t,n)=>{if(r!=null&&r.aborted){n(new DOMException("Aborted","AbortError"));return}let o=s=>{r&&s&&r.removeEventListener("abort",s)},a,i=()=>{a&&clearTimeout(a),o(i),n(new DOMException("Aborted","AbortError"))};a=setTimeout(()=>{o(i),t()},e),r==null||r.addEventListener("abort",i,{once:!0})}),oe=(e,r,t,n)=>new Promise((o,a)=>{if(t!=null&&t.aborted){a(new DOMException("Aborted","AbortError"));return}let i=!1,s=setTimeout(()=>{var d;i=!0,u(),a((d=n==null?void 0:n())!=null?d:new Error(`Operation timed out after ${r}ms`))},r),l=()=>{i||(i=!0,u(),a(new DOMException("Aborted","AbortError")))},u=()=>{clearTimeout(s),t==null||t.removeEventListener("abort",l)};t==null||t.addEventListener("abort",l,{once:!0}),e.then(d=>{i||(i=!0,u(),o(d))},d=>{i||(i=!0,u(),a(d))})});var Oe=e=>{var i,s,l;if(e.toError)return e.toError;let r=(i=e.rulesMode)!=null?i:"extend",t=(s=e.rules)!=null?s:[],n=j,o=(l=e.fallback)!=null?l:(u=>X(_)(u)),a=r==="replace"?t:[...t,...n];return Q(a,o)},Se=e=>{if(e)switch(e.type){case"none":return;case"full":case"equal":G(e.ratio);return;case"custom":return;default:{let r=e;throw new Error(`Unsupported jitter configuration: ${r}`)}}},q=e=>{let r=e;return r.timeout!==void 0&&(r={...r,timeout:Number(w(r.timeout))}),r.concurrency!==void 0&&(r={...r,concurrency:Number.isFinite(r.concurrency)?Number(H(r.concurrency)):r.concurrency}),r.retry&&(te(r.retry.strategy),Se(r.retry.jitter),r={...r,retry:{...r.retry,maxRetries:Number(h(r.retry.maxRetries))}}),r},V=class e{constructor(r={}){y(this,"circuitBreaker");y(this,"config");y(this,"lastCircuitState");let{rules:t,rulesMode:n,fallback:o,toError:a,mapError:i,...s}=r,l=Oe(r),u={...s,errorHandling:{normalizer:l,mapError:i}};this.config=q(u),u.circuitBreaker&&(this.circuitBreaker=new B(u.circuitBreaker),this.lastCircuitState=this.circuitBreaker.getState().state)}async run(r,t={}){var a,i,s,l,u,d;let n=q({...this.config,...t});if(this.circuitBreaker){let c=(a=this.lastCircuitState)!=null?a:this.circuitBreaker.getState().state,m=await this.circuitBreaker.canExecute(),E=this.circuitBreaker.getState().state;if(c!==E)try{(s=(i=n.hooks)==null?void 0:i.onCircuitStateChange)==null||s.call(i,c,E)}catch{}if(this.lastCircuitState=E,!m)return{type:"failure",ok:!1,data:null,error:this.circuitBreaker.createOpenError(),metrics:{totalAttempts:0,totalRetries:0,totalDuration:0,retryHistory:[]}}}let o=await Ne(r,n);if(this.circuitBreaker){let c=(l=this.lastCircuitState)!=null?l:this.circuitBreaker.getState().state;o.ok?await this.circuitBreaker.recordSuccess():await this.circuitBreaker.recordFailure(o.error);let m=this.circuitBreaker.getState().state;if(c!==m)try{(d=(u=n.hooks)==null?void 0:u.onCircuitStateChange)==null||d.call(u,c,m)}catch{}this.lastCircuitState=m}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=q({...this.config,...t}),o=(d=n.concurrency)!=null?d:Number.POSITIVE_INFINITY,a=Number.isFinite(o)?Number(H(o)):Number.POSITIVE_INFINITY;if(a===Number.POSITIVE_INFINITY)return Promise.all(r.map(c=>this.run(c,n)));let i=new Array(r.length),s=0,l=async()=>{var c;for(;s<r.length&&!((c=n.signal)!=null&&c.aborted);){let m=s++;if(m>=r.length)break;let E=r[m];E&&(i[m]=await this.run(E,n))}},u=Array.from({length:Math.min(a,r.length)},()=>l());await Promise.all(u);for(let c=0;c<r.length;c++)if(!(c in i)){let m=r[c];m&&(i[c]=await this.run(m,n))}return i}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=[],i=[];for(let s of r){if(s.type==="success"){t.push(s);continue}switch(n.push(s),s.type){case"failure":o.push(s);break;case"aborted":a.push(s);break;case"timeout":i.push(s);break}}return{ok:t,errors:n,failure:o,aborted:a,timeout:i}}getCircuitBreakerState(){var r;return(r=this.circuitBreaker)==null?void 0:r.getState()}resetCircuitBreaker(){var r;(r=this.circuitBreaker)==null||r.reset()}getConfig(){return{...this.config}}withConfig(r){var l,u;let{errorHandling:t,...n}=this.config,{errorHandling:o,...a}=r,i=(l=o==null?void 0:o.normalizer)!=null?l:t.normalizer,s=(u=o==null?void 0:o.mapError)!=null?u:t.mapError;return new e({...n,...a,toError:i,mapError:s})}};function S(e={}){let r=new V(e);return{run:(t,n)=>r.run(t,n),orThrow:(t,n)=>r.orThrow(t,n),runOrThrow:(t,n)=>r.runOrThrow(t,n),all:(t,n)=>r.all(t,n),allOrThrow:(t,n)=>r.allOrThrow(t,n),partitionAll:t=>r.partitionAll(t),withConfig:t=>r.withConfig(t)}}async function Ne(e,r){let{signal:t,ignoreAbort:n=!0,timeout:o,retry:a,errorHandling:i,hooks:s,logger:l}=r,u=(R,...p)=>{try{R==null||R(...p)}catch{}},d,c=0,m=0,E=[],k=Date.now(),{signal:A,cleanup:ye}=se(t),M=R=>({totalAttempts:c,totalRetries:c>0?Number(c)-1:0,totalDuration:Date.now()-k,lastError:R,retryHistory:E});try{if(A.aborted){u(s==null?void 0:s.onAbort,A);let p=i.normalizer(new DOMException("Aborted","AbortError")),b=i.mapError?i.mapError(p):p;return{type:"aborted",ok:!1,data:null,error:b,metrics:{totalAttempts:c,totalRetries:m,totalDuration:Date.now()-k,lastError:b,retryHistory:E}}}let R=async()=>{var v,g,W;let p=1,b=h((v=a==null?void 0:a.maxRetries)!=null?v:0);for(;;){c=p;let K=new AbortController,{signal:z,cleanup:de}=se(A,K.signal);try{let D=Promise.resolve(e({signal:z})),O=o?await oe(D,o,z,()=>(K.abort(),new P(w(o)))):await D;return u(s==null?void 0:s.onSuccess,O,M()),u(l==null?void 0:l.info,`Task succeeded on attempt ${p}`),O}catch(D){let O=i.normalizer(D),f=i.mapError?i.mapError(O):O;if(d=f,f.code==="ABORTED"&&u(s==null?void 0:s.onAbort,z),n&&f.code==="ABORTED"||(u(s==null?void 0:s.onError,f,M(f)),u(l==null?void 0:l.error,`Task failed on attempt ${p}`,f)),f.code==="ABORTED"||f.retryable===!1)throw f;if(p<=Number(b)){let J=a==null?void 0:a.shouldRetry,pe={totalAttempts:Number(c),elapsedTime:Date.now()-k,startTime:new Date(k),lastDelay:(g=E[E.length-1])!=null&&g.delay?Number((W=E[E.length-1])==null?void 0:W.delay):void 0};if(!J||J(p,f,pe)){let me=a?re(a.strategy,p,f):0,L=Me(me,a==null?void 0:a.jitter),Y=w(L);E.push({attempt:p,error:f,delay:Y,timestamp:new Date}),u(s==null?void 0:s.onRetry,p,f,L),u(l==null?void 0:l.info,`Retrying in ${L}ms (attempt ${p+1})`),p+=1,await ne(Y,A);continue}}throw f}finally{de()}}};try{let p=await R(),b=M();return m=b.totalRetries,u(s==null?void 0:s.onFinally,b),{type:"success",ok:!0,data:p,error:null,metrics:b}}catch(p){let b=d!=null?d:i.normalizer(p),v=b.code==="TIMEOUT"?"timeout":b.code==="ABORTED"?"aborted":"failure",g=M(b);return m=g.totalRetries,u(s==null?void 0:s.onFinally,g),{type:v,ok:!1,data:null,error:b,metrics:g}}}finally{ye()}}function se(...e){let r=new AbortController,t=e.filter(o=>o!==void 0);if(t.length===0)return{signal:r.signal,cleanup:()=>{}};if(t.some(o=>o.aborted))return r.abort(),{signal:r.signal,cleanup:()=>{}};let n=[];for(let o of t){let 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 Me(e,r){if(!r||r.type==="none"||e<=0)return e;switch(r.type){case"full":{let t=Number(r.ratio)/100,n=Math.max(0,Number(e)*(1-t)),o=Number(e);return n+Math.random()*(o-n)}case"equal":{let t=Number(r.ratio)/100,n=Number(e)*t/2;return Number(e)-n+Math.random()*n}case"custom":return r.calculate(e);default:return r}}var N=S(),ae=N.run,ie=N.runOrThrow,ue=N.orThrow,le=N.all,ce=N.allOrThrow;0&&(module.exports={RetryStrategies,TypedError,all,allOrThrow,asMilliseconds,asRetryCount,errorRule,orThrow,run,runOrThrow,tryo});
package/dist/index.d.cts CHANGED
@@ -8,38 +8,30 @@ type Milliseconds = number & {
8
8
  type RetryCount = number & {
9
9
  readonly __brand: 'RetryCount';
10
10
  };
11
- type ConcurrencyLimit = number & {
12
- readonly __brand: 'ConcurrencyLimit';
13
- };
14
- type Percentage = number & {
15
- readonly __brand: 'Percentage';
16
- };
17
- type StatusCode = number & {
18
- readonly __brand: 'StatusCode';
19
- };
20
11
  declare const asMilliseconds: (n: number) => Milliseconds;
21
12
  declare const asRetryCount: (n: number) => RetryCount;
22
- declare const asConcurrencyLimit: (n: number) => ConcurrencyLimit;
23
- declare const asPercentage: (n: number) => Percentage;
24
- declare const asStatusCode: (n: number) => StatusCode;
25
13
 
26
14
  /**
27
15
  * Modern typed error hierarchy with enhanced capabilities
28
16
  * Provides type-safe error handling with fluent API and metadata support
29
17
  */
30
18
 
31
- declare abstract class TypedError<Code extends string = string, Meta = unknown> extends Error {
19
+ declare abstract class TypedError<Code extends string = string, Meta extends Record<string, unknown> = Record<string, unknown>, Raw = unknown> extends Error {
32
20
  abstract readonly code: Code;
33
21
  readonly cause?: unknown;
34
- readonly meta?: Meta;
22
+ readonly meta: Meta;
35
23
  readonly status?: number;
24
+ readonly raw: Raw;
25
+ readonly path?: string;
36
26
  readonly timestamp: number;
37
27
  readonly retryable: boolean;
38
- constructor(message: string, opts?: {
28
+ constructor(message: string, opts: {
39
29
  cause?: unknown;
40
30
  meta?: Meta;
41
31
  status?: number;
42
32
  retryable?: boolean;
33
+ raw: Raw;
34
+ path?: string;
43
35
  });
44
36
  is<C extends string>(code: C): this is TypedError<C> & {
45
37
  code: C;
@@ -53,107 +45,88 @@ declare abstract class TypedError<Code extends string = string, Meta = unknown>
53
45
  withCause(cause: unknown): this & {
54
46
  cause: unknown;
55
47
  };
48
+ withPath(path: string): this;
49
+ withRaw<const R>(raw: R): this & {
50
+ raw: R;
51
+ };
56
52
  withRetryable(retryable: boolean): this;
57
53
  toJSON(): Record<string, unknown>;
58
54
  }
59
- declare class TimeoutError extends TypedError<'TIMEOUT'> {
55
+ type AnyTypedError = TypedError<string, any, unknown>;
56
+ declare class TimeoutError extends TypedError<'TIMEOUT', Record<string, unknown>, unknown> {
60
57
  readonly code: "TIMEOUT";
61
58
  constructor(timeout: Milliseconds, cause?: unknown);
62
59
  }
63
- declare class AbortedError extends TypedError<'ABORTED'> {
60
+ declare class AbortedError extends TypedError<'ABORTED', Record<string, unknown>, unknown> {
64
61
  readonly code: "ABORTED";
65
62
  constructor(reason?: string, cause?: unknown);
66
63
  }
67
- declare class CircuitOpenError extends TypedError<'CIRCUIT_OPEN'> {
64
+ declare class CircuitOpenError extends TypedError<'CIRCUIT_OPEN', Record<string, unknown>, unknown> {
68
65
  readonly code: "CIRCUIT_OPEN";
69
66
  constructor(resetAfter: Milliseconds, cause?: unknown);
70
67
  }
71
- type ValidationMeta = {
68
+ type ValidationMeta = Record<string, unknown> & {
72
69
  validationErrors: unknown[];
73
70
  };
74
- declare class ValidationError extends TypedError<'VALIDATION', ValidationMeta> {
71
+ declare class ValidationError extends TypedError<'VALIDATION', ValidationMeta, unknown> {
75
72
  readonly validationErrors: unknown[];
76
73
  readonly code: "VALIDATION";
77
74
  constructor(message: string, validationErrors: unknown[], cause?: unknown);
78
75
  }
79
- declare class NetworkError extends TypedError<'NETWORK'> {
76
+ declare class NetworkError extends TypedError<'NETWORK', Record<string, unknown>, unknown> {
80
77
  readonly statusCode?: number | undefined;
81
78
  readonly code: "NETWORK";
82
79
  constructor(message: string, statusCode?: number | undefined, cause?: unknown);
83
80
  }
84
- type HttpMeta = {
81
+ type HttpMeta = Record<string, unknown> & {
85
82
  response?: unknown;
86
83
  };
87
- declare class HttpError extends TypedError<'HTTP', HttpMeta> {
84
+ declare class HttpError extends TypedError<'HTTP', HttpMeta, unknown> {
88
85
  readonly status: number;
89
86
  readonly response?: unknown | undefined;
90
87
  readonly code: "HTTP";
91
88
  constructor(message: string, status: number, response?: unknown | undefined, cause?: unknown);
92
89
  }
93
- declare class UnknownError extends TypedError<'UNKNOWN'> {
90
+ declare class UnknownError extends TypedError<'UNKNOWN', Record<string, unknown>, unknown> {
94
91
  readonly code: "UNKNOWN";
95
92
  constructor(message: string, cause?: unknown);
96
93
  }
97
94
 
98
- /**
99
- * Modern circuit breaker implementation with enhanced state management
100
- * Provides circuit breaker pattern with type safety and observability
101
- */
102
-
103
- interface CircuitBreakerConfig<E extends TypedError = TypedError> {
104
- /** Number of consecutive failures before opening circuit */
105
- readonly failureThreshold: number;
106
- /** How long to wait before attempting to close circuit */
107
- readonly resetTimeout: number;
108
- /** Number of requests allowed in half-open state */
109
- readonly halfOpenRequests: number;
110
- /** Optional function to determine if error should count as failure */
111
- readonly shouldCountAsFailure?: (error: E) => boolean;
112
- }
113
-
114
- /**
115
- * Modern error normalization system
116
- * Provides type-safe error transformation and normalization
117
- */
118
-
119
- type ErrorNormalizer<E extends TypedError = TypedError> = (error: unknown) => E;
120
- type ErrorRule<E extends TypedError = TypedError> = (error: unknown) => E | null;
121
-
122
95
  /**
123
96
  * Modern result types with enhanced discriminated unions
124
97
  * Provides better type safety and more granular result categorization
125
98
  */
126
99
 
127
- type TryoResult<T, E extends TypedError = TypedError> = SuccessResult<T, E> | FailureResult<E> | AbortedResult<E> | TimeoutResult<E>;
128
- interface SuccessResult<T, E extends TypedError> {
100
+ type TryoResult<T, E extends AnyTypedError = AnyTypedError> = SuccessResult<T, E> | FailureResult<E> | AbortedResult<E> | TimeoutResult<E>;
101
+ interface SuccessResult<T, E extends AnyTypedError> {
129
102
  readonly type: 'success';
130
103
  readonly ok: true;
131
104
  readonly data: T;
132
105
  readonly error: null;
133
- readonly metrics?: TryoMetrics$1<E>;
106
+ readonly metrics: TryoMetrics$1<E>;
134
107
  }
135
- interface FailureResult<E extends TypedError> {
108
+ interface FailureResult<E extends AnyTypedError> {
136
109
  readonly type: 'failure';
137
110
  readonly ok: false;
138
111
  readonly data: null;
139
112
  readonly error: E;
140
- readonly metrics?: TryoMetrics$1<E>;
113
+ readonly metrics: TryoMetrics$1<E>;
141
114
  }
142
- interface AbortedResult<E extends TypedError> {
115
+ interface AbortedResult<E extends AnyTypedError> {
143
116
  readonly type: 'aborted';
144
117
  readonly ok: false;
145
118
  readonly data: null;
146
119
  readonly error: E;
147
- readonly metrics?: TryoMetrics$1<E>;
120
+ readonly metrics: TryoMetrics$1<E>;
148
121
  }
149
- interface TimeoutResult<E extends TypedError> {
122
+ interface TimeoutResult<E extends AnyTypedError> {
150
123
  readonly type: 'timeout';
151
124
  readonly ok: false;
152
125
  readonly data: null;
153
126
  readonly error: E;
154
- readonly metrics?: TryoMetrics$1<E>;
127
+ readonly metrics: TryoMetrics$1<E>;
155
128
  }
156
- interface TryoMetrics$1<E extends TypedError> {
129
+ interface TryoMetrics$1<E extends AnyTypedError> {
157
130
  readonly totalAttempts: RetryCount;
158
131
  readonly totalRetries: RetryCount;
159
132
  readonly totalDuration: Milliseconds;
@@ -166,6 +139,31 @@ interface TryoMetrics$1<E extends TypedError> {
166
139
  }>;
167
140
  }
168
141
 
142
+ /**
143
+ * Modern circuit breaker implementation with enhanced state management
144
+ * Provides circuit breaker pattern with type safety and observability
145
+ */
146
+
147
+ interface CircuitBreakerConfig<E extends AnyTypedError = AnyTypedError> {
148
+ /** Number of consecutive failures before opening circuit */
149
+ readonly failureThreshold: number;
150
+ /** How long to wait before attempting to close circuit */
151
+ readonly resetTimeout: number;
152
+ /** Number of requests allowed in half-open state */
153
+ readonly halfOpenRequests: number;
154
+ /** Optional function to determine if error should count as failure */
155
+ readonly shouldCountAsFailure?: (error: E) => boolean;
156
+ }
157
+ type CircuitState = 'closed' | 'open' | 'half-open';
158
+
159
+ /**
160
+ * Modern error normalization system
161
+ * Provides type-safe error transformation and normalization
162
+ */
163
+
164
+ type ErrorNormalizer<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E;
165
+ type ErrorRule<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E | null;
166
+
169
167
  /**
170
168
  * Modern retry strategies with enhanced capabilities
171
169
  * Provides various retry patterns with type safety
@@ -198,7 +196,7 @@ declare const RetryStrategies: {
198
196
  readonly custom: (calculate: (attempt: RetryCount, error: unknown) => number) => CustomDelayStrategy;
199
197
  };
200
198
 
201
- interface TryoConfig<E extends TypedError = TypedError> {
199
+ interface TryoConfig<E extends AnyTypedError = AnyTypedError> {
202
200
  /** Abort signal passed to tasks */
203
201
  readonly signal?: AbortSignal;
204
202
  /** If true, aborts are treated as non-throwing failures */
@@ -218,7 +216,7 @@ interface TryoConfig<E extends TypedError = TypedError> {
218
216
  /** Callback hooks */
219
217
  readonly hooks?: HookConfig<E>;
220
218
  }
221
- interface RetryConfig<E extends TypedError> {
219
+ interface RetryConfig<E extends AnyTypedError> {
222
220
  /** Maximum number of retry attempts */
223
221
  readonly maxRetries: number;
224
222
  /** Base delay strategy */
@@ -228,7 +226,7 @@ interface RetryConfig<E extends TypedError> {
228
226
  /** Function to determine if retry should be attempted */
229
227
  readonly shouldRetry?: ShouldRetryPredicate<E>;
230
228
  }
231
- type ShouldRetryPredicate<E extends TypedError> = (attempt: number, error: E, context: RetryContext) => boolean;
229
+ type ShouldRetryPredicate<E extends AnyTypedError> = (attempt: number, error: E, context: RetryContext) => boolean;
232
230
  interface RetryContext {
233
231
  /** Total attempts made so far */
234
232
  readonly totalAttempts: number;
@@ -239,13 +237,13 @@ interface RetryContext {
239
237
  /** Last delay applied */
240
238
  readonly lastDelay?: number;
241
239
  }
242
- interface ErrorHandlingConfig<E extends TypedError> {
240
+ interface ErrorHandlingConfig<E extends AnyTypedError> {
243
241
  /** Error normalizer function */
244
242
  readonly normalizer: ErrorNormalizer<E>;
245
243
  /** Optional error mapping/transformation */
246
244
  readonly mapError?: (error: E) => E;
247
245
  }
248
- interface LoggerConfig<E extends TypedError> {
246
+ interface LoggerConfig<E extends AnyTypedError> {
249
247
  /** Debug logging function */
250
248
  readonly debug?: (message: string, meta?: unknown) => void;
251
249
  /** Error logging function */
@@ -255,7 +253,7 @@ interface LoggerConfig<E extends TypedError> {
255
253
  /** Warning logging function */
256
254
  readonly warn?: (message: string, meta?: unknown) => void;
257
255
  }
258
- interface HookConfig<E extends TypedError> {
256
+ interface HookConfig<E extends AnyTypedError> {
259
257
  /** Called on successful execution */
260
258
  readonly onSuccess?: <T>(data: T, metrics?: TryoMetrics<E>) => void;
261
259
  /** Called on failed execution */
@@ -269,8 +267,7 @@ interface HookConfig<E extends TypedError> {
269
267
  /** Called when circuit breaker state changes */
270
268
  readonly onCircuitStateChange?: (from: CircuitState, to: CircuitState) => void;
271
269
  }
272
- type CircuitState = 'closed' | 'open' | 'half-open';
273
- type TryoMetrics<E extends TypedError> = TryoMetrics$1<E>;
270
+ type TryoMetrics<E extends AnyTypedError> = TryoMetrics$1<E>;
274
271
  type JitterConfig = {
275
272
  type: 'none';
276
273
  } | {
@@ -292,40 +289,51 @@ declare const JitterConfig: {
292
289
 
293
290
  type RulesMode = 'extend' | 'replace';
294
291
  type DefaultError = AbortedError | TimeoutError | NetworkError | HttpError | CircuitOpenError | ValidationError | UnknownError;
292
+ type RunOptions<E extends AnyTypedError> = Omit<Partial<TryoConfig<E>>, 'circuitBreaker'>;
293
+ type AllOptions<E extends AnyTypedError> = Omit<Partial<TryoConfig<E> & {
294
+ concurrency?: number;
295
+ }>, 'circuitBreaker'>;
296
+ type MaybePromise<T> = T | Promise<T>;
295
297
  type NonNull<T> = T extends null ? never : T;
296
298
  type RuleReturn<R> = R extends (err: unknown) => infer Out ? NonNull<Out> : never;
297
- type InferErrorFromRules<TRules extends readonly ErrorRule<TypedError>[]> = TRules extends readonly [] ? TypedError : RuleReturn<TRules[number]> | UnknownError;
298
- type TryoOptions<E extends TypedError = TypedError> = Omit<Partial<TryoConfig<E>>, 'errorHandling' | 'signal'> & {
299
+ type InferErrorFromRules<TRules extends readonly ErrorRule<AnyTypedError>[]> = TRules extends readonly [] ? TypedError : RuleReturn<TRules[number]> | UnknownError;
300
+ type TryoOptions<E extends AnyTypedError = AnyTypedError> = Omit<Partial<TryoConfig<E>>, 'errorHandling' | 'signal'> & {
299
301
  rules?: Array<ErrorRule<E>>;
300
302
  rulesMode?: RulesMode;
301
303
  fallback?: (err: unknown) => E;
302
304
  toError?: (err: unknown) => E;
303
305
  mapError?: (error: E) => E;
304
306
  };
305
- declare function tryo<const TRules extends readonly ErrorRule<TypedError>[]>(options: Omit<TryoOptions<InferErrorFromRules<TRules>>, 'rules'> & {
306
- rules: TRules;
307
+ type ExtractCode<R> = R extends (...args: any[]) => infer E ? E extends TypedError<any, any, any> | null ? E extends null ? never : E extends TypedError<infer C, any, any> ? string extends C ? never : C : never : never : never;
308
+ type CheckUniqueCodes<T extends readonly any[], Seen = never> = T extends readonly [infer Head, ...infer Tail] ? ExtractCode<Head> extends infer C ? [C] extends [never] ? CheckUniqueCodes<Tail, Seen> : [C] extends [Seen] ? {
309
+ error: '❌ ERROR: Código duplicado detectado';
310
+ code: C;
311
+ } : CheckUniqueCodes<Tail, Seen | C> : never : true;
312
+ declare function tryo<const TRules extends readonly ErrorRule<AnyTypedError>[]>(options: Omit<TryoOptions<InferErrorFromRules<TRules>>, 'rules' | 'rulesMode'> & {
313
+ rules: TRules & (CheckUniqueCodes<TRules> extends true ? unknown : CheckUniqueCodes<TRules>);
314
+ rulesMode: 'replace';
307
315
  }): Tryo<InferErrorFromRules<TRules>>;
308
- declare function tryo<E extends TypedError = DefaultError>(options?: TryoOptions<E>): Tryo<E>;
309
- type Tryo<E extends TypedError = TypedError> = {
316
+ declare function tryo<const TRules extends readonly ErrorRule<AnyTypedError>[]>(options: Omit<TryoOptions<InferErrorFromRules<TRules> | DefaultError>, 'rules'> & {
317
+ rules: TRules & (CheckUniqueCodes<TRules> extends true ? unknown : CheckUniqueCodes<TRules>);
318
+ rulesMode?: 'extend';
319
+ }): Tryo<InferErrorFromRules<TRules> | DefaultError>;
320
+ declare function tryo<E extends AnyTypedError = DefaultError>(options?: TryoOptions<E>): Tryo<E>;
321
+ type Tryo<E extends AnyTypedError = AnyTypedError> = {
310
322
  run: <T>(task: (ctx: {
311
323
  signal: AbortSignal;
312
- }) => Promise<T>, options?: Partial<TryoConfig<E>>) => Promise<TryoResult<T, E>>;
324
+ }) => MaybePromise<T>, options?: RunOptions<E>) => Promise<TryoResult<T, E>>;
313
325
  runOrThrow: <T>(task: (ctx: {
314
326
  signal: AbortSignal;
315
- }) => Promise<T>, options?: Partial<TryoConfig<E>>) => Promise<T>;
327
+ }) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
316
328
  orThrow: <T>(task: (ctx: {
317
329
  signal: AbortSignal;
318
- }) => Promise<T>, options?: Partial<TryoConfig<E>>) => Promise<T>;
330
+ }) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
319
331
  all: <T>(tasks: Array<(ctx: {
320
332
  signal: AbortSignal;
321
- }) => Promise<T>>, options?: Partial<TryoConfig<E> & {
322
- concurrency?: number;
323
- }>) => Promise<Array<TryoResult<T, E>>>;
333
+ }) => MaybePromise<T>>, options?: AllOptions<E>) => Promise<Array<TryoResult<T, E>>>;
324
334
  allOrThrow: <T>(tasks: Array<(ctx: {
325
335
  signal: AbortSignal;
326
- }) => Promise<T>>, options?: Partial<TryoConfig<E> & {
327
- concurrency?: number;
328
- }>) => Promise<T[]>;
336
+ }) => MaybePromise<T>>, options?: AllOptions<E>) => Promise<T[]>;
329
337
  partitionAll: <T>(results: Array<TryoResult<T, E>>) => {
330
338
  ok: Array<SuccessResult<T, E>>;
331
339
  errors: Array<FailureResult<E> | AbortedResult<E> | TimeoutResult<E>>;
@@ -338,23 +346,64 @@ type Tryo<E extends TypedError = TypedError> = {
338
346
 
339
347
  declare const run: <T>(task: (ctx: {
340
348
  signal: AbortSignal;
341
- }) => Promise<T>, options?: Partial<TryoConfig<DefaultError>> | undefined) => Promise<TryoResult<T, DefaultError>>;
349
+ }) => T | Promise<T>, options?: {
350
+ readonly timeout?: number | undefined;
351
+ readonly signal?: AbortSignal | undefined;
352
+ readonly ignoreAbort?: boolean | undefined;
353
+ readonly retry?: RetryConfig<DefaultError> | undefined;
354
+ readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
355
+ readonly concurrency?: number | undefined;
356
+ readonly logger?: LoggerConfig<DefaultError> | undefined;
357
+ readonly hooks?: HookConfig<DefaultError> | undefined;
358
+ } | undefined) => Promise<TryoResult<T, DefaultError>>;
342
359
  declare const runOrThrow: <T>(task: (ctx: {
343
360
  signal: AbortSignal;
344
- }) => Promise<T>, options?: Partial<TryoConfig<DefaultError>> | undefined) => Promise<T>;
361
+ }) => T | Promise<T>, options?: {
362
+ readonly timeout?: number | undefined;
363
+ readonly signal?: AbortSignal | undefined;
364
+ readonly ignoreAbort?: boolean | undefined;
365
+ readonly retry?: RetryConfig<DefaultError> | undefined;
366
+ readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
367
+ readonly concurrency?: number | undefined;
368
+ readonly logger?: LoggerConfig<DefaultError> | undefined;
369
+ readonly hooks?: HookConfig<DefaultError> | undefined;
370
+ } | undefined) => Promise<T>;
345
371
  declare const orThrow: <T>(task: (ctx: {
346
372
  signal: AbortSignal;
347
- }) => Promise<T>, options?: Partial<TryoConfig<DefaultError>> | undefined) => Promise<T>;
373
+ }) => T | Promise<T>, options?: {
374
+ readonly timeout?: number | undefined;
375
+ readonly signal?: AbortSignal | undefined;
376
+ readonly ignoreAbort?: boolean | undefined;
377
+ readonly retry?: RetryConfig<DefaultError> | undefined;
378
+ readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
379
+ readonly concurrency?: number | undefined;
380
+ readonly logger?: LoggerConfig<DefaultError> | undefined;
381
+ readonly hooks?: HookConfig<DefaultError> | undefined;
382
+ } | undefined) => Promise<T>;
348
383
  declare const all: <T>(tasks: ((ctx: {
349
384
  signal: AbortSignal;
350
- }) => Promise<T>)[], options?: Partial<TryoConfig<DefaultError> & {
351
- concurrency?: number;
352
- }> | undefined) => Promise<TryoResult<T, DefaultError>[]>;
385
+ }) => T | Promise<T>)[], options?: {
386
+ readonly timeout?: number | undefined;
387
+ readonly signal?: AbortSignal | undefined;
388
+ readonly ignoreAbort?: boolean | undefined;
389
+ readonly retry?: RetryConfig<DefaultError> | undefined;
390
+ readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
391
+ concurrency?: number | undefined;
392
+ readonly logger?: LoggerConfig<DefaultError> | undefined;
393
+ readonly hooks?: HookConfig<DefaultError> | undefined;
394
+ } | undefined) => Promise<TryoResult<T, DefaultError>[]>;
353
395
  declare const allOrThrow: <T>(tasks: ((ctx: {
354
396
  signal: AbortSignal;
355
- }) => Promise<T>)[], options?: Partial<TryoConfig<DefaultError> & {
356
- concurrency?: number;
357
- }> | undefined) => Promise<T[]>;
397
+ }) => T | Promise<T>)[], options?: {
398
+ readonly timeout?: number | undefined;
399
+ readonly signal?: AbortSignal | undefined;
400
+ readonly ignoreAbort?: boolean | undefined;
401
+ readonly retry?: RetryConfig<DefaultError> | undefined;
402
+ readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
403
+ concurrency?: number | undefined;
404
+ readonly logger?: LoggerConfig<DefaultError> | undefined;
405
+ readonly hooks?: HookConfig<DefaultError> | undefined;
406
+ } | undefined) => Promise<T[]>;
358
407
 
359
408
  /**
360
409
  * Modern fluent error rule builder
@@ -368,23 +417,27 @@ declare class ErrorRuleBuilder<T> {
368
417
  toError<const Out extends {
369
418
  code: string;
370
419
  message: string;
371
- meta?: unknown;
420
+ meta?: Record<string, unknown>;
372
421
  status?: number;
373
422
  cause?: unknown;
374
423
  retryable?: boolean;
375
- }>(mapper: (err: T) => Out): ErrorRule<TypedError<Out['code'], Out['meta']>>;
424
+ raw?: any;
425
+ path?: string;
426
+ }>(mapper: (err: T) => Out): ErrorRule<TypedError<Out['code'], Out['meta'] extends Record<string, unknown> ? Out['meta'] : Record<string, unknown>, unknown extends Out['raw'] ? T : Out['raw']>>;
376
427
  }
377
428
  declare class ErrorMapper<T, C extends string> {
378
429
  private readonly predicate;
379
430
  private readonly errorCode;
380
431
  constructor(predicate: (err: unknown) => err is T, errorCode: C);
381
- with<const M = unknown>(mapper: (err: T) => {
432
+ with<const M extends Record<string, unknown> = Record<string, unknown>, const R = '__NOT_SET__'>(mapper: (err: T) => {
382
433
  message: string;
383
434
  cause?: unknown;
384
435
  meta?: M;
385
436
  status?: number;
386
437
  retryable?: boolean;
387
- }): (err: unknown) => TypedError<C, M> | null;
438
+ raw?: R;
439
+ path?: string;
440
+ }): ErrorRule<TypedError<C, M, R extends '__NOT_SET__' ? T : R>>;
388
441
  }
389
442
 
390
443
  declare const errorRule: {
@@ -392,4 +445,4 @@ declare const errorRule: {
392
445
  readonly instance: <T extends new (...args: unknown[]) => unknown>(ErrorClass: T) => ErrorRuleBuilder<InstanceType<T>>;
393
446
  };
394
447
 
395
- export { type AbortedResult, type ConcurrencyLimit, type FailureResult, type Milliseconds, type Percentage, type RetryCount, RetryStrategies, type RulesMode, type StatusCode, type SuccessResult, type TimeoutResult, type TryoConfig, type TryoMetrics$1 as TryoMetrics, type TryoOptions, type TryoResult, all, allOrThrow, asConcurrencyLimit, asMilliseconds, asPercentage, asRetryCount, asStatusCode, errorRule, orThrow, run, runOrThrow, tryo };
448
+ 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 };
package/dist/index.d.ts CHANGED
@@ -8,38 +8,30 @@ type Milliseconds = number & {
8
8
  type RetryCount = number & {
9
9
  readonly __brand: 'RetryCount';
10
10
  };
11
- type ConcurrencyLimit = number & {
12
- readonly __brand: 'ConcurrencyLimit';
13
- };
14
- type Percentage = number & {
15
- readonly __brand: 'Percentage';
16
- };
17
- type StatusCode = number & {
18
- readonly __brand: 'StatusCode';
19
- };
20
11
  declare const asMilliseconds: (n: number) => Milliseconds;
21
12
  declare const asRetryCount: (n: number) => RetryCount;
22
- declare const asConcurrencyLimit: (n: number) => ConcurrencyLimit;
23
- declare const asPercentage: (n: number) => Percentage;
24
- declare const asStatusCode: (n: number) => StatusCode;
25
13
 
26
14
  /**
27
15
  * Modern typed error hierarchy with enhanced capabilities
28
16
  * Provides type-safe error handling with fluent API and metadata support
29
17
  */
30
18
 
31
- declare abstract class TypedError<Code extends string = string, Meta = unknown> extends Error {
19
+ declare abstract class TypedError<Code extends string = string, Meta extends Record<string, unknown> = Record<string, unknown>, Raw = unknown> extends Error {
32
20
  abstract readonly code: Code;
33
21
  readonly cause?: unknown;
34
- readonly meta?: Meta;
22
+ readonly meta: Meta;
35
23
  readonly status?: number;
24
+ readonly raw: Raw;
25
+ readonly path?: string;
36
26
  readonly timestamp: number;
37
27
  readonly retryable: boolean;
38
- constructor(message: string, opts?: {
28
+ constructor(message: string, opts: {
39
29
  cause?: unknown;
40
30
  meta?: Meta;
41
31
  status?: number;
42
32
  retryable?: boolean;
33
+ raw: Raw;
34
+ path?: string;
43
35
  });
44
36
  is<C extends string>(code: C): this is TypedError<C> & {
45
37
  code: C;
@@ -53,107 +45,88 @@ declare abstract class TypedError<Code extends string = string, Meta = unknown>
53
45
  withCause(cause: unknown): this & {
54
46
  cause: unknown;
55
47
  };
48
+ withPath(path: string): this;
49
+ withRaw<const R>(raw: R): this & {
50
+ raw: R;
51
+ };
56
52
  withRetryable(retryable: boolean): this;
57
53
  toJSON(): Record<string, unknown>;
58
54
  }
59
- declare class TimeoutError extends TypedError<'TIMEOUT'> {
55
+ type AnyTypedError = TypedError<string, any, unknown>;
56
+ declare class TimeoutError extends TypedError<'TIMEOUT', Record<string, unknown>, unknown> {
60
57
  readonly code: "TIMEOUT";
61
58
  constructor(timeout: Milliseconds, cause?: unknown);
62
59
  }
63
- declare class AbortedError extends TypedError<'ABORTED'> {
60
+ declare class AbortedError extends TypedError<'ABORTED', Record<string, unknown>, unknown> {
64
61
  readonly code: "ABORTED";
65
62
  constructor(reason?: string, cause?: unknown);
66
63
  }
67
- declare class CircuitOpenError extends TypedError<'CIRCUIT_OPEN'> {
64
+ declare class CircuitOpenError extends TypedError<'CIRCUIT_OPEN', Record<string, unknown>, unknown> {
68
65
  readonly code: "CIRCUIT_OPEN";
69
66
  constructor(resetAfter: Milliseconds, cause?: unknown);
70
67
  }
71
- type ValidationMeta = {
68
+ type ValidationMeta = Record<string, unknown> & {
72
69
  validationErrors: unknown[];
73
70
  };
74
- declare class ValidationError extends TypedError<'VALIDATION', ValidationMeta> {
71
+ declare class ValidationError extends TypedError<'VALIDATION', ValidationMeta, unknown> {
75
72
  readonly validationErrors: unknown[];
76
73
  readonly code: "VALIDATION";
77
74
  constructor(message: string, validationErrors: unknown[], cause?: unknown);
78
75
  }
79
- declare class NetworkError extends TypedError<'NETWORK'> {
76
+ declare class NetworkError extends TypedError<'NETWORK', Record<string, unknown>, unknown> {
80
77
  readonly statusCode?: number | undefined;
81
78
  readonly code: "NETWORK";
82
79
  constructor(message: string, statusCode?: number | undefined, cause?: unknown);
83
80
  }
84
- type HttpMeta = {
81
+ type HttpMeta = Record<string, unknown> & {
85
82
  response?: unknown;
86
83
  };
87
- declare class HttpError extends TypedError<'HTTP', HttpMeta> {
84
+ declare class HttpError extends TypedError<'HTTP', HttpMeta, unknown> {
88
85
  readonly status: number;
89
86
  readonly response?: unknown | undefined;
90
87
  readonly code: "HTTP";
91
88
  constructor(message: string, status: number, response?: unknown | undefined, cause?: unknown);
92
89
  }
93
- declare class UnknownError extends TypedError<'UNKNOWN'> {
90
+ declare class UnknownError extends TypedError<'UNKNOWN', Record<string, unknown>, unknown> {
94
91
  readonly code: "UNKNOWN";
95
92
  constructor(message: string, cause?: unknown);
96
93
  }
97
94
 
98
- /**
99
- * Modern circuit breaker implementation with enhanced state management
100
- * Provides circuit breaker pattern with type safety and observability
101
- */
102
-
103
- interface CircuitBreakerConfig<E extends TypedError = TypedError> {
104
- /** Number of consecutive failures before opening circuit */
105
- readonly failureThreshold: number;
106
- /** How long to wait before attempting to close circuit */
107
- readonly resetTimeout: number;
108
- /** Number of requests allowed in half-open state */
109
- readonly halfOpenRequests: number;
110
- /** Optional function to determine if error should count as failure */
111
- readonly shouldCountAsFailure?: (error: E) => boolean;
112
- }
113
-
114
- /**
115
- * Modern error normalization system
116
- * Provides type-safe error transformation and normalization
117
- */
118
-
119
- type ErrorNormalizer<E extends TypedError = TypedError> = (error: unknown) => E;
120
- type ErrorRule<E extends TypedError = TypedError> = (error: unknown) => E | null;
121
-
122
95
  /**
123
96
  * Modern result types with enhanced discriminated unions
124
97
  * Provides better type safety and more granular result categorization
125
98
  */
126
99
 
127
- type TryoResult<T, E extends TypedError = TypedError> = SuccessResult<T, E> | FailureResult<E> | AbortedResult<E> | TimeoutResult<E>;
128
- interface SuccessResult<T, E extends TypedError> {
100
+ type TryoResult<T, E extends AnyTypedError = AnyTypedError> = SuccessResult<T, E> | FailureResult<E> | AbortedResult<E> | TimeoutResult<E>;
101
+ interface SuccessResult<T, E extends AnyTypedError> {
129
102
  readonly type: 'success';
130
103
  readonly ok: true;
131
104
  readonly data: T;
132
105
  readonly error: null;
133
- readonly metrics?: TryoMetrics$1<E>;
106
+ readonly metrics: TryoMetrics$1<E>;
134
107
  }
135
- interface FailureResult<E extends TypedError> {
108
+ interface FailureResult<E extends AnyTypedError> {
136
109
  readonly type: 'failure';
137
110
  readonly ok: false;
138
111
  readonly data: null;
139
112
  readonly error: E;
140
- readonly metrics?: TryoMetrics$1<E>;
113
+ readonly metrics: TryoMetrics$1<E>;
141
114
  }
142
- interface AbortedResult<E extends TypedError> {
115
+ interface AbortedResult<E extends AnyTypedError> {
143
116
  readonly type: 'aborted';
144
117
  readonly ok: false;
145
118
  readonly data: null;
146
119
  readonly error: E;
147
- readonly metrics?: TryoMetrics$1<E>;
120
+ readonly metrics: TryoMetrics$1<E>;
148
121
  }
149
- interface TimeoutResult<E extends TypedError> {
122
+ interface TimeoutResult<E extends AnyTypedError> {
150
123
  readonly type: 'timeout';
151
124
  readonly ok: false;
152
125
  readonly data: null;
153
126
  readonly error: E;
154
- readonly metrics?: TryoMetrics$1<E>;
127
+ readonly metrics: TryoMetrics$1<E>;
155
128
  }
156
- interface TryoMetrics$1<E extends TypedError> {
129
+ interface TryoMetrics$1<E extends AnyTypedError> {
157
130
  readonly totalAttempts: RetryCount;
158
131
  readonly totalRetries: RetryCount;
159
132
  readonly totalDuration: Milliseconds;
@@ -166,6 +139,31 @@ interface TryoMetrics$1<E extends TypedError> {
166
139
  }>;
167
140
  }
168
141
 
142
+ /**
143
+ * Modern circuit breaker implementation with enhanced state management
144
+ * Provides circuit breaker pattern with type safety and observability
145
+ */
146
+
147
+ interface CircuitBreakerConfig<E extends AnyTypedError = AnyTypedError> {
148
+ /** Number of consecutive failures before opening circuit */
149
+ readonly failureThreshold: number;
150
+ /** How long to wait before attempting to close circuit */
151
+ readonly resetTimeout: number;
152
+ /** Number of requests allowed in half-open state */
153
+ readonly halfOpenRequests: number;
154
+ /** Optional function to determine if error should count as failure */
155
+ readonly shouldCountAsFailure?: (error: E) => boolean;
156
+ }
157
+ type CircuitState = 'closed' | 'open' | 'half-open';
158
+
159
+ /**
160
+ * Modern error normalization system
161
+ * Provides type-safe error transformation and normalization
162
+ */
163
+
164
+ type ErrorNormalizer<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E;
165
+ type ErrorRule<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E | null;
166
+
169
167
  /**
170
168
  * Modern retry strategies with enhanced capabilities
171
169
  * Provides various retry patterns with type safety
@@ -198,7 +196,7 @@ declare const RetryStrategies: {
198
196
  readonly custom: (calculate: (attempt: RetryCount, error: unknown) => number) => CustomDelayStrategy;
199
197
  };
200
198
 
201
- interface TryoConfig<E extends TypedError = TypedError> {
199
+ interface TryoConfig<E extends AnyTypedError = AnyTypedError> {
202
200
  /** Abort signal passed to tasks */
203
201
  readonly signal?: AbortSignal;
204
202
  /** If true, aborts are treated as non-throwing failures */
@@ -218,7 +216,7 @@ interface TryoConfig<E extends TypedError = TypedError> {
218
216
  /** Callback hooks */
219
217
  readonly hooks?: HookConfig<E>;
220
218
  }
221
- interface RetryConfig<E extends TypedError> {
219
+ interface RetryConfig<E extends AnyTypedError> {
222
220
  /** Maximum number of retry attempts */
223
221
  readonly maxRetries: number;
224
222
  /** Base delay strategy */
@@ -228,7 +226,7 @@ interface RetryConfig<E extends TypedError> {
228
226
  /** Function to determine if retry should be attempted */
229
227
  readonly shouldRetry?: ShouldRetryPredicate<E>;
230
228
  }
231
- type ShouldRetryPredicate<E extends TypedError> = (attempt: number, error: E, context: RetryContext) => boolean;
229
+ type ShouldRetryPredicate<E extends AnyTypedError> = (attempt: number, error: E, context: RetryContext) => boolean;
232
230
  interface RetryContext {
233
231
  /** Total attempts made so far */
234
232
  readonly totalAttempts: number;
@@ -239,13 +237,13 @@ interface RetryContext {
239
237
  /** Last delay applied */
240
238
  readonly lastDelay?: number;
241
239
  }
242
- interface ErrorHandlingConfig<E extends TypedError> {
240
+ interface ErrorHandlingConfig<E extends AnyTypedError> {
243
241
  /** Error normalizer function */
244
242
  readonly normalizer: ErrorNormalizer<E>;
245
243
  /** Optional error mapping/transformation */
246
244
  readonly mapError?: (error: E) => E;
247
245
  }
248
- interface LoggerConfig<E extends TypedError> {
246
+ interface LoggerConfig<E extends AnyTypedError> {
249
247
  /** Debug logging function */
250
248
  readonly debug?: (message: string, meta?: unknown) => void;
251
249
  /** Error logging function */
@@ -255,7 +253,7 @@ interface LoggerConfig<E extends TypedError> {
255
253
  /** Warning logging function */
256
254
  readonly warn?: (message: string, meta?: unknown) => void;
257
255
  }
258
- interface HookConfig<E extends TypedError> {
256
+ interface HookConfig<E extends AnyTypedError> {
259
257
  /** Called on successful execution */
260
258
  readonly onSuccess?: <T>(data: T, metrics?: TryoMetrics<E>) => void;
261
259
  /** Called on failed execution */
@@ -269,8 +267,7 @@ interface HookConfig<E extends TypedError> {
269
267
  /** Called when circuit breaker state changes */
270
268
  readonly onCircuitStateChange?: (from: CircuitState, to: CircuitState) => void;
271
269
  }
272
- type CircuitState = 'closed' | 'open' | 'half-open';
273
- type TryoMetrics<E extends TypedError> = TryoMetrics$1<E>;
270
+ type TryoMetrics<E extends AnyTypedError> = TryoMetrics$1<E>;
274
271
  type JitterConfig = {
275
272
  type: 'none';
276
273
  } | {
@@ -292,40 +289,51 @@ declare const JitterConfig: {
292
289
 
293
290
  type RulesMode = 'extend' | 'replace';
294
291
  type DefaultError = AbortedError | TimeoutError | NetworkError | HttpError | CircuitOpenError | ValidationError | UnknownError;
292
+ type RunOptions<E extends AnyTypedError> = Omit<Partial<TryoConfig<E>>, 'circuitBreaker'>;
293
+ type AllOptions<E extends AnyTypedError> = Omit<Partial<TryoConfig<E> & {
294
+ concurrency?: number;
295
+ }>, 'circuitBreaker'>;
296
+ type MaybePromise<T> = T | Promise<T>;
295
297
  type NonNull<T> = T extends null ? never : T;
296
298
  type RuleReturn<R> = R extends (err: unknown) => infer Out ? NonNull<Out> : never;
297
- type InferErrorFromRules<TRules extends readonly ErrorRule<TypedError>[]> = TRules extends readonly [] ? TypedError : RuleReturn<TRules[number]> | UnknownError;
298
- type TryoOptions<E extends TypedError = TypedError> = Omit<Partial<TryoConfig<E>>, 'errorHandling' | 'signal'> & {
299
+ type InferErrorFromRules<TRules extends readonly ErrorRule<AnyTypedError>[]> = TRules extends readonly [] ? TypedError : RuleReturn<TRules[number]> | UnknownError;
300
+ type TryoOptions<E extends AnyTypedError = AnyTypedError> = Omit<Partial<TryoConfig<E>>, 'errorHandling' | 'signal'> & {
299
301
  rules?: Array<ErrorRule<E>>;
300
302
  rulesMode?: RulesMode;
301
303
  fallback?: (err: unknown) => E;
302
304
  toError?: (err: unknown) => E;
303
305
  mapError?: (error: E) => E;
304
306
  };
305
- declare function tryo<const TRules extends readonly ErrorRule<TypedError>[]>(options: Omit<TryoOptions<InferErrorFromRules<TRules>>, 'rules'> & {
306
- rules: TRules;
307
+ type ExtractCode<R> = R extends (...args: any[]) => infer E ? E extends TypedError<any, any, any> | null ? E extends null ? never : E extends TypedError<infer C, any, any> ? string extends C ? never : C : never : never : never;
308
+ type CheckUniqueCodes<T extends readonly any[], Seen = never> = T extends readonly [infer Head, ...infer Tail] ? ExtractCode<Head> extends infer C ? [C] extends [never] ? CheckUniqueCodes<Tail, Seen> : [C] extends [Seen] ? {
309
+ error: '❌ ERROR: Código duplicado detectado';
310
+ code: C;
311
+ } : CheckUniqueCodes<Tail, Seen | C> : never : true;
312
+ declare function tryo<const TRules extends readonly ErrorRule<AnyTypedError>[]>(options: Omit<TryoOptions<InferErrorFromRules<TRules>>, 'rules' | 'rulesMode'> & {
313
+ rules: TRules & (CheckUniqueCodes<TRules> extends true ? unknown : CheckUniqueCodes<TRules>);
314
+ rulesMode: 'replace';
307
315
  }): Tryo<InferErrorFromRules<TRules>>;
308
- declare function tryo<E extends TypedError = DefaultError>(options?: TryoOptions<E>): Tryo<E>;
309
- type Tryo<E extends TypedError = TypedError> = {
316
+ declare function tryo<const TRules extends readonly ErrorRule<AnyTypedError>[]>(options: Omit<TryoOptions<InferErrorFromRules<TRules> | DefaultError>, 'rules'> & {
317
+ rules: TRules & (CheckUniqueCodes<TRules> extends true ? unknown : CheckUniqueCodes<TRules>);
318
+ rulesMode?: 'extend';
319
+ }): Tryo<InferErrorFromRules<TRules> | DefaultError>;
320
+ declare function tryo<E extends AnyTypedError = DefaultError>(options?: TryoOptions<E>): Tryo<E>;
321
+ type Tryo<E extends AnyTypedError = AnyTypedError> = {
310
322
  run: <T>(task: (ctx: {
311
323
  signal: AbortSignal;
312
- }) => Promise<T>, options?: Partial<TryoConfig<E>>) => Promise<TryoResult<T, E>>;
324
+ }) => MaybePromise<T>, options?: RunOptions<E>) => Promise<TryoResult<T, E>>;
313
325
  runOrThrow: <T>(task: (ctx: {
314
326
  signal: AbortSignal;
315
- }) => Promise<T>, options?: Partial<TryoConfig<E>>) => Promise<T>;
327
+ }) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
316
328
  orThrow: <T>(task: (ctx: {
317
329
  signal: AbortSignal;
318
- }) => Promise<T>, options?: Partial<TryoConfig<E>>) => Promise<T>;
330
+ }) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
319
331
  all: <T>(tasks: Array<(ctx: {
320
332
  signal: AbortSignal;
321
- }) => Promise<T>>, options?: Partial<TryoConfig<E> & {
322
- concurrency?: number;
323
- }>) => Promise<Array<TryoResult<T, E>>>;
333
+ }) => MaybePromise<T>>, options?: AllOptions<E>) => Promise<Array<TryoResult<T, E>>>;
324
334
  allOrThrow: <T>(tasks: Array<(ctx: {
325
335
  signal: AbortSignal;
326
- }) => Promise<T>>, options?: Partial<TryoConfig<E> & {
327
- concurrency?: number;
328
- }>) => Promise<T[]>;
336
+ }) => MaybePromise<T>>, options?: AllOptions<E>) => Promise<T[]>;
329
337
  partitionAll: <T>(results: Array<TryoResult<T, E>>) => {
330
338
  ok: Array<SuccessResult<T, E>>;
331
339
  errors: Array<FailureResult<E> | AbortedResult<E> | TimeoutResult<E>>;
@@ -338,23 +346,64 @@ type Tryo<E extends TypedError = TypedError> = {
338
346
 
339
347
  declare const run: <T>(task: (ctx: {
340
348
  signal: AbortSignal;
341
- }) => Promise<T>, options?: Partial<TryoConfig<DefaultError>> | undefined) => Promise<TryoResult<T, DefaultError>>;
349
+ }) => T | Promise<T>, options?: {
350
+ readonly timeout?: number | undefined;
351
+ readonly signal?: AbortSignal | undefined;
352
+ readonly ignoreAbort?: boolean | undefined;
353
+ readonly retry?: RetryConfig<DefaultError> | undefined;
354
+ readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
355
+ readonly concurrency?: number | undefined;
356
+ readonly logger?: LoggerConfig<DefaultError> | undefined;
357
+ readonly hooks?: HookConfig<DefaultError> | undefined;
358
+ } | undefined) => Promise<TryoResult<T, DefaultError>>;
342
359
  declare const runOrThrow: <T>(task: (ctx: {
343
360
  signal: AbortSignal;
344
- }) => Promise<T>, options?: Partial<TryoConfig<DefaultError>> | undefined) => Promise<T>;
361
+ }) => T | Promise<T>, options?: {
362
+ readonly timeout?: number | undefined;
363
+ readonly signal?: AbortSignal | undefined;
364
+ readonly ignoreAbort?: boolean | undefined;
365
+ readonly retry?: RetryConfig<DefaultError> | undefined;
366
+ readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
367
+ readonly concurrency?: number | undefined;
368
+ readonly logger?: LoggerConfig<DefaultError> | undefined;
369
+ readonly hooks?: HookConfig<DefaultError> | undefined;
370
+ } | undefined) => Promise<T>;
345
371
  declare const orThrow: <T>(task: (ctx: {
346
372
  signal: AbortSignal;
347
- }) => Promise<T>, options?: Partial<TryoConfig<DefaultError>> | undefined) => Promise<T>;
373
+ }) => T | Promise<T>, options?: {
374
+ readonly timeout?: number | undefined;
375
+ readonly signal?: AbortSignal | undefined;
376
+ readonly ignoreAbort?: boolean | undefined;
377
+ readonly retry?: RetryConfig<DefaultError> | undefined;
378
+ readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
379
+ readonly concurrency?: number | undefined;
380
+ readonly logger?: LoggerConfig<DefaultError> | undefined;
381
+ readonly hooks?: HookConfig<DefaultError> | undefined;
382
+ } | undefined) => Promise<T>;
348
383
  declare const all: <T>(tasks: ((ctx: {
349
384
  signal: AbortSignal;
350
- }) => Promise<T>)[], options?: Partial<TryoConfig<DefaultError> & {
351
- concurrency?: number;
352
- }> | undefined) => Promise<TryoResult<T, DefaultError>[]>;
385
+ }) => T | Promise<T>)[], options?: {
386
+ readonly timeout?: number | undefined;
387
+ readonly signal?: AbortSignal | undefined;
388
+ readonly ignoreAbort?: boolean | undefined;
389
+ readonly retry?: RetryConfig<DefaultError> | undefined;
390
+ readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
391
+ concurrency?: number | undefined;
392
+ readonly logger?: LoggerConfig<DefaultError> | undefined;
393
+ readonly hooks?: HookConfig<DefaultError> | undefined;
394
+ } | undefined) => Promise<TryoResult<T, DefaultError>[]>;
353
395
  declare const allOrThrow: <T>(tasks: ((ctx: {
354
396
  signal: AbortSignal;
355
- }) => Promise<T>)[], options?: Partial<TryoConfig<DefaultError> & {
356
- concurrency?: number;
357
- }> | undefined) => Promise<T[]>;
397
+ }) => T | Promise<T>)[], options?: {
398
+ readonly timeout?: number | undefined;
399
+ readonly signal?: AbortSignal | undefined;
400
+ readonly ignoreAbort?: boolean | undefined;
401
+ readonly retry?: RetryConfig<DefaultError> | undefined;
402
+ readonly errorHandling?: ErrorHandlingConfig<DefaultError> | undefined;
403
+ concurrency?: number | undefined;
404
+ readonly logger?: LoggerConfig<DefaultError> | undefined;
405
+ readonly hooks?: HookConfig<DefaultError> | undefined;
406
+ } | undefined) => Promise<T[]>;
358
407
 
359
408
  /**
360
409
  * Modern fluent error rule builder
@@ -368,23 +417,27 @@ declare class ErrorRuleBuilder<T> {
368
417
  toError<const Out extends {
369
418
  code: string;
370
419
  message: string;
371
- meta?: unknown;
420
+ meta?: Record<string, unknown>;
372
421
  status?: number;
373
422
  cause?: unknown;
374
423
  retryable?: boolean;
375
- }>(mapper: (err: T) => Out): ErrorRule<TypedError<Out['code'], Out['meta']>>;
424
+ raw?: any;
425
+ path?: string;
426
+ }>(mapper: (err: T) => Out): ErrorRule<TypedError<Out['code'], Out['meta'] extends Record<string, unknown> ? Out['meta'] : Record<string, unknown>, unknown extends Out['raw'] ? T : Out['raw']>>;
376
427
  }
377
428
  declare class ErrorMapper<T, C extends string> {
378
429
  private readonly predicate;
379
430
  private readonly errorCode;
380
431
  constructor(predicate: (err: unknown) => err is T, errorCode: C);
381
- with<const M = unknown>(mapper: (err: T) => {
432
+ with<const M extends Record<string, unknown> = Record<string, unknown>, const R = '__NOT_SET__'>(mapper: (err: T) => {
382
433
  message: string;
383
434
  cause?: unknown;
384
435
  meta?: M;
385
436
  status?: number;
386
437
  retryable?: boolean;
387
- }): (err: unknown) => TypedError<C, M> | null;
438
+ raw?: R;
439
+ path?: string;
440
+ }): ErrorRule<TypedError<C, M, R extends '__NOT_SET__' ? T : R>>;
388
441
  }
389
442
 
390
443
  declare const errorRule: {
@@ -392,4 +445,4 @@ declare const errorRule: {
392
445
  readonly instance: <T extends new (...args: unknown[]) => unknown>(ErrorClass: T) => ErrorRuleBuilder<InstanceType<T>>;
393
446
  };
394
447
 
395
- export { type AbortedResult, type ConcurrencyLimit, type FailureResult, type Milliseconds, type Percentage, type RetryCount, RetryStrategies, type RulesMode, type StatusCode, type SuccessResult, type TimeoutResult, type TryoConfig, type TryoMetrics$1 as TryoMetrics, type TryoOptions, type TryoResult, all, allOrThrow, asConcurrencyLimit, asMilliseconds, asPercentage, asRetryCount, asStatusCode, errorRule, orThrow, run, runOrThrow, tryo };
448
+ 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 };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var j=Object.defineProperty;var ee=(e,r,t)=>r in e?j(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t;var m=(e,r,t)=>ee(e,typeof r!="symbol"?r+"":r,t);var T=class extends Error{constructor(t,n){var o;super(t);m(this,"cause");m(this,"meta");m(this,"status");m(this,"timestamp");m(this,"retryable");this.timestamp=Date.now(),this.retryable=(o=n==null?void 0:n.retryable)!=null?o:!0,this.name=this.constructor.name,this.cause=n==null?void 0:n.cause,this.meta=n==null?void 0:n.meta,this.status=n==null?void 0:n.status,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})}withRetryable(t){return this.retryable=t,this}toJSON(){return{name:this.name,code:this.code,message:this.message,timestamp:this.timestamp,retryable:this.retryable,cause:this.cause,stack:this.stack}}},D=class extends T{constructor(t,n){super(`Operation timed out after ${t}ms`,{cause:n,retryable:!0});m(this,"code","TIMEOUT")}};var g=class extends T{constructor(t,n){super(`Circuit breaker is open, reset after ${t}ms`,{cause:n,retryable:!1});m(this,"code","CIRCUIT_OPEN")}},v=class extends T{constructor(t,n,o){super(t,{cause:o,meta:{validationErrors:n},retryable:!1});this.validationErrors=n;m(this,"code","VALIDATION")}};var I=class extends T{constructor(t,n){super(t,{cause:n});m(this,"code","UNKNOWN")}};var x=e=>{if(e<0||!Number.isFinite(e))throw new Error(`Invalid milliseconds: must be a non-negative finite number, got ${e}`);return e},A=e=>{if(e<0||!Number.isInteger(e))throw new Error(`Invalid retry count: must be a non-negative integer, got ${e}`);return e},_=e=>{if(e<1||!Number.isInteger(e))throw new Error(`Invalid concurrency limit: must be a positive integer, got ${e}`);return e},re=e=>{if(e<0||e>100||!Number.isFinite(e))throw new Error(`Invalid percentage: must be between 0 and 100, got ${e}`);return e},te=e=>{if(!Number.isInteger(e)||e<100||e>599)throw new Error(`Invalid status code: must be an integer between 100-599, got ${e}`);return e};var F=class{constructor(r){m(this,"state");m(this,"config");this.config={failureThreshold:A(r.failureThreshold),resetTimeout:x(r.resetTimeout),halfOpenRequests:A(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,i;if(!((i=(a=(o=this.config).shouldCountAsFailure)==null?void 0:a.call(o,r))!=null?i:!0))return;let n=new Date;switch(this.state.state){case"closed":{let s=this.state.failureCount+1;s>=this.config.failureThreshold?this.state={state:"open",failureCount:s,halfOpenCount:0,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)}:this.state={...this.state,failureCount:s,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?x(Math.max(0,this.state.nextAttemptTime.getTime()-Date.now())):this.config.resetTimeout;return new g(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 W=(e,r)=>t=>{for(let n of e){let o=n(t);if(o!==null)return o}return r(t)},J=e=>r=>r instanceof T?r:r instanceof Error?new e(r.message,r):typeof r=="string"?new e(r):new e("Unknown error occurred",r);var ne=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.status=="number"||typeof r.statusCode=="number"},oe=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){if(e.name==="TypeError")return!0;let t=e.message.toLowerCase();if(t.includes("fetch")&&t.includes("failed")||t.includes("network"))return!0}if(oe(e)){let t=((r=e.code)!=null?r:"").toUpperCase();return t==="ECONNRESET"||t==="ECONNREFUSED"||t==="ETIMEDOUT"||t==="ENOTFOUND"||t==="EAI_AGAIN"}return!1},B=class{constructor(r){this.predicate=r}toCode(r){return new L(this.predicate,r)}toError(r){return t=>{if(!this.predicate(t))return null;let n=r(t),o=n.code;class a extends T{constructor(){var u;super(n.message,{cause:(u=n.cause)!=null?u:t,meta:n.meta,status:n.status,retryable:n.retryable});m(this,"code",o)}}return new a}}},L=class{constructor(r,t){this.predicate=r;this.errorCode=t}with(r){return t=>{if(!this.predicate(t))return null;let n=r(t),o=this.errorCode;class a extends T{constructor(){super(n.message,{cause:n.cause,meta:n.meta,status:n.status,retryable:n.retryable});m(this,"code",o)}}return new a}}},E={when:e=>new B(e),instance:e=>new B(r=>r instanceof e),code:e=>({for:r=>new L(r,e)}),string:(e,r)=>({when:t=>E.when(t).toCode(r).with(n=>({message:n===e?e:`${r}: ${n}`,cause:n}))}),httpStatus:(e,r)=>({for:t=>E.when(t).toCode(r!=null?r:`HTTP_${e}`).with(n=>({message:`HTTP ${e} error`,cause:n}))})};var w={typed:(e=>e instanceof T?e:null),abort:E.when(e=>e instanceof DOMException&&e.name==="AbortError").toCode("ABORTED").with(e=>({message:e.message||"Operation was aborted",cause:e,retryable:!1})),timeout:E.when(e=>e instanceof Error&&e.name==="TimeoutError").toCode("TIMEOUT").with(e=>({message:e.message||"Operation timed out",cause:e})),network:E.when(e=>se(e)).toCode("NETWORK").with(e=>({message:(e instanceof Error,e.message||"Network error"),cause:e})),http:E.when(e=>{var n;if(!ne(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}}),unknown:E.when(e=>e instanceof Error&&!(e instanceof T)).toCode("UNKNOWN").with(e=>({message:e.message||"Unknown error occurred",cause:e}))};var ae=[w.typed,w.abort,w.timeout,w.http,w.network,w.unknown];var ie={when:e=>E.when(e),instance:e=>E.instance(e)},K=ae,Fe=w.timeout,Be=w.abort,Le=w.network,Ue=w.http,_e=E.when(e=>e instanceof g).toCode("CIRCUIT_OPEN").with(e=>({message:e.message,cause:e})),ze=E.when(e=>e instanceof v).toCode("VALIDATION").with(e=>({message:e.message,cause:e}));var ue={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})},q=(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?Math.min(n,e.maxDelay):n}case"fibonacci":{let n=e.base*ce(Number(r));return e.maxDelay?Math.min(n,e.maxDelay):n}case"custom":return e.calculate(r,t);default:return e}},ce=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};var Y=(e,r)=>new Promise((t,n)=>{if(r!=null&&r.aborted){n(new DOMException("Aborted","AbortError"));return}let o=s=>{r&&s&&r.removeEventListener("abort",s)},a,i=()=>{a&&clearTimeout(a),o(i),n(new DOMException("Aborted","AbortError"))};a=setTimeout(()=>{o(i),t()},e),r==null||r.addEventListener("abort",i,{once:!0})});var le=e=>{var i,s,u;if(e.toError)return e.toError;let r=(i=e.rulesMode)!=null?i:"extend",t=(s=e.rules)!=null?s:[],n=K,o=(u=e.fallback)!=null?u:(c=>J(I)(c)),a=r==="replace"?t:[...t,...n];return W(a,o)},z=class e{constructor(r={}){m(this,"circuitBreaker");m(this,"config");m(this,"lastCircuitState");let{rules:t,rulesMode:n,fallback:o,toError:a,mapError:i,...s}=r,u=le(r),c={...s,errorHandling:{normalizer:u,mapError:i}};this.config=c,c.circuitBreaker&&(this.circuitBreaker=new F(c.circuitBreaker),this.lastCircuitState=this.circuitBreaker.getState().state)}async run(r,t={}){var a,i,s,u,c,b;let n={...this.config,...t};if(this.circuitBreaker){let l=(a=this.lastCircuitState)!=null?a:this.circuitBreaker.getState().state,y=await this.circuitBreaker.canExecute(),p=this.circuitBreaker.getState().state;if(l!==p)try{(s=(i=n.hooks)==null?void 0:i.onCircuitStateChange)==null||s.call(i,l,p)}catch{}if(this.lastCircuitState=p,!y)return{type:"failure",ok:!1,data:null,error:this.circuitBreaker.createOpenError(),metrics:{totalAttempts:0,totalRetries:0,totalDuration:0,retryHistory:[]}}}let o=await me(r,n);if(this.circuitBreaker){let l=(u=this.lastCircuitState)!=null?u:this.circuitBreaker.getState().state;o.ok?await this.circuitBreaker.recordSuccess():await this.circuitBreaker.recordFailure(o.error);let y=this.circuitBreaker.getState().state;if(l!==y)try{(b=(c=n.hooks)==null?void 0:c.onCircuitStateChange)==null||b.call(c,l,y)}catch{}this.lastCircuitState=y}return o}async runOrThrow(r,t={}){let n=await this.run(r,t);if(n.ok)return n.data;throw n.error}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 b;let n={...this.config,...t},o=(b=n.concurrency)!=null?b:Number.POSITIVE_INFINITY,a=Number.isFinite(o)?Number(_(o)):Number.POSITIVE_INFINITY,i=new Array(r.length),s=0,u=async()=>{var l;for(;s<r.length&&!((l=n.signal)!=null&&l.aborted);){let y=s++;if(y>=r.length)break;let p=r[y];p&&(i[y]=await this.run(p,n))}},c=Array.from({length:Math.min(a,r.length)},()=>u());await Promise.all(c);for(let l=0;l<r.length;l++)if(!(l in i)){let y=r[l];y&&(i[l]=await this.run(y,n))}return i}async allOrThrow(r,t={}){let n=await this.all(r,t);for(let o of n)if(!o.ok)throw o.error;return n.map(o=>{if(!o.ok)throw o.error;return o.data})}partitionAll(r){let t=[],n=[],o=[],a=[],i=[];for(let s of r){if(s.type==="success"){t.push(s);continue}switch(n.push(s),s.type){case"failure":o.push(s);break;case"aborted":a.push(s);break;case"timeout":i.push(s);break}}return{ok:t,errors:n,failure:o,aborted:a,timeout:i}}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 u,c;let{errorHandling:t,...n}=this.config,{errorHandling:o,...a}=r,i=(u=o==null?void 0:o.normalizer)!=null?u:t.normalizer,s=(c=o==null?void 0:o.mapError)!=null?c:t.mapError;return new e({...n,...a,toError:i,mapError:s})}withErrorType(r={}){return new e(r)}};function $(e={}){let r=new z(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 me(e,r){let{signal:t,ignoreAbort:n=!0,timeout:o,retry:a,errorHandling:i,hooks:s,logger:u}=r,c=(k,...d)=>{try{k==null||k(...d)}catch{}},b,l=0,y=0,p=[],R=Date.now(),{signal:C,cleanup:G}=de(t);try{if(C.aborted){c(s==null?void 0:s.onAbort,C);let d=i.normalizer(new DOMException("Aborted","AbortError")),f=i.mapError?i.mapError(d):d;return{type:"aborted",ok:!1,data:null,error:f,metrics:{totalAttempts:l,totalRetries:y,totalDuration:Date.now()-R,lastError:f,retryHistory:p}}}let k=async d=>{var f,P,O;l=d;try{let M=e({signal:C}),S=o?await ye(M,o,C):await M;return c(s==null?void 0:s.onSuccess,S),c(u==null?void 0:u.info,`Task succeeded on attempt ${d}`),S}catch(M){let S=i.normalizer(M),h=i.mapError?i.mapError(S):S;b=h,h.code==="ABORTED"&&c(s==null?void 0:s.onAbort,C),n&&h.code==="ABORTED"||(c(s==null?void 0:s.onError,h),c(u==null?void 0:u.error,`Task failed on attempt ${d}`,h));let Q=A((f=a==null?void 0:a.maxRetries)!=null?f:0);if(d<=Number(Q)){let H=a==null?void 0:a.shouldRetry,X={totalAttempts:Number(l),elapsedTime:Date.now()-R,startTime:new Date(R),lastDelay:(P=p[p.length-1])!=null&&P.delay?Number((O=p[p.length-1])==null?void 0:O.delay):void 0};if(!H||H(d,h,X)){let Z=a?q(a.strategy,d,h):0,U=pe(Z,a==null?void 0:a.jitter),V=x(U);return p.push({attempt:d,error:h,delay:V,timestamp:new Date}),c(s==null?void 0:s.onRetry,d,h,U),c(u==null?void 0:u.info,`Retrying in ${U}ms (attempt ${d+1})`),await Y(V,C),k(d+1)}}throw h}};try{let d=await k(1);y=l>0?Number(l)-1:0;let f={totalAttempts:l,totalRetries:y,totalDuration:Date.now()-R,retryHistory:p};return c(s==null?void 0:s.onFinally,f),{type:"success",ok:!0,data:d,error:null,metrics:f}}catch(d){let f=b!=null?b:i.normalizer(d),P=f.code==="TIMEOUT"?"timeout":f.code==="ABORTED"?"aborted":"failure";y=l>0?Number(l)-1:0;let O={totalAttempts:l,totalRetries:y,totalDuration:Date.now()-R,lastError:f,retryHistory:p};return c(s==null?void 0:s.onFinally,O),{type:P,ok:!1,data:null,error:f,metrics:O}}}finally{G()}}function de(e){let r=new AbortController;if(!e)return{signal:r.signal,cleanup:()=>{}};let t=()=>r.abort();return e.aborted?(t(),{signal:r.signal,cleanup:()=>{}}):(e.addEventListener("abort",t,{once:!0}),{signal:r.signal,cleanup:()=>e.removeEventListener("abort",t)})}async function ye(e,r,t){return new Promise((n,o)=>{if(t!=null&&t.aborted){o(new DOMException("Aborted","AbortError"));return}let a=!1,i=setTimeout(()=>{a=!0,u(),o(new D(x(r)))},r),s=()=>{a||(a=!0,u(),o(new DOMException("Aborted","AbortError")))},u=()=>{clearTimeout(i),t==null||t.removeEventListener("abort",s)};t==null||t.addEventListener("abort",s,{once:!0}),e.then(c=>{a||(a=!0,u(),n(c))},c=>{a||(a=!0,u(),o(c))})})}function pe(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=$(),fe=N.run,Te=N.runOrThrow,Ee=N.orThrow,we=N.all,be=N.allOrThrow;export{ue as RetryStrategies,we as all,be as allOrThrow,_ as asConcurrencyLimit,x as asMilliseconds,re as asPercentage,A as asRetryCount,te as asStatusCode,ie as errorRule,Ee as orThrow,fe as run,Te as runOrThrow,$ as tryo};
1
+ var ie=Object.defineProperty;var ue=(e,r,t)=>r in e?ie(e,r,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[r]=t;var y=(e,r,t)=>ue(e,typeof r!="symbol"?r+"":r,t);var b=class extends Error{constructor(t,n){var o,a;super(t);y(this,"cause");y(this,"meta");y(this,"status");y(this,"raw");y(this,"path");y(this,"timestamp");y(this,"retryable");this.timestamp=Date.now(),this.retryable=(o=n.retryable)!=null?o:!0,this.name=this.constructor.name,this.cause=n.cause,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,message:this.message,timestamp:this.timestamp,retryable:this.retryable,cause:this.cause,raw:this.raw,path:this.path,stack:this.stack}}},D=class extends b{constructor(t,n){super(`Operation timed out after ${t}ms`,{cause:n,retryable:!0,raw:n});y(this,"code","TIMEOUT")}};var I=class extends b{constructor(t,n){super(`Circuit breaker is open, reset after ${t}ms`,{cause:n,retryable:!1,raw:n});y(this,"code","CIRCUIT_OPEN")}};var P=class extends b{constructor(t,n){super(t,{cause:n,raw:n});y(this,"code","UNKNOWN")}};var w=e=>{if(e<0||!Number.isFinite(e))throw new Error(`Invalid milliseconds: must be a non-negative finite number, got ${e}`);return e},R=e=>{if(e<0||!Number.isInteger(e))throw new Error(`Invalid retry count: must be a non-negative integer, got ${e}`);return e},L=e=>{if(e<1||!Number.isInteger(e))throw new Error(`Invalid concurrency limit: must be a positive integer, got ${e}`);return e},Y=e=>{if(e<0||e>100||!Number.isFinite(e))throw new Error(`Invalid percentage: must be between 0 and 100, got ${e}`);return e};var F=class{constructor(r){y(this,"state");y(this,"config");this.config={failureThreshold:R(r.failureThreshold),resetTimeout:w(r.resetTimeout),halfOpenRequests:R(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,i;if(!((i=(a=(o=this.config).shouldCountAsFailure)==null?void 0:a.call(o,r))!=null?i:!0))return;let n=new Date;switch(this.state.state){case"closed":{let s=this.state.failureCount+1;s>=this.config.failureThreshold?this.state={state:"open",failureCount:s,halfOpenCount:0,lastFailureTime:n,nextAttemptTime:new Date(n.getTime()+this.config.resetTimeout)}:this.state={...this.state,failureCount:s,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?w(Math.max(0,this.state.nextAttemptTime.getTime()-Date.now())):this.config.resetTimeout;return new I(r)}forceState(r){this.state={state:r,failureCount:0,halfOpenCount:0}}reset(){this.state={state:"closed",failureCount:0,halfOpenCount:0}}updateStateIfNeeded(){this.state.state==="open"&&this.state.nextAttemptTime&&new Date>=this.state.nextAttemptTime&&(this.state={...this.state,state:"half-open",halfOpenCount:0})}};var G=(e,r)=>t=>{for(let n of e){let o=n(t);if(o!==null)return o}return r(t)},Q=e=>r=>r instanceof b?r:r instanceof Error?new e(r.message,r):typeof r=="string"?new e(r):new e("Unknown error occurred",r);var le=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.status=="number"||typeof r.statusCode=="number"},ce=e=>{if(typeof e!="object"||e===null)return!1;let r=e;return typeof r.code=="string"&&r.code.length>0},ye=e=>{var r;if(e instanceof Error){let t=e.message.toLowerCase();if(e.name==="TypeError"&&(t.includes("fetch")&&t.includes("failed")||t.includes("network"))||t.includes("fetch")&&t.includes("failed")||t.includes("network"))return!0}if(ce(e)){let t=((r=e.code)!=null?r:"").toUpperCase();return t==="ECONNRESET"||t==="ECONNREFUSED"||t==="ETIMEDOUT"||t==="ENOTFOUND"||t==="EAI_AGAIN"}return!1},_=class{constructor(r){this.predicate=r}toCode(r){return new H(this.predicate,r)}toError(r){return t=>{if(!this.predicate(t))return null;let n=r(t),o=n.code;class a extends b{constructor(){var l,u,d;super(n.message,{cause:(l=n.cause)!=null?l:t,meta:(u=n.meta)!=null?u:{},status:n.status,retryable:n.retryable,raw:(d=n.raw)!=null?d:t,path:n.path});y(this,"code",o)}}return new a}}},H=class{constructor(r,t){this.predicate=r;this.errorCode=t}with(r){return t=>{if(!this.predicate(t))return null;let n=r(t),o=this.errorCode;class a extends b{constructor(){var u;let l=Object.hasOwn(n,"raw")?n.raw:t;super(n.message,{cause:n.cause,meta:(u=n.meta)!=null?u:{},status:n.status,retryable:n.retryable,raw:l,path:n.path});y(this,"code",o)}}return new a}}},h={when:e=>new _(e),instance:e=>new _(r=>r instanceof e)},x={typed:(e=>e instanceof b?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=>ye(e)).toCode("NETWORK").with(e=>({message:(e instanceof Error,e.message||"Network error"),cause:e,raw:e})),http:h.when(e=>{var n;if(!le(e))return!1;let r=e,t=(n=r.status)!=null?n:r.statusCode;return typeof t=="number"&&t>=400}).toCode("HTTP").with(e=>{var n;let r=(n=e.status)!=null?n:e.statusCode,t=typeof r=="number"&&(r>=500||r===429);return{message:e.message||`HTTP ${r!=null?r:"error"} error`,cause:e,status:typeof r=="number"?r:void 0,retryable:t,raw:e}}),unknown:h.when(e=>e instanceof Error&&!(e instanceof b)).toCode("UNKNOWN").with(e=>({message:e.message||"Unknown error occurred",cause:e,raw:e}))};var de=[x.typed,x.abort,x.timeout,x.http,x.network,x.unknown];var pe={when:e=>h.when(e),instance:e=>h.instance(e)},X=de;var me={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})},Z=(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*fe(Number(r));return e.maxDelay!==void 0?Math.min(n,e.maxDelay):n}case"custom":return e.calculate(r,t);default:return e}},fe=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},j=e=>{switch(e.type){case"fixed":{if(e.delay<0)throw new Error("Fixed delay must be non-negative");break}case"exponential":if(e.base<=0)throw new Error("Exponential base delay must be positive");if(e.factor<=1)throw new Error("Exponential factor must be greater than 1");if(e.maxDelay!==void 0&&e.maxDelay<=0)throw new Error("Exponential max delay must be positive");break;case"fibonacci":if(e.base<=0)throw new Error("Fibonacci base delay must be positive");if(e.maxDelay!==void 0&&e.maxDelay<=0)throw new Error("Fibonacci max delay must be positive");break;case"custom":break;default:{let r=e;throw new Error(`Unknown strategy type: ${r}`)}}};var ee=(e,r)=>new Promise((t,n)=>{if(r!=null&&r.aborted){n(new DOMException("Aborted","AbortError"));return}let o=s=>{r&&s&&r.removeEventListener("abort",s)},a,i=()=>{a&&clearTimeout(a),o(i),n(new DOMException("Aborted","AbortError"))};a=setTimeout(()=>{o(i),t()},e),r==null||r.addEventListener("abort",i,{once:!0})}),re=(e,r,t,n)=>new Promise((o,a)=>{if(t!=null&&t.aborted){a(new DOMException("Aborted","AbortError"));return}let i=!1,s=setTimeout(()=>{var d;i=!0,u(),a((d=n==null?void 0:n())!=null?d:new Error(`Operation timed out after ${r}ms`))},r),l=()=>{i||(i=!0,u(),a(new DOMException("Aborted","AbortError")))},u=()=>{clearTimeout(s),t==null||t.removeEventListener("abort",l)};t==null||t.addEventListener("abort",l,{once:!0}),e.then(d=>{i||(i=!0,u(),o(d))},d=>{i||(i=!0,u(),a(d))})});var Ee=e=>{var i,s,l;if(e.toError)return e.toError;let r=(i=e.rulesMode)!=null?i:"extend",t=(s=e.rules)!=null?s:[],n=X,o=(l=e.fallback)!=null?l:(u=>Q(P)(u)),a=r==="replace"?t:[...t,...n];return G(a,o)},Te=e=>{if(e)switch(e.type){case"none":return;case"full":case"equal":Y(e.ratio);return;case"custom":return;default:{let r=e;throw new Error(`Unsupported jitter configuration: ${r}`)}}},$=e=>{let r=e;return r.timeout!==void 0&&(r={...r,timeout:Number(w(r.timeout))}),r.concurrency!==void 0&&(r={...r,concurrency:Number.isFinite(r.concurrency)?Number(L(r.concurrency)):r.concurrency}),r.retry&&(j(r.retry.strategy),Te(r.retry.jitter),r={...r,retry:{...r.retry,maxRetries:Number(R(r.retry.maxRetries))}}),r},q=class e{constructor(r={}){y(this,"circuitBreaker");y(this,"config");y(this,"lastCircuitState");let{rules:t,rulesMode:n,fallback:o,toError:a,mapError:i,...s}=r,l=Ee(r),u={...s,errorHandling:{normalizer:l,mapError:i}};this.config=$(u),u.circuitBreaker&&(this.circuitBreaker=new F(u.circuitBreaker),this.lastCircuitState=this.circuitBreaker.getState().state)}async run(r,t={}){var a,i,s,l,u,d;let n=$({...this.config,...t});if(this.circuitBreaker){let c=(a=this.lastCircuitState)!=null?a:this.circuitBreaker.getState().state,m=await this.circuitBreaker.canExecute(),E=this.circuitBreaker.getState().state;if(c!==E)try{(s=(i=n.hooks)==null?void 0:i.onCircuitStateChange)==null||s.call(i,c,E)}catch{}if(this.lastCircuitState=E,!m)return{type:"failure",ok:!1,data:null,error:this.circuitBreaker.createOpenError(),metrics:{totalAttempts:0,totalRetries:0,totalDuration:0,retryHistory:[]}}}let o=await be(r,n);if(this.circuitBreaker){let c=(l=this.lastCircuitState)!=null?l:this.circuitBreaker.getState().state;o.ok?await this.circuitBreaker.recordSuccess():await this.circuitBreaker.recordFailure(o.error);let m=this.circuitBreaker.getState().state;if(c!==m)try{(d=(u=n.hooks)==null?void 0:u.onCircuitStateChange)==null||d.call(u,c,m)}catch{}this.lastCircuitState=m}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=$({...this.config,...t}),o=(d=n.concurrency)!=null?d:Number.POSITIVE_INFINITY,a=Number.isFinite(o)?Number(L(o)):Number.POSITIVE_INFINITY;if(a===Number.POSITIVE_INFINITY)return Promise.all(r.map(c=>this.run(c,n)));let i=new Array(r.length),s=0,l=async()=>{var c;for(;s<r.length&&!((c=n.signal)!=null&&c.aborted);){let m=s++;if(m>=r.length)break;let E=r[m];E&&(i[m]=await this.run(E,n))}},u=Array.from({length:Math.min(a,r.length)},()=>l());await Promise.all(u);for(let c=0;c<r.length;c++)if(!(c in i)){let m=r[c];m&&(i[c]=await this.run(m,n))}return i}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=[],i=[];for(let s of r){if(s.type==="success"){t.push(s);continue}switch(n.push(s),s.type){case"failure":o.push(s);break;case"aborted":a.push(s);break;case"timeout":i.push(s);break}}return{ok:t,errors:n,failure:o,aborted:a,timeout:i}}getCircuitBreakerState(){var r;return(r=this.circuitBreaker)==null?void 0:r.getState()}resetCircuitBreaker(){var r;(r=this.circuitBreaker)==null||r.reset()}getConfig(){return{...this.config}}withConfig(r){var l,u;let{errorHandling:t,...n}=this.config,{errorHandling:o,...a}=r,i=(l=o==null?void 0:o.normalizer)!=null?l:t.normalizer,s=(u=o==null?void 0:o.mapError)!=null?u:t.mapError;return new e({...n,...a,toError:i,mapError:s})}};function B(e={}){let r=new q(e);return{run:(t,n)=>r.run(t,n),orThrow:(t,n)=>r.orThrow(t,n),runOrThrow:(t,n)=>r.runOrThrow(t,n),all:(t,n)=>r.all(t,n),allOrThrow:(t,n)=>r.allOrThrow(t,n),partitionAll:t=>r.partitionAll(t),withConfig:t=>r.withConfig(t)}}async function be(e,r){let{signal:t,ignoreAbort:n=!0,timeout:o,retry:a,errorHandling:i,hooks:s,logger:l}=r,u=(C,...p)=>{try{C==null||C(...p)}catch{}},d,c=0,m=0,E=[],k=Date.now(),{signal:A,cleanup:ne}=te(t),N=C=>({totalAttempts:c,totalRetries:c>0?Number(c)-1:0,totalDuration:Date.now()-k,lastError:C,retryHistory:E});try{if(A.aborted){u(s==null?void 0:s.onAbort,A);let p=i.normalizer(new DOMException("Aborted","AbortError")),T=i.mapError?i.mapError(p):p;return{type:"aborted",ok:!1,data:null,error:T,metrics:{totalAttempts:c,totalRetries:m,totalDuration:Date.now()-k,lastError:T,retryHistory:E}}}let C=async()=>{var M,g,V;let p=1,T=R((M=a==null?void 0:a.maxRetries)!=null?M:0);for(;;){c=p;let W=new AbortController,{signal:U,cleanup:oe}=te(A,W.signal);try{let v=Promise.resolve(e({signal:U})),O=o?await re(v,o,U,()=>(W.abort(),new D(w(o)))):await v;return u(s==null?void 0:s.onSuccess,O,N()),u(l==null?void 0:l.info,`Task succeeded on attempt ${p}`),O}catch(v){let O=i.normalizer(v),f=i.mapError?i.mapError(O):O;if(d=f,f.code==="ABORTED"&&u(s==null?void 0:s.onAbort,U),n&&f.code==="ABORTED"||(u(s==null?void 0:s.onError,f,N(f)),u(l==null?void 0:l.error,`Task failed on attempt ${p}`,f)),f.code==="ABORTED"||f.retryable===!1)throw f;if(p<=Number(T)){let K=a==null?void 0:a.shouldRetry,se={totalAttempts:Number(c),elapsedTime:Date.now()-k,startTime:new Date(k),lastDelay:(g=E[E.length-1])!=null&&g.delay?Number((V=E[E.length-1])==null?void 0:V.delay):void 0};if(!K||K(p,f,se)){let ae=a?Z(a.strategy,p,f):0,z=we(ae,a==null?void 0:a.jitter),J=w(z);E.push({attempt:p,error:f,delay:J,timestamp:new Date}),u(s==null?void 0:s.onRetry,p,f,z),u(l==null?void 0:l.info,`Retrying in ${z}ms (attempt ${p+1})`),p+=1,await ee(J,A);continue}}throw f}finally{oe()}}};try{let p=await C(),T=N();return m=T.totalRetries,u(s==null?void 0:s.onFinally,T),{type:"success",ok:!0,data:p,error:null,metrics:T}}catch(p){let T=d!=null?d:i.normalizer(p),M=T.code==="TIMEOUT"?"timeout":T.code==="ABORTED"?"aborted":"failure",g=N(T);return m=g.totalRetries,u(s==null?void 0:s.onFinally,g),{type:M,ok:!1,data:null,error:T,metrics:g}}}finally{ne()}}function te(...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 we(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=B(),he=S.run,Ce=S.runOrThrow,Re=S.orThrow,xe=S.all,ge=S.allOrThrow;export{me as RetryStrategies,b as TypedError,xe as all,ge as allOrThrow,w as asMilliseconds,R as asRetryCount,B as default,pe as errorRule,Re as orThrow,he as run,Ce as runOrThrow,B as tryo};
package/package.json CHANGED
@@ -1,12 +1,21 @@
1
1
  {
2
2
  "name": "tryo",
3
- "version": "0.13.0",
4
- "description": "Run sync/async functions and return a typed Result instead of throwing.",
5
- "type": "module",
6
- "sideEffects": false,
3
+ "version": "0.13.3",
4
+ "author": {
5
+ "name": "sebasxsala",
6
+ "url": "https://github.com/sebasxsala"
7
+ },
7
8
  "main": "./dist/index.cjs",
8
9
  "module": "./dist/index.js",
9
- "types": "./dist/index.d.ts",
10
+ "devDependencies": {
11
+ "@biomejs/biome": "2.3.13",
12
+ "@types/bun": "latest",
13
+ "husky": "^9.1.7",
14
+ "lint-staged": "^16.2.7",
15
+ "mint": "latest",
16
+ "tsup": "^8.5.1",
17
+ "typescript": "^5.0.0"
18
+ },
10
19
  "exports": {
11
20
  ".": {
12
21
  "types": "./dist/index.d.ts",
@@ -14,11 +23,20 @@
14
23
  "require": "./dist/index.cjs"
15
24
  }
16
25
  },
26
+ "bugs": "https://github.com/sebasxsala/tryo/issues",
27
+ "description": "Run sync/async functions and return a typed Result instead of throwing.",
17
28
  "files": [
18
29
  "dist",
19
30
  "README.md",
20
31
  "LICENSE"
21
32
  ],
33
+ "homepage": "https://tryo-docs.pages.dev/",
34
+ "license": "MIT",
35
+ "lint-staged": {
36
+ "*.{ts,tsx,js,jsx,json}": [
37
+ "biome check --write"
38
+ ]
39
+ },
22
40
  "scripts": {
23
41
  "build": "tsup",
24
42
  "typecheck": "tsc --noEmit",
@@ -33,27 +51,9 @@
33
51
  "lint:fix": "biome lint --fix",
34
52
  "check": "biome check",
35
53
  "check:fix": "biome check --write",
36
- "prepare": "husky"
37
- },
38
- "lint-staged": {
39
- "*.{ts,tsx,js,jsx,json}": [
40
- "biome check --write"
41
- ]
54
+ "prepare": ""
42
55
  },
43
- "devDependencies": {
44
- "@biomejs/biome": "2.3.13",
45
- "@types/bun": "latest",
46
- "husky": "^9.1.7",
47
- "lint-staged": "^16.2.7",
48
- "mint": "latest",
49
- "tsup": "^8.5.1",
50
- "typescript": "^5.0.0"
51
- },
52
- "license": "MIT",
53
- "homepage": "https://tryo-docs.pages.dev/",
54
- "bugs": "https://github.com/sebasxsala/tryo/issues",
55
- "author": {
56
- "name": "sebasxsala",
57
- "url": "https://github.com/sebasxsala"
58
- }
56
+ "sideEffects": false,
57
+ "type": "module",
58
+ "types": "./dist/index.d.ts"
59
59
  }