@scirexs/fetchy 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/LICENSE +21 -0
- package/README.md +329 -0
- package/esm/main.js +441 -0
- package/esm/mod.js +5 -0
- package/esm/package.json +3 -0
- package/esm/types.js +1 -0
- package/package.json +33 -0
- package/types/main.d.ts +305 -0
- package/types/main.d.ts.map +1 -0
- package/types/mod.d.ts +7 -0
- package/types/mod.d.ts.map +1 -0
- package/types/types.d.ts +80 -0
- package/types/types.d.ts.map +1 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 scirexs
|
|
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,329 @@
|
|
|
1
|
+
# fetchy
|
|
2
|
+
|
|
3
|
+
A lightweight, type-safe fetch wrapper with built-in retry logic, timeout handling, and automatic body parsing.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Lightweight** - Zero dependencies, works in Deno, Node.js, and browsers
|
|
8
|
+
- **Simple API** - Drop-in replacement for native fetch with enhanced capabilities
|
|
9
|
+
- **Timeout Support** - Configurable request timeouts with automatic cancellation
|
|
10
|
+
- **Smart Retry Logic** - Exponential backoff with Retry-After header support
|
|
11
|
+
- **Type-Safe** - Full TypeScript support with generic type inference
|
|
12
|
+
- **Bearer Token Helper** - Built-in Authorization header management
|
|
13
|
+
- **Jitter Support** - Prevent thundering herd with randomized delays
|
|
14
|
+
- **Auto Body Parsing** - Automatic JSON serialization and Content-Type detection
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
```bash
|
|
18
|
+
# npm
|
|
19
|
+
npm install @scirexs/fetchy
|
|
20
|
+
|
|
21
|
+
# JSR (Deno)
|
|
22
|
+
deno add jsr:@scirexs/fetchy
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
```ts
|
|
27
|
+
import { fetchy, fetchyb } from "@scirexs/fetchy";
|
|
28
|
+
|
|
29
|
+
// Simple GET request with timeout
|
|
30
|
+
const response = await fetchy("https://api.example.com/data", {
|
|
31
|
+
timeout: 10
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Auto-parsed JSON response
|
|
35
|
+
interface User {
|
|
36
|
+
id: number;
|
|
37
|
+
name: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const user = await fetchyb<User>("https://api.example.com/user/1", "json");
|
|
41
|
+
console.log(user?.name);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## API Reference
|
|
45
|
+
|
|
46
|
+
### `fetchy(url, options?)`
|
|
47
|
+
|
|
48
|
+
Performs an HTTP request and returns the raw Response object.
|
|
49
|
+
|
|
50
|
+
#### Parameters
|
|
51
|
+
- `url`: string | URL | Request - The request URL
|
|
52
|
+
- `options`: FetchyOptions (optional) - Configuration options
|
|
53
|
+
|
|
54
|
+
#### Returns
|
|
55
|
+
`Promise<Response | null>`
|
|
56
|
+
|
|
57
|
+
#### Example
|
|
58
|
+
```ts
|
|
59
|
+
const response = await fetchy("https://api.example.com/data", {
|
|
60
|
+
method: "POST",
|
|
61
|
+
body: { key: "value" },
|
|
62
|
+
timeout: 10,
|
|
63
|
+
retry: { max: 3, interval: 2 },
|
|
64
|
+
bearerToken: "your-token-here"
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (response?.ok) {
|
|
68
|
+
const data = await response.json();
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### `fetchyb(url, type?, options?)`
|
|
73
|
+
|
|
74
|
+
Performs an HTTP request and automatically parses the response body.
|
|
75
|
+
|
|
76
|
+
#### Parameters
|
|
77
|
+
- `url`: string | URL | Request - The request URL
|
|
78
|
+
- `type`: "text" | "json" | "bytes" | "auto" (default: "auto") - Response parsing type
|
|
79
|
+
- `options`: FetchyOptions (optional) - Configuration options
|
|
80
|
+
|
|
81
|
+
#### Returns
|
|
82
|
+
`Promise<T | string | Uint8Array | null>`
|
|
83
|
+
|
|
84
|
+
#### Example
|
|
85
|
+
```ts
|
|
86
|
+
// Automatic type detection from Content-Type header
|
|
87
|
+
const data = await fetchyb("https://api.example.com/data");
|
|
88
|
+
|
|
89
|
+
// Explicit JSON parsing with type assertion
|
|
90
|
+
interface Product {
|
|
91
|
+
id: number;
|
|
92
|
+
name: string;
|
|
93
|
+
price: number;
|
|
94
|
+
}
|
|
95
|
+
const product = await fetchyb<Product>("https://api.example.com/product/1", "json");
|
|
96
|
+
|
|
97
|
+
// Text content
|
|
98
|
+
const html = await fetchyb("https://example.com", "text");
|
|
99
|
+
|
|
100
|
+
// Binary data
|
|
101
|
+
const image = await fetchyb("https://example.com/image.png", "bytes");
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Configuration Options
|
|
105
|
+
|
|
106
|
+
### FetchyOptions
|
|
107
|
+
```ts
|
|
108
|
+
interface FetchyOptions {
|
|
109
|
+
// Standard fetch options (method, headers, etc.)
|
|
110
|
+
method?: string;
|
|
111
|
+
headers?: HeadersInit;
|
|
112
|
+
|
|
113
|
+
// Request body (auto-serializes JSON)
|
|
114
|
+
body?: JSONValue | FormData | URLSearchParams | Blob | ArrayBuffer | string;
|
|
115
|
+
|
|
116
|
+
// Timeout in seconds (default: 15)
|
|
117
|
+
timeout?: number;
|
|
118
|
+
|
|
119
|
+
// Retry configuration
|
|
120
|
+
retry?: {
|
|
121
|
+
max?: number; // Max retry attempts (default: 3)
|
|
122
|
+
interval?: number; // Base interval in seconds (default: 3)
|
|
123
|
+
maxInterval?: number; // Max interval cap (default: 30)
|
|
124
|
+
byHeader?: boolean; // Respect Retry-After header (default: true)
|
|
125
|
+
} | false; // Set to false to disable retry
|
|
126
|
+
|
|
127
|
+
// Bearer token (auto-adds "Bearer " prefix)
|
|
128
|
+
bearerToken?: string;
|
|
129
|
+
|
|
130
|
+
// Error throwing behavior
|
|
131
|
+
throwError?: {
|
|
132
|
+
onError?: boolean; // Throw on native errors (default: true)
|
|
133
|
+
onErrorStatus?: boolean; // Throw on 4xx/5xx status (default: false)
|
|
134
|
+
} | boolean; // Set to true to throw all errors
|
|
135
|
+
|
|
136
|
+
// Initial jitter delay in seconds
|
|
137
|
+
jitter?: number;
|
|
138
|
+
|
|
139
|
+
// Manual abort controller (if timeout occur, reason is set to "timeout")
|
|
140
|
+
abort?: AbortController;
|
|
141
|
+
|
|
142
|
+
// Redirect behavior
|
|
143
|
+
redirect?: "follow" | "error" | "manual";
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Default Values
|
|
148
|
+
```ts
|
|
149
|
+
{
|
|
150
|
+
timeout: 15, // 15 seconds
|
|
151
|
+
jitter: 0, // No jitter
|
|
152
|
+
retry: {
|
|
153
|
+
max: 3, // 3 retry attempts
|
|
154
|
+
interval: 3, // 3 seconds base interval
|
|
155
|
+
maxInterval: 30, // 30 seconds max interval
|
|
156
|
+
byHeader: true // Respect Retry-After header
|
|
157
|
+
},
|
|
158
|
+
throwError: {
|
|
159
|
+
onError: true, // Throw parsing errors
|
|
160
|
+
onErrorStatus: false // Don't throw on HTTP errors
|
|
161
|
+
},
|
|
162
|
+
redirect: "follow" // Follow redirects
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Usage Examples
|
|
167
|
+
|
|
168
|
+
### Basic Requests
|
|
169
|
+
```ts
|
|
170
|
+
import { fetchy, fetchyb } from "@scirexs/fetchy";
|
|
171
|
+
|
|
172
|
+
// GET request
|
|
173
|
+
const data = await fetchyb("https://api.example.com/data", "json");
|
|
174
|
+
|
|
175
|
+
// POST with JSON body
|
|
176
|
+
const result = await fetchyb("https://api.example.com/create", "json", {
|
|
177
|
+
body: { name: "John", email: "john@example.com" }
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Custom headers
|
|
181
|
+
const response = await fetchy("https://api.example.com/data", {
|
|
182
|
+
headers: {
|
|
183
|
+
"X-Custom-Header": "value"
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Authentication
|
|
189
|
+
```ts
|
|
190
|
+
// Bearer token authentication
|
|
191
|
+
const user = await fetchyb<User>("https://api.example.com/me", "json", {
|
|
192
|
+
bearerToken: "your-access-token"
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// Custom authorization
|
|
196
|
+
const data = await fetchyb("https://api.example.com/data", "json", {
|
|
197
|
+
headers: {
|
|
198
|
+
"Authorization": "Basic " + btoa("user:pass")
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Timeout and Retry
|
|
204
|
+
```ts
|
|
205
|
+
// Custom timeout
|
|
206
|
+
const response = await fetchy("https://slow-api.example.com", {
|
|
207
|
+
timeout: 30 // 30 seconds
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Retry with exponential backoff
|
|
211
|
+
const data = await fetchyb("https://api.example.com/data", "json", {
|
|
212
|
+
retry: {
|
|
213
|
+
max: 5, // Retry up to 5 times
|
|
214
|
+
interval: 2, // Start with 2 seconds
|
|
215
|
+
maxInterval: 60, // Cap at 60 seconds
|
|
216
|
+
byHeader: true // Respect Retry-After header
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Disable retry
|
|
221
|
+
const response = await fetchy("https://api.example.com/data", {
|
|
222
|
+
retry: false
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Error Handling
|
|
227
|
+
```ts
|
|
228
|
+
import { fetchy, HTTPStatusError, RedirectError } from "@scirexs/fetchy";
|
|
229
|
+
|
|
230
|
+
// Return null on error (default)
|
|
231
|
+
const data = await fetchyb("https://api.example.com/data", "json");
|
|
232
|
+
if (data === null) {
|
|
233
|
+
console.log("Request failed");
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Throw on error
|
|
237
|
+
try {
|
|
238
|
+
const data = await fetchyb("https://api.example.com/data", "json", {
|
|
239
|
+
throwError: true
|
|
240
|
+
});
|
|
241
|
+
} catch (error) {
|
|
242
|
+
console.error("Request failed:", error);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Throw only on HTTP errors
|
|
246
|
+
try {
|
|
247
|
+
const data = await fetchyb("https://api.example.com/data", "json", {
|
|
248
|
+
throwError: { onErrorStatus: true }
|
|
249
|
+
});
|
|
250
|
+
} catch (error) {
|
|
251
|
+
if (error instanceof HTTPStatusError) {
|
|
252
|
+
console.error("HTTP error:", error.message); // e.g., "404 Not Found"
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Handle redirects
|
|
257
|
+
try {
|
|
258
|
+
const response = await fetchy("https://example.com/redirect", {
|
|
259
|
+
redirect: "error"
|
|
260
|
+
});
|
|
261
|
+
} catch (error) {
|
|
262
|
+
if (error instanceof RedirectError) {
|
|
263
|
+
console.error("Unexpected redirect:", error.message);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Advanced Usage
|
|
269
|
+
```ts
|
|
270
|
+
// Jitter to prevent thundering herd
|
|
271
|
+
const response = await fetchy("https://api.example.com/data", {
|
|
272
|
+
jitter: 2, // Random delay up to 2 seconds before request
|
|
273
|
+
retry: { max: 3 }
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Manual abort control
|
|
277
|
+
const controller = new AbortController();
|
|
278
|
+
|
|
279
|
+
setTimeout(() => controller.abort(), 5000); // Abort after 5 seconds
|
|
280
|
+
|
|
281
|
+
const response = await fetchy("https://api.example.com/data", {
|
|
282
|
+
abort: controller
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// Form data
|
|
286
|
+
const formData = new FormData();
|
|
287
|
+
formData.append("file", blob);
|
|
288
|
+
formData.append("name", "example");
|
|
289
|
+
|
|
290
|
+
const response = await fetchy("https://api.example.com/upload", {
|
|
291
|
+
body: formData
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
// URL-encoded form
|
|
295
|
+
const params = new URLSearchParams();
|
|
296
|
+
params.append("key", "value");
|
|
297
|
+
|
|
298
|
+
const response = await fetchy("https://api.example.com/form", {
|
|
299
|
+
body: params
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Type-Safe API Responses
|
|
304
|
+
```ts
|
|
305
|
+
interface ApiResponse<T> {
|
|
306
|
+
success: boolean;
|
|
307
|
+
data: T;
|
|
308
|
+
error?: string;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
interface Todo {
|
|
312
|
+
id: number;
|
|
313
|
+
title: string;
|
|
314
|
+
completed: boolean;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const response = await fetchyb<ApiResponse<Todo>>(
|
|
318
|
+
"https://api.example.com/todos/1",
|
|
319
|
+
"json"
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
if (response?.success) {
|
|
323
|
+
console.log(response.data.title); // Fully typed
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## License
|
|
328
|
+
|
|
329
|
+
MIT
|
package/esm/main.js
ADDED
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
export { _correctNumber, _fetchWithJitter, _fetchWithRetry, _fetchWithTimeout, _getBody, _getContentType, _getHeaders, _getNextInterval, _getOptions, _getRequestInit, _getRetryOption, _handleRedirectResponse, _isBool, _isJSONObject, _isNumber, _isPlainObject, _isString, _parseRetryAfter, _shouldNotRetry, _shouldRedirect, _throwError, _wait, DEFAULT, fetchy, fetchyb, HTTPStatusError, RedirectError, };
|
|
2
|
+
/*=============== Constant Values ===============*/
|
|
3
|
+
/**
|
|
4
|
+
* Default configuration values for fetchy.
|
|
5
|
+
* These values are used when corresponding options are not specified.
|
|
6
|
+
*/
|
|
7
|
+
const DEFAULT = {
|
|
8
|
+
timeout: 15,
|
|
9
|
+
jitter: 0,
|
|
10
|
+
interval: 3,
|
|
11
|
+
maxInterval: 30,
|
|
12
|
+
max: 3,
|
|
13
|
+
byHeader: true,
|
|
14
|
+
onError: true,
|
|
15
|
+
onErrorStatus: false,
|
|
16
|
+
userRedirect: "follow",
|
|
17
|
+
};
|
|
18
|
+
/*=============== Main Code =====================*/
|
|
19
|
+
/**
|
|
20
|
+
* Error thrown when HTTP response has a non-OK status code (4xx, 5xx).
|
|
21
|
+
* Only thrown when throwError.onErrorStatus is set to true.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* try {
|
|
26
|
+
* await fetchy("https://api.example.com/data", {
|
|
27
|
+
* throwError: { onErrorStatus: true }
|
|
28
|
+
* });
|
|
29
|
+
* } catch (error) {
|
|
30
|
+
* if (error instanceof HTTPStatusError) {
|
|
31
|
+
* console.error("HTTP error:", error.message); // e.g., "404 Not Found"
|
|
32
|
+
* }
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
class HTTPStatusError extends Error {
|
|
37
|
+
constructor(msg) {
|
|
38
|
+
super(msg);
|
|
39
|
+
this.name = "HTTPStatusError";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Error thrown when a redirect response is received and redirect option is set to "error".
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* try {
|
|
48
|
+
* await fetchy("https://example.com/redirect", {
|
|
49
|
+
* redirect: "error"
|
|
50
|
+
* });
|
|
51
|
+
* } catch (error) {
|
|
52
|
+
* if (error instanceof RedirectError) {
|
|
53
|
+
* console.error("Unexpected redirect:", error.message);
|
|
54
|
+
* }
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
class RedirectError extends Error {
|
|
59
|
+
constructor(msg) {
|
|
60
|
+
super(msg);
|
|
61
|
+
this.name = "RedirectError";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function fetchyb(url, type = "auto", options) {
|
|
65
|
+
const resp = await fetchy(url, options);
|
|
66
|
+
if (!resp || !resp.ok)
|
|
67
|
+
return null;
|
|
68
|
+
const btype = resp.headers.get("Content-Type") ?? "";
|
|
69
|
+
try {
|
|
70
|
+
if (type === "text" || (type === "auto" && btype.startsWith("text/")))
|
|
71
|
+
return await resp.text();
|
|
72
|
+
if (type === "json" || (type === "auto" && btype === "application/json"))
|
|
73
|
+
return await resp.json();
|
|
74
|
+
return await resp.bytes();
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
if (_throwError("onError", options?.throwError))
|
|
78
|
+
throw e;
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Performs an HTTP request with enhanced features like timeout, retry, and automatic header management.
|
|
84
|
+
* Returns the raw Response object or null on failure, unless throwError is configured.
|
|
85
|
+
*
|
|
86
|
+
* @param url - The URL to fetch. Can be a string, URL object, or Request object.
|
|
87
|
+
* @param options - Configuration options for the request.
|
|
88
|
+
* @returns Response object or null on failure.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* import { fetchy } from "@scirexs/fetchy";
|
|
93
|
+
*
|
|
94
|
+
* // Simple GET request
|
|
95
|
+
* const response = await fetchy("https://api.example.com/data");
|
|
96
|
+
* if (response?.ok) {
|
|
97
|
+
* const data = await response.json();
|
|
98
|
+
* }
|
|
99
|
+
*
|
|
100
|
+
* // POST request with JSON body
|
|
101
|
+
* const response = await fetchy("https://api.example.com/create", {
|
|
102
|
+
* body: { name: "John", age: 30 },
|
|
103
|
+
* bearerToken: "your-token"
|
|
104
|
+
* });
|
|
105
|
+
*
|
|
106
|
+
* // With retry and timeout
|
|
107
|
+
* const response = await fetchy("https://api.example.com/data", {
|
|
108
|
+
* timeout: 10,
|
|
109
|
+
* retry: { max: 5, interval: 2 },
|
|
110
|
+
* throwError: { onErrorStatus: true }
|
|
111
|
+
* });
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
async function fetchy(url, options) {
|
|
115
|
+
try {
|
|
116
|
+
const opts = _getOptions(options);
|
|
117
|
+
const init = _getRequestInit(options, opts.abort);
|
|
118
|
+
const resp = await _fetchWithRetry(url, init, opts);
|
|
119
|
+
if (!resp.ok && opts.onErrorStatus)
|
|
120
|
+
throw new HTTPStatusError(`${resp.status} ${resp.statusText}`.trim());
|
|
121
|
+
return resp;
|
|
122
|
+
}
|
|
123
|
+
catch (e) {
|
|
124
|
+
if (_throwError("onError", options?.throwError))
|
|
125
|
+
throw e;
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/*=============== Helper Code ===================*/
|
|
130
|
+
/**
|
|
131
|
+
* Checks if a value is a string.
|
|
132
|
+
* @internal
|
|
133
|
+
* @param v - Value to check.
|
|
134
|
+
* @returns True if the value is a string.
|
|
135
|
+
*/
|
|
136
|
+
function _isString(v) {
|
|
137
|
+
return typeof v === "string";
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Checks if a value is a number.
|
|
141
|
+
* @internal
|
|
142
|
+
* @param v - Value to check.
|
|
143
|
+
* @returns True if the value is a number.
|
|
144
|
+
*/
|
|
145
|
+
function _isNumber(v) {
|
|
146
|
+
return typeof v === "number";
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Checks if a value is a boolean.
|
|
150
|
+
* @internal
|
|
151
|
+
* @param v - Value to check.
|
|
152
|
+
* @returns True if the value is a boolean.
|
|
153
|
+
*/
|
|
154
|
+
function _isBool(v) {
|
|
155
|
+
return typeof v === "boolean";
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Checks if a value is a plain object (not array, null, or other object types).
|
|
159
|
+
* @internal
|
|
160
|
+
* @param v - Value to check.
|
|
161
|
+
* @returns True if the value is a plain object.
|
|
162
|
+
*/
|
|
163
|
+
function _isPlainObject(v) {
|
|
164
|
+
return Boolean(v &&
|
|
165
|
+
typeof v === "object" &&
|
|
166
|
+
Object.prototype.toString.call(v).slice(8, -1) === "Object" &&
|
|
167
|
+
v.constructor === Object);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Determines whether to throw an error based on configuration.
|
|
171
|
+
* @internal
|
|
172
|
+
* @param prop - The error option property to check.
|
|
173
|
+
* @param options - Error configuration or boolean flag.
|
|
174
|
+
* @returns True if error should be thrown.
|
|
175
|
+
*/
|
|
176
|
+
function _throwError(prop, options) {
|
|
177
|
+
return Boolean((options === void 0 && DEFAULT[prop]) ||
|
|
178
|
+
(typeof options === "boolean" && options) ||
|
|
179
|
+
(typeof options === "object" && (options[prop] ?? DEFAULT[prop])));
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Corrects a number to be non-negative, using default if invalid.
|
|
183
|
+
* @internal
|
|
184
|
+
* @param dflt - Default value to use if number is invalid.
|
|
185
|
+
* @param num - Number to validate.
|
|
186
|
+
* @param integer - Whether to truncate to integer.
|
|
187
|
+
* @returns Corrected number.
|
|
188
|
+
*/
|
|
189
|
+
function _correctNumber(dflt, num, integer = false) {
|
|
190
|
+
if (num === void 0 || num < 0)
|
|
191
|
+
return dflt;
|
|
192
|
+
return integer ? Math.trunc(num) : num;
|
|
193
|
+
}
|
|
194
|
+
function _getRetryOption(prop, off, options) {
|
|
195
|
+
if (_isBool(options))
|
|
196
|
+
return off;
|
|
197
|
+
if (options === void 0 || options[prop] === void 0)
|
|
198
|
+
return DEFAULT[prop];
|
|
199
|
+
if (_isNumber(options[prop]))
|
|
200
|
+
return _correctNumber(DEFAULT[prop], options[prop], prop === "max");
|
|
201
|
+
return options[prop];
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Converts FetchyOptions to internal Options format with validated values.
|
|
205
|
+
* @internal
|
|
206
|
+
* @param options - User-provided options.
|
|
207
|
+
* @returns Normalized internal options.
|
|
208
|
+
*/
|
|
209
|
+
function _getOptions(options) {
|
|
210
|
+
const timeout = _correctNumber(DEFAULT.timeout, options?.timeout);
|
|
211
|
+
return {
|
|
212
|
+
timeout,
|
|
213
|
+
jitter: _correctNumber(DEFAULT.jitter, options?.jitter),
|
|
214
|
+
interval: _getRetryOption("interval", 0, options?.retry),
|
|
215
|
+
maxInterval: _getRetryOption("maxInterval", 0, options?.retry),
|
|
216
|
+
max: _getRetryOption("max", 0, options?.retry),
|
|
217
|
+
byHeader: _getRetryOption("byHeader", false, options?.retry),
|
|
218
|
+
onErrorStatus: _throwError("onErrorStatus", options?.throwError),
|
|
219
|
+
abort: options?.abort ?? (timeout ? new AbortController() : undefined),
|
|
220
|
+
userRedirect: options?.redirect ?? DEFAULT.userRedirect,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Converts FetchyOptions to standard RequestInit format.
|
|
225
|
+
* @internal
|
|
226
|
+
* @param options - User-provided options.
|
|
227
|
+
* @param optsAbort - AbortController for timeout handling.
|
|
228
|
+
* @returns Standard RequestInit object.
|
|
229
|
+
*/
|
|
230
|
+
function _getRequestInit(options, optsAbort) {
|
|
231
|
+
const { body, timeout, retry, bearerToken, throwError, jitter, abort, redirect, ...rest } = options ?? {};
|
|
232
|
+
return {
|
|
233
|
+
method: body === void 0 ? "GET" : "POST",
|
|
234
|
+
headers: _getHeaders(options),
|
|
235
|
+
...(redirect && { redirect: redirect === "error" ? "manual" : redirect }),
|
|
236
|
+
...(optsAbort && { signal: optsAbort.signal }),
|
|
237
|
+
...(body && { body: _getBody(body) }),
|
|
238
|
+
...rest,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Converts FetchyBody to standard BodyInit format.
|
|
243
|
+
* @internal
|
|
244
|
+
* @param body - Body content to convert.
|
|
245
|
+
* @returns Standard BodyInit or undefined.
|
|
246
|
+
*/
|
|
247
|
+
function _getBody(body) {
|
|
248
|
+
return _isJSONObject(body) ? JSON.stringify(body) : body;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Checks if a value should be treated as JSON object for serialization.
|
|
252
|
+
* @internal
|
|
253
|
+
* @param arg - Value to check.
|
|
254
|
+
* @returns True if value should be JSON stringified.
|
|
255
|
+
*/
|
|
256
|
+
function _isJSONObject(arg) {
|
|
257
|
+
return Boolean(arg === null || _isNumber(arg) || _isBool(arg) || Array.isArray(arg) || _isPlainObject(arg));
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Constructs request headers with automatic Content-Type and Authorization.
|
|
261
|
+
* @internal
|
|
262
|
+
* @param options - User-provided options.
|
|
263
|
+
* @returns Headers object.
|
|
264
|
+
*/
|
|
265
|
+
function _getHeaders(options) {
|
|
266
|
+
const type = _getContentType(options?.body);
|
|
267
|
+
return {
|
|
268
|
+
"Accept": "application/json, text/plain",
|
|
269
|
+
...(type && { "Content-Type": type }),
|
|
270
|
+
...(options?.bearerToken && { "Authorization": `Bearer ${options.bearerToken}` }),
|
|
271
|
+
...options?.headers,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Determines Content-Type header based on body type.
|
|
276
|
+
* @internal
|
|
277
|
+
* @param body - Request body content.
|
|
278
|
+
* @returns Content-Type string or undefined.
|
|
279
|
+
*/
|
|
280
|
+
function _getContentType(body) {
|
|
281
|
+
if (body === void 0 || body instanceof FormData)
|
|
282
|
+
return;
|
|
283
|
+
if (_isString(body))
|
|
284
|
+
return "text/plain";
|
|
285
|
+
if (body instanceof URLSearchParams)
|
|
286
|
+
return "application/x-www-form-urlencoded";
|
|
287
|
+
if (_isJSONObject(body))
|
|
288
|
+
return "application/json";
|
|
289
|
+
return "application/octet-stream";
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Waits for specified seconds with optional randomization.
|
|
293
|
+
* @internal
|
|
294
|
+
* @param sec - Seconds to wait.
|
|
295
|
+
* @param random - Whether to randomize the delay.
|
|
296
|
+
*/
|
|
297
|
+
async function _wait(sec, random = true) {
|
|
298
|
+
if (sec <= 0)
|
|
299
|
+
return;
|
|
300
|
+
const delay = Math.trunc((random ? Math.random() : 1) * sec * 1000);
|
|
301
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Checks if response is a redirect (3xx status).
|
|
305
|
+
* @internal
|
|
306
|
+
* @param resp - Response to check.
|
|
307
|
+
* @returns True if response is a redirect.
|
|
308
|
+
*/
|
|
309
|
+
function _shouldRedirect(resp) {
|
|
310
|
+
return resp.status < 400 && resp.status >= 300;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Determines if retry should stop based on conditions and waits if continuing.
|
|
314
|
+
* @internal
|
|
315
|
+
* @param count - Current retry attempt number.
|
|
316
|
+
* @param opts - Internal options.
|
|
317
|
+
* @param resp - Response from previous attempt.
|
|
318
|
+
* @returns True if retry should stop.
|
|
319
|
+
*/
|
|
320
|
+
async function _shouldNotRetry(count, opts, resp) {
|
|
321
|
+
if (count >= opts.max || resp?.ok)
|
|
322
|
+
return true;
|
|
323
|
+
if (resp && _shouldRedirect(resp)) {
|
|
324
|
+
if (opts.userRedirect === "manual")
|
|
325
|
+
return true;
|
|
326
|
+
if (opts.userRedirect === "error") {
|
|
327
|
+
opts.max = 0;
|
|
328
|
+
throw new RedirectError(`Received redirect response: ${resp.status}`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
const interval = _getNextInterval(count, opts, resp);
|
|
332
|
+
if (interval > opts.maxInterval)
|
|
333
|
+
return true;
|
|
334
|
+
await _wait(interval, false);
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Calculates next retry interval using exponential backoff or Retry-After header.
|
|
339
|
+
* @internal
|
|
340
|
+
* @param count - Current retry attempt number.
|
|
341
|
+
* @param opts - Internal options.
|
|
342
|
+
* @param resp - Response from previous attempt.
|
|
343
|
+
* @returns Next retry interval in seconds.
|
|
344
|
+
*/
|
|
345
|
+
function _getNextInterval(count, opts, resp) {
|
|
346
|
+
return opts.byHeader && resp
|
|
347
|
+
? Math.max(_parseRetryAfter(resp.headers.get("Retry-After")?.trim() ?? ""), opts.interval)
|
|
348
|
+
: Math.min(Math.pow(Math.max(1, opts.interval), count), opts.maxInterval);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Parses Retry-After header value to seconds.
|
|
352
|
+
* @internal
|
|
353
|
+
* @param value - Retry-After header value (seconds or HTTP date).
|
|
354
|
+
* @returns Retry delay in seconds, or Infinity if invalid.
|
|
355
|
+
*/
|
|
356
|
+
function _parseRetryAfter(value) {
|
|
357
|
+
if (!value)
|
|
358
|
+
return Infinity;
|
|
359
|
+
const sec1 = Number.parseInt(value, 10);
|
|
360
|
+
if (!Number.isNaN(sec1))
|
|
361
|
+
return sec1;
|
|
362
|
+
const sec2 = Math.ceil((new Date(value).getTime() - Date.now()) / 1000);
|
|
363
|
+
if (!Number.isNaN(sec2))
|
|
364
|
+
return sec2;
|
|
365
|
+
return Infinity;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Updates URL and method for redirect responses.
|
|
369
|
+
* @internal
|
|
370
|
+
* @param url - Original request URL.
|
|
371
|
+
* @param init - Request initialization object.
|
|
372
|
+
* @param resp - Redirect response.
|
|
373
|
+
* @returns Updated URL for next request.
|
|
374
|
+
*/
|
|
375
|
+
function _handleRedirectResponse(url, init, resp) {
|
|
376
|
+
if (!resp.redirected)
|
|
377
|
+
return url;
|
|
378
|
+
if (resp.status === 303)
|
|
379
|
+
init.method = "GET";
|
|
380
|
+
return url instanceof Request ? new Request(resp.url, url) : resp.url;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Executes fetch with retry logic and exponential backoff.
|
|
384
|
+
* @internal
|
|
385
|
+
* @param url - Request URL.
|
|
386
|
+
* @param init - Request initialization object.
|
|
387
|
+
* @param opts - Internal options.
|
|
388
|
+
* @returns Response from successful request.
|
|
389
|
+
*/
|
|
390
|
+
async function _fetchWithRetry(url, init, opts) {
|
|
391
|
+
if (!opts.max)
|
|
392
|
+
return await _fetchWithTimeout(url, init, opts);
|
|
393
|
+
for (let i = 1; i <= opts.max; i++) {
|
|
394
|
+
try {
|
|
395
|
+
const resp = await (opts.jitter ? _fetchWithJitter(url, init, opts) : _fetchWithTimeout(url, init, opts));
|
|
396
|
+
if (await _shouldNotRetry(i, opts, resp))
|
|
397
|
+
return resp;
|
|
398
|
+
url = _handleRedirectResponse(url, init, resp);
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
catch (e) {
|
|
402
|
+
if (await _shouldNotRetry(i, opts))
|
|
403
|
+
throw e;
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
throw new Error("never reach");
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Executes fetch with initial jitter delay.
|
|
411
|
+
* @internal
|
|
412
|
+
* @param url - Request URL.
|
|
413
|
+
* @param init - Request initialization object.
|
|
414
|
+
* @param opts - Internal options.
|
|
415
|
+
* @returns Response from request.
|
|
416
|
+
*/
|
|
417
|
+
async function _fetchWithJitter(url, init, opts) {
|
|
418
|
+
await _wait(opts.jitter);
|
|
419
|
+
return await _fetchWithTimeout(url, init, opts);
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Executes fetch with timeout handling.
|
|
423
|
+
* @internal
|
|
424
|
+
* @param url - Request URL.
|
|
425
|
+
* @param init - Request initialization object.
|
|
426
|
+
* @param opts - Internal options.
|
|
427
|
+
* @returns Response from request.
|
|
428
|
+
*/
|
|
429
|
+
async function _fetchWithTimeout(url, init, opts) {
|
|
430
|
+
const req = url instanceof Request ? url.clone() : url;
|
|
431
|
+
const id = opts.abort ? setTimeout(() => opts.abort?.abort("timeout"), opts.timeout * 1000) : 0;
|
|
432
|
+
try {
|
|
433
|
+
return await fetch(req, init);
|
|
434
|
+
}
|
|
435
|
+
catch (e) {
|
|
436
|
+
throw e;
|
|
437
|
+
}
|
|
438
|
+
finally {
|
|
439
|
+
clearTimeout(id);
|
|
440
|
+
}
|
|
441
|
+
}
|
package/esm/mod.js
ADDED
package/esm/package.json
ADDED
package/esm/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@scirexs/fetchy",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A light fetch wrapper.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"fetch",
|
|
7
|
+
"typescript"
|
|
8
|
+
],
|
|
9
|
+
"author": "scirexs",
|
|
10
|
+
"homepage": "https://github.com/scirexs/fetchy#readme",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/scirexs/fetchy.git"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/scirexs/fetchy/issues"
|
|
18
|
+
},
|
|
19
|
+
"module": "./esm/mod.js",
|
|
20
|
+
"types": "./types/mod.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"import": {
|
|
24
|
+
"types": "./types/mod.d.ts",
|
|
25
|
+
"default": "./esm/mod.js"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"scripts": {},
|
|
30
|
+
"type": "module",
|
|
31
|
+
"sideEffects": false,
|
|
32
|
+
"_generatedBy": "dnt@dev"
|
|
33
|
+
}
|
package/types/main.d.ts
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
export { _correctNumber, _fetchWithJitter, _fetchWithRetry, _fetchWithTimeout, _getBody, _getContentType, _getHeaders, _getNextInterval, _getOptions, _getRequestInit, _getRetryOption, _handleRedirectResponse, _isBool, _isJSONObject, _isNumber, _isPlainObject, _isString, _parseRetryAfter, _shouldNotRetry, _shouldRedirect, _throwError, _wait, DEFAULT, fetchy, fetchyb, HTTPStatusError, RedirectError, };
|
|
2
|
+
import type { ErrorOptions, FetchyBody, FetchyOptions, RetryOptions } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Default configuration values for fetchy.
|
|
5
|
+
* These values are used when corresponding options are not specified.
|
|
6
|
+
*/
|
|
7
|
+
declare const DEFAULT: Options;
|
|
8
|
+
/**
|
|
9
|
+
* Valid input types for fetch requests.
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
type Input = string | URL | Request;
|
|
13
|
+
/**
|
|
14
|
+
* Internal normalized options used throughout the fetch process.
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
interface Options {
|
|
18
|
+
timeout: number;
|
|
19
|
+
jitter: number;
|
|
20
|
+
interval: number;
|
|
21
|
+
maxInterval: number;
|
|
22
|
+
max: number;
|
|
23
|
+
byHeader: boolean;
|
|
24
|
+
onError?: boolean;
|
|
25
|
+
onErrorStatus: boolean;
|
|
26
|
+
abort?: AbortController;
|
|
27
|
+
userRedirect: "follow" | "error" | "manual";
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Error thrown when HTTP response has a non-OK status code (4xx, 5xx).
|
|
31
|
+
* Only thrown when throwError.onErrorStatus is set to true.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* try {
|
|
36
|
+
* await fetchy("https://api.example.com/data", {
|
|
37
|
+
* throwError: { onErrorStatus: true }
|
|
38
|
+
* });
|
|
39
|
+
* } catch (error) {
|
|
40
|
+
* if (error instanceof HTTPStatusError) {
|
|
41
|
+
* console.error("HTTP error:", error.message); // e.g., "404 Not Found"
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
declare class HTTPStatusError extends Error {
|
|
47
|
+
constructor(msg: string);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Error thrown when a redirect response is received and redirect option is set to "error".
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* try {
|
|
55
|
+
* await fetchy("https://example.com/redirect", {
|
|
56
|
+
* redirect: "error"
|
|
57
|
+
* });
|
|
58
|
+
* } catch (error) {
|
|
59
|
+
* if (error instanceof RedirectError) {
|
|
60
|
+
* console.error("Unexpected redirect:", error.message);
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
declare class RedirectError extends Error {
|
|
66
|
+
constructor(msg: string);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Performs an HTTP request and automatically parses the response body based on Content-Type or specified type.
|
|
70
|
+
* Returns null if the request fails or response is not OK, unless throwError is configured.
|
|
71
|
+
*
|
|
72
|
+
* @param url - The URL to fetch. Can be a string, URL object, or Request object.
|
|
73
|
+
* @param type - The expected response type. "auto" detects type from Content-Type header.
|
|
74
|
+
* @param options - Configuration options for the request.
|
|
75
|
+
* @returns Parsed response body or null on failure.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { fetchyb } from "@scirexs/fetchy";
|
|
80
|
+
*
|
|
81
|
+
* // Automatic type detection
|
|
82
|
+
* const data = await fetchyb("https://api.example.com/user");
|
|
83
|
+
*
|
|
84
|
+
* // Explicit JSON parsing with type assertion
|
|
85
|
+
* interface User { id: number; name: string; }
|
|
86
|
+
* const user = await fetchyb<User>("https://api.example.com/user", "json");
|
|
87
|
+
*
|
|
88
|
+
* // Text response
|
|
89
|
+
* const text = await fetchyb("https://example.com/page", "text");
|
|
90
|
+
*
|
|
91
|
+
* // Binary data
|
|
92
|
+
* const bytes = await fetchyb("https://example.com/image.png", "bytes");
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
declare function fetchyb(url: Input, type: "text", options?: FetchyOptions): Promise<string | null>;
|
|
96
|
+
declare function fetchyb<T>(url: Input, type: "json", options?: FetchyOptions): Promise<T | null>;
|
|
97
|
+
declare function fetchyb(url: Input, type: "bytes", options?: FetchyOptions): Promise<Uint8Array | null>;
|
|
98
|
+
declare function fetchyb<T>(url: Input, type?: "auto", options?: FetchyOptions): Promise<T | string | Uint8Array | null>;
|
|
99
|
+
/**
|
|
100
|
+
* Performs an HTTP request with enhanced features like timeout, retry, and automatic header management.
|
|
101
|
+
* Returns the raw Response object or null on failure, unless throwError is configured.
|
|
102
|
+
*
|
|
103
|
+
* @param url - The URL to fetch. Can be a string, URL object, or Request object.
|
|
104
|
+
* @param options - Configuration options for the request.
|
|
105
|
+
* @returns Response object or null on failure.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* import { fetchy } from "@scirexs/fetchy";
|
|
110
|
+
*
|
|
111
|
+
* // Simple GET request
|
|
112
|
+
* const response = await fetchy("https://api.example.com/data");
|
|
113
|
+
* if (response?.ok) {
|
|
114
|
+
* const data = await response.json();
|
|
115
|
+
* }
|
|
116
|
+
*
|
|
117
|
+
* // POST request with JSON body
|
|
118
|
+
* const response = await fetchy("https://api.example.com/create", {
|
|
119
|
+
* body: { name: "John", age: 30 },
|
|
120
|
+
* bearerToken: "your-token"
|
|
121
|
+
* });
|
|
122
|
+
*
|
|
123
|
+
* // With retry and timeout
|
|
124
|
+
* const response = await fetchy("https://api.example.com/data", {
|
|
125
|
+
* timeout: 10,
|
|
126
|
+
* retry: { max: 5, interval: 2 },
|
|
127
|
+
* throwError: { onErrorStatus: true }
|
|
128
|
+
* });
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
declare function fetchy(url: Input, options?: FetchyOptions): Promise<Response | null>;
|
|
132
|
+
/**
|
|
133
|
+
* Checks if a value is a string.
|
|
134
|
+
* @internal
|
|
135
|
+
* @param v - Value to check.
|
|
136
|
+
* @returns True if the value is a string.
|
|
137
|
+
*/
|
|
138
|
+
declare function _isString(v: unknown): v is string;
|
|
139
|
+
/**
|
|
140
|
+
* Checks if a value is a number.
|
|
141
|
+
* @internal
|
|
142
|
+
* @param v - Value to check.
|
|
143
|
+
* @returns True if the value is a number.
|
|
144
|
+
*/
|
|
145
|
+
declare function _isNumber(v: unknown): v is number;
|
|
146
|
+
/**
|
|
147
|
+
* Checks if a value is a boolean.
|
|
148
|
+
* @internal
|
|
149
|
+
* @param v - Value to check.
|
|
150
|
+
* @returns True if the value is a boolean.
|
|
151
|
+
*/
|
|
152
|
+
declare function _isBool(v: unknown): v is boolean;
|
|
153
|
+
/**
|
|
154
|
+
* Checks if a value is a plain object (not array, null, or other object types).
|
|
155
|
+
* @internal
|
|
156
|
+
* @param v - Value to check.
|
|
157
|
+
* @returns True if the value is a plain object.
|
|
158
|
+
*/
|
|
159
|
+
declare function _isPlainObject(v: unknown): v is object;
|
|
160
|
+
/**
|
|
161
|
+
* Determines whether to throw an error based on configuration.
|
|
162
|
+
* @internal
|
|
163
|
+
* @param prop - The error option property to check.
|
|
164
|
+
* @param options - Error configuration or boolean flag.
|
|
165
|
+
* @returns True if error should be thrown.
|
|
166
|
+
*/
|
|
167
|
+
declare function _throwError(prop: keyof ErrorOptions, options?: ErrorOptions | boolean): boolean;
|
|
168
|
+
/**
|
|
169
|
+
* Corrects a number to be non-negative, using default if invalid.
|
|
170
|
+
* @internal
|
|
171
|
+
* @param dflt - Default value to use if number is invalid.
|
|
172
|
+
* @param num - Number to validate.
|
|
173
|
+
* @param integer - Whether to truncate to integer.
|
|
174
|
+
* @returns Corrected number.
|
|
175
|
+
*/
|
|
176
|
+
declare function _correctNumber(dflt: number, num?: number, integer?: boolean): number;
|
|
177
|
+
/**
|
|
178
|
+
* Gets retry option value from configuration with fallback to default.
|
|
179
|
+
* @internal
|
|
180
|
+
* @param prop - The retry option property to get.
|
|
181
|
+
* @param off - Fallback value when retry is disabled.
|
|
182
|
+
* @param options - Retry configuration.
|
|
183
|
+
* @returns The retry option value.
|
|
184
|
+
*/
|
|
185
|
+
declare function _getRetryOption(prop: keyof RetryOptions, off: number, options?: RetryOptions | false): number;
|
|
186
|
+
declare function _getRetryOption(prop: keyof RetryOptions, off: boolean, options?: RetryOptions | false): boolean;
|
|
187
|
+
/**
|
|
188
|
+
* Converts FetchyOptions to internal Options format with validated values.
|
|
189
|
+
* @internal
|
|
190
|
+
* @param options - User-provided options.
|
|
191
|
+
* @returns Normalized internal options.
|
|
192
|
+
*/
|
|
193
|
+
declare function _getOptions(options?: FetchyOptions): Options;
|
|
194
|
+
/**
|
|
195
|
+
* Converts FetchyOptions to standard RequestInit format.
|
|
196
|
+
* @internal
|
|
197
|
+
* @param options - User-provided options.
|
|
198
|
+
* @param optsAbort - AbortController for timeout handling.
|
|
199
|
+
* @returns Standard RequestInit object.
|
|
200
|
+
*/
|
|
201
|
+
declare function _getRequestInit(options?: FetchyOptions, optsAbort?: AbortController): RequestInit;
|
|
202
|
+
/**
|
|
203
|
+
* Converts FetchyBody to standard BodyInit format.
|
|
204
|
+
* @internal
|
|
205
|
+
* @param body - Body content to convert.
|
|
206
|
+
* @returns Standard BodyInit or undefined.
|
|
207
|
+
*/
|
|
208
|
+
declare function _getBody(body: FetchyBody): BodyInit | undefined;
|
|
209
|
+
/**
|
|
210
|
+
* Checks if a value should be treated as JSON object for serialization.
|
|
211
|
+
* @internal
|
|
212
|
+
* @param arg - Value to check.
|
|
213
|
+
* @returns True if value should be JSON stringified.
|
|
214
|
+
*/
|
|
215
|
+
declare function _isJSONObject(arg?: FetchyBody): boolean;
|
|
216
|
+
/**
|
|
217
|
+
* Constructs request headers with automatic Content-Type and Authorization.
|
|
218
|
+
* @internal
|
|
219
|
+
* @param options - User-provided options.
|
|
220
|
+
* @returns Headers object.
|
|
221
|
+
*/
|
|
222
|
+
declare function _getHeaders(options?: FetchyOptions): HeadersInit;
|
|
223
|
+
/**
|
|
224
|
+
* Determines Content-Type header based on body type.
|
|
225
|
+
* @internal
|
|
226
|
+
* @param body - Request body content.
|
|
227
|
+
* @returns Content-Type string or undefined.
|
|
228
|
+
*/
|
|
229
|
+
declare function _getContentType(body?: FetchyBody): string | undefined;
|
|
230
|
+
/**
|
|
231
|
+
* Waits for specified seconds with optional randomization.
|
|
232
|
+
* @internal
|
|
233
|
+
* @param sec - Seconds to wait.
|
|
234
|
+
* @param random - Whether to randomize the delay.
|
|
235
|
+
*/
|
|
236
|
+
declare function _wait(sec: number, random?: boolean): Promise<void>;
|
|
237
|
+
/**
|
|
238
|
+
* Checks if response is a redirect (3xx status).
|
|
239
|
+
* @internal
|
|
240
|
+
* @param resp - Response to check.
|
|
241
|
+
* @returns True if response is a redirect.
|
|
242
|
+
*/
|
|
243
|
+
declare function _shouldRedirect(resp: Response): boolean;
|
|
244
|
+
/**
|
|
245
|
+
* Determines if retry should stop based on conditions and waits if continuing.
|
|
246
|
+
* @internal
|
|
247
|
+
* @param count - Current retry attempt number.
|
|
248
|
+
* @param opts - Internal options.
|
|
249
|
+
* @param resp - Response from previous attempt.
|
|
250
|
+
* @returns True if retry should stop.
|
|
251
|
+
*/
|
|
252
|
+
declare function _shouldNotRetry(count: number, opts: Options, resp?: Response): Promise<boolean>;
|
|
253
|
+
/**
|
|
254
|
+
* Calculates next retry interval using exponential backoff or Retry-After header.
|
|
255
|
+
* @internal
|
|
256
|
+
* @param count - Current retry attempt number.
|
|
257
|
+
* @param opts - Internal options.
|
|
258
|
+
* @param resp - Response from previous attempt.
|
|
259
|
+
* @returns Next retry interval in seconds.
|
|
260
|
+
*/
|
|
261
|
+
declare function _getNextInterval(count: number, opts: Options, resp?: Response): number;
|
|
262
|
+
/**
|
|
263
|
+
* Parses Retry-After header value to seconds.
|
|
264
|
+
* @internal
|
|
265
|
+
* @param value - Retry-After header value (seconds or HTTP date).
|
|
266
|
+
* @returns Retry delay in seconds, or Infinity if invalid.
|
|
267
|
+
*/
|
|
268
|
+
declare function _parseRetryAfter(value: string): number;
|
|
269
|
+
/**
|
|
270
|
+
* Updates URL and method for redirect responses.
|
|
271
|
+
* @internal
|
|
272
|
+
* @param url - Original request URL.
|
|
273
|
+
* @param init - Request initialization object.
|
|
274
|
+
* @param resp - Redirect response.
|
|
275
|
+
* @returns Updated URL for next request.
|
|
276
|
+
*/
|
|
277
|
+
declare function _handleRedirectResponse(url: Input, init: RequestInit, resp: Response): Input;
|
|
278
|
+
/**
|
|
279
|
+
* Executes fetch with retry logic and exponential backoff.
|
|
280
|
+
* @internal
|
|
281
|
+
* @param url - Request URL.
|
|
282
|
+
* @param init - Request initialization object.
|
|
283
|
+
* @param opts - Internal options.
|
|
284
|
+
* @returns Response from successful request.
|
|
285
|
+
*/
|
|
286
|
+
declare function _fetchWithRetry(url: Input, init: RequestInit, opts: Options): Promise<Response>;
|
|
287
|
+
/**
|
|
288
|
+
* Executes fetch with initial jitter delay.
|
|
289
|
+
* @internal
|
|
290
|
+
* @param url - Request URL.
|
|
291
|
+
* @param init - Request initialization object.
|
|
292
|
+
* @param opts - Internal options.
|
|
293
|
+
* @returns Response from request.
|
|
294
|
+
*/
|
|
295
|
+
declare function _fetchWithJitter(url: Input, init: RequestInit, opts: Options): Promise<Response>;
|
|
296
|
+
/**
|
|
297
|
+
* Executes fetch with timeout handling.
|
|
298
|
+
* @internal
|
|
299
|
+
* @param url - Request URL.
|
|
300
|
+
* @param init - Request initialization object.
|
|
301
|
+
* @param opts - Internal options.
|
|
302
|
+
* @returns Response from request.
|
|
303
|
+
*/
|
|
304
|
+
declare function _fetchWithTimeout(url: Input, init: RequestInit, opts: Options): Promise<Response>;
|
|
305
|
+
//# sourceMappingURL=main.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
|
package/types/mod.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exports main functions and types for external.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
export { fetchy, fetchyb, HTTPStatusError, RedirectError } from "./main.js";
|
|
6
|
+
export type { ErrorOptions, FetchyBody, FetchyOptions, JSONValue, RetryOptions } from "./types.js";
|
|
7
|
+
//# sourceMappingURL=mod.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC5E,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
|
package/types/types.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a JSON-compatible value that can be serialized and deserialized.
|
|
3
|
+
* This type includes primitives, arrays, and plain objects with string keys.
|
|
4
|
+
*/
|
|
5
|
+
export type JSONValue = string | number | boolean | null | JSONValue[] | {
|
|
6
|
+
[key: string]: JSONValue;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Represents the body content that can be sent in a fetch request.
|
|
10
|
+
* Includes JSON-compatible values and standard BodyInit types except ReadableStream.
|
|
11
|
+
*/
|
|
12
|
+
export type FetchyBody = JSONValue | Exclude<BodyInit, ReadableStream>;
|
|
13
|
+
/**
|
|
14
|
+
* Configuration options for fetchy requests.
|
|
15
|
+
* Extends standard RequestInit but provides additional features like timeout, retry, and error handling.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { fetchy } from "@scirexs/fetchy";
|
|
20
|
+
*
|
|
21
|
+
* const response = await fetchy("https://api.example.com/data", {
|
|
22
|
+
* method: "POST",
|
|
23
|
+
* body: { key: "value" },
|
|
24
|
+
* timeout: 10,
|
|
25
|
+
* retry: { max: 3, interval: 2 },
|
|
26
|
+
* bearerToken: "your-token-here"
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export interface FetchyOptions extends Omit<RequestInit, "body" | "signal"> {
|
|
31
|
+
/** Request body content. Automatically serializes JSON objects. */
|
|
32
|
+
body?: FetchyBody;
|
|
33
|
+
/** Request timeout in seconds. Default is 15 seconds. */
|
|
34
|
+
timeout?: number;
|
|
35
|
+
/** Retry configuration. Set to false to disable retry functionality. */
|
|
36
|
+
retry?: RetryOptions | false;
|
|
37
|
+
/** Bearer token for Authorization header. Automatically adds "Bearer " prefix. */
|
|
38
|
+
bearerToken?: string;
|
|
39
|
+
/** Error throwing behavior configuration. Set to true to throw all errors. */
|
|
40
|
+
throwError?: ErrorOptions | boolean;
|
|
41
|
+
/** Initial jitter delay in seconds before sending the request. Adds randomness to prevent thundering herd. */
|
|
42
|
+
jitter?: number;
|
|
43
|
+
/** AbortController for manual request cancellation. If not provided, an internal controller is created for timeout. */
|
|
44
|
+
abort?: AbortController;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Configuration options for retry behavior.
|
|
48
|
+
* Supports exponential backoff and respects Retry-After headers.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* const retryOptions: RetryOptions = {
|
|
53
|
+
* interval: 3,
|
|
54
|
+
* maxInterval: 30,
|
|
55
|
+
* max: 5,
|
|
56
|
+
* byHeader: true
|
|
57
|
+
* };
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export interface RetryOptions {
|
|
61
|
+
/** Base interval in seconds between retries. Used for exponential backoff calculation. Default is 3 seconds. */
|
|
62
|
+
interval?: number;
|
|
63
|
+
/** Maximum interval in seconds between retries. Caps the exponential backoff. Default is 30 seconds. */
|
|
64
|
+
maxInterval?: number;
|
|
65
|
+
/** Maximum number of retry attempts. Default is 3. */
|
|
66
|
+
max?: number;
|
|
67
|
+
/** Whether to respect Retry-After header from response. Default is true. */
|
|
68
|
+
byHeader?: boolean;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Configuration options for error throwing behavior.
|
|
72
|
+
* Allows fine-grained control over which errors should be thrown vs. returned as null.
|
|
73
|
+
*/
|
|
74
|
+
export interface ErrorOptions {
|
|
75
|
+
/** Whether to throw errors during response parsing (e.g., JSON parsing errors). Default is true. */
|
|
76
|
+
onError?: boolean;
|
|
77
|
+
/** Whether to throw HTTPStatusError for non-OK status codes (4xx, 5xx). Default is false. */
|
|
78
|
+
onErrorStatus?: boolean;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtG;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;AAEvE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzE,mEAAmE;IACnE,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,KAAK,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IAC7B,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC;IACpC,8GAA8G;IAC9G,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uHAAuH;IACvH,KAAK,CAAC,EAAE,eAAe,CAAC;CACzB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,YAAY;IAC3B,gHAAgH;IAChH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wGAAwG;IACxG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,oGAAoG;IACpG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6FAA6F;IAC7F,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB"}
|