@scirexs/fetchy 0.4.2 → 0.5.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 +13 -13
- package/esm/main.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -146,7 +146,7 @@ interface FetchyOptions extends RequestInit {
|
|
|
146
146
|
// Error throwing behavior
|
|
147
147
|
onError?: {
|
|
148
148
|
onNative?: boolean; // Throw on native errors (default: true)
|
|
149
|
-
onStatus?: boolean; // Throw on 4xx/5xx status (default:
|
|
149
|
+
onStatus?: boolean; // Throw on 4xx/5xx status (default: true)
|
|
150
150
|
} | boolean; // Set to true to throw on all errors
|
|
151
151
|
|
|
152
152
|
// Initial jitter delay in seconds
|
|
@@ -171,7 +171,7 @@ interface FetchyOptions extends RequestInit {
|
|
|
171
171
|
},
|
|
172
172
|
onError: {
|
|
173
173
|
onNative: true, // Throw native errors
|
|
174
|
-
onStatus:
|
|
174
|
+
onStatus: true // Don't throw on HTTP errors
|
|
175
175
|
},
|
|
176
176
|
}
|
|
177
177
|
```
|
|
@@ -206,7 +206,7 @@ If the timeout duration specified in the `timeout` option is exceeded, the reque
|
|
|
206
206
|
|
|
207
207
|
### HTTPStatusError
|
|
208
208
|
|
|
209
|
-
If `onStatus` is set to `true
|
|
209
|
+
If `onStatus` is set to `true` (default), an `HTTPStatusError` will be thrown when the response status is outside the 2xx range. You can access the status and body through this error object. The error message format is: `404 Not Found: (no response body)`.
|
|
210
210
|
|
|
211
211
|
### RedirectError
|
|
212
212
|
|
|
@@ -290,11 +290,15 @@ const response = await fetchy("https://api.example.com/data", {
|
|
|
290
290
|
```ts
|
|
291
291
|
import { fetchy, HTTPStatusError, RedirectError } from "@scirexs/fetchy";
|
|
292
292
|
|
|
293
|
-
// Throw on error
|
|
293
|
+
// Throw on error and not ok response (default behavior)
|
|
294
294
|
try {
|
|
295
295
|
const response = await fetchy("https://api.example.com/data");
|
|
296
296
|
} catch (error) {
|
|
297
|
-
|
|
297
|
+
if (error instanceof HTTPStatusError) {
|
|
298
|
+
console.error("HTTP error:", error.message); // e.g., "404 Not Found: (no response body)"
|
|
299
|
+
console.error("Status:", error.status);
|
|
300
|
+
console.error("Body:", error.body);
|
|
301
|
+
}
|
|
298
302
|
}
|
|
299
303
|
|
|
300
304
|
// Return null on error
|
|
@@ -305,17 +309,13 @@ if (response === null) {
|
|
|
305
309
|
console.log("Request failed");
|
|
306
310
|
}
|
|
307
311
|
|
|
308
|
-
// Throw only on
|
|
312
|
+
// Throw only on native errors
|
|
309
313
|
try {
|
|
310
314
|
const response = await fetchy("https://api.example.com/data", {
|
|
311
|
-
onError: { onNative:
|
|
315
|
+
onError: { onNative: true, onStatus: false } as const
|
|
312
316
|
});
|
|
313
317
|
} catch (error) {
|
|
314
|
-
|
|
315
|
-
console.error("HTTP error:", error.message); // e.g., "404 Not Found: (no response body)"
|
|
316
|
-
console.error("Status:", error.status);
|
|
317
|
-
console.error("Body:", error.body);
|
|
318
|
-
}
|
|
318
|
+
console.error("Request failed:", error);
|
|
319
319
|
}
|
|
320
320
|
|
|
321
321
|
// Handle redirects
|
|
@@ -408,7 +408,7 @@ interface User {
|
|
|
408
408
|
name: string;
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
-
const options = { timeout: 5, onError: true as const }; // Add `as const`
|
|
411
|
+
const options = { timeout: 5, onError: { onNative: true, onStatus: false } as const }; // Add `as const`
|
|
412
412
|
const response = await fetchy("https://api.example.com/todos/1", "json", options);
|
|
413
413
|
// `response` is User (not User | null)
|
|
414
414
|
```
|
package/esm/main.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{m as fetchy,A as fetchyb,
|
|
1
|
+
export{m as fetchy,A as fetchyb,c as HTTPStatusError,h as RedirectError};const s={timeout:15,delay:0,interval:3,maxInterval:30,maxAttempts:3,retryAfter:!0,onNative:!0,onStatus:!0,redirect:"follow"};class c extends Error{static#t=80;status;body;constructor(e,r,n){super(e),this.name="HTTPStatusError",this.status=r,this.body=n}static async fromResponse(e){const r=await e.text(),n=r.length>this.#t?`${r.slice(0,this.#t)}... (more ${r.length-this.#t} chars)`:r||"(no response body)",a=`${e.status} ${e.statusText}: ${n}`;return new this(a,e.status,r)}}class h extends Error{status;constructor(e,r){super(e),this.name="RedirectError",this.status=r}static fromResponse(e){const r=`${e.status} ${e.statusText}`.trim();return new this(r,e.status)}}async function A(t,e="auto",r){const n=await m(t,r);if(!n||!n.ok)return null;const a=n.headers.get("Content-Type")??"";try{return e==="text"||e==="auto"&&a.startsWith("text/")?await n.text():e==="json"||e==="auto"&&a==="application/json"?await n.json():await n.bytes()}catch(i){if(f("onNative",r?.onError)||i instanceof c)throw i;return null}}async function m(t,e){try{t||(t=e?.url??new URL(""));const r=v(e),n=T(t,r,e),a=await P(t,n,r);if(!a.ok&&r.onStatus)throw await c.fromResponse(a);return a}catch(r){if(f("onNative",e?.onError)||r instanceof c)throw r;return null}}function R(t){return typeof t=="string"}function y(t){return typeof t=="number"}function d(t){return typeof t=="boolean"}function N(t){return!!(t&&typeof t=="object"&&Object.prototype.toString.call(t).slice(8,-1)==="Object"&&t.constructor===Object)}function f(t,e){return!!(e===void 0&&s[t]||typeof e=="boolean"&&e||typeof e=="object"&&(e[t]??s[t]))}function l(t,e,r=!1){return e===void 0||e<0?t:r?Math.trunc(e):e}function u(t,e,r){return d(r)?e:r===void 0||r[t]===void 0?s[t]:y(r[t])?l(s[t],r[t],t==="maxAttempts"):r[t]}function v(t){return{timeout:l(s.timeout,t?.timeout),delay:l(s.delay,t?.delay),interval:u("interval",0,t?.retry),maxInterval:u("maxInterval",0,t?.retry),maxAttempts:u("maxAttempts",0,t?.retry),retryAfter:u("retryAfter",!1,t?.retry),onStatus:f("onStatus",t?.onError),redirect:t?.redirect??s.redirect}}function T(t,e,r){const{method:n,body:a,timeout:i,retry:D,bearer:C,onError:H,delay:L,redirect:o,signal:k,...g}=r??{};return{headers:S(r),method:n||(t instanceof Request?t.method:a===void 0?"GET":"POST"),signal:I(t,e.timeout,r?.signal),...o&&{redirect:o==="error"?"manual":o},...a&&{body:E(a)},...g}}function E(t){return w(t)?JSON.stringify(t):t}function w(t){return!!(t===null||y(t)||d(t)||Array.isArray(t)||N(t))}function S(t){const e=new Headers(t?.headers);if(e.has("Accept")||e.append("Accept","application/json, text/plain"),!e.has("Content-Type")){const r=j(t?.body);r&&e.append("Content-Type",r)}return t?.bearer&&e.set("Authorization",`Bearer ${t.bearer}`),e}function j(t){if(!(t===void 0||R(t)||t instanceof FormData||t instanceof URLSearchParams)&&!(t instanceof Blob&&t.type))return w(t)?"application/json":"application/octet-stream"}function I(t,e,r){const n=[];return t instanceof Request&&t.signal&&n.push(t.signal),r&&n.push(r),e>0&&n.push(AbortSignal.timeout(e*1e3+1)),n.length?AbortSignal.any(n):void 0}async function b(t,e=!0){if(t<=0)return;const r=Math.trunc((e?Math.random():1)*t*1e3);await new Promise(n=>setTimeout(n,r))}function O(t){return t.status<400&&t.status>=300}async function x(t,e,r,n){if(t>=r.maxAttempts-1||e.signal?.aborted||n?.ok)return!0;if(n&&O(n)){if(r.redirect==="manual")return!0;if(r.redirect==="error")throw r.maxAttempts=0,h.fromResponse(n)}const a=M(t,r,n);return a>r.maxInterval?!0:(await b(a,!1),!1)}function M(t,e,r){return e.retryAfter&&r?Math.max(B(r.headers.get("Retry-After")?.trim()??""),e.interval):Math.min(Math.pow(Math.max(1,e.interval),t),e.maxInterval)}function B(t){if(!t)return 1/0;const e=Number.parseInt(t,10);if(!Number.isNaN(e))return e;const r=Math.ceil((new Date(t).getTime()-Date.now())/1e3);return Number.isNaN(r)?1/0:r}function $(t,e,r){return r.redirected?(r.status===303&&(e.method="GET"),t instanceof Request?new Request(r.url,t):r.url):t}function q(t,e){return t instanceof Request&&e?t.clone():t}async function P(t,e,r){for(let n=0;n<r.maxAttempts;n++)try{const a=q(t,n<r.maxAttempts-1),i=await _(a,e,r);if(await x(n,e,r,i))return i;t=$(t,e,i);continue}catch(a){if(await x(n,e,r))throw a;continue}return await _(t,e,r)}async function _(t,e,r){return await b(r.delay),await fetch(t,e)}
|