airbag 0.1.0
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 +180 -0
- package/dist/index.d.mts +160 -0
- package/dist/index.d.ts +160 -0
- package/dist/index.js +386 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +353 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Airbag
|
|
2
|
+
|
|
3
|
+
Execution Orchestration Layer for JavaScript/TypeScript.
|
|
4
|
+
|
|
5
|
+
Replace imperative `try/catch/finally` blocks with declarative async function wrappers. Airbag handles **loading states**, **error catching**, **retries with exponential backoff**, **timeouts**, and **circuit breaking** — fully type-safe with zero runtime dependencies.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install airbag
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { airbag } from 'airbag';
|
|
17
|
+
|
|
18
|
+
interface User {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const fetchUser = async (id: string): Promise<User> => {
|
|
24
|
+
const res = await fetch(`/api/users/${id}`);
|
|
25
|
+
if (!res.ok) throw new Error('Failed to fetch user');
|
|
26
|
+
return res.json() as Promise<User>;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const safeFetchUser = airbag(fetchUser, {
|
|
30
|
+
timeout: 5000,
|
|
31
|
+
retries: 3,
|
|
32
|
+
onLoading: (loading) => spinner.toggle(loading),
|
|
33
|
+
onSuccess: (user) => toast.success(`Loaded ${user.name}`),
|
|
34
|
+
onError: (err) => toast.error(err.message),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Fully type-safe — same signature as fetchUser
|
|
38
|
+
const user = await safeFetchUser('user-123');
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Configuration Hierarchy
|
|
42
|
+
|
|
43
|
+
Three levels of configuration merged in order of specificity:
|
|
44
|
+
|
|
45
|
+
### Global → Instance → Execution
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { createAirbagInstance } from 'airbag';
|
|
49
|
+
|
|
50
|
+
// Level 1: Global defaults
|
|
51
|
+
const { wrap } = createAirbagInstance({
|
|
52
|
+
retries: 3,
|
|
53
|
+
timeout: 10000,
|
|
54
|
+
onError: (err) => logger.error(err),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Level 2: Instance options (merged over global)
|
|
58
|
+
const safeFetch = wrap(fetchUser, {
|
|
59
|
+
name: 'fetchUser',
|
|
60
|
+
timeout: 5000,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Level 3: Execution overrides (merged over instance)
|
|
64
|
+
const user = await safeFetch.with({ timeout: 15000 })('user-123');
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## API
|
|
68
|
+
|
|
69
|
+
### `airbag(fn, options?)`
|
|
70
|
+
|
|
71
|
+
Wraps an async function with execution orchestration.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
const wrapped = airbag(myAsyncFn, { timeout: 5000, retries: 3 });
|
|
75
|
+
const result = await wrapped(...originalArgs);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### `createAirbagInstance(options?)`
|
|
79
|
+
|
|
80
|
+
Creates a factory with shared global defaults.
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
const { wrap, configure, getDefaults } = createAirbagInstance({ retries: 2 });
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `wrapped.with(overrides)`
|
|
87
|
+
|
|
88
|
+
Creates a new wrapped function with execution-level overrides while sharing the same circuit breaker state.
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
const urgent = wrapped.with({ timeout: 2000 });
|
|
92
|
+
const result = await urgent(...args);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `wrapped.reset()`
|
|
96
|
+
|
|
97
|
+
Resets the circuit breaker state back to `closed`.
|
|
98
|
+
|
|
99
|
+
## Options
|
|
100
|
+
|
|
101
|
+
| Option | Type | Default | Description |
|
|
102
|
+
| --- | --- | --- | --- |
|
|
103
|
+
| `name` | `string` | `'anonymous'` | Identifier for logging and error messages |
|
|
104
|
+
| `timeout` | `number` | `30000` | Timeout in ms (`0` disables) |
|
|
105
|
+
| `retries` | `number` | `0` | Shorthand for `retry.count` |
|
|
106
|
+
| `retry.count` | `number` | `0` | Number of retries after initial failure |
|
|
107
|
+
| `retry.backoff` | `'exponential' \| 'linear' \| 'fixed'` | `'exponential'` | Backoff strategy between retries |
|
|
108
|
+
| `retry.baseDelay` | `number` | `1000` | Base delay in ms |
|
|
109
|
+
| `retry.maxDelay` | `number` | `30000` | Maximum delay cap in ms |
|
|
110
|
+
| `retry.jitter` | `boolean` | `true` | Randomize delays to avoid thundering herd |
|
|
111
|
+
| `circuitBreaker.enabled` | `boolean` | `false` | Enable the circuit breaker |
|
|
112
|
+
| `circuitBreaker.threshold` | `number` | `5` | Consecutive failures before opening |
|
|
113
|
+
| `circuitBreaker.resetTimeout` | `number` | `60000` | Ms before probing with a half-open attempt |
|
|
114
|
+
| `signal` | `AbortSignal` | — | Cancel execution via `AbortController` |
|
|
115
|
+
|
|
116
|
+
## Callbacks
|
|
117
|
+
|
|
118
|
+
Lifecycle callbacks can be passed **flat** at the top level — no nesting required:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
airbag(fetchUser, {
|
|
122
|
+
retries: 3,
|
|
123
|
+
onSuccess: (user) => toast.success(user.name),
|
|
124
|
+
onError: (err) => toast.error(err.message),
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
For reusable callback sets, group them in an `adapter` object instead:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
const logger: AirbagAdapter = {
|
|
132
|
+
onError: (err, ctx) => log.error(ctx.functionName, err),
|
|
133
|
+
onFinish: (ctx) => log.info(`Done in ${ctx.duration}ms`),
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
airbag(fetchUser, { retries: 3, adapter: logger });
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
If both flat callbacks and an `adapter` are provided, the `adapter` takes precedence.
|
|
140
|
+
|
|
141
|
+
Every callback receives an `ExecutionContext`:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
interface ExecutionContext {
|
|
145
|
+
functionName: string;
|
|
146
|
+
duration: number;
|
|
147
|
+
timestamp: number;
|
|
148
|
+
attempt: number;
|
|
149
|
+
maxAttempts: number;
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Error Types
|
|
154
|
+
|
|
155
|
+
All errors extend `AirbagError` with a `code` and `context` property:
|
|
156
|
+
|
|
157
|
+
| Error | Code | When |
|
|
158
|
+
| --- | --- | --- |
|
|
159
|
+
| `TimeoutError` | `TIMEOUT` | Promise exceeded the configured timeout |
|
|
160
|
+
| `RetryExhaustedError` | `RETRY_EXHAUSTED` | All retry attempts failed |
|
|
161
|
+
| `CircuitOpenError` | `CIRCUIT_OPEN` | Circuit breaker blocked execution |
|
|
162
|
+
| `AbortError` | `ABORTED` | Execution cancelled via `AbortSignal` |
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
import { TimeoutError, RetryExhaustedError } from 'airbag';
|
|
166
|
+
|
|
167
|
+
const result = await safeFetch('id').catch((err) => {
|
|
168
|
+
if (err instanceof TimeoutError) {
|
|
169
|
+
// err.timeout — the configured timeout in ms
|
|
170
|
+
// err.context — execution metadata
|
|
171
|
+
}
|
|
172
|
+
if (err instanceof RetryExhaustedError) {
|
|
173
|
+
// err.cause — the last error that caused the final failure
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## License
|
|
179
|
+
|
|
180
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
type BackoffStrategy = 'exponential' | 'linear' | 'fixed';
|
|
2
|
+
type CircuitBreakerState = 'closed' | 'open' | 'half-open';
|
|
3
|
+
type AirbagErrorCode = 'TIMEOUT' | 'RETRY_EXHAUSTED' | 'CIRCUIT_OPEN' | 'ABORTED' | 'EXECUTION_FAILED';
|
|
4
|
+
type Result<T> = {
|
|
5
|
+
ok: true;
|
|
6
|
+
value: T;
|
|
7
|
+
} | {
|
|
8
|
+
ok: false;
|
|
9
|
+
error: Error;
|
|
10
|
+
};
|
|
11
|
+
interface RetryConfig {
|
|
12
|
+
count: number;
|
|
13
|
+
backoff: BackoffStrategy;
|
|
14
|
+
baseDelay: number;
|
|
15
|
+
maxDelay: number;
|
|
16
|
+
jitter: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface CircuitBreakerConfig {
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
threshold: number;
|
|
21
|
+
resetTimeout: number;
|
|
22
|
+
}
|
|
23
|
+
interface ExecutionContext {
|
|
24
|
+
functionName: string;
|
|
25
|
+
duration: number;
|
|
26
|
+
timestamp: number;
|
|
27
|
+
attempt: number;
|
|
28
|
+
maxAttempts: number;
|
|
29
|
+
}
|
|
30
|
+
interface AirbagAdapter<TReturn = unknown> {
|
|
31
|
+
onLoading?: (isLoading: boolean, context: ExecutionContext) => void;
|
|
32
|
+
onSuccess?: (data: TReturn, context: ExecutionContext) => void;
|
|
33
|
+
onError?: (error: Error, context: ExecutionContext) => void;
|
|
34
|
+
onRetry?: (attempt: number, error: Error, context: ExecutionContext) => void;
|
|
35
|
+
onFinish?: (context: ExecutionContext) => void;
|
|
36
|
+
}
|
|
37
|
+
interface AirbagOptions<TReturn = unknown> {
|
|
38
|
+
name?: string;
|
|
39
|
+
timeout?: number;
|
|
40
|
+
retries?: number;
|
|
41
|
+
retry?: Partial<RetryConfig>;
|
|
42
|
+
circuitBreaker?: Partial<CircuitBreakerConfig>;
|
|
43
|
+
signal?: AbortSignal;
|
|
44
|
+
adapter?: AirbagAdapter<TReturn>;
|
|
45
|
+
onLoading?: AirbagAdapter<TReturn>['onLoading'];
|
|
46
|
+
onSuccess?: AirbagAdapter<TReturn>['onSuccess'];
|
|
47
|
+
onError?: AirbagAdapter<TReturn>['onError'];
|
|
48
|
+
onRetry?: AirbagAdapter<TReturn>['onRetry'];
|
|
49
|
+
onFinish?: AirbagAdapter<TReturn>['onFinish'];
|
|
50
|
+
}
|
|
51
|
+
interface AirbagResolvedConfig<TReturn = unknown> {
|
|
52
|
+
name: string;
|
|
53
|
+
adapter: AirbagAdapter<TReturn>;
|
|
54
|
+
retry: RetryConfig;
|
|
55
|
+
timeout: number;
|
|
56
|
+
circuitBreaker: CircuitBreakerConfig;
|
|
57
|
+
signal?: AbortSignal;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Wrapped async function that preserves the original function's
|
|
61
|
+
* argument types and return type while adding execution orchestration.
|
|
62
|
+
*
|
|
63
|
+
* @typeParam TArgs - Tuple of the original function's parameter types
|
|
64
|
+
* @typeParam TReturn - The resolved type of the original function's promise
|
|
65
|
+
*/
|
|
66
|
+
interface WrappedFunction<TArgs extends unknown[], TReturn> {
|
|
67
|
+
(...args: TArgs): Promise<TReturn>;
|
|
68
|
+
/** Creates a new wrapped function with execution-level option overrides. */
|
|
69
|
+
with(overrides: AirbagOptions<TReturn>): WrappedFunction<TArgs, TReturn>;
|
|
70
|
+
/** Resets the circuit breaker state for this wrapped function. */
|
|
71
|
+
reset(): void;
|
|
72
|
+
}
|
|
73
|
+
interface CircuitBreakerInstance {
|
|
74
|
+
canExecute(): boolean;
|
|
75
|
+
recordSuccess(): void;
|
|
76
|
+
recordFailure(): void;
|
|
77
|
+
getState(): CircuitBreakerState;
|
|
78
|
+
reset(): void;
|
|
79
|
+
}
|
|
80
|
+
interface AirbagInstance {
|
|
81
|
+
/** Wraps an async function with airbag orchestration using instance-level defaults. */
|
|
82
|
+
wrap<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => Promise<TReturn>, options?: AirbagOptions<TReturn>): WrappedFunction<TArgs, TReturn>;
|
|
83
|
+
/** Merges new options into the instance-level defaults. */
|
|
84
|
+
configure(options: AirbagOptions): void;
|
|
85
|
+
/** Returns the fully resolved configuration with current defaults. */
|
|
86
|
+
getDefaults(): AirbagResolvedConfig;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Wraps an async function with execution orchestration.
|
|
91
|
+
*
|
|
92
|
+
* The returned function has the same signature as the original but adds:
|
|
93
|
+
* - Automatic loading state management
|
|
94
|
+
* - Configurable retries with exponential backoff
|
|
95
|
+
* - Timeout enforcement
|
|
96
|
+
* - Circuit breaker protection
|
|
97
|
+
* - Structured error reporting via adapters
|
|
98
|
+
*
|
|
99
|
+
* @typeParam TArgs - Tuple of the original function's parameter types
|
|
100
|
+
* @typeParam TReturn - The resolved type of the original function's promise
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* const safeFetch = airbag(fetchUser, {
|
|
105
|
+
* name: 'fetchUser',
|
|
106
|
+
* timeout: 5000,
|
|
107
|
+
* retry: { count: 3 },
|
|
108
|
+
* adapter: {
|
|
109
|
+
* onError: (err) => toast.error(err.message),
|
|
110
|
+
* },
|
|
111
|
+
* });
|
|
112
|
+
*
|
|
113
|
+
* const user = await safeFetch('user-123');
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
declare function airbag<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => Promise<TReturn>, options?: AirbagOptions<TReturn>): WrappedFunction<TArgs, TReturn>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Creates a pre-configured airbag instance with shared global defaults.
|
|
120
|
+
*
|
|
121
|
+
* All functions wrapped through this instance inherit the global options
|
|
122
|
+
* before applying their own instance-level and execution-level overrides.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* const { wrap } = createAirbagInstance({
|
|
127
|
+
* retry: { count: 3 },
|
|
128
|
+
* adapter: {
|
|
129
|
+
* onError: (err) => logger.error(err),
|
|
130
|
+
* },
|
|
131
|
+
* });
|
|
132
|
+
*
|
|
133
|
+
* const safeFetch = wrap(fetchUser, { timeout: 5000 });
|
|
134
|
+
* const user = await safeFetch('user-123');
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
declare function createAirbagInstance(globalOptions?: AirbagOptions): AirbagInstance;
|
|
138
|
+
|
|
139
|
+
declare class AirbagError extends Error {
|
|
140
|
+
readonly code: AirbagErrorCode;
|
|
141
|
+
readonly context: ExecutionContext;
|
|
142
|
+
constructor(message: string, code: AirbagErrorCode, context: ExecutionContext, options?: {
|
|
143
|
+
cause?: Error;
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
declare class TimeoutError extends AirbagError {
|
|
147
|
+
readonly timeout: number;
|
|
148
|
+
constructor(context: ExecutionContext, timeout: number);
|
|
149
|
+
}
|
|
150
|
+
declare class RetryExhaustedError extends AirbagError {
|
|
151
|
+
constructor(context: ExecutionContext, cause: Error);
|
|
152
|
+
}
|
|
153
|
+
declare class CircuitOpenError extends AirbagError {
|
|
154
|
+
constructor(context: ExecutionContext);
|
|
155
|
+
}
|
|
156
|
+
declare class AbortError extends AirbagError {
|
|
157
|
+
constructor(context: ExecutionContext);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export { AbortError, type AirbagAdapter, AirbagError, type AirbagErrorCode, type AirbagInstance, type AirbagOptions, type AirbagResolvedConfig, type BackoffStrategy, type CircuitBreakerConfig, type CircuitBreakerInstance, type CircuitBreakerState, CircuitOpenError, type ExecutionContext, type Result, type RetryConfig, RetryExhaustedError, TimeoutError, type WrappedFunction, airbag, createAirbagInstance };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
type BackoffStrategy = 'exponential' | 'linear' | 'fixed';
|
|
2
|
+
type CircuitBreakerState = 'closed' | 'open' | 'half-open';
|
|
3
|
+
type AirbagErrorCode = 'TIMEOUT' | 'RETRY_EXHAUSTED' | 'CIRCUIT_OPEN' | 'ABORTED' | 'EXECUTION_FAILED';
|
|
4
|
+
type Result<T> = {
|
|
5
|
+
ok: true;
|
|
6
|
+
value: T;
|
|
7
|
+
} | {
|
|
8
|
+
ok: false;
|
|
9
|
+
error: Error;
|
|
10
|
+
};
|
|
11
|
+
interface RetryConfig {
|
|
12
|
+
count: number;
|
|
13
|
+
backoff: BackoffStrategy;
|
|
14
|
+
baseDelay: number;
|
|
15
|
+
maxDelay: number;
|
|
16
|
+
jitter: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface CircuitBreakerConfig {
|
|
19
|
+
enabled: boolean;
|
|
20
|
+
threshold: number;
|
|
21
|
+
resetTimeout: number;
|
|
22
|
+
}
|
|
23
|
+
interface ExecutionContext {
|
|
24
|
+
functionName: string;
|
|
25
|
+
duration: number;
|
|
26
|
+
timestamp: number;
|
|
27
|
+
attempt: number;
|
|
28
|
+
maxAttempts: number;
|
|
29
|
+
}
|
|
30
|
+
interface AirbagAdapter<TReturn = unknown> {
|
|
31
|
+
onLoading?: (isLoading: boolean, context: ExecutionContext) => void;
|
|
32
|
+
onSuccess?: (data: TReturn, context: ExecutionContext) => void;
|
|
33
|
+
onError?: (error: Error, context: ExecutionContext) => void;
|
|
34
|
+
onRetry?: (attempt: number, error: Error, context: ExecutionContext) => void;
|
|
35
|
+
onFinish?: (context: ExecutionContext) => void;
|
|
36
|
+
}
|
|
37
|
+
interface AirbagOptions<TReturn = unknown> {
|
|
38
|
+
name?: string;
|
|
39
|
+
timeout?: number;
|
|
40
|
+
retries?: number;
|
|
41
|
+
retry?: Partial<RetryConfig>;
|
|
42
|
+
circuitBreaker?: Partial<CircuitBreakerConfig>;
|
|
43
|
+
signal?: AbortSignal;
|
|
44
|
+
adapter?: AirbagAdapter<TReturn>;
|
|
45
|
+
onLoading?: AirbagAdapter<TReturn>['onLoading'];
|
|
46
|
+
onSuccess?: AirbagAdapter<TReturn>['onSuccess'];
|
|
47
|
+
onError?: AirbagAdapter<TReturn>['onError'];
|
|
48
|
+
onRetry?: AirbagAdapter<TReturn>['onRetry'];
|
|
49
|
+
onFinish?: AirbagAdapter<TReturn>['onFinish'];
|
|
50
|
+
}
|
|
51
|
+
interface AirbagResolvedConfig<TReturn = unknown> {
|
|
52
|
+
name: string;
|
|
53
|
+
adapter: AirbagAdapter<TReturn>;
|
|
54
|
+
retry: RetryConfig;
|
|
55
|
+
timeout: number;
|
|
56
|
+
circuitBreaker: CircuitBreakerConfig;
|
|
57
|
+
signal?: AbortSignal;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Wrapped async function that preserves the original function's
|
|
61
|
+
* argument types and return type while adding execution orchestration.
|
|
62
|
+
*
|
|
63
|
+
* @typeParam TArgs - Tuple of the original function's parameter types
|
|
64
|
+
* @typeParam TReturn - The resolved type of the original function's promise
|
|
65
|
+
*/
|
|
66
|
+
interface WrappedFunction<TArgs extends unknown[], TReturn> {
|
|
67
|
+
(...args: TArgs): Promise<TReturn>;
|
|
68
|
+
/** Creates a new wrapped function with execution-level option overrides. */
|
|
69
|
+
with(overrides: AirbagOptions<TReturn>): WrappedFunction<TArgs, TReturn>;
|
|
70
|
+
/** Resets the circuit breaker state for this wrapped function. */
|
|
71
|
+
reset(): void;
|
|
72
|
+
}
|
|
73
|
+
interface CircuitBreakerInstance {
|
|
74
|
+
canExecute(): boolean;
|
|
75
|
+
recordSuccess(): void;
|
|
76
|
+
recordFailure(): void;
|
|
77
|
+
getState(): CircuitBreakerState;
|
|
78
|
+
reset(): void;
|
|
79
|
+
}
|
|
80
|
+
interface AirbagInstance {
|
|
81
|
+
/** Wraps an async function with airbag orchestration using instance-level defaults. */
|
|
82
|
+
wrap<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => Promise<TReturn>, options?: AirbagOptions<TReturn>): WrappedFunction<TArgs, TReturn>;
|
|
83
|
+
/** Merges new options into the instance-level defaults. */
|
|
84
|
+
configure(options: AirbagOptions): void;
|
|
85
|
+
/** Returns the fully resolved configuration with current defaults. */
|
|
86
|
+
getDefaults(): AirbagResolvedConfig;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Wraps an async function with execution orchestration.
|
|
91
|
+
*
|
|
92
|
+
* The returned function has the same signature as the original but adds:
|
|
93
|
+
* - Automatic loading state management
|
|
94
|
+
* - Configurable retries with exponential backoff
|
|
95
|
+
* - Timeout enforcement
|
|
96
|
+
* - Circuit breaker protection
|
|
97
|
+
* - Structured error reporting via adapters
|
|
98
|
+
*
|
|
99
|
+
* @typeParam TArgs - Tuple of the original function's parameter types
|
|
100
|
+
* @typeParam TReturn - The resolved type of the original function's promise
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* const safeFetch = airbag(fetchUser, {
|
|
105
|
+
* name: 'fetchUser',
|
|
106
|
+
* timeout: 5000,
|
|
107
|
+
* retry: { count: 3 },
|
|
108
|
+
* adapter: {
|
|
109
|
+
* onError: (err) => toast.error(err.message),
|
|
110
|
+
* },
|
|
111
|
+
* });
|
|
112
|
+
*
|
|
113
|
+
* const user = await safeFetch('user-123');
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
declare function airbag<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => Promise<TReturn>, options?: AirbagOptions<TReturn>): WrappedFunction<TArgs, TReturn>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Creates a pre-configured airbag instance with shared global defaults.
|
|
120
|
+
*
|
|
121
|
+
* All functions wrapped through this instance inherit the global options
|
|
122
|
+
* before applying their own instance-level and execution-level overrides.
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* const { wrap } = createAirbagInstance({
|
|
127
|
+
* retry: { count: 3 },
|
|
128
|
+
* adapter: {
|
|
129
|
+
* onError: (err) => logger.error(err),
|
|
130
|
+
* },
|
|
131
|
+
* });
|
|
132
|
+
*
|
|
133
|
+
* const safeFetch = wrap(fetchUser, { timeout: 5000 });
|
|
134
|
+
* const user = await safeFetch('user-123');
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
declare function createAirbagInstance(globalOptions?: AirbagOptions): AirbagInstance;
|
|
138
|
+
|
|
139
|
+
declare class AirbagError extends Error {
|
|
140
|
+
readonly code: AirbagErrorCode;
|
|
141
|
+
readonly context: ExecutionContext;
|
|
142
|
+
constructor(message: string, code: AirbagErrorCode, context: ExecutionContext, options?: {
|
|
143
|
+
cause?: Error;
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
declare class TimeoutError extends AirbagError {
|
|
147
|
+
readonly timeout: number;
|
|
148
|
+
constructor(context: ExecutionContext, timeout: number);
|
|
149
|
+
}
|
|
150
|
+
declare class RetryExhaustedError extends AirbagError {
|
|
151
|
+
constructor(context: ExecutionContext, cause: Error);
|
|
152
|
+
}
|
|
153
|
+
declare class CircuitOpenError extends AirbagError {
|
|
154
|
+
constructor(context: ExecutionContext);
|
|
155
|
+
}
|
|
156
|
+
declare class AbortError extends AirbagError {
|
|
157
|
+
constructor(context: ExecutionContext);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export { AbortError, type AirbagAdapter, AirbagError, type AirbagErrorCode, type AirbagInstance, type AirbagOptions, type AirbagResolvedConfig, type BackoffStrategy, type CircuitBreakerConfig, type CircuitBreakerInstance, type CircuitBreakerState, CircuitOpenError, type ExecutionContext, type Result, type RetryConfig, RetryExhaustedError, TimeoutError, type WrappedFunction, airbag, createAirbagInstance };
|