@superutils/fetch 1.1.7 → 1.2.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
@@ -13,7 +13,10 @@ This package enhances the native `fetch` API by providing a streamlined interfac
13
13
  - [`Method Specific Functions`](#methods)
14
14
  - [`fetch.get.deferred()`](#fetch-deferred): cancellable and debounced or throttled `fetch()`
15
15
  - [`fetch.post()`](#post): make post requests
16
- - [`fetch.post.deferred()`](#post-deferred) cancellable and debounced or throttled `post()`
16
+ - [`fetch.post.deferred()`](#post-deferred): cancellable and debounced or throttled `post()`
17
+ - [`Retry`](#retry) Retry on request failure
18
+ - [`Timeout`](#timeout) Abort request on timeout
19
+ - [`Interceptors/Transformers`](#interceptors)
17
20
 
18
21
  ## Features
19
22
 
@@ -37,18 +40,14 @@ npm install @superutils/fetch
37
40
 
38
41
  ### `fetch(url, options)`
39
42
 
40
- Make a simple GET request. No need for `response.json()` or `result.data.theActualData` drilling.
43
+ Use as a drop-in replacement to the built-in `fetch()`.
41
44
 
42
- ```typescript
45
+ ```javascript
43
46
  import fetch from '@superutils/fetch'
44
47
 
45
- fetch('https://dummyjson.com/products/1', {
46
- method: 'get', // default
47
- }).then(theActualData => console.log(theActualData))
48
- // Alternative:
49
- fetch
50
- .get('https://dummyjson.com/products/1')
51
- .then(theActualData => console.log(theActualData))
48
+ fetch('https://dummyjson.com/products/1')
49
+ .then(response => response.json())
50
+ .then(console.log)
52
51
  ```
53
52
 
54
53
  <div id="methods"></div>
@@ -75,6 +74,16 @@ While `fetch()` provides access to all HTTP request methods by specifying it in
75
74
  - `fetch.post.deferred(...)`
76
75
  - `fetch.put.deferred(...)`
77
76
 
77
+ All method specific functions by default return result parsed as JSON. No need for `response.json()` or `result.data.data` drilling.
78
+
79
+ ```javascript
80
+ import fetch from '@superutils/fetch'
81
+
82
+ fetch
83
+ .get('https://dummyjson.com/products/1')
84
+ .then(product => console.log({ product }))
85
+ ```
86
+
78
87
  <div id="fetch-deferred"></div>
79
88
 
80
89
  ### `fetch.get.deferred(deferOptions, defaultUrl, defaultOptions)`
@@ -268,3 +277,163 @@ fetch
268
277
  // Only the final call executes, 300ms after it was made (at the 400ms mark).
269
278
  // The token is refreshed only once, preventing redundant network requests.
270
279
  ```
280
+
281
+ <div id="interceptors"></div>
282
+
283
+ ### Interceptors: intercept and/or transform request & result
284
+
285
+ The following interceptor callbacks allow intercepting and/or transforming at different stages of the request.
286
+
287
+ #### Interceptor types (executed in sequence):
288
+
289
+ 1. `request`: Request interceptors are executed before a HTTP request is made.
290
+ - To transform the URL simply return a new or modified URL.
291
+ - To transform `fetch` options simply modify the options parameter
292
+ 2. `response`: Response interceptors are executed after receiving a `fetch` Response regardless of the HTTP status code.
293
+ 3. `result`: Result interceptors are executed before returning the result. To transform the result simply return a new value.
294
+ PS: if the value of `options.as` is `FetchAs.response` (`"response"`), the value received in result will be a `Response` object.
295
+ 4. `error`: Error interceptors are executed when the request fails. Error can be transformed by returning a modified/new `FetchError`.
296
+
297
+ #### Notes:
298
+
299
+ - All interceptors can be either asynchronous or synchronous functions.
300
+ - If an exception is raised while executing the interceptors, it will be gracefully ignored.
301
+ - Value returned (transformed) by an interceptor will be carried over to the subsequent interceptor of the same type.
302
+ - There are 2 category of interceptors:
303
+ - Local: interceptors provided when making a request.
304
+ - Global: intereptors that are executed application-wide on every request. Global interceptors can be added/accessed at `fetch.defaults.interceptors`. Global interceptors are always executed before local interceptors.
305
+
306
+ **Example: Add global request and error interceptors**
307
+
308
+ ```javascript
309
+ import fetch from '@superutils/fetch'
310
+
311
+ const { interceptors } = fetch.defaults
312
+ interceptors.request.push((url, options) => {
313
+ // a headers to all requests make by the application
314
+ options.headers.append('x-auth', 'token')
315
+ })
316
+
317
+ interceptors.error.push((err, url, options) => {
318
+ // log whenever a request fails
319
+ console.log('Error interceptor', err)
320
+ })
321
+ ```
322
+
323
+ ```javascript
324
+ import fetch, { FetchError } from '@superutils/fetch'
325
+
326
+ const interceptors = {
327
+ error: [
328
+ (err, url, options) => {
329
+ console.log('Request failed', err, url, options)
330
+ // return nothing/undefined to keep the error unchanged
331
+ // or return modified/new error
332
+ err.message = 'My custom error message!'
333
+ // or create a new FetchError by cloning it (make sure all the required properties are set correctly)
334
+ return err.clone('My custom error message!')
335
+ },
336
+ ],
337
+ request: [
338
+ (url, options) => {
339
+ // add extra headers or modify request options here
340
+ options.headers.append('x-custom-header', 'some value')
341
+
342
+ // transform the URL by returning a modified URL
343
+ return url + '?param=value'
344
+ },
345
+ ],
346
+ response: [
347
+ (response, url, options) => {
348
+ if (response.ok) return
349
+ console.log('request was successful', { url, options })
350
+
351
+ // You can transform the response by returning different `Response` object or even make a completely new HTTP reuqest.
352
+ // The subsequent response interceptors will receive the returned response
353
+ return fetch('https://dummyjson.com/products/1') // promise will be resolved automatically
354
+ },
355
+ ],
356
+ result: [
357
+ (result, url, options) => {
358
+ const productId = Number(
359
+ new URL(url).pathname.split('/products/')[1],
360
+ )
361
+ if (options.method === 'get' && !Number.isNaN(productId)) {
362
+ result.title ??= 'Unknown title'
363
+ }
364
+ return result
365
+ },
366
+ ],
367
+ }
368
+ fetch
369
+ .get('https://dummyjson.com/products/1', { interceptors })
370
+ .then(product => console.log({ product }))
371
+ ```
372
+
373
+ <div id="retry"></div>
374
+
375
+ ### Retry
376
+
377
+ The `retry` option provides a robust mechanism to automatically re-attempt failed requests, with support for both linear and exponential backoff strategies to gracefully handle transient network issues.
378
+
379
+ ```javascript
380
+ import fetch from '@superutils/fetch'
381
+
382
+ fetch.get('https://dummyjson.com/products/1', {
383
+ retry: 3, // Max number of retries.
384
+ retryBackOff: 'linear', // Backoff strategy: 'linear' or 'exponential'.
385
+ // Delay in milliseconds.
386
+ // - 'linear': Constant delay between each attempt.
387
+ // - 'exponential': Initial delay that doubles with each retry.
388
+ retryDelay: 300,
389
+ retryDelayJitter: true, // Add random delay to avoid thundering herd.
390
+ retryDelayJitterMax: 100, // Max jitter delay (ms).
391
+ retryIf: (response, retryCount, error) => {
392
+ console.log('Attempt #', retryCount + 1)
393
+ // re-attempt if status code not 200
394
+ return response.status !== 200
395
+ },
396
+ })
397
+ ```
398
+
399
+ <div id="timeout"></div>
400
+
401
+ ### Request Timeout
402
+
403
+ A request can be automatically cancelled by simply providing a `timeout` duration in milliseconds. Internally, `fetch` uses an `AbortController` to cancel the request if it does not complete within the specified time.
404
+
405
+ ```javascript
406
+ import fetch from '@superutils/fetch'
407
+
408
+ fetch.get('https://dummyjson.com/products/1', {
409
+ timeout: 5000,
410
+ })
411
+ ```
412
+
413
+ <div id="fetch-as"></div>
414
+
415
+ ### Response Parsing
416
+
417
+ By default, `fetch()` returns a `Response` object, making it a drop-in replacement for the built-in `fetch`.
418
+
419
+ However, all method-specific functions (e.g., `fetch.get`, `fetch.post`, `fetch.get.deferred`) automatically parse and return the result as JSON.
420
+
421
+ To retrieve the response in a different format (e.g., as text, a blob, or the raw `Response` object), set the `as` option to one of the following `FetchAs` values:
422
+
423
+ - `FetchAs.json`
424
+ - `FetchAs.text`
425
+ - `FetchAs.blob`
426
+ - `FetchAs.arrayBuffer`
427
+ - `FetchAs.formData`
428
+ - `FetchAs.bytes`
429
+ - `FetchAs.response`
430
+
431
+ > **Note:** When not using TypeScript, you can simply pass the string value (e.g., `'text'`, `'blob'`, `'response'`).
432
+
433
+ ```typescript
434
+ import fetch, { FetchAs } from '@superutils/fetch'
435
+
436
+ fetch.get('https://dummyjson.com/products/1', {
437
+ as: FetchAs.text,
438
+ })
439
+ ```
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { ValueOrPromise } from '@superutils/core';
2
1
  import * as _superutils_promise from '@superutils/promise';
3
2
  import { RetryOptions, IPromisE, DeferredAsyncOptions } from '@superutils/promise';
4
3
  export { DeferredAsyncOptions, ResolveError, ResolveIgnored } from '@superutils/promise';
4
+ import { ValueOrPromise } from '@superutils/core';
5
5
 
6
6
  type FetchArgs<OmitMethod extends boolean = false> = [
7
7
  url: string | URL,
@@ -46,7 +46,7 @@ type FetchErrMsgs = {
46
46
  };
47
47
  /** Custom error message for fetch requests with more detailed info about the request URL, fetch options and response */
48
48
  declare class FetchError extends Error {
49
- options?: FetchOptions;
49
+ options: FetchOptions;
50
50
  response?: Response;
51
51
  url: string | URL;
52
52
  constructor(message: string, options: {
@@ -55,6 +55,7 @@ declare class FetchError extends Error {
55
55
  response?: Response;
56
56
  url: string | URL;
57
57
  });
58
+ clone: (newMessage: string) => FetchError;
58
59
  }
59
60
  /**
60
61
  * Fetch error interceptor to be invoked whenever an exception occurs.
@@ -97,11 +98,10 @@ declare class FetchError extends Error {
97
98
  */
98
99
  type FetchInterceptorError = Interceptor<FetchError, FetchArgsInterceptor>;
99
100
  /**
100
- *
101
101
  * Fetch request interceptor to be invoked before making a fetch request.
102
102
  * This interceptor can also be used as a transformer:
103
103
  * 1. by returning an API URL (string/URL)
104
- * 2. by modifying the properties of the options object to be used before making the fetch request
104
+ * 2. by modifying the properties of the options parameter to be used before making the fetch request
105
105
  *
106
106
  * @example intercept and transform fetch request
107
107
  * ```typescript
@@ -119,7 +119,9 @@ type FetchInterceptorError = Interceptor<FetchError, FetchArgsInterceptor>;
119
119
  * })
120
120
  * ```
121
121
  */
122
- type FetchInterceptorRequest = Interceptor<FetchArgs[0], FetchArgsInterceptor>;
122
+ type FetchInterceptorRequest = Interceptor<FetchArgs[0], [
123
+ FetchArgsInterceptor[1]
124
+ ]>;
123
125
  /**
124
126
  * Fetch response interceptor to be invoked before making a fetch request.
125
127
  *
@@ -187,7 +189,7 @@ type FetchInterceptorResponse = Interceptor<Response, FetchArgsInterceptor>;
187
189
  * })
188
190
  * ```
189
191
  */
190
- type FetchInterceptorResult = Interceptor<unknown, FetchArgsInterceptor>;
192
+ type FetchInterceptorResult<Args extends unknown[] = FetchArgsInterceptor> = Interceptor<unknown, Args>;
191
193
  /**
192
194
  * All valid interceptors for fetch requests are:
193
195
  * ---
@@ -235,7 +237,7 @@ type FetchInterceptors = {
235
237
  * Fetch request options
236
238
  */
237
239
  type FetchOptions = RequestInit & FetchCustomOptions;
238
- type FetchOptionsDefaults = Omit<FetchOptionsInterceptor, 'method' | 'retryIf'>;
240
+ type FetchOptionsDefaults = Omit<FetchOptionsInterceptor, 'as' | 'method' | 'retryIf'>;
239
241
  /**
240
242
  * Fetch options available to interceptors
241
243
  */
@@ -248,7 +250,7 @@ type FetchOptionsInterceptor = Omit<FetchOptions, 'as' | 'errMsgs' | 'intercepto
248
250
  /**
249
251
  * Result types for specific parsers ("as": FetchAs)
250
252
  */
251
- interface FetchResult<T> {
253
+ type FetchResult<T> = {
252
254
  arrayBuffer: ArrayBuffer;
253
255
  blob: Blob;
254
256
  bytes: Uint8Array<ArrayBuffer>;
@@ -256,7 +258,7 @@ interface FetchResult<T> {
256
258
  json: T;
257
259
  text: string;
258
260
  response: Response;
259
- }
261
+ };
260
262
  /**
261
263
  * Fetch retry options
262
264
  */
@@ -318,12 +320,218 @@ type PostOptions = Omit<FetchOptions, 'method'> & {
318
320
  method?: 'post' | 'put' | 'patch' | 'delete' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
319
321
  };
320
322
 
321
- declare const fetch$1: {
322
- <T, TOptions extends FetchOptions = FetchOptions, TReturn = TOptions["as"] extends FetchAs ? FetchResult<T>[TOptions["as"]] : T>(url: string | URL, options?: TOptions): IPromisE<TReturn>;
323
+ /** Create a method-specific fetch function attached with a `.deferred()` function */
324
+ declare const createFetchMethodFunc: (method?: Pick<FetchOptions, "method">["method"]) => {
325
+ <T, TOptions extends FetchOptions = FetchOptions, TAs extends FetchAs = TOptions["as"] extends FetchAs ? TOptions["as"] : FetchAs.json, TReturn = FetchResult<T>[TAs]>(url: string | URL, options?: TOptions | undefined): _superutils_promise.IPromisE<T>;
326
+ deferred<ThisArg = unknown, Delay extends number = number, GlobalUrl = string | URL | undefined, CbArgs extends unknown[] = undefined extends GlobalUrl ? FetchArgs<true> : [options?: Omit<FetchOptions, "method"> | undefined]>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultOptions?: FetchOptions | undefined): <TResult = unknown>(...args: undefined extends GlobalUrl ? FetchArgs<false> : [options?: FetchOptions | undefined]) => _superutils_promise.IPromisE<TResult>;
327
+ };
328
+
329
+ /**
330
+ * Create a method-specific function for POST-like methods that automatically stringifies `data`
331
+ * and attached with a `.deferred()` function
332
+ */
333
+ declare const createPostMethodFunc: (method?: Pick<PostOptions, "method">["method"]) => {
334
+ <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
335
+ deferred<ThisArg, Delay extends number = number, GlobalUrl extends PostArgs[0] | undefined = undefined, GlobalData extends PostArgs[1] | undefined = undefined, CbArgs extends unknown[] = PostDeferredCbArgs<GlobalUrl, GlobalData, true>>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultData?: GlobalData | undefined, defaultOptions?: PostOptions | undefined): <TResult = unknown>(...args: PostDeferredCbArgs<GlobalUrl, GlobalData, false, PostArgs<false>, PostOptions | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: PostOptions]>) => _superutils_promise.IPromisE<TResult>;
336
+ };
337
+
338
+ /**
339
+ * Extended `fetch` with timeout, retry, and other options. Automatically parses as JSON by default on success.
340
+ *
341
+ * @param url request URL
342
+ * @param options (optional) Standard `fetch` options extended with {@link FetchCustomOptions}.
343
+ * Default content type is 'application/json'
344
+ * @param options.as (optional) determines who to parse the result. Default: {@link FetchAs.json}
345
+ * @param options.method (optional) fetch method. Default: `'get'`
346
+ *
347
+ * @example Make a simple HTTP requests
348
+ * ```typescript
349
+ * import { fetch } from '@superutils/fetch'
350
+ *
351
+ * // no need for `response.json()` or `result.data.data` drilling
352
+ * fetch('https://dummyjson.com/products/1')
353
+ * .then(product => console.log(product))
354
+ * ```
355
+ */
356
+ declare const fetch: {
357
+ <T, TOptions extends FetchOptions = FetchOptions, TAs extends FetchAs = TOptions["as"] extends FetchAs ? TOptions["as"] : FetchAs.json, TReturn = FetchResult<T>[TAs]>(url: string | URL, options?: TOptions): IPromisE<TReturn>;
323
358
  /** Default fetch options */
324
359
  defaults: FetchOptionsDefaults;
325
360
  };
326
361
 
362
+ /**
363
+ * Drop-in replacement for built-in `fetch()` with with timeout, retry etc options and Response as default return type.
364
+ *
365
+ * @param url request URL
366
+ * @param options (optional) Standard `fetch` options extended with {@link FetchCustomOptions}
367
+ * @param options.as (optional) determines who to parse the result. Default: {@link FetchAs.response}
368
+ * @param options.method (optional) fetch method. Default: `'get'`
369
+ *
370
+ * @example Make a simple HTTP requests
371
+ * ```typescript
372
+ * import { fetchResponse } from '@superutils/fetch'
373
+ *
374
+ * fetchResponse('https://dummyjson.com/products/1')
375
+ * .then(response => response.json())
376
+ * .then(console.log, console.error)
377
+ * ```
378
+ */
379
+ declare const fetchResponse: <T = Response, TOptions extends FetchOptions = FetchOptions, TAs extends FetchAs = TOptions["as"] extends FetchAs ? TOptions["as"] : FetchAs.response, TReturn = FetchResult<T>[TAs]>(...args: Parameters<typeof fetch<T, TOptions, TAs, TReturn>>) => IPromisE<TReturn>;
380
+
381
+ declare const _get: {
382
+ <T, TOptions extends FetchOptions = FetchOptions, TAs extends FetchAs = TOptions["as"] extends FetchAs ? TOptions["as"] : FetchAs.json, TReturn = FetchResult<T>[TAs]>(url: string | URL, options?: TOptions | undefined): _superutils_promise.IPromisE<T>;
383
+ deferred<ThisArg = unknown, Delay extends number = number, GlobalUrl = string | URL | undefined, CbArgs extends unknown[] = undefined extends GlobalUrl ? FetchArgs<true> : [options?: Omit<FetchOptions, "method"> | undefined]>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultOptions?: FetchOptions | undefined): <TResult = unknown>(...args: undefined extends GlobalUrl ? FetchArgs<false> : [options?: FetchOptions | undefined]) => _superutils_promise.IPromisE<TResult>;
384
+ };
385
+ declare const _head: {
386
+ <T, TOptions extends FetchOptions = FetchOptions, TAs extends FetchAs = TOptions["as"] extends FetchAs ? TOptions["as"] : FetchAs.json, TReturn = FetchResult<T>[TAs]>(url: string | URL, options?: TOptions | undefined): _superutils_promise.IPromisE<T>;
387
+ deferred<ThisArg = unknown, Delay extends number = number, GlobalUrl = string | URL | undefined, CbArgs extends unknown[] = undefined extends GlobalUrl ? FetchArgs<true> : [options?: Omit<FetchOptions, "method"> | undefined]>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultOptions?: FetchOptions | undefined): <TResult = unknown>(...args: undefined extends GlobalUrl ? FetchArgs<false> : [options?: FetchOptions | undefined]) => _superutils_promise.IPromisE<TResult>;
388
+ };
389
+ declare const _options: {
390
+ <T, TOptions extends FetchOptions = FetchOptions, TAs extends FetchAs = TOptions["as"] extends FetchAs ? TOptions["as"] : FetchAs.json, TReturn = FetchResult<T>[TAs]>(url: string | URL, options?: TOptions | undefined): _superutils_promise.IPromisE<T>;
391
+ deferred<ThisArg = unknown, Delay extends number = number, GlobalUrl = string | URL | undefined, CbArgs extends unknown[] = undefined extends GlobalUrl ? FetchArgs<true> : [options?: Omit<FetchOptions, "method"> | undefined]>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultOptions?: FetchOptions | undefined): <TResult = unknown>(...args: undefined extends GlobalUrl ? FetchArgs<false> : [options?: FetchOptions | undefined]) => _superutils_promise.IPromisE<TResult>;
392
+ };
393
+ declare const _delete: {
394
+ <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
395
+ deferred<ThisArg, Delay extends number = number, GlobalUrl extends PostArgs[0] | undefined = undefined, GlobalData extends PostArgs[1] | undefined = undefined, CbArgs extends unknown[] = PostDeferredCbArgs<GlobalUrl, GlobalData, true>>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultData?: GlobalData | undefined, defaultOptions?: PostOptions | undefined): <TResult = unknown>(...args: PostDeferredCbArgs<GlobalUrl, GlobalData, false, PostArgs<false>, PostOptions | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: PostOptions]>) => _superutils_promise.IPromisE<TResult>;
396
+ };
397
+ declare const _patch: {
398
+ <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
399
+ deferred<ThisArg, Delay extends number = number, GlobalUrl extends PostArgs[0] | undefined = undefined, GlobalData extends PostArgs[1] | undefined = undefined, CbArgs extends unknown[] = PostDeferredCbArgs<GlobalUrl, GlobalData, true>>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultData?: GlobalData | undefined, defaultOptions?: PostOptions | undefined): <TResult = unknown>(...args: PostDeferredCbArgs<GlobalUrl, GlobalData, false, PostArgs<false>, PostOptions | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: PostOptions]>) => _superutils_promise.IPromisE<TResult>;
400
+ };
401
+ declare const _post: {
402
+ <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
403
+ deferred<ThisArg, Delay extends number = number, GlobalUrl extends PostArgs[0] | undefined = undefined, GlobalData extends PostArgs[1] | undefined = undefined, CbArgs extends unknown[] = PostDeferredCbArgs<GlobalUrl, GlobalData, true>>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultData?: GlobalData | undefined, defaultOptions?: PostOptions | undefined): <TResult = unknown>(...args: PostDeferredCbArgs<GlobalUrl, GlobalData, false, PostArgs<false>, PostOptions | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: PostOptions]>) => _superutils_promise.IPromisE<TResult>;
404
+ };
405
+ declare const _put: {
406
+ <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
407
+ deferred<ThisArg, Delay extends number = number, GlobalUrl extends PostArgs[0] | undefined = undefined, GlobalData extends PostArgs[1] | undefined = undefined, CbArgs extends unknown[] = PostDeferredCbArgs<GlobalUrl, GlobalData, true>>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultData?: GlobalData | undefined, defaultOptions?: PostOptions | undefined): <TResult = unknown>(...args: PostDeferredCbArgs<GlobalUrl, GlobalData, false, PostArgs<false>, PostOptions | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: PostOptions]>) => _superutils_promise.IPromisE<TResult>;
408
+ };
409
+ type FetchWithMethods = typeof fetchResponse & {
410
+ /** Default options */
411
+ defaults: typeof fetch.defaults;
412
+ /** Make HTTP `DELETE` request, result automatically parsed as JSON */
413
+ delete: typeof _delete;
414
+ /** Make HTTP `GET` request, result automatically parsed as JSON */
415
+ get: typeof _get;
416
+ /** Make HTTP `HEAD` request, result automatically parsed as JSON */
417
+ head: typeof _head;
418
+ /** Make HTTP `OPTIONS` request, result automatically parsed as JSON */
419
+ options: typeof _options;
420
+ /** Make HTTP `PATCH` request, result automatically parsed as JSON */
421
+ patch: typeof _patch;
422
+ /** Make HTTP `POST` request, result automatically parsed as JSON */
423
+ post: typeof _post;
424
+ /** Make HTTP `PUT` request, result automatically parsed as JSON */
425
+ put: typeof _put;
426
+ };
427
+ /**
428
+ * A `fetch()` replacement that simplifies data fetching with automatic JSON parsing, request timeouts, retries,
429
+ * and handy interceptors that also work as transformers. It also includes deferred and throttled request
430
+ * capabilities for complex asynchronous control flows.
431
+ *
432
+ * Will reject promise if response status code is not 2xx (200 <= status < 300).
433
+ *
434
+ * ## Method Specific Functions
435
+ *
436
+ * While `fetch()` provides access to all HTTP request methods by specifying it in options (eg: `{ method: 'get' }`),
437
+ * for ease of use you can also use the following:
438
+ *
439
+ * - `fetch.delete(...)`
440
+ * - `fetch.get(...)`
441
+ * - `fetch.head(...)`
442
+ * - `fetch.options(...)`
443
+ * - `fetch.patch(...)`
444
+ * - `fetch.post(...)`
445
+ * - `fetch.put(...)`
446
+ *
447
+ * **Deferred variants:** To debounce/throttle requests.
448
+ *
449
+ * - `fetch.delete.deferred(...)`
450
+ * - `fetch.get.deferred(...)`
451
+ * - `fetch.head.deferred(...)`
452
+ * - `fetch.options.deferred(...)`
453
+ * - `fetch.patch.deferred(...)`
454
+ * - `fetch.post.deferred(...)`
455
+ * - `fetch.put.deferred(...)`
456
+ *
457
+ * @template T The type of the value that the `fetch` resolves to.
458
+ * @template TReturn Return value type.
459
+ *
460
+ * If `T` is not specified defaults to the following based on the value of `options.as`:
461
+ * - FetchAs.arrayBuffer: `ArrayBuffer`
462
+ * - FetchAs.blob: `Blob`
463
+ * - FetchAs.bytes: `Uint8Array<ArrayBuffer>`
464
+ * - FetchAs.formData: `FormData`
465
+ * - FetchAs.json: `unknown`
466
+ * - FetchAs.text: `string`
467
+ * - FetchAs.response: `Response`
468
+ * @param url
469
+ * @param options (optional) Standard `fetch` options extended with {@link FetchCustomOptions}
470
+ * @param options.as (optional) determines who to parse the result. Default: {@link FetchAs.response}
471
+ * @param options.headers (optional) request headers
472
+ * Default: `{ 'content-type': `'application/json' }` (unless changed in the fetch.defaults).
473
+ * @param options.method (optional) fetch method. Default: `'get'`
474
+ *
475
+ * Options' default values (excluding `as`, `method` and `retryIf`) can be configured to be EFFECTIVE GLOBALLY.
476
+ *
477
+ * ```typescript
478
+ * import fetch from '@superutils/fetch'
479
+ *
480
+ * fetch.defaults = {
481
+ * errMsgs: {
482
+ * invalidUrl: 'Invalid URL',
483
+ * parseFailed: 'Failed to parse response as',
484
+ * reqTimedout: 'Request timed out',
485
+ * requestFailed: 'Request failed with status code:',
486
+ * },
487
+ * headers: new Headers([['content-type', 'application/json']]),
488
+ * // Global/application-wide Interceptor & Transfermers
489
+ * interceptors: {
490
+ * error: [],
491
+ * request: [],
492
+ * response: [],
493
+ * result: [],
494
+ * },
495
+ * timeout: 0,
496
+ * //........
497
+ * }
498
+ * ```
499
+ *
500
+ * @property options.abortCtrl (optional) if not provided `AbortController` will be instantiated when `timeout` used.
501
+ * @property options.headers (optional) request headers. Default: `{ 'content-type' : 'application/json'}`
502
+ * @property options.interceptors (optional) request interceptor callbacks. See {@link FetchInterceptors} for details.
503
+ * @property options.method (optional) Default: `"get"`
504
+ * @property options.timeout (optional) duration in milliseconds to abort the request if it takes longer.
505
+ * @property options.parse (optional) specify how to parse the result.
506
+ * Default: {@link FetchAs.json}
507
+ * For raw `Response` use {@link FetchAs.response}
508
+ *
509
+ * @example Drop-in replacement for built-in `fetch`
510
+ * ```typescript
511
+ * import fetch from '@superutils/fetch'
512
+ *
513
+ * fetch('https://dummyjson.com/products/1')
514
+ * .then(response => response.json())
515
+ * .then(console.log, console.error)
516
+ * ```
517
+ *
518
+ * @example Method specific function with JSON parsing by default
519
+ * ```typescript
520
+ * import fetch from '@superutils/fetch'
521
+ *
522
+ * // no need for `response.json()` or `result.data.data` drilling
523
+ * fetch.get('https://dummyjson.com/products/1')
524
+ * .then(product => console.log(product))
525
+ * fetch.get('https://dummyjson.com/products/1')
526
+ * .then(product => console.log(product))
527
+ *
528
+ *
529
+ * fetch.post('https://dummyjson.com/products/add', { title: 'Product title' })
530
+ * .then(product => console.log(product))
531
+ * ```
532
+ */
533
+ declare const fetchDefault: FetchWithMethods;
534
+
327
535
  /**
328
536
  * Creates a deferred/throttled version of {@link fetch}, powered by {@link PromisE.deferred}.
329
537
  * This is ideal for scenarios requiring advanced control over HTTP requests, such as debouncing search inputs,
@@ -521,140 +729,4 @@ declare function postDeferred<ThisArg, Delay = unknown, DefaultUrl extends PostA
521
729
  */
522
730
  declare const mergeFetchOptions: (...allOptions: FetchOptions[]) => FetchOptionsInterceptor;
523
731
 
524
- /** Create a method-specific fetch function attached with a `.deferred()` function */
525
- declare const createFetchMethodFunc: (method?: string) => {
526
- <T>(url: string | URL, options?: Omit<FetchOptions, "method">): _superutils_promise.IPromisE<T>;
527
- deferred<ThisArg = unknown, Delay extends number = number, GlobalUrl = string | URL | undefined, CbArgs extends unknown[] = undefined extends GlobalUrl ? FetchArgs<true> : [options?: Omit<FetchOptions, "method"> | undefined]>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultOptions?: FetchOptions | undefined): <TResult = unknown>(...args: undefined extends GlobalUrl ? FetchArgs<false> : [options?: FetchOptions | undefined]) => _superutils_promise.IPromisE<TResult>;
528
- };
529
- /** Create a method-specific function for POST-like methods and with a `.deferred()` function */
530
- declare const createPostMethodFunc: (method?: Pick<PostOptions, "method">["method"]) => {
531
- <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
532
- deferred<ThisArg, Delay extends number = number, GlobalUrl extends PostArgs[0] | undefined = undefined, GlobalData extends PostArgs[1] | undefined = undefined, CbArgs extends unknown[] = PostDeferredCbArgs<GlobalUrl, GlobalData, true>>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultData?: GlobalData | undefined, defaultOptions?: PostOptions | undefined): <TResult = unknown>(...args: PostDeferredCbArgs<GlobalUrl, GlobalData, false, PostArgs<false>, PostOptions | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: PostOptions]>) => _superutils_promise.IPromisE<TResult>;
533
- };
534
- declare const _get: {
535
- <T>(url: string | URL, options?: Omit<FetchOptions, "method">): _superutils_promise.IPromisE<T>;
536
- deferred<ThisArg = unknown, Delay extends number = number, GlobalUrl = string | URL | undefined, CbArgs extends unknown[] = undefined extends GlobalUrl ? FetchArgs<true> : [options?: Omit<FetchOptions, "method"> | undefined]>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultOptions?: FetchOptions | undefined): <TResult = unknown>(...args: undefined extends GlobalUrl ? FetchArgs<false> : [options?: FetchOptions | undefined]) => _superutils_promise.IPromisE<TResult>;
537
- };
538
- declare const _head: {
539
- <T>(url: string | URL, options?: Omit<FetchOptions, "method">): _superutils_promise.IPromisE<T>;
540
- deferred<ThisArg = unknown, Delay extends number = number, GlobalUrl = string | URL | undefined, CbArgs extends unknown[] = undefined extends GlobalUrl ? FetchArgs<true> : [options?: Omit<FetchOptions, "method"> | undefined]>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultOptions?: FetchOptions | undefined): <TResult = unknown>(...args: undefined extends GlobalUrl ? FetchArgs<false> : [options?: FetchOptions | undefined]) => _superutils_promise.IPromisE<TResult>;
541
- };
542
- declare const _options: {
543
- <T>(url: string | URL, options?: Omit<FetchOptions, "method">): _superutils_promise.IPromisE<T>;
544
- deferred<ThisArg = unknown, Delay extends number = number, GlobalUrl = string | URL | undefined, CbArgs extends unknown[] = undefined extends GlobalUrl ? FetchArgs<true> : [options?: Omit<FetchOptions, "method"> | undefined]>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultOptions?: FetchOptions | undefined): <TResult = unknown>(...args: undefined extends GlobalUrl ? FetchArgs<false> : [options?: FetchOptions | undefined]) => _superutils_promise.IPromisE<TResult>;
545
- };
546
- declare const _delete: {
547
- <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
548
- deferred<ThisArg, Delay extends number = number, GlobalUrl extends PostArgs[0] | undefined = undefined, GlobalData extends PostArgs[1] | undefined = undefined, CbArgs extends unknown[] = PostDeferredCbArgs<GlobalUrl, GlobalData, true>>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultData?: GlobalData | undefined, defaultOptions?: PostOptions | undefined): <TResult = unknown>(...args: PostDeferredCbArgs<GlobalUrl, GlobalData, false, PostArgs<false>, PostOptions | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: PostOptions]>) => _superutils_promise.IPromisE<TResult>;
549
- };
550
- declare const _patch: {
551
- <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
552
- deferred<ThisArg, Delay extends number = number, GlobalUrl extends PostArgs[0] | undefined = undefined, GlobalData extends PostArgs[1] | undefined = undefined, CbArgs extends unknown[] = PostDeferredCbArgs<GlobalUrl, GlobalData, true>>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultData?: GlobalData | undefined, defaultOptions?: PostOptions | undefined): <TResult = unknown>(...args: PostDeferredCbArgs<GlobalUrl, GlobalData, false, PostArgs<false>, PostOptions | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: PostOptions]>) => _superutils_promise.IPromisE<TResult>;
553
- };
554
- declare const _post: {
555
- <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
556
- deferred<ThisArg, Delay extends number = number, GlobalUrl extends PostArgs[0] | undefined = undefined, GlobalData extends PostArgs[1] | undefined = undefined, CbArgs extends unknown[] = PostDeferredCbArgs<GlobalUrl, GlobalData, true>>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultData?: GlobalData | undefined, defaultOptions?: PostOptions | undefined): <TResult = unknown>(...args: PostDeferredCbArgs<GlobalUrl, GlobalData, false, PostArgs<false>, PostOptions | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: PostOptions]>) => _superutils_promise.IPromisE<TResult>;
557
- };
558
- declare const _put: {
559
- <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
560
- deferred<ThisArg, Delay extends number = number, GlobalUrl extends PostArgs[0] | undefined = undefined, GlobalData extends PostArgs[1] | undefined = undefined, CbArgs extends unknown[] = PostDeferredCbArgs<GlobalUrl, GlobalData, true>>(deferOptions?: _superutils_promise.DeferredAsyncOptions<ThisArg, Delay> | undefined, defaultUrl?: GlobalUrl | undefined, defaultData?: GlobalData | undefined, defaultOptions?: PostOptions | undefined): <TResult = unknown>(...args: PostDeferredCbArgs<GlobalUrl, GlobalData, false, PostArgs<false>, PostOptions | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: PostOptions]>) => _superutils_promise.IPromisE<TResult>;
561
- };
562
- /**
563
- * @function fetch
564
- *
565
- * A `fetch()` replacement that simplifies data fetching with automatic JSON parsing, request timeouts, retries,
566
- * and handy interceptors that also work as transformers. It also includes deferred and throttled request
567
- * capabilities for complex asynchronous control flows.
568
- *
569
- * Will reject promise if response status code is not 2xx (200 <= status < 300).
570
- *
571
- * ## Method Specific Functions
572
- *
573
- * While `fetch()` provides access to all HTTP request methods by specifying it in options (eg: `{ method: 'get' }`),
574
- * for ease of use you can also use the following:
575
- *
576
- * - `fetch.delete(...)`
577
- * - `fetch.get(...)`
578
- * - `fetch.head(...)`
579
- * - `fetch.options(...)`
580
- * - `fetch.patch(...)`
581
- * - `fetch.post(...)`
582
- * - `fetch.put(...)`
583
- *
584
- * **Deferred variants:** To debounce/throttle requests.
585
- *
586
- * - `fetch.delete.deferred(...)`
587
- * - `fetch.get.deferred(...)`
588
- * - `fetch.head.deferred(...)`
589
- * - `fetch.options.deferred(...)`
590
- * - `fetch.patch.deferred(...)`
591
- * - `fetch.post.deferred(...)`
592
- * - `fetch.put.deferred(...)`
593
- *
594
- * @template T The type of the value that the `fetch` resolves to.
595
- * @template TReturn Return value type.
596
- *
597
- * If `T` is not specified defaults to the following based on the value of `options.as`:
598
- * - FetchAs.arrayBuffer: `ArrayBuffer`
599
- * - FetchAs.blob: `Blob`
600
- * - FetchAs.bytes: `Uint8Array<ArrayBuffer>`
601
- * - FetchAs.formData: `FormData`
602
- * - FetchAs.json: `unknown`
603
- * - FetchAs.text: `string`
604
- * - FetchAs.response: `Response`
605
- * @param url
606
- * @param options (optional) all built-in `fetch()` options such as "method", "headers" and the additionals below.
607
- *
608
- * Options' default values (excluding `method` and `retryIf`) can be configured to be EFFECTIVE GLOBALLY.
609
- *
610
- * ```typescript
611
- * import fetch from '@superutils/fetch'
612
- *
613
- * fetch.defaults = {
614
- * as: FetchAs.json,
615
- * errMsgs: {
616
- * invalidUrl: 'Invalid URL',
617
- * parseFailed: 'Failed to parse response as',
618
- * reqTimedout: 'Request timed out',
619
- * requestFailed: 'Request failed with status code:',
620
- * },
621
- * headers: new Headers([['content-type', 'application/json']]),
622
- * interceptors: {
623
- * error: [],
624
- * request: [],
625
- * response: [],
626
- * result: [],
627
- * },
628
- * timeout: 0,
629
- * //........
630
- * }
631
- * ```
632
- *
633
- * @property options.abortCtrl (optional) if not provided `AbortController` will be instantiated when `timeout` used.
634
- * @property options.headers (optional) request headers. Default: `{ 'content-type' : 'application/json'}`
635
- * @property options.interceptors (optional) request interceptor callbacks. See {@link FetchInterceptors} for details.
636
- * @property options.method (optional) Default: `"get"`
637
- * @property options.timeout (optional) duration in milliseconds to abort the request if it takes longer.
638
- * @property options.parse (optional) specify how to parse the result.
639
- * Default: {@link FetchAs.json}
640
- * For raw `Response` use {@link FetchAs.response}
641
- *
642
- * @example Make a simple HTTP requests
643
- * ```typescript
644
- * import { fetch } from '@superutils/fetch'
645
- *
646
- * // no need for `response.json()` or `result.data.theActualData` drilling
647
- * fetch('https://dummyjson.com/products/1').then(theActualData => console.log(theActualData))
648
- * ```
649
- */
650
- declare const fetch: typeof fetch$1 & {
651
- delete: typeof _delete;
652
- get: typeof _get;
653
- head: typeof _head;
654
- options: typeof _options;
655
- patch: typeof _patch;
656
- post: typeof _post;
657
- put: typeof _put;
658
- };
659
-
660
- export { type FetchArgs, type FetchArgsInterceptor, FetchAs, type FetchCustomOptions, type FetchDeferredArgs, type FetchErrMsgs, FetchError, type FetchInterceptorError, type FetchInterceptorRequest, type FetchInterceptorResponse, type FetchInterceptorResult, type FetchInterceptors, type FetchOptions, type FetchOptionsDefaults, type FetchOptionsInterceptor, type FetchResult, type FetchRetryOptions, type Interceptor, type PostArgs, type PostBody, type PostDeferredCbArgs, type PostOptions, createFetchMethodFunc, createPostMethodFunc, fetch as default, fetch, fetchDeferred, mergeFetchOptions, postDeferred };
732
+ export { type FetchArgs, type FetchArgsInterceptor, FetchAs, type FetchCustomOptions, type FetchDeferredArgs, type FetchErrMsgs, FetchError, type FetchInterceptorError, type FetchInterceptorRequest, type FetchInterceptorResponse, type FetchInterceptorResult, type FetchInterceptors, type FetchOptions, type FetchOptionsDefaults, type FetchOptionsInterceptor, type FetchResult, type FetchRetryOptions, type FetchWithMethods, type Interceptor, type PostArgs, type PostBody, type PostDeferredCbArgs, type PostOptions, createFetchMethodFunc, createPostMethodFunc, fetchDefault as default, fetch, fetchDeferred, fetchResponse, mergeFetchOptions, postDeferred };
package/dist/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  // src/fetch.ts
2
2
  import {
3
3
  fallbackIfFails as fallbackIfFails2,
4
- isEmpty as isEmpty2,
5
4
  isFn as isFn2,
6
5
  isPositiveNumber,
7
6
  isPromise,
@@ -28,27 +27,22 @@ var executeInterceptors_default = executeInterceptors;
28
27
  import PromisE from "@superutils/promise";
29
28
  import { isPositiveInteger } from "@superutils/core";
30
29
  var getResponse = async (...[url, options = {}]) => {
30
+ const fetchFunc = globalThis.fetch;
31
+ if (!isPositiveInteger(options.retry)) return fetchFunc(url, options);
31
32
  let attemptCount = 0;
32
- const doFetch = async () => {
33
- attemptCount++;
34
- return globalThis.fetch(url, options).catch(
35
- (err) => err.message === "Failed to fetch" ? (
36
- // catch network errors to allow retries
37
- new Response(null, {
38
- status: 0,
39
- statusText: "Network Error"
40
- })
41
- ) : Promise.reject(err)
42
- );
43
- };
44
- if (!isPositiveInteger(options.retry)) return doFetch();
45
- const response = PromisE.retry(doFetch, {
46
- ...options,
47
- retryIf: async (res, count) => {
48
- var _a;
49
- return (res == null ? void 0 : res.ok) === false || await ((_a = options == null ? void 0 : options.retryIf) == null ? void 0 : _a.call(options, res, count)) === true;
33
+ const response = PromisE.retry(
34
+ () => {
35
+ attemptCount++;
36
+ return fetchFunc(url, options);
37
+ },
38
+ {
39
+ ...options,
40
+ retryIf: async (res, count) => {
41
+ var _a;
42
+ return (res == null ? void 0 : res.ok) === false || await ((_a = options == null ? void 0 : options.retryIf) == null ? void 0 : _a.call(options, res, count)) === true;
43
+ }
50
44
  }
51
- }).catch(
45
+ ).catch(
52
46
  (err) => Promise.reject(
53
47
  new Error(`Request failed after attempt #${attemptCount}`, {
54
48
  cause: err
@@ -114,9 +108,15 @@ var FetchAs = /* @__PURE__ */ ((FetchAs2) => {
114
108
  FetchAs2["text"] = "text";
115
109
  return FetchAs2;
116
110
  })(FetchAs || {});
117
- var FetchError = class extends Error {
111
+ var FetchError = class _FetchError extends Error {
118
112
  constructor(message, options) {
119
113
  super(message, { cause: options.cause });
114
+ this.clone = (newMessage) => new _FetchError(newMessage, {
115
+ cause: this.cause,
116
+ options: this.options,
117
+ response: this.response,
118
+ url: this.url
119
+ });
120
120
  this.name = "FetchError";
121
121
  this.options = options.options;
122
122
  this.response = options.response;
@@ -129,17 +129,18 @@ var fetch = (url, options = {}) => {
129
129
  let abortCtrl;
130
130
  let timeoutId;
131
131
  const promise = new PromisE2(async (resolve, reject) => {
132
- var _a, _b;
132
+ var _a, _b, _c, _d;
133
133
  const _options2 = mergeFetchOptions_default(fetch.defaults, options);
134
- if (isEmpty2(_options2.method)) _options2.method = "get";
134
+ (_a = _options2.as) != null ? _a : _options2.as = "json" /* json */;
135
+ (_b = _options2.method) != null ? _b : _options2.method = "get";
135
136
  const errorInterceptors = [..._options2.interceptors.error];
136
137
  const requestInterceptors = [..._options2.interceptors.request];
137
138
  const responseInterceptors = [..._options2.interceptors.response];
138
139
  const resultInterceptors = [..._options2.interceptors.result];
139
- url = await executeInterceptors_default(url, requestInterceptors, url, _options2);
140
+ url = await executeInterceptors_default(url, requestInterceptors, _options2);
140
141
  const { as: parseAs, errMsgs, timeout } = _options2;
141
142
  if (isPositiveNumber(timeout)) {
142
- (_a = _options2.abortCtrl) != null ? _a : _options2.abortCtrl = new AbortController();
143
+ (_c = _options2.abortCtrl) != null ? _c : _options2.abortCtrl = new AbortController();
143
144
  timeoutId = setTimeout(() => {
144
145
  var _a2;
145
146
  return (_a2 = _options2.abortCtrl) == null ? void 0 : _a2.abort();
@@ -161,14 +162,14 @@ var fetch = (url, options = {}) => {
161
162
  const { status = 0 } = response;
162
163
  const isSuccess = status >= 200 && status < 300;
163
164
  if (!isSuccess) {
165
+ const fallbackMsg = `${errMsgs.requestFailed} ${status}`;
164
166
  const jsonError = await fallbackIfFails2(
165
167
  // try to parse error response as json first
166
168
  () => response.json(),
167
169
  [],
168
- // fallback to text if json parsing fails
169
- `Request failed with status code: ${status}`
170
+ void 0
170
171
  );
171
- const message = (jsonError == null ? void 0 : jsonError.message) || `${errMsgs.requestFailed} ${status}.`;
172
+ const message = (jsonError == null ? void 0 : jsonError.message) || fallbackMsg;
172
173
  throw new Error(`${message}`.replace("Error: ", ""), {
173
174
  cause: jsonError
174
175
  });
@@ -181,23 +182,23 @@ var fetch = (url, options = {}) => {
181
182
  `${errMsgs.parseFailed} ${parseAs}. ${err == null ? void 0 : err.message}`,
182
183
  { cause: err }
183
184
  );
184
- return globalThis.Promise.reject(err);
185
+ return Promise.reject(err);
185
186
  };
186
187
  result = parseFunc.bind(response)();
187
188
  if (isPromise(result)) result = result.catch(handleErr);
188
- result = await executeInterceptors_default(
189
- result,
190
- resultInterceptors,
191
- url,
192
- _options2
193
- );
194
189
  }
190
+ result = await executeInterceptors_default(
191
+ result,
192
+ resultInterceptors,
193
+ url,
194
+ _options2
195
+ );
195
196
  resolve(result);
196
197
  } catch (err) {
197
198
  const errX = err;
198
199
  const msg = (errX == null ? void 0 : errX.name) === "AbortError" ? errMsgs.reqTimedout : err == null ? void 0 : err.message;
199
200
  let error = new FetchError(msg, {
200
- cause: (_b = errX == null ? void 0 : errX.cause) != null ? _b : err,
201
+ cause: (_d = errX == null ? void 0 : errX.cause) != null ? _d : err,
201
202
  response: errResponse,
202
203
  options: _options2,
203
204
  url
@@ -216,7 +217,6 @@ var fetch = (url, options = {}) => {
216
217
  return promise;
217
218
  };
218
219
  fetch.defaults = {
219
- as: "json" /* json */,
220
220
  errMsgs: {
221
221
  invalidUrl: "Invalid URL",
222
222
  parseFailed: "Failed to parse response as",
@@ -237,6 +237,7 @@ fetch.defaults = {
237
237
  response: [],
238
238
  result: []
239
239
  },
240
+ /** Request timeout duration in milliseconds. Default: `0` */
240
241
  timeout: 0
241
242
  };
242
243
  var fetch_default = fetch;
@@ -263,25 +264,37 @@ function fetchDeferred(deferOptions = {}, defaultUrl, defaultOptions) {
263
264
  }
264
265
  var fetchDeferred_default = fetchDeferred;
265
266
 
266
- // src/postDeferred.ts
267
- import PromisE4 from "@superutils/promise";
267
+ // src/createFetchMethodFunc.ts
268
+ var createFetchMethodFunc = (method = "get") => {
269
+ const methodFunc = (...args) => {
270
+ var _a;
271
+ (_a = args[1]) != null ? _a : args[1] = {};
272
+ args[1].method = method;
273
+ return fetch_default(...args);
274
+ };
275
+ methodFunc.deferred = (...args) => {
276
+ var _a;
277
+ (_a = args[2]) != null ? _a : args[2] = {};
278
+ args[2].method = method;
279
+ return fetchDeferred_default(...args);
280
+ };
281
+ return methodFunc;
282
+ };
283
+ var createFetchMethodFunc_default = createFetchMethodFunc;
268
284
 
269
285
  // src/post.ts
270
286
  import { isFn as isFn3, isStr } from "@superutils/core";
271
287
  function post(...[url = "", data, options = {}]) {
272
- return fetch_default(
273
- url,
274
- mergeFetchOptions_default(
275
- {
276
- method: "post",
277
- body: isStr(data) ? data : JSON.stringify(isFn3(data) ? data() : data)
278
- },
279
- options
280
- )
281
- );
288
+ var _a;
289
+ (_a = options.method) != null ? _a : options.method = "post";
290
+ return fetch_default(url, {
291
+ ...options,
292
+ body: isStr(data) ? data : JSON.stringify(isFn3(data) ? data() : data)
293
+ });
282
294
  }
283
295
 
284
296
  // src/postDeferred.ts
297
+ import PromisE4 from "@superutils/promise";
285
298
  function postDeferred(deferOptions = {}, defaultUrl, defaultData, defaultOptions) {
286
299
  let _abortCtrl;
287
300
  const doPost = (...args) => {
@@ -304,21 +317,7 @@ function postDeferred(deferOptions = {}, defaultUrl, defaultData, defaultOptions
304
317
  }
305
318
  var postDeferred_default = postDeferred;
306
319
 
307
- // src/index.ts
308
- var createFetchMethodFunc = (method = "get") => {
309
- const methodFunc = (url, options) => {
310
- options != null ? options : options = {};
311
- options.method = method;
312
- return fetch_default(url, options);
313
- };
314
- methodFunc.deferred = (...args) => {
315
- var _a;
316
- (_a = args[2]) != null ? _a : args[2] = {};
317
- args[2].method = method;
318
- return fetchDeferred_default(...args);
319
- };
320
- return methodFunc;
321
- };
320
+ // src/createPostMethodFunc.ts
322
321
  var createPostMethodFunc = (method = "post") => {
323
322
  const methodFunc = (url, data, options) => {
324
323
  options != null ? options : options = {};
@@ -333,22 +332,45 @@ var createPostMethodFunc = (method = "post") => {
333
332
  };
334
333
  return methodFunc;
335
334
  };
336
- var _get = createFetchMethodFunc("get");
337
- var _head = createFetchMethodFunc("head");
338
- var _options = createFetchMethodFunc("options");
339
- var _delete = createPostMethodFunc("delete");
340
- var _patch = createPostMethodFunc("patch");
341
- var _post = createPostMethodFunc("post");
342
- var _put = createPostMethodFunc("put");
343
- var fetch2 = fetch_default;
344
- fetch2.delete = _delete;
345
- fetch2.get = _get;
346
- fetch2.head = _head;
347
- fetch2.options = _options;
348
- fetch2.patch = _patch;
349
- fetch2.post = _post;
350
- fetch2.put = _put;
351
- var index_default = fetch2;
335
+ var createPostMethodFunc_default = createPostMethodFunc;
336
+
337
+ // src/fetchResponse.ts
338
+ var fetchResponse = (...args) => {
339
+ var _a, _b, _c;
340
+ (_a = args[1]) != null ? _a : args[1] = {};
341
+ (_c = (_b = args[1]).as) != null ? _c : _b.as = "response" /* response */;
342
+ return fetch_default(...args);
343
+ };
344
+ var fetchResponse_default = fetchResponse;
345
+
346
+ // src/fetchDefault.ts
347
+ var _get = createFetchMethodFunc_default("get");
348
+ var _head = createFetchMethodFunc_default("head");
349
+ var _options = createFetchMethodFunc_default("options");
350
+ var _delete = createPostMethodFunc_default("delete");
351
+ var _patch = createPostMethodFunc_default("patch");
352
+ var _post = createPostMethodFunc_default("post");
353
+ var _put = createPostMethodFunc_default("put");
354
+ var fetchDefault = fetchResponse_default;
355
+ Object.defineProperty(fetchDefault, "defaults", {
356
+ get() {
357
+ return fetch_default.defaults;
358
+ },
359
+ set(newDefaults) {
360
+ fetch_default.defaults = newDefaults;
361
+ }
362
+ });
363
+ fetchDefault.delete = _delete;
364
+ fetchDefault.get = _get;
365
+ fetchDefault.head = _head;
366
+ fetchDefault.options = _options;
367
+ fetchDefault.patch = _patch;
368
+ fetchDefault.post = _post;
369
+ fetchDefault.put = _put;
370
+ var fetchDefault_default = fetchDefault;
371
+
372
+ // src/index.ts
373
+ var index_default = fetchDefault_default;
352
374
  export {
353
375
  FetchAs,
354
376
  FetchError,
@@ -357,8 +379,9 @@ export {
357
379
  createFetchMethodFunc,
358
380
  createPostMethodFunc,
359
381
  index_default as default,
360
- fetch2 as fetch,
382
+ fetch,
361
383
  fetchDeferred,
384
+ fetchResponse,
362
385
  mergeFetchOptions,
363
386
  postDeferred
364
387
  };
package/package.json CHANGED
@@ -45,5 +45,5 @@
45
45
  "sideEffects": false,
46
46
  "type": "module",
47
47
  "types": "dist/index.d.ts",
48
- "version": "1.1.7"
48
+ "version": "1.2.0"
49
49
  }