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/dist/index.d.ts CHANGED
@@ -1,321 +1,448 @@
1
- import { MaybePromise as MaybePromise$1 } from 'bun';
2
-
3
- type AppErrorCode = "ABORTED" | "NETWORK" | "TIMEOUT" | "VALIDATION" | "HTTP" | "UNKNOWN";
4
1
  /**
5
- * A normalized error shape returned by `run()`.
6
- *
7
- * - `code`: A stable identifier you can switch on (e.g. "HTTP", "VALIDATION").
8
- * - `message`: User-facing or log-friendly message.
9
- * - `status`: Optional numeric status (commonly HTTP status).
10
- * - `meta`: Optional payload with extra context (response body, validation fields, etc.).
11
- * - `cause`: The original thrown value for debugging.
2
+ * Branded types for enhanced type safety and runtime validation
3
+ * These provide compile-time guarantees while maintaining runtime checks
12
4
  */
13
- type AppError<Code extends string = AppErrorCode | (string & {}), Meta = unknown> = {
14
- code: Code;
15
- message: string;
16
- status?: number;
17
- meta?: Meta;
18
- cause?: unknown;
5
+ type Milliseconds = number & {
6
+ readonly __brand: 'Milliseconds';
19
7
  };
20
- type NonNull<T> = T extends null ? never : T;
21
- type RuleReturn<R> = R extends (err: unknown) => infer Out ? NonNull<Out> : never;
22
- type InferErrorFromRules<TRules extends readonly Rule<any>[]> = TRules extends readonly [] ? AppError : RuleReturn<TRules[number]> | AppError<"UNKNOWN">;
23
- type Rule<E extends AppError = AppError> = (err: unknown) => E | null;
24
-
25
- type RetryDelayFn<E> = (attempt: number, err: E) => number;
26
- type MaybePromise<T> = T | Promise<T>;
27
- type Jitter = boolean | number | {
28
- ratio?: number;
29
- mode?: "full" | "equal";
30
- rng?: () => number;
31
- };
32
- /**
33
- * Backoff strategy to calculate the delay between retries.
34
- * - "linear": uses the base delay as is in each attempt.
35
- * - "exponential": multiplies the delay by 2^(attempt-1).
36
- * - "fibonacci": multiplies by F(attempt) (classic Fibonacci sequence).
37
- * - function: custom function based on the attempt number.
38
- */
39
- type BackoffStrategy = "linear" | "exponential" | "fibonacci" | ((attempt: number) => number);
40
- /**
41
- * Retry options for `run`, `runAll` and `runAllOrThrow`.
42
- */
43
- type RetryOptions<E extends AppError = AppError> = {
44
- /**
45
- * Number of retries to perform (does not include the initial attempt).
46
- * @default 0
47
- */
48
- retries?: number;
49
- /**
50
- * Delay between attempts:
51
- * - number: fixed delay (ms)
52
- * - () => number: lazy delay (evaluated per attempt)
53
- * - (attempt, err) => number: delay based on attempt and last error
54
- * @default 0 or a default baseDelay if retries are present
55
- */
56
- retryDelay?: number | (() => number) | RetryDelayFn<E>;
57
- /**
58
- * Decides whether to retry given a specific error.
59
- * Can be synchronous or asynchronous.
60
- * Receives the next attempt number and a context with accumulated metrics.
61
- * @default () => true
62
- */
63
- shouldRetry?: (attempt: number, error: E, context: RetryContext) => boolean | Promise<boolean>;
64
- /**
65
- * Random jitter to avoid thundering herd:
66
- * - true: default ratio 0.5
67
- * - false: no jitter
68
- * - number: ratio 0..1
69
- * - object: full control (ratio, mode, rng)
70
- * @default 0.5
71
- */
72
- jitter?: Jitter;
73
- /**
74
- * Backoff strategy to apply on the calculated delay.
75
- * @default "linear"
76
- */
77
- backoffStrategy?: BackoffStrategy;
78
- /**
79
- * Upper limit of the delay after backoff and before jitter.
80
- * @default undefined (no limit)
81
- */
82
- maxDelay?: number;
83
- };
84
- /**
85
- * Context for `shouldRetry` with accumulated metrics of the current attempt.
86
- */
87
- type RetryContext = {
88
- /** Total attempts (including the next retry). */
89
- totalAttempts: number;
90
- /** Elapsed time in ms since the start of `run`. */
91
- elapsedTime: number;
8
+ type RetryCount = number & {
9
+ readonly __brand: 'RetryCount';
92
10
  };
11
+ declare const asMilliseconds: (n: number) => Milliseconds;
12
+ declare const asRetryCount: (n: number) => RetryCount;
13
+
93
14
  /**
94
- * Main options for `run` and extended to `runAll`/`runAllOrThrow`.
15
+ * Modern typed error hierarchy with enhanced capabilities
16
+ * Provides type-safe error handling with fluent API and metadata support
95
17
  */
96
- type RunOptions<T, E extends AppError = AppError> = RetryOptions<E> & {
97
- /**
98
- * Normalizes an unknown error value to your type `E`.
99
- * If not provided, a default normalizer is used.
100
- */
101
- toError?: (err: unknown) => E;
102
- /**
103
- * Optional transformation applied after `toError`.
104
- * Useful for adjusting messages, codes, or adding metadata.
105
- */
106
- mapError?: (error: E) => E;
107
- /**
108
- * Callback on failure (not called if `ignoreAbort` and error is ABORTED).
109
- */
110
- onError?: (error: E) => void;
111
- /**
112
- * Callback on success.
113
- */
114
- onSuccess?: (data: T) => void;
115
- /**
116
- * Callback that always executes at the end (success or error).
117
- */
118
- onFinally?: () => void;
119
- /**
120
- * If true, aborts (ABORTED) are not considered fatal errors:
121
- * `onError` is not called and `{ ok: false, error }` is returned.
122
- * @default true
123
- */
124
- ignoreAbort?: boolean;
125
- /**
126
- * Signal for native work cancellation.
127
- * If aborted, it cuts with `AbortError`.
128
- */
129
- signal?: AbortSignal;
130
- /**
131
- * Maximum timeout in ms for the work; expires with `TimeoutError`.
132
- */
133
- timeout?: number;
134
- /**
135
- * Retry observability: receives attempt, error, and next delay.
136
- */
137
- onRetry?: (attempt: number, error: E, nextDelay: number) => void;
138
- /**
139
- * Optional structured logger for debug and errors.
140
- */
141
- logger?: {
142
- debug?: (msg: string, meta?: any) => void;
143
- error?: (msg: string, error: E) => void;
18
+
19
+ declare abstract class TypedError<Code extends string = string, Meta extends Record<string, unknown> = Record<string, unknown>, Raw = unknown> extends Error {
20
+ abstract readonly code: Code;
21
+ readonly cause?: unknown;
22
+ readonly meta: Meta;
23
+ readonly status?: number;
24
+ readonly raw: Raw;
25
+ readonly path?: string;
26
+ readonly timestamp: number;
27
+ readonly retryable: boolean;
28
+ constructor(message: string, opts: {
29
+ cause?: unknown;
30
+ meta?: Meta;
31
+ status?: number;
32
+ retryable?: boolean;
33
+ raw: Raw;
34
+ path?: string;
35
+ });
36
+ is<C extends string>(code: C): this is TypedError<C> & {
37
+ code: C;
38
+ };
39
+ withMeta<const M>(meta: M): this & {
40
+ meta: M;
41
+ };
42
+ withStatus(status: number): this & {
43
+ status: number;
44
+ };
45
+ withCause(cause: unknown): this & {
46
+ cause: unknown;
47
+ };
48
+ withPath(path: string): this;
49
+ withRaw<const R>(raw: R): this & {
50
+ raw: R;
144
51
  };
145
- /**
146
- * Callback on abort, useful for reacting to `AbortSignal`.
147
- */
148
- onAbort?: (signal: AbortSignal) => void;
149
- /**
150
- * Per-call circuit breaker configuration.
151
- * If not defined, can use the default value from `Runner`.
152
- */
153
- circuitBreaker?: CircuitBreakerOptions;
52
+ withRetryable(retryable: boolean): this;
53
+ toJSON(): Record<string, unknown>;
54
+ }
55
+ type AnyTypedError = TypedError<string, any, unknown>;
56
+ declare class TimeoutError extends TypedError<'TIMEOUT', Record<string, unknown>, unknown> {
57
+ readonly code: "TIMEOUT";
58
+ constructor(timeout: Milliseconds, cause?: unknown);
59
+ }
60
+ declare class AbortedError extends TypedError<'ABORTED', Record<string, unknown>, unknown> {
61
+ readonly code: "ABORTED";
62
+ constructor(reason?: string, cause?: unknown);
63
+ }
64
+ declare class CircuitOpenError extends TypedError<'CIRCUIT_OPEN', Record<string, unknown>, unknown> {
65
+ readonly code: "CIRCUIT_OPEN";
66
+ constructor(resetAfter: Milliseconds, cause?: unknown);
67
+ }
68
+ type ValidationMeta = Record<string, unknown> & {
69
+ validationErrors: unknown[];
154
70
  };
155
- /**
156
- * Circuit breaker configuration options:
157
- * - failureThreshold: number of consecutive failures to open the circuit
158
- * - resetTimeout: time in ms it remains open before attempting half-open
159
- * - halfOpenRequests: allowed quantity in half-open state
160
- */
161
- type CircuitBreakerOptions = {
162
- failureThreshold: number;
163
- resetTimeout: number;
164
- halfOpenRequests?: number;
71
+ declare class ValidationError extends TypedError<'VALIDATION', ValidationMeta, unknown> {
72
+ readonly validationErrors: unknown[];
73
+ readonly code: "VALIDATION";
74
+ constructor(message: string, validationErrors: unknown[], cause?: unknown);
75
+ }
76
+ declare class NetworkError extends TypedError<'NETWORK', Record<string, unknown>, unknown> {
77
+ readonly statusCode?: number | undefined;
78
+ readonly code: "NETWORK";
79
+ constructor(message: string, statusCode?: number | undefined, cause?: unknown);
80
+ }
81
+ type HttpMeta = Record<string, unknown> & {
82
+ response?: unknown;
165
83
  };
84
+ declare class HttpError extends TypedError<'HTTP', HttpMeta, unknown> {
85
+ readonly status: number;
86
+ readonly response?: unknown | undefined;
87
+ readonly code: "HTTP";
88
+ constructor(message: string, status: number, response?: unknown | undefined, cause?: unknown);
89
+ }
90
+ declare class UnknownError extends TypedError<'UNKNOWN', Record<string, unknown>, unknown> {
91
+ readonly code: "UNKNOWN";
92
+ constructor(message: string, cause?: unknown);
93
+ }
94
+
166
95
  /**
167
- * Execution metrics optionally returned in `RunResult`.
96
+ * Modern result types with enhanced discriminated unions
97
+ * Provides better type safety and more granular result categorization
168
98
  */
169
- type Metrics = {
170
- totalAttempts: number;
171
- totalRetries: number;
172
- totalDuration: number;
173
- lastError?: AppError;
174
- };
175
- type RunResult<T, E extends AppError = AppError> = {
176
- ok: true;
177
- data: T;
178
- error: null;
179
- metrics?: Metrics;
180
- } | {
181
- ok: false;
182
- data: null;
183
- error: E;
184
- metrics?: Metrics;
185
- };
99
+
100
+ type TryoResult<T, E extends AnyTypedError = AnyTypedError> = SuccessResult<T, E> | FailureResult<E> | AbortedResult<E> | TimeoutResult<E>;
101
+ interface SuccessResult<T, E extends AnyTypedError> {
102
+ readonly type: 'success';
103
+ readonly ok: true;
104
+ readonly data: T;
105
+ readonly error: null;
106
+ readonly metrics: TryoMetrics$1<E>;
107
+ }
108
+ interface FailureResult<E extends AnyTypedError> {
109
+ readonly type: 'failure';
110
+ readonly ok: false;
111
+ readonly data: null;
112
+ readonly error: E;
113
+ readonly metrics: TryoMetrics$1<E>;
114
+ }
115
+ interface AbortedResult<E extends AnyTypedError> {
116
+ readonly type: 'aborted';
117
+ readonly ok: false;
118
+ readonly data: null;
119
+ readonly error: E;
120
+ readonly metrics: TryoMetrics$1<E>;
121
+ }
122
+ interface TimeoutResult<E extends AnyTypedError> {
123
+ readonly type: 'timeout';
124
+ readonly ok: false;
125
+ readonly data: null;
126
+ readonly error: E;
127
+ readonly metrics: TryoMetrics$1<E>;
128
+ }
129
+ interface TryoMetrics$1<E extends AnyTypedError> {
130
+ readonly totalAttempts: RetryCount;
131
+ readonly totalRetries: RetryCount;
132
+ readonly totalDuration: Milliseconds;
133
+ readonly lastError?: E;
134
+ readonly retryHistory: Array<{
135
+ readonly attempt: RetryCount;
136
+ readonly error: E;
137
+ readonly delay: Milliseconds;
138
+ readonly timestamp: Date;
139
+ }>;
140
+ }
186
141
 
187
142
  /**
188
- * Executes an async operation and returns a Result instead of throwing.
189
- *
190
- * Errors are normalized into an `AppError` (or a custom error type `E`)
191
- * using the provided `toError` function.
192
- *
193
- * This utility is framework-agnostic and works in browsers, Node.js,
194
- * React effects, and any async context.
143
+ * Modern circuit breaker implementation with enhanced state management
144
+ * Provides circuit breaker pattern with type safety and observability
195
145
  */
196
- declare function run<T, E extends AppError = AppError>(fn: () => MaybePromise<T>, options?: RunOptions<T, E>): Promise<RunResult<T, E>>;
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';
197
158
 
198
159
  /**
199
- * Discriminated result per item in `runAllSettled`:
200
- * - "ok": successful task with `data`
201
- * - "error": failed task with `error`
202
- * - "skipped": task not executed due to cancellation/fail-fast/concurrency
160
+ * Modern error normalization system
161
+ * Provides type-safe error transformation and normalization
203
162
  */
204
- type RunAllItemResult<T, E extends AppError = AppError> = {
205
- status: "ok";
206
- ok: true;
207
- data: T;
208
- error: null;
209
- } | {
210
- status: "error";
211
- ok: false;
212
- data: null;
213
- error: E;
214
- } | {
215
- status: "skipped";
216
- ok: false;
217
- data: null;
218
- error: null;
219
- };
220
- /** Helper to discriminate successful results. */
221
- type SuccessResult<T> = Extract<RunAllItemResult<T, any>, {
222
- status: "ok";
223
- }>;
224
- /** Helper to discriminate error results. */
225
- type ErrorResult<E> = Extract<RunAllItemResult<any, E extends AppError ? E : AppError>, {
226
- status: "error";
227
- }>;
228
- /** Type guard that detects `status: "ok"` with `data` typing. */
229
- declare const isSuccess: <T, E extends AppError = AppError>(r: RunAllItemResult<T, E>) => r is SuccessResult<T>;
230
- type RunAllOptions<T, E extends AppError = AppError> = RunOptions<T, E> & {
231
- /**
232
- * Maximum number of concurrent tasks to run.
233
- * @default Infinity
234
- */
235
- concurrency?: number;
236
- /**
237
- * Execution mode regarding errors.
238
- * - "settle": Run all tasks (default).
239
- * - "fail-fast": Stop starting new tasks if one fails.
240
- * @default "settle"
241
- */
242
- mode?: "settle" | "fail-fast";
243
- };
244
- declare function runAllSettled<T, E extends AppError = AppError>(tasks: Array<() => MaybePromise<T>>, options?: RunAllOptions<T, E>): Promise<RunAllItemResult<T, E>[]>;
163
+
164
+ type ErrorNormalizer<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E;
165
+ type ErrorRule<E extends AnyTypedError = AnyTypedError> = (error: unknown) => E | null;
245
166
 
246
167
  /**
247
- * Options for `runAll`:
248
- * - Inherits all options from `RunOptions`
249
- * - `concurrency`: limit of simultaneous tasks; if one fails, it throws
168
+ * Modern retry strategies with enhanced capabilities
169
+ * Provides various retry patterns with type safety
250
170
  */
251
- type RunAllOrThrowOptions<T, E extends AppError = AppError> = RunOptions<T, E> & {
252
- /**
253
- * Maximum number of concurrent tasks to run.
254
- * @default Infinity
255
- */
256
- concurrency?: number;
257
- };
258
- declare function runAll<T, E extends AppError = AppError>(tasks: Array<() => MaybePromise$1<T>>, options?: RunAllOrThrowOptions<T, E>): Promise<T[]>;
259
171
 
260
- declare function createNormalizer<E extends AppError>(rules: Rule<E>[], fallback: (err: unknown) => E): (err: unknown) => E;
261
- declare function defaultFallback(err: unknown): AppError;
262
- declare function toAppError(err: unknown): AppError;
263
-
264
- declare const rules: {
265
- abort: Rule<AppError<"ABORTED">>;
266
- timeout: Rule<AppError<"TIMEOUT">>;
267
- httpStatus: Rule<AppError<"HTTP">>;
268
- aggregate: Rule<AppError<"UNKNOWN", {
269
- errors: unknown[];
270
- }>>;
271
- string: Rule<AppError<"UNKNOWN">>;
272
- message: Rule<AppError<"UNKNOWN">>;
172
+ type RetryStrategy = FixedDelayStrategy | ExponentialBackoffStrategy | FibonacciBackoffStrategy | CustomDelayStrategy;
173
+ interface FixedDelayStrategy {
174
+ readonly type: 'fixed';
175
+ readonly delay: number;
176
+ }
177
+ interface ExponentialBackoffStrategy {
178
+ readonly type: 'exponential';
179
+ readonly base: number;
180
+ readonly factor: number;
181
+ readonly maxDelay?: number;
182
+ }
183
+ interface FibonacciBackoffStrategy {
184
+ readonly type: 'fibonacci';
185
+ readonly base: number;
186
+ readonly maxDelay?: number;
187
+ }
188
+ interface CustomDelayStrategy {
189
+ readonly type: 'custom';
190
+ readonly calculate: (attempt: RetryCount, error: unknown) => number;
191
+ }
192
+ declare const RetryStrategies: {
193
+ readonly fixed: (delay: number) => FixedDelayStrategy;
194
+ readonly exponential: (base: number, factor?: number, maxDelay?: number) => ExponentialBackoffStrategy;
195
+ readonly fibonacci: (base: number, maxDelay?: number) => FibonacciBackoffStrategy;
196
+ readonly custom: (calculate: (attempt: RetryCount, error: unknown) => number) => CustomDelayStrategy;
273
197
  };
274
198
 
275
- declare class ErrorRuleBuilder<E> {
276
- private readonly matcher;
277
- constructor(matcher: (err: unknown) => err is E);
278
- toError<const Out extends AppError>(mapper: (err: E) => Out): Rule<Out>;
199
+ interface TryoConfig<E extends AnyTypedError = AnyTypedError> {
200
+ /** Abort signal passed to tasks */
201
+ readonly signal?: AbortSignal;
202
+ /** If true, aborts are treated as non-throwing failures */
203
+ readonly ignoreAbort?: boolean;
204
+ /** Timeout configuration */
205
+ readonly timeout?: number;
206
+ /** Retry configuration */
207
+ readonly retry?: RetryConfig<E>;
208
+ /** Circuit breaker configuration */
209
+ readonly circuitBreaker?: CircuitBreakerConfig<E>;
210
+ /** Error handling configuration */
211
+ readonly errorHandling: ErrorHandlingConfig<E>;
212
+ /** Concurrency configuration for batch operations */
213
+ readonly concurrency?: number;
214
+ /** Logging configuration */
215
+ readonly logger?: LoggerConfig<E>;
216
+ /** Callback hooks */
217
+ readonly hooks?: HookConfig<E>;
279
218
  }
280
- declare const errorRule: {
281
- instance<E extends new (...args: any[]) => unknown>(ctor: E): ErrorRuleBuilder<InstanceType<E>>;
282
- when<E = unknown>(predicate: (err: unknown) => err is E): ErrorRuleBuilder<E>;
219
+ interface RetryConfig<E extends AnyTypedError> {
220
+ /** Maximum number of retry attempts */
221
+ readonly maxRetries: number;
222
+ /** Base delay strategy */
223
+ readonly strategy: RetryStrategy;
224
+ /** Jitter configuration to prevent thundering herd */
225
+ readonly jitter?: JitterConfig;
226
+ /** Function to determine if retry should be attempted */
227
+ readonly shouldRetry?: ShouldRetryPredicate<E>;
228
+ }
229
+ type ShouldRetryPredicate<E extends AnyTypedError> = (attempt: number, error: E, context: RetryContext) => boolean;
230
+ interface RetryContext {
231
+ /** Total attempts made so far */
232
+ readonly totalAttempts: number;
233
+ /** Elapsed time since start */
234
+ readonly elapsedTime: number;
235
+ /** Start timestamp */
236
+ readonly startTime: Date;
237
+ /** Last delay applied */
238
+ readonly lastDelay?: number;
239
+ }
240
+ interface ErrorHandlingConfig<E extends AnyTypedError> {
241
+ /** Error normalizer function */
242
+ readonly normalizer: ErrorNormalizer<E>;
243
+ /** Optional error mapping/transformation */
244
+ readonly mapError?: (error: E) => E;
245
+ }
246
+ interface LoggerConfig<E extends AnyTypedError> {
247
+ /** Debug logging function */
248
+ readonly debug?: (message: string, meta?: unknown) => void;
249
+ /** Error logging function */
250
+ readonly error?: (message: string, error: E) => void;
251
+ /** Info logging function */
252
+ readonly info?: (message: string, meta?: unknown) => void;
253
+ /** Warning logging function */
254
+ readonly warn?: (message: string, meta?: unknown) => void;
255
+ }
256
+ interface HookConfig<E extends AnyTypedError> {
257
+ /** Called on successful execution */
258
+ readonly onSuccess?: <T>(data: T, metrics?: TryoMetrics<E>) => void;
259
+ /** Called on failed execution */
260
+ readonly onError?: (error: E, metrics?: TryoMetrics<E>) => void;
261
+ /** Called always, success or failure */
262
+ readonly onFinally?: (metrics?: TryoMetrics<E>) => void;
263
+ /** Called on abort */
264
+ readonly onAbort?: (signal: AbortSignal) => void;
265
+ /** Called before retry attempt */
266
+ readonly onRetry?: (attempt: number, error: E, delay: number) => void;
267
+ /** Called when circuit breaker state changes */
268
+ readonly onCircuitStateChange?: (from: CircuitState, to: CircuitState) => void;
269
+ }
270
+ type TryoMetrics<E extends AnyTypedError> = TryoMetrics$1<E>;
271
+ type JitterConfig = {
272
+ type: 'none';
273
+ } | {
274
+ type: 'full';
275
+ ratio: number;
276
+ } | {
277
+ type: 'equal';
278
+ ratio: number;
279
+ } | {
280
+ type: 'custom';
281
+ calculate: (delay: number) => number;
282
+ };
283
+ declare const JitterConfig: {
284
+ readonly none: () => JitterConfig;
285
+ readonly full: (ratio?: number) => JitterConfig;
286
+ readonly equal: (ratio?: number) => JitterConfig;
287
+ readonly custom: (calculate: (delay: number) => number) => JitterConfig;
283
288
  };
284
289
 
285
- type CreateRunnerOptions<E extends AppError = AppError> = {
286
- /**
287
- * Custom matchers to use for normalizing errors.
288
- * If not provided, the default matchers are used.
289
- */
290
- rules?: Rule<E>[];
291
- /**
292
- * Custom fallback function to use for normalizing errors.
293
- * If not provided, the default fallback is used.
294
- */
290
+ type RulesMode = 'extend' | 'replace';
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>;
297
+ type NonNull<T> = T extends null ? never : T;
298
+ type RuleReturn<R> = R extends (err: unknown) => infer Out ? NonNull<Out> : never;
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'> & {
301
+ rules?: Array<ErrorRule<E>>;
302
+ rulesMode?: RulesMode;
295
303
  fallback?: (err: unknown) => E;
296
- /**
297
- * If you want a completely custom normalizer, you can provide it directly.
298
- * If set, `matchers` and `fallback` are ignored.
299
- */
300
304
  toError?: (err: unknown) => E;
301
- /** Default for run options */
302
- ignoreAbort?: boolean;
303
- /** Optional default mapper for all runs */
304
305
  mapError?: (error: E) => E;
305
- /**
306
- * Default circuit breaker for all executions of the instance.
307
- * Can be overridden by `options.circuitBreaker` in each `run`.
308
- */
309
- circuitBreaker?: CircuitBreakerOptions;
310
306
  };
311
- interface Runner<E extends AppError> {
312
- run<T>(fn: () => Promise<T>, options?: RunOptions<T, E>): Promise<RunResult<T, E>>;
313
- all<T>(fns: Array<() => MaybePromise<T>>, options?: RunAllOptions<T, E>): Promise<RunAllItemResult<T, E>[]>;
314
- allOrThrow<T>(fns: Array<() => MaybePromise<T>>, options?: RunOptions<T, E>): Promise<T[]>;
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';
315
+ }): Tryo<InferErrorFromRules<TRules>>;
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> = {
322
+ run: <T>(task: (ctx: {
323
+ signal: AbortSignal;
324
+ }) => MaybePromise<T>, options?: RunOptions<E>) => Promise<TryoResult<T, E>>;
325
+ runOrThrow: <T>(task: (ctx: {
326
+ signal: AbortSignal;
327
+ }) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
328
+ orThrow: <T>(task: (ctx: {
329
+ signal: AbortSignal;
330
+ }) => MaybePromise<T>, options?: RunOptions<E>) => Promise<T>;
331
+ all: <T>(tasks: Array<(ctx: {
332
+ signal: AbortSignal;
333
+ }) => MaybePromise<T>>, options?: AllOptions<E>) => Promise<Array<TryoResult<T, E>>>;
334
+ allOrThrow: <T>(tasks: Array<(ctx: {
335
+ signal: AbortSignal;
336
+ }) => MaybePromise<T>>, options?: AllOptions<E>) => Promise<T[]>;
337
+ partitionAll: <T>(results: Array<TryoResult<T, E>>) => {
338
+ ok: Array<SuccessResult<T, E>>;
339
+ errors: Array<FailureResult<E> | AbortedResult<E> | TimeoutResult<E>>;
340
+ failure: Array<FailureResult<E>>;
341
+ aborted: Array<AbortedResult<E>>;
342
+ timeout: Array<TimeoutResult<E>>;
343
+ };
344
+ withConfig: (additionalConfig: Omit<Partial<TryoConfig<E>>, 'signal'>) => Tryo<E>;
345
+ };
346
+
347
+ declare const run: <T>(task: (ctx: {
348
+ signal: AbortSignal;
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>>;
359
+ declare const runOrThrow: <T>(task: (ctx: {
360
+ signal: AbortSignal;
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>;
371
+ declare const orThrow: <T>(task: (ctx: {
372
+ signal: AbortSignal;
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>;
383
+ declare const all: <T>(tasks: ((ctx: {
384
+ signal: AbortSignal;
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>[]>;
395
+ declare const allOrThrow: <T>(tasks: ((ctx: {
396
+ signal: AbortSignal;
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[]>;
407
+
408
+ /**
409
+ * Modern fluent error rule builder
410
+ * Provides type-safe error rule creation with enhanced ergonomics
411
+ */
412
+
413
+ declare class ErrorRuleBuilder<T> {
414
+ private readonly predicate;
415
+ constructor(predicate: (err: unknown) => err is T);
416
+ toCode<const C extends string>(code: C): ErrorMapper<T, C>;
417
+ toError<const Out extends {
418
+ code: string;
419
+ message: string;
420
+ meta?: Record<string, unknown>;
421
+ status?: number;
422
+ cause?: unknown;
423
+ retryable?: boolean;
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']>>;
427
+ }
428
+ declare class ErrorMapper<T, C extends string> {
429
+ private readonly predicate;
430
+ private readonly errorCode;
431
+ constructor(predicate: (err: unknown) => err is T, errorCode: C);
432
+ with<const M extends Record<string, unknown> = Record<string, unknown>, const R = '__NOT_SET__'>(mapper: (err: T) => {
433
+ message: string;
434
+ cause?: unknown;
435
+ meta?: M;
436
+ status?: number;
437
+ retryable?: boolean;
438
+ raw?: R;
439
+ path?: string;
440
+ }): ErrorRule<TypedError<C, M, R extends '__NOT_SET__' ? T : R>>;
315
441
  }
316
- declare function createRunner(opts?: Omit<CreateRunnerOptions<AppError>, "rules">): Runner<AppError>;
317
- declare function createRunner<const TRules extends readonly Rule<any>[]>(opts: {
318
- rules: TRules;
319
- } & Omit<CreateRunnerOptions<InferErrorFromRules<TRules>>, "rules">): Runner<InferErrorFromRules<TRules>>;
320
442
 
321
- export { type AppError, type AppErrorCode, type BackoffStrategy, type CircuitBreakerOptions, type CreateRunnerOptions, type ErrorResult, type Metrics, type RetryContext, type RetryOptions, type RunAllItemResult, type RunAllOptions, type RunOptions, type RunResult, type SuccessResult, createNormalizer, createRunner, defaultFallback, errorRule, isSuccess, rules, run, runAll, runAllSettled, toAppError };
443
+ declare const errorRule: {
444
+ readonly when: <T>(predicate: (err: unknown) => err is T) => ErrorRuleBuilder<T>;
445
+ readonly instance: <T extends new (...args: unknown[]) => unknown>(ErrorClass: T) => ErrorRuleBuilder<InstanceType<T>>;
446
+ };
447
+
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 };