@scirexs/fetchy 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,9 +15,10 @@ A lightweight, type-safe fetch wrapper with built-in retry logic, timeout handli
15
15
  - **Type-Safe** - Full TypeScript support with generic type inference
16
16
  - **Bearer Token Helper** - Built-in Authorization header management
17
17
  - **Jitter Support** - Prevent thundering herd with randomized delays
18
- - **Auto Body Parsing** - Automatic JSON serialization and Content-Type detection
18
+ - **Automatic Body Parsing** - Automatic JSON serialization and Content-Type detection
19
19
 
20
20
  ## Installation
21
+
21
22
  ```bash
22
23
  # npm
23
24
  npm install @scirexs/fetchy
@@ -27,6 +28,7 @@ deno add jsr:@scirexs/fetchy
27
28
  ```
28
29
 
29
30
  ## Quick Start
31
+
30
32
  ```ts
31
33
  import { fetchy, fetchyb } from "@scirexs/fetchy";
32
34
 
@@ -52,20 +54,23 @@ console.log(user?.name);
52
54
  Performs an HTTP request and returns the raw Response object.
53
55
 
54
56
  #### Parameters
55
- - `url`: `string | URL | Request` - The request URL
57
+
58
+ - `url`: `string | URL | Request | null` - The request URL
56
59
  - `options`: `FetchyOptions` (optional) - Configuration options
57
60
 
58
61
  #### Returns
59
- `Promise<Response | null>`
62
+
63
+ `Promise<Response>`; If `onError.onNative` is configured as `false`, returns `Promise<Response | null>`
60
64
 
61
65
  #### Example
66
+
62
67
  ```ts
63
68
  const response = await fetchy("https://api.example.com/data", {
64
69
  method: "POST",
65
70
  body: { key: "value" },
66
71
  timeout: 10,
67
- retry: { max: 3, interval: 2 },
68
- bearerToken: "your-token-here"
72
+ retry: { maxAttempts: 3, interval: 2 },
73
+ bearer: "your-token-here"
69
74
  });
70
75
 
71
76
  if (response?.ok) {
@@ -78,14 +83,17 @@ if (response?.ok) {
78
83
  Performs an HTTP request and automatically parses the response body.
79
84
 
80
85
  #### Parameters
81
- - `url`: `string | URL | Request` - The request URL
86
+
87
+ - `url`: `string | URL | Request | null` - The request URL
82
88
  - `type`: `"text" | "json" | "bytes" | "auto"` (default: `"auto"`) - Response parsing type
83
89
  - `options`: `FetchyOptions` (optional) - Configuration options
84
90
 
85
91
  #### Returns
86
- `Promise<T | string | Uint8Array | null>`
92
+
93
+ `Promise<T | string | Uint8Array>`; If `onError.onNative` is configured as `false`, returns `Promise<T | string | Uint8Array | null>`
87
94
 
88
95
  #### Example
96
+
89
97
  ```ts
90
98
  // Automatic type detection from Content-Type header
91
99
  const data = await fetchyb("https://api.example.com/data");
@@ -105,50 +113,47 @@ const html = await fetchyb("https://example.com", "text");
105
113
  const image = await fetchyb("https://example.com/image.png", "bytes");
106
114
  ```
107
115
 
108
- ## Configurations
116
+ ## Configuration
109
117
 
110
118
  ### API Options
111
119
 
112
120
  #### `FetchyOptions`
113
121
 
114
122
  ```ts
115
- interface FetchyOptions {
123
+ interface FetchyOptions extends RequestInit {
116
124
  // Standard fetch options (method, headers, etc.)
117
125
  method?: string;
118
126
  headers?: HeadersInit;
119
127
 
120
- // Request body (auto-serializes JSON, ReadableStream is NOT supported)
128
+ // Request body (auto-serializes JSON; ReadableStream is NOT supported)
121
129
  // type JSONValue = string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue };
122
130
  body?: JSONValue | FormData | URLSearchParams | Blob | ArrayBuffer | string;
123
131
 
124
132
  // Timeout in seconds (default: 15)
125
- timeout?: number;
133
+ timeout?: number; // Set to 0 to disable timeout
126
134
 
127
135
  // Retry configuration
128
136
  retry?: {
129
- max?: number; // Max retry attempts (default: 3)
130
- interval?: number; // Base interval in seconds (default: 3)
131
- maxInterval?: number; // Max interval cap (default: 30)
132
- byHeader?: boolean; // Respect Retry-After header (default: true)
137
+ maxAttempts?: number; // Maximum retry attempts (default: 3)
138
+ interval?: number; // Base interval in seconds (default: 3)
139
+ maxInterval?: number; // Maximum interval cap in seconds (default: 30)
140
+ retryAfter?: boolean; // Respect Retry-After header (default: true)
133
141
  } | false; // Set to false to disable retry
134
142
 
135
- // Bearer token (auto-adds "Bearer " prefix)
136
- bearerToken?: string;
143
+ // Bearer token (automatically adds "Bearer " prefix)
144
+ bearer?: string;
137
145
 
138
146
  // Error throwing behavior
139
- throwError?: {
140
- onError?: boolean; // Throw on native errors (default: true)
141
- onErrorStatus?: boolean; // Throw on 4xx/5xx status (default: false)
142
- } | boolean; // Set to true to throw all errors
147
+ onError?: {
148
+ onNative?: boolean; // Throw on native errors (default: true)
149
+ onStatus?: boolean; // Throw on 4xx/5xx status (default: false)
150
+ } | boolean; // Set to true to throw on all errors
143
151
 
144
152
  // Initial jitter delay in seconds
145
- jitter?: number;
146
-
147
- // Manual abort controller (if timeout occur, reason is set to "timeout")
148
- abort?: AbortController;
149
-
150
- // Redirect behavior
151
- redirect?: "follow" | "error" | "manual";
153
+ delay?: number;
154
+
155
+ // URL for fetch (allows reusing FetchyOptions as preset configuration)
156
+ url?: string | URL;
152
157
  }
153
158
  ```
154
159
 
@@ -156,63 +161,65 @@ interface FetchyOptions {
156
161
 
157
162
  ```ts
158
163
  {
159
- timeout: 15, // 15 seconds
160
- jitter: 0, // No jitter
164
+ timeout: 15, // 15 seconds
165
+ delay: 0, // No jitter delay
161
166
  retry: {
162
- max: 3, // 3 retry attempts
163
- interval: 3, // 3 seconds base interval
164
- maxInterval: 30, // 30 seconds max interval
165
- byHeader: true // Respect Retry-After header
167
+ maxAttempts: 3, // 3 retry attempts
168
+ interval: 3, // 3 seconds base interval
169
+ maxInterval: 30, // 30 seconds maximum interval
170
+ retryAfter: true // Respect Retry-After header
166
171
  },
167
- throwError: {
168
- onError: true, // Throw parsing errors
169
- onErrorStatus: false // Don't throw on HTTP errors
172
+ onError: {
173
+ onNative: true, // Throw native errors
174
+ onStatus: false // Don't throw on HTTP errors
170
175
  },
171
- redirect: "follow" // Follow redirects
172
176
  }
173
177
  ```
174
178
 
175
- ### Auto-Configurations
179
+ ### Automatic Configuration
176
180
 
177
181
  #### Method
178
182
 
179
- If a body is passed as an option without specifying a method, the method will default to "POST".
183
+ If a body is provided without specifying a method, the method defaults to `"POST"`. When a Request object is passed as the `url` argument, its method is used.
180
184
 
181
185
  #### Headers
182
186
 
183
- If the following headers are not specified, they will be automatically set:
187
+ The following headers are automatically set if not specified:
184
188
 
185
- - Accept: `application/json, text/plain`
186
- - Content-Type: Automatically determined based on the body type:
189
+ - **Accept**: `application/json, text/plain`
190
+ - **Content-Type**: Automatically determined based on the body type:
187
191
  - `string`, `URLSearchParams`, `FormData`, `Blob` with type: Not set by this package; [`fetch` will set it automatically](https://fetch.spec.whatwg.org/#concept-bodyinit-extract).
188
192
  - `JSONValue`: `application/json`
189
193
  - `Blob` without type: `application/octet-stream`
190
194
  - `ArrayBuffer`: `application/octet-stream`
191
- - Authorization: Set to `Bearer ${options.bearerToken}` if `options.bearerToken` is provided.
195
+ - **Authorization**: Set to `Bearer ${options.bearer}` if `options.bearer` is provided.
196
+
197
+ **Note 1:** If you pass serialized JSON as the body (i.e., a string), Content-Type will be set to `text/plain;charset=UTF-8`. To ensure Content-Type is set to `application/json`, pass the JSON object directly instead of a serialized string.
192
198
 
193
- **Note:** If you pass serialized JSON as the body (i.e., a string), Content-Type will be set to `text/plain;charset=UTF-8`. To ensure Content-Type is set to `application/json`, pass the JSON object directly instead of a serialized string.
199
+ **Note 2:** If you pass a body through a Request object, Content-Type will NOT be set automatically by this package.
194
200
 
195
- ## Error Behavior
201
+ ## Error Handling
196
202
 
197
203
  ### Timeout
198
204
 
199
- If the timeout duration specified in the `timeout` option is exceeded, `abort("timeout")` will be called on the provided AbortController. Note that there is no specific error class for timeout errors; they will be thrown as standard `AbortError`s.
205
+ If the timeout duration specified in the `timeout` option is exceeded, the request is aborted using the standard `AbortSignal.timeout()` method. Note that there is no specific error class for timeout errors; they will be thrown as standard `AbortError`s.
200
206
 
201
207
  ### HTTPStatusError
202
208
 
203
- If `onErrorStatus` is set to `true`, an `HTTPStatusError` will be thrown when the response status is outside the 200 range. The error message format is: `404 Not Found`.
209
+ If `onStatus` is set to `true`, an `HTTPStatusError` will be thrown when the response status is outside the 2xx range. You can access the status and body through this error object. The error message format is: `404 Not Found: (no response body)`.
204
210
 
205
211
  ### RedirectError
206
212
 
207
- If `redirect` is set to `"error"`, a `RedirectError` will be thrown when the response status is in the 300 range. The error message format is: `Received redirect response: 301`.
213
+ If `redirect` is set to `"error"`, a `RedirectError` will be thrown when the response status is in the 3xx range. You can access the status through this error object. The error message format is: `301 Moved Permanently`.
208
214
 
209
- ### Others
215
+ ### Other Errors
210
216
 
211
- If the `onError` option is set to `true`, any other errors that occur will be thrown directly.
217
+ If the `onNative` option is set to `true`, any other errors that occur will be thrown directly.
212
218
 
213
219
  ## Usage Examples
214
220
 
215
221
  ### Basic Requests
222
+
216
223
  ```ts
217
224
  import { fetchy, fetchyb } from "@scirexs/fetchy";
218
225
 
@@ -230,13 +237,19 @@ const response = await fetchy("https://api.example.com/data", {
230
237
  "X-Custom-Header": "value"
231
238
  }
232
239
  });
240
+
241
+ // Reuse options as preset configuration (avoids Request object limitations)
242
+ const options = { url: "https://api.example.com/data", retry: false };
243
+ await fetchy(null, options);
244
+ await fetchy(null, options);
233
245
  ```
234
246
 
235
247
  ### Authentication
248
+
236
249
  ```ts
237
250
  // Bearer token authentication
238
251
  const user = await fetchyb<User>("https://api.example.com/me", "json", {
239
- bearerToken: "your-access-token"
252
+ bearer: "your-access-token"
240
253
  });
241
254
 
242
255
  // Custom authorization
@@ -248,6 +261,7 @@ const data = await fetchyb("https://api.example.com/data", "json", {
248
261
  ```
249
262
 
250
263
  ### Timeout and Retry
264
+
251
265
  ```ts
252
266
  // Custom timeout
253
267
  const response = await fetchy("https://slow-api.example.com", {
@@ -255,12 +269,13 @@ const response = await fetchy("https://slow-api.example.com", {
255
269
  });
256
270
 
257
271
  // Retry with exponential backoff
272
+ // Retry intervals: 1s, 3s (3^1), 9s (3^2), 27s (3^3), 60s (capped at maxInterval)
258
273
  const data = await fetchyb("https://api.example.com/data", "json", {
259
274
  retry: {
260
- max: 5, // Retry up to 5 times
261
- interval: 2, // Start with 2 seconds
275
+ maxAttempts: 5, // Retry up to 5 times
276
+ interval: 3, // Base interval for exponential backoff (interval^n)
262
277
  maxInterval: 60, // Cap at 60 seconds
263
- byHeader: true // Respect Retry-After header
278
+ retryAfter: true // Respect Retry-After header
264
279
  }
265
280
  });
266
281
 
@@ -271,10 +286,11 @@ const response = await fetchy("https://api.example.com/data", {
271
286
  ```
272
287
 
273
288
  ### Error Handling
289
+
274
290
  ```ts
275
291
  import { fetchy, HTTPStatusError, RedirectError } from "@scirexs/fetchy";
276
292
 
277
- // Throw on error (default is same with `fetch`)
293
+ // Throw on error (default behavior, same as native fetch)
278
294
  try {
279
295
  const response = await fetchy("https://api.example.com/data");
280
296
  } catch (error) {
@@ -283,7 +299,7 @@ try {
283
299
 
284
300
  // Return null on error
285
301
  const response = await fetchy("https://api.example.com/data", {
286
- throwError: false,
302
+ onError: false,
287
303
  });
288
304
  if (response === null) {
289
305
  console.log("Request failed");
@@ -292,12 +308,13 @@ if (response === null) {
292
308
  // Throw only on HTTP errors
293
309
  try {
294
310
  const response = await fetchy("https://api.example.com/data", {
295
- throwError: { onError: false, onErrorStatus: true }
311
+ onError: { onNative: false, onStatus: true }
296
312
  });
297
313
  } catch (error) {
298
314
  if (error instanceof HTTPStatusError) {
299
- // You can also use error.status and error.body.
300
315
  console.error("HTTP error:", error.message); // e.g., "404 Not Found: (no response body)"
316
+ console.error("Status:", error.status);
317
+ console.error("Body:", error.body);
301
318
  }
302
319
  }
303
320
 
@@ -309,28 +326,34 @@ try {
309
326
  } catch (error) {
310
327
  if (error instanceof RedirectError) {
311
328
  console.error("Unexpected redirect:", error.message);
329
+ console.error("Status:", error.status);
312
330
  }
313
331
  }
314
332
  ```
315
333
 
316
334
  ### Advanced Usage
335
+
317
336
  ```ts
318
337
  // Jitter to prevent thundering herd
319
338
  const response = await fetchy("https://api.example.com/data", {
320
- jitter: 2, // Random delay up to 2 seconds before request
321
- retry: { max: 3 }
339
+ delay: 2, // Random delay up to 2 seconds before request
340
+ retry: { maxAttempts: 3 }
322
341
  });
323
342
 
324
- // Manual abort control
325
- const controller = new AbortController();
343
+ // Combined abort signals
344
+ const controller1 = new AbortController();
345
+ const controller2 = new AbortController();
346
+ const request = new Request("https://api.example.com/data", {
347
+ signal: controller1.signal
348
+ });
326
349
 
327
- setTimeout(() => controller.abort(), 5000); // Abort after 5 seconds
350
+ setTimeout(() => controller1.abort(), 5000); // Abort after 5 seconds
328
351
 
329
- const response = await fetchy("https://api.example.com/data", {
330
- abort: controller
352
+ const response = await fetchy(request, {
353
+ signal: controller2.signal
331
354
  });
332
355
 
333
- // Form data
356
+ // Form data upload
334
357
  const formData = new FormData();
335
358
  formData.append("file", blob);
336
359
  formData.append("name", "example");
@@ -349,6 +372,7 @@ const response = await fetchy("https://api.example.com/form", {
349
372
  ```
350
373
 
351
374
  ### Type-Safe API Responses
375
+
352
376
  ```ts
353
377
  interface ApiResponse<T> {
354
378
  success: boolean;
@@ -367,11 +391,42 @@ const response = await fetchyb<ApiResponse<Todo>>(
367
391
  "json"
368
392
  );
369
393
 
370
- if (response?.success) {
394
+ if (response.success) {
371
395
  console.log(response.data.title); // Fully typed
372
396
  }
373
397
  ```
374
398
 
399
+ ## Limitations
400
+
401
+ ### Return Type Inference
402
+
403
+ When setting the `onError` property in `FetchyOptions`, the return type will include `null` even if you set it to `true` or `{ onNative: true }`. To prevent this and ensure a non-nullable return type, add `as const` to the `onError` property value:
404
+
405
+ ```ts
406
+ interface User {
407
+ id: number;
408
+ name: string;
409
+ }
410
+
411
+ const options = { timeout: 5, onError: true as const }; // Add `as const`
412
+ const response = await fetchy("https://api.example.com/todos/1", "json", options);
413
+ // `response` is User (not User | null)
414
+ ```
415
+
416
+ ### Content-Type Header with Request Objects
417
+
418
+ When a body is set in a Request object, the Content-Type header is NOT set automatically by this package. Therefore, when using Request objects, you must explicitly set the Content-Type header for any body types other than those automatically handled by the native `fetch` API.
419
+
420
+ This limitation can be avoided by using the `url` property in `FetchyOptions` instead of Request objects. This approach allows you to benefit from all automatic header configuration features while still maintaining reusable preset configurations. See the "Reuse options as preset configuration" example in the [Basic Requests](#basic-requests) section.
421
+
422
+ ### ReadableStream as Body
423
+
424
+ `FetchyOptions` does not accept ReadableStream as a body. If you need to use ReadableStream, create a Request object with the stream and pass it to `fetchy()`.
425
+
426
+ ### Redirect Error Handling
427
+
428
+ When `redirect` is set to `"error"`, this package throws a custom `RedirectError` (instead of the native TypeError) to enable proper retry handling for redirect responses.
429
+
375
430
  ## License
376
431
 
377
432
  MIT
package/esm/main.js CHANGED
@@ -1,19 +1,19 @@
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, };
1
+ export { _cloneInput, _combineSignal, _correctNumber, _DEFAULT, _fetchWithJitter, _fetchWithRetry, _getBody, _getContentType, _getHeaders, _getNextInterval, _getOptions, _getRequestInit, _getRetryOption, _handleRedirectResponse, _isBool, _isJSONObject, _isNumber, _isPlainObject, _isString, _parseRetryAfter, _shouldNotRetry, _shouldRedirect, _throwError, _wait, fetchy, fetchyb, HTTPStatusError, RedirectError, };
2
2
  /*=============== Constant Values ===============*/
3
3
  /**
4
4
  * Default configuration values for fetchy.
5
5
  * These values are used when corresponding options are not specified.
6
6
  */
7
- const DEFAULT = {
7
+ const _DEFAULT = {
8
8
  timeout: 15,
9
- jitter: 0,
9
+ delay: 0,
10
10
  interval: 3,
11
11
  maxInterval: 30,
12
- max: 3,
13
- byHeader: true,
14
- onError: true,
15
- onErrorStatus: false,
16
- userRedirect: "follow",
12
+ maxAttempts: 3,
13
+ retryAfter: true,
14
+ onNative: true,
15
+ onStatus: false,
16
+ redirect: "follow",
17
17
  };
18
18
  /*=============== Main Code =====================*/
19
19
  /**
@@ -93,54 +93,24 @@ async function fetchyb(url, type = "auto", options) {
93
93
  return await resp.bytes();
94
94
  }
95
95
  catch (e) {
96
- if (_throwError("onError", options?.throwError))
96
+ if (_throwError("onNative", options?.onError))
97
97
  throw e;
98
98
  return null;
99
99
  }
100
100
  }
101
- /**
102
- * Performs an HTTP request with enhanced features like timeout, retry, and automatic header management.
103
- * Returns the raw Response object or null on failure, unless throwError is configured.
104
- *
105
- * @param url - The URL to fetch. Can be a string, URL object, or Request object.
106
- * @param options - Configuration options for the request.
107
- * @returns Response object or null on failure.
108
- *
109
- * @example
110
- * ```ts
111
- * import { fetchy } from "@scirexs/fetchy";
112
- *
113
- * // Simple GET request
114
- * const response = await fetchy("https://api.example.com/data");
115
- * if (response?.ok) {
116
- * const data = await response.json();
117
- * }
118
- *
119
- * // POST request with JSON body
120
- * const response = await fetchy("https://api.example.com/create", {
121
- * body: { name: "John", age: 30 },
122
- * bearerToken: "your-token"
123
- * });
124
- *
125
- * // With retry and timeout
126
- * const response = await fetchy("https://api.example.com/data", {
127
- * timeout: 10,
128
- * retry: { max: 5, interval: 2 },
129
- * throwError: { onErrorStatus: true }
130
- * });
131
- * ```
132
- */
133
101
  async function fetchy(url, options) {
134
102
  try {
103
+ if (!url)
104
+ url = options?.url ?? new URL("");
135
105
  const opts = _getOptions(options);
136
- const init = _getRequestInit(options, opts.abort);
106
+ const init = _getRequestInit(url, opts, options);
137
107
  const resp = await _fetchWithRetry(url, init, opts);
138
- if (!resp.ok && opts.onErrorStatus)
108
+ if (!resp.ok && opts.onStatus)
139
109
  throw await HTTPStatusError.fromResponse(resp);
140
110
  return resp;
141
111
  }
142
112
  catch (e) {
143
- if (_throwError("onError", options?.throwError))
113
+ if (_throwError("onNative", options?.onError))
144
114
  throw e;
145
115
  return null;
146
116
  }
@@ -193,9 +163,9 @@ function _isPlainObject(v) {
193
163
  * @returns True if error should be thrown.
194
164
  */
195
165
  function _throwError(prop, options) {
196
- return Boolean((options === void 0 && DEFAULT[prop]) ||
166
+ return Boolean((options === void 0 && _DEFAULT[prop]) ||
197
167
  (typeof options === "boolean" && options) ||
198
- (typeof options === "object" && (options[prop] ?? DEFAULT[prop])));
168
+ (typeof options === "object" && (options[prop] ?? _DEFAULT[prop])));
199
169
  }
200
170
  /**
201
171
  * Corrects a number to be non-negative, using default if invalid.
@@ -214,9 +184,9 @@ function _getRetryOption(prop, off, options) {
214
184
  if (_isBool(options))
215
185
  return off;
216
186
  if (options === void 0 || options[prop] === void 0)
217
- return DEFAULT[prop];
187
+ return _DEFAULT[prop];
218
188
  if (_isNumber(options[prop]))
219
- return _correctNumber(DEFAULT[prop], options[prop], prop === "max");
189
+ return _correctNumber(_DEFAULT[prop], options[prop], prop === "maxAttempts");
220
190
  return options[prop];
221
191
  }
222
192
  /**
@@ -226,33 +196,32 @@ function _getRetryOption(prop, off, options) {
226
196
  * @returns Normalized internal options.
227
197
  */
228
198
  function _getOptions(options) {
229
- const timeout = _correctNumber(DEFAULT.timeout, options?.timeout);
230
199
  return {
231
- timeout,
232
- jitter: _correctNumber(DEFAULT.jitter, options?.jitter),
200
+ timeout: _correctNumber(_DEFAULT.timeout, options?.timeout),
201
+ delay: _correctNumber(_DEFAULT.delay, options?.delay),
233
202
  interval: _getRetryOption("interval", 0, options?.retry),
234
203
  maxInterval: _getRetryOption("maxInterval", 0, options?.retry),
235
- max: _getRetryOption("max", 0, options?.retry),
236
- byHeader: _getRetryOption("byHeader", false, options?.retry),
237
- onErrorStatus: _throwError("onErrorStatus", options?.throwError),
238
- abort: options?.abort ?? (timeout ? new AbortController() : undefined),
239
- userRedirect: options?.redirect ?? DEFAULT.userRedirect,
204
+ maxAttempts: _getRetryOption("maxAttempts", 0, options?.retry),
205
+ retryAfter: _getRetryOption("retryAfter", false, options?.retry),
206
+ onStatus: _throwError("onStatus", options?.onError),
207
+ redirect: options?.redirect ?? _DEFAULT.redirect,
240
208
  };
241
209
  }
242
210
  /**
243
211
  * Converts FetchyOptions to standard RequestInit format.
244
212
  * @internal
213
+ * @param url - Original request URL.
214
+ * @param opts - Internal options.
245
215
  * @param options - User-provided options.
246
- * @param optsAbort - AbortController for timeout handling.
247
216
  * @returns Standard RequestInit object.
248
217
  */
249
- function _getRequestInit(options, optsAbort) {
250
- const { body, timeout, retry, bearerToken, throwError, jitter, abort, redirect, ...rest } = options ?? {};
218
+ function _getRequestInit(url, opts, options) {
219
+ const { method, body, timeout, retry, bearer, onError, delay, redirect, signal, ...rest } = options ?? {};
251
220
  return {
252
- method: body === void 0 ? "GET" : "POST",
253
221
  headers: _getHeaders(options),
222
+ method: method ? method : url instanceof Request ? url.method : body === void 0 ? "GET" : "POST",
223
+ signal: _combineSignal(url, opts.timeout, options?.signal),
254
224
  ...(redirect && { redirect: redirect === "error" ? "manual" : redirect }),
255
- ...(optsAbort && { signal: optsAbort.signal }),
256
225
  ...(body && { body: _getBody(body) }),
257
226
  ...rest,
258
227
  };
@@ -286,7 +255,7 @@ function _getHeaders(options) {
286
255
  return {
287
256
  "Accept": "application/json, text/plain",
288
257
  ...(type && { "Content-Type": type }),
289
- ...(options?.bearerToken && { "Authorization": `Bearer ${options.bearerToken}` }),
258
+ ...(options?.bearer && { "Authorization": `Bearer ${options.bearer}` }),
290
259
  ...options?.headers,
291
260
  };
292
261
  }
@@ -305,6 +274,24 @@ function _getContentType(body) {
305
274
  return "application/json";
306
275
  return "application/octet-stream";
307
276
  }
277
+ /**
278
+ * Combine abort signals.
279
+ * @internal
280
+ * @param url - Original request URL.
281
+ * @param timeout - Request timeout in seconds.
282
+ * @param signal - AbortSignal in User-provided options.
283
+ * @returns Combined AbortSignal or undefined.
284
+ */
285
+ function _combineSignal(url, timeout, signal) {
286
+ const signals = [];
287
+ if (url instanceof Request && url.signal)
288
+ signals.push(url.signal);
289
+ if (signal)
290
+ signals.push(signal);
291
+ if (timeout > 0)
292
+ signals.push(AbortSignal.timeout(timeout * 1000 + 1));
293
+ return signals.length ? AbortSignal.any(signals) : undefined;
294
+ }
308
295
  /**
309
296
  * Waits for specified seconds with optional randomization.
310
297
  * @internal
@@ -330,18 +317,19 @@ function _shouldRedirect(resp) {
330
317
  * Determines if retry should stop based on conditions and waits if continuing.
331
318
  * @internal
332
319
  * @param count - Current retry attempt number.
320
+ * @param init - Request initialization object.
333
321
  * @param opts - Internal options.
334
322
  * @param resp - Response from previous attempt.
335
323
  * @returns True if retry should stop.
336
324
  */
337
- async function _shouldNotRetry(count, opts, resp) {
338
- if (count >= opts.max || resp?.ok)
325
+ async function _shouldNotRetry(count, init, opts, resp) {
326
+ if (count >= opts.maxAttempts - 1 || init.signal?.aborted || resp?.ok)
339
327
  return true;
340
328
  if (resp && _shouldRedirect(resp)) {
341
- if (opts.userRedirect === "manual")
329
+ if (opts.redirect === "manual")
342
330
  return true;
343
- if (opts.userRedirect === "error") {
344
- opts.max = 0;
331
+ if (opts.redirect === "error") {
332
+ opts.maxAttempts = 0;
345
333
  throw RedirectError.fromResponse(resp);
346
334
  }
347
335
  }
@@ -360,7 +348,7 @@ async function _shouldNotRetry(count, opts, resp) {
360
348
  * @returns Next retry interval in seconds.
361
349
  */
362
350
  function _getNextInterval(count, opts, resp) {
363
- return opts.byHeader && resp
351
+ return opts.retryAfter && resp
364
352
  ? Math.max(_parseRetryAfter(resp.headers.get("Retry-After")?.trim() ?? ""), opts.interval)
365
353
  : Math.min(Math.pow(Math.max(1, opts.interval), count), opts.maxInterval);
366
354
  }
@@ -396,6 +384,16 @@ function _handleRedirectResponse(url, init, resp) {
396
384
  init.method = "GET";
397
385
  return url instanceof Request ? new Request(resp.url, url) : resp.url;
398
386
  }
387
+ /**
388
+ * Clone input if required.
389
+ * @internal
390
+ * @param url - Original request URL.
391
+ * @param required - Switch to clone or not.
392
+ * @returns Cloned input for fetch.
393
+ */
394
+ function _cloneInput(url, required) {
395
+ return url instanceof Request && required ? url.clone() : url;
396
+ }
399
397
  /**
400
398
  * Executes fetch with retry logic and exponential backoff.
401
399
  * @internal
@@ -405,23 +403,22 @@ function _handleRedirectResponse(url, init, resp) {
405
403
  * @returns Response from successful request.
406
404
  */
407
405
  async function _fetchWithRetry(url, init, opts) {
408
- if (!opts.max)
409
- return await _fetchWithTimeout(url, init, opts);
410
- for (let i = 1; i <= opts.max; i++) {
406
+ for (let i = 0; i < opts.maxAttempts; i++) {
411
407
  try {
412
- const resp = await (opts.jitter ? _fetchWithJitter(url, init, opts) : _fetchWithTimeout(url, init, opts));
413
- if (await _shouldNotRetry(i, opts, resp))
408
+ const input = _cloneInput(url, i < opts.maxAttempts - 1); // no clone if end of retry
409
+ const resp = await _fetchWithJitter(input, init, opts);
410
+ if (await _shouldNotRetry(i, init, opts, resp))
414
411
  return resp;
415
412
  url = _handleRedirectResponse(url, init, resp);
416
413
  continue;
417
414
  }
418
415
  catch (e) {
419
- if (await _shouldNotRetry(i, opts))
416
+ if (await _shouldNotRetry(i, init, opts))
420
417
  throw e;
421
418
  continue;
422
419
  }
423
420
  }
424
- throw new Error("never reach");
421
+ return await _fetchWithJitter(url, init, opts);
425
422
  }
426
423
  /**
427
424
  * Executes fetch with initial jitter delay.
@@ -432,27 +429,6 @@ async function _fetchWithRetry(url, init, opts) {
432
429
  * @returns Response from request.
433
430
  */
434
431
  async function _fetchWithJitter(url, init, opts) {
435
- await _wait(opts.jitter);
436
- return await _fetchWithTimeout(url, init, opts);
437
- }
438
- /**
439
- * Executes fetch with timeout handling.
440
- * @internal
441
- * @param url - Request URL.
442
- * @param init - Request initialization object.
443
- * @param opts - Internal options.
444
- * @returns Response from request.
445
- */
446
- async function _fetchWithTimeout(url, init, opts) {
447
- const req = url instanceof Request ? url.clone() : url;
448
- const id = opts.abort ? setTimeout(() => opts.abort?.abort("timeout"), opts.timeout * 1000) : 0;
449
- try {
450
- return await fetch(req, init);
451
- }
452
- catch (e) {
453
- throw e;
454
- }
455
- finally {
456
- clearTimeout(id);
457
- }
432
+ await _wait(opts.delay);
433
+ return await fetch(url, init);
458
434
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scirexs/fetchy",
3
- "version": "0.2.1",
3
+ "version": "0.4.0",
4
4
  "description": "A lightweight fetch wrapper.",
5
5
  "keywords": [
6
6
  "fetch",
package/types/main.d.ts CHANGED
@@ -1,10 +1,10 @@
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, };
1
+ export { _cloneInput, _combineSignal, _correctNumber, _DEFAULT, _fetchWithJitter, _fetchWithRetry, _getBody, _getContentType, _getHeaders, _getNextInterval, _getOptions, _getRequestInit, _getRetryOption, _handleRedirectResponse, _isBool, _isJSONObject, _isNumber, _isPlainObject, _isString, _parseRetryAfter, _shouldNotRetry, _shouldRedirect, _throwError, _wait, fetchy, fetchyb, HTTPStatusError, RedirectError, };
2
2
  import type { ErrorOptions, FetchyBody, FetchyOptions, RetryOptions } from "./types.js";
3
3
  /**
4
4
  * Default configuration values for fetchy.
5
5
  * These values are used when corresponding options are not specified.
6
6
  */
7
- declare const DEFAULT: Options;
7
+ declare const _DEFAULT: Options;
8
8
  /**
9
9
  * Valid input types for fetch requests.
10
10
  * @internal
@@ -16,16 +16,26 @@ type Input = string | URL | Request;
16
16
  */
17
17
  interface Options {
18
18
  timeout: number;
19
- jitter: number;
19
+ delay: number;
20
20
  interval: number;
21
21
  maxInterval: number;
22
- max: number;
23
- byHeader: boolean;
24
- onError?: boolean;
25
- onErrorStatus: boolean;
26
- abort?: AbortController;
27
- userRedirect: "follow" | "error" | "manual";
22
+ maxAttempts: number;
23
+ retryAfter: boolean;
24
+ onNative?: boolean;
25
+ onStatus: boolean;
26
+ redirect: "follow" | "error" | "manual";
28
27
  }
28
+ /**
29
+ * Infer helper type for response type overload.
30
+ * @internal
31
+ */
32
+ type ThrowError = FetchyOptions & Partial<{
33
+ throwError: true;
34
+ }> | FetchyOptions & Partial<{
35
+ throwError: {
36
+ onError: true;
37
+ };
38
+ }>;
29
39
  /**
30
40
  * Error thrown when HTTP response has a non-OK status code (4xx, 5xx, ...).
31
41
  * Only thrown when throwError.onErrorStatus is set to true.
@@ -98,10 +108,18 @@ declare class RedirectError extends Error {
98
108
  * const bytes = await fetchyb("https://example.com/image.png", "bytes");
99
109
  * ```
100
110
  */
101
- declare function fetchyb(url: Input, type: "text", options?: FetchyOptions): Promise<string | null>;
102
- declare function fetchyb<T>(url: Input, type: "json", options?: FetchyOptions): Promise<T | null>;
103
- declare function fetchyb(url: Input, type: "bytes", options?: FetchyOptions): Promise<Uint8Array | null>;
104
- declare function fetchyb<T>(url: Input, type?: "auto", options?: FetchyOptions): Promise<T | string | Uint8Array | null>;
111
+ declare function fetchyb(url: Input | null, type: "text", options?: undefined): Promise<string>;
112
+ declare function fetchyb(url: Input | null, type: "text", options: FetchyOptions & ThrowError): Promise<string>;
113
+ declare function fetchyb(url: Input | null, type: "text", options?: FetchyOptions): Promise<string | null>;
114
+ declare function fetchyb<T>(url: Input | null, type: "json", options?: undefined): Promise<T>;
115
+ declare function fetchyb<T>(url: Input | null, type: "json", options: FetchyOptions & ThrowError): Promise<T>;
116
+ declare function fetchyb<T>(url: Input | null, type: "json", options?: FetchyOptions): Promise<T | null>;
117
+ declare function fetchyb(url: Input | null, type: "bytes", options?: undefined): Promise<Uint8Array>;
118
+ declare function fetchyb(url: Input | null, type: "bytes", options: FetchyOptions & ThrowError): Promise<Uint8Array>;
119
+ declare function fetchyb(url: Input | null, type: "bytes", options?: FetchyOptions): Promise<Uint8Array | null>;
120
+ declare function fetchyb<T>(url: Input | null, type?: "auto", options?: undefined): Promise<T | string | Uint8Array>;
121
+ declare function fetchyb<T>(url: Input | null, type?: "auto", options?: FetchyOptions & ThrowError): Promise<T | string | Uint8Array>;
122
+ declare function fetchyb<T>(url: Input | null, type?: "auto", options?: FetchyOptions): Promise<T | string | Uint8Array | null>;
105
123
  /**
106
124
  * Performs an HTTP request with enhanced features like timeout, retry, and automatic header management.
107
125
  * Returns the raw Response object or null on failure, unless throwError is configured.
@@ -134,7 +152,9 @@ declare function fetchyb<T>(url: Input, type?: "auto", options?: FetchyOptions):
134
152
  * });
135
153
  * ```
136
154
  */
137
- declare function fetchy(url: Input, options?: FetchyOptions): Promise<Response | null>;
155
+ declare function fetchy(url: Input | null, options?: undefined): Promise<Response>;
156
+ declare function fetchy(url: Input | null, options: FetchyOptions & ThrowError): Promise<Response>;
157
+ declare function fetchy(url: Input | null, options?: FetchyOptions): Promise<Response | null>;
138
158
  /**
139
159
  * Checks if a value is a string.
140
160
  * @internal
@@ -200,11 +220,12 @@ declare function _getOptions(options?: FetchyOptions): Options;
200
220
  /**
201
221
  * Converts FetchyOptions to standard RequestInit format.
202
222
  * @internal
223
+ * @param url - Original request URL.
224
+ * @param opts - Internal options.
203
225
  * @param options - User-provided options.
204
- * @param optsAbort - AbortController for timeout handling.
205
226
  * @returns Standard RequestInit object.
206
227
  */
207
- declare function _getRequestInit(options?: FetchyOptions, optsAbort?: AbortController): RequestInit;
228
+ declare function _getRequestInit(url: Input, opts: Options, options?: FetchyOptions): RequestInit;
208
229
  /**
209
230
  * Converts FetchyBody to standard BodyInit format.
210
231
  * @internal
@@ -233,6 +254,15 @@ declare function _getHeaders(options?: FetchyOptions): HeadersInit;
233
254
  * @returns Content-Type string or undefined.
234
255
  */
235
256
  declare function _getContentType(body?: FetchyBody): string | undefined;
257
+ /**
258
+ * Combine abort signals.
259
+ * @internal
260
+ * @param url - Original request URL.
261
+ * @param timeout - Request timeout in seconds.
262
+ * @param signal - AbortSignal in User-provided options.
263
+ * @returns Combined AbortSignal or undefined.
264
+ */
265
+ declare function _combineSignal(url: Input, timeout: number, signal?: AbortSignal | null): AbortSignal | undefined;
236
266
  /**
237
267
  * Waits for specified seconds with optional randomization.
238
268
  * @internal
@@ -251,11 +281,12 @@ declare function _shouldRedirect(resp: Response): boolean;
251
281
  * Determines if retry should stop based on conditions and waits if continuing.
252
282
  * @internal
253
283
  * @param count - Current retry attempt number.
284
+ * @param init - Request initialization object.
254
285
  * @param opts - Internal options.
255
286
  * @param resp - Response from previous attempt.
256
287
  * @returns True if retry should stop.
257
288
  */
258
- declare function _shouldNotRetry(count: number, opts: Options, resp?: Response): Promise<boolean>;
289
+ declare function _shouldNotRetry(count: number, init: RequestInit, opts: Options, resp?: Response): Promise<boolean>;
259
290
  /**
260
291
  * Calculates next retry interval using exponential backoff or Retry-After header.
261
292
  * @internal
@@ -281,6 +312,14 @@ declare function _parseRetryAfter(value: string): number;
281
312
  * @returns Updated URL for next request.
282
313
  */
283
314
  declare function _handleRedirectResponse(url: Input, init: RequestInit, resp: Response): Input;
315
+ /**
316
+ * Clone input if required.
317
+ * @internal
318
+ * @param url - Original request URL.
319
+ * @param required - Switch to clone or not.
320
+ * @returns Cloned input for fetch.
321
+ */
322
+ declare function _cloneInput(url: Input, required: boolean): Input;
284
323
  /**
285
324
  * Executes fetch with retry logic and exponential backoff.
286
325
  * @internal
@@ -299,13 +338,4 @@ declare function _fetchWithRetry(url: Input, init: RequestInit, opts: Options):
299
338
  * @returns Response from request.
300
339
  */
301
340
  declare function _fetchWithJitter(url: Input, init: RequestInit, opts: Options): Promise<Response>;
302
- /**
303
- * Executes fetch with timeout handling.
304
- * @internal
305
- * @param url - Request URL.
306
- * @param init - Request initialization object.
307
- * @param opts - Internal options.
308
- * @returns Response from request.
309
- */
310
- declare function _fetchWithTimeout(url: Input, init: RequestInit, opts: Options): Promise<Response>;
311
341
  //# sourceMappingURL=main.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
package/types/types.d.ts CHANGED
@@ -27,7 +27,9 @@ export type FetchyBody = JSONValue | Exclude<BodyInit, ReadableStream>;
27
27
  * });
28
28
  * ```
29
29
  */
30
- export interface FetchyOptions extends Omit<RequestInit, "body" | "signal"> {
30
+ export interface FetchyOptions extends Omit<RequestInit, "body"> {
31
+ /** Request URL. Used if call fetchy with null. */
32
+ url?: string | URL;
31
33
  /** Request body content. Automatically serializes JSON objects. */
32
34
  body?: FetchyBody;
33
35
  /** Request timeout in seconds. Default is 15 seconds. */
@@ -35,13 +37,11 @@ export interface FetchyOptions extends Omit<RequestInit, "body" | "signal"> {
35
37
  /** Retry configuration. Set to false to disable retry functionality. */
36
38
  retry?: RetryOptions | false;
37
39
  /** Bearer token for Authorization header. Automatically adds "Bearer " prefix. */
38
- bearerToken?: string;
40
+ bearer?: string;
39
41
  /** Error throwing behavior configuration. Set to true to throw all errors. */
40
- throwError?: ErrorOptions | boolean;
42
+ onError?: ErrorOptions | boolean;
41
43
  /** 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;
44
+ delay?: number;
45
45
  }
46
46
  /**
47
47
  * Configuration options for retry behavior.
@@ -63,18 +63,18 @@ export interface RetryOptions {
63
63
  /** Maximum interval in seconds between retries. Caps the exponential backoff. Default is 30 seconds. */
64
64
  maxInterval?: number;
65
65
  /** Maximum number of retry attempts. Default is 3. */
66
- max?: number;
66
+ maxAttempts?: number;
67
67
  /** Whether to respect Retry-After header from response. Default is true. */
68
- byHeader?: boolean;
68
+ retryAfter?: boolean;
69
69
  }
70
70
  /**
71
71
  * Configuration options for error throwing behavior.
72
72
  * Allows fine-grained control over which errors should be thrown vs. returned as null.
73
73
  */
74
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;
75
+ /** Whether to throw native errors (network errors, parsing errors, etc.). If false, returns null instead. Default is true. */
76
+ onNative?: boolean;
77
+ /** Whether to throw HTTPStatusError for non-OK status codes (4xx, 5xx, ...). Default is false. */
78
+ onStatus?: boolean;
79
79
  }
80
80
  //# sourceMappingURL=types.d.ts.map
@@ -1 +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"}
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,CAAC;IAC9D,kDAAkD;IAClD,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,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,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC;IACjC,8GAA8G;IAC9G,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;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,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,8HAA8H;IAC9H,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kGAAkG;IAClG,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB"}