@firekid/hurl 1.0.5 → 1.0.7

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
@@ -12,7 +12,7 @@ https://github.com/Firekid-is-him/hurl
12
12
 
13
13
  ## Purpose
14
14
 
15
- `hurl` solves the problems that `request` left behind when it was deprecated and that `axios` never fully addressed: no edge runtime support, a 35KB bundle, no built-in retry logic, no request deduplication, and no upload progress tracking. `hurl` ships all of these in under 3KB with zero runtime dependencies.
15
+ `hurl` solves the problems that `request` left behind when it was deprecated and that `axios` never fully addressed: no edge runtime support, a 35KB bundle, no built-in retry logic, no request deduplication, and no upload progress tracking. `hurl` ships all of these in under 10KB with zero runtime dependencies.
16
16
 
17
17
  ## Core Concepts
18
18
 
@@ -93,6 +93,7 @@ type HurlRequestOptions = {
93
93
  onUploadProgress?: ProgressCallback
94
94
  onDownloadProgress?: ProgressCallback
95
95
  stream?: boolean
96
+ throwOnError?: boolean
96
97
  debug?: boolean
97
98
  requestId?: string
98
99
  deduplicate?: boolean
@@ -219,6 +220,17 @@ await hurl.get('/users', {
219
220
  })
220
221
  ```
221
222
 
223
+ ```ts
224
+ import { clearCache, invalidateCache } from '@firekid/hurl'
225
+
226
+ // Clear the entire cache
227
+ clearCache()
228
+
229
+ // Invalidate a single entry by URL or custom key
230
+ invalidateCache('https://api.example.com/users')
231
+ invalidateCache('all-users') // if you used a custom cache key
232
+ ```
233
+
222
234
  ## Request Deduplication
223
235
 
224
236
  When `deduplicate` is true and the same GET URL is called multiple times simultaneously, only one network request is made.
@@ -232,19 +244,35 @@ const [a, b] = await Promise.all([
232
244
 
233
245
  ## Proxy
234
246
 
247
+ Native fetch does not support programmatic proxy configuration out of the box. Proxy support depends on your Node.js version:
248
+
249
+ **Node.js 18** — install `undici@6` (v7 dropped Node 18 support), use `ProxyAgent`:
235
250
  ```ts
236
- await hurl.get('/users', {
237
- proxy: { url: 'http://proxy.example.com:8080' }
238
- })
251
+ // npm install undici@6
252
+ import { ProxyAgent, setGlobalDispatcher } from 'undici'
253
+ setGlobalDispatcher(new ProxyAgent('http://proxy.example.com:8080'))
254
+ ```
239
255
 
240
- await hurl.get('/users', {
241
- proxy: {
242
- url: 'socks5://proxy.example.com:1080',
243
- auth: { username: 'user', password: 'pass' }
244
- }
245
- })
256
+ **Node.js 20** — `undici` is bundled with `ProxyAgent` support:
257
+ ```ts
258
+ import { ProxyAgent, setGlobalDispatcher } from 'undici'
259
+ setGlobalDispatcher(new ProxyAgent('http://proxy.example.com:8080'))
246
260
  ```
247
261
 
262
+ **Node.js 22.3+** — supports `EnvHttpProxyAgent` which reads `HTTP_PROXY`/`HTTPS_PROXY` env vars automatically:
263
+ ```ts
264
+ import { EnvHttpProxyAgent, setGlobalDispatcher } from 'undici'
265
+ setGlobalDispatcher(new EnvHttpProxyAgent())
266
+ // now set HTTP_PROXY=http://proxy.example.com:8080 in your env
267
+ ```
268
+
269
+ **Node.js 24+** — native fetch respects env vars when `NODE_USE_ENV_PROXY=1` is set:
270
+ ```bash
271
+ NODE_USE_ENV_PROXY=1 HTTP_PROXY=http://proxy.example.com:8080 node app.js
272
+ ```
273
+
274
+ The `proxy` option in `HurlRequestOptions` is reserved for a future release where this will be handled automatically.
275
+
248
276
  ## Parallel Requests
249
277
 
250
278
  ```ts
@@ -271,6 +299,8 @@ const adminApi = api.extend({
271
299
  })
272
300
  ```
273
301
 
302
+ `create()` produces a fully isolated instance — no shared defaults, interceptors, or state with the parent. `extend()` merges the provided defaults on top of the parent's and inherits all of the parent's interceptors.
303
+
274
304
  ## Debug Mode
275
305
 
276
306
  Logs the full request (method, url, headers, body, query, timeout, retry config) and response (status, timing, headers, data) to the console. Errors and retries are also logged.
@@ -283,6 +313,15 @@ await hurl.get('/users', { debug: true })
283
313
 
284
314
  `hurl` throws a `HurlError` on HTTP errors (4xx, 5xx), network failures, timeouts, aborts, and parse failures. It never resolves silently on bad status codes.
285
315
 
316
+ If you want to handle 4xx/5xx responses without a try/catch, set `throwOnError: false` — the response resolves normally and you can check `res.status` yourself.
317
+
318
+ ```ts
319
+ const res = await hurl.get('/users', { throwOnError: false })
320
+ if (res.status === 404) {
321
+ console.log('not found')
322
+ }
323
+ ```
324
+
286
325
  ```ts
287
326
  import hurl, { HurlError } from '@firekid/hurl'
288
327
 
@@ -373,10 +412,10 @@ Sends a request with the method specified in options. Defaults to GET. Returns `
373
412
  Runs an array of requests in parallel. Returns a promise that resolves when all requests complete. Equivalent to `Promise.all`.
374
413
 
375
414
  ### hurl.create(defaults?)
376
- Creates a new isolated instance with its own defaults, interceptors, and state. Does not share anything with the parent instance.
415
+ Creates a new isolated instance with its own defaults, interceptors, and state. Does not inherit anything from the parent instance.
377
416
 
378
417
  ### hurl.extend(defaults?)
379
- Creates a new instance that inherits the current defaults and merges in the provided ones.
418
+ Creates a new instance that inherits the current defaults, merges in the provided ones, and copies all parent interceptors (request, response, and error).
380
419
 
381
420
  ### hurl.defaults.set(defaults)
382
421
  Sets global defaults for the current instance. Merged into every request.
@@ -404,6 +443,15 @@ import { clearCache } from '@firekid/hurl'
404
443
  clearCache()
405
444
  ```
406
445
 
446
+ ### invalidateCache(key)
447
+ Removes a single entry from the in-memory cache by URL or custom cache key.
448
+
449
+ ```ts
450
+ import { invalidateCache } from '@firekid/hurl'
451
+ invalidateCache('https://api.example.com/users')
452
+ invalidateCache('all-users') // if you used a custom cache key
453
+ ```
454
+
407
455
  ## License
408
456
 
409
- MIT
457
+ MIT
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";var P=Object.defineProperty;var ae=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var ce=Object.prototype.hasOwnProperty;var pe=(e,r)=>{for(var t in r)P(e,t,{get:r[t],enumerable:!0})},fe=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of le(r))!ce.call(e,s)&&s!==t&&P(e,s,{get:()=>r[s],enumerable:!(n=ae(r,s))||n.enumerable});return e};var de=e=>fe(P({},"__esModule",{value:!0}),e);var we={};pe(we,{HurlError:()=>c,clearCache:()=>Z,createInstance:()=>I,default:()=>be});module.exports=de(we);var c=class extends Error{constructor(r){super(r.message),this.name="HurlError",this.type=r.type,this.status=r.status,this.statusText=r.statusText,this.data=r.data,this.headers=r.headers,this.requestId=r.requestId,this.retries=r.retries??0}};function F(e){return new c({message:`HTTP ${e.status}: ${e.statusText}`,type:"HTTP_ERROR",...e})}function _(e,r){return new c({message:e,type:"NETWORK_ERROR",requestId:r})}function M(e,r){return new c({message:`Request timed out after ${e}ms`,type:"TIMEOUT_ERROR",requestId:r})}function j(e){return new c({message:"Request was aborted",type:"ABORT_ERROR",requestId:e})}function k(e,r){return new c({message:`Failed to parse response: ${e}`,type:"PARSE_ERROR",requestId:r})}async function K(e,r){let t=e.body?.getReader(),n=parseInt(e.headers.get("content-length")??"0",10);if(!t)return new ArrayBuffer(0);let s=[],u=0;for(;;){let{done:i,value:p}=await t.read();if(i)break;s.push(p),u+=p.byteLength,r({loaded:u,total:n,percent:n>0?Math.round(u/n*100):0})}let a=new Uint8Array(u),o=0;for(let i of s)a.set(i,o),o+=i.byteLength;return a.buffer}function N(e,r){let t=0;typeof e=="string"?t=new TextEncoder().encode(e).byteLength:e instanceof ArrayBuffer?t=e.byteLength:e instanceof Blob&&(t=e.size);let n=0;return(e instanceof ReadableStream?e:new Response(e).body).pipeThrough(new TransformStream({transform(u,a){n+=u.byteLength,r({loaded:n,total:t,percent:t>0?Math.round(n/t*100):0}),a.enqueue(u)}}))}function C(e){let r={};return e.forEach((t,n)=>{r[n]=t}),r}async function W(e,r,t,n,s){if(t==="HEAD"||e.status===204||e.headers.get("content-length")==="0")return null;if(n)return e.body;let u=e.headers.get("content-type")??"",a=u.includes("application/octet-stream")||u.includes("image/")||u.includes("video/")||u.includes("audio/");if(s&&a)try{return await K(e,s)}catch(o){throw k(o.message,r)}try{return u.includes("application/json")?await e.json():u.includes("text/")?await e.text():a?await e.arrayBuffer():await e.text()}catch(o){throw k(o.message,r)}}function G(e,r,t,n){let s=Date.now();return{data:e,status:r.status,statusText:r.statusText,headers:C(r.headers),requestId:t,timing:{start:n,end:s,duration:s-n},fromCache:!1}}function ge(e){return typeof globalThis<"u"&&globalThis.Buffer?globalThis.Buffer.from(e).toString("base64"):btoa(encodeURIComponent(e).replace(/%([0-9A-F]{2})/g,(r,t)=>String.fromCharCode(parseInt(t,16))))}function z(e,r,t){if(t.type==="bearer"&&(e.Authorization=`Bearer ${t.token}`),t.type==="basic"){let n=ge(`${t.username}:${t.password}`);e.Authorization=`Basic ${n}`}t.type==="apikey"&&(t.in==="query"?r[t.key]=t.value:e[t.key]=t.value)}function X(e){return e==null?null:typeof e=="number"?{count:e,delay:300,backoff:"exponential"}:e}function Y(e,r,t){return t>=r.count||e.type==="ABORT_ERROR"?!1:r.on&&e.status?r.on.includes(e.status):!!(e.type==="NETWORK_ERROR"||e.type==="TIMEOUT_ERROR"||e.status&&e.status>=500)}async function J(e,r){let t=e.delay??300,n=e.backoff==="exponential"?t*Math.pow(2,r):t*(r+1);await new Promise(s=>setTimeout(s,n))}var E=new Map;function A(e,r){return r?.key??e}function Q(e){let r=E.get(e);return r?Date.now()>r.expiresAt?(E.delete(e),null):{...r.response,fromCache:!0}:null}function V(e,r,t){E.set(e,{response:r,expiresAt:Date.now()+t.ttl})}function Z(){E.clear()}var U=new Map;function ee(e){return U.get(e)??null}function re(e,r){U.set(e,r),r.finally(()=>U.delete(e))}function te(e,r){console.group(`[hurl] \u2192 ${r.method??"GET"} ${e}`),r.headers&&Object.keys(r.headers).length>0&&console.log("headers:",r.headers),r.query&&console.log("query:",r.query),r.body&&console.log("body:",r.body),r.timeout&&console.log("timeout:",r.timeout),r.retry&&console.log("retry:",r.retry),console.groupEnd()}function D(e){let r=e.status>=400?"\u{1F534}":e.status>=300?"\u{1F7E1}":"\u{1F7E2}";console.group(`[hurl] ${r} ${e.status} ${e.statusText} (${e.timing.duration}ms)`),console.log("requestId:",e.requestId),e.fromCache&&console.log("served from cache"),console.log("headers:",e.headers),console.log("data:",e.data),console.groupEnd()}function ne(e){console.group("[hurl] \u{1F534} Error"),console.error(e),console.groupEnd()}function Re(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():Math.random().toString(36).slice(2,10)}function me(e,r,t){let n;if(r.startsWith("http://")||r.startsWith("https://")){if(e){let u=new URL(e).origin,a=new URL(r).origin;if(u!==a)throw new Error(`Absolute URL "${r}" does not match baseUrl origin "${u}". Pass the full URL without baseUrl, or use a path-relative URL.`)}n=r}else{if(r.startsWith("//"))throw new Error("Protocol-relative URLs are not supported. Use an explicit https:// or http:// scheme.");n=e?`${e.replace(/\/$/,"")}/${r.replace(/^\//,"")}`:r}if(!t||Object.keys(t).length===0)return n;let s=new URLSearchParams;for(let[u,a]of Object.entries(t))s.set(u,String(a));return`${n}?${s.toString()}`}function he(e){return e instanceof ReadableStream||e!==null&&typeof e=="object"&&typeof e.pipe=="function"}function ye(e,r){let t={...r.headers,...e.headers},n=e.body;return n!=null&&typeof n=="object"&&!(n instanceof FormData)&&!(n instanceof Blob)&&!(n instanceof ArrayBuffer)&&!he(n)&&(t["Content-Type"]=t["Content-Type"]??"application/json"),t}function Te(e){if(e!=null)return e instanceof FormData||e instanceof Blob||e instanceof ArrayBuffer||typeof e=="string"||e instanceof ReadableStream||typeof e.pipe=="function"?e:JSON.stringify(e)}async function oe(e,r,t){let n=r.requestId??Re(),s=r.method??"GET",u=Date.now(),a=X(r.retry??t.retry),o=r.debug??t.debug??!1,i=r.throwOnError??t.throwOnError??!0,p={...t.query,...r.query},H=ye(r,t),h=r.timeout??t.timeout,b=r.auth??t.auth;b&&z(H,p,b);let R=me(t.baseUrl??"",e,Object.keys(p).length>0?p:void 0);(r.proxy??t.proxy)&&o&&console.warn("[hurl] proxy option is not supported with native fetch. Use HTTP_PROXY/HTTPS_PROXY env vars in Node.js.");let l=r.cache??t.cache,y=!!l&&!l.bypass&&s==="GET";if(y){let f=A(R,l),m=Q(f);if(m)return o&&D(m),m}let B=r.deduplicate??t.deduplicate??!1;if(B&&s==="GET"){let f=ee(R);if(f)return f}o&&te(R,{...r,method:s});let v=async f=>{let m=null,$=!1,O=new AbortController,w=null;r.signal&&(w=()=>O.abort(),r.signal.addEventListener("abort",w)),h&&(m=setTimeout(()=>{$=!0,O.abort()},h));try{let d=Te(r.body),g=r.onUploadProgress??t.onUploadProgress;d!==void 0&&g&&(r.body instanceof FormData?o&&console.warn("[hurl] onUploadProgress is not supported for FormData bodies. Use XMLHttpRequest for FormData upload progress."):d=N(d,g));let T=await fetch(R,{method:s,headers:H,body:d,signal:O.signal,redirect:r.followRedirects??!0?"follow":"manual"}),L=await W(T,n,s,r.stream??!1,r.onDownloadProgress??t.onDownloadProgress);if(!T.ok&&i)throw F({status:T.status,statusText:T.statusText,data:L,headers:C(T.headers),requestId:n,retries:f});let q=G(L,T,n,u);return y&&l&&V(A(R,l),q,l),o&&D(q),q}catch(d){let g;if(d instanceof c?g=d:d.name==="AbortError"||d.code==="ABORT_ERR"?g=$?M(h,n):j(n):g=_(d.message,n),g.retries=f,a&&Y(g,a,f))return o&&console.log(`[hurl] retrying (${f+1}/${a.count})...`),await J(a,f),v(f+1);throw o&&ne(g),g}finally{m&&clearTimeout(m),w&&r.signal&&r.signal.removeEventListener("abort",w)}},S=v(0);return B&&s==="GET"&&re(R,S),S}function x(){let e=[];return{use(r){return e.push(r),()=>{let t=e.indexOf(r);t!==-1&&e.splice(t,1)}},clear(){e.length=0},getAll(){return[...e]}}}async function se(e,r,t){let n={url:r,options:t};for(let s of e)n=await s(n.url,n.options);return n}async function ue(e,r){let t=r;for(let n of e)t=await n(t);return t}async function ie(e,r){let t=r;for(let n of e)t instanceof c&&(t=await n(t));return t}function I(e={}){let r={...e},t=x(),n=x(),s=x();async function u(o,i={}){let p=o,H=i,h=t.getAll(),b=n.getAll(),R=s.getAll();if(h.length>0){let l=await se(h,o,i);p=l.url,H=l.options}try{let l=await oe(p,H,r);return b.length>0?await ue(b,l):l}catch(l){if(l instanceof c&&R.length>0){let y=await ie(R,l);if(!(y instanceof c))return y;throw y}throw l}}return{request:u,get(o,i){return u(o,{...i,method:"GET"})},post(o,i,p){return u(o,{...p,method:"POST",body:i})},put(o,i,p){return u(o,{...p,method:"PUT",body:i})},patch(o,i,p){return u(o,{...p,method:"PATCH",body:i})},delete(o,i){return u(o,{...i,method:"DELETE"})},head(o,i){return u(o,{...i,method:"HEAD"})},options(o,i){return u(o,{...i,method:"OPTIONS"})},all(o){return Promise.all(o)},defaults:{set(o){r={...r,...o}},get(){return{...r}},reset(){r={...e}}},interceptors:{request:{use:t.use.bind(t),clear:t.clear.bind(t)},response:{use:n.use.bind(n),clear:n.clear.bind(n)},error:{use:s.use.bind(s),clear:s.clear.bind(s)}},create(o){return I({...r,...o})},extend(o){return I({...r,...o})}}}var He=I(),be=He;0&&(module.exports={HurlError,clearCache,createInstance});
1
+ "use strict";var C=Object.defineProperty;var le=Object.getOwnPropertyDescriptor;var ce=Object.getOwnPropertyNames;var pe=Object.prototype.hasOwnProperty;var fe=(e,r)=>{for(var t in r)C(e,t,{get:r[t],enumerable:!0})},de=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of ce(r))!pe.call(e,s)&&s!==t&&C(e,s,{get:()=>r[s],enumerable:!(n=le(r,s))||n.enumerable});return e};var ge=e=>de(C({},"__esModule",{value:!0}),e);var xe={};fe(xe,{HurlError:()=>c,clearCache:()=>ee,createInstance:()=>q,default:()=>we});module.exports=ge(xe);var c=class extends Error{constructor(r){super(r.message),this.name="HurlError",this.type=r.type,this.status=r.status,this.statusText=r.statusText,this.data=r.data,this.headers=r.headers,this.requestId=r.requestId,this.retries=r.retries??0}};function F(e){return new c({message:`HTTP ${e.status}: ${e.statusText}`,type:"HTTP_ERROR",...e})}function M(e,r){return new c({message:e,type:"NETWORK_ERROR",requestId:r})}function K(e,r){return new c({message:`Request timed out after ${e}ms`,type:"TIMEOUT_ERROR",requestId:r})}function j(e){return new c({message:"Request was aborted",type:"ABORT_ERROR",requestId:e})}function k(e,r){return new c({message:`Failed to parse response: ${e}`,type:"PARSE_ERROR",requestId:r})}async function N(e,r){let t=e.body?.getReader(),n=parseInt(e.headers.get("content-length")??"0",10);if(!t)return new ArrayBuffer(0);let s=[],u=0;for(;;){let{done:i,value:p}=await t.read();if(i)break;s.push(p),u+=p.byteLength,r({loaded:u,total:n,percent:n>0?Math.round(u/n*100):0})}let a=new Uint8Array(u),o=0;for(let i of s)a.set(i,o),o+=i.byteLength;return a.buffer}function W(e,r){let t=0;typeof e=="string"?t=new TextEncoder().encode(e).byteLength:e instanceof ArrayBuffer?t=e.byteLength:e instanceof Blob&&(t=e.size);let n=0;return(e instanceof ReadableStream?e:new Response(e).body).pipeThrough(new TransformStream({transform(u,a){n+=u.byteLength,r({loaded:n,total:t,percent:t>0?Math.round(n/t*100):0}),a.enqueue(u)}}))}function A(e){let r={};return e.forEach((t,n)=>{r[n]=t}),r}async function G(e,r,t,n,s){if(t==="HEAD"||e.status===204||e.headers.get("content-length")==="0")return null;if(n)return e.body;let u=e.headers.get("content-type")??"",a=u.includes("application/octet-stream")||u.includes("image/")||u.includes("video/")||u.includes("audio/");if(s&&a)try{return await N(e,s)}catch(o){throw k(o.message,r)}try{return u.includes("application/json")?await e.json():u.includes("text/")?await e.text():a?await e.arrayBuffer():await e.text()}catch(o){throw k(o.message,r)}}function z(e,r,t,n){let s=Date.now();return{data:e,status:r.status,statusText:r.statusText,headers:A(r.headers),requestId:t,timing:{start:n,end:s,duration:s-n},fromCache:!1}}function Re(e){return typeof globalThis<"u"&&globalThis.Buffer?globalThis.Buffer.from(e).toString("base64"):btoa(encodeURIComponent(e).replace(/%([0-9A-F]{2})/g,(r,t)=>String.fromCharCode(parseInt(t,16))))}function X(e,r,t){if(t.type==="bearer"&&(e.Authorization=`Bearer ${t.token}`),t.type==="basic"){let n=Re(`${t.username}:${t.password}`);e.Authorization=`Basic ${n}`}t.type==="apikey"&&(t.in==="query"?r[t.key]=t.value:e[t.key]=t.value)}function Y(e){return e==null?null:typeof e=="number"?{count:e,delay:300,backoff:"exponential"}:e}function J(e,r,t){return t>=r.count||e.type==="ABORT_ERROR"?!1:r.on&&e.status?r.on.includes(e.status):!!(e.type==="NETWORK_ERROR"||e.type==="TIMEOUT_ERROR"||e.status&&e.status>=500)}async function Z(e,r){let t=e.delay??300,n=e.backoff==="exponential"?t*Math.pow(2,r):t*(r+1);await new Promise(s=>setTimeout(s,n))}var m=new Map,me=1e3;function U(e,r){return r?.key??e}function Q(e){let r=m.get(e);if(!r)return null;if(Date.now()>r.expiresAt)return m.delete(e),null;let t=r.response.data;return t instanceof ArrayBuffer&&(t=t.slice(0)),{...r.response,data:t,fromCache:!0}}function V(e,r,t){if(m.size>=me&&!m.has(e)){let n=m.keys().next().value;n!==void 0&&m.delete(n)}m.set(e,{response:r,expiresAt:Date.now()+t.ttl})}function ee(){m.clear()}var D=new Map;function re(e){return D.get(e)??null}function te(e,r){D.set(e,r),r.finally(()=>D.delete(e))}function ne(e,r){console.group(`[hurl] \u2192 ${r.method??"GET"} ${e}`),r.headers&&Object.keys(r.headers).length>0&&console.log("headers:",r.headers),r.query&&console.log("query:",r.query),r.body&&console.log("body:",r.body),r.timeout&&console.log("timeout:",r.timeout),r.retry&&console.log("retry:",r.retry),console.groupEnd()}function B(e){let r=e.status>=400?"\u{1F534}":e.status>=300?"\u{1F7E1}":"\u{1F7E2}";console.group(`[hurl] ${r} ${e.status} ${e.statusText} (${e.timing.duration}ms)`),console.log("requestId:",e.requestId),e.fromCache&&console.log("served from cache"),console.log("headers:",e.headers),console.log("data:",e.data),console.groupEnd()}function oe(e){console.group("[hurl] \u{1F534} Error"),console.error(e),console.groupEnd()}function he(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():Math.random().toString(36).slice(2,10)}function ye(e,r,t){let n;if(r.startsWith("http://")||r.startsWith("https://")){if(e){let u=new URL(e).origin,a=new URL(r).origin;if(u!==a)throw new Error(`Absolute URL "${r}" does not match baseUrl origin "${u}". Pass the full URL without baseUrl, or use a path-relative URL.`)}n=r}else{if(r.startsWith("//"))throw new Error("Protocol-relative URLs are not supported. Use an explicit https:// or http:// scheme.");n=e?`${e.replace(/\/$/,"")}/${r.replace(/^\//,"")}`:r}if(!t||Object.keys(t).length===0)return n;let s=new URLSearchParams;for(let[u,a]of Object.entries(t))s.set(u,String(a));return`${n}?${s.toString()}`}function Te(e){return e instanceof ReadableStream||e!==null&&typeof e=="object"&&typeof e.pipe=="function"}function He(e,r){let t={...r.headers,...e.headers},n=e.body;return n!=null&&typeof n=="object"&&!(n instanceof FormData)&&!(n instanceof Blob)&&!(n instanceof ArrayBuffer)&&!Te(n)&&(t["Content-Type"]=t["Content-Type"]??"application/json"),t}function be(e){if(e!=null)return e instanceof FormData||e instanceof Blob||e instanceof ArrayBuffer||typeof e=="string"||e instanceof ReadableStream||typeof e.pipe=="function"?e:JSON.stringify(e)}async function se(e,r,t){let n=r.requestId??he(),s=r.method??"GET",u=Date.now(),a=Y(r.retry??t.retry),o=r.debug??t.debug??!1,i=r.throwOnError??t.throwOnError??!0,p={...t.query,...r.query},E=He(r,t),T=r.timeout??t.timeout,w=r.auth??t.auth;w&&X(E,p,w);let R=ye(t.baseUrl??"",e,Object.keys(p).length>0?p:void 0);(r.proxy??t.proxy)&&o&&console.warn("[hurl] proxy option is not supported with native fetch. Use HTTP_PROXY/HTTPS_PROXY env vars in Node.js.");let l=r.cache??t.cache,H=!!l&&!l.bypass&&s==="GET";if(H){let f=U(R,l),h=Q(f);if(h)return o&&B(h),h}let v=r.deduplicate??t.deduplicate??!1;if(v&&s==="GET"){let f=re(R);if(f)return f}o&&ne(R,{...r,method:s});let S=async f=>{let h=null,L=!1,x=new AbortController,y=r.signal,I=null;y&&(y.aborted?x.abort(y.reason):(I=()=>x.abort(y.reason),y.addEventListener("abort",I,{once:!0}))),T&&(h=setTimeout(()=>{L=!0,x.abort()},T));try{let d=be(r.body),g=r.onUploadProgress??t.onUploadProgress;d!==void 0&&g&&(r.body instanceof FormData?o&&console.warn("[hurl] onUploadProgress is not supported for FormData bodies. Use XMLHttpRequest for FormData upload progress."):d=W(d,g));let b=await fetch(R,{method:s,headers:E,body:d,signal:x.signal,redirect:r.followRedirects??!0?"follow":"manual"}),_=await G(b,n,s,r.stream??!1,r.onDownloadProgress??t.onDownloadProgress);if(!b.ok&&i)throw F({status:b.status,statusText:b.statusText,data:_,headers:A(b.headers),requestId:n,retries:f});let P=z(_,b,n,u);return H&&l&&V(U(R,l),P,l),o&&B(P),P}catch(d){let g;if(d instanceof c?g=d:d.name==="AbortError"||d.code==="ABORT_ERR"?g=L?K(T,n):j(n):g=M(d.message,n),g.retries=f,a&&J(g,a,f))return o&&console.log(`[hurl] retrying (${f+1}/${a.count})...`),await Z(a,f),S(f+1);throw o&&oe(g),g}finally{h&&clearTimeout(h),I&&y&&y.removeEventListener("abort",I)}},$=S(0);return v&&s==="GET"&&te(R,$),$}function O(){let e=[];return{use(r){return e.push(r),()=>{let t=e.indexOf(r);t!==-1&&e.splice(t,1)}},clear(){e.length=0},getAll(){return[...e]}}}async function ue(e,r,t){let n={url:r,options:t};for(let s of e)n=await s(n.url,n.options);return n}async function ie(e,r){let t=r;for(let n of e)t=await n(t);return t}async function ae(e,r){let t=r;for(let n of e)t instanceof c&&(t=await n(t));return t}function q(e={}){let r={...e},t=O(),n=O(),s=O();async function u(o,i={}){let p=o,E=i,T=t.getAll(),w=n.getAll(),R=s.getAll();if(T.length>0){let l=await ue(T,o,i);p=l.url,E=l.options}try{let l=await se(p,E,r);return w.length>0?await ie(w,l):l}catch(l){if(l instanceof c&&R.length>0){let H=await ae(R,l);if(!(H instanceof c))return H;throw H}throw l}}return{request:u,get(o,i){return u(o,{...i,method:"GET"})},post(o,i,p){return u(o,{...p,method:"POST",body:i})},put(o,i,p){return u(o,{...p,method:"PUT",body:i})},patch(o,i,p){return u(o,{...p,method:"PATCH",body:i})},delete(o,i){return u(o,{...i,method:"DELETE"})},head(o,i){return u(o,{...i,method:"HEAD"})},options(o,i){return u(o,{...i,method:"OPTIONS"})},all(o){return Promise.all(o)},defaults:{set(o){r={...r,...o}},get(){return{...r}},reset(){r={...e}}},interceptors:{request:{use:t.use.bind(t),clear:t.clear.bind(t)},response:{use:n.use.bind(n),clear:n.clear.bind(n)},error:{use:s.use.bind(s),clear:s.clear.bind(s)}},create(o){return q({...r,...o})},extend(o){return q({...r,...o})}}}var Ee=q(),we=Ee;0&&(module.exports={HurlError,clearCache,createInstance});
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- var p=class extends Error{constructor(r){super(r.message),this.name="HurlError",this.type=r.type,this.status=r.status,this.statusText=r.statusText,this.data=r.data,this.headers=r.headers,this.requestId=r.requestId,this.retries=r.retries??0}};function L(e){return new p({message:`HTTP ${e.status}: ${e.statusText}`,type:"HTTP_ERROR",...e})}function F(e,r){return new p({message:e,type:"NETWORK_ERROR",requestId:r})}function _(e,r){return new p({message:`Request timed out after ${e}ms`,type:"TIMEOUT_ERROR",requestId:r})}function M(e){return new p({message:"Request was aborted",type:"ABORT_ERROR",requestId:e})}function q(e,r){return new p({message:`Failed to parse response: ${e}`,type:"PARSE_ERROR",requestId:r})}async function j(e,r){let t=e.body?.getReader(),n=parseInt(e.headers.get("content-length")??"0",10);if(!t)return new ArrayBuffer(0);let u=[],s=0;for(;;){let{done:i,value:c}=await t.read();if(i)break;u.push(c),s+=c.byteLength,r({loaded:s,total:n,percent:n>0?Math.round(s/n*100):0})}let a=new Uint8Array(s),o=0;for(let i of u)a.set(i,o),o+=i.byteLength;return a.buffer}function K(e,r){let t=0;typeof e=="string"?t=new TextEncoder().encode(e).byteLength:e instanceof ArrayBuffer?t=e.byteLength:e instanceof Blob&&(t=e.size);let n=0;return(e instanceof ReadableStream?e:new Response(e).body).pipeThrough(new TransformStream({transform(s,a){n+=s.byteLength,r({loaded:n,total:t,percent:t>0?Math.round(n/t*100):0}),a.enqueue(s)}}))}function P(e){let r={};return e.forEach((t,n)=>{r[n]=t}),r}async function N(e,r,t,n,u){if(t==="HEAD"||e.status===204||e.headers.get("content-length")==="0")return null;if(n)return e.body;let s=e.headers.get("content-type")??"",a=s.includes("application/octet-stream")||s.includes("image/")||s.includes("video/")||s.includes("audio/");if(u&&a)try{return await j(e,u)}catch(o){throw q(o.message,r)}try{return s.includes("application/json")?await e.json():s.includes("text/")?await e.text():a?await e.arrayBuffer():await e.text()}catch(o){throw q(o.message,r)}}function W(e,r,t,n){let u=Date.now();return{data:e,status:r.status,statusText:r.statusText,headers:P(r.headers),requestId:t,timing:{start:n,end:u,duration:u-n},fromCache:!1}}function ue(e){return typeof globalThis<"u"&&globalThis.Buffer?globalThis.Buffer.from(e).toString("base64"):btoa(encodeURIComponent(e).replace(/%([0-9A-F]{2})/g,(r,t)=>String.fromCharCode(parseInt(t,16))))}function G(e,r,t){if(t.type==="bearer"&&(e.Authorization=`Bearer ${t.token}`),t.type==="basic"){let n=ue(`${t.username}:${t.password}`);e.Authorization=`Basic ${n}`}t.type==="apikey"&&(t.in==="query"?r[t.key]=t.value:e[t.key]=t.value)}function z(e){return e==null?null:typeof e=="number"?{count:e,delay:300,backoff:"exponential"}:e}function X(e,r,t){return t>=r.count||e.type==="ABORT_ERROR"?!1:r.on&&e.status?r.on.includes(e.status):!!(e.type==="NETWORK_ERROR"||e.type==="TIMEOUT_ERROR"||e.status&&e.status>=500)}async function Y(e,r){let t=e.delay??300,n=e.backoff==="exponential"?t*Math.pow(2,r):t*(r+1);await new Promise(u=>setTimeout(u,n))}var E=new Map;function k(e,r){return r?.key??e}function J(e){let r=E.get(e);return r?Date.now()>r.expiresAt?(E.delete(e),null):{...r.response,fromCache:!0}:null}function Q(e,r,t){E.set(e,{response:r,expiresAt:Date.now()+t.ttl})}function ie(){E.clear()}var C=new Map;function V(e){return C.get(e)??null}function Z(e,r){C.set(e,r),r.finally(()=>C.delete(e))}function ee(e,r){console.group(`[hurl] \u2192 ${r.method??"GET"} ${e}`),r.headers&&Object.keys(r.headers).length>0&&console.log("headers:",r.headers),r.query&&console.log("query:",r.query),r.body&&console.log("body:",r.body),r.timeout&&console.log("timeout:",r.timeout),r.retry&&console.log("retry:",r.retry),console.groupEnd()}function A(e){let r=e.status>=400?"\u{1F534}":e.status>=300?"\u{1F7E1}":"\u{1F7E2}";console.group(`[hurl] ${r} ${e.status} ${e.statusText} (${e.timing.duration}ms)`),console.log("requestId:",e.requestId),e.fromCache&&console.log("served from cache"),console.log("headers:",e.headers),console.log("data:",e.data),console.groupEnd()}function re(e){console.group("[hurl] \u{1F534} Error"),console.error(e),console.groupEnd()}function ae(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():Math.random().toString(36).slice(2,10)}function le(e,r,t){let n;if(r.startsWith("http://")||r.startsWith("https://")){if(e){let s=new URL(e).origin,a=new URL(r).origin;if(s!==a)throw new Error(`Absolute URL "${r}" does not match baseUrl origin "${s}". Pass the full URL without baseUrl, or use a path-relative URL.`)}n=r}else{if(r.startsWith("//"))throw new Error("Protocol-relative URLs are not supported. Use an explicit https:// or http:// scheme.");n=e?`${e.replace(/\/$/,"")}/${r.replace(/^\//,"")}`:r}if(!t||Object.keys(t).length===0)return n;let u=new URLSearchParams;for(let[s,a]of Object.entries(t))u.set(s,String(a));return`${n}?${u.toString()}`}function ce(e){return e instanceof ReadableStream||e!==null&&typeof e=="object"&&typeof e.pipe=="function"}function pe(e,r){let t={...r.headers,...e.headers},n=e.body;return n!=null&&typeof n=="object"&&!(n instanceof FormData)&&!(n instanceof Blob)&&!(n instanceof ArrayBuffer)&&!ce(n)&&(t["Content-Type"]=t["Content-Type"]??"application/json"),t}function fe(e){if(e!=null)return e instanceof FormData||e instanceof Blob||e instanceof ArrayBuffer||typeof e=="string"||e instanceof ReadableStream||typeof e.pipe=="function"?e:JSON.stringify(e)}async function te(e,r,t){let n=r.requestId??ae(),u=r.method??"GET",s=Date.now(),a=z(r.retry??t.retry),o=r.debug??t.debug??!1,i=r.throwOnError??t.throwOnError??!0,c={...t.query,...r.query},H=pe(r,t),h=r.timeout??t.timeout,b=r.auth??t.auth;b&&G(H,c,b);let R=le(t.baseUrl??"",e,Object.keys(c).length>0?c:void 0);(r.proxy??t.proxy)&&o&&console.warn("[hurl] proxy option is not supported with native fetch. Use HTTP_PROXY/HTTPS_PROXY env vars in Node.js.");let l=r.cache??t.cache,y=!!l&&!l.bypass&&u==="GET";if(y){let f=k(R,l),m=J(f);if(m)return o&&A(m),m}let D=r.deduplicate??t.deduplicate??!1;if(D&&u==="GET"){let f=V(R);if(f)return f}o&&ee(R,{...r,method:u});let B=async f=>{let m=null,S=!1,I=new AbortController,w=null;r.signal&&(w=()=>I.abort(),r.signal.addEventListener("abort",w)),h&&(m=setTimeout(()=>{S=!0,I.abort()},h));try{let d=fe(r.body),g=r.onUploadProgress??t.onUploadProgress;d!==void 0&&g&&(r.body instanceof FormData?o&&console.warn("[hurl] onUploadProgress is not supported for FormData bodies. Use XMLHttpRequest for FormData upload progress."):d=K(d,g));let T=await fetch(R,{method:u,headers:H,body:d,signal:I.signal,redirect:r.followRedirects??!0?"follow":"manual"}),$=await N(T,n,u,r.stream??!1,r.onDownloadProgress??t.onDownloadProgress);if(!T.ok&&i)throw L({status:T.status,statusText:T.statusText,data:$,headers:P(T.headers),requestId:n,retries:f});let O=W($,T,n,s);return y&&l&&Q(k(R,l),O,l),o&&A(O),O}catch(d){let g;if(d instanceof p?g=d:d.name==="AbortError"||d.code==="ABORT_ERR"?g=S?_(h,n):M(n):g=F(d.message,n),g.retries=f,a&&X(g,a,f))return o&&console.log(`[hurl] retrying (${f+1}/${a.count})...`),await Y(a,f),B(f+1);throw o&&re(g),g}finally{m&&clearTimeout(m),w&&r.signal&&r.signal.removeEventListener("abort",w)}},v=B(0);return D&&u==="GET"&&Z(R,v),v}function x(){let e=[];return{use(r){return e.push(r),()=>{let t=e.indexOf(r);t!==-1&&e.splice(t,1)}},clear(){e.length=0},getAll(){return[...e]}}}async function ne(e,r,t){let n={url:r,options:t};for(let u of e)n=await u(n.url,n.options);return n}async function oe(e,r){let t=r;for(let n of e)t=await n(t);return t}async function se(e,r){let t=r;for(let n of e)t instanceof p&&(t=await n(t));return t}function U(e={}){let r={...e},t=x(),n=x(),u=x();async function s(o,i={}){let c=o,H=i,h=t.getAll(),b=n.getAll(),R=u.getAll();if(h.length>0){let l=await ne(h,o,i);c=l.url,H=l.options}try{let l=await te(c,H,r);return b.length>0?await oe(b,l):l}catch(l){if(l instanceof p&&R.length>0){let y=await se(R,l);if(!(y instanceof p))return y;throw y}throw l}}return{request:s,get(o,i){return s(o,{...i,method:"GET"})},post(o,i,c){return s(o,{...c,method:"POST",body:i})},put(o,i,c){return s(o,{...c,method:"PUT",body:i})},patch(o,i,c){return s(o,{...c,method:"PATCH",body:i})},delete(o,i){return s(o,{...i,method:"DELETE"})},head(o,i){return s(o,{...i,method:"HEAD"})},options(o,i){return s(o,{...i,method:"OPTIONS"})},all(o){return Promise.all(o)},defaults:{set(o){r={...r,...o}},get(){return{...r}},reset(){r={...e}}},interceptors:{request:{use:t.use.bind(t),clear:t.clear.bind(t)},response:{use:n.use.bind(n),clear:n.clear.bind(n)},error:{use:u.use.bind(u),clear:u.clear.bind(u)}},create(o){return U({...r,...o})},extend(o){return U({...r,...o})}}}var de=U(),nr=de;export{p as HurlError,ie as clearCache,U as createInstance,nr as default};
1
+ var p=class extends Error{constructor(r){super(r.message),this.name="HurlError",this.type=r.type,this.status=r.status,this.statusText=r.statusText,this.data=r.data,this.headers=r.headers,this.requestId=r.requestId,this.retries=r.retries??0}};function _(e){return new p({message:`HTTP ${e.status}: ${e.statusText}`,type:"HTTP_ERROR",...e})}function F(e,r){return new p({message:e,type:"NETWORK_ERROR",requestId:r})}function M(e,r){return new p({message:`Request timed out after ${e}ms`,type:"TIMEOUT_ERROR",requestId:r})}function K(e){return new p({message:"Request was aborted",type:"ABORT_ERROR",requestId:e})}function P(e,r){return new p({message:`Failed to parse response: ${e}`,type:"PARSE_ERROR",requestId:r})}async function j(e,r){let t=e.body?.getReader(),n=parseInt(e.headers.get("content-length")??"0",10);if(!t)return new ArrayBuffer(0);let u=[],s=0;for(;;){let{done:i,value:c}=await t.read();if(i)break;u.push(c),s+=c.byteLength,r({loaded:s,total:n,percent:n>0?Math.round(s/n*100):0})}let a=new Uint8Array(s),o=0;for(let i of u)a.set(i,o),o+=i.byteLength;return a.buffer}function N(e,r){let t=0;typeof e=="string"?t=new TextEncoder().encode(e).byteLength:e instanceof ArrayBuffer?t=e.byteLength:e instanceof Blob&&(t=e.size);let n=0;return(e instanceof ReadableStream?e:new Response(e).body).pipeThrough(new TransformStream({transform(s,a){n+=s.byteLength,r({loaded:n,total:t,percent:t>0?Math.round(n/t*100):0}),a.enqueue(s)}}))}function C(e){let r={};return e.forEach((t,n)=>{r[n]=t}),r}async function W(e,r,t,n,u){if(t==="HEAD"||e.status===204||e.headers.get("content-length")==="0")return null;if(n)return e.body;let s=e.headers.get("content-type")??"",a=s.includes("application/octet-stream")||s.includes("image/")||s.includes("video/")||s.includes("audio/");if(u&&a)try{return await j(e,u)}catch(o){throw P(o.message,r)}try{return s.includes("application/json")?await e.json():s.includes("text/")?await e.text():a?await e.arrayBuffer():await e.text()}catch(o){throw P(o.message,r)}}function G(e,r,t,n){let u=Date.now();return{data:e,status:r.status,statusText:r.statusText,headers:C(r.headers),requestId:t,timing:{start:n,end:u,duration:u-n},fromCache:!1}}function ie(e){return typeof globalThis<"u"&&globalThis.Buffer?globalThis.Buffer.from(e).toString("base64"):btoa(encodeURIComponent(e).replace(/%([0-9A-F]{2})/g,(r,t)=>String.fromCharCode(parseInt(t,16))))}function z(e,r,t){if(t.type==="bearer"&&(e.Authorization=`Bearer ${t.token}`),t.type==="basic"){let n=ie(`${t.username}:${t.password}`);e.Authorization=`Basic ${n}`}t.type==="apikey"&&(t.in==="query"?r[t.key]=t.value:e[t.key]=t.value)}function X(e){return e==null?null:typeof e=="number"?{count:e,delay:300,backoff:"exponential"}:e}function Y(e,r,t){return t>=r.count||e.type==="ABORT_ERROR"?!1:r.on&&e.status?r.on.includes(e.status):!!(e.type==="NETWORK_ERROR"||e.type==="TIMEOUT_ERROR"||e.status&&e.status>=500)}async function J(e,r){let t=e.delay??300,n=e.backoff==="exponential"?t*Math.pow(2,r):t*(r+1);await new Promise(u=>setTimeout(u,n))}var m=new Map,ae=1e3;function k(e,r){return r?.key??e}function Z(e){let r=m.get(e);if(!r)return null;if(Date.now()>r.expiresAt)return m.delete(e),null;let t=r.response.data;return t instanceof ArrayBuffer&&(t=t.slice(0)),{...r.response,data:t,fromCache:!0}}function Q(e,r,t){if(m.size>=ae&&!m.has(e)){let n=m.keys().next().value;n!==void 0&&m.delete(n)}m.set(e,{response:r,expiresAt:Date.now()+t.ttl})}function le(){m.clear()}var A=new Map;function V(e){return A.get(e)??null}function ee(e,r){A.set(e,r),r.finally(()=>A.delete(e))}function re(e,r){console.group(`[hurl] \u2192 ${r.method??"GET"} ${e}`),r.headers&&Object.keys(r.headers).length>0&&console.log("headers:",r.headers),r.query&&console.log("query:",r.query),r.body&&console.log("body:",r.body),r.timeout&&console.log("timeout:",r.timeout),r.retry&&console.log("retry:",r.retry),console.groupEnd()}function U(e){let r=e.status>=400?"\u{1F534}":e.status>=300?"\u{1F7E1}":"\u{1F7E2}";console.group(`[hurl] ${r} ${e.status} ${e.statusText} (${e.timing.duration}ms)`),console.log("requestId:",e.requestId),e.fromCache&&console.log("served from cache"),console.log("headers:",e.headers),console.log("data:",e.data),console.groupEnd()}function te(e){console.group("[hurl] \u{1F534} Error"),console.error(e),console.groupEnd()}function ce(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():Math.random().toString(36).slice(2,10)}function pe(e,r,t){let n;if(r.startsWith("http://")||r.startsWith("https://")){if(e){let s=new URL(e).origin,a=new URL(r).origin;if(s!==a)throw new Error(`Absolute URL "${r}" does not match baseUrl origin "${s}". Pass the full URL without baseUrl, or use a path-relative URL.`)}n=r}else{if(r.startsWith("//"))throw new Error("Protocol-relative URLs are not supported. Use an explicit https:// or http:// scheme.");n=e?`${e.replace(/\/$/,"")}/${r.replace(/^\//,"")}`:r}if(!t||Object.keys(t).length===0)return n;let u=new URLSearchParams;for(let[s,a]of Object.entries(t))u.set(s,String(a));return`${n}?${u.toString()}`}function fe(e){return e instanceof ReadableStream||e!==null&&typeof e=="object"&&typeof e.pipe=="function"}function de(e,r){let t={...r.headers,...e.headers},n=e.body;return n!=null&&typeof n=="object"&&!(n instanceof FormData)&&!(n instanceof Blob)&&!(n instanceof ArrayBuffer)&&!fe(n)&&(t["Content-Type"]=t["Content-Type"]??"application/json"),t}function ge(e){if(e!=null)return e instanceof FormData||e instanceof Blob||e instanceof ArrayBuffer||typeof e=="string"||e instanceof ReadableStream||typeof e.pipe=="function"?e:JSON.stringify(e)}async function ne(e,r,t){let n=r.requestId??ce(),u=r.method??"GET",s=Date.now(),a=X(r.retry??t.retry),o=r.debug??t.debug??!1,i=r.throwOnError??t.throwOnError??!0,c={...t.query,...r.query},E=de(r,t),T=r.timeout??t.timeout,w=r.auth??t.auth;w&&z(E,c,w);let R=pe(t.baseUrl??"",e,Object.keys(c).length>0?c:void 0);(r.proxy??t.proxy)&&o&&console.warn("[hurl] proxy option is not supported with native fetch. Use HTTP_PROXY/HTTPS_PROXY env vars in Node.js.");let l=r.cache??t.cache,H=!!l&&!l.bypass&&u==="GET";if(H){let f=k(R,l),h=Z(f);if(h)return o&&U(h),h}let B=r.deduplicate??t.deduplicate??!1;if(B&&u==="GET"){let f=V(R);if(f)return f}o&&re(R,{...r,method:u});let v=async f=>{let h=null,$=!1,x=new AbortController,y=r.signal,I=null;y&&(y.aborted?x.abort(y.reason):(I=()=>x.abort(y.reason),y.addEventListener("abort",I,{once:!0}))),T&&(h=setTimeout(()=>{$=!0,x.abort()},T));try{let d=ge(r.body),g=r.onUploadProgress??t.onUploadProgress;d!==void 0&&g&&(r.body instanceof FormData?o&&console.warn("[hurl] onUploadProgress is not supported for FormData bodies. Use XMLHttpRequest for FormData upload progress."):d=N(d,g));let b=await fetch(R,{method:u,headers:E,body:d,signal:x.signal,redirect:r.followRedirects??!0?"follow":"manual"}),L=await W(b,n,u,r.stream??!1,r.onDownloadProgress??t.onDownloadProgress);if(!b.ok&&i)throw _({status:b.status,statusText:b.statusText,data:L,headers:C(b.headers),requestId:n,retries:f});let q=G(L,b,n,s);return H&&l&&Q(k(R,l),q,l),o&&U(q),q}catch(d){let g;if(d instanceof p?g=d:d.name==="AbortError"||d.code==="ABORT_ERR"?g=$?M(T,n):K(n):g=F(d.message,n),g.retries=f,a&&Y(g,a,f))return o&&console.log(`[hurl] retrying (${f+1}/${a.count})...`),await J(a,f),v(f+1);throw o&&te(g),g}finally{h&&clearTimeout(h),I&&y&&y.removeEventListener("abort",I)}},S=v(0);return B&&u==="GET"&&ee(R,S),S}function O(){let e=[];return{use(r){return e.push(r),()=>{let t=e.indexOf(r);t!==-1&&e.splice(t,1)}},clear(){e.length=0},getAll(){return[...e]}}}async function oe(e,r,t){let n={url:r,options:t};for(let u of e)n=await u(n.url,n.options);return n}async function se(e,r){let t=r;for(let n of e)t=await n(t);return t}async function ue(e,r){let t=r;for(let n of e)t instanceof p&&(t=await n(t));return t}function D(e={}){let r={...e},t=O(),n=O(),u=O();async function s(o,i={}){let c=o,E=i,T=t.getAll(),w=n.getAll(),R=u.getAll();if(T.length>0){let l=await oe(T,o,i);c=l.url,E=l.options}try{let l=await ne(c,E,r);return w.length>0?await se(w,l):l}catch(l){if(l instanceof p&&R.length>0){let H=await ue(R,l);if(!(H instanceof p))return H;throw H}throw l}}return{request:s,get(o,i){return s(o,{...i,method:"GET"})},post(o,i,c){return s(o,{...c,method:"POST",body:i})},put(o,i,c){return s(o,{...c,method:"PUT",body:i})},patch(o,i,c){return s(o,{...c,method:"PATCH",body:i})},delete(o,i){return s(o,{...i,method:"DELETE"})},head(o,i){return s(o,{...i,method:"HEAD"})},options(o,i){return s(o,{...i,method:"OPTIONS"})},all(o){return Promise.all(o)},defaults:{set(o){r={...r,...o}},get(){return{...r}},reset(){r={...e}}},interceptors:{request:{use:t.use.bind(t),clear:t.clear.bind(t)},response:{use:n.use.bind(n),clear:n.clear.bind(n)},error:{use:u.use.bind(u),clear:u.clear.bind(u)}},create(o){return D({...r,...o})},extend(o){return D({...r,...o})}}}var Re=D(),sr=Re;export{p as HurlError,le as clearCache,D as createInstance,sr as default};
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@firekid/hurl",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Zero-dependency HTTP client for Node.js and edge runtimes. Built on fetch. The modern replacement for axios, request, got, node-fetch, and ky. Works on Cloudflare Workers, Vercel Edge, Deno, and Bun.",
5
- "main": "./dist/index.cjs",
5
+ "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
7
7
  "types": "./dist/index.d.ts",
8
8
  "exports": {
9
9
  ".": {
10
10
  "types": "./dist/index.d.ts",
11
11
  "import": "./dist/index.mjs",
12
- "require": "./dist/index.cjs"
12
+ "require": "./dist/index.js"
13
13
  }
14
14
  },
15
15
  "files": [
@@ -106,4 +106,4 @@
106
106
  "typescript": "^5.0.0",
107
107
  "vitest": "^1.0.0"
108
108
  }
109
- }
109
+ }