safe-fetch-iq 0.1.2
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/LICENSE +21 -0
- package/README.md +422 -0
- package/dist/abort.d.ts +3 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/abort.js +48 -0
- package/dist/abort.js.map +1 -0
- package/dist/adapters.d.ts +9 -0
- package/dist/adapters.d.ts.map +1 -0
- package/dist/adapters.js +18 -0
- package/dist/adapters.js.map +1 -0
- package/dist/backoff.d.ts +9 -0
- package/dist/backoff.d.ts.map +1 -0
- package/dist/backoff.js +83 -0
- package/dist/backoff.js.map +1 -0
- package/dist/core.d.ts +3 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +197 -0
- package/dist/core.js.map +1 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -0
- package/dist/http.d.ts +7 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +69 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/safeFetch.d.ts +12 -0
- package/dist/safeFetch.d.ts.map +1 -0
- package/dist/safeFetch.js +181 -0
- package/dist/safeFetch.js.map +1 -0
- package/dist/types.d.ts +66 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +39 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Noteal Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
# safe-fetch-iq – Smart, Safe HTTP Fetch for JS/TS
|
|
2
|
+
|
|
3
|
+
safe-fetch-iq is a small TypeScript library that makes `fetch` safe and ergonomic by default, powered internally by an intelligent retry engine.
|
|
4
|
+
- Drop-in `fetch` replacement (`import fetch from "safe-fetch-iq"`)
|
|
5
|
+
- Smart defaults: retry, timeout, auto JSON/text parsing
|
|
6
|
+
- Request deduplication and response caching
|
|
7
|
+
- Built on native `fetch` (Node 18+ and browsers)
|
|
8
|
+
- Zero runtime dependencies, tiny bundle size
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install safe-fetch-iq
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
If you use TypeScript, `typescript` and `@types/node` should be available in your project.
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import fetch from "safe-fetch-iq";
|
|
22
|
+
|
|
23
|
+
const users = await fetch("https://api.example.com/users");
|
|
24
|
+
|
|
25
|
+
console.log(users);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Default behavior:
|
|
29
|
+
|
|
30
|
+
- Retries network and transient errors up to 3 times
|
|
31
|
+
- Per-attempt timeout of 30 seconds
|
|
32
|
+
- Automatically parses JSON or text based on `Content-Type`
|
|
33
|
+
- Follows redirects using native fetch behavior
|
|
34
|
+
- Throws descriptive errors instead of silent failures
|
|
35
|
+
|
|
36
|
+
## Smart Options
|
|
37
|
+
|
|
38
|
+
safe-fetch-iq extends the standard `RequestInit` with a few focused options:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import fetch from "safe-fetch-iq";
|
|
42
|
+
|
|
43
|
+
const data = await fetch("https://api.example.com/data", {
|
|
44
|
+
method: "POST",
|
|
45
|
+
headers: { "Content-Type": "application/json" },
|
|
46
|
+
body: JSON.stringify({ foo: "bar" }),
|
|
47
|
+
|
|
48
|
+
retry: 5,
|
|
49
|
+
timeout: 10_000,
|
|
50
|
+
retryOn: [429, 503],
|
|
51
|
+
retryDelay: attempt => attempt * 1000,
|
|
52
|
+
dedupe: true,
|
|
53
|
+
cache: "5m"
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Supported options:
|
|
58
|
+
|
|
59
|
+
- `retry?: number`
|
|
60
|
+
- Maximum retry attempts (default: `3`)
|
|
61
|
+
- `timeout?: number`
|
|
62
|
+
- Per-attempt timeout in milliseconds (default: `30000`)
|
|
63
|
+
- `retryOn?: number[]`
|
|
64
|
+
- HTTP status codes to retry (e.g. `[429, 503]`)
|
|
65
|
+
- `retryDelay?: (attempt: number) => number`
|
|
66
|
+
- Custom backoff function for delay in ms
|
|
67
|
+
- `dedupe?: boolean`
|
|
68
|
+
- Request deduplication for identical in-flight `GET` requests (default: `true`)
|
|
69
|
+
- `cache?: number | string`
|
|
70
|
+
- Response cache TTL for `GET` requests
|
|
71
|
+
- Number (ms) or string like `"10s"`, `"5m"`, `"1h"`
|
|
72
|
+
|
|
73
|
+
All regular `fetch` options still work. You can also pass an `AbortSignal` via `signal` as usual.
|
|
74
|
+
|
|
75
|
+
## Request Deduplication
|
|
76
|
+
|
|
77
|
+
When `dedupe` is enabled (default), concurrent identical `GET` requests share the same promise:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import fetch from "safe-fetch-iq";
|
|
81
|
+
|
|
82
|
+
const p1 = fetch("https://api.example.com/users");
|
|
83
|
+
const p2 = fetch("https://api.example.com/users");
|
|
84
|
+
|
|
85
|
+
// p1 and p2 resolve with the same underlying network response
|
|
86
|
+
const [a, b] = await Promise.all([p1, p2]);
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
This avoids stampedes when multiple parts of your app request the same data at the same time.
|
|
90
|
+
|
|
91
|
+
## Response Caching
|
|
92
|
+
|
|
93
|
+
For `GET` requests, you can enable simple in-memory caching:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import fetch from "safe-fetch-iq";
|
|
97
|
+
|
|
98
|
+
// Cache for 5 minutes
|
|
99
|
+
const data = await fetch("https://api.example.com/data", {
|
|
100
|
+
cache: "5m"
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
- The cache key is based on method+URL+body
|
|
105
|
+
- Calls within the TTL return the cached parsed value
|
|
106
|
+
- After TTL expires, a new request is made and cache is refreshed
|
|
107
|
+
|
|
108
|
+
## Error Handling
|
|
109
|
+
|
|
110
|
+
safe-fetch-iq throws when:
|
|
111
|
+
|
|
112
|
+
- The response is not `ok` (non-2xx), after applying retries
|
|
113
|
+
- Retries are exhausted or cancelled by rules
|
|
114
|
+
|
|
115
|
+
Example:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import fetch, { RetryIQError } from "safe-fetch-iq";
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
const data = await fetch("https://api.example.com/data", {
|
|
122
|
+
retry: 5,
|
|
123
|
+
retryOn: [429, 503]
|
|
124
|
+
});
|
|
125
|
+
console.log(data);
|
|
126
|
+
} catch (err) {
|
|
127
|
+
if (err instanceof RetryIQError) {
|
|
128
|
+
console.error("Retry failed", err.metadata);
|
|
129
|
+
} else {
|
|
130
|
+
console.error("Unexpected error", err);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`RetryIQError` includes metadata:
|
|
136
|
+
|
|
137
|
+
- `attempt` – last attempt index
|
|
138
|
+
- `totalAttempts`
|
|
139
|
+
- `errorType`
|
|
140
|
+
- `elapsedMs`
|
|
141
|
+
|
|
142
|
+
Non-OK HTTP responses are surfaced as errors that still carry the original `Response` for advanced handling.
|
|
143
|
+
|
|
144
|
+
## Advanced Use: withRetry Engine
|
|
145
|
+
|
|
146
|
+
Under the hood, safe-fetch-iq is powered by a generic intelligent retry engine. You can use it directly for other clients like `axios`, custom HTTP clients, or even non-HTTP operations.
|
|
147
|
+
|
|
148
|
+
### Core Idea
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { withRetry } from "safe-fetch-iq";
|
|
152
|
+
|
|
153
|
+
const result = await withRetry(async (attempt, signal) => {
|
|
154
|
+
return doSomethingHttpLike(attempt, signal);
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The engine decides when to retry, how long to wait, and when to give up.
|
|
159
|
+
|
|
160
|
+
### Smart Behavior
|
|
161
|
+
|
|
162
|
+
### 1. Detects Retry-After
|
|
163
|
+
|
|
164
|
+
When the server returns `429` or `5xx` with a `Retry-After` header, the engine parses the header and waits at least that long before the next attempt.
|
|
165
|
+
|
|
166
|
+
- `Retry-After: 10` is interpreted as 10 seconds
|
|
167
|
+
- `Retry-After: Wed, 21 Oct 2015 07:28:00 GMT` is treated as an absolute time
|
|
168
|
+
|
|
169
|
+
If no `Retry-After` header exists, standard backoff is used.
|
|
170
|
+
|
|
171
|
+
### 2. Error-Aware Backoff
|
|
172
|
+
|
|
173
|
+
Errors are classified into types:
|
|
174
|
+
|
|
175
|
+
- `rateLimit` – typically HTTP `429`
|
|
176
|
+
- `serverError` – HTTP `5xx`
|
|
177
|
+
- `networkError` – connection resets, timeouts, DNS errors
|
|
178
|
+
- `clientError` – `4xx` that should not be retried
|
|
179
|
+
- `unknown` – anything else
|
|
180
|
+
|
|
181
|
+
By default, only `rateLimit`, `serverError`, `networkError`, and `unknown` are retried. Client errors are treated as final.
|
|
182
|
+
|
|
183
|
+
### 3. Budget-Aware Retries
|
|
184
|
+
|
|
185
|
+
You control how aggressive the retries can be.
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
import { withRetry } from "safe-fetch-iq";
|
|
189
|
+
|
|
190
|
+
const response = await withRetry(
|
|
191
|
+
() => fetch("https://api.example.com/data"),
|
|
192
|
+
{
|
|
193
|
+
budget: {
|
|
194
|
+
maxRetries: 5,
|
|
195
|
+
maxRetryTimeMs: 60_000
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
- `maxRetries` – maximum number of retry attempts
|
|
202
|
+
- `maxRetryTimeMs` – hard cap on total time spent retrying
|
|
203
|
+
|
|
204
|
+
If the server sends rate-limit headers:
|
|
205
|
+
|
|
206
|
+
- `X-RateLimit-Remaining`
|
|
207
|
+
- `X-Rate-Limit-Remaining`
|
|
208
|
+
|
|
209
|
+
and they indicate that you are out of quota, Retry IQ stops early instead of blindly continuing to hit the API.
|
|
210
|
+
|
|
211
|
+
## Backoff Configuration
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
import { withRetry } from "safe-fetch-iq";
|
|
215
|
+
|
|
216
|
+
await withRetry(
|
|
217
|
+
() => fetch("https://api.example.com/data"),
|
|
218
|
+
{
|
|
219
|
+
backoff: {
|
|
220
|
+
baseDelayMs: 250,
|
|
221
|
+
maxDelayMs: 30_000,
|
|
222
|
+
factor: 2,
|
|
223
|
+
jitter: "full",
|
|
224
|
+
perErrorType: {
|
|
225
|
+
rateLimit: {
|
|
226
|
+
baseDelayMs: 1000
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
- `baseDelayMs` – first delay before backoff, default `250`
|
|
235
|
+
- `factor` – exponential factor, default `2`
|
|
236
|
+
- `maxDelayMs` – max per-attempt delay, default `30000`
|
|
237
|
+
- `jitter`
|
|
238
|
+
- `"none"` – deterministic backoff
|
|
239
|
+
- `"full"` – random between `0` and `delay`
|
|
240
|
+
- `"decorrelated"` – random between `delay / 2` and `delay`
|
|
241
|
+
- `perErrorType` – override backoff settings per error type
|
|
242
|
+
|
|
243
|
+
## shouldRetry Hook
|
|
244
|
+
|
|
245
|
+
Use `shouldRetry` to inject custom rules.
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
import { withRetry } from "safe-fetch-iq";
|
|
249
|
+
|
|
250
|
+
await withRetry(
|
|
251
|
+
() => fetch("https://api.example.com/data"),
|
|
252
|
+
{
|
|
253
|
+
shouldRetry: (error, context) => {
|
|
254
|
+
if (context.errorType === "clientError") return false;
|
|
255
|
+
if (context.attempt > 3) return false;
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
);
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
You receive both the error and detailed context, including the calculated next delay.
|
|
263
|
+
|
|
264
|
+
## Logging
|
|
265
|
+
|
|
266
|
+
Pass a logger to understand how retries behave in production.
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
import { withRetry } from "safe-fetch-iq";
|
|
270
|
+
|
|
271
|
+
await withRetry(
|
|
272
|
+
() => fetch("https://api.example.com/data"),
|
|
273
|
+
{
|
|
274
|
+
logger: event => {
|
|
275
|
+
if (event.type === "retry") {
|
|
276
|
+
console.log(
|
|
277
|
+
`[RetryIQ] ${event.operationName ?? "operation"} attempt ${event.attempt} – waiting ${event.delayMs}ms`
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
if (event.type === "giveUp") {
|
|
281
|
+
console.warn(
|
|
282
|
+
`[RetryIQ] giving up after ${event.attempt} attempts due to ${event.reason} (${event.errorType})`
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
if (event.type === "succeeded") {
|
|
286
|
+
console.log(
|
|
287
|
+
`[RetryIQ] succeeded in ${event.elapsedMs}ms after ${event.attempt} attempts`
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
## Using AbortSignal
|
|
296
|
+
|
|
297
|
+
You can cancel the entire retry sequence with an `AbortSignal`.
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
import { withRetry } from "safe-fetch-iq";
|
|
301
|
+
|
|
302
|
+
const controller = new AbortController();
|
|
303
|
+
|
|
304
|
+
const promise = withRetry(
|
|
305
|
+
(attempt, signal) => fetch("https://api.example.com/data", { signal }),
|
|
306
|
+
{
|
|
307
|
+
signal: controller.signal
|
|
308
|
+
}
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
setTimeout(() => controller.abort(), 5000);
|
|
312
|
+
|
|
313
|
+
await promise;
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
If the signal is aborted, Retry IQ stops immediately.
|
|
317
|
+
|
|
318
|
+
## Error Handling
|
|
319
|
+
|
|
320
|
+
When retries are exhausted or cancelled by rules, the engine throws a `RetryIQError`.
|
|
321
|
+
|
|
322
|
+
```ts
|
|
323
|
+
import { withRetry, RetryIQError } from "safe-fetch-iq";
|
|
324
|
+
|
|
325
|
+
try {
|
|
326
|
+
await withRetry(() => fetch("https://api.example.com/data"));
|
|
327
|
+
} catch (err) {
|
|
328
|
+
if (err instanceof RetryIQError) {
|
|
329
|
+
console.error("Retry failed", err.metadata);
|
|
330
|
+
} else {
|
|
331
|
+
console.error("Unexpected error", err);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
`RetryIQError` includes metadata:
|
|
337
|
+
|
|
338
|
+
- `attempt` – last attempt index
|
|
339
|
+
- `totalAttempts`
|
|
340
|
+
- `errorType`
|
|
341
|
+
- `elapsedMs`
|
|
342
|
+
|
|
343
|
+
## Adapters
|
|
344
|
+
|
|
345
|
+
### fetch adapter
|
|
346
|
+
|
|
347
|
+
If you prefer a dedicated wrapper on top of native fetch:
|
|
348
|
+
|
|
349
|
+
```ts
|
|
350
|
+
import { withRetryFetch } from "safe-fetch-iq";
|
|
351
|
+
|
|
352
|
+
const fetchWithRetry = withRetryFetch(fetch);
|
|
353
|
+
|
|
354
|
+
const response = await fetchWithRetry("https://api.example.com/data");
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
You can pass options on each call:
|
|
358
|
+
|
|
359
|
+
```ts
|
|
360
|
+
const response = await fetchWithRetry(
|
|
361
|
+
"https://api.example.com/data",
|
|
362
|
+
{ method: "GET" },
|
|
363
|
+
{
|
|
364
|
+
budget: { maxRetries: 3 }
|
|
365
|
+
}
|
|
366
|
+
);
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
### axios adapter
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
import axios from "axios";
|
|
373
|
+
import { withRetryAxios } from "safe-fetch-iq";
|
|
374
|
+
|
|
375
|
+
const axiosClient = axios.create({ baseURL: "https://api.example.com" });
|
|
376
|
+
|
|
377
|
+
const axiosWithRetryFactory = withRetryAxios(axiosClient);
|
|
378
|
+
const axiosWithRetry = axiosWithRetryFactory({
|
|
379
|
+
budget: { maxRetries: 4 }
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
const response = await axiosWithRetry.request({ method: "GET", url: "/users" });
|
|
383
|
+
console.log(response.data);
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## API Reference
|
|
387
|
+
|
|
388
|
+
### withRetry(operation, options?)
|
|
389
|
+
|
|
390
|
+
Wraps any async operation with intelligent retry behavior.
|
|
391
|
+
|
|
392
|
+
- `operation(attempt, signal)` – async function that performs the work
|
|
393
|
+
- `options` – `RetryIQOptions`
|
|
394
|
+
|
|
395
|
+
### RetryIQOptions
|
|
396
|
+
|
|
397
|
+
- `operationName?: string`
|
|
398
|
+
- `classifyError?: (error) => RetryErrorType`
|
|
399
|
+
- `shouldRetry?: (error, context) => boolean | Promise<boolean>`
|
|
400
|
+
- `budget?: RetryBudgetConfig`
|
|
401
|
+
- `backoff?: RetryBackoffConfig`
|
|
402
|
+
- `logger?: (event: RetryEvent) => void`
|
|
403
|
+
- `respectRetryAfterHeader?: boolean` (default `true`)
|
|
404
|
+
- `signal?: AbortSignal`
|
|
405
|
+
|
|
406
|
+
### Backoff and budget types
|
|
407
|
+
|
|
408
|
+
- `RetryBudgetConfig`
|
|
409
|
+
- `maxRetries: number`
|
|
410
|
+
- `maxRetryTimeMs?: number`
|
|
411
|
+
- `RetryBackoffConfig`
|
|
412
|
+
- `baseDelayMs?: number`
|
|
413
|
+
- `maxDelayMs?: number`
|
|
414
|
+
- `factor?: number`
|
|
415
|
+
- `jitter?: "none" | "full" | "decorrelated"`
|
|
416
|
+
- `perErrorType?: Partial<Record<RetryErrorType, Partial<Omit<RetryBackoffConfig, "perErrorType">>>>`
|
|
417
|
+
|
|
418
|
+
## When To Use safe-fetch-iq
|
|
419
|
+
|
|
420
|
+
- You want a safer default `fetch` with retries and timeouts
|
|
421
|
+
- You need simple request deduplication and caching without extra infra
|
|
422
|
+
- You prefer zero-dependency utilities over heavyweight HTTP clients
|
package/dist/abort.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abort.d.ts","sourceRoot":"","sources":["../src/abort.ts"],"names":[],"mappings":"AAEA,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBrE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,WAAW,CAiBtF"}
|
package/dist/abort.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { RetryAbortError } from "./errors";
|
|
2
|
+
export function delay(ms, signal) {
|
|
3
|
+
if (ms <= 0)
|
|
4
|
+
return Promise.resolve();
|
|
5
|
+
return new Promise((resolve, reject) => {
|
|
6
|
+
const timeout = setTimeout(onDone, ms);
|
|
7
|
+
function onDone() {
|
|
8
|
+
if (signal) {
|
|
9
|
+
signal.removeEventListener("abort", onAbort);
|
|
10
|
+
}
|
|
11
|
+
resolve();
|
|
12
|
+
}
|
|
13
|
+
function onAbort() {
|
|
14
|
+
clearTimeout(timeout);
|
|
15
|
+
reject(new RetryAbortError());
|
|
16
|
+
}
|
|
17
|
+
if (signal) {
|
|
18
|
+
if (signal.aborted) {
|
|
19
|
+
clearTimeout(timeout);
|
|
20
|
+
reject(new RetryAbortError());
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
signal.addEventListener("abort", onAbort);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export function mergeAbortSignals(inner, outer) {
|
|
29
|
+
if (!outer)
|
|
30
|
+
return inner;
|
|
31
|
+
if (outer.aborted)
|
|
32
|
+
return outer;
|
|
33
|
+
const controller = new AbortController();
|
|
34
|
+
const onOuterAbort = () => {
|
|
35
|
+
controller.abort();
|
|
36
|
+
inner.removeEventListener("abort", onInnerAbort);
|
|
37
|
+
outer.removeEventListener("abort", onOuterAbort);
|
|
38
|
+
};
|
|
39
|
+
const onInnerAbort = () => {
|
|
40
|
+
controller.abort();
|
|
41
|
+
inner.removeEventListener("abort", onInnerAbort);
|
|
42
|
+
outer.removeEventListener("abort", onOuterAbort);
|
|
43
|
+
};
|
|
44
|
+
inner.addEventListener("abort", onInnerAbort);
|
|
45
|
+
outer.addEventListener("abort", onOuterAbort);
|
|
46
|
+
return controller.signal;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=abort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abort.js","sourceRoot":"","sources":["../src/abort.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE3C,MAAM,UAAU,KAAK,CAAC,EAAU,EAAE,MAAoB;IACpD,IAAI,EAAE,IAAI,CAAC;QAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IACtC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACvC,SAAS,MAAM;YACb,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC/C,CAAC;YACD,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,SAAS,OAAO;YACd,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,MAAM,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC;QAChC,CAAC;QACD,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACnB,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,MAAM,CAAC,IAAI,eAAe,EAAE,CAAC,CAAC;YAChC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAAkB,EAAE,KAAmB;IACvE,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,IAAI,KAAK,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAChC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QACjD,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACnD,CAAC,CAAC;IACF,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;QACjD,KAAK,CAAC,mBAAmB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACnD,CAAC,CAAC;IACF,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC9C,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC9C,OAAO,UAAU,CAAC,MAAM,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { WithRetryOptions } from "./types";
|
|
2
|
+
export type FetchLike = (input: unknown, init?: unknown) => Promise<unknown>;
|
|
3
|
+
export declare function withRetryFetch(fetchImpl: FetchLike): (input: unknown, init?: unknown, options?: WithRetryOptions) => Promise<unknown>;
|
|
4
|
+
export declare function withRetryAxios<TInstance extends {
|
|
5
|
+
request(config: any): Promise<any>;
|
|
6
|
+
}>(axiosInstance: TInstance): (defaultOptions?: WithRetryOptions) => {
|
|
7
|
+
request(config: any, options?: WithRetryOptions): Promise<any>;
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=adapters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.d.ts","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAE3C,MAAM,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE7E,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,IAE/C,OAAO,OAAO,EACd,OAAO,OAAO,EACd,UAAU,gBAAgB,KACzB,OAAO,CAAC,OAAO,CAAC,CAMpB;AAED,wBAAgB,cAAc,CAAC,SAAS,SAAS;IAAE,OAAO,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;CAAE,EACrF,aAAa,EAAE,SAAS,IAEa,iBAAiB,gBAAgB;oBAGlD,GAAG,YAAY,gBAAgB;EASpD"}
|
package/dist/adapters.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { withRetry } from "./core";
|
|
2
|
+
export function withRetryFetch(fetchImpl) {
|
|
3
|
+
return async function fetchWithRetry(input, init, options) {
|
|
4
|
+
return withRetry(() => fetchImpl(input, init), options);
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
export function withRetryAxios(axiosInstance) {
|
|
8
|
+
return function createAxiosWithRetry(defaultOptions) {
|
|
9
|
+
const instance = axiosInstance;
|
|
10
|
+
return {
|
|
11
|
+
request(config, options) {
|
|
12
|
+
const mergedOptions = { ...(defaultOptions !== null && defaultOptions !== void 0 ? defaultOptions : {}), ...(options !== null && options !== void 0 ? options : {}) };
|
|
13
|
+
return withRetry(() => instance.request(config), mergedOptions);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=adapters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAKnC,MAAM,UAAU,cAAc,CAAC,SAAoB;IACjD,OAAO,KAAK,UAAU,cAAc,CAClC,KAAc,EACd,IAAc,EACd,OAA0B;QAE1B,OAAO,SAAS,CACd,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,EAC5B,OAAO,CACR,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,aAAwB;IAExB,OAAO,SAAS,oBAAoB,CAAC,cAAiC;QACpE,MAAM,QAAQ,GAAG,aAAa,CAAC;QAC/B,OAAO;YACL,OAAO,CAAC,MAAW,EAAE,OAA0B;gBAC7C,MAAM,aAAa,GAAqB,EAAE,GAAG,CAAC,cAAc,aAAd,cAAc,cAAd,cAAc,GAAI,EAAE,CAAC,EAAE,GAAG,CAAC,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,EAAE,CAAC,EAAE,CAAC;gBAC1F,OAAO,SAAS,CACd,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,EAC9B,aAAa,CACd,CAAC;YACJ,CAAC;SACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { RetryBackoffConfig, RetryBudgetConfig, RetryErrorType } from "./types";
|
|
2
|
+
export declare const defaultBudget: RetryBudgetConfig;
|
|
3
|
+
export declare const defaultBackoff: RetryBackoffConfig;
|
|
4
|
+
export declare function defaultClassifyError(error: unknown): RetryErrorType;
|
|
5
|
+
export declare function isRetriableType(errorType: RetryErrorType): boolean;
|
|
6
|
+
export declare function mergeBackoffConfig(base: RetryBackoffConfig, errorType: RetryErrorType): Required<Omit<RetryBackoffConfig, "perErrorType">>;
|
|
7
|
+
export declare function computeBackoffDelayMs(baseConfig: RetryBackoffConfig, errorType: RetryErrorType, attempt: number): number;
|
|
8
|
+
export declare function selectClassifier(classifyError: ((error: unknown) => RetryErrorType) | undefined): (error: unknown) => RetryErrorType;
|
|
9
|
+
//# sourceMappingURL=backoff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backoff.d.ts","sourceRoot":"","sources":["../src/backoff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAGhF,eAAO,MAAM,aAAa,EAAE,iBAG3B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,kBAK5B,CAAC;AAaF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAmBnE;AAED,wBAAgB,eAAe,CAAC,SAAS,EAAE,cAAc,GAAG,OAAO,CAOlE;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,kBAAkB,EACxB,SAAS,EAAE,cAAc,GACxB,QAAQ,CAAC,IAAI,CAAC,kBAAkB,EAAE,cAAc,CAAC,CAAC,CAepD;AAED,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,cAAc,EACzB,OAAO,EAAE,MAAM,GACd,MAAM,CAYR;AAED,wBAAgB,gBAAgB,CAC9B,aAAa,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,cAAc,CAAC,GAAG,SAAS,GAC9D,CAAC,KAAK,EAAE,OAAO,KAAK,cAAc,CAGpC"}
|
package/dist/backoff.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { classifyHttpStatus, detectHttpResponse } from "./http";
|
|
2
|
+
export const defaultBudget = {
|
|
3
|
+
maxRetries: 5,
|
|
4
|
+
maxRetryTimeMs: 60000
|
|
5
|
+
};
|
|
6
|
+
export const defaultBackoff = {
|
|
7
|
+
baseDelayMs: 250,
|
|
8
|
+
maxDelayMs: 30000,
|
|
9
|
+
factor: 2,
|
|
10
|
+
jitter: "full"
|
|
11
|
+
};
|
|
12
|
+
function random() {
|
|
13
|
+
return Math.random();
|
|
14
|
+
}
|
|
15
|
+
function isAbortError(error) {
|
|
16
|
+
if (typeof error !== "object" || error === null)
|
|
17
|
+
return false;
|
|
18
|
+
const name = error.name;
|
|
19
|
+
const code = error.code;
|
|
20
|
+
return name === "AbortError" || code === "ABORT_ERR";
|
|
21
|
+
}
|
|
22
|
+
export function defaultClassifyError(error) {
|
|
23
|
+
if (isAbortError(error))
|
|
24
|
+
return "clientError";
|
|
25
|
+
const response = detectHttpResponse(error);
|
|
26
|
+
if (response) {
|
|
27
|
+
return classifyHttpStatus(response.status);
|
|
28
|
+
}
|
|
29
|
+
if (typeof error === "object" && error !== null) {
|
|
30
|
+
const code = error.code;
|
|
31
|
+
if (code === "ECONNRESET" ||
|
|
32
|
+
code === "ENOTFOUND" ||
|
|
33
|
+
code === "ETIMEDOUT" ||
|
|
34
|
+
code === "EAI_AGAIN" ||
|
|
35
|
+
code === "ECONNREFUSED") {
|
|
36
|
+
return "networkError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return "unknown";
|
|
40
|
+
}
|
|
41
|
+
export function isRetriableType(errorType) {
|
|
42
|
+
return (errorType === "rateLimit" ||
|
|
43
|
+
errorType === "serverError" ||
|
|
44
|
+
errorType === "networkError" ||
|
|
45
|
+
errorType === "unknown");
|
|
46
|
+
}
|
|
47
|
+
export function mergeBackoffConfig(base, errorType) {
|
|
48
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
49
|
+
const perType = (_b = (_a = base.perErrorType) === null || _a === void 0 ? void 0 : _a[errorType]) !== null && _b !== void 0 ? _b : {};
|
|
50
|
+
const merged = {
|
|
51
|
+
baseDelayMs: (_c = base.baseDelayMs) !== null && _c !== void 0 ? _c : defaultBackoff.baseDelayMs,
|
|
52
|
+
maxDelayMs: (_d = base.maxDelayMs) !== null && _d !== void 0 ? _d : defaultBackoff.maxDelayMs,
|
|
53
|
+
factor: (_e = base.factor) !== null && _e !== void 0 ? _e : defaultBackoff.factor,
|
|
54
|
+
jitter: (_f = base.jitter) !== null && _f !== void 0 ? _f : defaultBackoff.jitter,
|
|
55
|
+
...perType
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
baseDelayMs: (_g = merged.baseDelayMs) !== null && _g !== void 0 ? _g : defaultBackoff.baseDelayMs,
|
|
59
|
+
maxDelayMs: (_h = merged.maxDelayMs) !== null && _h !== void 0 ? _h : defaultBackoff.maxDelayMs,
|
|
60
|
+
factor: (_j = merged.factor) !== null && _j !== void 0 ? _j : defaultBackoff.factor,
|
|
61
|
+
jitter: (_k = merged.jitter) !== null && _k !== void 0 ? _k : defaultBackoff.jitter
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export function computeBackoffDelayMs(baseConfig, errorType, attempt) {
|
|
65
|
+
const cfg = mergeBackoffConfig(baseConfig, errorType);
|
|
66
|
+
const exp = Math.max(attempt - 1, 0);
|
|
67
|
+
const rawDelay = cfg.baseDelayMs * Math.pow(cfg.factor, exp);
|
|
68
|
+
const clamped = Math.min(rawDelay, cfg.maxDelayMs);
|
|
69
|
+
if (cfg.jitter === "none")
|
|
70
|
+
return clamped;
|
|
71
|
+
if (cfg.jitter === "full") {
|
|
72
|
+
return random() * clamped;
|
|
73
|
+
}
|
|
74
|
+
const min = clamped / 2;
|
|
75
|
+
const max = clamped;
|
|
76
|
+
return min + random() * (max - min);
|
|
77
|
+
}
|
|
78
|
+
export function selectClassifier(classifyError) {
|
|
79
|
+
if (classifyError)
|
|
80
|
+
return classifyError;
|
|
81
|
+
return defaultClassifyError;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=backoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backoff.js","sourceRoot":"","sources":["../src/backoff.ts"],"names":[],"mappings":"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"}
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,cAAc,EAEf,MAAM,SAAS,CAAC;AAgBjB,wBAAsB,SAAS,CAAC,CAAC,EAC/B,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EAC/D,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,CAAC,CAAC,CA2LZ"}
|