vigor-fetch 1.0.20 โ†’ 2.0.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.
Files changed (2) hide show
  1. package/README.md +341 -224
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,289 +1,406 @@
1
1
  # vigor-fetch
2
2
 
3
- **Vigor** is a lightweight TypeScript HTTP utility library.
4
- It lets you compose `fetch`, retry, response parsing, and parallel requests using a clean fluent chaining API.
3
+ **Vigor** is a lightweight (gzipped ~7.7kb) TypeScript HTTP / Retry utility library.
4
+ Vigor provides a fluent, chainable API for building robust network logic with built-in retry, backoff, interceptors, parsing, and concurrency control.
5
5
 
6
6
  ---
7
7
 
8
8
  ## Features
9
9
 
10
- - ๐Ÿ” **Auto Retry** โ€” Exponential backoff with jitter support
11
- - ๐ŸŒ **Smart Fetch** โ€” Automatic 429 Rate Limit header handling, configurable unretry status codes
12
- - ๐Ÿ“ฆ **Auto Parsing** โ€” Content-Type based response parsing (JSON, Blob, FormData, etc.)
13
- - โšก **Parallel Requests** โ€” `Promise.allSettled` wrapper with concurrency limit and jitter
14
- - ๐Ÿ”Œ **Interceptors** โ€” Lifecycle hooks: `before` / `after` / `onRetry` / `onError`
15
- - ๐Ÿงฉ **Plugins** โ€” Extend functionality via the `use()` method
16
- - ๐Ÿ’ก **Immutable Chaining** โ€” Every config method returns a new instance with no side effects
17
- - โšก **Zero Dependencies** โ€” Built using native Fetch API and AbortController.
10
+ - ๐Ÿงฉ **Fluent & Immutable API** โ€” Fully composable, side-effect-free chaining
11
+ - ๐Ÿ” **Advanced Retry System** โ€” Exponential backoff with jitter support.
12
+ - ๐ŸŒ **Smart Fetch Layer** โ€” Automatic 429 handling & configurable retry rules
13
+ - โšก **Parallel Requests** โ€” Concurrency-limited task runner
14
+ - ๐Ÿ”Œ **Smart Response Parsing** โ€” Auto parsing based on Content-Type
15
+ - โšก **Zero Dependencies** โ€” Built on native Fetch + AbortController
16
+ - ๐Ÿช **Powerful Interceptors** โ€” Lifecycle hooks for full control flow
17
+ - ๐Ÿง  **TypeScript First** โ€” Fully typed inference across all modules
18
18
  ---
19
19
 
20
+ ## Installation
21
+
22
+ ```bash
23
+ npm install vigor-fetch
24
+ ```
25
+
20
26
  ## Why Vigor?
21
27
 
22
28
  | Feature | Vigor | native fetch | ky | axios |
23
29
  |---|:---:|:---:|:---:|:---:|
24
- | Zero dependencies | โœ… | โœ… | โœ… | โŒ |
25
- | Auto retry with backoff | โœ… | โŒ | โœ… | โŒ |
26
- | 429 rate-limit header handling | โœ… | โŒ | โŒ | โŒ |
27
- | Jitter on retry | โœ… | โŒ | โŒ | โŒ |
28
- | Auto response parsing | โœ… | โŒ | partial | partial |
30
+ | Zero dependencies | โœ… | โœ… | โŒ | โœ… |
31
+ | 429 rate-limit handling | โœ… | โŒ | โœ…(manual/config-based) | โŒ |
32
+ | Retry with jitter | โœ… | โŒ | โœ… | โŒ |
33
+ | Exponential backoff | โœ… | โŒ | โœ… | โŒ |
34
+ | Auto response parsing | โœ… | โŒ | โœ… | โœ… |
29
35
  | Fluent chaining API | โœ… | โŒ | โœ… | โŒ |
30
- | Concurrency-limited parallel requests | โœ… | โŒ | โŒ | โŒ |
31
- | Lifecycle interceptors | โœ… | โŒ | โœ… | โœ… |
36
+ | Concurrency control | โœ… | โŒ | โŒ | โŒ |
37
+ | Lifecycle interceptors | โœ… | โŒ | partial | โŒ |
32
38
  | Plugin system | โœ… | โŒ | โŒ | โŒ |
33
- | TypeScript-first | โœ… | โŒ | โœ… | partial |
34
39
 
35
- ## Installation
40
+ ## Quick Start
36
41
 
37
- ```bash
38
- npm install vigor-fetch
42
+ ```ts
43
+ import vigor from "vigor-fetch";
44
+ const data = await vigor
45
+ .fetch("https://api.example.com")
46
+ .path("api", "v1", "main")
47
+ .request()
39
48
  ```
40
49
 
50
+ # ๐Ÿ› ๏ธ Vigor API Reference (Rewritten)
51
+
41
52
  ---
42
53
 
43
- ## Quick Start
54
+ # ๐Ÿ“ก vigor.fetch(origin)
44
55
 
45
- ```typescript
46
- import vigor from 'vigor-fetch';
56
+ vigor.fetch(origin: string)
47
57
 
48
- // Basic GET request
49
- const data = await vigor
50
- .fetch('https://api.example.com')
51
- .path('/users')
52
- .request();
53
-
54
- // POST request
55
- const result = await vigor
56
- .fetch('https://api.example.com')
57
- .path('/users')
58
- .body({ name: 'John', age: 30 })
59
- .request();
60
- ```
58
+ ## Chain Methods
59
+
60
+ | Method | Type | Description |
61
+ |--------|------|-------------|
62
+ | origin | (string) => VigorFetch | Set base URL |
63
+ | path | (...string[]) => VigorFetch | Append URL path segments |
64
+ | query | (object) => VigorFetch | Set query parameters |
65
+ | method | (VigorFetchMethods) => VigorFetch | Set HTTP method |
66
+ | headers | (HeadersInit) => VigorFetch | Set request headers |
67
+ | body | (any) => VigorFetch | Set request body |
68
+ | options | (object) => VigorFetch | Merge fetch options |
69
+ | setting | (fn: (s: VigorFetchSettings) => VigorFetchSettings) => VigorFetch | Settings pipeline |
70
+ | retryConfig | (fn: (r: VigorRetry) => VigorRetry) => VigorFetch | Retry engine config |
71
+ | parseConfig | (fn: (p: VigorParse) => VigorParse) => VigorFetch | Response parser config |
72
+ | interceptors | (fn: (i: VigorFetchInterceptors) => VigorFetchInterceptors) => VigorFetch | Lifecycle hooks |
73
+ | request | () => Promise<T> | Execute request |
61
74
 
62
75
  ---
63
76
 
64
- ## API Reference
65
-
66
- ### `vigor.fetch(origin?)` โ€” VigorFetch
67
-
68
- Builds and executes an HTTP request.
69
-
70
- | Method | Description |
71
- |---|---|
72
- | `.origin(str)` | Set the base URL |
73
- | `.path(str)` | Set the URL path |
74
- | `.query(obj)` | Set query parameters |
75
- | `.method(str)` | Set the HTTP method (default: POST if body present, otherwise GET) |
76
- | `.headers(obj)` | Set request headers |
77
- | `.body(obj)` | Set the request body (objects/arrays are automatically JSON-serialized) |
78
- | `.offset(obj)` | Pass options directly to `fetch` |
79
- | `.limit(ms)` | Maximum wait time per retry (ms) |
80
- | `.retryHeaders(...str)` | Add custom headers for Rate Limit detection |
81
- | `.unretry(...int)` | Set HTTP status codes that should not be retried |
82
- | `.retryConfig(fn)` | Customize the internal VigorRetry configuration |
83
- | `.parseConfig(fn)` | Customize the internal VigorParse configuration |
84
- | `.before(...fn)` | Interceptor called before the request |
85
- | `.after(...fn)` | Interceptor called after response is received (before parsing) |
86
- | `.result(...fn)` | Interceptor called after parsing is complete |
87
- | `.onError(...fn)` | Interceptor called on error |
88
- | `.request()` | Execute the request |
89
-
90
- **Example**
91
-
92
- ```typescript
93
- const data = await vigor
94
- .fetch('https://api.example.com')
95
- .path('/items')
96
- .query({ page: 1, limit: 20 })
97
- .headers({ Authorization: 'Bearer TOKEN' })
98
- .retryConfig(r => r.count(3).baseDelay(500))
99
- .before(async (ctx) => {
100
- console.log('Request started:', ctx.url);
101
- })
102
- .onError(async (ctx, err) => {
103
- console.error('Error occurred:', err.message);
104
- })
105
- .request();
106
- ```
77
+ ## โš™๏ธ fetch().setting(s => s)
78
+
79
+ | Field | Type | Description |
80
+ |------|------|-------------|
81
+ | origin | string | Base URL |
82
+ | path | string[] | URL segments |
83
+ | query | object | Query params |
84
+ | unretry | number[] | Non-retry status codes |
85
+ | retryHeaders | string[] | Retry-related headers |
86
+ | method | string | HTTP method |
87
+ | headers | object | Request headers |
88
+ | body | any | Request body |
89
+ | options | object | Fetch options |
90
+ | default | T | Fallback value |
107
91
 
108
92
  ---
109
93
 
110
- ### `vigor.retry(target, args?, config?)` โ€” VigorRetry
111
-
112
- Applies retry logic to any async function.
113
-
114
- | Method | Description |
115
- |---|---|
116
- | `.args(...args)` | Set arguments to pass to the target function |
117
- | `.count(n)` | Maximum number of attempts (default: 5) |
118
- | `.max(ms)` | Maximum wait time per attempt (default: 10000ms) |
119
- | `.backoff(factor)` | Exponential backoff multiplier (default: 1.3) |
120
- | `.baseDelay(ms)` | Base delay between retries (default: 1000ms) |
121
- | `.jitter(ms)` | Random jitter range added to each delay (default: 500ms) |
122
- | `.before(...fn)` | Interceptor called before each attempt |
123
- | `.after(...fn)` | Interceptor called after each successful attempt |
124
- | `.onRetry(...fn)` | Interceptor called when a retry is triggered |
125
- | `.onError(...fn)` | Interceptor called on final failure |
126
- | `.request()` | Execute |
127
-
128
- **Example**
129
-
130
- ```typescript
131
- const result = await vigor
132
- .retry(async () => {
133
- const res = await fetch('https://api.example.com/unstable');
134
- if (!res.ok) throw new Error('Failed');
135
- return res.json();
136
- })
137
- .count(5)
138
- .baseDelay(1000)
139
- .backoff(1.5)
140
- .jitter(300)
141
- .onRetry(async (ctx) => {
142
- console.log(`Retry #${ctx.attempt}, waiting ${ctx.wait}ms`);
143
- })
144
- .request();
145
- ```
94
+ ## ๐Ÿงฉ fetch().interceptors(i => i)
95
+
96
+ | Hook | Signature | Description |
97
+ |------|----------|-------------|
98
+ | before | (ctx, { setOptions, throwError }) => void | Before request |
99
+ | after | (ctx, { throwError }) => void | After success |
100
+ | onError | (ctx, { setResult, throwError }) => void | Error handler |
101
+ | result | (ctx, { setResult, throwError }) => void | Final result hook |
146
102
 
147
103
  ---
148
104
 
149
- ### `vigor.parse(response?)` โ€” VigorParse
105
+ # ๐Ÿ” vigor.retry(task)
150
106
 
151
- Automatically parses a `Response` object based on its Content-Type.
107
+ vigor.retry(task: VigorRetryTask<T>)
152
108
 
153
- | Content-Type | Parsing Method |
154
- |---|---|
155
- | `application/json` | `response.json()` |
156
- | `multipart/form-data` | `response.formData()` |
157
- | `application/octet-stream` | `response.arrayBuffer()` |
158
- | `image/*`, `video/*`, `audio/*`, `pdf` | `response.blob()` |
159
- | anything else | `response.text()` |
109
+ ## Methods
160
110
 
161
- | Method | Description |
162
- |---|---|
163
- | `.original(bool)` | If `true`, returns the raw Response without parsing |
164
- | `.type(str)` | Force a specific parsing method: `'json'`, `'text'`, `'blob'`, etc. |
165
- | `.before(...fn)` | Interceptor called before parsing |
166
- | `.after(...fn)` | Interceptor called after parsing |
167
- | `.onError(...fn)` | Interceptor called on error |
168
- | `.request()` | Execute parsing |
111
+ | Method | Type | Description |
112
+ |--------|------|-------------|
113
+ | target | (fn: VigorRetryTask<T>) => VigorRetry | Set retry function |
114
+ | setting | (fn: (s: VigorRetrySettings) => VigorRetrySettings) => VigorRetry | Retry settings |
115
+ | backoff | (fn: (b: VigorRetryBackoff) => VigorRetryBackoff) => VigorRetry | Backoff strategy |
116
+ | interceptors | (fn: (i: VigorRetryInterceptors) => VigorRetryInterceptors) => VigorRetry | Lifecycle hooks |
117
+ | request | () => Promise<T> | Execute retry flow |
118
+ | createController | () => (error: Error) => void | Abort controller |
169
119
 
170
- **Example**
120
+ ---
121
+
122
+ ## โš™๏ธ retry().setting(s => s)
171
123
 
172
- ```typescript
173
- const raw = await fetch('https://api.example.com/data');
124
+ | Field | Type | Description |
125
+ |------|------|-------------|
126
+ | count | number | Max retry attempts |
127
+ | limit | number | Timeout per attempt |
128
+ | maxDelay | number | Max delay cap |
129
+ | default | T | Fallback value |
174
130
 
175
- // Auto parsing based on Content-Type
176
- const parsed = await vigor.parse(raw).request();
131
+ ---
177
132
 
178
- // Force text parsing
179
- const text = await vigor.parse(raw).type('text').request();
133
+ ## ๐Ÿ“ˆ retry().backoff(b => b)
180
134
 
181
- // Return the raw Response object
182
- const original = await vigor.parse(raw).original(true).request();
183
- ```
135
+ | Field | Type | Description |
136
+ |------|------|-------------|
137
+ | initialDelay | number | Initial delay |
138
+ | baseDelay | number | Base delay |
139
+ | factor | number | Exponential multiplier |
140
+ | jitter | number | Random noise |
184
141
 
185
142
  ---
186
143
 
187
- ### `vigor.all(config?)` โ€” VigorAll
188
-
189
- Runs multiple async tasks in parallel with a concurrency limit.
190
-
191
- | Method | Description |
192
- |---|---|
193
- | `.promises(...fn)` | Add Promise factory functions to execute |
194
- | `.limit(n)` | Maximum number of concurrent tasks (default: 10) |
195
- | `.jitter(ms)` | Random delay before each task starts (default: 1000ms) |
196
- | `.before(...fn)` | Interceptor called before execution |
197
- | `.after(...fn)` | Interceptor called after all tasks complete |
198
- | `.onError(...fn)` | Interceptor called on error |
199
- | `.request()` | Execute โ€” always returns an array; failed items are `VigorAllError` instances |
200
-
201
- **Example**
202
-
203
- ```typescript
204
- const tasks = [1, 2, 3, 4, 5].map(id =>
205
- () => vigor.fetch('https://api.example.com').path(`/items/${id}`).request()
206
- );
207
-
208
- const results = await vigor
209
- .all()
210
- .promises(...tasks)
211
- .limit(3) // Run at most 3 tasks concurrently
212
- .jitter(200) // Add 0โ€“200ms random delay before each task starts
213
- .request();
214
-
215
- results.forEach((res, i) => {
216
- if (res instanceof VigorAllError) {
217
- console.error(`Task ${i} failed:`, res.message);
218
- } else {
219
- console.log(`Task ${i} succeeded:`, res);
220
- }
221
- });
222
- ```
144
+ ## ๐Ÿงฉ retry().interceptors(i => i)
145
+
146
+ | Hook | Signature | Description |
147
+ |------|----------|-------------|
148
+ | before | (ctx, { setAttempt, throwError, abort }) => void | Before execution |
149
+ | after | (ctx, { setAttempt, setResult, throwError }) => void | After success |
150
+ | onError | (ctx, { setResult, throwError }) => void | Error handling |
151
+ | onRetry | (ctx, { setDelay }) => void | Retry event |
152
+ | retryIf | (ctx, { proceedRetry, cancelRetry }) => void | Retry decision |
153
+
154
+ ---
155
+
156
+ # โšก vigor.all(tasks)
157
+
158
+ vigor.all(tasks: VigorAllTask<T>[])
159
+
160
+ ## Methods
161
+
162
+ | Method | Type | Description |
163
+ |--------|------|-------------|
164
+ | target | (...tasks) => VigorAll | Set tasks |
165
+ | setting | (fn: (s: VigorAllSettings) => VigorAllSettings) => VigorAll | Concurrency config |
166
+ | interceptors | (fn: (i: VigorAllInterceptors) => VigorAllInterceptors) => VigorAll | Hooks |
167
+ | request | () => Promise<Array<T | Error>> | Execute all tasks |
168
+
169
+ ---
170
+
171
+ ## โš™๏ธ all().setting(s => s)
172
+
173
+ | Field | Type | Description |
174
+ |------|------|-------------|
175
+ | concurrency | number | Max parallel tasks |
176
+ | jitter | number | Delay randomness |
177
+
178
+ ---
179
+
180
+ ## ๐Ÿงฉ all().interceptors(i => i)
181
+
182
+ | Hook | Signature | Description |
183
+ |------|----------|-------------|
184
+ | before | (ctx) => void | Before each task |
185
+ | after | (ctx, { setResult }) => void | After success |
186
+ | onError | (ctx, { setResult }) => void | Error handling |
187
+ | result | (ctx, { setResult }) => void | Final aggregation |
223
188
 
224
189
  ---
225
190
 
226
- ## Interceptor Context (`ctx`)
191
+ # ๐Ÿงช vigor.parse(response)
192
+
193
+ vigor.parse(response: Response)
227
194
 
228
- All interceptor functions receive a `ctx` object as their first argument.
229
- Returning a plain object from an interceptor merges its keys into `ctx`, making them available to subsequent interceptors.
195
+ | Method | Type | Description |
196
+ |--------|------|-------------|
197
+ | target | Response | Set response |
198
+ | original | boolean | Return raw response |
199
+ | type | keyof Response | Force parse type |
200
+ | request | () => Promise<T> | Execute parsing |
201
+
202
+ ---
230
203
 
231
- ```typescript
232
- vigor
233
- .fetch('https://api.example.com')
234
- .before(async (ctx, option) => {
235
- // Access ctx.origin, ctx.path, ctx.option, etc.
236
- return { requestId: 'abc-123' }; // merged into ctx
204
+ # ๐Ÿš€ vigor.fetch examples
205
+
206
+ ## GET request
207
+ ```ts
208
+ vigor.fetch("https://api.example.com")
209
+ .path("users", "profile")
210
+ .query({ id: 123 })
211
+ .method("GET")
212
+ .request()
213
+ ```
214
+ ---
215
+
216
+ ## POST request
217
+ ```ts
218
+ vigor.fetch("https://api.example.com")
219
+ .path("users")
220
+ .method("POST")
221
+ .headers({
222
+ Authorization: "Bearer TOKEN"
237
223
  })
238
- .after(async (ctx, response) => {
239
- // ctx.requestId === 'abc-123'
240
- // ctx.result: current response object
224
+ .body({
225
+ name: "John",
226
+ age: 30
241
227
  })
242
- .request();
228
+ .request()
243
229
  ```
230
+ ---
244
231
 
232
+ ## fetch + retry + backoff + parse
233
+ ```ts
234
+ vigor.fetch("https://api.example.com")
235
+ .path("data")
236
+ .retryConfig(r =>
237
+ r
238
+ .setting(s =>
239
+ s
240
+ .count(3)
241
+ .limit(5000)
242
+ )
243
+ .backoff(b =>
244
+ b
245
+ .factor(2)
246
+ .jitter(300)
247
+ )
248
+ )
249
+ .parseConfig(p =>
250
+ p.original(false)
251
+ )
252
+ .request()
253
+ ```
245
254
  ---
246
255
 
247
- ## Error Classes
248
-
249
- | Class | Description |
250
- |---|---|
251
- | `VigorError` | Base error class |
252
- | `VigorFetchError` | Error thrown during fetch |
253
- | `VigorRetryError` | Error thrown during retry |
254
- | `VigorParseError` | Error thrown during parsing |
255
- | `VigorAllError` | Error thrown during parallel execution |
256
-
257
- All errors share the following shape:
258
-
259
- ```typescript
260
- interface VigorErrorOptions {
261
- type?: string; // Error category
262
- data?: any; // Related data
263
- status?: number; // HTTP status code
264
- response?: any; // Original response
265
- message?: string; // Custom message
266
- origin?: string; // Request origin
267
- }
256
+ # ๐Ÿ” vigor.retry examples
257
+
258
+ ## basic retry
259
+ ```ts
260
+ vigor.retry(async (ctx, { signal }) => {
261
+ const res = await fetch("https://api.example.com/data", { signal })
262
+ if (!res.ok) throw new Error("failed")
263
+ return res.json()
264
+ })
265
+ .setting(s =>
266
+ s
267
+ .count(5)
268
+ .limit(3000)
269
+ )
270
+ .backoff(b =>
271
+ b
272
+ .baseDelay(500)
273
+ .factor(2)
274
+ )
275
+ .request()
268
276
  ```
277
+ ---
269
278
 
279
+ ## retryIf control
280
+ ```ts
281
+ vigor.retry(async () => {
282
+ const res = await fetch("https://api.example.com")
283
+ return res.json()
284
+ })
285
+ .interceptors(i =>
286
+ i.retryIf((ctx, { cancelRetry }) => {
287
+ const result = ctx.runtime.result
288
+
289
+ if (result?.error === "fatal") {
290
+ cancelRetry()
291
+ }
292
+ })
293
+ )
294
+ .request()
295
+ ```
270
296
  ---
271
297
 
272
- ## Plugins
298
+ ## abort controller
299
+ ```ts
300
+ const retry = vigor.retry(async (ctx, { signal }) => {
301
+ const res = await fetch("https://api.example.com", { signal })
302
+ return res.json()
303
+ })
273
304
 
274
- Use `vigor.use(plugin, options?)` to extend behavior.
305
+ const abort = retry.createController()
275
306
 
276
- ```typescript
277
- const authPlugin = (instance, options) => {
278
- const original = instance.fetch.bind(instance);
279
- instance.fetch = (origin, config) =>
280
- original(origin, config).headers({ Authorization: `Bearer ${options.token}` });
281
- };
307
+ setTimeout(() => {
308
+ abort(new Error("manual abort"))
309
+ }, 2000)
282
310
 
283
- vigor.use(authPlugin, { token: 'MY_TOKEN' });
311
+ await retry.request()
312
+ ```
313
+ ---
314
+
315
+ # โšก vigor.all examples
316
+ ```ts
317
+ vigor.all([
318
+ async () => fetch("https://api.com/a").then(r => r.json()),
319
+ async () => fetch("https://api.com/b").then(r => r.json()),
320
+ async () => fetch("https://api.com/c").then(r => r.json())
321
+ ]).request()
322
+ ```
323
+ ---
324
+ ```ts
325
+ vigor.all([
326
+ async () => "A",
327
+ async () => "B",
328
+ async () => "C",
329
+ async () => "D"
330
+ ])
331
+ .setting(s =>
332
+ s
333
+ .concurrency(2)
334
+ .jitter(500)
335
+ )
336
+ .request()
337
+ ```
338
+ ---
339
+ ```ts
340
+ vigor.all([
341
+ async () => "ok1",
342
+ async () => { throw new Error("fail") },
343
+ async () => "ok2"
344
+ ]).request()
345
+ ```
346
+ ---
284
347
 
285
- // Authorization header is now automatically attached to every vigor.fetch() call
286
- const data = await vigor.fetch('https://api.example.com').path('/me').request();
348
+ # ๐Ÿงช vigor.parse examples
349
+ ```ts
350
+ const res = await fetch("https://api.com/data")
351
+
352
+ vigor.parse(res).request()
287
353
  ```
354
+ ---
355
+ ```ts
356
+ const img = await fetch("https://api.com/image.png")
357
+
358
+ vigor.parse(img)
359
+ .type("blob")
360
+ .request()
361
+ ```
362
+ ---
363
+ ```ts
364
+ const raw = await fetch("https://api.com")
288
365
 
366
+ vigor.parse(raw)
367
+ .original(true)
368
+ .request()
369
+ ```
370
+ ---
371
+
372
+ # ๐Ÿ”ฅ full pipeline example
373
+ ```ts
374
+ vigor.fetch("https://api.example.com")
375
+ .path("users")
376
+ .query({ page: 1 })
377
+ .method("GET")
378
+ .retryConfig(r =>
379
+ r
380
+ .setting(s =>
381
+ s
382
+ .count(3)
383
+ .limit(5000)
384
+ )
385
+ .backoff(b =>
386
+ b
387
+ .factor(2)
388
+ .jitter(200)
389
+ )
390
+ .interceptors(i =>
391
+ i.onRetry((ctx, { setDelay }) => {
392
+ setDelay(1000)
393
+ })
394
+ )
395
+ )
396
+ .parseConfig(p =>
397
+ p.original(false)
398
+ )
399
+ .interceptors(i =>
400
+ i.result(() => {
401
+ console.log("done")
402
+ })
403
+ )
404
+ .request()
405
+ ```
289
406
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vigor-fetch",
3
- "version": "1.0.20",
3
+ "version": "2.0.0",
4
4
  "description": "Smart, zero-dependency HTTP client with self-healing retries for rate-limited servers.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",