@superutils/fetch 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -9
- package/dist/index.d.ts +104 -54
- package/dist/index.js +159 -163
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -9,8 +9,10 @@ This package enhances the native `fetch` API by providing a streamlined interfac
|
|
|
9
9
|
- Features
|
|
10
10
|
- Installation
|
|
11
11
|
- Usage
|
|
12
|
-
- `fetch(
|
|
13
|
-
- `fetchDeferred(
|
|
12
|
+
- [`fetch()`](#fetch): make HTTP requests just like built-in `fetch()`
|
|
13
|
+
- [`fetchDeferred()`](#fetch-deferred): cancellable and debounced or throttled `fetch()`
|
|
14
|
+
- [`post()`](#post): make post-like requests
|
|
15
|
+
- [`postDeferred()`](#post-deferred) cancellable and debounced or throttled `post()`
|
|
14
16
|
|
|
15
17
|
## Features
|
|
16
18
|
|
|
@@ -39,13 +41,18 @@ Make a simple GET request. No need for `response.json()` or `result.data.theActu
|
|
|
39
41
|
```typescript
|
|
40
42
|
import { fetch } from '@superutils/fetch'
|
|
41
43
|
|
|
42
|
-
const theActualData = await fetch('https://dummyjson.com/products/1'
|
|
44
|
+
const theActualData = await fetch('https://dummyjson.com/products/1', {
|
|
45
|
+
method: 'get', // default
|
|
46
|
+
})
|
|
47
|
+
console.log(theActualData)
|
|
48
|
+
// Alternative:
|
|
49
|
+
const theActualData = await fetch.get('https://dummyjson.com/products/1')
|
|
43
50
|
console.log(theActualData)
|
|
44
51
|
```
|
|
45
52
|
|
|
46
|
-
<div id="
|
|
53
|
+
<div id="fetch-deferred"></div>
|
|
47
54
|
|
|
48
|
-
### `
|
|
55
|
+
### `fetch.get.deferred(deferOptions, url, fetchOptions)`
|
|
49
56
|
|
|
50
57
|
A practical utility that combines `PromisE.deferred()` from the `@superutils/promise` package with `fetch()`. It's perfect for implementing cancellable, debounced, or throttled search inputs.
|
|
51
58
|
|
|
@@ -53,7 +60,7 @@ A practical utility that combines `PromisE.deferred()` from the `@superutils/pro
|
|
|
53
60
|
import { fetchDeferred, ResolveIgnored } from '@superutils/fetch'
|
|
54
61
|
|
|
55
62
|
// Create a debounced search function with a 300ms delay.
|
|
56
|
-
const searchProducts =
|
|
63
|
+
const searchProducts = fetch.get.deferred({
|
|
57
64
|
delayMs: 300, // Debounce delay
|
|
58
65
|
resolveIgnored: ResolveIgnored.WITH_UNDEFINED, // Ignored (aborted) promises will resolve with `undefined`
|
|
59
66
|
})
|
|
@@ -126,8 +133,10 @@ getRandomQuote().then(quote => console.log('Call 3 resolved:', quote.id))
|
|
|
126
133
|
|
|
127
134
|
<div id="post"></div>
|
|
128
135
|
|
|
129
|
-
### `post(url, options)`
|
|
136
|
+
### `fetch.post(url, options)`
|
|
137
|
+
|
|
138
|
+
<div id="post-deferred"></div>
|
|
130
139
|
|
|
131
|
-
|
|
140
|
+
### `fetch.post.deferred(deferOptions, url, postOptions)`
|
|
132
141
|
|
|
133
|
-
|
|
142
|
+
<div id="method-specific"></div>
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as _superutils_promise from '@superutils/promise';
|
|
2
|
-
import { RetryOptions,
|
|
3
|
-
export {
|
|
2
|
+
import { RetryOptions, IPromisE, DeferredAsyncOptions } from '@superutils/promise';
|
|
3
|
+
export { DeferredAsyncOptions, ResolveError, ResolveIgnored } from '@superutils/promise';
|
|
4
4
|
import { ValueOrPromise } from '@superutils/core';
|
|
5
5
|
|
|
6
6
|
type FetchArgs = [url: string | URL, options?: FetchOptions];
|
|
@@ -239,7 +239,7 @@ type FetchOptionsInterceptor = Omit<FetchOptions, 'as' | 'errMsgs' | 'intercepto
|
|
|
239
239
|
errMsgs: Required<FetchErrMsgs>;
|
|
240
240
|
headers: Headers;
|
|
241
241
|
interceptors: Required<FetchInterceptors>;
|
|
242
|
-
} &
|
|
242
|
+
} & FetchRetryOptions;
|
|
243
243
|
/**
|
|
244
244
|
* Result types for specific parsers ("as": FetchAs)
|
|
245
245
|
*/
|
|
@@ -255,7 +255,7 @@ interface FetchResult<T> {
|
|
|
255
255
|
/**
|
|
256
256
|
* Fetch retry options
|
|
257
257
|
*/
|
|
258
|
-
type FetchRetryOptions = Partial<RetryOptions> & {
|
|
258
|
+
type FetchRetryOptions = Omit<Partial<RetryOptions>, 'retry' | 'retryIf'> & {
|
|
259
259
|
/**
|
|
260
260
|
* Maximum number of retries.
|
|
261
261
|
*
|
|
@@ -264,6 +264,7 @@ type FetchRetryOptions = Partial<RetryOptions> & {
|
|
|
264
264
|
* Default: `0`
|
|
265
265
|
*/
|
|
266
266
|
retry?: number;
|
|
267
|
+
retryIf?: null | ((response: Response | undefined, retryCount: number, error?: unknown) => boolean | Promise<boolean>);
|
|
267
268
|
};
|
|
268
269
|
/**
|
|
269
270
|
* Generic fetch interceptor type
|
|
@@ -273,44 +274,48 @@ type PostBody = Record<string, unknown> | BodyInit | null;
|
|
|
273
274
|
type PostArgs = [
|
|
274
275
|
url: string | URL,
|
|
275
276
|
data?: PostBody,
|
|
276
|
-
options?:
|
|
277
|
-
/** Default: `'post'` */
|
|
278
|
-
method?: 'post' | 'put' | 'patch' | 'delete';
|
|
279
|
-
}
|
|
277
|
+
options?: PostOptions
|
|
280
278
|
];
|
|
281
|
-
|
|
282
|
-
type Config = Config$1 & {
|
|
283
|
-
fetchOptions: FetchOptionsInterceptor;
|
|
284
|
-
};
|
|
285
|
-
declare const config: Config;
|
|
286
|
-
|
|
287
279
|
/**
|
|
288
|
-
* A `fetch()` replacement that simplifies data fetching with automatic JSON parsing, request timeouts, retries,
|
|
289
|
-
* and powerful interceptors. It also includes deferred and throttled request capabilities for complex asynchronous
|
|
290
|
-
* control flows.
|
|
291
|
-
*
|
|
292
|
-
* Will reject promise if response status code is not 2xx (200 <= status < 300).
|
|
293
280
|
*
|
|
294
|
-
* @
|
|
295
|
-
* @param options (optional) all built-in `fetch()` options such as "method", "headers" and the additionals below.
|
|
296
|
-
* @param options.abortCtrl (optional) if not provided `AbortController` will be instantiated when `timeout` used.
|
|
297
|
-
* @param options.headers (optional) request headers. Default: `{ 'content-type' : 'application/json'}`
|
|
298
|
-
* @param options.interceptors (optional) request interceptor callbacks. See {@link FetchInterceptors} for details.
|
|
299
|
-
* @param options.method (optional) Default: `"get"`
|
|
300
|
-
* @param options.timeout (optional) duration in milliseconds to abort the request if it takes longer.
|
|
301
|
-
* @param options.parse (optional) specify how to parse the result.
|
|
302
|
-
* Default: {@link FetchAs.json}
|
|
303
|
-
* For raw `Response` use {@link FetchAs.response}
|
|
304
|
-
*
|
|
305
|
-
* @example Make a simple HTTP requests
|
|
281
|
+
* @example
|
|
306
282
|
* ```typescript
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
283
|
+
* // test with types
|
|
284
|
+
* type T1 = PostDeferredCallbackArgs<string | URL, undefined> // expected: [data, options]
|
|
285
|
+
* type T2 = PostDeferredCallbackArgs<undefined, string> // expected: [url, options]
|
|
286
|
+
* type T3 = PostDeferredCallbackArgs // expected: [url, data, options]
|
|
287
|
+
* type T4 = PostDeferredCallbackArgs<string, string> // expected: [options]
|
|
288
|
+
*
|
|
289
|
+
* const data = { name: 'test' }
|
|
290
|
+
* const url = 'https://domain.com'
|
|
291
|
+
* // test with postDeferred()
|
|
292
|
+
* const f1 = postDeferred({}, 'https://domain.com')
|
|
293
|
+
* // expected: [data, options]
|
|
294
|
+
* f1({data: 1}).then(console.log, console.warn)
|
|
295
|
+
*
|
|
296
|
+
* const f2 = postDeferred({}, undefined, 'dome data')
|
|
297
|
+
* // expected: [url, options]
|
|
298
|
+
* f2('https').then(console.log, console.warn)
|
|
299
|
+
*
|
|
300
|
+
* const f3 = postDeferred({})
|
|
301
|
+
* // expected: [url, data, options]
|
|
302
|
+
* f3('https://domain.com').then(console.log, console.warn)
|
|
303
|
+
*
|
|
304
|
+
* const f4 = postDeferred({}, 'url', 'data')
|
|
305
|
+
* // expected: [options]
|
|
306
|
+
* f4().then(console.log, console.warn)
|
|
311
307
|
* ```
|
|
312
308
|
*/
|
|
313
|
-
|
|
309
|
+
type PostDeferredCallbackArgs<TUrl = undefined, TData = undefined, RPA extends unknown[] = Required<PostArgs>> = [TUrl, TData] extends [RPA[0], undefined] ? [data?: PostArgs[1], options?: PostArgs[2]] : [TUrl, TData] extends [undefined, RPA[1]] ? [url: PostArgs[0], options?: PostArgs[2]] : [TUrl, TData] extends [RPA[0], RPA[1]] ? [options?: PostArgs[2]] : PostArgs;
|
|
310
|
+
type PostOptions = Omit<FetchOptions, 'method'> & {
|
|
311
|
+
/** Default: `'post'` */
|
|
312
|
+
method?: 'post' | 'put' | 'patch' | 'delete';
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
declare const fetch$1: {
|
|
316
|
+
<TJSON, TOptions extends FetchOptions = FetchOptions, TReturn = TOptions["as"] extends FetchAs ? FetchResult<TJSON>[TOptions["as"]] : TJSON>(url: string | URL, options?: TOptions): IPromisE<TReturn>;
|
|
317
|
+
defaults: Omit<FetchOptionsInterceptor, "retryIf" | "method">;
|
|
318
|
+
};
|
|
314
319
|
|
|
315
320
|
/**
|
|
316
321
|
* Creates a deferred/throttled version of {@link fetch}, powered by {@link PromisE.deferred}.
|
|
@@ -321,10 +326,11 @@ declare function fetch$1<TJSON, TOptions extends FetchOptions = FetchOptions, TR
|
|
|
321
326
|
* `fetchDeferred` uses this to automatically abort pending requests when a new one is initiated, preventing race conditions and redundant network traffic.
|
|
322
327
|
*
|
|
323
328
|
* @param deferOptions Configuration for the deferred execution behavior (e.g., `delayMs`, `throttle`).
|
|
324
|
-
* See {@link
|
|
325
|
-
* @param
|
|
326
|
-
*
|
|
327
|
-
*
|
|
329
|
+
* See {@link DeferredAsyncOptions} for details.
|
|
330
|
+
* @param globalUrl (optional) If a global URL is `undefined`, returned callback will always require an URL.
|
|
331
|
+
* @param defaultOptions (optional) Default {@link FetchOptions} to be used by the returned function.
|
|
332
|
+
* Default options will be merged with the options provided in the callback.
|
|
333
|
+
* If the same property is provided in both cases, defaults will be overriden by the callback.
|
|
328
334
|
*
|
|
329
335
|
* @example Debounce/Throttle requests for an auto-complete search input
|
|
330
336
|
* ```typescript
|
|
@@ -397,7 +403,7 @@ declare function fetch$1<TJSON, TOptions extends FetchOptions = FetchOptions, TR
|
|
|
397
403
|
* // Console output will show the same quote ID for all three calls.
|
|
398
404
|
* ```
|
|
399
405
|
*/
|
|
400
|
-
declare function fetchDeferred<ThisArg,
|
|
406
|
+
declare function fetchDeferred<ThisArg = unknown, Delay extends number = number, GlobalUrl extends string | URL | undefined = string | URL | undefined, Args extends unknown[] = undefined extends GlobalUrl ? FetchArgs : [options?: FetchOptions]>(deferOptions?: DeferredAsyncOptions<ThisArg, Delay>, globalUrl?: GlobalUrl, defaultOptions?: FetchDeferredArgs[1]): <TResult = unknown>(...args: Args) => _superutils_promise.IPromisE<TResult>;
|
|
401
407
|
|
|
402
408
|
/**
|
|
403
409
|
* Creates a deferred/throttled function for making `POST`, `PUT`, or `PATCH` requests, powered by
|
|
@@ -408,6 +414,16 @@ declare function fetchDeferred<ThisArg, DefaultUrl extends string | URL>(deferOp
|
|
|
408
414
|
* Like `fetchDeferred`, it automatically aborts pending requests when a new one is initiated, ensuring only
|
|
409
415
|
* the most recent or relevant action is executed.
|
|
410
416
|
*
|
|
417
|
+
*
|
|
418
|
+
* @param deferOptions Configuration for the deferred execution behavior (e.g., `delayMs`, `throttle`).
|
|
419
|
+
* See {@link DeferredAsyncOptions} for details.
|
|
420
|
+
* @param globalUrl (optional) If global URL is `undefined`, returned callback will always require an URL.
|
|
421
|
+
* @param globalData (optional) If global data is `undefined`, returned callback will allow a data parameter.
|
|
422
|
+
* @param defaultOptions (optional) Default {@link FetchOptions} to be used by the returned function.
|
|
423
|
+
* Default options will be merged with the options provided in the callback.
|
|
424
|
+
* If the same property is provided in both cases, defaults will be overriden by the callback.
|
|
425
|
+
*
|
|
426
|
+
*
|
|
411
427
|
* @example Debouncing an authentication token refresh
|
|
412
428
|
* ```typescript
|
|
413
429
|
* import { postDeferred } from '@superutils/fetch'
|
|
@@ -485,12 +501,12 @@ declare function fetchDeferred<ThisArg, DefaultUrl extends string | URL>(deferOp
|
|
|
485
501
|
* // This results in only two network requests instead of four.
|
|
486
502
|
* ```
|
|
487
503
|
*/
|
|
488
|
-
declare function postDeferred<ThisArg,
|
|
489
|
-
|
|
490
|
-
|
|
504
|
+
declare function postDeferred<ThisArg, Delay extends number = number, GlobalUrl extends PostArgs[0] | undefined = undefined, GlobalData extends PostArgs[1] | undefined = undefined, Args extends unknown[] = PostDeferredCallbackArgs<GlobalUrl, GlobalData>>(deferOptions?: DeferredAsyncOptions<ThisArg, Delay>, globalUrl?: GlobalUrl, // The default URL for all calls
|
|
505
|
+
globalData?: GlobalData, // The default data for all calls
|
|
506
|
+
defaultOptions?: PostOptions): <TResult = unknown>(...args: Args) => _superutils_promise.IPromisE<TResult>;
|
|
491
507
|
|
|
492
508
|
/**
|
|
493
|
-
* Merge one or more {@link FetchOptions}
|
|
509
|
+
* Merge one or more {@link FetchOptions}
|
|
494
510
|
*
|
|
495
511
|
* Notes:
|
|
496
512
|
* - {@link config.fetchOptions} will be added as the base and not necessary to be included
|
|
@@ -505,16 +521,50 @@ declare function postDeferred<ThisArg, DefaultUrl extends string | URL>(deferOpt
|
|
|
505
521
|
*/
|
|
506
522
|
declare const mergeFetchOptions: (...allOptions: FetchOptions[]) => FetchOptionsInterceptor;
|
|
507
523
|
|
|
508
|
-
type
|
|
509
|
-
|
|
524
|
+
type FetchWithoutMethods = typeof fetch$1;
|
|
525
|
+
/** Describes method-specific fetch-functions that includes `.deferred()` function for deferred/throttled requests */
|
|
526
|
+
type FetchMethodFunc = (<T, Options extends Omit<FetchOptions, 'method'>>(url: string | URL, options?: Options) => ReturnType<typeof fetch$1<T, Options>>) & {
|
|
510
527
|
deferred: typeof fetchDeferred;
|
|
511
|
-
}
|
|
528
|
+
};
|
|
529
|
+
/** Describes method-specific fetch-functions that includes `.deferred()` function for deferred/throttled requests */
|
|
530
|
+
type PostMethodFunc = (<T, Options extends Omit<FetchOptions, 'method'>>(url: string | URL, data?: PostBody, options?: Options) => ReturnType<typeof fetch$1<T, Options>>) & {
|
|
512
531
|
deferred: typeof postDeferred;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
532
|
+
};
|
|
533
|
+
interface FetchWithMethods extends FetchWithoutMethods {
|
|
534
|
+
get: FetchMethodFunc;
|
|
535
|
+
head: FetchMethodFunc;
|
|
536
|
+
options: FetchMethodFunc;
|
|
537
|
+
delete: PostMethodFunc;
|
|
538
|
+
patch: PostMethodFunc;
|
|
539
|
+
post: PostMethodFunc;
|
|
540
|
+
put: PostMethodFunc;
|
|
517
541
|
}
|
|
518
|
-
|
|
542
|
+
/**
|
|
543
|
+
* A `fetch()` replacement that simplifies data fetching with automatic JSON parsing, request timeouts, retries,
|
|
544
|
+
* and powerful interceptors. It also includes deferred and throttled request capabilities for complex asynchronous
|
|
545
|
+
* control flows.
|
|
546
|
+
*
|
|
547
|
+
* Will reject promise if response status code is not 2xx (200 <= status < 300).
|
|
548
|
+
*
|
|
549
|
+
* @param url
|
|
550
|
+
* @param options (optional) all built-in `fetch()` options such as "method", "headers" and the additionals below.
|
|
551
|
+
* @param options.abortCtrl (optional) if not provided `AbortController` will be instantiated when `timeout` used.
|
|
552
|
+
* @param options.headers (optional) request headers. Default: `{ 'content-type' : 'application/json'}`
|
|
553
|
+
* @param options.interceptors (optional) request interceptor callbacks. See {@link FetchInterceptors} for details.
|
|
554
|
+
* @param options.method (optional) Default: `"get"`
|
|
555
|
+
* @param options.timeout (optional) duration in milliseconds to abort the request if it takes longer.
|
|
556
|
+
* @param options.parse (optional) specify how to parse the result.
|
|
557
|
+
* Default: {@link FetchAs.json}
|
|
558
|
+
* For raw `Response` use {@link FetchAs.response}
|
|
559
|
+
*
|
|
560
|
+
* @example Make a simple HTTP requests
|
|
561
|
+
* ```typescript
|
|
562
|
+
* import { fetch } from '@superutils/fetch'
|
|
563
|
+
*
|
|
564
|
+
* // no need for `response.json()` or `result.data.theActualData` drilling
|
|
565
|
+
* fetch('https://dummyjson.com/products/1').then(theActualData => console.log(theActualData))
|
|
566
|
+
* ```
|
|
567
|
+
*/
|
|
568
|
+
declare const fetch: FetchWithMethods;
|
|
519
569
|
|
|
520
|
-
export { type
|
|
570
|
+
export { type FetchArgs, type FetchArgsInterceptor, FetchAs, type FetchConf, type FetchDeferredArgs, type FetchErrMsgs, FetchError, type FetchInterceptorError, type FetchInterceptorRequest, type FetchInterceptorResponse, type FetchInterceptorResult, type FetchInterceptors, type FetchMethodFunc, type FetchOptions, type FetchOptionsInterceptor, type FetchResult, type FetchRetryOptions, type FetchWithMethods, type FetchWithoutMethods, type Interceptor, type PostArgs, type PostBody, type PostDeferredCallbackArgs, type PostMethodFunc, type PostOptions, fetch as default, fetch, fetchDeferred, mergeFetchOptions, postDeferred };
|
package/dist/index.js
CHANGED
|
@@ -1,62 +1,6 @@
|
|
|
1
|
-
// src/config.ts
|
|
2
|
-
import {
|
|
3
|
-
config as promiseConfig
|
|
4
|
-
} from "@superutils/promise";
|
|
5
|
-
|
|
6
|
-
// src/types.ts
|
|
7
|
-
var FetchAs = /* @__PURE__ */ ((FetchAs3) => {
|
|
8
|
-
FetchAs3["arrayBuffer"] = "arrayBuffer";
|
|
9
|
-
FetchAs3["blob"] = "blob";
|
|
10
|
-
FetchAs3["bytes"] = "bytes";
|
|
11
|
-
FetchAs3["formData"] = "formData";
|
|
12
|
-
FetchAs3["json"] = "json";
|
|
13
|
-
FetchAs3["response"] = "response";
|
|
14
|
-
FetchAs3["text"] = "text";
|
|
15
|
-
return FetchAs3;
|
|
16
|
-
})(FetchAs || {});
|
|
17
|
-
var FetchError = class extends Error {
|
|
18
|
-
constructor(message, options) {
|
|
19
|
-
super(message, { cause: options.cause });
|
|
20
|
-
this.name = "FetchError";
|
|
21
|
-
this.options = options.options;
|
|
22
|
-
this.response = options.response;
|
|
23
|
-
this.url = options.url;
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// src/config.ts
|
|
28
|
-
var fetchOptions = {
|
|
29
|
-
as: "json" /* json */,
|
|
30
|
-
errMsgs: {
|
|
31
|
-
invalidUrl: "Invalid URL",
|
|
32
|
-
parseFailed: "Failed to parse response as",
|
|
33
|
-
reqTimedout: "Request timed out",
|
|
34
|
-
requestFailed: "Request failed with status code:"
|
|
35
|
-
},
|
|
36
|
-
// all error messages must be defined here
|
|
37
|
-
headers: new Headers([["content-type", "application/json"]]),
|
|
38
|
-
/** Global interceptors for fetch requests */
|
|
39
|
-
interceptors: {
|
|
40
|
-
/**
|
|
41
|
-
* Global error interceptors to be invoked whenever an exception occurs
|
|
42
|
-
* Returning an
|
|
43
|
-
*/
|
|
44
|
-
error: [],
|
|
45
|
-
/** Interceptors to be invoked before making fetch requests */
|
|
46
|
-
request: [],
|
|
47
|
-
response: [],
|
|
48
|
-
result: []
|
|
49
|
-
},
|
|
50
|
-
...promiseConfig.retryOptions,
|
|
51
|
-
retryIf: null,
|
|
52
|
-
timeout: 0
|
|
53
|
-
};
|
|
54
|
-
var config = promiseConfig;
|
|
55
|
-
config.fetchOptions = fetchOptions;
|
|
56
|
-
var config_default = config;
|
|
57
|
-
|
|
58
1
|
// src/fetch.ts
|
|
59
2
|
import {
|
|
3
|
+
isEmpty as isEmpty2,
|
|
60
4
|
isFn as isFn2,
|
|
61
5
|
isPositiveNumber,
|
|
62
6
|
isPromise,
|
|
@@ -64,35 +8,6 @@ import {
|
|
|
64
8
|
} from "@superutils/core";
|
|
65
9
|
import PromisE2 from "@superutils/promise";
|
|
66
10
|
|
|
67
|
-
// src/mergeFetchOptions.ts
|
|
68
|
-
import { isEmpty, objKeys } from "@superutils/core";
|
|
69
|
-
var mergeFetchOptions = (...allOptions) => allOptions.reduce((o1, o2) => {
|
|
70
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
|
|
71
|
-
const { errMsgs = {}, headers, interceptors: ints1 = {} } = o1;
|
|
72
|
-
const { errMsgs: msgs2 = {}, interceptors: ints2 = {} } = o2;
|
|
73
|
-
o2.headers && new Headers(o2.headers).forEach(
|
|
74
|
-
(value, key) => headers.set(key, value)
|
|
75
|
-
);
|
|
76
|
-
for (const key of objKeys(msgs2)) {
|
|
77
|
-
if (!isEmpty(msgs2[key])) continue;
|
|
78
|
-
errMsgs[key] = msgs2[key];
|
|
79
|
-
}
|
|
80
|
-
return {
|
|
81
|
-
...o1,
|
|
82
|
-
...o2,
|
|
83
|
-
errMsgs,
|
|
84
|
-
headers,
|
|
85
|
-
interceptors: {
|
|
86
|
-
error: (_c = (_b = ints1 == null ? void 0 : ints1.error) == null ? void 0 : _b.concat((_a = ints2 == null ? void 0 : ints2.error) != null ? _a : [])) != null ? _c : [],
|
|
87
|
-
request: (_f = (_e = ints1 == null ? void 0 : ints1.request) == null ? void 0 : _e.concat((_d = ints2 == null ? void 0 : ints2.request) != null ? _d : [])) != null ? _f : [],
|
|
88
|
-
response: (_i = (_h = ints1 == null ? void 0 : ints1.response) == null ? void 0 : _h.concat((_g = ints2 == null ? void 0 : ints2.response) != null ? _g : [])) != null ? _i : [],
|
|
89
|
-
result: (_l = (_k = ints1 == null ? void 0 : ints1.result) == null ? void 0 : _k.concat((_j = ints2 == null ? void 0 : ints2.result) != null ? _j : [])) != null ? _l : []
|
|
90
|
-
},
|
|
91
|
-
timeout: (_n = (_m = o2.timeout) != null ? _m : o1.timeout) != null ? _n : 0
|
|
92
|
-
};
|
|
93
|
-
}, config_default.fetchOptions);
|
|
94
|
-
var mergeFetchOptions_default = mergeFetchOptions;
|
|
95
|
-
|
|
96
11
|
// src/executeInterceptors.ts
|
|
97
12
|
import { fallbackIfFails, isFn } from "@superutils/core";
|
|
98
13
|
var executeInterceptors = async (value, interceptors, ...args) => {
|
|
@@ -110,40 +25,99 @@ var executeInterceptors_default = executeInterceptors;
|
|
|
110
25
|
|
|
111
26
|
// src/getResponse.ts
|
|
112
27
|
import PromisE from "@superutils/promise";
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
28
|
+
import { isPositiveInteger } from "@superutils/core";
|
|
29
|
+
var getResponse = async (...[url, options = {}]) => {
|
|
30
|
+
let attemptCount = 0;
|
|
31
|
+
const doFetch = async () => {
|
|
32
|
+
attemptCount++;
|
|
33
|
+
return globalThis.fetch(url, options).catch(
|
|
34
|
+
(err) => err.message === "Failed to fetch" ? (
|
|
35
|
+
// catch network errors to allow retries
|
|
36
|
+
new Response(null, {
|
|
37
|
+
status: 0,
|
|
38
|
+
statusText: "Network Error"
|
|
39
|
+
})
|
|
40
|
+
) : Promise.reject(err)
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
if (!isPositiveInteger(options.retry)) return doFetch();
|
|
44
|
+
const response = PromisE.retry(doFetch, {
|
|
124
45
|
...options,
|
|
125
|
-
retryIf: (res, count) => {
|
|
46
|
+
retryIf: async (res, count, err) => {
|
|
126
47
|
var _a;
|
|
127
|
-
return
|
|
48
|
+
return (res == null ? void 0 : res.ok) === false || await ((_a = options == null ? void 0 : options.retryIf) == null ? void 0 : _a.call(options, res, count, err)) === true;
|
|
128
49
|
}
|
|
129
|
-
}).catch(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
50
|
+
}).catch(
|
|
51
|
+
(err) => Promise.reject(
|
|
52
|
+
new Error(`Request failed after attempt #${attemptCount}`, {
|
|
53
|
+
cause: err
|
|
54
|
+
})
|
|
55
|
+
)
|
|
56
|
+
);
|
|
134
57
|
return response;
|
|
135
58
|
};
|
|
136
59
|
var getResponse_default = getResponse;
|
|
137
60
|
|
|
61
|
+
// src/mergeFetchOptions.ts
|
|
62
|
+
import { isEmpty, objKeys } from "@superutils/core";
|
|
63
|
+
var mergeFetchOptions = (...allOptions) => allOptions.reduce(
|
|
64
|
+
(o1, o2) => {
|
|
65
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
|
|
66
|
+
const { errMsgs = {}, headers, interceptors: ints1 = {} } = o1;
|
|
67
|
+
const { errMsgs: msgs2 = {}, interceptors: ints2 = {} } = o2;
|
|
68
|
+
o2.headers && new Headers(o2.headers).forEach((value, key) => {
|
|
69
|
+
headers && headers.set(key, value);
|
|
70
|
+
});
|
|
71
|
+
for (const key of objKeys(msgs2)) {
|
|
72
|
+
if (!isEmpty(msgs2[key])) errMsgs[key] = msgs2[key];
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
...o1,
|
|
76
|
+
...o2,
|
|
77
|
+
errMsgs,
|
|
78
|
+
headers,
|
|
79
|
+
interceptors: {
|
|
80
|
+
error: (_c = (_b = ints1 == null ? void 0 : ints1.error) == null ? void 0 : _b.concat((_a = ints2 == null ? void 0 : ints2.error) != null ? _a : [])) != null ? _c : [],
|
|
81
|
+
request: (_f = (_e = ints1 == null ? void 0 : ints1.request) == null ? void 0 : _e.concat((_d = ints2 == null ? void 0 : ints2.request) != null ? _d : [])) != null ? _f : [],
|
|
82
|
+
response: (_i = (_h = ints1 == null ? void 0 : ints1.response) == null ? void 0 : _h.concat((_g = ints2 == null ? void 0 : ints2.response) != null ? _g : [])) != null ? _i : [],
|
|
83
|
+
result: (_l = (_k = ints1 == null ? void 0 : ints1.result) == null ? void 0 : _k.concat((_j = ints2 == null ? void 0 : ints2.result) != null ? _j : [])) != null ? _l : []
|
|
84
|
+
},
|
|
85
|
+
timeout: (_n = (_m = o2.timeout) != null ? _m : o1.timeout) != null ? _n : 0
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
{ headers: new Headers() }
|
|
89
|
+
);
|
|
90
|
+
var mergeFetchOptions_default = mergeFetchOptions;
|
|
91
|
+
|
|
92
|
+
// src/types.ts
|
|
93
|
+
var FetchAs = /* @__PURE__ */ ((FetchAs2) => {
|
|
94
|
+
FetchAs2["arrayBuffer"] = "arrayBuffer";
|
|
95
|
+
FetchAs2["blob"] = "blob";
|
|
96
|
+
FetchAs2["bytes"] = "bytes";
|
|
97
|
+
FetchAs2["formData"] = "formData";
|
|
98
|
+
FetchAs2["json"] = "json";
|
|
99
|
+
FetchAs2["response"] = "response";
|
|
100
|
+
FetchAs2["text"] = "text";
|
|
101
|
+
return FetchAs2;
|
|
102
|
+
})(FetchAs || {});
|
|
103
|
+
var FetchError = class extends Error {
|
|
104
|
+
constructor(message, options) {
|
|
105
|
+
super(message, { cause: options.cause });
|
|
106
|
+
this.name = "FetchError";
|
|
107
|
+
this.options = options.options;
|
|
108
|
+
this.response = options.response;
|
|
109
|
+
this.url = options.url;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
138
113
|
// src/fetch.ts
|
|
139
|
-
|
|
140
|
-
var _a;
|
|
114
|
+
var fetch = (url, options = {}) => {
|
|
141
115
|
let abortCtrl;
|
|
142
116
|
let timeoutId;
|
|
143
|
-
(_a = options.method) != null ? _a : options.method = "get";
|
|
144
117
|
const promise = new PromisE2(async (resolve, reject) => {
|
|
145
|
-
var
|
|
146
|
-
const _options = mergeFetchOptions_default(options);
|
|
118
|
+
var _a, _b;
|
|
119
|
+
const _options = mergeFetchOptions_default(defaults, options);
|
|
120
|
+
if (isEmpty2(_options.method)) _options.method = "get";
|
|
147
121
|
const errorInterceptors = [..._options.interceptors.error];
|
|
148
122
|
const requestInterceptors = [..._options.interceptors.request];
|
|
149
123
|
const responseInterceptors = [..._options.interceptors.response];
|
|
@@ -151,10 +125,10 @@ function fetch(url, options = {}) {
|
|
|
151
125
|
url = await executeInterceptors_default(url, requestInterceptors, url, _options);
|
|
152
126
|
const { as: parseAs, errMsgs, timeout } = _options;
|
|
153
127
|
if (isPositiveNumber(timeout)) {
|
|
154
|
-
(
|
|
128
|
+
(_a = _options.abortCtrl) != null ? _a : _options.abortCtrl = new AbortController();
|
|
155
129
|
timeoutId = setTimeout(() => {
|
|
156
|
-
var
|
|
157
|
-
return (
|
|
130
|
+
var _a2;
|
|
131
|
+
return (_a2 = _options.abortCtrl) == null ? void 0 : _a2.abort();
|
|
158
132
|
}, timeout);
|
|
159
133
|
}
|
|
160
134
|
abortCtrl = _options.abortCtrl;
|
|
@@ -183,12 +157,12 @@ function fetch(url, options = {}) {
|
|
|
183
157
|
const parseFunc = response[parseAs];
|
|
184
158
|
if (isFn2(parseFunc)) {
|
|
185
159
|
const handleErr = (err) => {
|
|
186
|
-
var
|
|
160
|
+
var _a2, _b2;
|
|
187
161
|
err = new Error(
|
|
188
162
|
[
|
|
189
163
|
errMsgs.parseFailed,
|
|
190
164
|
parseAs + ".",
|
|
191
|
-
(_b2 = `${(
|
|
165
|
+
(_b2 = `${(_a2 = err == null ? void 0 : err.message) != null ? _a2 : err}`) == null ? void 0 : _b2.replace("Error: ", "")
|
|
192
166
|
].join(" "),
|
|
193
167
|
{ cause: err }
|
|
194
168
|
);
|
|
@@ -227,32 +201,54 @@ function fetch(url, options = {}) {
|
|
|
227
201
|
});
|
|
228
202
|
promise.onEarlyFinalize.push(() => abortCtrl == null ? void 0 : abortCtrl.abort());
|
|
229
203
|
return promise;
|
|
230
|
-
}
|
|
204
|
+
};
|
|
205
|
+
var defaults = {
|
|
206
|
+
as: "json" /* json */,
|
|
207
|
+
errMsgs: {
|
|
208
|
+
invalidUrl: "Invalid URL",
|
|
209
|
+
parseFailed: "Failed to parse response as",
|
|
210
|
+
reqTimedout: "Request timed out",
|
|
211
|
+
requestFailed: "Request failed with status code:"
|
|
212
|
+
},
|
|
213
|
+
// all error messages must be defined here
|
|
214
|
+
headers: new Headers([["content-type", "application/json"]]),
|
|
215
|
+
/** Global interceptors for fetch requests */
|
|
216
|
+
interceptors: {
|
|
217
|
+
/**
|
|
218
|
+
* Global error interceptors to be invoked whenever an exception occurs
|
|
219
|
+
* Returning an
|
|
220
|
+
*/
|
|
221
|
+
error: [],
|
|
222
|
+
/** Interceptors to be invoked before making fetch requests */
|
|
223
|
+
request: [],
|
|
224
|
+
response: [],
|
|
225
|
+
result: []
|
|
226
|
+
},
|
|
227
|
+
timeout: 0
|
|
228
|
+
};
|
|
229
|
+
fetch.defaults = defaults;
|
|
231
230
|
var fetch_default = fetch;
|
|
232
231
|
|
|
233
232
|
// src/fetchDeferred.ts
|
|
234
|
-
import { forceCast } from "@superutils/core";
|
|
235
233
|
import PromisE3 from "@superutils/promise";
|
|
236
234
|
import {
|
|
237
235
|
ResolveError,
|
|
238
236
|
ResolveIgnored
|
|
239
237
|
} from "@superutils/promise";
|
|
240
|
-
function fetchDeferred(deferOptions = {},
|
|
238
|
+
function fetchDeferred(deferOptions = {}, globalUrl, defaultOptions) {
|
|
241
239
|
let _abortCtrl;
|
|
242
240
|
const fetchCallback = (...args) => {
|
|
243
|
-
var _a, _b;
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
_abortCtrl == null ? void 0 : _abortCtrl.abort();
|
|
250
|
-
_abortCtrl = abortCtrl;
|
|
241
|
+
var _a, _b, _c;
|
|
242
|
+
let options = {
|
|
243
|
+
...(_a = globalUrl === void 0 ? args[1] : args[0]) != null ? _a : {}
|
|
244
|
+
};
|
|
245
|
+
if (defaultOptions) options = mergeFetchOptions_default(defaultOptions, options);
|
|
246
|
+
(_b = options.abortCtrl) != null ? _b : options.abortCtrl = new AbortController();
|
|
247
|
+
(_c = _abortCtrl == null ? void 0 : _abortCtrl.abort) == null ? void 0 : _c.call(_abortCtrl);
|
|
248
|
+
_abortCtrl = options.abortCtrl;
|
|
251
249
|
const promise = fetch_default(
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
mergeFetchOptions_default(defaultOptions != null ? defaultOptions : {}, options)
|
|
255
|
-
])
|
|
250
|
+
globalUrl != null ? globalUrl : args[0],
|
|
251
|
+
options
|
|
256
252
|
);
|
|
257
253
|
promise.onEarlyFinalize.push(() => _abortCtrl == null ? void 0 : _abortCtrl.abort());
|
|
258
254
|
return promise;
|
|
@@ -262,7 +258,6 @@ function fetchDeferred(deferOptions = {}, defaultUrl, defaultOptions) {
|
|
|
262
258
|
var fetchDeferred_default = fetchDeferred;
|
|
263
259
|
|
|
264
260
|
// src/postDeferred.ts
|
|
265
|
-
import { forceCast as forceCast2 } from "@superutils/core";
|
|
266
261
|
import PromisE4 from "@superutils/promise";
|
|
267
262
|
|
|
268
263
|
// src/post.ts
|
|
@@ -285,21 +280,22 @@ import {
|
|
|
285
280
|
ResolveError as ResolveError2,
|
|
286
281
|
ResolveIgnored as ResolveIgnored2
|
|
287
282
|
} from "@superutils/promise";
|
|
288
|
-
function postDeferred(deferOptions = {},
|
|
283
|
+
function postDeferred(deferOptions = {}, globalUrl, globalData, defaultOptions) {
|
|
289
284
|
let _abortCtrl;
|
|
290
|
-
const doPost = (...
|
|
291
|
-
var _a;
|
|
292
|
-
(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
data != null ? data : defaultData,
|
|
300
|
-
mergedOptions
|
|
301
|
-
])
|
|
285
|
+
const doPost = (...args) => {
|
|
286
|
+
var _a, _b, _c;
|
|
287
|
+
if (globalUrl !== void 0) args.splice(0, 0, globalUrl);
|
|
288
|
+
if (globalData !== void 0) args.splice(1, 0, globalData);
|
|
289
|
+
const url = args[0];
|
|
290
|
+
const data = args[1];
|
|
291
|
+
const options = mergeFetchOptions_default(
|
|
292
|
+
defaultOptions != null ? defaultOptions : {},
|
|
293
|
+
(_a = args[2]) != null ? _a : {}
|
|
302
294
|
);
|
|
295
|
+
(_b = options.abortCtrl) != null ? _b : options.abortCtrl = new AbortController();
|
|
296
|
+
(_c = _abortCtrl == null ? void 0 : _abortCtrl.abort) == null ? void 0 : _c.call(_abortCtrl);
|
|
297
|
+
_abortCtrl = options.abortCtrl;
|
|
298
|
+
const promise = post(url, data, options);
|
|
303
299
|
promise.onEarlyFinalize.push(() => _abortCtrl == null ? void 0 : _abortCtrl.abort());
|
|
304
300
|
return promise;
|
|
305
301
|
};
|
|
@@ -308,37 +304,37 @@ function postDeferred(deferOptions = {}, defaultUrl, defaultData, defaultOptions
|
|
|
308
304
|
var postDeferred_default = postDeferred;
|
|
309
305
|
|
|
310
306
|
// src/index.ts
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
307
|
+
import { isObj } from "@superutils/core";
|
|
308
|
+
var createFetchMethodFunc = (method = "get") => {
|
|
309
|
+
const methodFunc = ((url, options) => {
|
|
310
|
+
const _options = isObj(options) ? options : {};
|
|
311
|
+
_options.method = method;
|
|
312
|
+
return fetch_default(url, _options);
|
|
316
313
|
});
|
|
317
|
-
methodFunc.deferred = (...args) => fetchDeferred_default(...args);
|
|
314
|
+
methodFunc.deferred = ((...args) => fetchDeferred_default(...args));
|
|
318
315
|
return methodFunc;
|
|
319
316
|
};
|
|
320
|
-
var
|
|
321
|
-
const methodFunc = ((url, options
|
|
322
|
-
;
|
|
323
|
-
|
|
324
|
-
return post(url,
|
|
317
|
+
var createPostMethodFunc = (method = "post") => {
|
|
318
|
+
const methodFunc = ((url, data, options) => {
|
|
319
|
+
const _options = isObj(options) ? options : {};
|
|
320
|
+
_options.method = method;
|
|
321
|
+
return post(url, data, _options);
|
|
325
322
|
});
|
|
326
|
-
methodFunc.deferred = (...args) => postDeferred_default(...args);
|
|
323
|
+
methodFunc.deferred = ((...args) => postDeferred_default(...args));
|
|
327
324
|
return methodFunc;
|
|
328
325
|
};
|
|
329
326
|
var fetch2 = fetch_default;
|
|
330
|
-
fetch2.get =
|
|
331
|
-
fetch2.head =
|
|
332
|
-
fetch2.
|
|
333
|
-
fetch2.delete =
|
|
334
|
-
fetch2.patch =
|
|
335
|
-
fetch2.post =
|
|
336
|
-
fetch2.put =
|
|
327
|
+
fetch2.get = createFetchMethodFunc("get");
|
|
328
|
+
fetch2.head = createFetchMethodFunc("head");
|
|
329
|
+
fetch2.options = createFetchMethodFunc("options");
|
|
330
|
+
fetch2.delete = createPostMethodFunc("delete");
|
|
331
|
+
fetch2.patch = createPostMethodFunc("patch");
|
|
332
|
+
fetch2.post = createPostMethodFunc("post");
|
|
333
|
+
fetch2.put = createPostMethodFunc("put");
|
|
337
334
|
var index_default = fetch2;
|
|
338
335
|
export {
|
|
339
336
|
FetchAs,
|
|
340
337
|
FetchError,
|
|
341
|
-
config,
|
|
342
338
|
index_default as default,
|
|
343
339
|
fetch2 as fetch,
|
|
344
340
|
fetchDeferred,
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Toufiqur Rahaman Chowdhury",
|
|
3
|
-
"description": "
|
|
3
|
+
"description": "A lightweight `fetch` wrapper for browsers and Node.js, designed to simplify data fetching and reduce boilerplate.",
|
|
4
4
|
"dependencies": {
|
|
5
|
-
"@superutils/core": "^1.0.
|
|
6
|
-
"@superutils/promise": "^1.0.
|
|
5
|
+
"@superutils/core": "^1.0.5",
|
|
6
|
+
"@superutils/promise": "^1.0.5"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
9
|
"dist",
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"main": "dist/index.js",
|
|
21
21
|
"name": "@superutils/fetch",
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"@superutils/core": "^1.0.
|
|
24
|
-
"@superutils/promise": "^1.0.
|
|
23
|
+
"@superutils/core": "^1.0.5",
|
|
24
|
+
"@superutils/promise": "^1.0.5"
|
|
25
25
|
},
|
|
26
26
|
"publishConfig": {
|
|
27
27
|
"access": "public"
|
|
@@ -31,10 +31,11 @@
|
|
|
31
31
|
"_watch": "tsc -p tsconfig.json --watch",
|
|
32
32
|
"build": "tsup src/index.ts --format esm --dts --clean --config ../../tsup.config.js",
|
|
33
33
|
"dev": "npm run build -- --watch",
|
|
34
|
-
"
|
|
34
|
+
"start": "npm run build -- --watch",
|
|
35
|
+
"test": "cd ../../ && npm run test fetch"
|
|
35
36
|
},
|
|
36
37
|
"sideEffects": false,
|
|
37
38
|
"type": "module",
|
|
38
39
|
"types": "dist/index.d.ts",
|
|
39
|
-
"version": "
|
|
40
|
+
"version": "1.0.0"
|
|
40
41
|
}
|