1000fetches 0.2.1 → 0.2.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 Max Tarsis
3
+ Copyright (c) 2026 Max Tarsis
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -30,8 +30,8 @@ A type-first HTTP client that unifies validation, retries, streaming, and middle
30
30
 
31
31
  - 🧭 **Compile-time path safety** — `:pathParam` can't slip through undefined
32
32
  - 🧩 **Schema-driven validation** — infer types at build time, verify data at runtime
33
- - ⚡ **Native streaming** — observe, transform, or pipe data chunks as they flow
34
- - 🔁 **Retries, timeouts, middleware** — production essentials, zero config
33
+ - ⚡ **Streaming telemetry** — observe upload/download chunks and progress as data flows
34
+ - 🔁 **Retries, timeouts, middleware** — production essentials with opt-ins
35
35
  - 🎯 **Method-based API** — `api.get()` with schema validation `.schema()` and extractor `.data()` for clean and concise code
36
36
  - 🧠 **Designed for flow** — clear API, predictable behavior, no hidden magic
37
37
 
@@ -55,7 +55,8 @@ const api = createHttpClient({
55
55
  // Define schemas for types and safety
56
56
  const userSchema = z.object({
57
57
  id: z.number(),
58
- ...
58
+ name: z.string(),
59
+ email: z.email(),
59
60
  })
60
61
 
61
62
  // Request data with schema validation
@@ -76,34 +77,40 @@ const user = await api
76
77
  // user 👉 { id: number, ... }
77
78
  ```
78
79
 
79
- **Or use the default client for quick requests:**
80
+ **Or use the shortcut client for quick requests with absolute URLs:**
80
81
 
81
82
  ```ts
82
- import http from '1000fetches'
83
+ import http from '1000fetches/http'
83
84
 
84
85
  const user = await http
85
- .get('/users/:id', {
86
+ .get('https://api.example.com/users/:id', {
86
87
  pathParams: { id: '123' },
87
88
  })
88
89
  .schema(userSchema)
90
+ .data()
89
91
  ```
90
92
 
93
+ With native Node `fetch`, requests must resolve to absolute URLs. Use an absolute `baseUrl` in Node, or provide a custom `fetch` implementation that supports relative URLs.
94
+
95
+ The `1000fetches/http` subpath intentionally exports only this default client. Use `1000fetches` when you need named exports like `createHttpClient` or error classes.
96
+
91
97
  ## ➡️ Key Features
92
98
 
93
99
  ### ✔️ Type Safety That Actually Works
94
100
 
95
101
  - **Compile-time path validation** — TypeScript catches missing `:userId` parameters before runtime
102
+ - **Trailing optional path params only** — `'/users/:id?'` supported, `'/users/:id?/cards/:cardId'` rejected
96
103
  - **Runtime schema validation** — Schemas verify data at the network boundary
97
104
  - **Schema-based type inference** — Types inferred from schemas, no generics needed
98
105
  - **Multi-schema support** — [Zod](https://github.com/colinhacks/zod), [Valibot](https://github.com/fabian-hiller/valibot), [ArkType](https://github.com/arktypeio/arktype), or any [Standard Schema](https://github.com/standard-schema/standard-schema)-compatible library
99
106
 
100
107
  ### ✔️ Production-Ready Quality
101
108
 
102
- - **Smart retry logic** — Exponential backoff with jitter for resilient requests
109
+ - **Smart retry logic** — Opt-in exponential backoff for resilient requests
103
110
  - **Timeout and cancellation support** — Built-in `AbortController` integration
104
111
  - **Structured error handling** — `HttpError`, `NetworkError`, `TimeoutError` with full context
105
112
  - **Request/Response middleware** — Authentication, logging, transformations
106
- - **Minimalistic footprint** — Enterprise features without the bloat
113
+ - **Minimalistic footprint** — Production features without the bloat
107
114
 
108
115
  ### ✔️ Engineer-Friendly DX
109
116
 
@@ -111,11 +118,11 @@ const user = await http
111
118
  - **Schema-first validation** — Chain `.schema()` for runtime validation and automatic type inference
112
119
  - **Smart data extraction** — Chain `.data()` for direct value access without `.data` property
113
120
  - **Automatic response parsing** — JSON/text responses parsed automatically
114
- - **Real-time streaming** — Access actual data chunks during upload/download
115
- - **Zero dependencies** — Optional peer dependencies, tree-shakable builds
121
+ - **Chunk telemetry** — Observe upload/download chunks and byte progress
122
+ - **Tiny runtime footprint** — one tiny Standard Schema type dependency, tree-shakable builds
116
123
  - **TypeScript-first** — Full type inference and `IntelliSense` support
117
124
 
118
- **1000fetches** combines native `fetch` performance with enterprise-grade features and bulletproof type safety.
125
+ **1000fetches** combines native `fetch` performance with production-oriented features and schema-backed type safety.
119
126
 
120
127
  ## ➡️ Usage Examples
121
128
 
@@ -144,8 +151,10 @@ const api = createHttpClient({
144
151
  // Upload progress with actual data chunks
145
152
  await api.post('/api/files', fileData, {
146
153
  onUploadStreaming: ({ chunk, transferredBytes, totalBytes }) => {
147
- const progress = Math.round((transferredBytes / totalBytes) * 100)
148
- console.log(`Uploading: ${progress}% - chunk size: ${chunk.length} bytes`)
154
+ const progress = totalBytes
155
+ ? `${Math.round((transferredBytes / totalBytes) * 100)}%`
156
+ : `${transferredBytes} bytes`
157
+ console.log(`Uploading: ${progress} - chunk size: ${chunk.length} bytes`)
149
158
  },
150
159
  })
151
160
 
@@ -153,8 +162,10 @@ await api.post('/api/files', fileData, {
153
162
  await api.get('/api/files/:id', {
154
163
  pathParams: { id: '123' },
155
164
  onDownloadStreaming: ({ chunk, transferredBytes, totalBytes }) => {
156
- const progress = Math.round((transferredBytes / totalBytes) * 100)
157
- console.log(`Downloading: ${progress}% - chunk size: ${chunk.length} bytes`)
165
+ const progress = totalBytes
166
+ ? `${Math.round((transferredBytes / totalBytes) * 100)}%`
167
+ : `${transferredBytes} bytes`
168
+ console.log(`Downloading: ${progress} - chunk size: ${chunk.length} bytes`)
158
169
  },
159
170
  })
160
171
  ```
@@ -168,6 +179,7 @@ import {
168
179
  TimeoutError,
169
180
  MiddlewareError,
170
181
  PathParameterError,
182
+ SchemaValidationError,
171
183
  } from '1000fetches'
172
184
 
173
185
  try {
@@ -187,6 +199,8 @@ try {
187
199
  console.log('Middleware error:', error.message)
188
200
  } else if (error instanceof PathParameterError) {
189
201
  console.log('Path parameter error:', error.message)
202
+ } else if (error instanceof SchemaValidationError) {
203
+ console.log('Schema validation error:', error.message)
190
204
  }
191
205
  }
192
206
  ```
@@ -198,20 +212,20 @@ try {
198
212
  Creates a new HTTP client with optional configuration.
199
213
 
200
214
  ```ts
201
- function createHttpClient(config?: HttpClientConfig): HttpClient
215
+ function createHttpClient(config?: HttpClientConfig)
202
216
  ```
203
217
 
204
218
  **Configuration Options:**
205
219
 
206
- | Option | Type | Description |
207
- | ---------------------- | --------------------------------------------- | ------------------------------- |
208
- | `baseUrl` | `string` | Base URL for all requests |
209
- | `headers` | `Record<string, string>` | Default headers |
210
- | `timeout` | `number` | Default timeout in milliseconds |
211
- | `retryOptions` | `RetryOptions` | Default retry configuration |
212
- | `onRequestMiddleware` | `(context: RequestContext) => RequestContext` | Request middleware |
213
- | `onResponseMiddleware` | `(response: ResponseType) => ResponseType` | Response middleware |
214
- | `schemaValidator` | `SchemaValidator` | Custom schema validator |
220
+ | Option | Type | Description |
221
+ | ---------------------- | ------------------------------------------------------------------------ | ---------------------------------- |
222
+ | `baseUrl` | `string` | Absolute or root-relative base URL |
223
+ | `headers` | `Record<string, string>` | Default headers |
224
+ | `timeout` | `number` | Default timeout in milliseconds |
225
+ | `retry` | `RetryOptions \| boolean` | Opt-in retry configuration |
226
+ | `onRequestMiddleware` | `(context: RequestContext) => RequestContext \| Promise<RequestContext>` | Request middleware |
227
+ | `onResponseMiddleware` | `(response: ResponseType) => ResponseType \| Promise<ResponseType>` | Response middleware |
228
+ | `schemaValidator` | `SchemaValidator` | Custom schema validator |
215
229
 
216
230
  ### <samp>HTTP Methods</samp>
217
231
 
@@ -228,10 +242,7 @@ const user = await api
228
242
  // user 👉 Fully typed user object
229
243
 
230
244
  // POST
231
- const newUser = await api
232
- .post('/users', userData)
233
- .schema(userSchema)
234
- .data()
245
+ const newUser = await api.post('/users', userData).schema(userSchema).data()
235
246
  // newUser 👉 Fully typed user object
236
247
 
237
248
  // PUT
@@ -260,23 +271,40 @@ await api.delete('/users/:id', {
260
271
 
261
272
  ### <samp>Request Options</samp>
262
273
 
263
- | Option | Type | Description |
264
- | --------------------- | ---------------------------------------------------------- | --------------------------------- |
265
- | `pathParams` | `Record<string, string \| number>` | Path parameters for URL templates |
266
- | `params` | `Record<string, string \| number \| boolean \| undefined>` | Query parameters |
267
- | `headers` | `Record<string, string>` | Request headers |
268
- | `body` | `any` | Request body |
269
- | `timeout` | `number` | Request timeout |
270
- | `signal` | `AbortSignal` | Request cancellation signal |
271
- | `validateStatus` | `(status: number) => boolean` | Custom status validation |
272
- | `responseType` | `'text' \| 'blob' \| 'arrayBuffer'` | Response type override |
273
- | `cache` | `RequestCache` | Cache mode |
274
- | `credentials` | `RequestCredentials` | Credentials mode |
275
- | `mode` | `RequestMode` | Request mode |
276
- | `redirect` | `RequestRedirect` | Redirect mode |
277
- | `retryOptions` | `RetryOptions` | Retry configuration |
278
- | `onUploadStreaming` | `(event: UploadStreamingEvent) => void` | Upload streaming callback |
279
- | `onDownloadStreaming` | `(event: DownloadStreamingEvent) => void` | Download streaming callback |
274
+ | Option | Type | Description |
275
+ | --------------------- | ----------------------------------------------------------- | --------------------------------- |
276
+ | `pathParams` | `Record<string, string \| number \| undefined>` | Path parameters for URL templates |
277
+ | `params` | `RequestParamsType` | Query parameters |
278
+ | `headers` | `Record<string, string>` | Request headers |
279
+ | `body` | `TBody` | Request body |
280
+ | `timeout` | `number` | Request timeout |
281
+ | `signal` | `AbortSignal` | Request cancellation signal |
282
+ | `responseType` | `'json' \| 'text' \| 'blob' \| 'arrayBuffer' \| 'formData'` | Response type override |
283
+ | `cache` | `RequestCache` | Cache mode |
284
+ | `credentials` | `RequestCredentials` | Credentials mode |
285
+ | `mode` | `RequestMode` | Request mode |
286
+ | `redirect` | `RequestRedirect` | Redirect mode |
287
+ | `fetchOptions` | `FetchOptions` | Native Fetch/Node passthrough |
288
+ | `retry` | `RetryOptions \| boolean` | Retry configuration |
289
+ | `onUploadStreaming` | `(event: UploadStreamingEvent) => void` | Upload streaming callback |
290
+ | `onDownloadStreaming` | `(event: DownloadStreamingEvent) => void` | Download streaming callback |
291
+
292
+ ### <samp>Retry Options</samp>
293
+
294
+ Retries are disabled unless you set client `retry`, request `retry: true`, or request retry settings. The built-in policy retries idempotent methods by default (`GET`, `HEAD`, `OPTIONS`, `PUT`, `DELETE`), honors `Retry-After`, supports jitter, and never retries one-shot request streams.
295
+
296
+ ```ts
297
+ const api = createHttpClient({
298
+ retry: {
299
+ maxRetries: 3,
300
+ retryDelay: 250,
301
+ jitter: 'full',
302
+ onRetry: event => {
303
+ console.log(event.method, event.url, event.nextAttempt)
304
+ },
305
+ },
306
+ })
307
+ ```
280
308
 
281
309
  ### <samp>Response Object</samp>
282
310
 
@@ -287,8 +315,8 @@ interface ResponseType<T> {
287
315
  data: T // Parsed response data
288
316
  status: number // HTTP status code
289
317
  statusText: string // HTTP status text
290
- headers: Record<string, string> // Response headers
291
- method: HttpMethod // HTTP method used
318
+ headers: HttpHeaders // Response headers
319
+ method: HttpMethod
292
320
  url: string // Final URL
293
321
  raw: Response // Raw fetch Response
294
322
  }
@@ -337,10 +365,7 @@ const user = await api
337
365
  // user 👉 { id: number, ... }
338
366
 
339
367
  // Works with all HTTP methods
340
- const newUser = await api
341
- .post('/users', userData)
342
- .schema(userSchema)
343
- .data()
368
+ const newUser = await api.post('/users', userData).schema(userSchema).data()
344
369
  // newUser 👉 Fully typed user object
345
370
 
346
371
  const updatedUser = await api
@@ -348,24 +373,25 @@ const updatedUser = await api
348
373
  .schema(userSchema)
349
374
  .data()
350
375
  // updatedUser 👉 Fully typed user object
376
+
377
+ // Run the request and intentionally ignore response data
378
+ await api.delete('/users/:id', { pathParams: { id: '123' } }).void()
351
379
  ```
352
380
 
353
- ## ➡️ Feature Comparison
354
-
355
- **1000fetches vs Popular Alternatives**
356
-
357
- | Feature | 1000fetches | Axios | Better-fetch | Up-fetch | Native Fetch |
358
- | --------------------- | ----------------- | --------------- | ------------------ | ------------------ | ------------------ |
359
- | **Bundle Size (gz)** | ≈4.3 kB | ≈14.75 kB | ≈3.07 kB | ≈1.6 kB | 0 kB |
360
- | **TypeScript** | Full inference | ⚠️ Limited | ⚠️ Limited | ✅ Good | ❌ Manual |
361
- | **Path Params** | Compile-time | Manual | Manual | Manual | ❌ Manual |
362
- | **Schema Validation** | ✅ Multi-library | None | ⚠️ Limited | Multi-library | ❌ None |
363
- | **Retry Logic** | Built-in | Built-in | Manual | Built-in | Manual |
364
- | **Error Handling** | Structured | Good | ⚠️ Basic | ✅ Good | ⚠️ Verbose |
365
- | **Middleware** | Full support | Full support | ⚠️ Limited | ✅ Lifecycle hooks | ❌ None |
366
- | **Streaming** | Real chunks | None | None | Real chunks | ✅ Native |
367
- | **API Design** | ✅ Method-based | ✅ Method-based | ❌ Single function | ❌ Single function | ❌ Single function |
368
- | **Tree Shaking** | ✅ Good | ⚠️ Partial | ✅ Good | ✅ Perfect | ✅ |
381
+ ## ➡️ Design Trade-Offs
382
+
383
+ 1000fetches is intentionally small, but it is not just a thin `fetch` alias. It focuses on the features that tend to become repetitive in application code:
384
+
385
+ | Capability | What 1000fetches Provides |
386
+ | --------------------- | --------------------------------------------------------------------- |
387
+ | **TypeScript** | Schema-inferred response types and typed path parameters |
388
+ | **Path Params** | Compile-time and runtime checks for `:param` placeholders |
389
+ | **Schema Validation** | Standard Schema support for Zod, Valibot, ArkType, and more |
390
+ | **Retry Logic** | Opt-in retry policy with backoff, jitter, and `Retry-After` |
391
+ | **Error Handling** | Structured errors for HTTP, network, timeout, and validation failures |
392
+ | **Middleware** | Request and response middleware with typed context |
393
+ | **Streaming** | Upload/download chunk telemetry through callback hooks |
394
+ | **Tree Shaking** | Side-effect-free ESM/CJS builds with a default-only `./http` shortcut |
369
395
 
370
396
  ---
371
397
 
@@ -0,0 +1,2 @@
1
+ var e=class extends Error{name="HttpError";status;statusText;data;response;url;method;cause;constructor(e,t,r,n,a,o,s,i){const c=`HTTP ${t>=500?"Server Error":t>=400?"Client Error":t>=300?"Redirect":"Success"} (${t}): ${e}\nRequest: ${s} ${o}\nData: ${function(e){if(null==e||""===e)return"No response data";let t;try{t="string"==typeof e?e:JSON.stringify(e)}catch{t=String(e)}return t.length>500?t.substring(0,500)+"...":t}(n)}`;super(c,{cause:i}),this.status=t,this.statusText=r,this.data=n,this.response=a,this.url=o,this.method=s,this.cause=i}},t=class extends Error{name="NetworkError";cause;constructor(e,t){super(e,{cause:t}),this.cause=t}},r=class extends Error{name="SchemaValidationError";schema;data;issues;cause;constructor(e,t,r,n,a){super(e,{cause:n}),this.schema=t,this.data=r,this.issues=a,this.cause=n}},n=class extends Error{name="TimeoutError";cause;constructor(e,t){super(e,{cause:t}),this.cause=t}},a=class extends Error{name="PathParameterError";url;requiredParams;providedParams;cause;constructor(e,t,r,n,a){super(`${e}\nURL Template: ${t}\nExpected: [${r.map(e=>`"${e}"`).join(", ")}], Actual: [${n.map(e=>`"${e}"`).join(", ")}]`,{cause:a}),this.url=t,this.requiredParams=r,this.providedParams=n,this.cause=a}},o=class extends Error{name="MiddlewareError";type;url;method;cause;constructor(e,t,r,n,a){const o=r?`Request: ${n||"UNKNOWN"} ${r}`:"";super(o?`${e}\n${o}`:e,{cause:a}),this.type=t,this.url=r,this.method=n,this.cause=a}},s=class extends Error{name="SerializationError";cause;constructor(e,t){super(e,{cause:t}),this.cause=t}},i=class extends Error{name="InvalidSchemaError";schema;cause;constructor(e,t,r){super(e,{cause:r}),this.schema=t,this.cause=r}},c=class extends Error{name="AsyncSchemaValidationError";schema;cause;constructor(e,t,r){super(e,{cause:r}),this.schema=t,this.cause=r}},u=class extends Error{name="InvalidBaseUrlError";baseUrl;cause;constructor(e,t,r){super(`${e}\nBase URL: ${t}`,{cause:r}),this.baseUrl=t,this.cause=r}};function d(e,t={}){return function(e,t){const r=e.match(/(^|\/):([^/\s?#]+)\?(?=\/)/);if(!r)return;const[,,n]=r;throw new a(`Optional path parameter "${n}" is not supported here. Optional path parameters are only supported at the end of the path.`,e,[n],t)}(e,Object.keys(t)),e.replace(/(^|\/):([^/\s?#]+?)(\?)?(?=\/|$|[?#])/g,(r,n,o,s)=>{const i="?"===s;if(!/^[a-zA-Z0-9_]+$/.test(o))throw new a(`Invalid path parameter name: "${o}"`,e,[o],Object.keys(t));const c=t[o];if(void 0===c){if(i)return"";throw new a(`Missing required path parameter: "${o}"`,e,[o],Object.keys(t))}return`${n}${encodeURIComponent(String(c))}`})}function l(e,t,r,n){let a=0,o=!1,s=!1;const i=()=>{if(!o){o=!0;try{e.releaseLock()}catch{}}},c=()=>{s=!0,i()};return n?.addEventListener("abort",c),new ReadableStream({async start(o){try{for(;!s;){const{done:n,value:s}=await e.read();if(n)break;a+=s.length,t(s,r,a),o.enqueue(s)}s||o.close()}catch(u){throw s||o.error(u),u}finally{n?.removeEventListener("abort",c),i()}},cancel(){s=!0,n?.removeEventListener("abort",c),i()}})}async function f(e,t){if(!t||!e.body)return e;if(!e.body.getReader)return e;const r=l(e.body.getReader(),(e,r,n)=>{t({chunk:e,totalBytes:r,transferredBytes:n})},e.headers.get("content-length")?parseInt(e.headers.get("content-length")||"0",10):void 0,e.signal);return new Request(e.url,{method:e.method,headers:e.headers,body:r,signal:e.signal,credentials:e.credentials,cache:e.cache,mode:e.mode,redirect:e.redirect,referrer:e.referrer,referrerPolicy:e.referrerPolicy,integrity:e.integrity,keepalive:e.keepalive,duplex:"half"})}async function h(e,t){if(!t||!e.body)return e;if(!e.body.getReader)return e;const r=l(e.body.getReader(),(e,r,n)=>{t({chunk:e,totalBytes:r,transferredBytes:n})},e.headers.get("content-length")?parseInt(e.headers.get("content-length")||"0",10):void 0);return new Response(r,{status:e.status,statusText:e.statusText,headers:e.headers})}var p={maxRetries:3,retryDelay:300,backoffFactor:2,retryStatusCodes:[408,429,500,502,503,504],retryNetworkErrors:!0,maxRetryDelay:3e4,retryMethods:["GET","HEAD","OPTIONS","PUT","DELETE"],retryUnsafeMethods:!1,jitter:"none",respectRetryAfter:!0};function m(e={}){const{baseUrl:t="",headers:r={},timeout:a=3e4,fetch:s,serializeBody:i,serializeParams:c,onRequestMiddleware:l,onResponseMiddleware:m}=e,x=void 0===s;return async function(N,q={}){const{method:D="GET",headers:k={},params:B,pathParams:C,body:I,timeout:H=a,signal:W,credentials:z,cache:V,mode:F,redirect:J,fetchOptions:G,onUploadStreaming:Z,onDownloadStreaming:K,responseType:_,retry:Q}=q;let X=void 0===C?d(N):d(N,C);t&&(X=function(e,t){return L(t)?t:L(e)?function(e,t){const r=new URL(e),n=r.pathname.replace(/\/$/,""),{path:a,search:o,hash:s}=T(t);a.startsWith("/")?r.pathname=n+a:a&&(r.pathname=n+"/"+a);o&&(r.search=O(r.search,o));s&&(r.hash=s);return r.toString()}(e,t):function(e,t){const{path:r,search:n,hash:a}=T(e),{path:o,search:s,hash:i}=T(t);return`${o?function(e,t){return e?t?t.startsWith("/")?`${e}${t}`:`${e}/${t}`:e:t.startsWith("/")?t:`/${t}`}(r,o):r||o}${O(n,s)}${i||a}`}(e,t)}(t,X));const Y=function(e,t){const r={...e??{}};void 0!==t.cache&&(r.cache=t.cache);void 0!==t.credentials&&(r.credentials=t.credentials);void 0!==t.mode&&(r.mode=t.mode);void 0!==t.redirect&&(r.redirect=t.redirect);return r}(G,{cache:V,credentials:z,mode:F,redirect:J}),ee={url:X,method:D,params:B,headers:new Headers({...r,...k}),body:I,signal:W,fetchOptions:Y};let te=ee;if(l)try{te=await l({...ee,headers:new Headers(ee.headers),fetchOptions:{...ee.fetchOptions}})}catch(ie){throw new o(v("Request middleware failed",ie),"request",te.url,te.method,R(ie,"Request middleware"))}if(te.params){const e=c?c(te.params):function(e){const t=new URLSearchParams;for(const[r,n]of Object.entries(e))if(Array.isArray(n))for(const e of n)null!=e&&t.append(r,String(e));else null!=n&&t.append(r,String(n));return t.toString()}(te.params);e&&(te.url=function(e,t){const r=t.startsWith("?")?t.slice(1):t;if(!r)return e;const{path:n,search:a,hash:o}=T(e);return`${n}${a?`${a}&${r}`:`?${r}`}${o}`}(te.url,e))}!function(e,t){if(!t||L(e)||"undefined"!=typeof window&&void 0!==window.location&&"null"!==window.location.origin)return;throw new u(`Relative request URL "${e}" requires an absolute baseUrl in non-browser environments. Pass an absolute baseUrl or use a custom fetch implementation.`,e)}(te.url,x);const re={method:te.method,headers:te.headers,...te.fetchOptions};if(void 0!==te.body&&"GET"!==te.method&&"HEAD"!==te.method){let e,t;if(i){const t=i(te.body);e=null==t?"":t}else{const r=function(e){if(ArrayBuffer.isView(e)){const t=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return{body:new Uint8Array(t).buffer}}return"string"==typeof e||e instanceof FormData||e instanceof URLSearchParams||e instanceof ArrayBuffer||e instanceof Blob||e instanceof ReadableStream?{body:e}:function(e){return null!==e&&"object"==typeof e&&(Array.isArray(e)||"toJSON"in e&&"function"==typeof e.toJSON||"[object Object]"===Object.prototype.toString.call(e))}(e)?{body:JSON.stringify(e),contentType:"application/json"}:null==e?{body:""}:{body:String(e)}}(te.body);e=r.body,t=r.contentType}re.body=e,t&&te.headers.set("content-type",t),re.duplex="half"}const ne=function(e,t){const r="object"==typeof e?e:void 0,n=!0===e||void 0!==r||!0===t||"object"==typeof t;if(!1===t)return;if(!n)return;const a={...p,...r};return!0===t?a:"object"==typeof t?{...a,...t}:a}(e.retry,Q),ae=ne?.maxRetries??0,oe=function(e){return!(e instanceof ReadableStream)}(re.body);let se;for(let e=0;e<=ae;e+=1){const t=new AbortController;let r=!1;const a=setTimeout(()=>{r=!0,t.abort()},H),{signal:i,cleanup:c}=$(te.signal,t.signal);let u=!1;const d=()=>{u||(u=!0,clearTimeout(a),c())};try{const e={...re,headers:te.headers,signal:i,...te.fetchOptions};if(Z&&void 0!==e.body){const t=await f(P(te.url,e),Z);e.body=t.body??void 0,e.headers=t.headers}const t=await j(s??globalThis.fetch,te.url,e),r=K?await h(t,K):t,n=await y(r,{responseType:_,method:te.method,url:te.url,tolerateParseError:!U(r.status)});let a=n;if(m)try{const e=await m(n);if(!A(e))throw new o("Response middleware must return a valid ResponseType object","response",te.url,te.method);a=e}catch(ie){throw new o(v("Response middleware failed",ie),"response",te.url,te.method,R(ie,"Response middleware"))}if(!U(a.status))throw S(a,n.parseError);return a}catch(ie){if(se=R(ie,"Request execution"),M(se)&&r&&(se=new n(`Request timeout after ${H}ms`,se)),e>=ae||!(await b(se,e,ne,{bodyReplayable:oe,method:te.method,url:te.url})))throw se;const t=w(e,ne,se);await g(ne,{bodyReplayable:oe,delay:t,error:se,method:te.method,nextAttempt:e+1,retryCount:e,url:te.url}),d(),await E(t,te.signal)}finally{d()}}throw new Error("Retry loop terminated unexpectedly")}}async function y(e,t){const r=Object.fromEntries(e.headers.entries());let n,a;const o=e.clone();try{const r=t.responseType,a=e.headers.get("content-type")??"",s=a.includes("application/json")?"json":a.includes("text/")?"text":a.includes("application/octet-stream")||a.includes("application/pdf")||a.includes("image/")||a.includes("video/")||a.includes("audio/")?"arrayBuffer":a.includes("multipart/form-data")||a.includes("application/x-www-form-urlencoded")?"formData":void 0,i=r??s;if("json"===i)n=await e.json();else if("text"===i)n=await e.text();else if("blob"===i)n=await e.blob();else if("arrayBuffer"===i)n=await e.arrayBuffer();else if("formData"===i)n=await e.formData();else try{n=await e.json()}catch{n=await o.text()}}catch(i){if(a=new s(v("Failed to parse response body",i),i instanceof Error?i:void 0),!t.tolerateParseError)throw a;try{n=await o.text()}catch{n=""}}return{data:n,status:e.status,statusText:e.statusText,headers:r,method:t.method,url:t.url,raw:e,parseError:a}}async function b(r,n,a,o){if(!a)return!1;const s={...o,error:r,retryCount:n};return a.shouldRetry?await a.shouldRetry(r,n,s):!(!o.bodyReplayable||!function(e,t){if(t.retryUnsafeMethods)return!0;const r=e.toUpperCase();return t.retryMethods.some(e=>e.toUpperCase()===r)}(o.method,a))&&(r instanceof e?a.retryStatusCodes.includes(r.status):(r instanceof t||"TypeError"===r.name&&!function(e){return e.message.includes("Invalid URL")||e.message.includes("Failed to parse URL")}(r))&&a.retryNetworkErrors)}function w(t,r,n){if(!r)return 0;const a=r.respectRetryAfter?function(t){if(!(t instanceof e))return;const r=t.response.headers.get("retry-after");if(!r)return;const n=Number(r);if(Number.isFinite(n))return Math.max(0,1e3*n);const a=Date.parse(r);if(Number.isNaN(a))return;return Math.max(0,a-Date.now())}(n):void 0;if(void 0!==a)return Math.min(a,r.maxRetryDelay);const o=r.retryDelay*Math.pow(r.backoffFactor,t);return function(e,t,r){return"function"==typeof t?Math.max(0,t(e,r)):"full"===t?Math.floor(Math.random()*e):"equal"===t?Math.floor(e/2+Math.random()*(e/2)):e}(Math.min(o,r.maxRetryDelay),r.jitter,t)}async function g(e,t){await(e?.onRetry?.(t))}function v(e,t){return`${e}: ${t instanceof Error?t.message:String(t)}`}function E(e,t){return e<=0?Promise.resolve():t?.aborted?Promise.reject(x(t.reason)):new Promise((r,n)=>{const a=setTimeout(()=>{t?.removeEventListener("abort",o),r()},e),o=()=>{clearTimeout(a),t?.removeEventListener("abort",o),n(x(t?.reason))};t?.addEventListener("abort",o,{once:!0})})}function x(e){if(e instanceof Error)return e;const t=new Error("The operation was aborted");return t.name="AbortError",t}function $(e,t){if(!e&&!t)return{signal:void 0,cleanup:()=>{}};if(!e)return{signal:t,cleanup:()=>{}};if(!t)return{signal:e,cleanup:()=>{}};if(e?.aborted)return{signal:e,cleanup:()=>{}};if(t.aborted)return{signal:t,cleanup:()=>{}};const r=new AbortController,n=e=>{const t=e.target;t instanceof AbortSignal?r.abort(t.reason):r.abort()};return e.addEventListener("abort",n,{once:!0}),t.addEventListener("abort",n,{once:!0}),{signal:r.signal,cleanup:()=>{e.removeEventListener("abort",n),t.removeEventListener("abort",n)}}}function R(e,t){return e instanceof Error?e:new Error(`${t}: ${String(e)}`)}async function j(e,r,n){try{return await e(r,n)}catch(a){const e=R(a,"Network request failed");if(M(e)||e instanceof t)throw e;throw new t(e.message,e)}}function S(t,r){return new e(`HTTP ${t.status} ${t.statusText}`,t.status,t.statusText,t.data,t.raw,t.url,t.method,r)}function T(e){const t=e.indexOf("#"),r=-1===t?"":e.slice(t),n=-1===t?e:e.slice(0,t),a=n.indexOf("?");return{path:-1===a?n:n.slice(0,a),search:-1===a?"":n.slice(a),hash:r}}function O(e,t){return e?t?`${e}&${t.slice(1)}`:e:t}function P(e,t){return new Request(function(e){return L(e)?e:e?`https://1000fetches.local${e.startsWith("/")?e:`/${e}`}`:"https://1000fetches.local/"}(e),t)}function U(e){return e>=200&&e<300}function A(e){return null!==e&&"object"==typeof e&&"data"in e&&"status"in e&&"number"==typeof e.status&&"statusText"in e&&"string"==typeof e.statusText&&"headers"in e&&"object"==typeof e.headers&&null!==e.headers&&"method"in e&&"string"==typeof e.method&&"url"in e&&"string"==typeof e.url&&"raw"in e&&e.raw instanceof Response}function L(e){return/^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(e)}function M(e){return e instanceof Error&&"AbortError"===e.name}function N(e,t,n){if(n.issues)throw new r(JSON.stringify(n.issues),e,t,void 0,n.issues);return n.value}function q(){return{validate(e,t){if(null===(r=e)||"object"!=typeof r&&"function"!=typeof r||!("~standard"in r)||"object"!=typeof r["~standard"]||null===r["~standard"]||!("validate"in r["~standard"])||"function"!=typeof r["~standard"].validate||!("version"in r["~standard"])||1!==r["~standard"].version||!("vendor"in r["~standard"])||"string"!=typeof r["~standard"].vendor)throw new i("Schema must implement the Standard Schema interface",e);var r;const n=e["~standard"].validate(t);return null===(a=n)||"object"!=typeof a&&"function"!=typeof a||!("then"in a)||"function"!=typeof a.then?N(e,t,n):Promise.resolve(n).then(r=>N(e,t,r));var a}}}function D(e){if(!e)return"";if(e.startsWith("/"))return e.replace(/\/$/,"");try{new URL(e)}catch{throw new u(`Invalid baseUrl: "${e}". Must be a valid absolute URL or relative path starting with "/".`,e)}return e.endsWith("/")?e.slice(0,-1):e}function k(e,t,n,a){const o=n(e,t);return Object.assign(o,{schema:e=>function(e){const t=e;return t.data=async()=>(await e).data,t.void=async()=>{await e},t}(o.then(async t=>{try{const r=await a.validate(e,t.data);return{...t,data:r}}catch(n){if(n instanceof i||n instanceof r)throw n;throw new r(n instanceof Error?n.message:"Schema validation failed",e,t.data,n instanceof Error?n:void 0)}})),data:async()=>(await o).data,async void(){await o}})}function B(e={}){const t=m({...e,baseUrl:D(e.baseUrl)}),r=e.schemaValidator??q();return{get:function(e,...n){return k(e,{...n[0]??{},method:"GET"},t,r)},post:(e,n,...a)=>k(e,{...a[0]??{},method:"POST",body:n},t,r),put:(e,n,...a)=>k(e,{...a[0]??{},method:"PUT",body:n},t,r),patch:(e,n,...a)=>k(e,{...a[0]??{},method:"PATCH",body:n},t,r),delete:(e,...n)=>k(e,{...n[0]??{},method:"DELETE"},t,r),request:(e,...n)=>k(e,n[0]??{},t,r)}}Object.defineProperty(exports,"AsyncSchemaValidationError",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"HttpError",{enumerable:!0,get:function(){return e}}),Object.defineProperty(exports,"InvalidBaseUrlError",{enumerable:!0,get:function(){return u}}),Object.defineProperty(exports,"InvalidSchemaError",{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,"MiddlewareError",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"NetworkError",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"PathParameterError",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"SchemaValidationError",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"SerializationError",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"TimeoutError",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"createHttpClient",{enumerable:!0,get:function(){return B}}),Object.defineProperty(exports,"createSchemaValidator",{enumerable:!0,get:function(){return q}});
2
+ //# sourceMappingURL=client-C7dvgNnD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-C7dvgNnD.js","names":[],"sources":["../src/errors.ts","../src/utils/path.ts","../src/utils/streaming.ts","../src/core.ts","../src/schema.ts","../src/client.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec'\n\ninterface HttpClientError {\n name: string\n message: string\n cause?: Error\n stack?: string\n}\n\nfunction formatErrorData(data: unknown): string {\n if (data === null || data === undefined || data === '') {\n return 'No response data'\n }\n\n let dataString: string\n\n try {\n dataString = typeof data === 'string' ? data : JSON.stringify(data)\n } catch {\n dataString = String(data)\n }\n\n return dataString.length > 500\n ? dataString.substring(0, 500) + '...'\n : dataString\n}\n\nexport class HttpError<TErrorData = unknown>\n extends Error\n implements HttpClientError\n{\n public readonly name = 'HttpError'\n public readonly status: number\n public readonly statusText: string\n public readonly data: TErrorData\n public readonly response: Response\n public readonly url: string\n public readonly method: string\n public override readonly cause?: Error\n\n constructor(\n message: string,\n status: number,\n statusText: string,\n data: TErrorData,\n response: Response,\n url: string,\n method: string,\n cause?: Error\n ) {\n const statusCategory =\n status >= 500\n ? 'Server Error'\n : status >= 400\n ? 'Client Error'\n : status >= 300\n ? 'Redirect'\n : 'Success'\n\n const enhancedMessage = `HTTP ${statusCategory} (${status}): ${message}\nRequest: ${method} ${url}\nData: ${formatErrorData(data)}`\n\n super(enhancedMessage, { cause })\n this.status = status\n this.statusText = statusText\n this.data = data\n this.response = response\n this.url = url\n this.method = method\n this.cause = cause\n }\n}\n\nexport class NetworkError extends Error implements HttpClientError {\n public readonly name = 'NetworkError'\n public override readonly cause?: Error\n\n constructor(message: string, cause?: Error) {\n super(message, { cause })\n this.cause = cause\n }\n}\n\nexport class SchemaValidationError extends Error implements HttpClientError {\n public readonly name = 'SchemaValidationError'\n public readonly schema: unknown\n public readonly data: unknown\n public readonly issues?: ReadonlyArray<StandardSchemaV1.Issue>\n public override readonly cause?: Error\n\n constructor(\n message: string,\n schema: unknown,\n data: unknown,\n cause?: Error,\n issues?: ReadonlyArray<StandardSchemaV1.Issue>\n ) {\n super(message, { cause })\n this.schema = schema\n this.data = data\n this.issues = issues\n this.cause = cause\n }\n}\n\nexport class TimeoutError extends Error implements HttpClientError {\n public readonly name = 'TimeoutError'\n public override readonly cause?: Error\n\n constructor(message: string, cause?: Error) {\n super(message, { cause })\n this.cause = cause\n }\n}\n\nexport class PathParameterError extends Error implements HttpClientError {\n public readonly name = 'PathParameterError'\n public readonly url: string\n public readonly requiredParams: string[]\n public readonly providedParams: string[]\n public override readonly cause?: Error\n\n constructor(\n message: string,\n url: string,\n requiredParams: string[],\n providedParams: string[],\n cause?: Error\n ) {\n const enhancedMessage = `${message}\nURL Template: ${url}\nExpected: [${requiredParams.map(p => `\"${p}\"`).join(', ')}], Actual: [${providedParams.map(p => `\"${p}\"`).join(', ')}]`\n\n super(enhancedMessage, { cause })\n this.url = url\n this.requiredParams = requiredParams\n this.providedParams = providedParams\n this.cause = cause\n }\n}\n\nexport class MiddlewareError extends Error implements HttpClientError {\n public readonly name = 'MiddlewareError'\n public readonly type: 'request' | 'response'\n public readonly url?: string\n public readonly method?: string\n public override readonly cause?: Error\n\n constructor(\n message: string,\n type: 'request' | 'response',\n url?: string,\n method?: string,\n cause?: Error\n ) {\n const requestInfo = url ? `Request: ${method || 'UNKNOWN'} ${url}` : ''\n const enhancedMessage = requestInfo ? `${message}\\n${requestInfo}` : message\n\n super(enhancedMessage, { cause })\n this.type = type\n this.url = url\n this.method = method\n this.cause = cause\n }\n}\n\nexport class SerializationError extends Error implements HttpClientError {\n public readonly name = 'SerializationError'\n public override readonly cause?: Error\n\n constructor(message: string, cause?: Error) {\n super(message, { cause })\n this.cause = cause\n }\n}\n\nexport class InvalidSchemaError extends Error implements HttpClientError {\n public readonly name = 'InvalidSchemaError'\n public readonly schema: unknown\n public override readonly cause?: Error\n\n constructor(message: string, schema: unknown, cause?: Error) {\n super(message, { cause })\n this.schema = schema\n this.cause = cause\n }\n}\n\nexport class AsyncSchemaValidationError\n extends Error\n implements HttpClientError\n{\n public readonly name = 'AsyncSchemaValidationError'\n public readonly schema: unknown\n public override readonly cause?: Error\n\n constructor(message: string, schema: unknown, cause?: Error) {\n super(message, { cause })\n this.schema = schema\n this.cause = cause\n }\n}\n\nexport class InvalidBaseUrlError extends Error implements HttpClientError {\n public readonly name = 'InvalidBaseUrlError'\n public readonly baseUrl: string\n public override readonly cause?: Error\n\n constructor(message: string, baseUrl: string, cause?: Error) {\n const enhancedMessage = `${message}\nBase URL: ${baseUrl}`\n\n super(enhancedMessage, { cause })\n this.baseUrl = baseUrl\n this.cause = cause\n }\n}\n","import { PathParameterError } from '../errors'\n\n/**\n * Strips protocol from URL (e.g., https://, http://)\n */\ntype StripProtocol<T extends string> = T extends `${string}://${infer After}`\n ? After\n : T\n\n/**\n * Strips host and optional port from URL, keeping only the path\n * Handles cases like \"localhost:3000/users\" -> \"/users\"\n */\ntype StripHost<T extends string> = T extends `${infer _Host}/${infer Path}`\n ? `/${Path}`\n : T\n\n/**\n * Strips query string from path (e.g., \"/users?x=1\" -> \"/users\")\n * Only strips ? that comes after the path, not ? that's part of path parameters\n */\ntype StripQuery<T extends string> = T extends `${infer Path}?${infer Query}`\n ? Query extends\n | `${string}=${string}`\n | `${string}&${string}`\n | `${string}=${string}&${string}`\n ? Path // Contains query parameters (has = or &)\n : Query extends `/${string}`\n ? T // It's another path segment, not a query\n : Query extends ``\n ? T // It's an optional param marker (?)\n : Path // Plain query params like ?param\n : T\n\n/**\n * Normalizes URL to path only, stripping protocol, host, port, and query\n */\ntype NormalizePath<T extends string> = StripQuery<StripHost<StripProtocol<T>>>\n\n/**\n * Removes optional suffix from param name (e.g., \":id?\" -> \"id\", \":id\" -> \"id\")\n */\ntype CleanParamName<S extends string> = S extends `:${infer Name}?`\n ? Name\n : S extends `:${infer Name}`\n ? Name\n : S\n\n/**\n * Extracts required path parameters from a route\n */\ntype ExtractRequiredRouteParams<T extends string> =\n NormalizePath<T> extends `${infer _Before}:${infer AfterColon}`\n ? AfterColon extends `${infer Param}/${infer Rest}`\n ? Param extends `${string}?`\n ? ExtractRequiredRouteParams<`/${Rest}`>\n : CleanParamName<`:${Param}`> | ExtractRequiredRouteParams<`/${Rest}`>\n : AfterColon extends `${string}?`\n ? never\n : CleanParamName<`:${AfterColon}`>\n : never\n\n/**\n * Extracts optional path parameters from a route\n */\ntype ExtractOptionalRouteParams<T extends string> =\n NormalizePath<T> extends `${infer _Before}:${infer AfterColon}`\n ? AfterColon extends `${infer Param}/${infer Rest}`\n ?\n | (Param extends `${string}?` ? CleanParamName<`:${Param}`> : never)\n | ExtractOptionalRouteParams<`/${Rest}`>\n : AfterColon extends `${string}?`\n ? CleanParamName<`:${AfterColon}`>\n : never\n : never\n\ntype ExtractRouteParams<T extends string> =\n | ExtractRequiredRouteParams<T>\n | ExtractOptionalRouteParams<T>\n\ntype HasNonTrailingOptionalRouteParams<T extends string> = string extends T\n ? false\n : NormalizePath<T> extends `${infer _Before}:${infer AfterColon}`\n ? AfterColon extends `${infer Param}/${infer Rest}`\n ? Param extends `${string}?`\n ? true\n : HasNonTrailingOptionalRouteParams<`/${Rest}`>\n : false\n : false\n\nexport type AssertSupportedPath<Path extends string> = string extends Path\n ? Path\n : HasNonTrailingOptionalRouteParams<Path> extends true\n ? never\n : Path\n\nexport type HasRequiredParams<T extends string> = [\n ExtractRequiredRouteParams<T>,\n] extends [never]\n ? false\n : true\n\ntype HasPathParams<T extends string> = [ExtractRouteParams<T>] extends [never]\n ? false\n : true\n\ntype Simplify<T> = { [K in keyof T]: T[K] }\n\n/**\n * PathParams type - extracts parameter names and their types\n */\nexport type PathParams<Path extends string> = [\n AssertSupportedPath<Path>,\n] extends [never]\n ? never\n : Simplify<\n {\n [K in ExtractRequiredRouteParams<Path>]: string | number\n } & {\n [K in ExtractOptionalRouteParams<Path>]?: string | number\n }\n >\n\n/**\n * RequirePathParams enforces pathParams when needed\n */\nexport type RequirePathParams<Path extends string, T> = [\n AssertSupportedPath<Path>,\n] extends [never]\n ? never\n : HasRequiredParams<Path> extends true\n ? T & { pathParams: PathParams<Path> }\n : HasPathParams<Path> extends true\n ? T & { pathParams?: PathParams<Path> }\n : T\n\n/**\n * Interpolates parameters into a URL template\n * Similar to React Router's generatePath function\n *\n * @example\n * ```ts\n * const path = generatePath('/users/:id/posts/:postId', { id: '123', postId: '456' });\n * // => '/users/123/posts/456'\n * ```\n */\nexport function generatePath<Path extends string>(\n path: AssertSupportedPath<Path>\n): string\nexport function generatePath<Path extends string>(\n path: AssertSupportedPath<Path>,\n params: PathParams<Path>\n): string\nexport function generatePath(\n path: string,\n params: Record<string, string | number | undefined> = {}\n): string {\n validateSupportedOptionalPath(path, Object.keys(params))\n\n return path.replace(\n /(^|\\/):([^/\\s?#]+?)(\\?)?(?=\\/|$|[?#])/g,\n (_match, prefix: string, paramName: string, optionalMarker?: string) => {\n const isOptional = optionalMarker === '?'\n\n // Validate parameter name\n if (!/^[a-zA-Z0-9_]+$/.test(paramName)) {\n throw new PathParameterError(\n `Invalid path parameter name: \"${paramName}\"`,\n path,\n [paramName],\n Object.keys(params)\n )\n }\n\n // Get and validate parameter value\n const paramValue = params[paramName]\n\n if (paramValue === undefined) {\n if (isOptional) {\n return ''\n }\n\n throw new PathParameterError(\n `Missing required path parameter: \"${paramName}\"`,\n path,\n [paramName],\n Object.keys(params)\n )\n }\n\n return `${prefix}${encodeURIComponent(String(paramValue))}`\n }\n )\n}\n\nfunction validateSupportedOptionalPath(\n path: string,\n providedParams: string[]\n): void {\n const invalidOptionalMatch = path.match(/(^|\\/):([^/\\s?#]+)\\?(?=\\/)/)\n\n if (!invalidOptionalMatch) {\n return\n }\n\n const [, , paramName] = invalidOptionalMatch\n\n throw new PathParameterError(\n `Optional path parameter \"${paramName}\" is not supported here. Optional path parameters are only supported at the end of the path.`,\n path,\n [paramName],\n providedParams\n )\n}\n","import type { DownloadStreamingEvent, UploadStreamingEvent } from '../types'\n\nfunction createStreamingStream(\n reader: ReadableStreamDefaultReader<Uint8Array>,\n onChunk: (\n chunk: Uint8Array,\n totalBytes: number | undefined,\n transferredBytes: number\n ) => void,\n totalBytes: number | undefined,\n signal?: AbortSignal\n): ReadableStream<Uint8Array> {\n let transferredBytes = 0\n let readerReleased = false\n let isAborted = false\n\n const releaseReader = () => {\n if (!readerReleased) {\n readerReleased = true\n try {\n reader.releaseLock()\n } catch {\n // Reader might already be released, ignore\n }\n }\n }\n\n // Handle abort signal\n const abortHandler = () => {\n isAborted = true\n releaseReader()\n }\n\n signal?.addEventListener('abort', abortHandler)\n\n return new ReadableStream({\n async start(controller) {\n try {\n while (!isAborted) {\n const { done, value } = await reader.read()\n if (done) break\n\n transferredBytes += value.length\n onChunk(value, totalBytes, transferredBytes)\n controller.enqueue(value)\n }\n\n if (!isAborted) {\n controller.close()\n }\n } catch (error) {\n if (!isAborted) {\n controller.error(error)\n }\n throw error\n } finally {\n signal?.removeEventListener('abort', abortHandler)\n releaseReader()\n }\n },\n cancel() {\n isAborted = true\n signal?.removeEventListener('abort', abortHandler)\n releaseReader()\n },\n })\n}\n\n/**\n * Creates a request with upload streaming tracking\n */\nexport async function toStreamableRequest(\n request: Request,\n onUploadStreaming?: (event: UploadStreamingEvent) => void\n): Promise<Request> {\n if (!onUploadStreaming || !request.body) {\n return request\n }\n\n if (!request.body.getReader) {\n return request\n }\n\n const reader = request.body.getReader()\n const totalBytes = request.headers.get('content-length')\n ? parseInt(request.headers.get('content-length') || '0', 10)\n : undefined\n\n const stream = createStreamingStream(\n reader,\n (chunk, totalBytes, transferredBytes) => {\n onUploadStreaming({\n chunk,\n totalBytes,\n transferredBytes,\n })\n },\n totalBytes,\n request.signal\n )\n\n return new Request(request.url, {\n method: request.method,\n headers: request.headers,\n body: stream,\n signal: request.signal,\n credentials: request.credentials,\n cache: request.cache,\n mode: request.mode,\n redirect: request.redirect,\n referrer: request.referrer,\n referrerPolicy: request.referrerPolicy,\n integrity: request.integrity,\n keepalive: request.keepalive,\n duplex: 'half',\n } as RequestInit)\n}\n\n/**\n * Creates a response with download streaming tracking\n */\nexport async function toStreamableResponse(\n response: Response,\n onDownloadStreaming?: (event: DownloadStreamingEvent) => void\n): Promise<Response> {\n if (!onDownloadStreaming || !response.body) {\n return response\n }\n\n if (!response.body.getReader) {\n return response\n }\n\n const reader = response.body.getReader()\n const totalBytes = response.headers.get('content-length')\n ? parseInt(response.headers.get('content-length') || '0', 10)\n : undefined\n\n const stream = createStreamingStream(\n reader,\n (chunk, totalBytes, transferredBytes) => {\n onDownloadStreaming({\n chunk,\n totalBytes,\n transferredBytes,\n })\n },\n totalBytes\n )\n\n return new Response(stream, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n}\n","import {\n HttpError,\n InvalidBaseUrlError,\n MiddlewareError,\n NetworkError,\n SerializationError,\n TimeoutError,\n} from './errors'\nimport type { SchemaValidator } from './schema'\nimport type {\n CustomFetch,\n DownloadStreamingEvent,\n ExtendedRequestInit,\n FetchOptions,\n HttpHeaders,\n HttpMethod,\n RequestContext,\n RequestParamsType,\n ResponseType,\n RetryContext,\n RetryEvent,\n RetryOptions,\n SerializeBody,\n SerializeParams,\n UploadStreamingEvent,\n} from './types'\nimport {\n type AssertSupportedPath,\n generatePath,\n toStreamableRequest,\n toStreamableResponse,\n type PathParams,\n} from './utils'\n\ntype ResolvedRetryOptions = {\n maxRetries: number\n retryDelay: number\n backoffFactor: number\n retryStatusCodes: number[]\n retryNetworkErrors: boolean\n maxRetryDelay: number\n retryMethods: readonly HttpMethod[]\n retryUnsafeMethods: boolean\n jitter: NonNullable<RetryOptions['jitter']>\n respectRetryAfter: boolean\n shouldRetry?: RetryOptions['shouldRetry']\n onRetry?: RetryOptions['onRetry']\n}\n\ntype ParsedResponse<T> = ResponseType<T> & {\n parseError?: SerializationError\n}\n\nconst DEFAULT_RETRY_OPTIONS: Omit<\n ResolvedRetryOptions,\n 'shouldRetry' | 'onRetry'\n> = {\n maxRetries: 3,\n retryDelay: 300,\n backoffFactor: 2,\n retryStatusCodes: [408, 429, 500, 502, 503, 504],\n retryNetworkErrors: true,\n maxRetryDelay: 30_000,\n retryMethods: ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE'],\n retryUnsafeMethods: false,\n jitter: 'none',\n respectRetryAfter: true,\n}\n\nexport interface HttpRequestOptions<\n TBody = unknown,\n TParams extends RequestParamsType = RequestParamsType,\n> {\n method?: HttpMethod\n headers?: HttpHeaders\n /** Query parameters */\n params?: TParams\n /** Path parameters for URL template */\n pathParams?: Record<string, string | number | undefined>\n /** Request body */\n body?: TBody\n timeout?: number\n signal?: AbortSignal\n /** Fetch options */\n credentials?: RequestCredentials\n cache?: RequestCache\n mode?: RequestMode\n redirect?: RequestRedirect\n /** Additional Fetch/Node options passed through to the underlying fetch call */\n fetchOptions?: FetchOptions\n /** Upload streaming tracking for this specific request */\n onUploadStreaming?: (event: UploadStreamingEvent) => void\n /** Download streaming tracking for this specific request */\n onDownloadStreaming?: (event: DownloadStreamingEvent) => void\n /** Response type override */\n responseType?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData'\n /** Per-request retry configuration */\n retry?: RetryOptions | boolean\n}\n\nexport interface HttpClientConfig {\n /** Base URL for all requests */\n baseUrl?: string\n /** Default headers */\n headers?: HttpHeaders\n /** Default timeout */\n timeout?: number\n /** Schema validator */\n schemaValidator?: SchemaValidator\n /** Default retry configuration */\n retry?: RetryOptions | boolean\n /** Custom fetch implementation */\n fetch?: CustomFetch\n /** Custom body serializer */\n serializeBody?: SerializeBody\n /** Custom params serializer */\n serializeParams?: SerializeParams\n /** Request middleware - can modify request before sending */\n onRequestMiddleware?: <TBody = unknown>(\n context: RequestContext<TBody>\n ) => RequestContext<TBody> | Promise<RequestContext<TBody>>\n /** Response middleware - can modify response after receiving */\n onResponseMiddleware?: (\n response: ResponseType<unknown>\n ) => ResponseType<unknown> | Promise<ResponseType<unknown>>\n}\n\n/**\n * Creates an HTTP request handler with the given configuration.\n * This is the core function that handles all HTTP requests with retry logic,\n * interceptors, and streaming.\n */\nexport function createHttpRequest(config: HttpClientConfig = {}) {\n const {\n baseUrl = '',\n headers: defaultHeaders = {},\n timeout: defaultTimeout = 30_000,\n fetch: customFetch,\n serializeBody: customSerializeBody,\n serializeParams: customSerializeParams,\n onRequestMiddleware,\n onResponseMiddleware,\n } = config\n const usesNativeFetch = customFetch === undefined\n\n return async function fetcher<\n Path extends string = string,\n TResponse = unknown,\n TBody = unknown,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n options: HttpRequestOptions<TBody, TParams> = {}\n ): Promise<ResponseType<TResponse>> {\n const {\n method = 'GET',\n headers = {},\n params,\n pathParams,\n body,\n timeout = defaultTimeout,\n signal,\n credentials,\n cache,\n mode,\n redirect,\n fetchOptions,\n onUploadStreaming,\n onDownloadStreaming,\n responseType,\n retry: requestRetry,\n } = options\n\n let resolvedUrl =\n pathParams === undefined\n ? generatePath(url as AssertSupportedPath<Path>)\n : generatePath(\n url as AssertSupportedPath<Path>,\n pathParams as PathParams<Path>\n )\n\n if (baseUrl) {\n resolvedUrl = constructUrl(baseUrl, resolvedUrl)\n }\n\n const requestFetchOptions = mergeFetchOptions(fetchOptions, {\n cache,\n credentials,\n mode,\n redirect,\n })\n\n const baseRequestContext: RequestContext<TBody> = {\n url: resolvedUrl,\n method,\n params,\n headers: new Headers({ ...defaultHeaders, ...headers }),\n body,\n signal,\n fetchOptions: requestFetchOptions,\n }\n\n let requestContext: RequestContext<TBody> = baseRequestContext\n\n if (onRequestMiddleware) {\n try {\n // prevent middleware from mutating the original context\n const contextCopy: RequestContext<TBody> = {\n ...baseRequestContext,\n headers: new Headers(baseRequestContext.headers),\n fetchOptions: { ...baseRequestContext.fetchOptions },\n }\n\n requestContext = await onRequestMiddleware(contextCopy)\n } catch (error) {\n throw new MiddlewareError(\n createErrorMessage('Request middleware failed', error),\n 'request',\n requestContext.url,\n requestContext.method,\n createStandardizedError(error, 'Request middleware')\n )\n }\n }\n\n if (requestContext.params) {\n const serializedParams = customSerializeParams\n ? customSerializeParams(requestContext.params)\n : serializeQueryParams(requestContext.params)\n\n if (serializedParams) {\n requestContext.url = appendQueryString(\n requestContext.url,\n serializedParams\n )\n }\n }\n\n assertRequestUrlSupported(requestContext.url, usesNativeFetch)\n\n const baseRequestInit: ExtendedRequestInit = {\n method: requestContext.method,\n headers: requestContext.headers,\n ...requestContext.fetchOptions,\n }\n\n if (\n requestContext.body !== undefined &&\n requestContext.method !== 'GET' &&\n requestContext.method !== 'HEAD'\n ) {\n let body: BodyInit\n let contentType: string | undefined\n\n if (customSerializeBody) {\n const serializedBody = customSerializeBody(requestContext.body)\n if (serializedBody == null) {\n body = ''\n } else {\n body = serializedBody\n }\n } else {\n const serialized = serializeRequestBody(requestContext.body)\n body = serialized.body\n contentType = serialized.contentType\n }\n\n baseRequestInit.body = body\n\n if (contentType) {\n requestContext.headers.set('content-type', contentType)\n }\n\n baseRequestInit.duplex = 'half'\n }\n\n const mergedRetryOptions = resolveRetryOptions(config.retry, requestRetry)\n const maxRetries = mergedRetryOptions?.maxRetries ?? 0\n const bodyReplayable = isReplayableBody(baseRequestInit.body)\n let lastError: Error | undefined\n\n for (let attempt = 0; attempt <= maxRetries; attempt += 1) {\n const controller = new AbortController()\n let didTimeout = false\n const timeoutId = setTimeout(() => {\n didTimeout = true\n controller.abort()\n }, timeout)\n\n const { signal: finalSignal, cleanup: cleanupSignal } =\n createCombinedSignal(requestContext.signal, controller.signal)\n let attemptCleanedUp = false\n const cleanupAttempt = () => {\n if (attemptCleanedUp) {\n return\n }\n\n attemptCleanedUp = true\n clearTimeout(timeoutId)\n cleanupSignal()\n }\n\n try {\n const requestInit: ExtendedRequestInit = {\n ...baseRequestInit,\n headers: requestContext.headers,\n signal: finalSignal,\n ...requestContext.fetchOptions,\n }\n\n if (onUploadStreaming && requestInit.body !== undefined) {\n const streamableRequest = await toStreamableRequest(\n createInternalRequest(requestContext.url, requestInit),\n onUploadStreaming\n )\n\n requestInit.body = streamableRequest.body ?? undefined\n requestInit.headers = streamableRequest.headers\n }\n\n const response = await fetchWithNetworkError(\n customFetch ?? globalThis.fetch,\n requestContext.url,\n requestInit\n )\n\n const trackedResponse = onDownloadStreaming\n ? await toStreamableResponse(response, onDownloadStreaming)\n : response\n\n const responseData = await processResponse<TResponse>(trackedResponse, {\n responseType,\n method: requestContext.method,\n url: requestContext.url,\n tolerateParseError: !isSuccessfulStatus(trackedResponse.status),\n })\n\n let finalResponse = responseData\n\n if (onResponseMiddleware) {\n try {\n const middlewareResult = await onResponseMiddleware(responseData)\n if (!isResponseTypeLike(middlewareResult)) {\n throw new MiddlewareError(\n 'Response middleware must return a valid ResponseType object',\n 'response',\n requestContext.url,\n requestContext.method\n )\n }\n finalResponse = middlewareResult as ResponseType<TResponse>\n } catch (error) {\n throw new MiddlewareError(\n createErrorMessage('Response middleware failed', error),\n 'response',\n requestContext.url,\n requestContext.method,\n createStandardizedError(error, 'Response middleware')\n )\n }\n }\n\n if (!isSuccessfulStatus(finalResponse.status)) {\n throw createHttpError(finalResponse, responseData.parseError)\n }\n\n return finalResponse\n } catch (error) {\n lastError = createStandardizedError(error, 'Request execution')\n\n if (isAbortError(lastError) && didTimeout) {\n lastError = new TimeoutError(\n `Request timeout after ${timeout}ms`,\n lastError\n )\n }\n\n if (\n attempt >= maxRetries ||\n !(await shouldRetry(lastError, attempt, mergedRetryOptions, {\n bodyReplayable,\n method: requestContext.method,\n url: requestContext.url,\n }))\n ) {\n throw lastError\n }\n\n const delay = calculateRetryDelay(\n attempt,\n mergedRetryOptions,\n lastError\n )\n await notifyRetry(mergedRetryOptions, {\n bodyReplayable,\n delay,\n error: lastError,\n method: requestContext.method,\n nextAttempt: attempt + 1,\n retryCount: attempt,\n url: requestContext.url,\n })\n cleanupAttempt()\n await sleep(delay, requestContext.signal)\n } finally {\n cleanupAttempt()\n }\n }\n\n throw new Error('Retry loop terminated unexpectedly')\n }\n}\n\nasync function processResponse<T = unknown>(\n response: Response,\n options: {\n responseType?: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData'\n method: HttpMethod\n url: string\n tolerateParseError?: boolean\n }\n): Promise<ParsedResponse<T>> {\n const headers = Object.fromEntries(response.headers.entries())\n\n let data: unknown\n let parseError: SerializationError | undefined\n const responseClone = response.clone()\n\n try {\n const requestedType = options.responseType\n const contentType = response.headers.get('content-type') ?? ''\n\n const detectedType:\n | 'json'\n | 'text'\n | 'arrayBuffer'\n | 'formData'\n | undefined = contentType.includes('application/json')\n ? 'json'\n : contentType.includes('text/')\n ? 'text'\n : contentType.includes('application/octet-stream') ||\n contentType.includes('application/pdf') ||\n contentType.includes('image/') ||\n contentType.includes('video/') ||\n contentType.includes('audio/')\n ? 'arrayBuffer'\n : contentType.includes('multipart/form-data') ||\n contentType.includes('application/x-www-form-urlencoded')\n ? 'formData'\n : undefined\n\n const finalType:\n | 'json'\n | 'text'\n | 'arrayBuffer'\n | 'blob'\n | 'formData'\n | undefined = requestedType ?? detectedType\n\n if (finalType === 'json') {\n data = await response.json()\n } else if (finalType === 'text') {\n data = await response.text()\n } else if (finalType === 'blob') {\n data = await response.blob()\n } else if (finalType === 'arrayBuffer') {\n data = await response.arrayBuffer()\n } else if (finalType === 'formData') {\n data = await response.formData()\n } else {\n try {\n data = await response.json()\n } catch {\n data = await responseClone.text()\n }\n }\n } catch (error) {\n parseError = new SerializationError(\n createErrorMessage('Failed to parse response body', error),\n error instanceof Error ? error : undefined\n )\n\n if (!options.tolerateParseError) {\n throw parseError\n }\n\n try {\n data = await responseClone.text()\n } catch {\n data = ''\n }\n }\n\n return {\n data: data as T,\n status: response.status,\n statusText: response.statusText,\n headers,\n method: options.method,\n url: options.url,\n raw: response,\n parseError,\n }\n}\n\nasync function shouldRetry(\n error: Error,\n retryCount: number,\n retryConfig: ResolvedRetryOptions | undefined,\n context: Pick<RetryContext, 'bodyReplayable' | 'method' | 'url'>\n): Promise<boolean> {\n if (!retryConfig) return false\n\n const retryContext: RetryContext = {\n ...context,\n error,\n retryCount,\n }\n\n if (retryConfig.shouldRetry) {\n return await retryConfig.shouldRetry(error, retryCount, retryContext)\n }\n\n if (\n !context.bodyReplayable ||\n !isRetryMethodAllowed(context.method, retryConfig)\n ) {\n return false\n }\n\n if (error instanceof HttpError) {\n return retryConfig.retryStatusCodes.includes(error.status)\n }\n\n if (\n error instanceof NetworkError ||\n (error.name === 'TypeError' && !isInvalidUrlError(error))\n ) {\n return retryConfig.retryNetworkErrors\n }\n\n return false\n}\n\nfunction calculateRetryDelay(\n attempt: number,\n retryConfig: ResolvedRetryOptions | undefined,\n error: Error\n): number {\n if (!retryConfig) return 0\n\n const retryAfterDelay = retryConfig.respectRetryAfter\n ? getRetryAfterDelay(error)\n : undefined\n\n if (retryAfterDelay !== undefined) {\n return Math.min(retryAfterDelay, retryConfig.maxRetryDelay)\n }\n\n const delay =\n retryConfig.retryDelay * Math.pow(retryConfig.backoffFactor, attempt)\n\n return applyJitter(\n Math.min(delay, retryConfig.maxRetryDelay),\n retryConfig.jitter,\n attempt\n )\n}\n\nasync function notifyRetry(\n retryConfig: ResolvedRetryOptions | undefined,\n event: RetryEvent\n): Promise<void> {\n await retryConfig?.onRetry?.(event)\n}\n\nfunction resolveRetryOptions(\n clientRetry?: RetryOptions | boolean,\n requestRetry?: RetryOptions | boolean\n): ResolvedRetryOptions | undefined {\n const clientRetryOptions =\n typeof clientRetry === 'object' ? clientRetry : undefined\n const shouldEnableRetries =\n clientRetry === true ||\n clientRetryOptions !== undefined ||\n requestRetry === true ||\n typeof requestRetry === 'object'\n\n if (requestRetry === false) {\n return undefined\n }\n\n if (!shouldEnableRetries) {\n return undefined\n }\n\n const baseRetryOptions = {\n ...DEFAULT_RETRY_OPTIONS,\n ...clientRetryOptions,\n }\n\n if (requestRetry === true) {\n return baseRetryOptions\n }\n\n if (typeof requestRetry === 'object') {\n return {\n ...baseRetryOptions,\n ...requestRetry,\n }\n }\n\n return baseRetryOptions\n}\n\nfunction mergeFetchOptions(\n fetchOptions: FetchOptions | undefined,\n aliases: Pick<RequestInit, 'cache' | 'credentials' | 'mode' | 'redirect'>\n): FetchOptions {\n const merged: FetchOptions = { ...(fetchOptions ?? {}) }\n\n if (aliases.cache !== undefined) {\n merged.cache = aliases.cache\n }\n\n if (aliases.credentials !== undefined) {\n merged.credentials = aliases.credentials\n }\n\n if (aliases.mode !== undefined) {\n merged.mode = aliases.mode\n }\n\n if (aliases.redirect !== undefined) {\n merged.redirect = aliases.redirect\n }\n\n return merged\n}\n\nfunction isRetryMethodAllowed(\n method: HttpMethod,\n retryConfig: ResolvedRetryOptions\n): boolean {\n if (retryConfig.retryUnsafeMethods) {\n return true\n }\n\n const normalizedMethod = method.toUpperCase()\n return retryConfig.retryMethods.some(\n retryMethod => retryMethod.toUpperCase() === normalizedMethod\n )\n}\n\nfunction getRetryAfterDelay(error: Error): number | undefined {\n if (!(error instanceof HttpError)) {\n return undefined\n }\n\n const retryAfter = error.response.headers.get('retry-after')\n if (!retryAfter) {\n return undefined\n }\n\n const retryAfterSeconds = Number(retryAfter)\n if (Number.isFinite(retryAfterSeconds)) {\n return Math.max(0, retryAfterSeconds * 1000)\n }\n\n const retryAfterDate = Date.parse(retryAfter)\n if (Number.isNaN(retryAfterDate)) {\n return undefined\n }\n\n return Math.max(0, retryAfterDate - Date.now())\n}\n\nfunction applyJitter(\n delay: number,\n jitter: ResolvedRetryOptions['jitter'],\n attempt: number\n): number {\n if (typeof jitter === 'function') {\n return Math.max(0, jitter(delay, attempt))\n }\n\n if (jitter === 'full') {\n return Math.floor(Math.random() * delay)\n }\n\n if (jitter === 'equal') {\n return Math.floor(delay / 2 + Math.random() * (delay / 2))\n }\n\n return delay\n}\n\nfunction isObjectLike(\n value: unknown\n): value is Record<string, unknown> | unknown[] | { toJSON(): unknown } {\n return (\n value !== null &&\n typeof value === 'object' &&\n (Array.isArray(value) ||\n ('toJSON' in value && typeof value.toJSON === 'function') ||\n Object.prototype.toString.call(value) === '[object Object]')\n )\n}\n\nfunction serializeQueryParams(params: RequestParamsType): string {\n const searchParams = new URLSearchParams()\n\n for (const [key, value] of Object.entries(params)) {\n if (Array.isArray(value)) {\n for (const item of value) {\n if (item !== undefined && item !== null) {\n searchParams.append(key, String(item))\n }\n }\n } else if (value !== undefined && value !== null) {\n searchParams.append(key, String(value))\n }\n }\n\n return searchParams.toString()\n}\n\nfunction serializeRequestBody(body: unknown): {\n body: BodyInit\n contentType?: string\n} {\n if (ArrayBuffer.isView(body)) {\n const bytes = new Uint8Array(body.buffer, body.byteOffset, body.byteLength)\n return { body: new Uint8Array(bytes).buffer }\n }\n\n if (\n typeof body === 'string' ||\n body instanceof FormData ||\n body instanceof URLSearchParams ||\n body instanceof ArrayBuffer ||\n body instanceof Blob ||\n body instanceof ReadableStream\n ) {\n return { body: body }\n }\n\n if (isObjectLike(body)) {\n return {\n body: JSON.stringify(body),\n contentType: 'application/json',\n }\n }\n\n if (body === null || body === undefined) {\n return { body: '' }\n }\n\n return { body: String(body) }\n}\n\nfunction createErrorMessage(context: string, error: unknown): string {\n return `${context}: ${error instanceof Error ? error.message : String(error)}`\n}\n\nfunction isReplayableBody(body: BodyInit | null | undefined): boolean {\n return !(body instanceof ReadableStream)\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (ms <= 0) {\n return Promise.resolve()\n }\n\n if (signal?.aborted) {\n return Promise.reject(createAbortError(signal.reason))\n }\n\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n signal?.removeEventListener('abort', handleAbort)\n resolve()\n }, ms)\n\n const handleAbort = () => {\n clearTimeout(timeoutId)\n signal?.removeEventListener('abort', handleAbort)\n reject(createAbortError(signal?.reason))\n }\n\n signal?.addEventListener('abort', handleAbort, { once: true })\n })\n}\n\nfunction createAbortError(reason: unknown): Error {\n if (reason instanceof Error) {\n return reason\n }\n\n const error = new Error('The operation was aborted')\n error.name = 'AbortError'\n return error\n}\n\nfunction createCombinedSignal(\n requestSignal?: AbortSignal,\n timeoutSignal?: AbortSignal\n): { signal?: AbortSignal; cleanup: () => void } {\n if (!requestSignal && !timeoutSignal) {\n return {\n signal: undefined,\n cleanup: () => undefined,\n }\n }\n\n if (!requestSignal) {\n return {\n signal: timeoutSignal,\n cleanup: () => undefined,\n }\n }\n\n if (!timeoutSignal) {\n return {\n signal: requestSignal,\n cleanup: () => undefined,\n }\n }\n\n if (requestSignal?.aborted) {\n return {\n signal: requestSignal,\n cleanup: () => undefined,\n }\n }\n\n if (timeoutSignal.aborted) {\n return {\n signal: timeoutSignal,\n cleanup: () => undefined,\n }\n }\n\n const combinedController = new AbortController()\n\n const handleAbort = (event: Event) => {\n const sourceSignal = event.target\n\n if (sourceSignal instanceof AbortSignal) {\n combinedController.abort(sourceSignal.reason)\n return\n }\n\n combinedController.abort()\n }\n\n requestSignal.addEventListener('abort', handleAbort, { once: true })\n timeoutSignal.addEventListener('abort', handleAbort, { once: true })\n\n return {\n signal: combinedController.signal,\n cleanup: () => {\n requestSignal.removeEventListener('abort', handleAbort)\n timeoutSignal.removeEventListener('abort', handleAbort)\n },\n }\n}\n\nfunction createStandardizedError(error: unknown, context: string): Error {\n if (error instanceof Error) {\n return error\n }\n\n return new Error(`${context}: ${String(error)}`)\n}\n\nasync function fetchWithNetworkError(\n fetchImplementation: CustomFetch,\n url: string,\n requestInit: RequestInit\n): Promise<Response> {\n try {\n return await fetchImplementation(url, requestInit)\n } catch (error) {\n const standardizedError = createStandardizedError(\n error,\n 'Network request failed'\n )\n\n if (\n isAbortError(standardizedError) ||\n standardizedError instanceof NetworkError\n ) {\n throw standardizedError\n }\n\n throw new NetworkError(standardizedError.message, standardizedError)\n }\n}\n\nfunction createHttpError(\n response: ResponseType<unknown>,\n cause?: Error\n): HttpError {\n return new HttpError(\n `HTTP ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n response.data,\n response.raw,\n response.url,\n response.method,\n cause\n )\n}\n\nfunction constructUrl(baseUrl: string, requestUrl: string): string {\n if (isAbsoluteUrl(requestUrl)) {\n return requestUrl\n }\n\n return isAbsoluteUrl(baseUrl)\n ? constructAbsoluteUrl(baseUrl, requestUrl)\n : constructRelativeUrl(baseUrl, requestUrl)\n}\n\nfunction constructAbsoluteUrl(baseUrl: string, requestUrl: string): string {\n const baseUrlObj = new URL(baseUrl)\n const basePath = baseUrlObj.pathname.replace(/\\/$/, '')\n const { path, search, hash } = splitUrl(requestUrl)\n\n if (path.startsWith('/')) {\n baseUrlObj.pathname = basePath + path\n } else if (path) {\n baseUrlObj.pathname = basePath + '/' + path\n }\n\n if (search) {\n baseUrlObj.search = mergeSearch(baseUrlObj.search, search)\n }\n\n if (hash) {\n baseUrlObj.hash = hash\n }\n\n return baseUrlObj.toString()\n}\n\nfunction constructRelativeUrl(baseUrl: string, requestUrl: string): string {\n const {\n path: basePath,\n search: baseSearch,\n hash: baseHash,\n } = splitUrl(baseUrl)\n const {\n path: requestPath,\n search: requestSearch,\n hash: requestHash,\n } = splitUrl(requestUrl)\n\n const pathname = requestPath\n ? joinPathSegments(basePath, requestPath)\n : basePath || requestPath\n\n return `${pathname}${mergeSearch(baseSearch, requestSearch)}${\n requestHash || baseHash\n }`\n}\n\nfunction appendQueryString(url: string, queryString: string): string {\n const normalizedQuery = queryString.startsWith('?')\n ? queryString.slice(1)\n : queryString\n\n if (!normalizedQuery) {\n return url\n }\n\n const { path, search, hash } = splitUrl(url)\n const nextSearch = search\n ? `${search}&${normalizedQuery}`\n : `?${normalizedQuery}`\n\n return `${path}${nextSearch}${hash}`\n}\n\nfunction splitUrl(url: string): {\n path: string\n search: string\n hash: string\n} {\n const hashIndex = url.indexOf('#')\n const hash = hashIndex === -1 ? '' : url.slice(hashIndex)\n const withoutHash = hashIndex === -1 ? url : url.slice(0, hashIndex)\n const searchIndex = withoutHash.indexOf('?')\n\n return {\n path: searchIndex === -1 ? withoutHash : withoutHash.slice(0, searchIndex),\n search: searchIndex === -1 ? '' : withoutHash.slice(searchIndex),\n hash,\n }\n}\n\nfunction mergeSearch(baseSearch: string, requestSearch: string): string {\n if (!baseSearch) {\n return requestSearch\n }\n\n if (!requestSearch) {\n return baseSearch\n }\n\n return `${baseSearch}&${requestSearch.slice(1)}`\n}\n\nfunction joinPathSegments(basePath: string, requestPath: string): string {\n if (!basePath) {\n return requestPath.startsWith('/') ? requestPath : `/${requestPath}`\n }\n\n if (!requestPath) {\n return basePath\n }\n\n return requestPath.startsWith('/')\n ? `${basePath}${requestPath}`\n : `${basePath}/${requestPath}`\n}\n\nfunction createInternalRequest(\n url: string,\n requestInit: ExtendedRequestInit\n): Request {\n return new Request(toInternalRequestUrl(url), requestInit)\n}\n\nfunction isSuccessfulStatus(status: number): boolean {\n return status >= 200 && status < 300\n}\n\nfunction isResponseTypeLike(value: unknown): value is ResponseType<unknown> {\n return (\n value !== null &&\n typeof value === 'object' &&\n 'data' in value &&\n 'status' in value &&\n typeof value.status === 'number' &&\n 'statusText' in value &&\n typeof value.statusText === 'string' &&\n 'headers' in value &&\n typeof value.headers === 'object' &&\n value.headers !== null &&\n 'method' in value &&\n typeof value.method === 'string' &&\n 'url' in value &&\n typeof value.url === 'string' &&\n 'raw' in value &&\n value.raw instanceof Response\n )\n}\n\nfunction assertRequestUrlSupported(\n url: string,\n usesNativeFetch: boolean\n): void {\n if (!usesNativeFetch || isAbsoluteUrl(url) || supportsRelativeRequestUrls()) {\n return\n }\n\n throw new InvalidBaseUrlError(\n `Relative request URL \"${url}\" requires an absolute baseUrl in non-browser environments. Pass an absolute baseUrl or use a custom fetch implementation.`,\n url\n )\n}\n\nfunction isAbsoluteUrl(url: string): boolean {\n return /^[a-zA-Z][a-zA-Z\\d+\\-.]*:\\/\\//.test(url)\n}\n\nfunction supportsRelativeRequestUrls(): boolean {\n return (\n typeof window !== 'undefined' &&\n typeof window.location !== 'undefined' &&\n window.location.origin !== 'null'\n )\n}\n\nfunction toInternalRequestUrl(url: string): string {\n if (isAbsoluteUrl(url)) {\n return url\n }\n\n if (!url) {\n return 'https://1000fetches.local/'\n }\n\n return `https://1000fetches.local${url.startsWith('/') ? url : `/${url}`}`\n}\n\nfunction isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === 'AbortError'\n}\n\nfunction isInvalidUrlError(error: Error): boolean {\n return (\n error.message.includes('Invalid URL') ||\n error.message.includes('Failed to parse URL')\n )\n}\n","import type { StandardSchemaV1 } from '@standard-schema/spec'\nimport { InvalidSchemaError, SchemaValidationError } from './errors'\nimport { Schema } from './types'\n\n/**\n * Type guard to check if an object conforms to the Standard Schema V1 specification\n */\nfunction isStandardSchema(obj: unknown): obj is StandardSchemaV1 {\n return (\n obj !== null &&\n (typeof obj === 'object' || typeof obj === 'function') &&\n '~standard' in obj &&\n typeof obj['~standard'] === 'object' &&\n obj['~standard'] !== null &&\n 'validate' in obj['~standard'] &&\n typeof obj['~standard'].validate === 'function' &&\n 'version' in obj['~standard'] &&\n obj['~standard'].version === 1 &&\n 'vendor' in obj['~standard'] &&\n typeof obj['~standard'].vendor === 'string'\n )\n}\n\n/**\n * Interface for schema validators that can validate data against schemas.\n *\n * This interface allows you to create custom schema validators that work\n * with different validation libraries (Zod, Valibot, Arktype, etc.).\n */\nexport interface SchemaValidator {\n /**\n * Validate data against a schema.\n *\n * @template T - The expected type after validation\n * @param schema - The schema to validate against\n * @param data - The data to validate\n * @returns The validated data with the correct type, synchronously or asynchronously\n * @throws {SchemaValidationError} If the data doesn't match the schema\n */\n validate<T>(schema: Schema<T>, data: unknown): T | Promise<T>\n}\n\nfunction isPromiseLike<T>(value: unknown): value is PromiseLike<T> {\n return (\n value !== null &&\n (typeof value === 'object' || typeof value === 'function') &&\n 'then' in value &&\n typeof value.then === 'function'\n )\n}\n\nfunction readValidationResult<T>(\n schema: Schema<T>,\n data: unknown,\n result: StandardSchemaV1.Result<T>\n): T {\n if (result.issues) {\n throw new SchemaValidationError(\n JSON.stringify(result.issues),\n schema,\n data,\n undefined,\n result.issues\n )\n }\n\n return result.value\n}\n\n/**\n * Create a default schema validator that supports Standard Schema.\n *\n * This validator works with schemas that implement the Standard Schema\n * interface, including both synchronous and asynchronous validators.\n *\n * @returns A schema validator instance\n *\n * @example\n * ```ts\n * const validator = createSchemaValidator()\n *\n * const parsed = validator.validate(schema, data)\n * ```\n */\nexport function createSchemaValidator(): SchemaValidator {\n return {\n validate<T>(schema: Schema<T>, data: unknown): T | Promise<T> {\n if (!isStandardSchema(schema)) {\n throw new InvalidSchemaError(\n 'Schema must implement the Standard Schema interface',\n schema\n )\n }\n\n const result = schema['~standard'].validate(data) as\n | StandardSchemaV1.Result<T>\n | PromiseLike<StandardSchemaV1.Result<T>>\n\n if (isPromiseLike<StandardSchemaV1.Result<T>>(result)) {\n return Promise.resolve(result).then(asyncResult =>\n readValidationResult(schema, data, asyncResult)\n )\n }\n\n return readValidationResult(schema, data, result)\n },\n }\n}\n","import type { HttpClientConfig, HttpRequestOptions } from './core'\nimport { createHttpRequest } from './core'\nimport {\n InvalidBaseUrlError,\n InvalidSchemaError,\n SchemaValidationError,\n} from './errors'\nimport { createSchemaValidator } from './schema'\nimport type { SchemaValidator } from './schema'\nimport type {\n EnforcedPathParamsOptions,\n ExtractableResponse,\n InferSchemaOutput,\n RequestParamsType,\n ResponseType,\n Schema,\n SchemaableResponse,\n} from './types'\nimport type {\n AssertSupportedPath,\n HasRequiredParams,\n RequirePathParams,\n} from './utils'\n\ntype PathOptionsArgs<Path extends string, TOptions> = [\n AssertSupportedPath<Path>,\n] extends [never]\n ? [options: never]\n : HasRequiredParams<AssertSupportedPath<Path>> extends true\n ? [options: TOptions]\n : [options?: TOptions]\n\ntype EnforcedHttpRequestOptions<\n TBody,\n TParams extends RequestParamsType,\n Path extends string,\n> = RequirePathParams<\n AssertSupportedPath<Path>,\n string extends Path\n ? HttpRequestOptions<TBody, TParams>\n : Omit<HttpRequestOptions<TBody, TParams>, 'pathParams'>\n>\n\nfunction validateAndNormalizeBaseUrl(baseUrl?: string): string {\n if (!baseUrl) {\n return ''\n }\n\n if (baseUrl.startsWith('/')) {\n return baseUrl.replace(/\\/$/, '')\n }\n\n try {\n new URL(baseUrl)\n } catch {\n throw new InvalidBaseUrlError(\n `Invalid baseUrl: \"${baseUrl}\". Must be a valid absolute URL or relative path starting with \"/\".`,\n baseUrl\n )\n }\n\n return baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl\n}\n\nfunction createExtractableResponse<T>(\n promise: Promise<ResponseType<T>>\n): ExtractableResponse<T> {\n const extractable = promise as ExtractableResponse<T>\n extractable.data = async () => (await promise).data\n extractable.void = async () => {\n await promise\n }\n return extractable\n}\n\n/**\n * Creates a chainable response that allows adding schema validation and extracting data\n */\nfunction createSchemaableResponse<\n Path extends string,\n TResponse,\n TBody,\n TParams extends RequestParamsType,\n>(\n url: Path,\n options: HttpRequestOptions<TBody, TParams>,\n requestHandler: ReturnType<typeof createHttpRequest>,\n schemaValidator: SchemaValidator\n): SchemaableResponse<TResponse> {\n const basePromise = requestHandler<Path, TResponse, TBody, TParams>(\n url,\n options\n )\n\n return Object.assign(basePromise, {\n schema<S extends Schema>(\n schema: S\n ): ExtractableResponse<InferSchemaOutput<S>> {\n const validatedPromise = basePromise.then(async response => {\n try {\n const validatedData = (await schemaValidator.validate(\n schema,\n response.data\n )) as InferSchemaOutput<S>\n return {\n ...response,\n data: validatedData,\n }\n } catch (error) {\n if (\n error instanceof InvalidSchemaError ||\n error instanceof SchemaValidationError\n ) {\n throw error\n }\n\n throw new SchemaValidationError(\n error instanceof Error ? error.message : 'Schema validation failed',\n schema,\n response.data,\n error instanceof Error ? error : undefined\n )\n }\n })\n\n return createExtractableResponse(validatedPromise)\n },\n async data() {\n return (await basePromise).data\n },\n async void() {\n await basePromise\n },\n })\n}\n\n/**\n * Creates a complete HTTP client with method builders\n */\nexport function createHttpClient(config: HttpClientConfig = {}) {\n const validatedConfig = {\n ...config,\n baseUrl: validateAndNormalizeBaseUrl(config.baseUrl),\n }\n\n const requestHandler = createHttpRequest(validatedConfig)\n const schemaValidator = config.schemaValidator ?? createSchemaValidator()\n\n function get<\n Path extends string = string,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n ...args: PathOptionsArgs<\n Path,\n EnforcedPathParamsOptions<never, TParams, Path>\n >\n ) {\n return createSchemaableResponse<Path, unknown, never, TParams>(\n url,\n {\n ...(args[0] ?? {}),\n method: 'GET',\n },\n requestHandler,\n schemaValidator\n )\n }\n\n return {\n get,\n\n post: <\n Path extends string = string,\n TBody = unknown,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n body?: TBody,\n ...args: PathOptionsArgs<\n Path,\n EnforcedPathParamsOptions<TBody, TParams, Path>\n >\n ) =>\n createSchemaableResponse<Path, unknown, TBody, TParams>(\n url,\n {\n ...(args[0] ?? {}),\n method: 'POST',\n body,\n },\n requestHandler,\n schemaValidator\n ),\n\n put: <\n Path extends string = string,\n TBody = unknown,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n body?: TBody,\n ...args: PathOptionsArgs<\n Path,\n EnforcedPathParamsOptions<TBody, TParams, Path>\n >\n ) =>\n createSchemaableResponse<Path, unknown, TBody, TParams>(\n url,\n {\n ...(args[0] ?? {}),\n method: 'PUT',\n body,\n },\n requestHandler,\n schemaValidator\n ),\n\n patch: <\n Path extends string = string,\n TBody = unknown,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n body?: TBody,\n ...args: PathOptionsArgs<\n Path,\n EnforcedPathParamsOptions<TBody, TParams, Path>\n >\n ) =>\n createSchemaableResponse<Path, unknown, TBody, TParams>(\n url,\n {\n ...(args[0] ?? {}),\n method: 'PATCH',\n body,\n },\n requestHandler,\n schemaValidator\n ),\n\n delete: <\n Path extends string = string,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n ...args: PathOptionsArgs<\n Path,\n EnforcedPathParamsOptions<never, TParams, Path>\n >\n ) =>\n createSchemaableResponse<Path, unknown, never, TParams>(\n url,\n {\n ...(args[0] ?? {}),\n method: 'DELETE',\n },\n requestHandler,\n schemaValidator\n ),\n\n /**\n * Generic request method for custom HTTP methods and full control\n */\n request: <\n Path extends string = string,\n TBody = unknown,\n TParams extends RequestParamsType = RequestParamsType,\n >(\n url: Path,\n ...args: PathOptionsArgs<\n Path,\n EnforcedHttpRequestOptions<TBody, TParams, Path>\n >\n ) =>\n createSchemaableResponse<Path, unknown, TBody, TParams>(\n url,\n args[0] ?? {},\n requestHandler,\n schemaValidator\n ),\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ var e=class extends Error{name="HttpError";status;statusText;data;response;url;method;cause;constructor(e,t,r,n,a,s,o,i){const c=`HTTP ${t>=500?"Server Error":t>=400?"Client Error":t>=300?"Redirect":"Success"} (${t}): ${e}\nRequest: ${o} ${s}\nData: ${function(e){if(null==e||""===e)return"No response data";let t;try{t="string"==typeof e?e:JSON.stringify(e)}catch{t=String(e)}return t.length>500?t.substring(0,500)+"...":t}(n)}`;super(c,{cause:i}),this.status=t,this.statusText=r,this.data=n,this.response=a,this.url=s,this.method=o,this.cause=i}},t=class extends Error{name="NetworkError";cause;constructor(e,t){super(e,{cause:t}),this.cause=t}},r=class extends Error{name="SchemaValidationError";schema;data;issues;cause;constructor(e,t,r,n,a){super(e,{cause:n}),this.schema=t,this.data=r,this.issues=a,this.cause=n}},n=class extends Error{name="TimeoutError";cause;constructor(e,t){super(e,{cause:t}),this.cause=t}},a=class extends Error{name="PathParameterError";url;requiredParams;providedParams;cause;constructor(e,t,r,n,a){super(`${e}\nURL Template: ${t}\nExpected: [${r.map(e=>`"${e}"`).join(", ")}], Actual: [${n.map(e=>`"${e}"`).join(", ")}]`,{cause:a}),this.url=t,this.requiredParams=r,this.providedParams=n,this.cause=a}},s=class extends Error{name="MiddlewareError";type;url;method;cause;constructor(e,t,r,n,a){const s=r?`Request: ${n||"UNKNOWN"} ${r}`:"";super(s?`${e}\n${s}`:e,{cause:a}),this.type=t,this.url=r,this.method=n,this.cause=a}},o=class extends Error{name="SerializationError";cause;constructor(e,t){super(e,{cause:t}),this.cause=t}},i=class extends Error{name="InvalidSchemaError";schema;cause;constructor(e,t,r){super(e,{cause:r}),this.schema=t,this.cause=r}},c=class extends Error{name="AsyncSchemaValidationError";schema;cause;constructor(e,t,r){super(e,{cause:r}),this.schema=t,this.cause=r}},u=class extends Error{name="InvalidBaseUrlError";baseUrl;cause;constructor(e,t,r){super(`${e}\nBase URL: ${t}`,{cause:r}),this.baseUrl=t,this.cause=r}};function d(e,t={}){return function(e,t){const r=e.match(/(^|\/):([^/\s?#]+)\?(?=\/)/);if(!r)return;const[,,n]=r;throw new a(`Optional path parameter "${n}" is not supported here. Optional path parameters are only supported at the end of the path.`,e,[n],t)}(e,Object.keys(t)),e.replace(/(^|\/):([^/\s?#]+?)(\?)?(?=\/|$|[?#])/g,(r,n,s,o)=>{const i="?"===o;if(!/^[a-zA-Z0-9_]+$/.test(s))throw new a(`Invalid path parameter name: "${s}"`,e,[s],Object.keys(t));const c=t[s];if(void 0===c){if(i)return"";throw new a(`Missing required path parameter: "${s}"`,e,[s],Object.keys(t))}return`${n}${encodeURIComponent(String(c))}`})}function l(e,t,r,n){let a=0,s=!1,o=!1;const i=()=>{if(!s){s=!0;try{e.releaseLock()}catch{}}},c=()=>{o=!0,i()};return n?.addEventListener("abort",c),new ReadableStream({async start(s){try{for(;!o;){const{done:n,value:o}=await e.read();if(n)break;a+=o.length,t(o,r,a),s.enqueue(o)}o||s.close()}catch(u){throw o||s.error(u),u}finally{n?.removeEventListener("abort",c),i()}},cancel(){o=!0,n?.removeEventListener("abort",c),i()}})}async function h(e,t){if(!t||!e.body)return e;if(!e.body.getReader)return e;const r=l(e.body.getReader(),(e,r,n)=>{t({chunk:e,totalBytes:r,transferredBytes:n})},e.headers.get("content-length")?parseInt(e.headers.get("content-length")||"0",10):void 0,e.signal);return new Request(e.url,{method:e.method,headers:e.headers,body:r,signal:e.signal,credentials:e.credentials,cache:e.cache,mode:e.mode,redirect:e.redirect,referrer:e.referrer,referrerPolicy:e.referrerPolicy,integrity:e.integrity,keepalive:e.keepalive,duplex:"half"})}async function f(e,t){if(!t||!e.body)return e;if(!e.body.getReader)return e;const r=l(e.body.getReader(),(e,r,n)=>{t({chunk:e,totalBytes:r,transferredBytes:n})},e.headers.get("content-length")?parseInt(e.headers.get("content-length")||"0",10):void 0);return new Response(r,{status:e.status,statusText:e.statusText,headers:e.headers})}var p={maxRetries:3,retryDelay:300,backoffFactor:2,retryStatusCodes:[408,429,500,502,503,504],retryNetworkErrors:!0,maxRetryDelay:3e4,retryMethods:["GET","HEAD","OPTIONS","PUT","DELETE"],retryUnsafeMethods:!1,jitter:"none",respectRetryAfter:!0};function m(e={}){const{baseUrl:t="",headers:r={},timeout:a=3e4,fetch:o,serializeBody:i,serializeParams:c,onRequestMiddleware:l,onResponseMiddleware:m}=e,$=void 0===o;return async function(M,N={}){const{method:D="GET",headers:k={},params:B,pathParams:C,body:I,timeout:H=a,signal:W,credentials:z,cache:F,mode:J,redirect:G,fetchOptions:V,onUploadStreaming:Z,onDownloadStreaming:K,responseType:_,retry:Q}=N;let X=void 0===C?d(M):d(M,C);t&&(X=function(e,t){return L(t)?t:L(e)?function(e,t){const r=new URL(e),n=r.pathname.replace(/\/$/,""),{path:a,search:s,hash:o}=j(t);a.startsWith("/")?r.pathname=n+a:a&&(r.pathname=n+"/"+a);s&&(r.search=U(r.search,s));o&&(r.hash=o);return r.toString()}(e,t):function(e,t){const{path:r,search:n,hash:a}=j(e),{path:s,search:o,hash:i}=j(t);return`${s?function(e,t){return e?t?t.startsWith("/")?`${e}${t}`:`${e}/${t}`:e:t.startsWith("/")?t:`/${t}`}(r,s):r||s}${U(n,o)}${i||a}`}(e,t)}(t,X));const Y=function(e,t){const r={...e??{}};void 0!==t.cache&&(r.cache=t.cache);void 0!==t.credentials&&(r.credentials=t.credentials);void 0!==t.mode&&(r.mode=t.mode);void 0!==t.redirect&&(r.redirect=t.redirect);return r}(V,{cache:F,credentials:z,mode:J,redirect:G}),ee={url:X,method:D,params:B,headers:new Headers({...r,...k}),body:I,signal:W,fetchOptions:Y};let te=ee;if(l)try{te=await l({...ee,headers:new Headers(ee.headers),fetchOptions:{...ee.fetchOptions}})}catch(ie){throw new s(g("Request middleware failed",ie),"request",te.url,te.method,x(ie,"Request middleware"))}if(te.params){const e=c?c(te.params):function(e){const t=new URLSearchParams;for(const[r,n]of Object.entries(e))if(Array.isArray(n))for(const e of n)null!=e&&t.append(r,String(e));else null!=n&&t.append(r,String(n));return t.toString()}(te.params);e&&(te.url=function(e,t){const r=t.startsWith("?")?t.slice(1):t;if(!r)return e;const{path:n,search:a,hash:s}=j(e);return`${n}${a?`${a}&${r}`:`?${r}`}${s}`}(te.url,e))}!function(e,t){if(!t||L(e)||"undefined"!=typeof window&&void 0!==window.location&&"null"!==window.location.origin)return;throw new u(`Relative request URL "${e}" requires an absolute baseUrl in non-browser environments. Pass an absolute baseUrl or use a custom fetch implementation.`,e)}(te.url,$);const re={method:te.method,headers:te.headers,...te.fetchOptions};if(void 0!==te.body&&"GET"!==te.method&&"HEAD"!==te.method){let e,t;if(i){const t=i(te.body);e=null==t?"":t}else{const r=function(e){if(ArrayBuffer.isView(e)){const t=new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return{body:new Uint8Array(t).buffer}}return"string"==typeof e||e instanceof FormData||e instanceof URLSearchParams||e instanceof ArrayBuffer||e instanceof Blob||e instanceof ReadableStream?{body:e}:function(e){return null!==e&&"object"==typeof e&&(Array.isArray(e)||"toJSON"in e&&"function"==typeof e.toJSON||"[object Object]"===Object.prototype.toString.call(e))}(e)?{body:JSON.stringify(e),contentType:"application/json"}:null==e?{body:""}:{body:String(e)}}(te.body);e=r.body,t=r.contentType}re.body=e,t&&te.headers.set("content-type",t),re.duplex="half"}const ne=function(e,t){const r="object"==typeof e?e:void 0,n=!0===e||void 0!==r||!0===t||"object"==typeof t;if(!1===t)return;if(!n)return;const a={...p,...r};return!0===t?a:"object"==typeof t?{...a,...t}:a}(e.retry,Q),ae=ne?.maxRetries??0,se=function(e){return!(e instanceof ReadableStream)}(re.body);let oe;for(let e=0;e<=ae;e+=1){const t=new AbortController;let r=!1;const a=setTimeout(()=>{r=!0,t.abort()},H),{signal:i,cleanup:c}=R(te.signal,t.signal);let u=!1;const d=()=>{u||(u=!0,clearTimeout(a),c())};try{const e={...re,headers:te.headers,signal:i,...te.fetchOptions};if(Z&&void 0!==e.body){const t=await h(O(te.url,e),Z);e.body=t.body??void 0,e.headers=t.headers}const t=await T(o??globalThis.fetch,te.url,e),r=K?await f(t,K):t,n=await y(r,{responseType:_,method:te.method,url:te.url,tolerateParseError:!P(r.status)});let a=n;if(m)try{const e=await m(n);if(!A(e))throw new s("Response middleware must return a valid ResponseType object","response",te.url,te.method);a=e}catch(ie){throw new s(g("Response middleware failed",ie),"response",te.url,te.method,x(ie,"Response middleware"))}if(!P(a.status))throw S(a,n.parseError);return a}catch(ie){if(oe=x(ie,"Request execution"),q(oe)&&r&&(oe=new n(`Request timeout after ${H}ms`,oe)),e>=ae||!(await w(oe,e,ne,{bodyReplayable:se,method:te.method,url:te.url})))throw oe;const t=b(e,ne,oe);await v(ne,{bodyReplayable:se,delay:t,error:oe,method:te.method,nextAttempt:e+1,retryCount:e,url:te.url}),d(),await E(t,te.signal)}finally{d()}}throw new Error("Retry loop terminated unexpectedly")}}async function y(e,t){const r=Object.fromEntries(e.headers.entries());let n,a;const s=e.clone();try{const r=t.responseType,a=e.headers.get("content-type")??"",o=a.includes("application/json")?"json":a.includes("text/")?"text":a.includes("application/octet-stream")||a.includes("application/pdf")||a.includes("image/")||a.includes("video/")||a.includes("audio/")?"arrayBuffer":a.includes("multipart/form-data")||a.includes("application/x-www-form-urlencoded")?"formData":void 0,i=r??o;if("json"===i)n=await e.json();else if("text"===i)n=await e.text();else if("blob"===i)n=await e.blob();else if("arrayBuffer"===i)n=await e.arrayBuffer();else if("formData"===i)n=await e.formData();else try{n=await e.json()}catch{n=await s.text()}}catch(i){if(a=new o(g("Failed to parse response body",i),i instanceof Error?i:void 0),!t.tolerateParseError)throw a;try{n=await s.text()}catch{n=""}}return{data:n,status:e.status,statusText:e.statusText,headers:r,method:t.method,url:t.url,raw:e,parseError:a}}async function w(r,n,a,s){if(!a)return!1;const o={...s,error:r,retryCount:n};return a.shouldRetry?await a.shouldRetry(r,n,o):!(!s.bodyReplayable||!function(e,t){if(t.retryUnsafeMethods)return!0;const r=e.toUpperCase();return t.retryMethods.some(e=>e.toUpperCase()===r)}(s.method,a))&&(r instanceof e?a.retryStatusCodes.includes(r.status):(r instanceof t||"TypeError"===r.name&&!function(e){return e.message.includes("Invalid URL")||e.message.includes("Failed to parse URL")}(r))&&a.retryNetworkErrors)}function b(t,r,n){if(!r)return 0;const a=r.respectRetryAfter?function(t){if(!(t instanceof e))return;const r=t.response.headers.get("retry-after");if(!r)return;const n=Number(r);if(Number.isFinite(n))return Math.max(0,1e3*n);const a=Date.parse(r);if(Number.isNaN(a))return;return Math.max(0,a-Date.now())}(n):void 0;if(void 0!==a)return Math.min(a,r.maxRetryDelay);const s=r.retryDelay*Math.pow(r.backoffFactor,t);return function(e,t,r){return"function"==typeof t?Math.max(0,t(e,r)):"full"===t?Math.floor(Math.random()*e):"equal"===t?Math.floor(e/2+Math.random()*(e/2)):e}(Math.min(s,r.maxRetryDelay),r.jitter,t)}async function v(e,t){await(e?.onRetry?.(t))}function g(e,t){return`${e}: ${t instanceof Error?t.message:String(t)}`}function E(e,t){return e<=0?Promise.resolve():t?.aborted?Promise.reject($(t.reason)):new Promise((r,n)=>{const a=setTimeout(()=>{t?.removeEventListener("abort",s),r()},e),s=()=>{clearTimeout(a),t?.removeEventListener("abort",s),n($(t?.reason))};t?.addEventListener("abort",s,{once:!0})})}function $(e){if(e instanceof Error)return e;const t=/* @__PURE__ */new Error("The operation was aborted");return t.name="AbortError",t}function R(e,t){if(!e&&!t)return{signal:void 0,cleanup:()=>{}};if(!e)return{signal:t,cleanup:()=>{}};if(!t)return{signal:e,cleanup:()=>{}};if(e?.aborted)return{signal:e,cleanup:()=>{}};if(t.aborted)return{signal:t,cleanup:()=>{}};const r=new AbortController,n=e=>{const t=e.target;t instanceof AbortSignal?r.abort(t.reason):r.abort()};return e.addEventListener("abort",n,{once:!0}),t.addEventListener("abort",n,{once:!0}),{signal:r.signal,cleanup:()=>{e.removeEventListener("abort",n),t.removeEventListener("abort",n)}}}function x(e,t){return e instanceof Error?e:/* @__PURE__ */new Error(`${t}: ${String(e)}`)}async function T(e,r,n){try{return await e(r,n)}catch(a){const e=x(a,"Network request failed");if(q(e)||e instanceof t)throw e;throw new t(e.message,e)}}function S(t,r){return new e(`HTTP ${t.status} ${t.statusText}`,t.status,t.statusText,t.data,t.raw,t.url,t.method,r)}function j(e){const t=e.indexOf("#"),r=-1===t?"":e.slice(t),n=-1===t?e:e.slice(0,t),a=n.indexOf("?");return{path:-1===a?n:n.slice(0,a),search:-1===a?"":n.slice(a),hash:r}}function U(e,t){return e?t?`${e}&${t.slice(1)}`:e:t}function O(e,t){return new Request(function(e){return L(e)?e:e?`https://1000fetches.local${e.startsWith("/")?e:`/${e}`}`:"https://1000fetches.local/"}(e),t)}function P(e){return e>=200&&e<300}function A(e){return null!==e&&"object"==typeof e&&"data"in e&&"status"in e&&"number"==typeof e.status&&"statusText"in e&&"string"==typeof e.statusText&&"headers"in e&&"object"==typeof e.headers&&null!==e.headers&&"method"in e&&"string"==typeof e.method&&"url"in e&&"string"==typeof e.url&&"raw"in e&&e.raw instanceof Response}function L(e){return/^[a-zA-Z][a-zA-Z\d+\-.]*:\/\//.test(e)}function q(e){return e instanceof Error&&"AbortError"===e.name}function M(e,t,n){if(n.issues)throw new r(JSON.stringify(n.issues),e,t,void 0,n.issues);return n.value}function N(){return{validate(e,t){if(null===(r=e)||"object"!=typeof r&&"function"!=typeof r||!("~standard"in r)||"object"!=typeof r["~standard"]||null===r["~standard"]||!("validate"in r["~standard"])||"function"!=typeof r["~standard"].validate||!("version"in r["~standard"])||1!==r["~standard"].version||!("vendor"in r["~standard"])||"string"!=typeof r["~standard"].vendor)throw new i("Schema must implement the Standard Schema interface",e);var r;const n=e["~standard"].validate(t);return null===(a=n)||"object"!=typeof a&&"function"!=typeof a||!("then"in a)||"function"!=typeof a.then?M(e,t,n):Promise.resolve(n).then(r=>M(e,t,r));var a}}}function D(e){if(!e)return"";if(e.startsWith("/"))return e.replace(/\/$/,"");try{new URL(e)}catch{throw new u(`Invalid baseUrl: "${e}". Must be a valid absolute URL or relative path starting with "/".`,e)}return e.endsWith("/")?e.slice(0,-1):e}function k(e,t,n,a){const s=n(e,t);return Object.assign(s,{schema:e=>function(e){const t=e;return t.data=async()=>(await e).data,t.void=async()=>{await e},t}(s.then(async t=>{try{const r=await a.validate(e,t.data);return{...t,data:r}}catch(n){if(n instanceof i||n instanceof r)throw n;throw new r(n instanceof Error?n.message:"Schema validation failed",e,t.data,n instanceof Error?n:void 0)}})),data:async()=>(await s).data,async void(){await s}})}function B(e={}){const t=m({...e,baseUrl:D(e.baseUrl)}),r=e.schemaValidator??N();return{get:function(e,...n){return k(e,{...n[0]??{},method:"GET"},t,r)},post:(e,n,...a)=>k(e,{...a[0]??{},method:"POST",body:n},t,r),put:(e,n,...a)=>k(e,{...a[0]??{},method:"PUT",body:n},t,r),patch:(e,n,...a)=>k(e,{...a[0]??{},method:"PATCH",body:n},t,r),delete:(e,...n)=>k(e,{...n[0]??{},method:"DELETE"},t,r),request:(e,...n)=>k(e,n[0]??{},t,r)}}export{u as a,t as c,o as d,n as f,e as i,a as l,N as n,i as o,c as r,s,B as t,r as u};
2
+ //# sourceMappingURL=client-DOv6m2TJ.mjs.map