tryo 0.9.4 → 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/README.md CHANGED
@@ -1,73 +1,190 @@
1
- ````
1
+ # tryo
2
2
 
3
- ---
3
+ Run sync/async functions and return a typed Result instead of throwing. `tryo` provides powerful error normalization, retry logic, concurrency control, and circuit breakers with a premium developer experience.
4
4
 
5
- ## API
5
+ ## Installation
6
6
 
7
- ### `run(fn, options?)`
7
+ ```bash
8
+ npm install tryo
9
+ # or
10
+ bun add tryo
11
+ ```
8
12
 
9
- Executes a single async function.
13
+ ## Basic Usage
10
14
 
11
- ```ts
12
- await runner.run(fn, {
13
- retries: 3,
14
- retryDelay: (attempt) => attempt * 1000,
15
- onError: (err) => toast.error(err.message),
16
- onSuccess: (data) => console.log(data),
17
- });
18
- ````
15
+ You can use the top-level shortcuts for simple cases, or create a configured instance for complex scenarios.
19
16
 
20
- ### `runAllSettled(tasks, options?)`
17
+ ### Using Shortcuts
21
18
 
22
- Executes multiple tasks with concurrency control. Returns a discriminated union for each result.
19
+ ```typescript
20
+ import { run } from 'tryo'
23
21
 
24
- ```ts
25
- const tasks = [
26
- () => fetch("/api/1"),
27
- () => fetch("/api/2"),
28
- () => fetch("/api/3"),
29
- ];
22
+ const result = await run(async () => {
23
+ const res = await fetch('/api/data')
24
+ if (!res.ok) throw new Error('Failed')
25
+ return res.json()
26
+ })
30
27
 
31
- // Run max 2 at a time, settle all results
32
- const results = await runner.allSettled(tasks, {
33
- concurrency: 2,
34
- mode: "settle", // "fail-fast" is also supported
35
- });
28
+ if (result.ok) {
29
+ console.log(result.data) // result.data is typed
30
+ } else {
31
+ console.error(result.error.code) // "HTTP", "UNKNOWN", etc.
32
+ }
36
33
  ```
37
34
 
38
- ### `runAll(tasks, options?)`
35
+ ### Using the Factory (Best for Apps)
36
+
37
+ Creating an instance allows you to shared configuration like retries, circuit breakers, and custom error rules across your app.
39
38
 
40
- Like `Promise.all` but with concurrency control and retries. Throws the first error (normalized).
39
+ ```typescript
40
+ import tryo from 'tryo'
41
+
42
+ const ex = tryo({
43
+ retry: {
44
+ maxRetries: 3,
45
+ strategy: RetryStrategies.exponential(100),
46
+ },
47
+ circuitBreaker: {
48
+ failureThreshold: 5,
49
+ resetTimeout: 10000,
50
+ },
51
+ })
52
+
53
+ const result = await ex.run(fetchData)
54
+ ```
41
55
 
42
- ```ts
43
- try {
44
- const data = await runner.all(tasks, { concurrency: 5 });
45
- } catch (err) {
46
- // err is your typed AppError
47
- console.error(err.code);
56
+ ## Error Handling
57
+
58
+ `tryo` normalizes all errors into a `TypedError` instance with a stable `code`.
59
+
60
+ ### The `TypedError` Shape
61
+
62
+ ```typescript
63
+ type TypedError<Code extends string = string, Meta = unknown> = {
64
+ code: Code // Stable error code (e.g. "TIMEOUT", "HTTP")
65
+ message: string // Human-readable message
66
+ cause?: unknown // Original error
67
+ meta?: Meta // Extra metadata (optional)
68
+ status?: number // Optional HTTP status (if applicable)
69
+ retryable: boolean // Whether the error is safe to retry
70
+ timestamp: number // When the error occurred (ms)
71
+ stack?: string // Stack trace for debugging
48
72
  }
49
73
  ```
50
74
 
51
- ---
75
+ ### Default Rules
76
+
77
+ By default, `tryo` detects:
78
+
79
+ - **ABORTED**: Detects `AbortError`.
80
+ - **TIMEOUT**: Detects `TimeoutError`.
81
+ - **HTTP**: Detects status codes in error objects.
82
+ - **UNKNOWN**: Fallback for everything else.
83
+
84
+ ### Custom Rules
85
+
86
+ Map specific exceptions to typed error codes using the `rules` option.
87
+
88
+ ```typescript
89
+ import tryo, { errorRule } from 'tryo'
90
+
91
+ const ex = tryo({
92
+ rules: [
93
+ errorRule
94
+ .when(e => e === 'unauthorized')
95
+ .toError(() => ({
96
+ code: 'AUTH_ERROR',
97
+ message: 'Please login',
98
+ })),
99
+ ] as const,
100
+ })
101
+ ```
102
+
103
+ ## API Reference
104
+
105
+ ### `.run(task, options?)`
106
+
107
+ Executes a single task. The `options` can override the instance defaults (except `signal`, which must be passed per call).
108
+
109
+ ```typescript
110
+ const result = await ex.run(task, {
111
+ timeout: 5000,
112
+ signal: abortController.signal,
113
+ })
114
+ ```
115
+
116
+ ### `.all(tasks, options?)`
117
+
118
+ Executes multiple tasks with **concurrency control**. Like `Promise.allSettled` but with retries, timeouts, and a worker pool.
119
+
120
+ ```typescript
121
+ const tasks = [() => job(1), () => job(2), () => job(3)]
52
122
 
53
- ## React Example
54
-
55
- ```ts
56
- useEffect(() => {
57
- let cancelled = false;
58
-
59
- runner.run(fetchData, {
60
- onSuccess: (data) => {
61
- if (!cancelled) setData(data);
62
- },
63
- onError: (err) => {
64
- if (err.code === "ABORTED") return;
65
- toast.error(err.message);
66
- },
67
- });
68
-
69
- return () => {
70
- cancelled = true;
71
- };
72
- }, []);
123
+ // Execute 5-at-a-time
124
+ const results = await ex.all(tasks, { concurrency: 5 })
73
125
  ```
126
+
127
+ ### `.partitionAll(results)`
128
+
129
+ Utility to separate successes from failures after an `all()` call.
130
+
131
+ ```typescript
132
+ const { ok, failure, aborted, timeout } = ex.partitionAll(results)
133
+
134
+ console.log(`Successes: ${ok.length}`)
135
+ console.log(`Errors: ${failure.length}`)
136
+ ```
137
+
138
+ ### `.runOrThrow(task, options?)`
139
+
140
+ Utility if you prefer exceptions but want the power of `tryo` (retries, breaker, normalization).
141
+
142
+ ```typescript
143
+ const data = await ex.runOrThrow(task) // Returns data or throws TypedError
144
+ ```
145
+
146
+ ## Advanced Features
147
+
148
+ ### Concurrency
149
+
150
+ The `all()` method includes a worker pool that respects your `concurrency` limit and stops launching new tasks if the `signal` is aborted.
151
+
152
+ ### Circuit Breaker
153
+
154
+ If your tasks fail repeatedly, the circuit breaker opens and prevents further calls to protect your downstream services.
155
+
156
+ ```typescript
157
+ const ex = tryo({
158
+ circuitBreaker: {
159
+ failureThreshold: 5,
160
+ resetTimeout: 30000,
161
+ halfOpenRequests: 2,
162
+ },
163
+ })
164
+ ```
165
+
166
+ ### Observability Hooks
167
+
168
+ Add hooks for logging or monitoring:
169
+
170
+ ```typescript
171
+ const ex = tryo({
172
+ hooks: {
173
+ onRetry: (attempt, error, delay) => console.log(`Retry ${attempt}...`),
174
+ onCircuitStateChange: (from, to) =>
175
+ console.log(`Breaker moved: ${from} -> ${to}`),
176
+ },
177
+ })
178
+ ```
179
+
180
+ ## Why tryo?
181
+
182
+ 1. **No More Try/Catch**: Handle results as data.
183
+ 2. **Concurrency Control**: Built-in worker pool for batch operations.
184
+ 3. **Normalized Errors**: Stable codes instead of unreliable error messages.
185
+ 4. **Resiliency**: Sophisticated retry strategies and circuit breakers out of the box.
186
+ 5. **Type Safety**: Full TypeScript support with inference for custom error rules.
187
+
188
+ ---
189
+
190
+ License: MIT
package/dist/index.cjs CHANGED
@@ -1,2 +1 @@
1
- 'use strict';function B(r,e){return t=>{for(let u of r){let n=u(t);if(n)return n}return e(t)}}function N(r){return r instanceof Error?{code:r.name==="TypeError"?"NETWORK":"UNKNOWN",message:r.message||"Something went wrong",cause:r}:{code:"UNKNOWN",message:"Something went wrong",cause:r}}function D(r){return r instanceof DOMException&&r.name==="AbortError"?{code:"ABORTED",message:"Request cancelled",cause:r}:r instanceof DOMException&&r.name==="TimeoutError"?{code:"TIMEOUT",message:"Request timed out",cause:r}:N(r)}function O(r){if(r.retries!=null&&r.retries<0)throw new Error("retries must be >= 0");if(r.timeout!=null&&r.timeout<=0)throw new Error("timeout must be > 0");if(r.maxDelay!=null&&r.maxDelay<0)throw new Error("maxDelay must be >= 0");let e=r.circuitBreaker;if(e){if(e.failureThreshold<1)throw new Error("failureThreshold must be >= 1");if(e.resetTimeout<=0)throw new Error("resetTimeout must be > 0");if(e.halfOpenRequests!=null&&e.halfOpenRequests<1)throw new Error("halfOpenRequests must be >= 1")}}var J=r=>new Promise(e=>setTimeout(e,r));function z(r,e,t){return Math.max(e,Math.min(t,r))}function H(r,e,t,u,n,s){let a=typeof r=="function"?r(e,t):typeof r=="number"?r:u,i=Q(n??"linear",a,e),p=s!=null?z(i,0,s):i;return Number.isFinite(p)?p:0}function _(r,e){if(r<=0||!e)return r;let t=typeof e=="object"&&e.rng?e.rng:Math.random,u=typeof e=="number"?e:e===true?.5:typeof e=="object"&&e.ratio!=null?e.ratio:.5,n=z(u,0,1);return (typeof e=="object"&&e.mode?e.mode:"full")==="equal"?r*(1-n)+t()*r*n:r+t()*r*n}function Q(r,e,t){if(typeof r=="function"){let s=r(t);return s>=0?s:0}let u=e>=0?e:0,n=t>=1?t:1;if(r==="linear")return u;if(r==="exponential")return u*Math.pow(2,n-1);if(r==="fibonacci"){if(n<=2)return u;let s=1,a=1;for(let i=3;i<=n;i++){let p=s+a;s=a,a=p;}return u*a}return u}async function g(r,e={}){let{toError:t=D,mapError:u,onError:n,onSuccess:s,onFinally:a,ignoreAbort:i=true,retries:p=0,retryDelay:y,shouldRetry:f=()=>true,jitter:E={ratio:.5,mode:"full"},backoffStrategy:o,maxDelay:m,timeout:A,signal:R,onRetry:x,logger:b,onAbort:q}=e,$=p>0?300:0;if(O(e),R?.aborted)try{q?.(R);}finally{let T=t(new DOMException("Aborted","AbortError")),l=u?u(T):T;return i||n?.(l),a?.(),{ok:false,data:null,error:l,metrics:{totalAttempts:0,totalRetries:0,totalDuration:0,lastError:l}}}let M=Date.now(),d=0,U;for(;;)try{let T=null,l=A&&A>0?new Promise((w,K)=>{T=setTimeout(()=>K(new DOMException("Timeout","TimeoutError")),A);}):null,I=await(l?Promise.race([r(),l]):r());T&&clearTimeout(T);try{s?.(I);}catch(w){b?.error?.("run:onSuccess failed",t(w));}try{a?.();}catch(w){b?.error?.("run:onFinally failed",t(w));}let h=Date.now()-M,k={totalAttempts:d+1,totalRetries:d,totalDuration:h,lastError:U};return b?.debug?.("run:success",{attempts:k.totalAttempts,duration:k.totalDuration}),{ok:!0,data:I,error:null,metrics:k}}catch(T){let l=t(T);if(u&&(l=u(l)),l?.code==="ABORTED"||T instanceof DOMException&&T.name==="AbortError"||R?.aborted)try{if(R)try{q?.(R);}catch(c){b?.error?.("run:onAbort failed",t(c));}}finally{if(!i)try{n?.(l);}catch(F){b?.error?.("run:onError failed",t(F));}try{a?.();}catch(F){b?.error?.("run:onFinally failed",t(F));}let c=Date.now()-M,W={totalAttempts:d,totalRetries:d,totalDuration:c,lastError:l};return b?.debug?.("run:aborted",{attempt:d,duration:W.totalDuration}),{ok:false,data:null,error:l,metrics:W}}U=l;let h=d+1,k={totalAttempts:h,elapsedTime:Date.now()-M},w=await Promise.resolve(f(h,l,k));if(d<p&&w){d=h;let c=H(y,d,l,$,o,m);(!Number.isFinite(c)||c<0)&&(c=0),c=_(c,E),x?.(d,l,c),b?.debug?.("run:retry",{attempt:d,delay:c}),c>0&&await J(c);continue}try{n?.(l);}catch(c){b?.error?.("run:onError failed",t(c));}try{a?.();}catch(c){b?.error?.("run:onFinally failed",t(c));}let G=Date.now()-M,L={totalAttempts:d+1,totalRetries:d,totalDuration:G,lastError:l};return b?.error?.("run:error",l),{ok:false,data:null,error:l,metrics:L}}}var V=r=>r.status==="ok";async function v(r,e={}){let{concurrency:t=1/0,mode:u="settle",...n}=e;if(O(n),r.length===0)return [];let s=Number.isFinite(t)?Math.max(1,Math.floor(t)):1/0,a=new Array(r.length),i=0,p=false,y=(o,m)=>{a[o]=m.ok?{status:"ok",ok:true,data:m.data,error:null}:{status:"error",ok:false,data:null,error:m.error};},f=()=>{for(let o=0;o<r.length;o++)a[o]||(a[o]={status:"skipped",ok:false,data:null,error:null});};if(s>=r.length)return (await Promise.all(r.map(m=>g(m,n)))).forEach((m,A)=>{y(A,m);}),a;let E=async()=>{for(;;){if(p)return;let o=i++;if(o>=r.length)return;let m=r[o];if(!m)continue;let A=await g(m,n);if(y(o,A),!A.ok&&u==="fail-fast"){p=true;return}}};return await Promise.all(Array.from({length:Math.min(s,r.length)},()=>E())),f(),a}async function C(r,e={}){let{concurrency:t=1/0,...u}=e;if(O(u),r.length===0)return [];let n=Number.isFinite(t)?Math.max(1,Math.floor(t)):1/0,s=new Array(r.length);if(n>=r.length)return await Promise.all(r.map(async(f,E)=>{let o=await g(f,u);if(!o.ok)throw o.error;s[E]=o.data;})),s;let a=0,i=false,p=null,y=async()=>{for(;;){if(i)return;let f=a++;if(f>=r.length)return;let E=r[f];if(!E)continue;let o=await g(E,u);if(!o.ok){p??(p=o.error),i=true;return}s[f]=o.data;}};if(await Promise.all(Array.from({length:Math.min(n,r.length)},()=>y())),p)throw p;return s}var X=r=>r instanceof DOMException&&r.name==="AbortError"?{code:"ABORTED",message:"Request cancelled",cause:r}:r instanceof Error&&r.name==="AbortError"?{code:"ABORTED",message:r.message||"Request cancelled",cause:r}:null,Y=r=>r instanceof DOMException&&r.name==="TimeoutError"?{code:"TIMEOUT",message:"Request timed out",cause:r}:r instanceof Error&&r.name==="TimeoutError"?{code:"TIMEOUT",message:r.message||"Request timed out",cause:r}:null,Z=r=>{if(typeof r=="object"&&r!==null){let e=r,t=e.status??e.statusCode;if(typeof t=="number")return {code:"HTTP",message:typeof e.message=="string"?e.message:`HTTP Error ${t}`,status:t,cause:r}}return null},j=r=>typeof AggregateError<"u"&&r instanceof AggregateError?{code:"UNKNOWN",message:r.message||"Multiple errors occurred",cause:r,meta:{errors:r.errors}}:null,rr=r=>typeof r=="string"?{code:"UNKNOWN",message:r,cause:r}:null,er=r=>typeof r=="object"&&r!==null&&"message"in r&&typeof r.message=="string"?{code:"UNKNOWN",message:r.message,cause:r}:null,tr={abort:X,timeout:Y,httpStatus:Z,aggregate:j,string:rr,message:er};var S=class{constructor(e){this.matcher=e;}toError(e){return t=>this.matcher(t)?e(t):null}},or={instance(r){return new S(e=>e instanceof r)},when(r){return new S(r)}};var P=(r,e)=>t=>e?e(r?r(t):t):r?r(t):t;function nr(r={}){let{rules:e=[],fallback:t=E=>N(E),toError:u,ignoreAbort:n=true,mapError:s,circuitBreaker:a}=r,i=u??(e.length>0?B(e,t):D),p=0,y=null,f=null;return {run(E,o={}){let m=o.circuitBreaker??a,A=Date.now();if(m){if(y&&A<y){let R=i(new Error("Circuit open")),x=P(s,o.mapError)(R);return o.onError?.(x),o.onFinally?.(),Promise.resolve({ok:false,data:null,error:x,metrics:{totalAttempts:0,totalRetries:0,totalDuration:0,lastError:x}})}if(y&&A>=y&&(y=null,p=0,f=m.halfOpenRequests??1),f!=null)if(f<=0){let R=i(new Error("Circuit half-open limit")),x=P(s,o.mapError)(R);return o.onError?.(x),o.onFinally?.(),Promise.resolve({ok:false,data:null,error:x,metrics:{totalAttempts:0,totalRetries:0,totalDuration:0,lastError:x}})}else f--;}return g(E,{toError:i,ignoreAbort:n,...o,mapError:P(s,o.mapError)}).then(R=>(m&&(R.ok?(p=0,y=null,f=null):(p++,p>=m.failureThreshold&&(y=Date.now()+m.resetTimeout,f=null))),R))},allSettled(E,o={}){return v(E,{toError:i,ignoreAbort:n,...o,mapError:P(s,o.mapError)})},all(E,o={}){return C(E,{toError:i,ignoreAbort:n,...o,mapError:P(s,o.mapError)})}}}exports.createNormalizer=B;exports.createRunner=nr;exports.defaultFallback=N;exports.errorRule=or;exports.isSuccess=V;exports.rules=tr;exports.run=g;exports.runAll=C;exports.runAllSettled=v;exports.toAppError=D;//# sourceMappingURL=index.cjs.map
2
- //# sourceMappingURL=index.cjs.map
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});