@superutils/fetch 1.5.14 → 1.5.16

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/dist/index.d.cts CHANGED
@@ -155,40 +155,33 @@ type FetchInterceptorResponse = Interceptor<Response, FetchArgsInterceptor>;
155
155
  * ```javascript
156
156
  * import fetch from '@superutils/fetch'
157
157
  *
158
- * // first transform result (user object) and ensure user result alwasy contain a hexadecimal crypto balance
159
- * const ensureBalanceHex = (user = {}) => {
160
- * user.crypto ??= {}
161
- * user.crypto.balance ??= '0x0'
162
- * return user
163
- * }
164
- * // then check convert hexadecimal number to BigInt
165
- * const hexToBigInt = user => {
166
- * user.crypto.balance = BigInt(user.crypto.balance)
167
- * return user
168
- * }
169
- * // then log balance (no transformation)
170
- * const logBalance = (result, url) => {
171
- * // only log balance for single user requests
172
- * const shouldLog = result?.hasOwnProperty('crypto') && /^[0-9]+$/.test(
173
- * url?.split('/users/')[1].replace('/', '')
174
- * )
175
- * shouldLog && console.log(
176
- * new Date().toISOString(),
177
- * '[UserBalance] UserID:', result.id,
178
- * result.crypto.balance
179
- * )
180
- * }
181
- * // now we make the actaul fetch request
182
158
  * const result = await fetch.get('[DUMMYJSON-DOT-COM]/users/1', {
183
159
  * interceptors: {
184
160
  * result: [
185
- * ensureBalanceHex,
186
- * hexToBigInt,
187
- * logBalance
161
+ * // 1. check & convert user crypto balance to BigInt
162
+ * userCryptoBalanceToBigInt,
163
+ *
164
+ * // 2. log balance (no transformation)
165
+ * logUserBalance
188
166
  * ]
189
167
  * }
190
168
  * })
191
169
  * console.log({result})
170
+ *
171
+ * function userCryptoBalanceToBigInt(user = {}) {
172
+ * user.crypto ??= {}
173
+ * user.crypto.balance ??= '0x0'
174
+ * user.crypto.balance = BigInt(user.crypto.balance || '0x0')
175
+ * return user
176
+ * }
177
+ *
178
+ * function logUserBalance(user, url) {
179
+ * console.log(
180
+ * new Date().toISOString(),
181
+ * '[UserBalance] UserID:', user.id,
182
+ * user.crypto.balance
183
+ * )
184
+ * }
192
185
  * ```
193
186
  */
194
187
  type FetchInterceptorResult<Args extends unknown[] = FetchArgsInterceptor> = Interceptor<unknown, Args>;
@@ -377,6 +370,61 @@ type FetchRetryOptions = Omit<Partial<RetryOptions>, 'retry' | 'retryIf'> & {
377
370
  * Default: `0`
378
371
  */
379
372
  retry?: number;
373
+ /**
374
+ * An optional predicate function to determine retry eligibility.
375
+ * Also useful for side effects like logging or analytics.
376
+ *
377
+ * Returning `true` explicitly triggers a retry, while `false` prevents it.
378
+ * If the function returns `undefined` or `void`, the default library logic is used
379
+ * (retry if an exception was thrown or if `response.ok` is `false`).
380
+ *
381
+ * @param response The Response object from the last attempt, if available.
382
+ * @param retryCount The current retry attempt number (starting from 1).
383
+ * @param error The error encountered during the request, if any.
384
+ *
385
+ * @returns A boolean indicating whether to retry, or a promise resolving to boolean.
386
+ *
387
+ *
388
+ * @example
389
+ * #### Example: Retry on specific status codes
390
+ * ```javascript
391
+ * import fetch from '@superutils/fetch'
392
+ *
393
+ * fetch
394
+ * .get('[DUMMYJSON-DOT-COM]/products/1', {
395
+ * retry: 3, // If request fails, retry up to three more times
396
+ * // Retry on rate limits (429) or transient server errors (5xx).
397
+ * retryIf: r => r.status === 429 || r.status >= 500,
398
+ * })
399
+ * .then(console.log)
400
+ * ```
401
+ *
402
+ * @example
403
+ * #### Example: Polling (Retry until a condition is met)
404
+ * Keep retrying every minute until a product is back in stock.
405
+ * ```javascript
406
+ * import fetch from '@superutils/fetch'
407
+ *
408
+ * fetch
409
+ * .get('[DUMMYJSON-DOT-COM]/products/1', {
410
+ * delay: 60_000, // Wait 1 minute between attempts
411
+ * retry: 10, // Attempt up to 10 more times
412
+ * retryIf: async (response) => {
413
+ * if (!response?.ok) return true // Retry on network or server errors
414
+ *
415
+ * // Use response.clone() to avoid consuming the body stream used by the final result.
416
+ * const result = await response.clone().json()
417
+ *
418
+ * // Retry if the product is still NOT in stock
419
+ * return result?.availabilityStatus !== 'In Stock'
420
+ * },
421
+ *
422
+ * // Ensure the overall timeout accounts for the polling duration
423
+ * timeout: 60_000 * 15
424
+ * })
425
+ * .then(product => console.log('Product is back in stock:', product))
426
+ * ```
427
+ */
380
428
  retryIf?: RetryIfFunc<Response>;
381
429
  };
382
430
  /**
@@ -487,6 +535,11 @@ type ClientData<FixedOptions> = ExtractAs<[FixedOptions]> extends FetchAs.json ?
487
535
  * which minimizes code repetition across your application. If a method is not specified during creation, the client
488
536
  * will default to `GET`.
489
537
  *
538
+ * **Option Priority:**
539
+ * 1. `fixedOptions`: Highest priority. Cannot be overridden by the caller.
540
+ * 2. `options`: Options passed during the specific call.
541
+ * 3. `commonOptions`: Default options set at creation time.
542
+ *
490
543
  * The returned client also includes a `.deferred()` method, providing the same debounce, throttle, and sequential
491
544
  * execution capabilities found in functions like `fetch.get.deferred()`.
492
545
  *
package/dist/index.d.ts CHANGED
@@ -155,40 +155,33 @@ type FetchInterceptorResponse = Interceptor<Response, FetchArgsInterceptor>;
155
155
  * ```javascript
156
156
  * import fetch from '@superutils/fetch'
157
157
  *
158
- * // first transform result (user object) and ensure user result alwasy contain a hexadecimal crypto balance
159
- * const ensureBalanceHex = (user = {}) => {
160
- * user.crypto ??= {}
161
- * user.crypto.balance ??= '0x0'
162
- * return user
163
- * }
164
- * // then check convert hexadecimal number to BigInt
165
- * const hexToBigInt = user => {
166
- * user.crypto.balance = BigInt(user.crypto.balance)
167
- * return user
168
- * }
169
- * // then log balance (no transformation)
170
- * const logBalance = (result, url) => {
171
- * // only log balance for single user requests
172
- * const shouldLog = result?.hasOwnProperty('crypto') && /^[0-9]+$/.test(
173
- * url?.split('/users/')[1].replace('/', '')
174
- * )
175
- * shouldLog && console.log(
176
- * new Date().toISOString(),
177
- * '[UserBalance] UserID:', result.id,
178
- * result.crypto.balance
179
- * )
180
- * }
181
- * // now we make the actaul fetch request
182
158
  * const result = await fetch.get('[DUMMYJSON-DOT-COM]/users/1', {
183
159
  * interceptors: {
184
160
  * result: [
185
- * ensureBalanceHex,
186
- * hexToBigInt,
187
- * logBalance
161
+ * // 1. check & convert user crypto balance to BigInt
162
+ * userCryptoBalanceToBigInt,
163
+ *
164
+ * // 2. log balance (no transformation)
165
+ * logUserBalance
188
166
  * ]
189
167
  * }
190
168
  * })
191
169
  * console.log({result})
170
+ *
171
+ * function userCryptoBalanceToBigInt(user = {}) {
172
+ * user.crypto ??= {}
173
+ * user.crypto.balance ??= '0x0'
174
+ * user.crypto.balance = BigInt(user.crypto.balance || '0x0')
175
+ * return user
176
+ * }
177
+ *
178
+ * function logUserBalance(user, url) {
179
+ * console.log(
180
+ * new Date().toISOString(),
181
+ * '[UserBalance] UserID:', user.id,
182
+ * user.crypto.balance
183
+ * )
184
+ * }
192
185
  * ```
193
186
  */
194
187
  type FetchInterceptorResult<Args extends unknown[] = FetchArgsInterceptor> = Interceptor<unknown, Args>;
@@ -377,6 +370,61 @@ type FetchRetryOptions = Omit<Partial<RetryOptions>, 'retry' | 'retryIf'> & {
377
370
  * Default: `0`
378
371
  */
379
372
  retry?: number;
373
+ /**
374
+ * An optional predicate function to determine retry eligibility.
375
+ * Also useful for side effects like logging or analytics.
376
+ *
377
+ * Returning `true` explicitly triggers a retry, while `false` prevents it.
378
+ * If the function returns `undefined` or `void`, the default library logic is used
379
+ * (retry if an exception was thrown or if `response.ok` is `false`).
380
+ *
381
+ * @param response The Response object from the last attempt, if available.
382
+ * @param retryCount The current retry attempt number (starting from 1).
383
+ * @param error The error encountered during the request, if any.
384
+ *
385
+ * @returns A boolean indicating whether to retry, or a promise resolving to boolean.
386
+ *
387
+ *
388
+ * @example
389
+ * #### Example: Retry on specific status codes
390
+ * ```javascript
391
+ * import fetch from '@superutils/fetch'
392
+ *
393
+ * fetch
394
+ * .get('[DUMMYJSON-DOT-COM]/products/1', {
395
+ * retry: 3, // If request fails, retry up to three more times
396
+ * // Retry on rate limits (429) or transient server errors (5xx).
397
+ * retryIf: r => r.status === 429 || r.status >= 500,
398
+ * })
399
+ * .then(console.log)
400
+ * ```
401
+ *
402
+ * @example
403
+ * #### Example: Polling (Retry until a condition is met)
404
+ * Keep retrying every minute until a product is back in stock.
405
+ * ```javascript
406
+ * import fetch from '@superutils/fetch'
407
+ *
408
+ * fetch
409
+ * .get('[DUMMYJSON-DOT-COM]/products/1', {
410
+ * delay: 60_000, // Wait 1 minute between attempts
411
+ * retry: 10, // Attempt up to 10 more times
412
+ * retryIf: async (response) => {
413
+ * if (!response?.ok) return true // Retry on network or server errors
414
+ *
415
+ * // Use response.clone() to avoid consuming the body stream used by the final result.
416
+ * const result = await response.clone().json()
417
+ *
418
+ * // Retry if the product is still NOT in stock
419
+ * return result?.availabilityStatus !== 'In Stock'
420
+ * },
421
+ *
422
+ * // Ensure the overall timeout accounts for the polling duration
423
+ * timeout: 60_000 * 15
424
+ * })
425
+ * .then(product => console.log('Product is back in stock:', product))
426
+ * ```
427
+ */
380
428
  retryIf?: RetryIfFunc<Response>;
381
429
  };
382
430
  /**
@@ -487,6 +535,11 @@ type ClientData<FixedOptions> = ExtractAs<[FixedOptions]> extends FetchAs.json ?
487
535
  * which minimizes code repetition across your application. If a method is not specified during creation, the client
488
536
  * will default to `GET`.
489
537
  *
538
+ * **Option Priority:**
539
+ * 1. `fixedOptions`: Highest priority. Cannot be overridden by the caller.
540
+ * 2. `options`: Options passed during the specific call.
541
+ * 3. `commonOptions`: Default options set at creation time.
542
+ *
490
543
  * The returned client also includes a `.deferred()` method, providing the same debounce, throttle, and sequential
491
544
  * execution capabilities found in functions like `fetch.get.deferred()`.
492
545
  *
package/package.json CHANGED
@@ -5,8 +5,8 @@
5
5
  },
6
6
  "description": "A lightweight `fetch` wrapper for browsers and Node.js, designed to simplify data fetching and reduce boilerplate.",
7
7
  "dependencies": {
8
- "@superutils/core": "^1.2.13",
9
- "@superutils/promise": "^1.3.12"
8
+ "@superutils/core": "^1.2.15",
9
+ "@superutils/promise": "^1.3.14"
10
10
  },
11
11
  "files": [
12
12
  "dist",
@@ -53,6 +53,6 @@
53
53
  "module": "./dist/index.js",
54
54
  "type": "module",
55
55
  "types": "./dist/index.d.ts",
56
- "version": "1.5.14",
57
- "gitHead": "1661eeeed9d00cb6b960e76563cdd3cee2cac8a7"
56
+ "version": "1.5.16",
57
+ "gitHead": "7be3be6fb4a8cb1955ee5f704fc49bbb792bd961"
58
58
  }