clutchit 0.0.9 → 0.0.11
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/circuit/circuit.breaker.d.ts +51 -0
- package/dist/circuit/index.d.ts +10 -0
- package/dist/concurrency/bulkhead.d.ts +28 -0
- package/dist/concurrency/index.d.ts +23 -0
- package/dist/concurrency/rate-limiter.d.ts +29 -0
- package/dist/concurrency/ref.d.ts +11 -0
- package/dist/concurrency/semaphore.d.ts +15 -0
- package/dist/queue/base.queue.d.ts +18 -0
- package/dist/queue/bounded.queue.d.ts +11 -0
- package/dist/queue/dropping.queue.d.ts +7 -0
- package/dist/queue/faults.d.ts +24 -0
- package/dist/queue/index.d.ts +15 -0
- package/dist/queue/sliding.queue.d.ts +7 -0
- package/dist/retry/index.d.ts +8 -0
- package/dist/retry/retry.d.ts +21 -0
- package/dist/schedule/index.d.ts +36 -0
- package/dist/schedule/operators.d.ts +22 -0
- package/dist/schedule/runner.d.ts +31 -0
- package/dist/schedule/schedule.d.ts +35 -0
- package/dist/timeout/index.d.ts +7 -0
- package/dist/timeout/timeout.d.ts +18 -0
- package/dist/unthrow/do.d.ts +7 -0
- package/dist/unthrow/fault.d.ts +23 -0
- package/dist/unthrow/helpers.d.ts +16 -0
- package/dist/unthrow/index.d.ts +14 -0
- package/dist/unthrow/try.async.d.ts +29 -0
- package/dist/unthrow/try.async.js +3 -0
- package/dist/unthrow/try.d.ts +58 -0
- package/dist/unthrow/try.js +6 -0
- package/package.json +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { type TryAsync } from '../unthrow/index.js';
|
|
2
|
+
import { Schedule } from '../schedule/index.js';
|
|
3
|
+
export type CircuitState = 'closed' | 'open' | 'half-open';
|
|
4
|
+
declare const CircuitOpenFault_base: abstract new (fields: {
|
|
5
|
+
remainingTimeout: number;
|
|
6
|
+
}) => Readonly<{
|
|
7
|
+
remainingTimeout: number;
|
|
8
|
+
}> & {
|
|
9
|
+
readonly code: "CIRCUIT_OPEN";
|
|
10
|
+
readonly _category: "infrastructure";
|
|
11
|
+
readonly _transient: false;
|
|
12
|
+
readonly message: string;
|
|
13
|
+
};
|
|
14
|
+
export declare class CircuitOpenFault extends CircuitOpenFault_base {
|
|
15
|
+
readonly message: string;
|
|
16
|
+
}
|
|
17
|
+
export interface CircuitBreakerOptions {
|
|
18
|
+
/** Number of consecutive failures before opening. Default: 5 */
|
|
19
|
+
failureThreshold?: number;
|
|
20
|
+
/** Schedule for reset timing. Default: Schedule.constant(30_000) */
|
|
21
|
+
resetSchedule?: Schedule;
|
|
22
|
+
/** Number of trial requests allowed in half-open state. Default: 1 */
|
|
23
|
+
halfOpenAttempts?: number;
|
|
24
|
+
/** Predicate to determine if an error should count as a failure. Default: all errors count. */
|
|
25
|
+
isFailure?: (error: unknown) => boolean;
|
|
26
|
+
/** Called when circuit state changes (for logging/monitoring). */
|
|
27
|
+
onStateChange?: (from: CircuitState, to: CircuitState) => void;
|
|
28
|
+
}
|
|
29
|
+
export declare class CircuitBreaker {
|
|
30
|
+
private _state;
|
|
31
|
+
private _failureCount;
|
|
32
|
+
private _resetAttempt;
|
|
33
|
+
private _halfOpenTrials;
|
|
34
|
+
private _nextResetTime;
|
|
35
|
+
private readonly _failureThreshold;
|
|
36
|
+
private readonly _resetSchedule;
|
|
37
|
+
private readonly _maxHalfOpenAttempts;
|
|
38
|
+
private readonly _isFailure;
|
|
39
|
+
private readonly _onStateChange?;
|
|
40
|
+
constructor(options?: CircuitBreakerOptions);
|
|
41
|
+
protect<T, E>(fn: () => TryAsync<T, E>): TryAsync<T, E | CircuitOpenFault>;
|
|
42
|
+
get state(): CircuitState;
|
|
43
|
+
get failureCount(): number;
|
|
44
|
+
reset(): void;
|
|
45
|
+
private onSuccess;
|
|
46
|
+
private onFailure;
|
|
47
|
+
private scheduleReset;
|
|
48
|
+
private transition;
|
|
49
|
+
}
|
|
50
|
+
export {};
|
|
51
|
+
//# sourceMappingURL=circuit.breaker.d.ts.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CircuitBreaker } from './circuit.breaker.js';
|
|
2
|
+
import type { CircuitState, CircuitBreakerOptions } from './circuit.breaker.js';
|
|
3
|
+
export { CircuitOpenFault } from './circuit.breaker.js';
|
|
4
|
+
export declare namespace Circuit {
|
|
5
|
+
const Breaker: typeof CircuitBreaker;
|
|
6
|
+
type Breaker = CircuitBreaker;
|
|
7
|
+
type BreakerOptions = CircuitBreakerOptions;
|
|
8
|
+
type State = CircuitState;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type TryAsync } from '../unthrow/index.js';
|
|
2
|
+
declare const BulkheadRejectedFault_base: abstract new () => Readonly<Record<string, unknown>> & {
|
|
3
|
+
readonly code: "BULKHEAD_REJECTED";
|
|
4
|
+
readonly _category: "infrastructure";
|
|
5
|
+
readonly _transient: false;
|
|
6
|
+
readonly message: string;
|
|
7
|
+
};
|
|
8
|
+
export declare class BulkheadRejectedFault extends BulkheadRejectedFault_base {
|
|
9
|
+
readonly message = "Bulkhead capacity exceeded";
|
|
10
|
+
}
|
|
11
|
+
export interface BulkheadOptions {
|
|
12
|
+
concurrency: number;
|
|
13
|
+
queue?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare class Bulkhead {
|
|
16
|
+
private _active;
|
|
17
|
+
private readonly _maxConcurrency;
|
|
18
|
+
private readonly _maxQueue;
|
|
19
|
+
private readonly _queue;
|
|
20
|
+
constructor(options: BulkheadOptions);
|
|
21
|
+
execute<T, E>(fn: () => TryAsync<T, E>): TryAsync<T, E | BulkheadRejectedFault>;
|
|
22
|
+
get activeCount(): number;
|
|
23
|
+
get queueSize(): number;
|
|
24
|
+
private acquire;
|
|
25
|
+
private release;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=bulkhead.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Semaphore as _Semaphore } from './semaphore.js';
|
|
2
|
+
import type { SemaphoreOptions as _SemaphoreOptions } from './semaphore.js';
|
|
3
|
+
import { RateLimiter as _RateLimiter } from './rate-limiter.js';
|
|
4
|
+
import type { RateLimiterOptions as _RateLimiterOptions } from './rate-limiter.js';
|
|
5
|
+
import { Bulkhead as _Bulkhead } from './bulkhead.js';
|
|
6
|
+
import type { BulkheadOptions as _BulkheadOptions } from './bulkhead.js';
|
|
7
|
+
import { Ref as _Ref } from './ref.js';
|
|
8
|
+
export { RateLimitFault } from './rate-limiter.js';
|
|
9
|
+
export { BulkheadRejectedFault } from './bulkhead.js';
|
|
10
|
+
export declare namespace Concurrency {
|
|
11
|
+
const Semaphore: typeof _Semaphore;
|
|
12
|
+
type Semaphore = _Semaphore;
|
|
13
|
+
type SemaphoreOptions = _SemaphoreOptions;
|
|
14
|
+
const RateLimiter: typeof _RateLimiter;
|
|
15
|
+
type RateLimiter = _RateLimiter;
|
|
16
|
+
type RateLimiterOptions = _RateLimiterOptions;
|
|
17
|
+
const Bulkhead: typeof _Bulkhead;
|
|
18
|
+
type Bulkhead = _Bulkhead;
|
|
19
|
+
type BulkheadOptions = _BulkheadOptions;
|
|
20
|
+
const Ref: typeof _Ref;
|
|
21
|
+
type Ref<T> = _Ref<T>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type TryAsync } from '../unthrow/index.js';
|
|
2
|
+
declare const RateLimitFault_base: abstract new (fields: {
|
|
3
|
+
retryAfter: number;
|
|
4
|
+
}) => Readonly<{
|
|
5
|
+
retryAfter: number;
|
|
6
|
+
}> & {
|
|
7
|
+
readonly code: "RATE_LIMITED";
|
|
8
|
+
readonly _category: "infrastructure";
|
|
9
|
+
readonly _transient: true;
|
|
10
|
+
readonly message: string;
|
|
11
|
+
};
|
|
12
|
+
export declare class RateLimitFault extends RateLimitFault_base {
|
|
13
|
+
readonly message: string;
|
|
14
|
+
}
|
|
15
|
+
export interface RateLimiterOptions {
|
|
16
|
+
limit: number;
|
|
17
|
+
window: number;
|
|
18
|
+
}
|
|
19
|
+
export declare class RateLimiter {
|
|
20
|
+
private readonly _limit;
|
|
21
|
+
private readonly _window;
|
|
22
|
+
private readonly _timestamps;
|
|
23
|
+
constructor(options: RateLimiterOptions);
|
|
24
|
+
execute<T, E>(fn: () => TryAsync<T, E>): TryAsync<T, E | RateLimitFault>;
|
|
25
|
+
get remaining(): number;
|
|
26
|
+
private cleanup;
|
|
27
|
+
}
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type TryAsync } from '../unthrow/index.js';
|
|
2
|
+
export declare class Ref<T> {
|
|
3
|
+
private _value;
|
|
4
|
+
private readonly _mutex;
|
|
5
|
+
constructor(initial: T);
|
|
6
|
+
get(): T;
|
|
7
|
+
modify<R>(fn: (current: T) => [next: T, result: R]): TryAsync<R, never>;
|
|
8
|
+
update(fn: (current: T) => T): TryAsync<void, never>;
|
|
9
|
+
set(value: T): TryAsync<void, never>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=ref.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type TryAsync } from '../unthrow/index.js';
|
|
2
|
+
export interface SemaphoreOptions {
|
|
3
|
+
permits: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class Semaphore {
|
|
6
|
+
private _available;
|
|
7
|
+
private readonly _queue;
|
|
8
|
+
constructor(options: SemaphoreOptions);
|
|
9
|
+
execute<T, E>(fn: () => TryAsync<T, E>): TryAsync<T, E>;
|
|
10
|
+
get available(): number;
|
|
11
|
+
get waiting(): number;
|
|
12
|
+
private acquire;
|
|
13
|
+
private release;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=semaphore.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Try, type TryAsync } from '../unthrow/index.js';
|
|
2
|
+
import { QueueEmptyFault } from './faults.js';
|
|
3
|
+
export interface QueueOptions {
|
|
4
|
+
capacity: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class BaseQueue<T> {
|
|
7
|
+
protected readonly _buffer: T[];
|
|
8
|
+
protected readonly _capacity: number;
|
|
9
|
+
protected readonly _takeWaiters: Array<(item: T) => void>;
|
|
10
|
+
constructor(options: QueueOptions);
|
|
11
|
+
protected _tryTake(): Try<T, QueueEmptyFault>;
|
|
12
|
+
take(signal?: AbortSignal): TryAsync<T, never>;
|
|
13
|
+
takeBatch(n: number, signal?: AbortSignal): TryAsync<T[], never>;
|
|
14
|
+
poll(): Try<T, QueueEmptyFault>;
|
|
15
|
+
get size(): number;
|
|
16
|
+
get capacity(): number;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=base.queue.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Try, type TryAsync } from '../unthrow/index.js';
|
|
2
|
+
import { QueueEmptyFault, QueueFullFault } from './faults.js';
|
|
3
|
+
import { BaseQueue, type QueueOptions } from './base.queue.js';
|
|
4
|
+
export declare class BoundedQueue<T> extends BaseQueue<T> {
|
|
5
|
+
private readonly _putWaiters;
|
|
6
|
+
constructor(options: QueueOptions);
|
|
7
|
+
protected _tryTake(): Try<T, QueueEmptyFault>;
|
|
8
|
+
offer(item: T): Try<void, QueueFullFault>;
|
|
9
|
+
put(item: T, signal?: AbortSignal): TryAsync<void, never>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=bounded.queue.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { BaseQueue, type QueueOptions } from './base.queue.js';
|
|
2
|
+
export declare class DroppingQueue<T> extends BaseQueue<T> {
|
|
3
|
+
constructor(options: QueueOptions);
|
|
4
|
+
/** Always succeeds. Drops the item if full. Returns whether item was accepted. */
|
|
5
|
+
offer(item: T): boolean;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=dropping.queue.d.ts.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
declare const QueueFullFault_base: abstract new (fields: {
|
|
2
|
+
capacity: number;
|
|
3
|
+
}) => Readonly<{
|
|
4
|
+
capacity: number;
|
|
5
|
+
}> & {
|
|
6
|
+
readonly code: "QUEUE_FULL";
|
|
7
|
+
readonly _category: "infrastructure";
|
|
8
|
+
readonly _transient: false;
|
|
9
|
+
readonly message: string;
|
|
10
|
+
};
|
|
11
|
+
export declare class QueueFullFault extends QueueFullFault_base {
|
|
12
|
+
readonly message: string;
|
|
13
|
+
}
|
|
14
|
+
declare const QueueEmptyFault_base: abstract new () => Readonly<Record<string, unknown>> & {
|
|
15
|
+
readonly code: "QUEUE_EMPTY";
|
|
16
|
+
readonly _category: "infrastructure";
|
|
17
|
+
readonly _transient: false;
|
|
18
|
+
readonly message: string;
|
|
19
|
+
};
|
|
20
|
+
export declare class QueueEmptyFault extends QueueEmptyFault_base {
|
|
21
|
+
readonly message = "Queue is empty";
|
|
22
|
+
}
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=faults.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { QueueOptions } from './base.queue.js';
|
|
2
|
+
import { BoundedQueue } from './bounded.queue.js';
|
|
3
|
+
import { DroppingQueue } from './dropping.queue.js';
|
|
4
|
+
import { SlidingQueue } from './sliding.queue.js';
|
|
5
|
+
export { QueueFullFault, QueueEmptyFault } from './faults.js';
|
|
6
|
+
export declare namespace Queue {
|
|
7
|
+
type Options = QueueOptions;
|
|
8
|
+
const Bounded: typeof BoundedQueue;
|
|
9
|
+
type Bounded<T> = BoundedQueue<T>;
|
|
10
|
+
const Dropping: typeof DroppingQueue;
|
|
11
|
+
type Dropping<T> = DroppingQueue<T>;
|
|
12
|
+
const Sliding: typeof SlidingQueue;
|
|
13
|
+
type Sliding<T> = SlidingQueue<T>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { BaseQueue, type QueueOptions } from './base.queue.js';
|
|
2
|
+
export declare class SlidingQueue<T> extends BaseQueue<T> {
|
|
3
|
+
constructor(options: QueueOptions);
|
|
4
|
+
/** Always succeeds. Drops oldest if full. */
|
|
5
|
+
offer(item: T): void;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=sliding.queue.d.ts.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type TryAsync } from '../unthrow/index.js';
|
|
2
|
+
import { Schedule } from '../schedule/index.js';
|
|
3
|
+
export interface RetryOptions<E = unknown> {
|
|
4
|
+
/** Schedule for backoff timing. Default: exponential(200) | recurs(3) */
|
|
5
|
+
schedule?: Schedule;
|
|
6
|
+
/**
|
|
7
|
+
* Predicate to decide if an error should be retried.
|
|
8
|
+
* Default: retries transient errors (error._transient === true).
|
|
9
|
+
*/
|
|
10
|
+
retryOn?: (error: E) => boolean;
|
|
11
|
+
/** Called on each retry attempt (for logging/observability). */
|
|
12
|
+
onRetry?: (error: E, attempt: number, delay: number) => void;
|
|
13
|
+
/** External cancellation signal. Aborts retrying when signalled. */
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
}
|
|
16
|
+
export declare class RetryPolicy {
|
|
17
|
+
private readonly defaults?;
|
|
18
|
+
constructor(defaults?: RetryOptions | undefined);
|
|
19
|
+
execute<T, E>(fn: (signal: AbortSignal) => TryAsync<T, E>, options?: RetryOptions<E>): TryAsync<T, E>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=retry.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Schedule as _Schedule } from './schedule.js';
|
|
2
|
+
import type { ScheduleStep, ScheduleOperator } from './schedule.js';
|
|
3
|
+
import { recurs as _recurs, cappedDelay as _cappedDelay, jittered as _jittered, upTo as _upTo, andThen as _andThen, union as _union, intersect as _intersect, whileInput as _whileInput, whileOutput as _whileOutput, map as _map } from './operators.js';
|
|
4
|
+
import { repeat as _repeat } from './runner.js';
|
|
5
|
+
import type { RepeatOptions as _RepeatOptions } from './runner.js';
|
|
6
|
+
export { ScheduleInterruptedFault } from './runner.js';
|
|
7
|
+
export type Schedule<In = unknown, Out = number> = _Schedule<In, Out>;
|
|
8
|
+
export declare namespace Schedule {
|
|
9
|
+
type Step = ScheduleStep;
|
|
10
|
+
type Operator = ScheduleOperator;
|
|
11
|
+
const spaced: (ms: number) => _Schedule;
|
|
12
|
+
const exponential: (initialDelay: number, multiplier?: number) => _Schedule;
|
|
13
|
+
const linear: (initialDelay: number) => _Schedule;
|
|
14
|
+
const constant: (delay: number) => _Schedule;
|
|
15
|
+
const fixed: (interval: number) => _Schedule;
|
|
16
|
+
const windowed: (interval: number) => _Schedule;
|
|
17
|
+
const forever: _Schedule<unknown, number>;
|
|
18
|
+
const once: _Schedule<unknown, number>;
|
|
19
|
+
const fibonacci: (one: number) => _Schedule;
|
|
20
|
+
const cron: (expression: string, options?: {
|
|
21
|
+
timezone?: string;
|
|
22
|
+
}) => _Schedule;
|
|
23
|
+
const recurs: typeof _recurs;
|
|
24
|
+
const cappedDelay: typeof _cappedDelay;
|
|
25
|
+
const jittered: typeof _jittered;
|
|
26
|
+
const upTo: typeof _upTo;
|
|
27
|
+
const andThen: typeof _andThen;
|
|
28
|
+
const union: typeof _union;
|
|
29
|
+
const intersect: typeof _intersect;
|
|
30
|
+
const whileInput: typeof _whileInput;
|
|
31
|
+
const whileOutput: typeof _whileOutput;
|
|
32
|
+
const map: typeof _map;
|
|
33
|
+
const repeat: typeof _repeat;
|
|
34
|
+
type RepeatOptions = _RepeatOptions;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Schedule, type ScheduleOperator } from './schedule.js';
|
|
2
|
+
/** Limit total repetitions to n */
|
|
3
|
+
export declare function recurs(n: number): ScheduleOperator;
|
|
4
|
+
/** Cap individual delay to maxDelay ms */
|
|
5
|
+
export declare function cappedDelay(maxDelay: number): ScheduleOperator;
|
|
6
|
+
/** Add random jitter (±factor, default ±0.25) */
|
|
7
|
+
export declare function jittered(factor?: number): ScheduleOperator;
|
|
8
|
+
/** Stop after total elapsed time exceeds duration ms */
|
|
9
|
+
export declare function upTo(duration: number): ScheduleOperator;
|
|
10
|
+
/** Sequential composition: run base until it stops, then switch to next */
|
|
11
|
+
export declare function andThen(next: Schedule): ScheduleOperator;
|
|
12
|
+
/** Continue while either wants to; use shorter delay */
|
|
13
|
+
export declare function union(other: Schedule): ScheduleOperator;
|
|
14
|
+
/** Continue while both want to; use longer delay */
|
|
15
|
+
export declare function intersect(other: Schedule): ScheduleOperator;
|
|
16
|
+
/** Continue while the input satisfies the predicate */
|
|
17
|
+
export declare function whileInput<In>(predicate: (input: In) => boolean): <Out>(schedule: Schedule<In, Out>) => Schedule<In, Out>;
|
|
18
|
+
/** Continue while the output satisfies the predicate */
|
|
19
|
+
export declare function whileOutput<Out>(predicate: (output: Out) => boolean): <In>(schedule: Schedule<In, Out>) => Schedule<In, Out>;
|
|
20
|
+
/** Transform the output value */
|
|
21
|
+
export declare function map<Out, Out2>(f: (output: Out) => Out2): <In>(schedule: Schedule<In, Out>) => Schedule<In, Out2>;
|
|
22
|
+
//# sourceMappingURL=operators.d.ts.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type TryAsync } from '../unthrow/index.js';
|
|
2
|
+
import type { Schedule } from './schedule.js';
|
|
3
|
+
declare const ScheduleInterruptedFault_base: abstract new () => Readonly<Record<string, unknown>> & {
|
|
4
|
+
readonly code: "SCHEDULE_INTERRUPTED";
|
|
5
|
+
readonly _category: "infrastructure";
|
|
6
|
+
readonly _transient: false;
|
|
7
|
+
readonly message: string;
|
|
8
|
+
};
|
|
9
|
+
export declare class ScheduleInterruptedFault extends ScheduleInterruptedFault_base {
|
|
10
|
+
readonly message = "Scheduled execution was interrupted";
|
|
11
|
+
}
|
|
12
|
+
export interface RepeatOptions {
|
|
13
|
+
/** External cancellation signal. Aborts the loop when signalled. */
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
/** Called after each execution (for logging/observability). */
|
|
16
|
+
onExecution?: (attempt: number, delay: number) => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Execute `fn` repeatedly according to the given schedule's timing.
|
|
20
|
+
*
|
|
21
|
+
* - Executes `fn` immediately (no initial delay).
|
|
22
|
+
* - After each successful execution, consults schedule.next() for the delay and continuation.
|
|
23
|
+
* - If the schedule returns `continue: false`, resolves with Ok(output).
|
|
24
|
+
* - If `fn` returns an Err, stops immediately and surfaces the error.
|
|
25
|
+
* - If the signal is aborted, stops and returns Err(ScheduleInterruptedFault).
|
|
26
|
+
*
|
|
27
|
+
* Returns the last schedule output on completion.
|
|
28
|
+
*/
|
|
29
|
+
export declare function repeat<Out, E>(schedule: Schedule<unknown, Out>, fn: (signal: AbortSignal) => TryAsync<void, E>, options?: RepeatOptions): TryAsync<Out, E | ScheduleInterruptedFault>;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface ScheduleStep<Out = number> {
|
|
2
|
+
readonly delay: number;
|
|
3
|
+
readonly continue: boolean;
|
|
4
|
+
readonly output: Out;
|
|
5
|
+
}
|
|
6
|
+
export type ScheduleOperator = <In, Out>(schedule: Schedule<In, Out>) => Schedule<In, Out>;
|
|
7
|
+
export declare class Schedule<In = unknown, Out = number> {
|
|
8
|
+
private readonly _next;
|
|
9
|
+
constructor(_next: (input: In, attempt: number) => ScheduleStep<Out>);
|
|
10
|
+
next(input: In, attempt: number): ScheduleStep<Out>;
|
|
11
|
+
pipe<Out2 = Out>(operator: (schedule: Schedule<In, Out>) => Schedule<In, Out2>): Schedule<In, Out2>;
|
|
12
|
+
/** Fixed delay between executions (from completion to next start) */
|
|
13
|
+
static spaced: (ms: number) => Schedule;
|
|
14
|
+
/** Exponential backoff: initialDelay * multiplier^attempt */
|
|
15
|
+
static exponential: (initialDelay: number, multiplier?: number) => Schedule;
|
|
16
|
+
/** Linear backoff: initialDelay * (attempt + 1) */
|
|
17
|
+
static linear: (initialDelay: number) => Schedule;
|
|
18
|
+
/** Constant delay (alias for spaced) */
|
|
19
|
+
static constant: (delay: number) => Schedule;
|
|
20
|
+
/** Fixed interval from start to start (compensates for execution time) */
|
|
21
|
+
static fixed: (interval: number) => Schedule;
|
|
22
|
+
/** Aligned to wall-clock time windows */
|
|
23
|
+
static windowed: (interval: number) => Schedule;
|
|
24
|
+
/** Zero-delay infinite schedule */
|
|
25
|
+
static forever: Schedule;
|
|
26
|
+
/** Continue once then stop. With repeat: initial + 1 repetition = 2 total executions */
|
|
27
|
+
static once: Schedule;
|
|
28
|
+
/** Fibonacci delay sequence: one, one, 2*one, 3*one, 5*one, 8*one, ... */
|
|
29
|
+
static fibonacci: (one: number) => Schedule;
|
|
30
|
+
/** Cron expression schedule (aligned to cron windows) */
|
|
31
|
+
static cron: (expression: string, options?: {
|
|
32
|
+
timezone?: string;
|
|
33
|
+
}) => Schedule;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=schedule.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { withTimeout as _withTimeout, createTimeout as _createTimeout } from './timeout.js';
|
|
2
|
+
export { TimeoutFault } from './timeout.js';
|
|
3
|
+
export declare namespace Timeout {
|
|
4
|
+
const wrap: typeof _withTimeout;
|
|
5
|
+
const create: typeof _createTimeout;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type TryAsync } from '../unthrow/index.js';
|
|
2
|
+
declare const TimeoutFault_base: abstract new (fields: {
|
|
3
|
+
duration: number;
|
|
4
|
+
}) => Readonly<{
|
|
5
|
+
duration: number;
|
|
6
|
+
}> & {
|
|
7
|
+
readonly code: "TIMEOUT";
|
|
8
|
+
readonly _category: "infrastructure";
|
|
9
|
+
readonly _transient: true;
|
|
10
|
+
readonly message: string;
|
|
11
|
+
};
|
|
12
|
+
export declare class TimeoutFault extends TimeoutFault_base {
|
|
13
|
+
readonly message: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function withTimeout<T, E>(fn: (signal: AbortSignal) => TryAsync<T, E>, duration: number): TryAsync<T, E | TimeoutFault>;
|
|
16
|
+
export declare function createTimeout(duration: number): <T, E>(fn: (signal: AbortSignal) => TryAsync<T, E>) => TryAsync<T, E | TimeoutFault>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=timeout.d.ts.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Try, Err } from './try.js';
|
|
2
|
+
import { TryAsync } from './try.async.js';
|
|
3
|
+
export declare function Do<T, E>(generator: () => Generator<Err<never, E>, T>): Try<T, NoInfer<E>>;
|
|
4
|
+
export declare function Do<C, T, E>(ctx: C, generator: (ctx: C) => Generator<Err<never, E>, T>): Try<T, NoInfer<E>>;
|
|
5
|
+
export declare function DoAsync<T, E>(generator: () => AsyncGenerator<Err<never, E>, T>): TryAsync<T, NoInfer<E>>;
|
|
6
|
+
export declare function DoAsync<C, T, E>(ctx: C, generator: (ctx: C) => AsyncGenerator<Err<never, E>, T>): TryAsync<T, NoInfer<E>>;
|
|
7
|
+
//# sourceMappingURL=do.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface Fault {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
readonly message: string;
|
|
4
|
+
readonly _category: 'domain' | 'infrastructure';
|
|
5
|
+
readonly _transient: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function isFault(value: unknown): value is Fault;
|
|
8
|
+
export declare function isDomainFault(value: unknown): value is Fault & {
|
|
9
|
+
readonly _category: 'domain';
|
|
10
|
+
};
|
|
11
|
+
export declare function isInfrastructureFault(value: unknown): value is Fault & {
|
|
12
|
+
readonly _category: 'infrastructure';
|
|
13
|
+
};
|
|
14
|
+
export declare function isTransientFault(value: unknown): value is Fault & {
|
|
15
|
+
readonly _transient: true;
|
|
16
|
+
};
|
|
17
|
+
export declare function Fault<const Code extends string, const Category extends 'domain' | 'infrastructure', const Transient extends boolean = false>(code: Code, category: Category, transient?: Transient): <A extends Record<string, unknown> = Record<string, unknown>>() => abstract new (...args: Record<string, unknown> extends A ? [] : [fields: A]) => Readonly<A> & {
|
|
18
|
+
readonly code: Code;
|
|
19
|
+
readonly _category: Category;
|
|
20
|
+
readonly _transient: Transient;
|
|
21
|
+
readonly message: string;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=fault.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Try } from './try.js';
|
|
2
|
+
import { TryAsync } from './try.async.js';
|
|
3
|
+
export declare function combine<T, E>(results: Try<T, E>[]): Try<T[], E>;
|
|
4
|
+
export declare function combine<T, E>(results: TryAsync<T, E>[]): TryAsync<T[], E>;
|
|
5
|
+
export declare function combineWithAllErrors<T, E>(results: Try<T, E>[]): Try<T[], E[]>;
|
|
6
|
+
export declare function combineWithAllErrors<T, E>(results: TryAsync<T, E>[]): TryAsync<T[], E[]>;
|
|
7
|
+
export declare function fromPromise<T, E>(promise: Promise<T>, errorMapper: (error: unknown) => E): TryAsync<T, E>;
|
|
8
|
+
export declare function fromSafePromise<T>(promise: Promise<T>): TryAsync<T, never>;
|
|
9
|
+
export declare function fromThrowable<T, E>(fn: () => T, errorMapper: (error: unknown) => E): Try<T, E>;
|
|
10
|
+
export declare function fromAsyncThrowable<T, E>(fn: () => Promise<T>, errorMapper: (error: unknown) => E): TryAsync<T, E>;
|
|
11
|
+
export declare function unwrap<T, E, F>(result: Try<T | null | undefined, E>, fault: F): Try<NonNullable<T>, E | F>;
|
|
12
|
+
export declare function unwrap<T, E, F>(result: TryAsync<T | null | undefined, E>, fault: F): TryAsync<NonNullable<T>, E | F>;
|
|
13
|
+
export declare function flatten<T, E1, E2>(result: Try<Try<T, E2>, E1>): Try<T, E1 | E2>;
|
|
14
|
+
export declare function flatten<T, E1, E2>(result: TryAsync<Try<T, E2>, E1>): TryAsync<T, E1 | E2>;
|
|
15
|
+
export declare function race<T, E>(results: TryAsync<T, E>[]): TryAsync<T, E>;
|
|
16
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Fault as _Fault, isFault as _isFault, isDomainFault as _isDomainFault, isInfrastructureFault as _isInfrastructureFault, isTransientFault as _isTransientFault } from './fault.js';
|
|
2
|
+
export type Fault = _Fault;
|
|
3
|
+
export declare namespace Fault {
|
|
4
|
+
const Tagged: typeof _Fault;
|
|
5
|
+
const is: typeof _isFault;
|
|
6
|
+
const isDomain: typeof _isDomainFault;
|
|
7
|
+
const isInfrastructure: typeof _isInfrastructureFault;
|
|
8
|
+
const isTransient: typeof _isTransientFault;
|
|
9
|
+
}
|
|
10
|
+
export { type Try, Ok, Err, ok, err } from './try.js';
|
|
11
|
+
export { TryAsync, okAsync, errAsync } from './try.async.js';
|
|
12
|
+
export { fromPromise, fromSafePromise, fromThrowable, fromAsyncThrowable, combine, combineWithAllErrors, unwrap, flatten, race, } from './helpers.js';
|
|
13
|
+
export { Do, DoAsync } from './do.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type Try, Err } from './try.js';
|
|
2
|
+
export declare class TryAsync<T, E> implements PromiseLike<Try<T, E>> {
|
|
3
|
+
private readonly _promise;
|
|
4
|
+
readonly then: PromiseLike<Try<T, E>>['then'];
|
|
5
|
+
constructor(promise: Promise<Try<T, E>>);
|
|
6
|
+
map<U>(fn: (value: T) => U | Promise<U>): TryAsync<U, E>;
|
|
7
|
+
mapErr<F>(fn: (error: E) => F | Promise<F>): TryAsync<T, F>;
|
|
8
|
+
andThen<U, F>(fn: (value: T) => Try<U, F> | TryAsync<U, F>): TryAsync<U, E | F>;
|
|
9
|
+
orElse<F>(fn: (error: E) => Try<T, F> | TryAsync<T, F>): TryAsync<T, F>;
|
|
10
|
+
tap(fn: (value: T) => void | Promise<void>): TryAsync<T, E>;
|
|
11
|
+
tapErr(fn: (error: E) => void | Promise<void>): TryAsync<T, E>;
|
|
12
|
+
andThrough<F>(fn: (value: T) => Try<unknown, F> | TryAsync<unknown, F>): TryAsync<T, E | F>;
|
|
13
|
+
orThrough<F>(fn: (error: E) => Try<unknown, F> | TryAsync<unknown, F>): TryAsync<T, E | F>;
|
|
14
|
+
catchFault<Code extends string, F>(code: Code, fn: (fault: Extract<E, {
|
|
15
|
+
code: Code;
|
|
16
|
+
}>) => Try<T, F> | TryAsync<T, F>): TryAsync<T, Exclude<E, {
|
|
17
|
+
code: Code;
|
|
18
|
+
}> | F>;
|
|
19
|
+
unwrapOr(defaultValue: T): Promise<T>;
|
|
20
|
+
match<U>(cases: {
|
|
21
|
+
ok: (value: T) => U;
|
|
22
|
+
err: (error: E) => U;
|
|
23
|
+
}): Promise<U>;
|
|
24
|
+
pipe<R>(fn: (result: TryAsync<T, E>) => R): R;
|
|
25
|
+
[Symbol.asyncIterator](): AsyncGenerator<Err<never, E>, T>;
|
|
26
|
+
}
|
|
27
|
+
export declare function okAsync<T, E = never>(value: T): TryAsync<T, E>;
|
|
28
|
+
export declare function errAsync<T = never, E = unknown>(error: E): TryAsync<T, E>;
|
|
29
|
+
//# sourceMappingURL=try.async.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export type Try<T, E> = Ok<T, E> | Err<T, E>;
|
|
2
|
+
export declare class Ok<T, E = never> {
|
|
3
|
+
readonly value: T;
|
|
4
|
+
readonly _tag: symbol;
|
|
5
|
+
constructor(value: T);
|
|
6
|
+
isOk(): this is Ok<T, E>;
|
|
7
|
+
isErr(): this is Err<T, E>;
|
|
8
|
+
map<U>(fn: (value: T) => U): Try<U, E>;
|
|
9
|
+
mapErr<F>(_fn: (error: E) => F): Try<T, F>;
|
|
10
|
+
andThen<U, F>(fn: (value: T) => Try<U, F>): Try<U, E | F>;
|
|
11
|
+
orElse<F>(_fn: (error: E) => Try<T, F>): Try<T, F>;
|
|
12
|
+
tap(fn: (value: T) => void): Try<T, E>;
|
|
13
|
+
tapErr(_fn: (error: E) => void): Try<T, E>;
|
|
14
|
+
andThrough<F>(fn: (value: T) => Try<unknown, F>): Try<T, E | F>;
|
|
15
|
+
orThrough<F>(_fn: (error: E) => Try<unknown, F>): Try<T, E | F>;
|
|
16
|
+
catchFault<Code extends string, F>(_code: Code, _fn: (fault: Extract<E, {
|
|
17
|
+
code: Code;
|
|
18
|
+
}>) => Try<T, F>): Try<T, Exclude<E, {
|
|
19
|
+
code: Code;
|
|
20
|
+
}> | F>;
|
|
21
|
+
unwrapOr(_defaultValue: T): T;
|
|
22
|
+
match<U>(cases: {
|
|
23
|
+
ok: (value: T) => U;
|
|
24
|
+
err: (error: E) => U;
|
|
25
|
+
}): U;
|
|
26
|
+
pipe<R>(fn: (result: Try<T, E>) => R): R;
|
|
27
|
+
[Symbol.iterator](): Generator<Err<never, E>, T>;
|
|
28
|
+
}
|
|
29
|
+
export declare class Err<T = never, E = unknown> {
|
|
30
|
+
readonly error: E;
|
|
31
|
+
readonly _tag: symbol;
|
|
32
|
+
constructor(error: E);
|
|
33
|
+
isOk(): this is Ok<T, E>;
|
|
34
|
+
isErr(): this is Err<T, E>;
|
|
35
|
+
map<U>(_fn: (value: T) => U): Try<U, E>;
|
|
36
|
+
mapErr<F>(fn: (error: E) => F): Try<T, F>;
|
|
37
|
+
andThen<U, F>(_fn: (value: T) => Try<U, F>): Try<U, E | F>;
|
|
38
|
+
orElse<F>(fn: (error: E) => Try<T, F>): Try<T, F>;
|
|
39
|
+
tap(_fn: (value: T) => void): Try<T, E>;
|
|
40
|
+
tapErr(fn: (error: E) => void): Try<T, E>;
|
|
41
|
+
andThrough<F>(_fn: (value: T) => Try<unknown, F>): Try<T, E | F>;
|
|
42
|
+
orThrough<F>(fn: (error: E) => Try<unknown, F>): Try<T, E | F>;
|
|
43
|
+
catchFault<Code extends string, F>(code: Code, fn: (fault: Extract<E, {
|
|
44
|
+
code: Code;
|
|
45
|
+
}>) => Try<T, F>): Try<T, Exclude<E, {
|
|
46
|
+
code: Code;
|
|
47
|
+
}> | F>;
|
|
48
|
+
unwrapOr(defaultValue: T): T;
|
|
49
|
+
match<U>(cases: {
|
|
50
|
+
ok: (value: T) => U;
|
|
51
|
+
err: (error: E) => U;
|
|
52
|
+
}): U;
|
|
53
|
+
pipe<R>(fn: (result: Try<T, E>) => R): R;
|
|
54
|
+
[Symbol.iterator](): Generator<Err<never, E>, T>;
|
|
55
|
+
}
|
|
56
|
+
export declare function ok<T, E = never>(value: T): Ok<T, E>;
|
|
57
|
+
export declare function err<T = never, E = unknown>(error: E): Err<T, E>;
|
|
58
|
+
//# sourceMappingURL=try.d.ts.map
|
package/dist/unthrow/try.js
CHANGED
|
@@ -49,6 +49,9 @@ export class Ok {
|
|
|
49
49
|
match(cases) {
|
|
50
50
|
return cases.ok(this.value);
|
|
51
51
|
}
|
|
52
|
+
pipe(fn) {
|
|
53
|
+
return fn(this);
|
|
54
|
+
}
|
|
52
55
|
// eslint-disable-next-line require-yield
|
|
53
56
|
*[Symbol.iterator]() {
|
|
54
57
|
return this.value;
|
|
@@ -110,6 +113,9 @@ export class Err {
|
|
|
110
113
|
match(cases) {
|
|
111
114
|
return cases.err(this.error);
|
|
112
115
|
}
|
|
116
|
+
pipe(fn) {
|
|
117
|
+
return fn(this);
|
|
118
|
+
}
|
|
113
119
|
*[Symbol.iterator]() {
|
|
114
120
|
// @ts-expect-error -- structurally equivalent, safe for Do notation
|
|
115
121
|
yield this;
|
package/package.json
CHANGED