@superutils/fetch 1.0.1 → 1.0.2

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
@@ -11,9 +11,9 @@ This package enhances the native `fetch` API by providing a streamlined interfac
11
11
  - Usage
12
12
  - [`fetch()`](#fetch): make HTTP requests just like built-in `fetch()`
13
13
  - [`Method Specific Functions`](#methods)
14
- - [`fetchDeferred()`](#fetch-deferred): cancellable and debounced or throttled `fetch()`
15
- - [`post()`](#post): make post-like requests
16
- - [`postDeferred()`](#post-deferred) cancellable and debounced or throttled `post()`
14
+ - [`fetch.get.deferred()`](#fetch-deferred): cancellable and debounced or throttled `fetch()`
15
+ - [`fetch.post()`](#post): make post requests
16
+ - [`fetch.post.deferred()`](#post-deferred) cancellable and debounced or throttled `post()`
17
17
 
18
18
  ## Features
19
19
 
@@ -47,8 +47,8 @@ const theActualData = await fetch('https://dummyjson.com/products/1', {
47
47
  })
48
48
  console.log(theActualData)
49
49
  // Alternative:
50
- const theActualData = await fetch.get('https://dummyjson.com/products/1')
51
- console.log(theActualData)
50
+ const theActualData2 = await fetch.get('https://dummyjson.com/products/1')
51
+ console.log(theActualData2)
52
52
  ```
53
53
 
54
54
  <div id="methods"></div>
@@ -124,7 +124,11 @@ setTimeout(() => {
124
124
  of the final "iphone 9" request. Both promises resolve to the same value.
125
125
  3. `ResolveIgnored.NEVER`: The promise for the aborted "iphone" request is neither resolved nor rejected.
126
126
  It will remain pending indefinitely.
127
- 4. `ResolveIgnored.WITH_ERROR`: The promise for the aborted "iphone" request is rejected with a `FetchError`.
127
+ - **`resolveError`**: Controls how failed requests are handled.
128
+ 1. `ResolveError.NEVER`: Never resolve ignored promises. Caution: make sure this doesn't cause any memory leaks.
129
+ 2. `ResolveError.WITH_LAST`: (default) resolve with active promise result, the one that caused the current promise/callback to be ignored.
130
+ 3. `ResolveError.WITH_UNDEFINED`: resolve failed requests with `undefined` value
131
+ 4. `ResolveError.WITH_ERROR`: The promise for the aborted "iphone" request is rejected with a `FetchError`.
128
132
 
129
133
  #### Using defaults to reduce redundancy
130
134
 
@@ -160,8 +164,107 @@ getRandomQuote().then(quote => console.log('Call 3 resolved:', quote.id))
160
164
 
161
165
  ### `fetch.post(url, options)`
162
166
 
167
+ Send a POST request to create a new product and receive the parsed JSON response.
168
+
169
+ ```javascript
170
+ import fetch from '@superutils/fetch'
171
+
172
+ const newProduct = { title: 'Perfume Oil' }
173
+
174
+ fetch.post('https://dummyjson.com/products/add', newProduct).then(
175
+ createdProduct => console.log('Product created:', createdProduct),
176
+ error => console.error('Failed to create product:', error),
177
+ )
178
+ ```
179
+
163
180
  <div id="post-deferred"></div>
164
181
 
165
- ### `fetch.post.deferred(deferOptions, url, postOptions)`
182
+ ### `fetch.post.deferred(deferOptions, url, data, options)`
183
+
184
+ HTTP POST request with debounce/throttle.
185
+
186
+ #### Example 1: Auto-saving form data with throttling
187
+
188
+ ```typescript
189
+ import fetch from '@superutils/fetch'
190
+ import PromisE from '@superutils/promise'
191
+
192
+ // Create a throttled function to auto-save product updates.
193
+ const saveProductThrottled = fetch.post.deferred(
194
+ {
195
+ delayMs: 1000, // Throttle window of 1 second
196
+ throttle: true,
197
+ trailing: true, // Ensures the very last update is always saved
198
+ onResult: product => console.log(`[Saved] Product: ${product.title}`),
199
+ },
200
+ 'https://dummyjson.com/products/1', // Default URL
201
+ undefined, // No default data
202
+ { method: 'put' }, // Default method
203
+ )
204
+ // Simulate a user typing quickly, triggering multiple saves.
205
+ console.log('User starts typing...')
206
+ saveProductThrottled({ title: 'iPhone' }) // Executed immediately (leading edge)
207
+ await PromisE.delay(200)
208
+ saveProductThrottled({ title: 'iPhone 15' }) // Ignored (within 1000ms throttle window)
209
+ await PromisE.delay(300)
210
+ saveProductThrottled({ title: 'iPhone 15 Pro' }) // Ignored
211
+ await PromisE.delay(400)
212
+ saveProductThrottled({ title: 'iPhone 15 Pro Max' }) // Queued to execute on the trailing edge
213
+ // Outcome:
214
+ // The first call ('iPhone') is executed immediately.
215
+ // The next two calls are ignored by the throttle.
216
+ // The final call ('iPhone 15 Pro Max') is executed after the 1000ms throttle window closes,
217
+ // thanks to `trailing: true`.
218
+ // This results in only two network requests instead of four.
219
+ ```
220
+
221
+ #### Example 2: debouncing an authentication token refresh
166
222
 
167
- <div id="method-specific"></div>
223
+ ```typescript
224
+ import fetch from '@superutils/fetch'
225
+ import PromisE from '@superutils/promise'
226
+
227
+ // Mock a simple token store
228
+ let currentRefreshToken = ''
229
+ // Create a debounced function to refresh the auth token.
230
+ // It waits 300ms after the last call before executing.
231
+ const requestNewToken = fetch.post.deferred(
232
+ {
233
+ delayMs: 300, // debounce delay
234
+ onResult: ({ token = '' }) => {
235
+ console.log(
236
+ `Auth token successfully refreshed at ${new Date().toISOString()}`,
237
+ )
238
+ currentRefreshToken = token
239
+ },
240
+ },
241
+ 'https://dummyjson.com/auth/refresh', // Default URL
242
+ () => ({
243
+ refreshToken: currentRefreshToken,
244
+ expiresInMins: 30,
245
+ }),
246
+ )
247
+
248
+ // First authenticate user to get the initial refresh token and then request new referesh tokens
249
+ fetch
250
+ .post<{ refreshToken: string }>(
251
+ 'https://dummyjson.com/auth/login',
252
+ {
253
+ username: 'emilys',
254
+ password: 'emilyspass',
255
+ expiresInMins: 30,
256
+ },
257
+ { credentials: 'include' },
258
+ )
259
+ .then(result => {
260
+ currentRefreshToken = result?.refreshToken
261
+
262
+ requestNewToken() // Called at 0ms
263
+ PromisE.delay(50, requestNewToken) // Called at 50ms
264
+ PromisE.delay(100, requestNewToken) // Called at 100ms
265
+ }, console.error)
266
+ // Outcome:
267
+ // The first two calls are aborted by the debounce mechanism.
268
+ // Only the final call executes, 300ms after it was made (at the 400ms mark).
269
+ // The token is refreshed only once, preventing redundant network requests.
270
+ ```
package/dist/index.d.ts CHANGED
@@ -1,9 +1,12 @@
1
+ import { ValueOrPromise } from '@superutils/core';
1
2
  import * as _superutils_promise from '@superutils/promise';
2
3
  import { RetryOptions, IPromisE, DeferredAsyncOptions } from '@superutils/promise';
3
4
  export { DeferredAsyncOptions, ResolveError, ResolveIgnored } from '@superutils/promise';
4
- import { ValueOrPromise } from '@superutils/core';
5
5
 
6
- type FetchArgs = [url: string | URL, options?: FetchOptions];
6
+ type FetchArgs<OmitMethod extends boolean = false> = [
7
+ url: string | URL,
8
+ options?: OmitMethod extends true ? Omit<FetchOptions, 'method'> : FetchOptions
9
+ ];
7
10
  type FetchArgsInterceptor = [
8
11
  url: string | URL,
9
12
  options: FetchOptionsInterceptor
@@ -31,9 +34,9 @@ type FetchCustomOptions = {
31
34
  timeout?: number;
32
35
  } & FetchRetryOptions;
33
36
  /** Default args */
34
- type FetchDeferredArgs = [
37
+ type FetchDeferredArgs<OmitMethod extends boolean = false> = [
35
38
  url?: string | URL,
36
- options?: Omit<FetchOptions, 'abortCtrl'>
39
+ options?: Omit<FetchOptions, 'abortCtrl' | (OmitMethod extends true ? 'method' : never)>
37
40
  ];
38
41
  type FetchErrMsgs = {
39
42
  invalidUrl?: string;
@@ -273,10 +276,10 @@ type FetchRetryOptions = Omit<Partial<RetryOptions>, 'retry' | 'retryIf'> & {
273
276
  */
274
277
  type Interceptor<T, TArgs extends unknown[], TArgsCb extends unknown[] = [value: T, ...TArgs]> = (...args: TArgsCb) => ValueOrPromise<void> | ValueOrPromise<T>;
275
278
  type PostBody = Record<string, unknown> | BodyInit | null;
276
- type PostArgs = [
279
+ type PostArgs<OmitMethod = false> = [
277
280
  url: string | URL,
278
- data?: PostBody,
279
- options?: PostOptions
281
+ data?: PostBody | (() => PostBody),
282
+ options?: OmitMethod extends true ? Omit<FetchOptions, 'method'> : PostOptions
280
283
  ];
281
284
  /**
282
285
  *
@@ -308,10 +311,10 @@ type PostArgs = [
308
311
  * f4().then(console.log, console.warn)
309
312
  * ```
310
313
  */
311
- 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;
314
+ type PostDeferredCallbackArgs<TUrl = undefined, TData = undefined, OmitMethod extends boolean = true, CbArgs extends PostArgs<OmitMethod> = PostArgs<OmitMethod>, Options = CbArgs[2], RPA extends unknown[] = Required<CbArgs>> = [TUrl, TData] extends [RPA[0], undefined] ? [data?: CbArgs[1], options?: Options] : [TUrl, TData] extends [undefined, RPA[1]] ? [url: CbArgs[0], options?: Options] : [TUrl, TData] extends [RPA[0], RPA[1]] ? [options?: Options] : CbArgs;
312
315
  type PostOptions = Omit<FetchOptions, 'method'> & {
313
316
  /** Default: `'post'` */
314
- method?: 'post' | 'put' | 'patch' | 'delete';
317
+ method?: 'post' | 'put' | 'patch' | 'delete' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
315
318
  };
316
319
 
317
320
  declare const fetch$1: {
@@ -406,18 +409,18 @@ declare const fetch$1: {
406
409
  * // Console output will show the same quote ID for all three calls.
407
410
  * ```
408
411
  */
409
- 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>;
412
+ declare function fetchDeferred<ThisArg = unknown, Delay extends number = number, GlobalUrl = FetchArgs[0] | undefined, CbArgs extends unknown[] = undefined extends GlobalUrl ? FetchArgs<true> : [options?: FetchArgs<true>[1]]>(deferOptions?: DeferredAsyncOptions<ThisArg, Delay>, globalUrl?: GlobalUrl, defaultOptions?: FetchArgs[1]): <TResult = unknown>(...args: CbArgs) => _superutils_promise.IPromisE<TResult>;
410
413
 
411
414
  /**
412
- * Creates a deferred/throttled function for making `POST`, `PUT`, or `PATCH` requests, powered by
415
+ * Creates a deferred/throttled function for making `DELETE`, `POST`, `PUT`, or `PATCH` requests, powered by
413
416
  * {@link PromisE.deferred}.
417
+ *
414
418
  * This is ideal for scenarios like auto-saving form data, preventing duplicate submissions on button clicks,
415
419
  * or throttling API updates.
416
420
  *
417
421
  * Like `fetchDeferred`, it automatically aborts pending requests when a new one is initiated, ensuring only
418
422
  * the most recent or relevant action is executed.
419
423
  *
420
- *
421
424
  * @param deferOptions Configuration for the deferred execution behavior (e.g., `delayMs`, `throttle`).
422
425
  * See {@link DeferredAsyncOptions} for details.
423
426
  * @param globalUrl (optional) If global URL is `undefined`, returned callback will always require an URL.
@@ -427,86 +430,87 @@ declare function fetchDeferred<ThisArg = unknown, Delay extends number = number,
427
430
  * If the same property is provided in both cases, defaults will be overriden by the callback.
428
431
  *
429
432
  *
430
- * @example Debouncing an authentication token refresh
431
- * ```typescript
433
+ *
434
+ * @example Auto-saving form data with throttling
435
+ * ```javascript
432
436
  * import { postDeferred } from '@superutils/fetch'
433
437
  * import PromisE from '@superutils/promise'
434
438
  *
435
- * // Mock a simple token store
436
- * let currentRefreshToken = 'initial-refresh-token'
439
+ * // Create a throttled function to auto-save product updates.
440
+ * const saveProductThrottled = fetch.post.deferred(
441
+ * {
442
+ * delayMs: 1000, // Throttle window of 1 second
443
+ * throttle: true,
444
+ * trailing: true, // Ensures the very last update is always saved
445
+ * onResult: product => console.log(`[Saved] Product: ${product.title}`),
446
+ * },
447
+ * 'https://dummyjson.com/products/1', // Default URL
448
+ * undefined, // No default data
449
+ * { method: 'put' }, // Default method
450
+ * )
451
+ * // Simulate a user typing quickly, triggering multiple saves.
452
+ * console.log('User starts typing...')
453
+ * // First call
454
+ * saveProductThrottled({ title: 'iPhone' }) // Executed immediately (leading edge)
455
+ * // Second call after 200ms => Ignored (within 1000ms throttle window)
456
+ * PromisE.delay(200, () => saveProductThrottled({ title: 'iPhone 15' }))
457
+ * // Third call 300ms after second call => Ignored
458
+ * PromisE.delay(500, () => saveProductThrottled({ title: 'iPhone 15 Pro' }))
459
+ * // Fourth call 400ms after third call => Queued to execute on the trailing edge
460
+ * PromisE.delay(900, () => saveProductThrottled({ title: 'iPhone 15 Pro Max' }))
461
+ * ```
437
462
  *
463
+ * @example Advanced example: debouncing an authentication token refresh
464
+ * ```typescript
465
+ * import fetch from '@superutils/fetch'
466
+ * import PromisE from '@superutils/promise'
467
+ *
468
+ * // Mock a simple token store
469
+ * let currentRefreshToken = ''
438
470
  * // Create a debounced function to refresh the auth token.
439
471
  * // It waits 300ms after the last call before executing.
440
- * const refreshAuthToken = postDeferred(
472
+ * const requestNewToken = fetch.post.deferred(
441
473
  * {
442
474
  * delayMs: 300, // debounce delay
443
- * onResult: (result: { token: string }) => {
444
- * console.log(`Auth token successfully refreshed at ${new Date().toISOString()}`)
445
- * currentRefreshToken = result.token
446
- * },
475
+ * onResult: ({ token = '' }) => {
476
+ * console.log(
477
+ * `Auth token successfully refreshed at ${new Date().toISOString()}`,
478
+ * )
479
+ * currentRefreshToken = token
480
+ * },
447
481
  * },
448
482
  * 'https://dummyjson.com/auth/refresh', // Default URL
483
+ * () => ({
484
+ * refreshToken: currentRefreshToken,
485
+ * expiresInMins: 30,
486
+ * }),
449
487
  * )
450
488
  *
451
- * // This function would be called from various parts of an app,
452
- * // for example, in response to multiple failed API calls.
453
- * function requestNewToken() {
454
- * const body = {
455
- * refreshToken: currentRefreshToken,
456
- * expiresInMins: 30,
457
- * }
458
- * refreshAuthToken(body)
459
- * }
460
- *
461
- * requestNewToken() // Called at 0ms
462
- * PromisE.delay(50, requestNewToken) // Called at 50ms
463
- * PromisE.delay(100, requestNewToken) // Called at 100ms
464
- *
489
+ * // First authenticate user to get the initial refresh token and then request new referesh tokens
490
+ * fetch
491
+ * .post<{ refreshToken: string }>(
492
+ * 'https://dummyjson.com/auth/login',
493
+ * {
494
+ * username: 'emilys',
495
+ * password: 'emilyspass',
496
+ * expiresInMins: 30,
497
+ * },
498
+ * { credentials: 'include' },
499
+ * )
500
+ * .then(result => {
501
+ * currentRefreshToken = result?.refreshToken
502
+ *
503
+ * requestNewToken() // Called at 0ms
504
+ * PromisE.delay(50, requestNewToken) // Called at 50ms
505
+ * PromisE.delay(100, requestNewToken) // Called at 100ms
506
+ * }, console.error)
465
507
  * // Outcome:
466
508
  * // The first two calls are aborted by the debounce mechanism.
467
509
  * // Only the final call executes, 300ms after it was made (at the 400ms mark).
468
510
  * // The token is refreshed only once, preventing redundant network requests.
469
511
  * ```
470
- *
471
- * @example Auto-saving form data with throttling
472
- * ```typescript
473
- * import { postDeferred } from '@superutils/fetch'
474
- * import PromisE from '@superutils/promise'
475
- *
476
- * // Create a throttled function to auto-save product updates.
477
- * const saveProductThrottled = postDeferred(
478
- * {
479
- * delayMs: 1000, // Throttle window of 1 second
480
- * throttle: true,
481
- * trailing: true, // Ensures the very last update is always saved
482
- * onResult: (product) => console.log(`[Saved] Product: ${product.title}`),
483
- * },
484
- * 'https://dummyjson.com/products/1', // Default URL
485
- * undefined, // No default data
486
- * { method: 'put' }, // Default method
487
- * )
488
- *
489
- * // Simulate a user typing quickly, triggering multiple saves.
490
- * console.log('User starts typing...');
491
- * saveProductThrottled({ title: 'iPhone' }); // Executed immediately (leading edge)
492
- * await PromisE.delay(200);
493
- * saveProductThrottled({ title: 'iPhone 15' }); // Ignored (within 1000ms throttle window)
494
- * await PromisE.delay(300);
495
- * saveProductThrottled({ title: 'iPhone 15 Pro' }); // Ignored
496
- * await PromisE.delay(400);
497
- * saveProductThrottled({ title: 'iPhone 15 Pro Max' }); // Queued to execute on the trailing edge
498
- *
499
- * // Outcome:
500
- * // The first call ('iPhone') is executed immediately.
501
- * // The next two calls are ignored by the throttle.
502
- * // The final call ('iPhone 15 Pro Max') is executed after the 1000ms throttle window closes,
503
- * // thanks to `trailing: true`.
504
- * // This results in only two network requests instead of four.
505
- * ```
506
512
  */
507
- 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
508
- globalData?: GlobalData, // The default data for all calls
509
- defaultOptions?: PostOptions): <TResult = unknown>(...args: Args) => _superutils_promise.IPromisE<TResult>;
513
+ 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, true>>(deferOptions?: DeferredAsyncOptions<ThisArg, Delay>, globalUrl?: GlobalUrl, globalData?: GlobalData, defaultOptions?: PostArgs[2]): <TResult = unknown>(...args: Args) => _superutils_promise.IPromisE<TResult>;
510
514
 
511
515
  /**
512
516
  * Merge one or more {@link FetchOptions}
@@ -525,29 +529,40 @@ defaultOptions?: PostOptions): <TResult = unknown>(...args: Args) => _superutils
525
529
  declare const mergeFetchOptions: (...allOptions: FetchOptions[]) => FetchOptionsInterceptor;
526
530
 
527
531
  type FetchWithoutMethods = typeof fetch$1;
528
- /** Describes method-specific fetch-functions that includes `.deferred()` function for deferred/throttled requests */
529
- type FetchMethodFunc = (<T, Options extends Omit<FetchOptions, 'method'>>(url: string | URL, options?: Options) => ReturnType<typeof fetch$1<T, Options>>) & {
530
- deferred: typeof fetchDeferred;
532
+ declare const _get: {
533
+ <T>(url: string | URL, options?: Omit<FetchOptions, "method">): _superutils_promise.IPromisE<T>;
534
+ deferred: <ThisArg, Delay extends number, GlobalUrl extends string | URL>(deferOptions?: DeferredAsyncOptions<ThisArg, Delay> | undefined, globalUrl?: GlobalUrl | undefined, defaultOptions?: FetchOptions | undefined) => <TResult = unknown>(...args: undefined extends GlobalUrl ? FetchArgs<true> : [options?: Omit<FetchOptions, "method"> | undefined]) => _superutils_promise.IPromisE<TResult>;
531
535
  };
532
- /** Describes method-specific fetch-functions that includes `.deferred()` function for deferred/throttled requests */
533
- type PostMethodFunc = (<T, Options extends Omit<FetchOptions, 'method'>>(url: string | URL, data?: PostBody, options?: Options) => ReturnType<typeof fetch$1<T, Options>>) & {
534
- deferred: typeof postDeferred;
536
+ declare const _head: {
537
+ <T>(url: string | URL, options?: Omit<FetchOptions, "method">): _superutils_promise.IPromisE<T>;
538
+ deferred: <ThisArg, Delay extends number, GlobalUrl extends string | URL>(deferOptions?: DeferredAsyncOptions<ThisArg, Delay> | undefined, globalUrl?: GlobalUrl | undefined, defaultOptions?: FetchOptions | undefined) => <TResult = unknown>(...args: undefined extends GlobalUrl ? FetchArgs<true> : [options?: Omit<FetchOptions, "method"> | undefined]) => _superutils_promise.IPromisE<TResult>;
539
+ };
540
+ declare const _options: {
541
+ <T>(url: string | URL, options?: Omit<FetchOptions, "method">): _superutils_promise.IPromisE<T>;
542
+ deferred: <ThisArg, Delay extends number, GlobalUrl extends string | URL>(deferOptions?: DeferredAsyncOptions<ThisArg, Delay> | undefined, globalUrl?: GlobalUrl | undefined, defaultOptions?: FetchOptions | undefined) => <TResult = unknown>(...args: undefined extends GlobalUrl ? FetchArgs<true> : [options?: Omit<FetchOptions, "method"> | undefined]) => _superutils_promise.IPromisE<TResult>;
543
+ };
544
+ declare const _delete: {
545
+ <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
546
+ deferred: <ThisArg, Delay extends number = number, Args extends PostArgs<true> = PostArgs<true>, GlobalUrl extends Args[0] | undefined = undefined, GlobalData extends Args[1] | undefined = undefined>(deferOptions?: DeferredAsyncOptions<ThisArg, Delay>, globalUrl?: GlobalUrl, globalData?: GlobalData, defaultOptions?: Args[2]) => <TResult = unknown>(...args: PostDeferredCallbackArgs<GlobalUrl, GlobalData, true, PostArgs<true>, Omit<FetchOptions, "method"> | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: Omit<FetchOptions, "method">]>) => _superutils_promise.IPromisE<TResult>;
547
+ };
548
+ declare const _patch: {
549
+ <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
550
+ deferred: <ThisArg, Delay extends number = number, Args extends PostArgs<true> = PostArgs<true>, GlobalUrl extends Args[0] | undefined = undefined, GlobalData extends Args[1] | undefined = undefined>(deferOptions?: DeferredAsyncOptions<ThisArg, Delay>, globalUrl?: GlobalUrl, globalData?: GlobalData, defaultOptions?: Args[2]) => <TResult = unknown>(...args: PostDeferredCallbackArgs<GlobalUrl, GlobalData, true, PostArgs<true>, Omit<FetchOptions, "method"> | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: Omit<FetchOptions, "method">]>) => _superutils_promise.IPromisE<TResult>;
551
+ };
552
+ declare const _post: {
553
+ <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
554
+ deferred: <ThisArg, Delay extends number = number, Args extends PostArgs<true> = PostArgs<true>, GlobalUrl extends Args[0] | undefined = undefined, GlobalData extends Args[1] | undefined = undefined>(deferOptions?: DeferredAsyncOptions<ThisArg, Delay>, globalUrl?: GlobalUrl, globalData?: GlobalData, defaultOptions?: Args[2]) => <TResult = unknown>(...args: PostDeferredCallbackArgs<GlobalUrl, GlobalData, true, PostArgs<true>, Omit<FetchOptions, "method"> | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: Omit<FetchOptions, "method">]>) => _superutils_promise.IPromisE<TResult>;
555
+ };
556
+ declare const _put: {
557
+ <T, Args extends PostArgs<true> = PostArgs<true>>(url: Args[0], data?: Args[1], options?: Args[2]): _superutils_promise.IPromisE<T>;
558
+ deferred: <ThisArg, Delay extends number = number, Args extends PostArgs<true> = PostArgs<true>, GlobalUrl extends Args[0] | undefined = undefined, GlobalData extends Args[1] | undefined = undefined>(deferOptions?: DeferredAsyncOptions<ThisArg, Delay>, globalUrl?: GlobalUrl, globalData?: GlobalData, defaultOptions?: Args[2]) => <TResult = unknown>(...args: PostDeferredCallbackArgs<GlobalUrl, GlobalData, true, PostArgs<true>, Omit<FetchOptions, "method"> | undefined, [url: string | URL, data: PostBody | (() => PostBody), options: Omit<FetchOptions, "method">]>) => _superutils_promise.IPromisE<TResult>;
535
559
  };
536
- interface FetchWithMethods extends FetchWithoutMethods {
537
- get: FetchMethodFunc;
538
- head: FetchMethodFunc;
539
- options: FetchMethodFunc;
540
- delete: PostMethodFunc;
541
- patch: PostMethodFunc;
542
- post: PostMethodFunc;
543
- put: PostMethodFunc;
544
- }
545
560
  /**
546
561
  * @function fetch
547
562
  *
548
563
  * A `fetch()` replacement that simplifies data fetching with automatic JSON parsing, request timeouts, retries,
549
- * and powerful interceptors. It also includes deferred and throttled request capabilities for complex asynchronous
550
- * control flows.
564
+ * and handy interceptors that also work as transformers. It also includes deferred and throttled request
565
+ * capabilities for complex asynchronous control flows.
551
566
  *
552
567
  * Will reject promise if response status code is not 2xx (200 <= status < 300).
553
568
  *
@@ -627,6 +642,14 @@ interface FetchWithMethods extends FetchWithoutMethods {
627
642
  * fetch('https://dummyjson.com/products/1').then(theActualData => console.log(theActualData))
628
643
  * ```
629
644
  */
630
- declare const fetch: FetchWithMethods;
645
+ declare const fetch: typeof fetch$1 & {
646
+ get: typeof _get;
647
+ head: typeof _head;
648
+ options: typeof _options;
649
+ delete: typeof _delete;
650
+ patch: typeof _patch;
651
+ post: typeof _post;
652
+ put: typeof _put;
653
+ };
631
654
 
632
- export { type FetchArgs, type FetchArgsInterceptor, FetchAs, type FetchCustomOptions, type FetchDeferredArgs, type FetchErrMsgs, FetchError, type FetchInterceptorError, type FetchInterceptorRequest, type FetchInterceptorResponse, type FetchInterceptorResult, type FetchInterceptors, type FetchMethodFunc, type FetchOptions, type FetchOptionsDefaults, 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 };
655
+ 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 FetchWithoutMethods, type Interceptor, type PostArgs, type PostBody, type PostDeferredCallbackArgs, type PostOptions, fetch as default, fetch, fetchDeferred, mergeFetchOptions, postDeferred };
package/dist/index.js CHANGED
@@ -116,32 +116,32 @@ var fetch = (url, options = {}) => {
116
116
  let timeoutId;
117
117
  const promise = new PromisE2(async (resolve, reject) => {
118
118
  var _a, _b;
119
- const _options = mergeFetchOptions_default(fetch.defaults, options);
120
- if (isEmpty2(_options.method)) _options.method = "get";
121
- const errorInterceptors = [..._options.interceptors.error];
122
- const requestInterceptors = [..._options.interceptors.request];
123
- const responseInterceptors = [..._options.interceptors.response];
124
- const resultInterceptors = [..._options.interceptors.result];
125
- url = await executeInterceptors_default(url, requestInterceptors, url, _options);
126
- const { as: parseAs, errMsgs, timeout } = _options;
119
+ const _options2 = mergeFetchOptions_default(fetch.defaults, options);
120
+ if (isEmpty2(_options2.method)) _options2.method = "get";
121
+ const errorInterceptors = [..._options2.interceptors.error];
122
+ const requestInterceptors = [..._options2.interceptors.request];
123
+ const responseInterceptors = [..._options2.interceptors.response];
124
+ const resultInterceptors = [..._options2.interceptors.result];
125
+ url = await executeInterceptors_default(url, requestInterceptors, url, _options2);
126
+ const { as: parseAs, errMsgs, timeout } = _options2;
127
127
  if (isPositiveNumber(timeout)) {
128
- (_a = _options.abortCtrl) != null ? _a : _options.abortCtrl = new AbortController();
128
+ (_a = _options2.abortCtrl) != null ? _a : _options2.abortCtrl = new AbortController();
129
129
  timeoutId = setTimeout(() => {
130
130
  var _a2;
131
- return (_a2 = _options.abortCtrl) == null ? void 0 : _a2.abort();
131
+ return (_a2 = _options2.abortCtrl) == null ? void 0 : _a2.abort();
132
132
  }, timeout);
133
133
  }
134
- abortCtrl = _options.abortCtrl;
135
- if (_options.abortCtrl) _options.signal = _options.abortCtrl.signal;
134
+ abortCtrl = _options2.abortCtrl;
135
+ if (_options2.abortCtrl) _options2.signal = _options2.abortCtrl.signal;
136
136
  let errResponse;
137
137
  try {
138
- if (!isUrlValid(url, false)) throw errMsgs.invalidUrl;
139
- let response = await getResponse_default(url, _options);
138
+ if (!isUrlValid(url, false)) throw new Error(errMsgs.invalidUrl);
139
+ let response = await getResponse_default(url, _options2);
140
140
  response = await executeInterceptors_default(
141
141
  response,
142
142
  responseInterceptors,
143
143
  url,
144
- _options
144
+ _options2
145
145
  );
146
146
  errResponse = response;
147
147
  const { status = 0 } = response;
@@ -157,43 +157,36 @@ var fetch = (url, options = {}) => {
157
157
  const parseFunc = response[parseAs];
158
158
  if (isFn2(parseFunc)) {
159
159
  const handleErr = (err) => {
160
- var _a2, _b2;
161
160
  err = new Error(
162
- [
163
- errMsgs.parseFailed,
164
- parseAs + ".",
165
- (_b2 = `${(_a2 = err == null ? void 0 : err.message) != null ? _a2 : err}`) == null ? void 0 : _b2.replace("Error: ", "")
166
- ].join(" "),
161
+ `${errMsgs.parseFailed} ${parseAs}. ${err == null ? void 0 : err.message}`,
167
162
  { cause: err }
168
163
  );
169
164
  return globalThis.Promise.reject(err);
170
165
  };
171
- result = parseFunc();
166
+ result = parseFunc.bind(response)();
172
167
  if (isPromise(result)) result = result.catch(handleErr);
173
168
  result = await executeInterceptors_default(
174
169
  result,
175
170
  resultInterceptors,
176
171
  url,
177
- _options
172
+ _options2
178
173
  );
179
174
  }
180
- resolve(await result);
175
+ resolve(result);
181
176
  } catch (err) {
182
177
  const errX = err;
183
- let error = new FetchError(
184
- (errX == null ? void 0 : errX.name) === "AbortError" ? errMsgs.reqTimedout : err instanceof Error ? err.message : String(err),
185
- {
186
- cause: (_b = errX == null ? void 0 : errX.cause) != null ? _b : err,
187
- response: errResponse,
188
- options: _options,
189
- url
190
- }
191
- );
178
+ const msg = (errX == null ? void 0 : errX.name) === "AbortError" ? errMsgs.reqTimedout : err == null ? void 0 : err.message;
179
+ let error = new FetchError(msg, {
180
+ cause: (_b = errX == null ? void 0 : errX.cause) != null ? _b : err,
181
+ response: errResponse,
182
+ options: _options2,
183
+ url
184
+ });
192
185
  error = await executeInterceptors_default(
193
186
  error,
194
187
  errorInterceptors,
195
188
  url,
196
- _options
189
+ _options2
197
190
  );
198
191
  reject(error);
199
192
  }
@@ -260,14 +253,14 @@ var fetchDeferred_default = fetchDeferred;
260
253
  import PromisE4 from "@superutils/promise";
261
254
 
262
255
  // src/post.ts
263
- import { isStr } from "@superutils/core";
256
+ import { isFn as isFn3, isStr } from "@superutils/core";
264
257
  function post(...[url = "", data, options = {}]) {
265
258
  return fetch_default(
266
259
  url,
267
260
  mergeFetchOptions_default(
268
261
  {
269
262
  method: "post",
270
- body: isStr(data) ? data : JSON.stringify(data)
263
+ body: isStr(data) ? data : JSON.stringify(isFn3(data) ? data() : data)
271
264
  },
272
265
  options
273
266
  )
@@ -287,10 +280,7 @@ function postDeferred(deferOptions = {}, globalUrl, globalData, defaultOptions)
287
280
  if (globalData !== void 0) args.splice(1, 0, globalData);
288
281
  const url = args[0];
289
282
  const data = args[1];
290
- const options = mergeFetchOptions_default(
291
- defaultOptions != null ? defaultOptions : {},
292
- (_a = args[2]) != null ? _a : {}
293
- );
283
+ const options = mergeFetchOptions_default(defaultOptions != null ? defaultOptions : {}, (_a = args[2]) != null ? _a : {});
294
284
  (_b = options.abortCtrl) != null ? _b : options.abortCtrl = new AbortController();
295
285
  (_c = _abortCtrl == null ? void 0 : _abortCtrl.abort) == null ? void 0 : _c.call(_abortCtrl);
296
286
  _abortCtrl = options.abortCtrl;
@@ -303,33 +293,50 @@ function postDeferred(deferOptions = {}, globalUrl, globalData, defaultOptions)
303
293
  var postDeferred_default = postDeferred;
304
294
 
305
295
  // src/index.ts
306
- import { isObj } from "@superutils/core";
307
296
  var createFetchMethodFunc = (method = "get") => {
308
- const methodFunc = ((url, options) => {
309
- const _options = isObj(options) ? options : {};
310
- _options.method = method;
311
- return fetch_default(url, _options);
312
- });
313
- methodFunc.deferred = ((...args) => fetchDeferred_default(...args));
297
+ const deferred = (...args) => fetchDeferred_default(...args);
298
+ const methodFunc = (url, options) => {
299
+ options != null ? options : options = {};
300
+ options.method = method;
301
+ return fetch_default(url, options);
302
+ };
303
+ methodFunc.deferred = deferred;
314
304
  return methodFunc;
315
305
  };
316
306
  var createPostMethodFunc = (method = "post") => {
317
- const methodFunc = ((url, data, options) => {
318
- const _options = isObj(options) ? options : {};
319
- _options.method = method;
320
- return post(url, data, _options);
321
- });
322
- methodFunc.deferred = ((...args) => postDeferred_default(...args));
307
+ const deferredFunc = (deferOptions = {}, globalUrl, globalData, defaultOptions) => {
308
+ defaultOptions != null ? defaultOptions : defaultOptions = {};
309
+ defaultOptions.method = method;
310
+ return postDeferred_default(
311
+ deferOptions,
312
+ globalUrl,
313
+ globalData,
314
+ defaultOptions
315
+ );
316
+ };
317
+ const methodFunc = (url, data, options) => {
318
+ options != null ? options : options = {};
319
+ options.method = method;
320
+ return post(url, data, options);
321
+ };
322
+ methodFunc.deferred = deferredFunc;
323
323
  return methodFunc;
324
324
  };
325
+ var _get = createFetchMethodFunc("get");
326
+ var _head = createFetchMethodFunc("head");
327
+ var _options = createFetchMethodFunc("options");
328
+ var _delete = createPostMethodFunc("delete");
329
+ var _patch = createPostMethodFunc("patch");
330
+ var _post = createPostMethodFunc("post");
331
+ var _put = createPostMethodFunc("put");
325
332
  var fetch2 = fetch_default;
326
- fetch2.get = createFetchMethodFunc("get");
327
- fetch2.head = createFetchMethodFunc("head");
328
- fetch2.options = createFetchMethodFunc("options");
329
- fetch2.delete = createPostMethodFunc("delete");
330
- fetch2.patch = createPostMethodFunc("patch");
331
- fetch2.post = createPostMethodFunc("post");
332
- fetch2.put = createPostMethodFunc("put");
333
+ fetch2.get = _get;
334
+ fetch2.head = _head;
335
+ fetch2.options = _options;
336
+ fetch2.delete = _delete;
337
+ fetch2.patch = _patch;
338
+ fetch2.post = _post;
339
+ fetch2.put = _put;
333
340
  var index_default = fetch2;
334
341
  export {
335
342
  FetchAs,
package/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "author": "Toufiqur Rahaman Chowdhury",
3
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.5",
6
- "@superutils/promise": "^1.0.6"
5
+ "@superutils/core": "^1.0.8",
6
+ "@superutils/promise": "^1.0.9"
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.5",
24
- "@superutils/promise": "^1.0.6"
23
+ "@superutils/core": "^1.0.8",
24
+ "@superutils/promise": "^1.0.9"
25
25
  },
26
26
  "publishConfig": {
27
27
  "access": "public"
@@ -37,5 +37,5 @@
37
37
  "sideEffects": false,
38
38
  "type": "module",
39
39
  "types": "dist/index.d.ts",
40
- "version": "1.0.1"
40
+ "version": "1.0.2"
41
41
  }