vigor-fetch 1.0.20 โ†’ 2.0.1

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 +395 -219
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,289 +1,465 @@
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
+
19
+
18
20
  ---
19
21
 
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install vigor-fetch
27
+ ```
28
+
20
29
  ## Why Vigor?
21
30
 
22
31
  | Feature | Vigor | native fetch | ky | axios |
23
32
  |---|:---:|:---:|:---:|:---:|
24
- | Zero dependencies | โœ… | โœ… | โœ… | โŒ |
25
- | Auto retry with backoff | โœ… | โŒ | โœ… | โŒ |
26
- | 429 rate-limit header handling | โœ… | โŒ | โŒ | โŒ |
27
- | Jitter on retry | โœ… | โŒ | โŒ | โŒ |
28
- | Auto response parsing | โœ… | โŒ | partial | partial |
33
+ | Zero dependencies | โœ… | โœ… | โŒ | โœ… |
34
+ | 429 rate-limit handling | โœ… | โŒ | โœ…(manual/config-based) | โŒ |
35
+ | Retry with jitter | โœ… | โŒ | โœ… | โŒ |
36
+ | Exponential backoff | โœ… | โŒ | โœ… | โŒ |
37
+ | Auto response parsing | โœ… | โŒ | โœ… | โœ… |
29
38
  | Fluent chaining API | โœ… | โŒ | โœ… | โŒ |
30
- | Concurrency-limited parallel requests | โœ… | โŒ | โŒ | โŒ |
31
- | Lifecycle interceptors | โœ… | โŒ | โœ… | โœ… |
39
+ | Concurrency control | โœ… | โŒ | โŒ | โŒ |
40
+ | Lifecycle interceptors | โœ… | โŒ | partial | โŒ |
32
41
  | Plugin system | โœ… | โŒ | โŒ | โŒ |
33
- | TypeScript-first | โœ… | โŒ | โœ… | partial |
34
42
 
35
- ## Installation
43
+ ## Quick Start
36
44
 
37
- ```bash
38
- npm install vigor-fetch
45
+ ```ts
46
+ import vigor from "vigor-fetch";
47
+ const data = await vigor
48
+ .fetch("https://api.example.com")
49
+ .path("api", "v1", "main")
50
+ .request()
39
51
  ```
40
52
 
53
+ # ๐Ÿ› ๏ธ Vigor API Reference
54
+
55
+
41
56
  ---
42
57
 
43
- ## Quick Start
44
58
 
45
- ```typescript
46
- import vigor from 'vigor-fetch';
59
+ # ๐Ÿ“ก vigor.fetch(origin)
60
+
61
+ vigor.fetch(origin: string)
62
+
63
+ ## Chain Methods
64
+
65
+ | Method | Type | Description |
66
+ |--------|------|-------------|
67
+ | origin | (string) => VigorFetch | Set base URL |
68
+ | path | (...string[]) => VigorFetch | Append URL path segments |
69
+ | query | (object) => VigorFetch | Set query parameters |
70
+ | method | (VigorFetchMethods) => VigorFetch | Set HTTP method |
71
+ | headers | (HeadersInit) => VigorFetch | Set request headers |
72
+ | body | (any) => VigorFetch | Set request body |
73
+ | options | (object) => VigorFetch | Merge fetch options |
74
+ | setting | (fn: (s: VigorFetchSettings) => VigorFetchSettings) => VigorFetch | Settings pipeline |
75
+ | retryConfig | (fn: (r: VigorRetry) => VigorRetry) => VigorFetch | Retry engine config |
76
+ | parseConfig | (fn: (p: VigorParse) => VigorParse) => VigorFetch | Response parser config |
77
+ | interceptors | (fn: (i: VigorFetchInterceptors) => VigorFetchInterceptors) => VigorFetch | Lifecycle hooks |
78
+ | request | () => Promise<T> | Execute request |
47
79
 
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
- ```
61
80
 
62
81
  ---
63
82
 
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);
83
+
84
+ ## โš™๏ธ fetch().setting(s => s)
85
+
86
+ | Field | Type | Description |
87
+ |------|------|-------------|
88
+ | origin | string | Base URL |
89
+ | path | string[] | URL segments |
90
+ | query | object | Query params |
91
+ | unretry | number[] | Non-retry status codes |
92
+ | retryHeaders | string[] | Retry-related headers |
93
+ | method | string | HTTP method |
94
+ | headers | object | Request headers |
95
+ | body | any | Request body |
96
+ | options | object | Fetch options |
97
+ | default | T | Fallback value |
98
+
99
+
100
+ ---
101
+
102
+
103
+ ## ๐Ÿงฉ fetch().interceptors(i => i)
104
+
105
+ | Hook | Signature | Description |
106
+ |------|----------|-------------|
107
+ | before | (ctx, { setOptions, throwError }) => void | Before request |
108
+ | after | (ctx, { throwError }) => void | After success |
109
+ | onError | (ctx, { setResult, throwError }) => void | Error handler |
110
+ | result | (ctx, { setResult, throwError }) => void | Final result hook |
111
+
112
+
113
+ ---
114
+
115
+
116
+ # ๐Ÿ” vigor.retry(task)
117
+
118
+ vigor.retry(task: VigorRetryTask<T>)
119
+
120
+ ## Methods
121
+
122
+ | Method | Type | Description |
123
+ |--------|------|-------------|
124
+ | target | (fn: VigorRetryTask<T>) => VigorRetry | Set retry function |
125
+ | setting | (fn: (s: VigorRetrySettings) => VigorRetrySettings) => VigorRetry | Retry settings |
126
+ | backoff | (fn: (b: VigorRetryBackoff) => VigorRetryBackoff) => VigorRetry | Backoff strategy |
127
+ | interceptors | (fn: (i: VigorRetryInterceptors) => VigorRetryInterceptors) => VigorRetry | Lifecycle hooks |
128
+ | request | () => Promise<T> | Execute retry flow |
129
+ | createController | () => (error: Error) => void | Abort controller |
130
+
131
+
132
+ ---
133
+
134
+
135
+ ## โš™๏ธ retry().setting(s => s)
136
+
137
+ | Field | Type | Description |
138
+ |------|------|-------------|
139
+ | count | number | Max retry attempts |
140
+ | limit | number | Timeout per attempt |
141
+ | maxDelay | number | Max delay cap |
142
+ | default | T | Fallback value |
143
+
144
+
145
+ ---
146
+
147
+
148
+ ## ๐Ÿ“ˆ retry().backoff(b => b)
149
+
150
+ | Field | Type | Description |
151
+ |------|------|-------------|
152
+ | initialDelay | number | Initial delay |
153
+ | baseDelay | number | Base delay |
154
+ | factor | number | Exponential multiplier |
155
+ | jitter | number | Random noise |
156
+
157
+
158
+ ---
159
+
160
+
161
+ ## ๐Ÿงฉ retry().interceptors(i => i)
162
+
163
+ | Hook | Signature | Description |
164
+ |------|----------|-------------|
165
+ | before | (ctx, { setAttempt, throwError, abort }) => void | Before execution |
166
+ | after | (ctx, { setAttempt, setResult, throwError }) => void | After success |
167
+ | onError | (ctx, { setResult, throwError }) => void | Error handling |
168
+ | onRetry | (ctx, { setDelay }) => void | Retry event |
169
+ | retryIf | (ctx, { proceedRetry, cancelRetry }) => void | Retry decision |
170
+
171
+
172
+ ---
173
+
174
+
175
+ # โšก vigor.all(tasks)
176
+
177
+ vigor.all(tasks: VigorAllTask<T>[])
178
+
179
+ ## Methods
180
+
181
+ | Method | Type | Description |
182
+ |--------|------|-------------|
183
+ | target | (...tasks) => VigorAll | Set tasks |
184
+ | setting | (fn: (s: VigorAllSettings) => VigorAllSettings) => VigorAll | Concurrency config |
185
+ | interceptors | (fn: (i: VigorAllInterceptors) => VigorAllInterceptors) => VigorAll | Hooks |
186
+ | request | () => Promise<Array<T | Error>> | Execute all tasks |
187
+
188
+
189
+ ---
190
+
191
+
192
+ ## โš™๏ธ all().setting(s => s)
193
+
194
+ | Field | Type | Description |
195
+ |------|------|-------------|
196
+ | concurrency | number | Max parallel tasks |
197
+ | jitter | number | Delay randomness |
198
+
199
+
200
+ ---
201
+
202
+
203
+ ## ๐Ÿงฉ all().interceptors(i => i)
204
+
205
+ | Hook | Signature | Description |
206
+ |------|----------|-------------|
207
+ | before | (ctx) => void | Before each task |
208
+ | after | (ctx, { setResult }) => void | After success |
209
+ | onError | (ctx, { setResult }) => void | Error handling |
210
+ | result | (ctx, { setResult }) => void | Final aggregation |
211
+
212
+
213
+ ---
214
+
215
+
216
+ # ๐Ÿงช vigor.parse(response)
217
+
218
+ vigor.parse(response: Response)
219
+
220
+ | Method | Type | Description |
221
+ |--------|------|-------------|
222
+ | target | Response | Set response |
223
+ | original | boolean | Return raw response |
224
+ | type | keyof Response | Force parse type |
225
+ | request | () => Promise<T> | Execute parsing |
226
+
227
+
228
+ ---
229
+
230
+
231
+ # ๐Ÿš€ vigor.fetch examples
232
+
233
+ ## GET request
234
+ ```ts
235
+ vigor.fetch("https://api.example.com")
236
+ .path("users", "profile")
237
+ .query({ id: 123 })
238
+ .method("GET")
239
+ .request()
240
+ ```
241
+ ---
242
+
243
+ ## POST request
244
+ ```ts
245
+ vigor.fetch("https://api.example.com")
246
+ .path("users")
247
+ .method("POST")
248
+ .headers({
249
+ Authorization: "Bearer TOKEN"
101
250
  })
102
- .onError(async (ctx, err) => {
103
- console.error('Error occurred:', err.message);
251
+ .body({
252
+ name: "John",
253
+ age: 30
104
254
  })
105
- .request();
255
+ .request()
256
+ ```
257
+ ---
258
+
259
+ ## fetch + retry + backoff + parse
260
+ ```ts
261
+ vigor.fetch("https://api.example.com")
262
+ .path("data")
263
+ .retryConfig(r =>
264
+ r
265
+ .setting(s =>
266
+ s
267
+ .count(3)
268
+ .limit(5000)
269
+ )
270
+ .backoff(b =>
271
+ b
272
+ .factor(2)
273
+ .jitter(300)
274
+ )
275
+ )
276
+ .parseConfig(p =>
277
+ p.original(false)
278
+ )
279
+ .request()
280
+ ```
281
+ ---
282
+
283
+ # ๐Ÿ” vigor.retry examples
284
+
285
+ ## basic retry
286
+ ```ts
287
+ vigor.retry(async (ctx, { signal }) => {
288
+ const res = await fetch("https://api.example.com/data", { signal })
289
+ if (!res.ok) throw new Error("failed")
290
+ return res.json()
291
+ })
292
+ .setting(s =>
293
+ s
294
+ .count(5)
295
+ .limit(3000)
296
+ )
297
+ .backoff(b =>
298
+ b
299
+ .baseDelay(500)
300
+ .factor(2)
301
+ )
302
+ .request()
106
303
  ```
107
304
 
305
+
108
306
  ---
109
307
 
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`);
308
+
309
+ ## retryIf control
310
+ ```ts
311
+ vigor.retry(async () => {
312
+ const res = await fetch("https://api.example.com")
313
+ return res.json()
314
+ })
315
+ .interceptors(i =>
316
+ i.retryIf((ctx, { cancelRetry }) => {
317
+ const result = ctx.runtime.result
318
+
319
+ if (result?.error === "fatal") {
320
+ cancelRetry()
321
+ }
143
322
  })
144
- .request();
323
+ )
324
+ .request()
145
325
  ```
146
326
 
327
+
147
328
  ---
148
329
 
149
- ### `vigor.parse(response?)` โ€” VigorParse
150
330
 
151
- Automatically parses a `Response` object based on its Content-Type.
331
+ ## abort controller
332
+ ```ts
333
+ const retry = vigor.retry(async (ctx, { signal }) => {
334
+ const res = await fetch("https://api.example.com", { signal })
335
+ return res.json()
336
+ })
152
337
 
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()` |
338
+ const abort = retry.createController()
160
339
 
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 |
340
+ setTimeout(() => {
341
+ abort(new Error("manual abort"))
342
+ }, 2000)
169
343
 
170
- **Example**
344
+ await retry.request()
345
+ ```
171
346
 
172
- ```typescript
173
- const raw = await fetch('https://api.example.com/data');
174
347
 
175
- // Auto parsing based on Content-Type
176
- const parsed = await vigor.parse(raw).request();
348
+ ---
177
349
 
178
- // Force text parsing
179
- const text = await vigor.parse(raw).type('text').request();
180
350
 
181
- // Return the raw Response object
182
- const original = await vigor.parse(raw).original(true).request();
351
+ # โšก vigor.all examples
352
+ ```ts
353
+ vigor.all([
354
+ async () => fetch("https://api.com/a").then(r => r.json()),
355
+ async () => fetch("https://api.com/b").then(r => r.json()),
356
+ async () => fetch("https://api.com/c").then(r => r.json())
357
+ ]).request()
183
358
  ```
184
359
 
360
+
185
361
  ---
186
362
 
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
- });
363
+
364
+ ```ts
365
+ vigor.all([
366
+ async () => "A",
367
+ async () => "B",
368
+ async () => "C",
369
+ async () => "D"
370
+ ])
371
+ .setting(s =>
372
+ s
373
+ .concurrency(2)
374
+ .jitter(500)
375
+ )
376
+ .request()
222
377
  ```
223
378
 
379
+
224
380
  ---
225
381
 
226
- ## Interceptor Context (`ctx`)
227
382
 
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.
383
+ ```ts
384
+ vigor.all([
385
+ async () => "ok1",
386
+ async () => { throw new Error("fail") },
387
+ async () => "ok2"
388
+ ]).request()
389
+ ```
230
390
 
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
237
- })
238
- .after(async (ctx, response) => {
239
- // ctx.requestId === 'abc-123'
240
- // ctx.result: current response object
241
- })
242
- .request();
391
+ ---
392
+
393
+
394
+ # ๐Ÿงช vigor.parse examples
395
+ ```ts
396
+ const res = await fetch("https://api.com/data")
397
+
398
+ vigor.parse(res).request()
243
399
  ```
244
400
 
401
+
245
402
  ---
246
403
 
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
- }
404
+
405
+ ```ts
406
+ const img = await fetch("https://api.com/image.png")
407
+
408
+ vigor.parse(img)
409
+ .type("blob")
410
+ .request()
268
411
  ```
269
412
 
413
+
270
414
  ---
271
415
 
272
- ## Plugins
273
416
 
274
- Use `vigor.use(plugin, options?)` to extend behavior.
417
+ ```ts
418
+ const raw = await fetch("https://api.com")
275
419
 
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
- };
420
+ vigor.parse(raw)
421
+ .original(true)
422
+ .request()
423
+ ```
282
424
 
283
- vigor.use(authPlugin, { token: 'MY_TOKEN' });
284
425
 
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();
426
+ ---
427
+
428
+
429
+ # ๐Ÿ”ฅ full pipeline example
430
+ ```ts
431
+ vigor.fetch("https://api.example.com")
432
+ .path("users")
433
+ .query({ page: 1 })
434
+ .method("GET")
435
+ .retryConfig(r =>
436
+ r
437
+ .setting(s =>
438
+ s
439
+ .count(3)
440
+ .limit(5000)
441
+ )
442
+ .backoff(b =>
443
+ b
444
+ .factor(2)
445
+ .jitter(200)
446
+ )
447
+ .interceptors(i =>
448
+ i.onRetry((ctx, { setDelay }) => {
449
+ setDelay(1000)
450
+ })
451
+ )
452
+ )
453
+ .parseConfig(p =>
454
+ p.original(false)
455
+ )
456
+ .interceptors(i =>
457
+ i.result(() => {
458
+ console.log("done")
459
+ })
460
+ )
461
+ .request()
287
462
  ```
288
463
 
464
+
289
465
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vigor-fetch",
3
- "version": "1.0.20",
3
+ "version": "2.0.1",
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",