@anmetric/neta 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,623 @@
1
+ # neta
2
+
3
+ > Tiny, elegant HTTP client built on [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) for browser and Node.js
4
+
5
+ - **Zero dependencies** — uses native `globalThis.fetch`
6
+ - **~12 KB** minified, ESM + CJS
7
+ - **TypeScript ready** — full `.d.ts` type definitions
8
+ - **Works everywhere** — browser, Node.js 18+, Deno, Bun
9
+
10
+ ## Install
11
+
12
+ ```sh
13
+ npm install neta
14
+ ```
15
+
16
+ ## Quick Start
17
+
18
+ ```js
19
+ import neta from 'neta';
20
+
21
+ // GET with JSON parsing
22
+ const data = await neta.get('https://api.example.com/users').json();
23
+
24
+ // POST with JSON body
25
+ const user = await neta.post('https://api.example.com/users', {
26
+ json: { name: 'John', email: 'john@example.com' },
27
+ }).json();
28
+
29
+ // Direct callable
30
+ const res = await neta('https://api.example.com/users', { method: 'get' });
31
+ ```
32
+
33
+ ## API
34
+
35
+ ### `neta(input, options?)`
36
+
37
+ Returns a [`ResponsePromise`](#responsepromise).
38
+
39
+ #### input
40
+
41
+ Type: `string | URL | Request`
42
+
43
+ #### options
44
+
45
+ Type: `object`
46
+
47
+ All [`fetch` options](https://developer.mozilla.org/en-US/docs/Web/API/fetch#parameters) plus:
48
+
49
+ ##### json
50
+
51
+ Type: `unknown`
52
+
53
+ JSON body. Automatically stringified and sets `Content-Type: application/json`.
54
+
55
+ ```js
56
+ const data = await neta.post('https://api.example.com/items', {
57
+ json: { title: 'New Item' },
58
+ }).json();
59
+ ```
60
+
61
+ ##### searchParams
62
+
63
+ Type: `string | object | URLSearchParams | Array<[string, string]>`
64
+
65
+ Query parameters appended to the URL.
66
+
67
+ ```js
68
+ const data = await neta.get('https://api.example.com/search', {
69
+ searchParams: { q: 'hello', page: 2 },
70
+ }).json();
71
+ // => GET https://api.example.com/search?q=hello&page=2
72
+ ```
73
+
74
+ Values set to `undefined` are filtered out.
75
+
76
+ ##### prefix
77
+
78
+ Type: `string | URL`
79
+
80
+ Prefix prepended to the input URL. Useful for API base paths.
81
+
82
+ ```js
83
+ const api = neta.create({ prefix: 'https://api.example.com/v2' });
84
+
85
+ await api.get('users').json();
86
+ // => GET https://api.example.com/v2/users
87
+ ```
88
+
89
+ ##### baseUrl
90
+
91
+ Type: `string | URL`
92
+
93
+ Base URL for resolving relative inputs using standard [URL resolution](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL).
94
+
95
+ ```js
96
+ const api = neta.create({ baseUrl: 'https://api.example.com/v2/' });
97
+
98
+ await api.get('users').json();
99
+ // => GET https://api.example.com/v2/users
100
+
101
+ await api.get('../v1/legacy').json();
102
+ // => GET https://api.example.com/v1/legacy
103
+ ```
104
+
105
+ ##### timeout
106
+
107
+ Type: `number | false`\
108
+ Default: `10000` (10 seconds)
109
+
110
+ Request timeout in milliseconds. Set to `false` to disable.
111
+
112
+ ##### totalTimeout
113
+
114
+ Type: `number | false`\
115
+ Default: `false`
116
+
117
+ Total timeout across all retries in milliseconds.
118
+
119
+ ```js
120
+ await neta.get('https://api.example.com/slow', {
121
+ timeout: 5000,
122
+ totalTimeout: 30000,
123
+ retry: 5,
124
+ });
125
+ ```
126
+
127
+ ##### retry
128
+
129
+ Type: `number | object`\
130
+ Default: `{ limit: 2 }`
131
+
132
+ Retry configuration. Pass a number for simple retry limit, or an object for full control.
133
+
134
+ ```js
135
+ // Simple
136
+ await neta.get(url, { retry: 3 });
137
+
138
+ // Full control
139
+ await neta.get(url, {
140
+ retry: {
141
+ limit: 3,
142
+ methods: ['get', 'put', 'head', 'delete', 'options'],
143
+ statusCodes: [408, 413, 429, 500, 502, 503, 504],
144
+ afterStatusCodes: [413, 429, 503],
145
+ maxRetryAfter: Infinity,
146
+ backoffLimit: Infinity,
147
+ delay: (attemptCount) => 300 * 2 ** (attemptCount - 1),
148
+ jitter: false,
149
+ retryOnTimeout: false,
150
+ shouldRetry: undefined,
151
+ },
152
+ });
153
+ ```
154
+
155
+ ###### retry.limit
156
+
157
+ Type: `number`\
158
+ Default: `2`
159
+
160
+ Maximum number of retries.
161
+
162
+ ###### retry.methods
163
+
164
+ Type: `string[]`\
165
+ Default: `['get', 'put', 'head', 'delete', 'options']`
166
+
167
+ HTTP methods eligible for retry.
168
+
169
+ ###### retry.statusCodes
170
+
171
+ Type: `number[]`\
172
+ Default: `[408, 413, 429, 500, 502, 503, 504]`
173
+
174
+ HTTP status codes that trigger a retry.
175
+
176
+ ###### retry.afterStatusCodes
177
+
178
+ Type: `number[]`\
179
+ Default: `[413, 429, 503]`
180
+
181
+ Status codes where the `Retry-After` header is honored.
182
+
183
+ ###### retry.maxRetryAfter
184
+
185
+ Type: `number`\
186
+ Default: `Infinity`
187
+
188
+ Maximum `Retry-After` delay (ms) to accept.
189
+
190
+ ###### retry.backoffLimit
191
+
192
+ Type: `number`\
193
+ Default: `Infinity`
194
+
195
+ Maximum backoff delay (ms).
196
+
197
+ ###### retry.delay
198
+
199
+ Type: `(attemptCount: number) => number`\
200
+ Default: `(n) => 300 * 2 ** (n - 1)`
201
+
202
+ Function returning delay in ms for each attempt.
203
+
204
+ ###### retry.jitter
205
+
206
+ Type: `boolean | ((delay: number) => number)`\
207
+ Default: `false`
208
+
209
+ Add randomness to retry delay to prevent thundering herd.
210
+
211
+ - `true` — random value between 0 and computed delay
212
+ - `function` — custom jitter function
213
+
214
+ ```js
215
+ await neta.get(url, {
216
+ retry: {
217
+ limit: 5,
218
+ delay: (n) => 1000 * 2 ** (n - 1),
219
+ jitter: true,
220
+ },
221
+ });
222
+ ```
223
+
224
+ ###### retry.retryOnTimeout
225
+
226
+ Type: `boolean`\
227
+ Default: `false`
228
+
229
+ Whether to retry when a request times out.
230
+
231
+ ###### retry.shouldRetry
232
+
233
+ Type: `({ error, retryCount }) => boolean | undefined | Promise<boolean | undefined>`
234
+
235
+ Custom function to decide whether to retry. Takes precedence over default checks.
236
+
237
+ - Return `true` to force retry
238
+ - Return `false` to prevent retry
239
+ - Return `undefined` to fall through to default behavior
240
+
241
+ ```js
242
+ await neta.get(url, {
243
+ retry: {
244
+ limit: 3,
245
+ shouldRetry: ({ error, retryCount }) => {
246
+ if (error.response?.status === 401) return false; // Don't retry auth errors
247
+ return undefined; // Default behavior for others
248
+ },
249
+ },
250
+ });
251
+ ```
252
+
253
+ ##### throwHttpErrors
254
+
255
+ Type: `boolean | ((status: number) => boolean)`\
256
+ Default: `true`
257
+
258
+ Throw `HTTPError` for non-2xx responses. Pass a function for custom logic.
259
+
260
+ ```js
261
+ // Never throw
262
+ const response = await neta.get(url, { throwHttpErrors: false });
263
+
264
+ // Only throw on 5xx
265
+ const response = await neta.get(url, {
266
+ throwHttpErrors: (status) => status >= 500,
267
+ });
268
+ ```
269
+
270
+ ##### parseJson
271
+
272
+ Type: `(text: string, context: { request, response }) => unknown`
273
+
274
+ Custom JSON parser. Useful for reviving dates, BigInts, etc.
275
+
276
+ ```js
277
+ import LosslessJSON from 'lossless-json';
278
+
279
+ const data = await neta.get(url, {
280
+ parseJson: (text) => LosslessJSON.parse(text),
281
+ }).json();
282
+ ```
283
+
284
+ ##### stringifyJson
285
+
286
+ Type: `(value: unknown) => string`
287
+
288
+ Custom JSON serializer for the `json` option.
289
+
290
+ ```js
291
+ import LosslessJSON from 'lossless-json';
292
+
293
+ await neta.post(url, {
294
+ json: data,
295
+ stringifyJson: (value) => LosslessJSON.stringify(value),
296
+ });
297
+ ```
298
+
299
+ ##### context
300
+
301
+ Type: `Record<string, unknown>`\
302
+ Default: `{}`
303
+
304
+ Arbitrary data passed through to hooks. Not sent with the request.
305
+
306
+ ```js
307
+ await neta.get(url, {
308
+ context: { token: 'abc123' },
309
+ hooks: {
310
+ init: [(options) => {
311
+ options.headers = { ...options.headers, Authorization: `Bearer ${options.context.token}` };
312
+ }],
313
+ },
314
+ });
315
+ ```
316
+
317
+ ##### fetch
318
+
319
+ Type: `typeof globalThis.fetch`
320
+
321
+ Custom fetch implementation.
322
+
323
+ ```js
324
+ import { fetch } from 'undici';
325
+
326
+ const api = neta.create({ fetch });
327
+ ```
328
+
329
+ ##### onDownloadProgress
330
+
331
+ Type: `(progress: { percent, transferredBytes, totalBytes }) => void`
332
+
333
+ Download progress callback. Requires `ReadableStream` support.
334
+
335
+ ```js
336
+ await neta.get('https://example.com/large-file', {
337
+ onDownloadProgress: ({ percent, transferredBytes, totalBytes }) => {
338
+ console.log(`${Math.round(percent * 100)}% (${transferredBytes}/${totalBytes})`);
339
+ },
340
+ });
341
+ ```
342
+
343
+ ##### onUploadProgress
344
+
345
+ Type: `(progress: { percent, transferredBytes, totalBytes }) => void`
346
+
347
+ Upload progress callback. Requires request streams support (`duplex: 'half'`).
348
+
349
+ ### HTTP Method Shortcuts
350
+
351
+ ```js
352
+ neta.get(input, options?)
353
+ neta.post(input, options?)
354
+ neta.put(input, options?)
355
+ neta.patch(input, options?)
356
+ neta.delete(input, options?)
357
+ neta.head(input, options?)
358
+ neta.options(input, options?)
359
+ ```
360
+
361
+ ### ResponsePromise
362
+
363
+ `neta` methods return a `ResponsePromise` — a `Promise<Response>` with body parsing shortcuts:
364
+
365
+ ```js
366
+ const json = await neta.get(url).json();
367
+ const text = await neta.get(url).text();
368
+ const blob = await neta.get(url).blob();
369
+ const buffer = await neta.get(url).arrayBuffer();
370
+ const form = await neta.get(url).formData();
371
+ ```
372
+
373
+ #### .json(schema?)
374
+
375
+ Parse response as JSON. Optionally validate against a [Standard Schema](https://github.com/standard-schema/standard-schema):
376
+
377
+ ```js
378
+ import { z } from 'zod';
379
+
380
+ const user = await neta.get('/user/1').json(z.object({
381
+ id: z.number(),
382
+ name: z.string(),
383
+ }));
384
+ // Throws SchemaValidationError if validation fails
385
+ ```
386
+
387
+ ### Instance Creation
388
+
389
+ #### neta.create(defaults?)
390
+
391
+ Create a new instance with default options:
392
+
393
+ ```js
394
+ const api = neta.create({
395
+ prefix: 'https://api.example.com',
396
+ headers: { Authorization: 'Bearer token' },
397
+ timeout: 30000,
398
+ retry: 3,
399
+ });
400
+
401
+ const data = await api.get('users').json();
402
+ ```
403
+
404
+ #### neta.extend(defaults?)
405
+
406
+ Alias for `neta.create()`. Creates a new instance by extending existing defaults:
407
+
408
+ ```js
409
+ const api = neta.create({ prefix: 'https://api.example.com' });
410
+ const authApi = api.extend({ headers: { Authorization: 'Bearer token' } });
411
+ ```
412
+
413
+ ## Hooks
414
+
415
+ Five hook points for intercepting the request lifecycle.
416
+
417
+ ### hooks.init
418
+
419
+ Type: `Array<(options) => void>`
420
+
421
+ Called synchronously before anything else. Can mutate options directly.
422
+
423
+ ```js
424
+ neta.create({
425
+ hooks: {
426
+ init: [(options) => {
427
+ options.headers = { ...options.headers, 'X-Request-Id': crypto.randomUUID() };
428
+ }],
429
+ },
430
+ });
431
+ ```
432
+
433
+ ### hooks.beforeRequest
434
+
435
+ Type: `Array<({ request, options, retryCount }) => Request | Response | void>`
436
+
437
+ Called before each request. Return a `Request` to replace it, a `Response` to short-circuit, or nothing.
438
+
439
+ ```js
440
+ neta.create({
441
+ hooks: {
442
+ beforeRequest: [({ request }) => {
443
+ console.log(`${request.method} ${request.url}`);
444
+ }],
445
+ },
446
+ });
447
+ ```
448
+
449
+ ### hooks.afterResponse
450
+
451
+ Type: `Array<({ request, options, response, retryCount }) => Response | RetryMarker | void>`
452
+
453
+ Called after a successful response. Return a `Response` to replace it, or `neta.retry()` to force a retry.
454
+
455
+ ```js
456
+ const api = neta.create({
457
+ hooks: {
458
+ afterResponse: [async ({ request, response }) => {
459
+ if (response.status === 401) {
460
+ const token = await refreshToken();
461
+ return neta.retry({
462
+ request: new Request(request, {
463
+ headers: { ...Object.fromEntries(request.headers), Authorization: `Bearer ${token}` },
464
+ }),
465
+ });
466
+ }
467
+ }],
468
+ },
469
+ });
470
+ ```
471
+
472
+ ### hooks.beforeError
473
+
474
+ Type: `Array<({ request, options, error, retryCount }) => Error | void>`
475
+
476
+ Called before an error is thrown. Return an `Error` to replace it.
477
+
478
+ ```js
479
+ neta.create({
480
+ hooks: {
481
+ beforeError: [({ error }) => {
482
+ if (error instanceof HTTPError) {
483
+ error.message = `API Error: ${error.response.status}`;
484
+ }
485
+ return error;
486
+ }],
487
+ },
488
+ });
489
+ ```
490
+
491
+ ### hooks.beforeRetry
492
+
493
+ Type: `Array<({ request, options, error, retryCount }) => Request | Response | symbol | void>`
494
+
495
+ Called before each retry attempt. Return:
496
+
497
+ - `Request` — use this request for the retry
498
+ - `Response` — skip the retry and use this response
499
+ - `stop` — abort the retry loop
500
+ - nothing — proceed normally
501
+
502
+ ```js
503
+ import { stop } from 'neta';
504
+
505
+ neta.create({
506
+ hooks: {
507
+ beforeRetry: [({ error, retryCount }) => {
508
+ console.log(`Retry #${retryCount}: ${error.message}`);
509
+ if (retryCount > 3) return stop;
510
+ }],
511
+ },
512
+ });
513
+ ```
514
+
515
+ ## Error Handling
516
+
517
+ ### HTTPError
518
+
519
+ Thrown for non-2xx responses (when `throwHttpErrors` is true).
520
+
521
+ ```js
522
+ import { HTTPError } from 'neta';
523
+
524
+ try {
525
+ await neta.get('https://api.example.com/missing');
526
+ } catch (error) {
527
+ if (error instanceof HTTPError) {
528
+ console.log(error.response.status); // 404
529
+ console.log(error.data); // Auto-parsed response body
530
+ console.log(error.request); // The Request object
531
+ }
532
+ }
533
+ ```
534
+
535
+ ### TimeoutError
536
+
537
+ Thrown when a request exceeds the `timeout` or `totalTimeout`.
538
+
539
+ ```js
540
+ import { TimeoutError } from 'neta';
541
+
542
+ try {
543
+ await neta.get(url, { timeout: 1000 });
544
+ } catch (error) {
545
+ if (error instanceof TimeoutError) {
546
+ console.log('Request timed out:', error.request.url);
547
+ }
548
+ }
549
+ ```
550
+
551
+ ### NetworkError
552
+
553
+ Thrown on network failures (DNS, connection refused, etc.).
554
+
555
+ ```js
556
+ import { NetworkError } from 'neta';
557
+
558
+ try {
559
+ await neta.get('https://nonexistent.invalid');
560
+ } catch (error) {
561
+ if (error instanceof NetworkError) {
562
+ console.log('Network error:', error.message);
563
+ console.log('Cause:', error.cause);
564
+ }
565
+ }
566
+ ```
567
+
568
+ ### SchemaValidationError
569
+
570
+ Thrown when JSON response fails schema validation.
571
+
572
+ ```js
573
+ import { SchemaValidationError } from 'neta';
574
+
575
+ try {
576
+ await neta.get(url).json(mySchema);
577
+ } catch (error) {
578
+ if (error instanceof SchemaValidationError) {
579
+ console.log('Validation issues:', error.issues);
580
+ }
581
+ }
582
+ ```
583
+
584
+ ## TypeScript
585
+
586
+ neta ships with full TypeScript definitions. Generic type parameters work on `.json()`:
587
+
588
+ ```ts
589
+ interface User {
590
+ id: number;
591
+ name: string;
592
+ }
593
+
594
+ const user = await neta.get('https://api.example.com/user/1').json<User>();
595
+ // user is typed as User
596
+ ```
597
+
598
+ ## Retry-After Header Support
599
+
600
+ neta automatically parses these headers during retry:
601
+
602
+ - `Retry-After`
603
+ - `RateLimit-Reset`
604
+ - `X-RateLimit-Retry-After`
605
+ - `X-RateLimit-Reset`
606
+ - `X-Rate-Limit-Reset`
607
+
608
+ Supports seconds, timestamps, and HTTP dates.
609
+
610
+ ## Browser + Node.js
611
+
612
+ neta uses `globalThis.fetch` which is available natively in:
613
+
614
+ - All modern browsers
615
+ - Node.js 18+
616
+ - Deno
617
+ - Bun
618
+
619
+ No polyfills needed.
620
+
621
+ ## License
622
+
623
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";var M=Object.defineProperty;var pe=Object.getOwnPropertyDescriptor;var ye=Object.getOwnPropertyNames;var we=Object.prototype.hasOwnProperty;var Re=(t,e)=>{for(var r in e)M(t,r,{get:e[r],enumerable:!0})},ge=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of ye(e))!we.call(t,n)&&n!==r&&M(t,n,{get:()=>e[n],enumerable:!(o=pe(e,n))||o.enumerable});return t};var be=t=>ge(M({},"__esModule",{value:!0}),t);var Ue={};Re(Ue,{ForceRetryError:()=>k,HTTPError:()=>E,NetaClient:()=>z,NetaError:()=>E,NetworkError:()=>S,SchemaValidationError:()=>D,TimeoutError:()=>R,createInstance:()=>z,default:()=>Oe,neta:()=>fe,stop:()=>T});module.exports=be(Ue);var W=["get","post","put","patch","delete","head","options"],_={limit:2,methods:["get","put","head","delete","options"],statusCodes:[408,413,429,500,502,503,504],afterStatusCodes:[413,429,503],maxRetryAfter:1/0,backoffLimit:1/0,delay:t=>300*2**(t-1),jitter:!1,retryOnTimeout:!1,shouldRetry:void 0},G=1e4,q=2147483647,K={json:"application/json",text:"text/*",formData:"multipart/form-data",arrayBuffer:"*/*",blob:"*/*",bytes:"*/*"},Fe=typeof globalThis.AbortController=="function",Me=typeof globalThis.AbortSignal<"u",_e=typeof globalThis.FormData=="function",Q=(()=>{try{return typeof globalThis.ReadableStream=="function"}catch{return!1}})(),X=(()=>{try{let t=!1,e=new Request(new URL("https://empty.invalid"),{body:new ReadableStream,method:"POST",get duplex(){return t=!0,"half"}}).headers.has("Content-Type");return t&&!e}catch{return!1}})();var E=class extends Error{constructor(e,r,o){let n=`${e.status}${e.statusText?` ${e.statusText}`:""}`;super(`Request failed with status code ${n}`),this.name="HTTPError",this.response=e,this.request=r,this.options=o,this.data=void 0}},R=class extends Error{constructor(e){super("Request timed out"),this.name="TimeoutError",this.request=e}},S=class extends Error{constructor(e,r){super("Network error",r),this.name="NetworkError",this.request=e}},k=class extends Error{constructor(e){super("Force retry"),this.name="ForceRetryError",this.customDelay=e?.delay,this.customRequest=e?.request}},D=class extends Error{constructor(e){let r=e.map(o=>o.message??"Unknown validation error").join("; ");super(`Schema validation failed: ${r}`),this.name="SchemaValidationError",this.issues=e}};var T=Symbol("neta.stop"),N=class{constructor(e){this.options=e}};function Z(t,e){let r=Number(t.headers.get("content-length"))||0,o=0,n=t.body.getReader(),i=new ReadableStream({async pull(p){let{done:y,value:d}=await n.read();if(y){e({percent:1,transferredBytes:o,totalBytes:r||o}),p.close();return}o+=d.byteLength;let g=r?o/r:0;e({percent:g,transferredBytes:o,totalBytes:r}),p.enqueue(d)},cancel(p){return n.cancel(p)}});return new Response(i,{status:t.status,statusText:t.statusText,headers:t.headers})}function ee(t,e,r){let o=Number(t.headers.get("content-length"))||0,n=0,i=t.body.getReader(),p=new ReadableStream({async pull(y){let{done:d,value:g}=await i.read();if(d){e({percent:1,transferredBytes:n,totalBytes:o||n}),y.close();return}n+=g.byteLength;let u=o?n/o:0;e({percent:u,transferredBytes:n,totalBytes:o}),y.enqueue(g)},cancel(y){return i.cancel(y)}});return new Request(t.url,{method:t.method,headers:t.headers,body:p,duplex:"half",signal:t.signal})}function xe(t){return typeof t=="number"?{..._,limit:t}:{..._,...t}}function Te(t){return{init:[...t?.init??[]],beforeRequest:[...t?.beforeRequest??[]],afterResponse:[...t?.afterResponse??[]],beforeError:[...t?.beforeError??[]],beforeRetry:[...t?.beforeRetry??[]]}}function Ee(t,e){let r=new Headers(t);return e&&new Headers(e).forEach((n,i)=>{r.set(i,n)}),r}function Se(t,e){return{init:[...t?.init??[],...e?.init??[]],beforeRequest:[...t?.beforeRequest??[],...e?.beforeRequest??[]],afterResponse:[...t?.afterResponse??[],...e?.afterResponse??[]],beforeError:[...t?.beforeError??[],...e?.beforeError??[]],beforeRetry:[...t?.beforeRetry??[],...e?.beforeRetry??[]]}}function $(t,e){if(!t)return e??{};if(!e)return t;let r={...t,...e};return(t.headers||e.headers)&&(r.headers=Ee(t.headers,e.headers)),(t.hooks||e.hooks)&&(r.hooks=Se(t.hooks,e.hooks)),r}function te(t,e){let r=t instanceof Request?t.url:String(t);if(e?.prefix){let o=String(e.prefix).replace(/\/+$/,""),n=r.replace(/^\/+/,"");r=`${o}/${n}`}if(e?.baseUrl)try{new URL(r)}catch{r=new URL(r,new Request(String(e.baseUrl)).url).href}return r}function re(t,e){if(!e)return t;if(typeof e=="string"){let o=e.replace(/^\?/,"");return o&&(t.search=t.search?`${t.search}&${o}`:`?${o}`),t}let r;if(e instanceof URLSearchParams)r=e;else if(Array.isArray(e))r=new URLSearchParams(e);else{r=new URLSearchParams;for(let[o,n]of Object.entries(e))n!==void 0&&r.set(o,String(n))}return r.forEach((o,n)=>{t.searchParams.append(n,o)}),t}function ne(t){let e={...t,method:ke(t.method??"get"),retry:xe(t.retry),timeout:t.timeout??G,totalTimeout:t.totalTimeout??!1,hooks:Te(t.hooks),throwHttpErrors:t.throwHttpErrors??!0,fetch:t.fetch??globalThis.fetch.bind(globalThis),context:t.context??{},prefix:t.prefix?String(t.prefix):""};if(t.json!==void 0){e.body=e.stringifyJson?e.stringifyJson(t.json):JSON.stringify(t.json);let r=new Headers(e.headers);r.has("content-type")||r.set("content-type","application/json"),e.headers=r}return e}function ke(t){return(t??"get").toLowerCase()}function v(t,e){return new Promise((r,o)=>{let n=e?.signal;if(n?.aborted){o(n.reason??new DOMException("Aborted","AbortError"));return}let i=setTimeout(r,t);n&&n.addEventListener("abort",()=>{clearTimeout(i),o(n.reason??new DOMException("Aborted","AbortError"))},{once:!0})})}function oe(t){let e=t.headers.get("retry-after")??t.headers.get("ratelimit-reset")??t.headers.get("x-ratelimit-retry-after")??t.headers.get("x-ratelimit-reset")??t.headers.get("x-rate-limit-reset");if(!e)return;let r=Number(e);if(!Number.isNaN(r))return r>=Date.parse("2024-01-01")/1e3?Math.max(0,r*1e3-Date.now()):r*1e3;let o=Date.parse(e);if(!Number.isNaN(o))return Math.max(0,o-Date.now())}function se(t,e){if(e===!0)return Math.random()*t;if(typeof e=="function"){let r=e(t);return Number.isFinite(r)&&r>=0?r:t}return t}function ae(t){return t instanceof TypeError&&(t.message==="Failed to fetch"||t.message==="fetch failed"||t.message==="NetworkError when attempting to fetch resource."||t.message.includes("network")||t.message.includes("ECONNREFUSED")||t.message.includes("ENOTFOUND")||t.message.includes("ETIMEDOUT")||t.message.includes("ECONNRESET"))}var ie="The `schema` argument must follow the Standard Schema specification";async function ce(t,e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError(ie);let r=e["~standard"];if(typeof r!="object"||r===null||typeof r.validate!="function")throw new TypeError(ie);let o=await r.validate(t);if(o.issues)throw new D(o.issues);return o.value}function qe(t,e){let r=new AbortController,o;return t!==!1&&typeof t=="number"&&(o=setTimeout(()=>r.abort("timeout"),t)),e&&(e.aborted?r.abort(e.reason):e.addEventListener("abort",()=>r.abort(e.reason),{once:!0})),{signal:r.signal,cleanup:()=>{o&&clearTimeout(o)}}}async function De(t,e){let{body:r}=t;if(!r)try{return await t.text()}catch{return}let o;try{o=r.getReader()}catch{return}let n=new TextDecoder,i=[],p=0,y=10*1024*1024,d=(async()=>{try{for(;;){let{done:b,value:w}=await o.read();if(b)break;if(p+=w.byteLength,p>y){o.cancel().catch(()=>{});return}i.push(n.decode(w,{stream:!0}))}}catch{return}return i.push(n.decode()),i.join("")})(),g=new Promise(b=>{let w=setTimeout(()=>b(void 0),e);d.finally(()=>clearTimeout(w))}),u=await Promise.race([d,g]);return u===void 0&&o.cancel().catch(()=>{}),u}async function Ne(t,e,r,o){let n=await De(t,e);if(!n)return;let i=(t.headers.get("content-type")??"").split(";",1)[0].trim().toLowerCase();if(!/\/(?:.*[.+-])?json$/.test(i))return n;try{return r.parseJson?await r.parseJson(n,{request:o,response:t}):JSON.parse(n)}catch{return}}function A(t){let{hooks:e,json:r,parseJson:o,stringifyJson:n,searchParams:i,timeout:p,totalTimeout:y,throwHttpErrors:d,fetch:g,context:u,_userSignal:b,prefix:w,baseUrl:U,onDownloadProgress:c,onUploadProgress:J,...I}=t;return Object.freeze(I)}function O(t,e){let r=t.delay(e),o=se(r,t.jitter);return Math.min(t.backoffLimit,o)}function ue(t,e){for(let u of e.hooks.init)u(e);let r=0,o=typeof e.totalTimeout=="number"?performance.now():void 0,n,i=()=>{if(o===void 0)return;let u=performance.now()-o;return Math.max(0,e.totalTimeout-u)},p=()=>{let u=i();return e.timeout===!1?u:u===void 0?e.timeout:Math.min(e.timeout,u)},y=()=>{let u=i();if(u!==void 0&&u<=0)throw new R(n)},d=(async()=>{if(typeof e.timeout=="number"&&e.timeout>q)throw new RangeError(`The \`timeout\` option cannot be greater than ${q}`);if(typeof e.totalTimeout=="number"&&e.totalTimeout>q)throw new RangeError(`The \`totalTimeout\` option cannot be greater than ${q}`);let u=te(t,{prefix:e.prefix,baseUrl:e.baseUrl}),b=new URL(u);b=re(b,e.searchParams);let{prefix:w,baseUrl:U,retry:c,timeout:J,totalTimeout:I,hooks:H,searchParams:Ae,json:Je,throwHttpErrors:P,fetch:le,parseJson:He,stringifyJson:Pe,context:Ce,_userSignal:Le,onDownloadProgress:C,onUploadProgress:B,...de}=e;n=new Request(b.href,{...de,method:e.method.toUpperCase()}),await Promise.resolve();for(let a of H.beforeRequest){let s=await a({request:n,options:A(e),retryCount:0});if(s instanceof Response)return s;s instanceof Request&&(n=s)}let V=e._userSignal,Y=async()=>{let a=p(),s=i();if(s!==void 0&&s<=0)throw new R(n);let l=qe(a,V),f=n.clone();B&&f.body&&X&&(f=ee(f,B,e.body));try{let h=await le(f,{signal:l.signal});return l.cleanup(),h}catch(h){throw l.cleanup(),l.signal.aborted&&l.signal.reason==="timeout"?new R(n):ae(h)?new S(n,{cause:h}):h}},L=async(a,s)=>{let l=Math.min(s,q),f={signal:V},h=i();if(h!==void 0){if(h<=0)throw new R(n);if(l>=h)throw await v(h,f),new R(n)}await v(l,f),y();for(let F of H.beforeRetry){let x=await F({request:n,options:A(e),error:a,retryCount:r+1});if(x instanceof Request){n=x;break}if(x instanceof Response)return r++,x;if(x===T)return T}return y(),r++,Y()},me=async a=>{if(r>=c.limit||!c.methods.includes(e.method))throw a;if(c.shouldRetry!==void 0){let s=await c.shouldRetry({error:a,retryCount:r+1});if(s===!1)throw a;if(s===!0)return O(c,r+1)}if(a instanceof R){if(!c.retryOnTimeout)throw a;return O(c,r+1)}if(a instanceof S)return O(c,r+1);throw a},he=async a=>{if(r>=c.limit||!c.methods.includes(e.method))throw a;if(c.shouldRetry!==void 0){let s=await c.shouldRetry({error:a,retryCount:r+1});if(s===!1)throw a;if(s===!0)return O(c,r+1)}if(!c.statusCodes.includes(a.response.status))throw a;if(c.afterStatusCodes.includes(a.response.status)){let s=oe(a.response);if(s!==void 0)return Math.min(c.maxRetryAfter,Math.max(0,s))}if(a.response.status===413)throw a;return O(c,r+1)},m;for(;;)try{m=await Y();break}catch(a){let s=await me(a),l=await L(a,s);if(l===T)return;if(l instanceof Response){m=l;break}}let j=!1;for(;;){try{for(let s of H.afterResponse){let l=m.clone(),f=await s({request:n,options:A(e),response:l,retryCount:r});if(f instanceof N)throw new k(f.options);f instanceof Response&&(m=f)}}catch(s){if(!(s instanceof k))throw s;let l=s.customDelay??O(c,r+1);s.customRequest&&(n=s.customRequest);let f=await L(s,l);if(f===T)return;if(f instanceof Response){m=f,j=!0;continue}continue}let a=typeof P=="function"?P(m.status):P;if(!m.ok&&m.type!=="opaque"&&a){let s=new E(m,n,A(e));if(s.data=await Ne(m,e.timeout===!1?1e4:e.timeout,e,n),j)throw s;let l;try{l=await he(s)}catch{let h=s;for(let F of H.beforeError){let x=await F({request:n,options:A(e),error:h,retryCount:r});x instanceof Error&&(h=x)}throw h}let f=await L(s,l);if(f===T)return;if(f instanceof Response){m=f,j=!1;continue}continue}break}if(e.parseJson&&(m.json=async()=>{let a=await m.clone().text();return a===""?JSON.parse(a):e.parseJson(a,{request:n,response:m})}),C){if(typeof C!="function")throw new TypeError("The `onDownloadProgress` option must be a function");if(!Q)throw new Error("Streams are not supported. `ReadableStream` is missing.");return Z(m,C)}return m})(),g={then:d.then.bind(d),catch:d.catch.bind(d),finally:d.finally.bind(d),[Symbol.toStringTag]:"ResponsePromise"};for(let[u,b]of Object.entries(K))g[u]=async w=>{n&&n.headers.set("accept",n.headers.get("accept")||b);let U=await d;if(u!=="json")return U[u]();let c=await U.text();if(c==="")return w!==void 0?ce(void 0,w):JSON.parse(c);let J=e.parseJson?await e.parseJson(c,{request:n,response:U}):JSON.parse(c);return w===void 0?J:ce(J,w)};return g}function z(t){let e=(r,o)=>{let n=$(t,o),i=ne(n);return i._userSignal=i.signal??void 0,ue(r,i)};for(let r of W)e[r]=(o,n)=>e(o,{...n,method:r});return e.create=r=>z($(t,r)),e.extend=e.create,e.retry=r=>new N(r),e}var fe=z(),Oe=fe;0&&(module.exports={ForceRetryError,HTTPError,NetaClient,NetaError,NetworkError,SchemaValidationError,TimeoutError,createInstance,neta,stop});
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.js","../src/constants.js","../src/errors.js","../src/types.js","../src/stream.js","../src/utils.js","../src/core.js"],"sourcesContent":["import { HTTP_METHODS } from './constants.js';\nimport { createResponsePromise } from './core.js';\nimport { RetryMarker } from './types.js';\nimport { mergeOptions, normalizeOptions } from './utils.js';\n\n/**\n * @param {import('../types/types.js').Options} [defaults]\n * @returns {import('../types/types.js').NetaInstance}\n */\nexport function createInstance(defaults) {\n const fn = (input, options) => {\n const merged = mergeOptions(defaults, options);\n const normalized = normalizeOptions(merged);\n // Stash user signal before we override it internally\n normalized._userSignal = normalized.signal ?? undefined;\n return createResponsePromise(input, normalized);\n };\n\n for (const method of HTTP_METHODS) {\n fn[method] = (input, options) => fn(input, { ...options, method });\n }\n\n fn.create = (newDefaults) => createInstance(mergeOptions(defaults, newDefaults));\n fn.extend = fn.create;\n\n /**\n * Signal forced retry from an afterResponse hook.\n * @param {{ delay?: number, request?: Request }} [options]\n * @returns {RetryMarker}\n */\n fn.retry = (options) => new RetryMarker(options);\n\n return fn;\n}\n\nconst neta = createInstance();\n\nexport default neta;\nexport { neta };\nexport { HTTPError, TimeoutError, NetworkError, ForceRetryError, SchemaValidationError } from './errors.js';\nexport { HTTPError as NetaError } from './errors.js';\nexport { createInstance as NetaClient };\nexport { stop } from './types.js';\n","/** @type {import('../types/types.js').HttpMethod[]} */\nexport const HTTP_METHODS = [\n 'get', 'post', 'put', 'patch', 'delete', 'head', 'options',\n];\n\n/** @type {import('../types/types.js').RetryOptions} */\nexport const DEFAULT_RETRY = {\n limit: 2,\n methods: ['get', 'put', 'head', 'delete', 'options'],\n statusCodes: [408, 413, 429, 500, 502, 503, 504],\n afterStatusCodes: [413, 429, 503],\n maxRetryAfter: Infinity,\n backoffLimit: Infinity,\n delay: (attemptCount) => 300 * 2 ** (attemptCount - 1),\n jitter: false,\n retryOnTimeout: false,\n shouldRetry: undefined,\n};\n\nexport const DEFAULT_TIMEOUT = 10_000;\n\nexport const maxSafeTimeout = 2_147_483_647; // 2^31 - 1\n\n/** @type {Record<string, string>} */\nexport const responseTypes = {\n json: 'application/json',\n text: 'text/*',\n formData: 'multipart/form-data',\n arrayBuffer: '*/*',\n blob: '*/*',\n bytes: '*/*',\n};\n\nexport const supportsAbortController = typeof globalThis.AbortController === 'function';\nexport const supportsAbortSignal = typeof globalThis.AbortSignal !== 'undefined';\nexport const supportsFormData = typeof globalThis.FormData === 'function';\n\nexport const supportsResponseStreams = (() => {\n try {\n return typeof globalThis.ReadableStream === 'function';\n } catch {\n return false;\n }\n})();\n\nexport const supportsRequestStreams = (() => {\n try {\n let duplexAccessed = false;\n const hasContentType = new Request(\n new URL('https://empty.invalid'),\n {\n body: new ReadableStream(),\n method: 'POST',\n get duplex() {\n duplexAccessed = true;\n return 'half';\n },\n },\n ).headers.has('Content-Type');\n return duplexAccessed && !hasContentType;\n } catch {\n return false;\n }\n})();\n","export class HTTPError extends Error {\n /**\n * @param {Response} response\n * @param {Request} request\n * @param {import('./types.js').NormalizedOptions} options\n */\n constructor(response, request, options) {\n const status = `${response.status}${response.statusText ? ` ${response.statusText}` : ''}`;\n super(`Request failed with status code ${status}`);\n this.name = 'HTTPError';\n this.response = response;\n this.request = request;\n this.options = options;\n /** @type {unknown} */\n this.data = undefined;\n }\n}\n\nexport class TimeoutError extends Error {\n /**\n * @param {Request} request\n */\n constructor(request) {\n super('Request timed out');\n this.name = 'TimeoutError';\n this.request = request;\n }\n}\n\nexport class NetworkError extends Error {\n /**\n * @param {Request} request\n * @param {{ cause?: Error }} [options]\n */\n constructor(request, options) {\n super('Network error', options);\n this.name = 'NetworkError';\n this.request = request;\n }\n}\n\nexport class ForceRetryError extends Error {\n /**\n * @param {{ delay?: number, request?: Request }} [options]\n */\n constructor(options) {\n super('Force retry');\n this.name = 'ForceRetryError';\n this.customDelay = options?.delay;\n this.customRequest = options?.request;\n }\n}\n\nexport class SchemaValidationError extends Error {\n /**\n * @param {Array<{ message?: string, path?: Array<string | number | symbol> }>} issues\n */\n constructor(issues) {\n const message = issues.map((i) => i.message ?? 'Unknown validation error').join('; ');\n super(`Schema validation failed: ${message}`);\n this.name = 'SchemaValidationError';\n this.issues = issues;\n }\n}\n","/** @type {unique symbol} */\nexport const stop = Symbol('neta.stop');\n\nexport class RetryMarker {\n /**\n * @param {{ delay?: number, request?: Request }} [options]\n */\n constructor(options) {\n this.options = options;\n }\n}\n","/**\n * @param {Response} response\n * @param {(progress: { percent: number, transferredBytes: number, totalBytes: number }) => void} onDownloadProgress\n * @returns {Response}\n */\nexport function streamResponse(response, onDownloadProgress) {\n const totalBytes = Number(response.headers.get('content-length')) || 0;\n let transferredBytes = 0;\n\n const reader = response.body.getReader();\n\n const stream = new ReadableStream({\n async pull(controller) {\n const { done, value } = await reader.read();\n if (done) {\n onDownloadProgress({\n percent: 1,\n transferredBytes,\n totalBytes: totalBytes || transferredBytes,\n });\n controller.close();\n return;\n }\n\n transferredBytes += value.byteLength;\n const percent = totalBytes ? transferredBytes / totalBytes : 0;\n onDownloadProgress({ percent, transferredBytes, totalBytes });\n controller.enqueue(value);\n },\n cancel(reason) {\n return reader.cancel(reason);\n },\n });\n\n return new Response(stream, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n}\n\n/**\n * @param {Request} request\n * @param {(progress: { percent: number, transferredBytes: number, totalBytes: number }) => void} onUploadProgress\n * @param {BodyInit} [originalBody]\n * @returns {Request}\n */\nexport function streamRequest(request, onUploadProgress, originalBody) {\n const totalBytes = Number(request.headers.get('content-length')) || 0;\n let transferredBytes = 0;\n\n const reader = request.body.getReader();\n\n const stream = new ReadableStream({\n async pull(controller) {\n const { done, value } = await reader.read();\n if (done) {\n onUploadProgress({\n percent: 1,\n transferredBytes,\n totalBytes: totalBytes || transferredBytes,\n });\n controller.close();\n return;\n }\n\n transferredBytes += value.byteLength;\n const percent = totalBytes ? transferredBytes / totalBytes : 0;\n onUploadProgress({ percent, transferredBytes, totalBytes });\n controller.enqueue(value);\n },\n cancel(reason) {\n return reader.cancel(reason);\n },\n });\n\n return new Request(request.url, {\n method: request.method,\n headers: request.headers,\n body: stream,\n duplex: 'half',\n signal: request.signal,\n });\n}\n","import { DEFAULT_RETRY, DEFAULT_TIMEOUT } from './constants.js';\n\n/**\n * @param {import('../types/types.js').Options['retry']} retry\n * @returns {import('../types/types.js').RetryOptions}\n */\nexport function normalizeRetry(retry) {\n if (typeof retry === 'number') {\n return { ...DEFAULT_RETRY, limit: retry };\n }\n return { ...DEFAULT_RETRY, ...retry };\n}\n\n/**\n * @param {import('../types/types.js').Hooks} [hooks]\n * @returns {import('../types/types.js').NormalizedHooks}\n */\nexport function normalizeHooks(hooks) {\n return {\n init: [...(hooks?.init ?? [])],\n beforeRequest: [...(hooks?.beforeRequest ?? [])],\n afterResponse: [...(hooks?.afterResponse ?? [])],\n beforeError: [...(hooks?.beforeError ?? [])],\n beforeRetry: [...(hooks?.beforeRetry ?? [])],\n };\n}\n\n/**\n * @param {HeadersInit} [target]\n * @param {HeadersInit} [source]\n * @returns {Headers}\n */\nexport function mergeHeaders(target, source) {\n const result = new Headers(target);\n if (source) {\n const sourceHeaders = new Headers(source);\n sourceHeaders.forEach((value, key) => {\n result.set(key, value);\n });\n }\n return result;\n}\n\n/**\n * Merge hooks by concatenating arrays.\n * @param {import('../types/types.js').Hooks} [base]\n * @param {import('../types/types.js').Hooks} [override]\n * @returns {import('../types/types.js').Hooks}\n */\nexport function mergeHooks(base, override) {\n return {\n init: [...(base?.init ?? []), ...(override?.init ?? [])],\n beforeRequest: [...(base?.beforeRequest ?? []), ...(override?.beforeRequest ?? [])],\n afterResponse: [...(base?.afterResponse ?? []), ...(override?.afterResponse ?? [])],\n beforeError: [...(base?.beforeError ?? []), ...(override?.beforeError ?? [])],\n beforeRetry: [...(base?.beforeRetry ?? []), ...(override?.beforeRetry ?? [])],\n };\n}\n\n/**\n * @param {import('../types/types.js').Options} [defaults]\n * @param {import('../types/types.js').Options} [overrides]\n * @returns {import('../types/types.js').Options}\n */\nexport function mergeOptions(defaults, overrides) {\n if (!defaults) return overrides ?? {};\n if (!overrides) return defaults;\n\n const merged = { ...defaults, ...overrides };\n\n if (defaults.headers || overrides.headers) {\n merged.headers = mergeHeaders(defaults.headers, overrides.headers);\n }\n\n if (defaults.hooks || overrides.hooks) {\n merged.hooks = mergeHooks(defaults.hooks, overrides.hooks);\n }\n\n return merged;\n}\n\n/**\n * @param {string | URL | Request} input\n * @param {{ prefix?: string, baseUrl?: string | URL }} [options]\n * @returns {string}\n */\nexport function resolveInput(input, options) {\n let inputStr = input instanceof Request ? input.url : String(input);\n\n if (options?.prefix) {\n const prefix = String(options.prefix).replace(/\\/+$/, '');\n const path = inputStr.replace(/^\\/+/, '');\n inputStr = `${prefix}/${path}`;\n }\n\n if (options?.baseUrl) {\n try {\n // If already absolute, keep as-is\n new URL(inputStr);\n } catch {\n // Relative — resolve against baseUrl\n inputStr = new URL(inputStr, new Request(String(options.baseUrl)).url).href;\n }\n }\n\n return inputStr;\n}\n\n/**\n * @param {URL} url\n * @param {import('../types/types.js').SearchParamsInit} [searchParams]\n * @returns {URL}\n */\nexport function appendSearchParams(url, searchParams) {\n if (!searchParams) return url;\n\n if (typeof searchParams === 'string') {\n const cleaned = searchParams.replace(/^\\?/, '');\n if (cleaned) {\n url.search = url.search ? `${url.search}&${cleaned}` : `?${cleaned}`;\n }\n return url;\n }\n\n /** @type {URLSearchParams} */\n let params;\n\n if (searchParams instanceof URLSearchParams) {\n params = searchParams;\n } else if (Array.isArray(searchParams)) {\n params = new URLSearchParams(searchParams);\n } else {\n params = new URLSearchParams();\n for (const [key, value] of Object.entries(searchParams)) {\n if (value !== undefined) {\n params.set(key, String(value));\n }\n }\n }\n\n params.forEach((value, key) => {\n url.searchParams.append(key, value);\n });\n\n return url;\n}\n\n/**\n * @param {import('../types/types.js').Options} options\n * @returns {import('../types/types.js').InternalOptions}\n */\nexport function normalizeOptions(options) {\n const normalized = {\n ...options,\n method: normalizeRequestMethod(options.method ?? 'get'),\n retry: normalizeRetry(options.retry),\n timeout: options.timeout ?? DEFAULT_TIMEOUT,\n totalTimeout: options.totalTimeout ?? false,\n hooks: normalizeHooks(options.hooks),\n throwHttpErrors: options.throwHttpErrors ?? true,\n fetch: options.fetch ?? globalThis.fetch.bind(globalThis),\n context: options.context ?? {},\n prefix: options.prefix ? String(options.prefix) : '',\n };\n\n if (options.json !== undefined) {\n normalized.body = normalized.stringifyJson\n ? normalized.stringifyJson(options.json)\n : JSON.stringify(options.json);\n const headers = new Headers(normalized.headers);\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n normalized.headers = headers;\n }\n\n return normalized;\n}\n\n/**\n * @param {string} [method]\n * @returns {string}\n */\nexport function normalizeRequestMethod(method) {\n return (method ?? 'get').toLowerCase();\n}\n\n/**\n * @param {number} ms\n * @param {{ signal?: AbortSignal }} [options]\n * @returns {Promise<void>}\n */\nexport function delay(ms, options) {\n return new Promise((resolve, reject) => {\n const signal = options?.signal;\n\n if (signal?.aborted) {\n reject(signal.reason ?? new DOMException('Aborted', 'AbortError'));\n return;\n }\n\n const timer = setTimeout(resolve, ms);\n\n if (signal) {\n signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n reject(signal.reason ?? new DOMException('Aborted', 'AbortError'));\n },\n { once: true },\n );\n }\n });\n}\n\n/**\n * Parse Retry-After from multiple common header formats.\n * @param {Response} response\n * @returns {number | undefined}\n */\nexport function parseRetryAfter(response) {\n const header =\n response.headers.get('retry-after') ??\n response.headers.get('ratelimit-reset') ??\n response.headers.get('x-ratelimit-retry-after') ??\n response.headers.get('x-ratelimit-reset') ??\n response.headers.get('x-rate-limit-reset');\n\n if (!header) return undefined;\n\n const seconds = Number(header);\n if (!Number.isNaN(seconds)) {\n // Large numbers are treated as timestamps (threshold: 2024-01-01 epoch)\n if (seconds >= Date.parse('2024-01-01') / 1000) {\n return Math.max(0, seconds * 1000 - Date.now());\n }\n return seconds * 1000;\n }\n\n const date = Date.parse(header);\n if (!Number.isNaN(date)) {\n return Math.max(0, date - Date.now());\n }\n\n return undefined;\n}\n\n/**\n * Apply jitter to a delay value.\n * @param {number} delayMs\n * @param {boolean | ((delay: number) => number)} jitter\n * @returns {number}\n */\nexport function applyJitter(delayMs, jitter) {\n if (jitter === true) {\n return Math.random() * delayMs;\n }\n if (typeof jitter === 'function') {\n const result = jitter(delayMs);\n return Number.isFinite(result) && result >= 0 ? result : delayMs;\n }\n return delayMs;\n}\n\n/**\n * Check if error is a raw network error (TypeError from fetch).\n * @param {unknown} error\n * @returns {boolean}\n */\nexport function isNetworkError(error) {\n return (\n error instanceof TypeError &&\n (error.message === 'Failed to fetch' ||\n error.message === 'fetch failed' ||\n error.message === 'NetworkError when attempting to fetch resource.' ||\n error.message.includes('network') ||\n error.message.includes('ECONNREFUSED') ||\n error.message.includes('ENOTFOUND') ||\n error.message.includes('ETIMEDOUT') ||\n error.message.includes('ECONNRESET'))\n );\n}\n","import { HTTPError, TimeoutError, NetworkError, ForceRetryError, SchemaValidationError } from './errors.js';\nimport { RetryMarker } from './types.js';\nimport { stop } from './types.js';\nimport { streamResponse, streamRequest } from './stream.js';\nimport {\n appendSearchParams,\n resolveInput,\n delay,\n isNetworkError,\n applyJitter,\n parseRetryAfter,\n} from './utils.js';\nimport {\n maxSafeTimeout,\n responseTypes,\n supportsResponseStreams,\n supportsRequestStreams,\n} from './constants.js';\n\nconst invalidSchemaMessage = 'The `schema` argument must follow the Standard Schema specification';\n\n/**\n * @param {unknown} jsonValue\n * @param {any} schema\n * @returns {Promise<unknown>}\n */\nasync function validateJsonWithSchema(jsonValue, schema) {\n if ((typeof schema !== 'object' && typeof schema !== 'function') || schema === null) {\n throw new TypeError(invalidSchemaMessage);\n }\n\n const standardSchema = schema['~standard'];\n if (\n typeof standardSchema !== 'object' ||\n standardSchema === null ||\n typeof standardSchema.validate !== 'function'\n ) {\n throw new TypeError(invalidSchemaMessage);\n }\n\n const result = await standardSchema.validate(jsonValue);\n if (result.issues) {\n throw new SchemaValidationError(result.issues);\n }\n\n return result.value;\n}\n\n/**\n * @param {number | false} timeout\n * @param {AbortSignal} [userSignal]\n * @returns {{ signal: AbortSignal, cleanup: () => void }}\n */\nfunction createManagedSignal(timeout, userSignal) {\n const controller = new AbortController();\n /** @type {ReturnType<typeof setTimeout> | undefined} */\n let timer;\n\n if (timeout !== false && typeof timeout === 'number') {\n timer = setTimeout(() => controller.abort('timeout'), timeout);\n }\n\n if (userSignal) {\n if (userSignal.aborted) {\n controller.abort(userSignal.reason);\n } else {\n userSignal.addEventListener('abort', () => controller.abort(userSignal.reason), { once: true });\n }\n }\n\n return {\n signal: controller.signal,\n cleanup: () => {\n if (timer) clearTimeout(timer);\n },\n };\n}\n\n/**\n * Read response text with timeout and size limit.\n * @param {Response} response\n * @param {number} timeoutMs\n * @returns {Promise<string | undefined>}\n */\nasync function readResponseText(response, timeoutMs) {\n const { body } = response;\n if (!body) {\n try {\n return await response.text();\n } catch {\n return undefined;\n }\n }\n\n /** @type {ReadableStreamDefaultReader<Uint8Array>} */\n let reader;\n try {\n reader = body.getReader();\n } catch {\n return undefined;\n }\n\n const decoder = new TextDecoder();\n const chunks = [];\n let totalBytes = 0;\n const maxSize = 10 * 1024 * 1024;\n\n const readAll = (async () => {\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n totalBytes += value.byteLength;\n if (totalBytes > maxSize) {\n void reader.cancel().catch(() => {});\n return undefined;\n }\n chunks.push(decoder.decode(value, { stream: true }));\n }\n } catch {\n return undefined;\n }\n chunks.push(decoder.decode());\n return chunks.join('');\n })();\n\n const timeoutPromise = new Promise((resolve) => {\n const id = setTimeout(() => resolve(undefined), timeoutMs);\n void readAll.finally(() => clearTimeout(id));\n });\n\n const result = await Promise.race([readAll, timeoutPromise]);\n if (result === undefined) void reader.cancel().catch(() => {});\n return result;\n}\n\n/**\n * @param {Response} response\n * @param {number} timeoutMs\n * @param {any} options\n * @param {Request} request\n * @returns {Promise<unknown>}\n */\nasync function getResponseData(response, timeoutMs, options, request) {\n const text = await readResponseText(response, timeoutMs);\n if (!text) return undefined;\n\n const contentType = (response.headers.get('content-type') ?? '').split(';', 1)[0].trim().toLowerCase();\n const isJson = /\\/(?:.*[.+-])?json$/.test(contentType);\n if (!isJson) return text;\n\n try {\n return options.parseJson\n ? await options.parseJson(text, { request, response })\n : JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Strip internal-only options.\n * @param {any} options\n * @returns {any}\n */\nfunction getNormalizedOptions(options) {\n const {\n hooks, json, parseJson, stringifyJson, searchParams,\n timeout, totalTimeout, throwHttpErrors, fetch,\n context, _userSignal, prefix, baseUrl,\n onDownloadProgress, onUploadProgress,\n ...rest\n } = options;\n return Object.freeze(rest);\n}\n\n/**\n * Calculate retry delay.\n * @param {any} retry\n * @param {number} retryCount\n * @returns {number}\n */\nfunction calculateDelay(retry, retryCount) {\n const base = retry.delay(retryCount);\n const jittered = applyJitter(base, retry.jitter);\n return Math.min(retry.backoffLimit, jittered);\n}\n\n/**\n * @param {string | URL | Request} input\n * @param {any} options\n * @returns {any}\n */\nexport function createResponsePromise(input, options) {\n // Run init hooks (synchronous, mutate options clone)\n for (const hook of options.hooks.init) {\n hook(options);\n }\n\n let retryCount = 0;\n const startTime = typeof options.totalTimeout === 'number' ? performance.now() : undefined;\n /** @type {Request} */\n let currentRequest;\n\n const getRemainingTotalTimeout = () => {\n if (startTime === undefined) return undefined;\n const elapsed = performance.now() - startTime;\n return Math.max(0, options.totalTimeout - elapsed);\n };\n\n const getEffectiveTimeout = () => {\n const remaining = getRemainingTotalTimeout();\n if (options.timeout === false) return remaining;\n if (remaining === undefined) return options.timeout;\n return Math.min(options.timeout, remaining);\n };\n\n const throwIfTotalTimeoutExhausted = () => {\n const remaining = getRemainingTotalTimeout();\n if (remaining !== undefined && remaining <= 0) {\n throw new TimeoutError(currentRequest);\n }\n };\n\n const innerPromise = (async () => {\n if (typeof options.timeout === 'number' && options.timeout > maxSafeTimeout) {\n throw new RangeError(`The \\`timeout\\` option cannot be greater than ${maxSafeTimeout}`);\n }\n if (typeof options.totalTimeout === 'number' && options.totalTimeout > maxSafeTimeout) {\n throw new RangeError(`The \\`totalTimeout\\` option cannot be greater than ${maxSafeTimeout}`);\n }\n\n // Resolve URL\n const inputStr = resolveInput(input, { prefix: options.prefix, baseUrl: options.baseUrl });\n let url = new URL(inputStr);\n url = appendSearchParams(url, options.searchParams);\n\n // Build request init (strip neta-specific options)\n const {\n prefix: _prefix, baseUrl: _baseUrl, retry, timeout, totalTimeout,\n hooks, searchParams, json, throwHttpErrors, fetch: fetchFn,\n parseJson, stringifyJson, context, _userSignal,\n onDownloadProgress, onUploadProgress,\n ...requestInit\n } = options;\n\n currentRequest = new Request(url.href, {\n ...requestInit,\n method: options.method.toUpperCase(),\n });\n\n // Defer so body shortcuts can set Accept header\n await Promise.resolve();\n\n // beforeRequest hooks\n for (const hook of hooks.beforeRequest) {\n const result = await hook({\n request: currentRequest,\n options: getNormalizedOptions(options),\n retryCount: 0,\n });\n\n if (result instanceof Response) return result;\n if (result instanceof Request) currentRequest = result;\n }\n\n const userSignal = options._userSignal;\n\n /**\n * Perform a single fetch attempt with timeout.\n * @returns {Promise<Response>}\n */\n const doFetch = async () => {\n const effectiveTimeout = getEffectiveTimeout();\n const remaining = getRemainingTotalTimeout();\n if (remaining !== undefined && remaining <= 0) throw new TimeoutError(currentRequest);\n\n const managed = createManagedSignal(effectiveTimeout, userSignal);\n\n let fetchRequest = currentRequest.clone();\n if (onUploadProgress && fetchRequest.body && supportsRequestStreams) {\n fetchRequest = streamRequest(fetchRequest, onUploadProgress, options.body);\n }\n\n try {\n const response = await fetchFn(fetchRequest, { signal: managed.signal });\n managed.cleanup();\n return response;\n } catch (error) {\n managed.cleanup();\n if (managed.signal.aborted && managed.signal.reason === 'timeout') {\n throw new TimeoutError(currentRequest);\n }\n if (isNetworkError(error)) {\n throw new NetworkError(currentRequest, { cause: error });\n }\n throw error;\n }\n };\n\n /**\n * Attempt retry: wait, run beforeRetry hooks, then fetch again.\n * @param {Error} error\n * @param {number} delayMs\n * @returns {Promise<Response | typeof stop>}\n */\n const attemptRetry = async (error, delayMs) => {\n const safeDelay = Math.min(delayMs, maxSafeTimeout);\n const delayOptions = { signal: userSignal };\n\n const remaining = getRemainingTotalTimeout();\n if (remaining !== undefined) {\n if (remaining <= 0) throw new TimeoutError(currentRequest);\n if (safeDelay >= remaining) {\n await delay(remaining, delayOptions);\n throw new TimeoutError(currentRequest);\n }\n }\n\n await delay(safeDelay, delayOptions);\n throwIfTotalTimeoutExhausted();\n\n // Run beforeRetry hooks\n for (const hook of hooks.beforeRetry) {\n const result = await hook({\n request: currentRequest,\n options: getNormalizedOptions(options),\n error,\n retryCount: retryCount + 1,\n });\n\n if (result instanceof Request) { currentRequest = result; break; }\n if (result instanceof Response) { retryCount++; return result; }\n if (result === stop) return stop;\n }\n\n throwIfTotalTimeoutExhausted();\n retryCount++;\n return doFetch();\n };\n\n /**\n * Check if we should retry a fetch-level error (timeout, network).\n * @param {Error} error\n * @returns {Promise<number>} delay in ms, or throws if no retry\n */\n const getRetryDelayForFetchError = async (error) => {\n if (retryCount >= retry.limit) throw error;\n if (!retry.methods.includes(options.method)) throw error;\n\n if (retry.shouldRetry !== undefined) {\n const result = await retry.shouldRetry({ error, retryCount: retryCount + 1 });\n if (result === false) throw error;\n if (result === true) return calculateDelay(retry, retryCount + 1);\n }\n\n if (error instanceof TimeoutError) {\n if (!retry.retryOnTimeout) throw error;\n return calculateDelay(retry, retryCount + 1);\n }\n\n if (error instanceof NetworkError) {\n return calculateDelay(retry, retryCount + 1);\n }\n\n throw error;\n };\n\n /**\n * Check if we should retry an HTTP error.\n * @param {HTTPError} error\n * @returns {Promise<number>} delay in ms, or throws if no retry\n */\n const getRetryDelayForHttpError = async (error) => {\n if (retryCount >= retry.limit) throw error;\n if (!retry.methods.includes(options.method)) throw error;\n\n if (retry.shouldRetry !== undefined) {\n const result = await retry.shouldRetry({ error, retryCount: retryCount + 1 });\n if (result === false) throw error;\n if (result === true) return calculateDelay(retry, retryCount + 1);\n }\n\n if (!retry.statusCodes.includes(error.response.status)) throw error;\n\n // Handle Retry-After\n if (retry.afterStatusCodes.includes(error.response.status)) {\n const retryAfter = parseRetryAfter(error.response);\n if (retryAfter !== undefined) {\n return Math.min(retry.maxRetryAfter, Math.max(0, retryAfter));\n }\n }\n\n if (error.response.status === 413) throw error;\n\n return calculateDelay(retry, retryCount + 1);\n };\n\n // === Main request loop ===\n /** @type {Response} */\n let response;\n\n // Initial fetch with fetch-error retry loop\n for (;;) {\n try {\n response = await doFetch();\n break;\n } catch (error) {\n const retryDelay = await getRetryDelayForFetchError(error);\n const retryResult = await attemptRetry(error, retryDelay);\n if (retryResult === stop) return undefined;\n if (retryResult instanceof Response) { response = retryResult; break; }\n }\n }\n\n // afterResponse hooks + HTTP error retry loop\n let responseFromHook = false;\n\n for (;;) {\n // Run afterResponse hooks\n try {\n for (const hook of hooks.afterResponse) {\n const clonedResponse = response.clone();\n const hookResult = await hook({\n request: currentRequest,\n options: getNormalizedOptions(options),\n response: clonedResponse,\n retryCount,\n });\n\n if (hookResult instanceof RetryMarker) {\n throw new ForceRetryError(hookResult.options);\n }\n\n if (hookResult instanceof Response) {\n response = hookResult;\n }\n }\n } catch (error) {\n if (!(error instanceof ForceRetryError)) throw error;\n\n // Forced retry from afterResponse hook\n const retryDelay = error.customDelay ?? calculateDelay(retry, retryCount + 1);\n if (error.customRequest) currentRequest = error.customRequest;\n const retryResult = await attemptRetry(error, retryDelay);\n if (retryResult === stop) return undefined;\n if (retryResult instanceof Response) {\n response = retryResult;\n responseFromHook = true;\n continue;\n }\n continue;\n }\n\n // Check HTTP errors\n const shouldThrow = typeof throwHttpErrors === 'function'\n ? throwHttpErrors(response.status)\n : throwHttpErrors;\n\n if (!response.ok && response.type !== 'opaque' && shouldThrow) {\n const error = new HTTPError(response, currentRequest, getNormalizedOptions(options));\n error.data = await getResponseData(\n response,\n options.timeout === false ? 10_000 : options.timeout,\n options,\n currentRequest,\n );\n\n if (responseFromHook) throw error;\n\n // Try to retry\n let retryDelay;\n try {\n retryDelay = await getRetryDelayForHttpError(error);\n } catch {\n // Run beforeError hooks, then throw\n let processedError = error;\n for (const hook of hooks.beforeError) {\n const hookResult = await hook({\n request: currentRequest,\n options: getNormalizedOptions(options),\n error: processedError,\n retryCount,\n });\n if (hookResult instanceof Error) processedError = hookResult;\n }\n throw processedError;\n }\n\n const retryResult = await attemptRetry(error, retryDelay);\n if (retryResult === stop) return undefined;\n if (retryResult instanceof Response) {\n response = retryResult;\n responseFromHook = false; // Allow further retries\n continue;\n }\n continue;\n }\n\n break;\n }\n\n // Decorate response with custom parseJson\n if (options.parseJson) {\n response.json = async () => {\n const text = await response.clone().text();\n if (text === '') return JSON.parse(text);\n return options.parseJson(text, { request: currentRequest, response });\n };\n }\n\n // Handle download progress\n if (onDownloadProgress) {\n if (typeof onDownloadProgress !== 'function') {\n throw new TypeError('The `onDownloadProgress` option must be a function');\n }\n if (!supportsResponseStreams) {\n throw new Error('Streams are not supported. `ReadableStream` is missing.');\n }\n return streamResponse(response, onDownloadProgress);\n }\n\n return response;\n })();\n\n // Build ResponsePromise thenable\n /** @type {any} */\n const responsePromise = {\n then: innerPromise.then.bind(innerPromise),\n catch: innerPromise.catch.bind(innerPromise),\n finally: innerPromise.finally.bind(innerPromise),\n [Symbol.toStringTag]: 'ResponsePromise',\n };\n\n for (const [type, mimeType] of Object.entries(responseTypes)) {\n responsePromise[type] = async (schema) => {\n if (currentRequest) {\n currentRequest.headers.set('accept', currentRequest.headers.get('accept') || mimeType);\n }\n\n const response = await innerPromise;\n if (type !== 'json') return response[type]();\n\n const text = await response.text();\n if (text === '') {\n if (schema !== undefined) return validateJsonWithSchema(undefined, schema);\n return JSON.parse(text);\n }\n\n const jsonValue = options.parseJson\n ? await options.parseJson(text, { request: currentRequest, response })\n : JSON.parse(text);\n\n return schema === undefined ? jsonValue : validateJsonWithSchema(jsonValue, schema);\n };\n }\n\n return responsePromise;\n}\n"],"mappings":"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","names":["index_exports","__export","ForceRetryError","HTTPError","createInstance","NetworkError","SchemaValidationError","TimeoutError","index_default","neta","stop","__toCommonJS","HTTP_METHODS","DEFAULT_RETRY","attemptCount","DEFAULT_TIMEOUT","maxSafeTimeout","responseTypes","supportsAbortController","supportsAbortSignal","supportsFormData","supportsResponseStreams","supportsRequestStreams","duplexAccessed","hasContentType","HTTPError","response","request","options","status","TimeoutError","NetworkError","ForceRetryError","SchemaValidationError","issues","message","i","stop","RetryMarker","options","streamResponse","response","onDownloadProgress","totalBytes","transferredBytes","reader","stream","controller","done","value","percent","reason","streamRequest","request","onUploadProgress","originalBody","normalizeRetry","retry","DEFAULT_RETRY","normalizeHooks","hooks","mergeHeaders","target","source","result","value","key","mergeHooks","base","override","mergeOptions","defaults","overrides","merged","resolveInput","input","options","inputStr","prefix","path","appendSearchParams","url","searchParams","cleaned","params","normalizeOptions","normalized","normalizeRequestMethod","DEFAULT_TIMEOUT","headers","method","delay","ms","resolve","reject","signal","timer","parseRetryAfter","response","header","seconds","date","applyJitter","delayMs","jitter","isNetworkError","error","invalidSchemaMessage","validateJsonWithSchema","jsonValue","schema","standardSchema","result","SchemaValidationError","createManagedSignal","timeout","userSignal","controller","timer","readResponseText","response","timeoutMs","body","reader","decoder","chunks","totalBytes","maxSize","readAll","done","value","timeoutPromise","resolve","id","getResponseData","options","request","text","contentType","getNormalizedOptions","hooks","json","parseJson","stringifyJson","searchParams","totalTimeout","throwHttpErrors","fetch","context","_userSignal","prefix","baseUrl","onDownloadProgress","onUploadProgress","rest","calculateDelay","retry","retryCount","base","jittered","applyJitter","createResponsePromise","input","hook","startTime","currentRequest","getRemainingTotalTimeout","elapsed","getEffectiveTimeout","remaining","throwIfTotalTimeoutExhausted","TimeoutError","innerPromise","maxSafeTimeout","inputStr","resolveInput","url","appendSearchParams","_prefix","_baseUrl","fetchFn","requestInit","doFetch","effectiveTimeout","managed","fetchRequest","supportsRequestStreams","streamRequest","error","isNetworkError","NetworkError","attemptRetry","delayMs","safeDelay","delayOptions","delay","stop","getRetryDelayForFetchError","getRetryDelayForHttpError","retryAfter","parseRetryAfter","retryDelay","retryResult","responseFromHook","clonedResponse","hookResult","RetryMarker","ForceRetryError","shouldThrow","HTTPError","processedError","supportsResponseStreams","streamResponse","responsePromise","type","mimeType","responseTypes","createInstance","defaults","fn","input","options","merged","mergeOptions","normalized","normalizeOptions","createResponsePromise","method","HTTP_METHODS","newDefaults","RetryMarker","neta","index_default"]}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ var V=["get","post","put","patch","delete","head","options"],M={limit:2,methods:["get","put","head","delete","options"],statusCodes:[408,413,429,500,502,503,504],afterStatusCodes:[413,429,503],maxRetryAfter:1/0,backoffLimit:1/0,delay:t=>300*2**(t-1),jitter:!1,retryOnTimeout:!1,shouldRetry:void 0},Y=1e4,E=2147483647,W={json:"application/json",text:"text/*",formData:"multipart/form-data",arrayBuffer:"*/*",blob:"*/*",bytes:"*/*"},Ne=typeof globalThis.AbortController=="function",Oe=typeof globalThis.AbortSignal<"u",Ue=typeof globalThis.FormData=="function",G=(()=>{try{return typeof globalThis.ReadableStream=="function"}catch{return!1}})(),K=(()=>{try{let t=!1,e=new Request(new URL("https://empty.invalid"),{body:new ReadableStream,method:"POST",get duplex(){return t=!0,"half"}}).headers.has("Content-Type");return t&&!e}catch{return!1}})();var S=class extends Error{constructor(e,r,o){let n=`${e.status}${e.statusText?` ${e.statusText}`:""}`;super(`Request failed with status code ${n}`),this.name="HTTPError",this.response=e,this.request=r,this.options=o,this.data=void 0}},b=class extends Error{constructor(e){super("Request timed out"),this.name="TimeoutError",this.request=e}},k=class extends Error{constructor(e,r){super("Network error",r),this.name="NetworkError",this.request=e}},q=class extends Error{constructor(e){super("Force retry"),this.name="ForceRetryError",this.customDelay=e?.delay,this.customRequest=e?.request}},U=class extends Error{constructor(e){let r=e.map(o=>o.message??"Unknown validation error").join("; ");super(`Schema validation failed: ${r}`),this.name="SchemaValidationError",this.issues=e}};var T=Symbol("neta.stop"),D=class{constructor(e){this.options=e}};function Q(t,e){let r=Number(t.headers.get("content-length"))||0,o=0,n=t.body.getReader(),i=new ReadableStream({async pull(p){let{done:y,value:d}=await n.read();if(y){e({percent:1,transferredBytes:o,totalBytes:r||o}),p.close();return}o+=d.byteLength;let R=r?o/r:0;e({percent:R,transferredBytes:o,totalBytes:r}),p.enqueue(d)},cancel(p){return n.cancel(p)}});return new Response(i,{status:t.status,statusText:t.statusText,headers:t.headers})}function X(t,e,r){let o=Number(t.headers.get("content-length"))||0,n=0,i=t.body.getReader(),p=new ReadableStream({async pull(y){let{done:d,value:R}=await i.read();if(d){e({percent:1,transferredBytes:n,totalBytes:o||n}),y.close();return}n+=R.byteLength;let u=o?n/o:0;e({percent:u,transferredBytes:n,totalBytes:o}),y.enqueue(R)},cancel(y){return i.cancel(y)}});return new Request(t.url,{method:t.method,headers:t.headers,body:p,duplex:"half",signal:t.signal})}function me(t){return typeof t=="number"?{...M,limit:t}:{...M,...t}}function he(t){return{init:[...t?.init??[]],beforeRequest:[...t?.beforeRequest??[]],afterResponse:[...t?.afterResponse??[]],beforeError:[...t?.beforeError??[]],beforeRetry:[...t?.beforeRetry??[]]}}function pe(t,e){let r=new Headers(t);return e&&new Headers(e).forEach((n,i)=>{r.set(i,n)}),r}function ye(t,e){return{init:[...t?.init??[],...e?.init??[]],beforeRequest:[...t?.beforeRequest??[],...e?.beforeRequest??[]],afterResponse:[...t?.afterResponse??[],...e?.afterResponse??[]],beforeError:[...t?.beforeError??[],...e?.beforeError??[]],beforeRetry:[...t?.beforeRetry??[],...e?.beforeRetry??[]]}}function _(t,e){if(!t)return e??{};if(!e)return t;let r={...t,...e};return(t.headers||e.headers)&&(r.headers=pe(t.headers,e.headers)),(t.hooks||e.hooks)&&(r.hooks=ye(t.hooks,e.hooks)),r}function Z(t,e){let r=t instanceof Request?t.url:String(t);if(e?.prefix){let o=String(e.prefix).replace(/\/+$/,""),n=r.replace(/^\/+/,"");r=`${o}/${n}`}if(e?.baseUrl)try{new URL(r)}catch{r=new URL(r,new Request(String(e.baseUrl)).url).href}return r}function ee(t,e){if(!e)return t;if(typeof e=="string"){let o=e.replace(/^\?/,"");return o&&(t.search=t.search?`${t.search}&${o}`:`?${o}`),t}let r;if(e instanceof URLSearchParams)r=e;else if(Array.isArray(e))r=new URLSearchParams(e);else{r=new URLSearchParams;for(let[o,n]of Object.entries(e))n!==void 0&&r.set(o,String(n))}return r.forEach((o,n)=>{t.searchParams.append(n,o)}),t}function te(t){let e={...t,method:we(t.method??"get"),retry:me(t.retry),timeout:t.timeout??Y,totalTimeout:t.totalTimeout??!1,hooks:he(t.hooks),throwHttpErrors:t.throwHttpErrors??!0,fetch:t.fetch??globalThis.fetch.bind(globalThis),context:t.context??{},prefix:t.prefix?String(t.prefix):""};if(t.json!==void 0){e.body=e.stringifyJson?e.stringifyJson(t.json):JSON.stringify(t.json);let r=new Headers(e.headers);r.has("content-type")||r.set("content-type","application/json"),e.headers=r}return e}function we(t){return(t??"get").toLowerCase()}function $(t,e){return new Promise((r,o)=>{let n=e?.signal;if(n?.aborted){o(n.reason??new DOMException("Aborted","AbortError"));return}let i=setTimeout(r,t);n&&n.addEventListener("abort",()=>{clearTimeout(i),o(n.reason??new DOMException("Aborted","AbortError"))},{once:!0})})}function re(t){let e=t.headers.get("retry-after")??t.headers.get("ratelimit-reset")??t.headers.get("x-ratelimit-retry-after")??t.headers.get("x-ratelimit-reset")??t.headers.get("x-rate-limit-reset");if(!e)return;let r=Number(e);if(!Number.isNaN(r))return r>=Date.parse("2024-01-01")/1e3?Math.max(0,r*1e3-Date.now()):r*1e3;let o=Date.parse(e);if(!Number.isNaN(o))return Math.max(0,o-Date.now())}function ne(t,e){if(e===!0)return Math.random()*t;if(typeof e=="function"){let r=e(t);return Number.isFinite(r)&&r>=0?r:t}return t}function oe(t){return t instanceof TypeError&&(t.message==="Failed to fetch"||t.message==="fetch failed"||t.message==="NetworkError when attempting to fetch resource."||t.message.includes("network")||t.message.includes("ECONNREFUSED")||t.message.includes("ENOTFOUND")||t.message.includes("ETIMEDOUT")||t.message.includes("ECONNRESET"))}var se="The `schema` argument must follow the Standard Schema specification";async function ae(t,e){if(typeof e!="object"&&typeof e!="function"||e===null)throw new TypeError(se);let r=e["~standard"];if(typeof r!="object"||r===null||typeof r.validate!="function")throw new TypeError(se);let o=await r.validate(t);if(o.issues)throw new U(o.issues);return o.value}function Re(t,e){let r=new AbortController,o;return t!==!1&&typeof t=="number"&&(o=setTimeout(()=>r.abort("timeout"),t)),e&&(e.aborted?r.abort(e.reason):e.addEventListener("abort",()=>r.abort(e.reason),{once:!0})),{signal:r.signal,cleanup:()=>{o&&clearTimeout(o)}}}async function ge(t,e){let{body:r}=t;if(!r)try{return await t.text()}catch{return}let o;try{o=r.getReader()}catch{return}let n=new TextDecoder,i=[],p=0,y=10*1024*1024,d=(async()=>{try{for(;;){let{done:g,value:w}=await o.read();if(g)break;if(p+=w.byteLength,p>y){o.cancel().catch(()=>{});return}i.push(n.decode(w,{stream:!0}))}}catch{return}return i.push(n.decode()),i.join("")})(),R=new Promise(g=>{let w=setTimeout(()=>g(void 0),e);d.finally(()=>clearTimeout(w))}),u=await Promise.race([d,R]);return u===void 0&&o.cancel().catch(()=>{}),u}async function be(t,e,r,o){let n=await ge(t,e);if(!n)return;let i=(t.headers.get("content-type")??"").split(";",1)[0].trim().toLowerCase();if(!/\/(?:.*[.+-])?json$/.test(i))return n;try{return r.parseJson?await r.parseJson(n,{request:o,response:t}):JSON.parse(n)}catch{return}}function A(t){let{hooks:e,json:r,parseJson:o,stringifyJson:n,searchParams:i,timeout:p,totalTimeout:y,throwHttpErrors:d,fetch:R,context:u,_userSignal:g,prefix:w,baseUrl:O,onDownloadProgress:c,onUploadProgress:J,...v}=t;return Object.freeze(v)}function N(t,e){let r=t.delay(e),o=ne(r,t.jitter);return Math.min(t.backoffLimit,o)}function ie(t,e){for(let u of e.hooks.init)u(e);let r=0,o=typeof e.totalTimeout=="number"?performance.now():void 0,n,i=()=>{if(o===void 0)return;let u=performance.now()-o;return Math.max(0,e.totalTimeout-u)},p=()=>{let u=i();return e.timeout===!1?u:u===void 0?e.timeout:Math.min(e.timeout,u)},y=()=>{let u=i();if(u!==void 0&&u<=0)throw new b(n)},d=(async()=>{if(typeof e.timeout=="number"&&e.timeout>E)throw new RangeError(`The \`timeout\` option cannot be greater than ${E}`);if(typeof e.totalTimeout=="number"&&e.totalTimeout>E)throw new RangeError(`The \`totalTimeout\` option cannot be greater than ${E}`);let u=Z(t,{prefix:e.prefix,baseUrl:e.baseUrl}),g=new URL(u);g=ee(g,e.searchParams);let{prefix:w,baseUrl:O,retry:c,timeout:J,totalTimeout:v,hooks:H,searchParams:Te,json:Ee,throwHttpErrors:P,fetch:ue,parseJson:Se,stringifyJson:ke,context:qe,_userSignal:De,onDownloadProgress:C,onUploadProgress:z,...fe}=e;n=new Request(g.href,{...fe,method:e.method.toUpperCase()}),await Promise.resolve();for(let a of H.beforeRequest){let s=await a({request:n,options:A(e),retryCount:0});if(s instanceof Response)return s;s instanceof Request&&(n=s)}let I=e._userSignal,B=async()=>{let a=p(),s=i();if(s!==void 0&&s<=0)throw new b(n);let l=Re(a,I),f=n.clone();z&&f.body&&K&&(f=X(f,z,e.body));try{let h=await ue(f,{signal:l.signal});return l.cleanup(),h}catch(h){throw l.cleanup(),l.signal.aborted&&l.signal.reason==="timeout"?new b(n):oe(h)?new k(n,{cause:h}):h}},L=async(a,s)=>{let l=Math.min(s,E),f={signal:I},h=i();if(h!==void 0){if(h<=0)throw new b(n);if(l>=h)throw await $(h,f),new b(n)}await $(l,f),y();for(let F of H.beforeRetry){let x=await F({request:n,options:A(e),error:a,retryCount:r+1});if(x instanceof Request){n=x;break}if(x instanceof Response)return r++,x;if(x===T)return T}return y(),r++,B()},le=async a=>{if(r>=c.limit||!c.methods.includes(e.method))throw a;if(c.shouldRetry!==void 0){let s=await c.shouldRetry({error:a,retryCount:r+1});if(s===!1)throw a;if(s===!0)return N(c,r+1)}if(a instanceof b){if(!c.retryOnTimeout)throw a;return N(c,r+1)}if(a instanceof k)return N(c,r+1);throw a},de=async a=>{if(r>=c.limit||!c.methods.includes(e.method))throw a;if(c.shouldRetry!==void 0){let s=await c.shouldRetry({error:a,retryCount:r+1});if(s===!1)throw a;if(s===!0)return N(c,r+1)}if(!c.statusCodes.includes(a.response.status))throw a;if(c.afterStatusCodes.includes(a.response.status)){let s=re(a.response);if(s!==void 0)return Math.min(c.maxRetryAfter,Math.max(0,s))}if(a.response.status===413)throw a;return N(c,r+1)},m;for(;;)try{m=await B();break}catch(a){let s=await le(a),l=await L(a,s);if(l===T)return;if(l instanceof Response){m=l;break}}let j=!1;for(;;){try{for(let s of H.afterResponse){let l=m.clone(),f=await s({request:n,options:A(e),response:l,retryCount:r});if(f instanceof D)throw new q(f.options);f instanceof Response&&(m=f)}}catch(s){if(!(s instanceof q))throw s;let l=s.customDelay??N(c,r+1);s.customRequest&&(n=s.customRequest);let f=await L(s,l);if(f===T)return;if(f instanceof Response){m=f,j=!0;continue}continue}let a=typeof P=="function"?P(m.status):P;if(!m.ok&&m.type!=="opaque"&&a){let s=new S(m,n,A(e));if(s.data=await be(m,e.timeout===!1?1e4:e.timeout,e,n),j)throw s;let l;try{l=await de(s)}catch{let h=s;for(let F of H.beforeError){let x=await F({request:n,options:A(e),error:h,retryCount:r});x instanceof Error&&(h=x)}throw h}let f=await L(s,l);if(f===T)return;if(f instanceof Response){m=f,j=!1;continue}continue}break}if(e.parseJson&&(m.json=async()=>{let a=await m.clone().text();return a===""?JSON.parse(a):e.parseJson(a,{request:n,response:m})}),C){if(typeof C!="function")throw new TypeError("The `onDownloadProgress` option must be a function");if(!G)throw new Error("Streams are not supported. `ReadableStream` is missing.");return Q(m,C)}return m})(),R={then:d.then.bind(d),catch:d.catch.bind(d),finally:d.finally.bind(d),[Symbol.toStringTag]:"ResponsePromise"};for(let[u,g]of Object.entries(W))R[u]=async w=>{n&&n.headers.set("accept",n.headers.get("accept")||g);let O=await d;if(u!=="json")return O[u]();let c=await O.text();if(c==="")return w!==void 0?ae(void 0,w):JSON.parse(c);let J=e.parseJson?await e.parseJson(c,{request:n,response:O}):JSON.parse(c);return w===void 0?J:ae(J,w)};return R}function ce(t){let e=(r,o)=>{let n=_(t,o),i=te(n);return i._userSignal=i.signal??void 0,ie(r,i)};for(let r of V)e[r]=(o,n)=>e(o,{...n,method:r});return e.create=r=>ce(_(t,r)),e.extend=e.create,e.retry=r=>new D(r),e}var xe=ce(),We=xe;export{q as ForceRetryError,S as HTTPError,ce as NetaClient,S as NetaError,k as NetworkError,U as SchemaValidationError,b as TimeoutError,ce as createInstance,We as default,xe as neta,T as stop};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants.js","../src/errors.js","../src/types.js","../src/stream.js","../src/utils.js","../src/core.js","../src/index.js"],"sourcesContent":["/** @type {import('../types/types.js').HttpMethod[]} */\nexport const HTTP_METHODS = [\n 'get', 'post', 'put', 'patch', 'delete', 'head', 'options',\n];\n\n/** @type {import('../types/types.js').RetryOptions} */\nexport const DEFAULT_RETRY = {\n limit: 2,\n methods: ['get', 'put', 'head', 'delete', 'options'],\n statusCodes: [408, 413, 429, 500, 502, 503, 504],\n afterStatusCodes: [413, 429, 503],\n maxRetryAfter: Infinity,\n backoffLimit: Infinity,\n delay: (attemptCount) => 300 * 2 ** (attemptCount - 1),\n jitter: false,\n retryOnTimeout: false,\n shouldRetry: undefined,\n};\n\nexport const DEFAULT_TIMEOUT = 10_000;\n\nexport const maxSafeTimeout = 2_147_483_647; // 2^31 - 1\n\n/** @type {Record<string, string>} */\nexport const responseTypes = {\n json: 'application/json',\n text: 'text/*',\n formData: 'multipart/form-data',\n arrayBuffer: '*/*',\n blob: '*/*',\n bytes: '*/*',\n};\n\nexport const supportsAbortController = typeof globalThis.AbortController === 'function';\nexport const supportsAbortSignal = typeof globalThis.AbortSignal !== 'undefined';\nexport const supportsFormData = typeof globalThis.FormData === 'function';\n\nexport const supportsResponseStreams = (() => {\n try {\n return typeof globalThis.ReadableStream === 'function';\n } catch {\n return false;\n }\n})();\n\nexport const supportsRequestStreams = (() => {\n try {\n let duplexAccessed = false;\n const hasContentType = new Request(\n new URL('https://empty.invalid'),\n {\n body: new ReadableStream(),\n method: 'POST',\n get duplex() {\n duplexAccessed = true;\n return 'half';\n },\n },\n ).headers.has('Content-Type');\n return duplexAccessed && !hasContentType;\n } catch {\n return false;\n }\n})();\n","export class HTTPError extends Error {\n /**\n * @param {Response} response\n * @param {Request} request\n * @param {import('./types.js').NormalizedOptions} options\n */\n constructor(response, request, options) {\n const status = `${response.status}${response.statusText ? ` ${response.statusText}` : ''}`;\n super(`Request failed with status code ${status}`);\n this.name = 'HTTPError';\n this.response = response;\n this.request = request;\n this.options = options;\n /** @type {unknown} */\n this.data = undefined;\n }\n}\n\nexport class TimeoutError extends Error {\n /**\n * @param {Request} request\n */\n constructor(request) {\n super('Request timed out');\n this.name = 'TimeoutError';\n this.request = request;\n }\n}\n\nexport class NetworkError extends Error {\n /**\n * @param {Request} request\n * @param {{ cause?: Error }} [options]\n */\n constructor(request, options) {\n super('Network error', options);\n this.name = 'NetworkError';\n this.request = request;\n }\n}\n\nexport class ForceRetryError extends Error {\n /**\n * @param {{ delay?: number, request?: Request }} [options]\n */\n constructor(options) {\n super('Force retry');\n this.name = 'ForceRetryError';\n this.customDelay = options?.delay;\n this.customRequest = options?.request;\n }\n}\n\nexport class SchemaValidationError extends Error {\n /**\n * @param {Array<{ message?: string, path?: Array<string | number | symbol> }>} issues\n */\n constructor(issues) {\n const message = issues.map((i) => i.message ?? 'Unknown validation error').join('; ');\n super(`Schema validation failed: ${message}`);\n this.name = 'SchemaValidationError';\n this.issues = issues;\n }\n}\n","/** @type {unique symbol} */\nexport const stop = Symbol('neta.stop');\n\nexport class RetryMarker {\n /**\n * @param {{ delay?: number, request?: Request }} [options]\n */\n constructor(options) {\n this.options = options;\n }\n}\n","/**\n * @param {Response} response\n * @param {(progress: { percent: number, transferredBytes: number, totalBytes: number }) => void} onDownloadProgress\n * @returns {Response}\n */\nexport function streamResponse(response, onDownloadProgress) {\n const totalBytes = Number(response.headers.get('content-length')) || 0;\n let transferredBytes = 0;\n\n const reader = response.body.getReader();\n\n const stream = new ReadableStream({\n async pull(controller) {\n const { done, value } = await reader.read();\n if (done) {\n onDownloadProgress({\n percent: 1,\n transferredBytes,\n totalBytes: totalBytes || transferredBytes,\n });\n controller.close();\n return;\n }\n\n transferredBytes += value.byteLength;\n const percent = totalBytes ? transferredBytes / totalBytes : 0;\n onDownloadProgress({ percent, transferredBytes, totalBytes });\n controller.enqueue(value);\n },\n cancel(reason) {\n return reader.cancel(reason);\n },\n });\n\n return new Response(stream, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n}\n\n/**\n * @param {Request} request\n * @param {(progress: { percent: number, transferredBytes: number, totalBytes: number }) => void} onUploadProgress\n * @param {BodyInit} [originalBody]\n * @returns {Request}\n */\nexport function streamRequest(request, onUploadProgress, originalBody) {\n const totalBytes = Number(request.headers.get('content-length')) || 0;\n let transferredBytes = 0;\n\n const reader = request.body.getReader();\n\n const stream = new ReadableStream({\n async pull(controller) {\n const { done, value } = await reader.read();\n if (done) {\n onUploadProgress({\n percent: 1,\n transferredBytes,\n totalBytes: totalBytes || transferredBytes,\n });\n controller.close();\n return;\n }\n\n transferredBytes += value.byteLength;\n const percent = totalBytes ? transferredBytes / totalBytes : 0;\n onUploadProgress({ percent, transferredBytes, totalBytes });\n controller.enqueue(value);\n },\n cancel(reason) {\n return reader.cancel(reason);\n },\n });\n\n return new Request(request.url, {\n method: request.method,\n headers: request.headers,\n body: stream,\n duplex: 'half',\n signal: request.signal,\n });\n}\n","import { DEFAULT_RETRY, DEFAULT_TIMEOUT } from './constants.js';\n\n/**\n * @param {import('../types/types.js').Options['retry']} retry\n * @returns {import('../types/types.js').RetryOptions}\n */\nexport function normalizeRetry(retry) {\n if (typeof retry === 'number') {\n return { ...DEFAULT_RETRY, limit: retry };\n }\n return { ...DEFAULT_RETRY, ...retry };\n}\n\n/**\n * @param {import('../types/types.js').Hooks} [hooks]\n * @returns {import('../types/types.js').NormalizedHooks}\n */\nexport function normalizeHooks(hooks) {\n return {\n init: [...(hooks?.init ?? [])],\n beforeRequest: [...(hooks?.beforeRequest ?? [])],\n afterResponse: [...(hooks?.afterResponse ?? [])],\n beforeError: [...(hooks?.beforeError ?? [])],\n beforeRetry: [...(hooks?.beforeRetry ?? [])],\n };\n}\n\n/**\n * @param {HeadersInit} [target]\n * @param {HeadersInit} [source]\n * @returns {Headers}\n */\nexport function mergeHeaders(target, source) {\n const result = new Headers(target);\n if (source) {\n const sourceHeaders = new Headers(source);\n sourceHeaders.forEach((value, key) => {\n result.set(key, value);\n });\n }\n return result;\n}\n\n/**\n * Merge hooks by concatenating arrays.\n * @param {import('../types/types.js').Hooks} [base]\n * @param {import('../types/types.js').Hooks} [override]\n * @returns {import('../types/types.js').Hooks}\n */\nexport function mergeHooks(base, override) {\n return {\n init: [...(base?.init ?? []), ...(override?.init ?? [])],\n beforeRequest: [...(base?.beforeRequest ?? []), ...(override?.beforeRequest ?? [])],\n afterResponse: [...(base?.afterResponse ?? []), ...(override?.afterResponse ?? [])],\n beforeError: [...(base?.beforeError ?? []), ...(override?.beforeError ?? [])],\n beforeRetry: [...(base?.beforeRetry ?? []), ...(override?.beforeRetry ?? [])],\n };\n}\n\n/**\n * @param {import('../types/types.js').Options} [defaults]\n * @param {import('../types/types.js').Options} [overrides]\n * @returns {import('../types/types.js').Options}\n */\nexport function mergeOptions(defaults, overrides) {\n if (!defaults) return overrides ?? {};\n if (!overrides) return defaults;\n\n const merged = { ...defaults, ...overrides };\n\n if (defaults.headers || overrides.headers) {\n merged.headers = mergeHeaders(defaults.headers, overrides.headers);\n }\n\n if (defaults.hooks || overrides.hooks) {\n merged.hooks = mergeHooks(defaults.hooks, overrides.hooks);\n }\n\n return merged;\n}\n\n/**\n * @param {string | URL | Request} input\n * @param {{ prefix?: string, baseUrl?: string | URL }} [options]\n * @returns {string}\n */\nexport function resolveInput(input, options) {\n let inputStr = input instanceof Request ? input.url : String(input);\n\n if (options?.prefix) {\n const prefix = String(options.prefix).replace(/\\/+$/, '');\n const path = inputStr.replace(/^\\/+/, '');\n inputStr = `${prefix}/${path}`;\n }\n\n if (options?.baseUrl) {\n try {\n // If already absolute, keep as-is\n new URL(inputStr);\n } catch {\n // Relative — resolve against baseUrl\n inputStr = new URL(inputStr, new Request(String(options.baseUrl)).url).href;\n }\n }\n\n return inputStr;\n}\n\n/**\n * @param {URL} url\n * @param {import('../types/types.js').SearchParamsInit} [searchParams]\n * @returns {URL}\n */\nexport function appendSearchParams(url, searchParams) {\n if (!searchParams) return url;\n\n if (typeof searchParams === 'string') {\n const cleaned = searchParams.replace(/^\\?/, '');\n if (cleaned) {\n url.search = url.search ? `${url.search}&${cleaned}` : `?${cleaned}`;\n }\n return url;\n }\n\n /** @type {URLSearchParams} */\n let params;\n\n if (searchParams instanceof URLSearchParams) {\n params = searchParams;\n } else if (Array.isArray(searchParams)) {\n params = new URLSearchParams(searchParams);\n } else {\n params = new URLSearchParams();\n for (const [key, value] of Object.entries(searchParams)) {\n if (value !== undefined) {\n params.set(key, String(value));\n }\n }\n }\n\n params.forEach((value, key) => {\n url.searchParams.append(key, value);\n });\n\n return url;\n}\n\n/**\n * @param {import('../types/types.js').Options} options\n * @returns {import('../types/types.js').InternalOptions}\n */\nexport function normalizeOptions(options) {\n const normalized = {\n ...options,\n method: normalizeRequestMethod(options.method ?? 'get'),\n retry: normalizeRetry(options.retry),\n timeout: options.timeout ?? DEFAULT_TIMEOUT,\n totalTimeout: options.totalTimeout ?? false,\n hooks: normalizeHooks(options.hooks),\n throwHttpErrors: options.throwHttpErrors ?? true,\n fetch: options.fetch ?? globalThis.fetch.bind(globalThis),\n context: options.context ?? {},\n prefix: options.prefix ? String(options.prefix) : '',\n };\n\n if (options.json !== undefined) {\n normalized.body = normalized.stringifyJson\n ? normalized.stringifyJson(options.json)\n : JSON.stringify(options.json);\n const headers = new Headers(normalized.headers);\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json');\n }\n normalized.headers = headers;\n }\n\n return normalized;\n}\n\n/**\n * @param {string} [method]\n * @returns {string}\n */\nexport function normalizeRequestMethod(method) {\n return (method ?? 'get').toLowerCase();\n}\n\n/**\n * @param {number} ms\n * @param {{ signal?: AbortSignal }} [options]\n * @returns {Promise<void>}\n */\nexport function delay(ms, options) {\n return new Promise((resolve, reject) => {\n const signal = options?.signal;\n\n if (signal?.aborted) {\n reject(signal.reason ?? new DOMException('Aborted', 'AbortError'));\n return;\n }\n\n const timer = setTimeout(resolve, ms);\n\n if (signal) {\n signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n reject(signal.reason ?? new DOMException('Aborted', 'AbortError'));\n },\n { once: true },\n );\n }\n });\n}\n\n/**\n * Parse Retry-After from multiple common header formats.\n * @param {Response} response\n * @returns {number | undefined}\n */\nexport function parseRetryAfter(response) {\n const header =\n response.headers.get('retry-after') ??\n response.headers.get('ratelimit-reset') ??\n response.headers.get('x-ratelimit-retry-after') ??\n response.headers.get('x-ratelimit-reset') ??\n response.headers.get('x-rate-limit-reset');\n\n if (!header) return undefined;\n\n const seconds = Number(header);\n if (!Number.isNaN(seconds)) {\n // Large numbers are treated as timestamps (threshold: 2024-01-01 epoch)\n if (seconds >= Date.parse('2024-01-01') / 1000) {\n return Math.max(0, seconds * 1000 - Date.now());\n }\n return seconds * 1000;\n }\n\n const date = Date.parse(header);\n if (!Number.isNaN(date)) {\n return Math.max(0, date - Date.now());\n }\n\n return undefined;\n}\n\n/**\n * Apply jitter to a delay value.\n * @param {number} delayMs\n * @param {boolean | ((delay: number) => number)} jitter\n * @returns {number}\n */\nexport function applyJitter(delayMs, jitter) {\n if (jitter === true) {\n return Math.random() * delayMs;\n }\n if (typeof jitter === 'function') {\n const result = jitter(delayMs);\n return Number.isFinite(result) && result >= 0 ? result : delayMs;\n }\n return delayMs;\n}\n\n/**\n * Check if error is a raw network error (TypeError from fetch).\n * @param {unknown} error\n * @returns {boolean}\n */\nexport function isNetworkError(error) {\n return (\n error instanceof TypeError &&\n (error.message === 'Failed to fetch' ||\n error.message === 'fetch failed' ||\n error.message === 'NetworkError when attempting to fetch resource.' ||\n error.message.includes('network') ||\n error.message.includes('ECONNREFUSED') ||\n error.message.includes('ENOTFOUND') ||\n error.message.includes('ETIMEDOUT') ||\n error.message.includes('ECONNRESET'))\n );\n}\n","import { HTTPError, TimeoutError, NetworkError, ForceRetryError, SchemaValidationError } from './errors.js';\nimport { RetryMarker } from './types.js';\nimport { stop } from './types.js';\nimport { streamResponse, streamRequest } from './stream.js';\nimport {\n appendSearchParams,\n resolveInput,\n delay,\n isNetworkError,\n applyJitter,\n parseRetryAfter,\n} from './utils.js';\nimport {\n maxSafeTimeout,\n responseTypes,\n supportsResponseStreams,\n supportsRequestStreams,\n} from './constants.js';\n\nconst invalidSchemaMessage = 'The `schema` argument must follow the Standard Schema specification';\n\n/**\n * @param {unknown} jsonValue\n * @param {any} schema\n * @returns {Promise<unknown>}\n */\nasync function validateJsonWithSchema(jsonValue, schema) {\n if ((typeof schema !== 'object' && typeof schema !== 'function') || schema === null) {\n throw new TypeError(invalidSchemaMessage);\n }\n\n const standardSchema = schema['~standard'];\n if (\n typeof standardSchema !== 'object' ||\n standardSchema === null ||\n typeof standardSchema.validate !== 'function'\n ) {\n throw new TypeError(invalidSchemaMessage);\n }\n\n const result = await standardSchema.validate(jsonValue);\n if (result.issues) {\n throw new SchemaValidationError(result.issues);\n }\n\n return result.value;\n}\n\n/**\n * @param {number | false} timeout\n * @param {AbortSignal} [userSignal]\n * @returns {{ signal: AbortSignal, cleanup: () => void }}\n */\nfunction createManagedSignal(timeout, userSignal) {\n const controller = new AbortController();\n /** @type {ReturnType<typeof setTimeout> | undefined} */\n let timer;\n\n if (timeout !== false && typeof timeout === 'number') {\n timer = setTimeout(() => controller.abort('timeout'), timeout);\n }\n\n if (userSignal) {\n if (userSignal.aborted) {\n controller.abort(userSignal.reason);\n } else {\n userSignal.addEventListener('abort', () => controller.abort(userSignal.reason), { once: true });\n }\n }\n\n return {\n signal: controller.signal,\n cleanup: () => {\n if (timer) clearTimeout(timer);\n },\n };\n}\n\n/**\n * Read response text with timeout and size limit.\n * @param {Response} response\n * @param {number} timeoutMs\n * @returns {Promise<string | undefined>}\n */\nasync function readResponseText(response, timeoutMs) {\n const { body } = response;\n if (!body) {\n try {\n return await response.text();\n } catch {\n return undefined;\n }\n }\n\n /** @type {ReadableStreamDefaultReader<Uint8Array>} */\n let reader;\n try {\n reader = body.getReader();\n } catch {\n return undefined;\n }\n\n const decoder = new TextDecoder();\n const chunks = [];\n let totalBytes = 0;\n const maxSize = 10 * 1024 * 1024;\n\n const readAll = (async () => {\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n totalBytes += value.byteLength;\n if (totalBytes > maxSize) {\n void reader.cancel().catch(() => {});\n return undefined;\n }\n chunks.push(decoder.decode(value, { stream: true }));\n }\n } catch {\n return undefined;\n }\n chunks.push(decoder.decode());\n return chunks.join('');\n })();\n\n const timeoutPromise = new Promise((resolve) => {\n const id = setTimeout(() => resolve(undefined), timeoutMs);\n void readAll.finally(() => clearTimeout(id));\n });\n\n const result = await Promise.race([readAll, timeoutPromise]);\n if (result === undefined) void reader.cancel().catch(() => {});\n return result;\n}\n\n/**\n * @param {Response} response\n * @param {number} timeoutMs\n * @param {any} options\n * @param {Request} request\n * @returns {Promise<unknown>}\n */\nasync function getResponseData(response, timeoutMs, options, request) {\n const text = await readResponseText(response, timeoutMs);\n if (!text) return undefined;\n\n const contentType = (response.headers.get('content-type') ?? '').split(';', 1)[0].trim().toLowerCase();\n const isJson = /\\/(?:.*[.+-])?json$/.test(contentType);\n if (!isJson) return text;\n\n try {\n return options.parseJson\n ? await options.parseJson(text, { request, response })\n : JSON.parse(text);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Strip internal-only options.\n * @param {any} options\n * @returns {any}\n */\nfunction getNormalizedOptions(options) {\n const {\n hooks, json, parseJson, stringifyJson, searchParams,\n timeout, totalTimeout, throwHttpErrors, fetch,\n context, _userSignal, prefix, baseUrl,\n onDownloadProgress, onUploadProgress,\n ...rest\n } = options;\n return Object.freeze(rest);\n}\n\n/**\n * Calculate retry delay.\n * @param {any} retry\n * @param {number} retryCount\n * @returns {number}\n */\nfunction calculateDelay(retry, retryCount) {\n const base = retry.delay(retryCount);\n const jittered = applyJitter(base, retry.jitter);\n return Math.min(retry.backoffLimit, jittered);\n}\n\n/**\n * @param {string | URL | Request} input\n * @param {any} options\n * @returns {any}\n */\nexport function createResponsePromise(input, options) {\n // Run init hooks (synchronous, mutate options clone)\n for (const hook of options.hooks.init) {\n hook(options);\n }\n\n let retryCount = 0;\n const startTime = typeof options.totalTimeout === 'number' ? performance.now() : undefined;\n /** @type {Request} */\n let currentRequest;\n\n const getRemainingTotalTimeout = () => {\n if (startTime === undefined) return undefined;\n const elapsed = performance.now() - startTime;\n return Math.max(0, options.totalTimeout - elapsed);\n };\n\n const getEffectiveTimeout = () => {\n const remaining = getRemainingTotalTimeout();\n if (options.timeout === false) return remaining;\n if (remaining === undefined) return options.timeout;\n return Math.min(options.timeout, remaining);\n };\n\n const throwIfTotalTimeoutExhausted = () => {\n const remaining = getRemainingTotalTimeout();\n if (remaining !== undefined && remaining <= 0) {\n throw new TimeoutError(currentRequest);\n }\n };\n\n const innerPromise = (async () => {\n if (typeof options.timeout === 'number' && options.timeout > maxSafeTimeout) {\n throw new RangeError(`The \\`timeout\\` option cannot be greater than ${maxSafeTimeout}`);\n }\n if (typeof options.totalTimeout === 'number' && options.totalTimeout > maxSafeTimeout) {\n throw new RangeError(`The \\`totalTimeout\\` option cannot be greater than ${maxSafeTimeout}`);\n }\n\n // Resolve URL\n const inputStr = resolveInput(input, { prefix: options.prefix, baseUrl: options.baseUrl });\n let url = new URL(inputStr);\n url = appendSearchParams(url, options.searchParams);\n\n // Build request init (strip neta-specific options)\n const {\n prefix: _prefix, baseUrl: _baseUrl, retry, timeout, totalTimeout,\n hooks, searchParams, json, throwHttpErrors, fetch: fetchFn,\n parseJson, stringifyJson, context, _userSignal,\n onDownloadProgress, onUploadProgress,\n ...requestInit\n } = options;\n\n currentRequest = new Request(url.href, {\n ...requestInit,\n method: options.method.toUpperCase(),\n });\n\n // Defer so body shortcuts can set Accept header\n await Promise.resolve();\n\n // beforeRequest hooks\n for (const hook of hooks.beforeRequest) {\n const result = await hook({\n request: currentRequest,\n options: getNormalizedOptions(options),\n retryCount: 0,\n });\n\n if (result instanceof Response) return result;\n if (result instanceof Request) currentRequest = result;\n }\n\n const userSignal = options._userSignal;\n\n /**\n * Perform a single fetch attempt with timeout.\n * @returns {Promise<Response>}\n */\n const doFetch = async () => {\n const effectiveTimeout = getEffectiveTimeout();\n const remaining = getRemainingTotalTimeout();\n if (remaining !== undefined && remaining <= 0) throw new TimeoutError(currentRequest);\n\n const managed = createManagedSignal(effectiveTimeout, userSignal);\n\n let fetchRequest = currentRequest.clone();\n if (onUploadProgress && fetchRequest.body && supportsRequestStreams) {\n fetchRequest = streamRequest(fetchRequest, onUploadProgress, options.body);\n }\n\n try {\n const response = await fetchFn(fetchRequest, { signal: managed.signal });\n managed.cleanup();\n return response;\n } catch (error) {\n managed.cleanup();\n if (managed.signal.aborted && managed.signal.reason === 'timeout') {\n throw new TimeoutError(currentRequest);\n }\n if (isNetworkError(error)) {\n throw new NetworkError(currentRequest, { cause: error });\n }\n throw error;\n }\n };\n\n /**\n * Attempt retry: wait, run beforeRetry hooks, then fetch again.\n * @param {Error} error\n * @param {number} delayMs\n * @returns {Promise<Response | typeof stop>}\n */\n const attemptRetry = async (error, delayMs) => {\n const safeDelay = Math.min(delayMs, maxSafeTimeout);\n const delayOptions = { signal: userSignal };\n\n const remaining = getRemainingTotalTimeout();\n if (remaining !== undefined) {\n if (remaining <= 0) throw new TimeoutError(currentRequest);\n if (safeDelay >= remaining) {\n await delay(remaining, delayOptions);\n throw new TimeoutError(currentRequest);\n }\n }\n\n await delay(safeDelay, delayOptions);\n throwIfTotalTimeoutExhausted();\n\n // Run beforeRetry hooks\n for (const hook of hooks.beforeRetry) {\n const result = await hook({\n request: currentRequest,\n options: getNormalizedOptions(options),\n error,\n retryCount: retryCount + 1,\n });\n\n if (result instanceof Request) { currentRequest = result; break; }\n if (result instanceof Response) { retryCount++; return result; }\n if (result === stop) return stop;\n }\n\n throwIfTotalTimeoutExhausted();\n retryCount++;\n return doFetch();\n };\n\n /**\n * Check if we should retry a fetch-level error (timeout, network).\n * @param {Error} error\n * @returns {Promise<number>} delay in ms, or throws if no retry\n */\n const getRetryDelayForFetchError = async (error) => {\n if (retryCount >= retry.limit) throw error;\n if (!retry.methods.includes(options.method)) throw error;\n\n if (retry.shouldRetry !== undefined) {\n const result = await retry.shouldRetry({ error, retryCount: retryCount + 1 });\n if (result === false) throw error;\n if (result === true) return calculateDelay(retry, retryCount + 1);\n }\n\n if (error instanceof TimeoutError) {\n if (!retry.retryOnTimeout) throw error;\n return calculateDelay(retry, retryCount + 1);\n }\n\n if (error instanceof NetworkError) {\n return calculateDelay(retry, retryCount + 1);\n }\n\n throw error;\n };\n\n /**\n * Check if we should retry an HTTP error.\n * @param {HTTPError} error\n * @returns {Promise<number>} delay in ms, or throws if no retry\n */\n const getRetryDelayForHttpError = async (error) => {\n if (retryCount >= retry.limit) throw error;\n if (!retry.methods.includes(options.method)) throw error;\n\n if (retry.shouldRetry !== undefined) {\n const result = await retry.shouldRetry({ error, retryCount: retryCount + 1 });\n if (result === false) throw error;\n if (result === true) return calculateDelay(retry, retryCount + 1);\n }\n\n if (!retry.statusCodes.includes(error.response.status)) throw error;\n\n // Handle Retry-After\n if (retry.afterStatusCodes.includes(error.response.status)) {\n const retryAfter = parseRetryAfter(error.response);\n if (retryAfter !== undefined) {\n return Math.min(retry.maxRetryAfter, Math.max(0, retryAfter));\n }\n }\n\n if (error.response.status === 413) throw error;\n\n return calculateDelay(retry, retryCount + 1);\n };\n\n // === Main request loop ===\n /** @type {Response} */\n let response;\n\n // Initial fetch with fetch-error retry loop\n for (;;) {\n try {\n response = await doFetch();\n break;\n } catch (error) {\n const retryDelay = await getRetryDelayForFetchError(error);\n const retryResult = await attemptRetry(error, retryDelay);\n if (retryResult === stop) return undefined;\n if (retryResult instanceof Response) { response = retryResult; break; }\n }\n }\n\n // afterResponse hooks + HTTP error retry loop\n let responseFromHook = false;\n\n for (;;) {\n // Run afterResponse hooks\n try {\n for (const hook of hooks.afterResponse) {\n const clonedResponse = response.clone();\n const hookResult = await hook({\n request: currentRequest,\n options: getNormalizedOptions(options),\n response: clonedResponse,\n retryCount,\n });\n\n if (hookResult instanceof RetryMarker) {\n throw new ForceRetryError(hookResult.options);\n }\n\n if (hookResult instanceof Response) {\n response = hookResult;\n }\n }\n } catch (error) {\n if (!(error instanceof ForceRetryError)) throw error;\n\n // Forced retry from afterResponse hook\n const retryDelay = error.customDelay ?? calculateDelay(retry, retryCount + 1);\n if (error.customRequest) currentRequest = error.customRequest;\n const retryResult = await attemptRetry(error, retryDelay);\n if (retryResult === stop) return undefined;\n if (retryResult instanceof Response) {\n response = retryResult;\n responseFromHook = true;\n continue;\n }\n continue;\n }\n\n // Check HTTP errors\n const shouldThrow = typeof throwHttpErrors === 'function'\n ? throwHttpErrors(response.status)\n : throwHttpErrors;\n\n if (!response.ok && response.type !== 'opaque' && shouldThrow) {\n const error = new HTTPError(response, currentRequest, getNormalizedOptions(options));\n error.data = await getResponseData(\n response,\n options.timeout === false ? 10_000 : options.timeout,\n options,\n currentRequest,\n );\n\n if (responseFromHook) throw error;\n\n // Try to retry\n let retryDelay;\n try {\n retryDelay = await getRetryDelayForHttpError(error);\n } catch {\n // Run beforeError hooks, then throw\n let processedError = error;\n for (const hook of hooks.beforeError) {\n const hookResult = await hook({\n request: currentRequest,\n options: getNormalizedOptions(options),\n error: processedError,\n retryCount,\n });\n if (hookResult instanceof Error) processedError = hookResult;\n }\n throw processedError;\n }\n\n const retryResult = await attemptRetry(error, retryDelay);\n if (retryResult === stop) return undefined;\n if (retryResult instanceof Response) {\n response = retryResult;\n responseFromHook = false; // Allow further retries\n continue;\n }\n continue;\n }\n\n break;\n }\n\n // Decorate response with custom parseJson\n if (options.parseJson) {\n response.json = async () => {\n const text = await response.clone().text();\n if (text === '') return JSON.parse(text);\n return options.parseJson(text, { request: currentRequest, response });\n };\n }\n\n // Handle download progress\n if (onDownloadProgress) {\n if (typeof onDownloadProgress !== 'function') {\n throw new TypeError('The `onDownloadProgress` option must be a function');\n }\n if (!supportsResponseStreams) {\n throw new Error('Streams are not supported. `ReadableStream` is missing.');\n }\n return streamResponse(response, onDownloadProgress);\n }\n\n return response;\n })();\n\n // Build ResponsePromise thenable\n /** @type {any} */\n const responsePromise = {\n then: innerPromise.then.bind(innerPromise),\n catch: innerPromise.catch.bind(innerPromise),\n finally: innerPromise.finally.bind(innerPromise),\n [Symbol.toStringTag]: 'ResponsePromise',\n };\n\n for (const [type, mimeType] of Object.entries(responseTypes)) {\n responsePromise[type] = async (schema) => {\n if (currentRequest) {\n currentRequest.headers.set('accept', currentRequest.headers.get('accept') || mimeType);\n }\n\n const response = await innerPromise;\n if (type !== 'json') return response[type]();\n\n const text = await response.text();\n if (text === '') {\n if (schema !== undefined) return validateJsonWithSchema(undefined, schema);\n return JSON.parse(text);\n }\n\n const jsonValue = options.parseJson\n ? await options.parseJson(text, { request: currentRequest, response })\n : JSON.parse(text);\n\n return schema === undefined ? jsonValue : validateJsonWithSchema(jsonValue, schema);\n };\n }\n\n return responsePromise;\n}\n","import { HTTP_METHODS } from './constants.js';\nimport { createResponsePromise } from './core.js';\nimport { RetryMarker } from './types.js';\nimport { mergeOptions, normalizeOptions } from './utils.js';\n\n/**\n * @param {import('../types/types.js').Options} [defaults]\n * @returns {import('../types/types.js').NetaInstance}\n */\nexport function createInstance(defaults) {\n const fn = (input, options) => {\n const merged = mergeOptions(defaults, options);\n const normalized = normalizeOptions(merged);\n // Stash user signal before we override it internally\n normalized._userSignal = normalized.signal ?? undefined;\n return createResponsePromise(input, normalized);\n };\n\n for (const method of HTTP_METHODS) {\n fn[method] = (input, options) => fn(input, { ...options, method });\n }\n\n fn.create = (newDefaults) => createInstance(mergeOptions(defaults, newDefaults));\n fn.extend = fn.create;\n\n /**\n * Signal forced retry from an afterResponse hook.\n * @param {{ delay?: number, request?: Request }} [options]\n * @returns {RetryMarker}\n */\n fn.retry = (options) => new RetryMarker(options);\n\n return fn;\n}\n\nconst neta = createInstance();\n\nexport default neta;\nexport { neta };\nexport { HTTPError, TimeoutError, NetworkError, ForceRetryError, SchemaValidationError } from './errors.js';\nexport { HTTPError as NetaError } from './errors.js';\nexport { createInstance as NetaClient };\nexport { stop } from './types.js';\n"],"mappings":"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","names":["HTTP_METHODS","DEFAULT_RETRY","attemptCount","DEFAULT_TIMEOUT","maxSafeTimeout","responseTypes","supportsAbortController","supportsAbortSignal","supportsFormData","supportsResponseStreams","supportsRequestStreams","duplexAccessed","hasContentType","HTTPError","response","request","options","status","TimeoutError","NetworkError","ForceRetryError","SchemaValidationError","issues","message","i","stop","RetryMarker","options","streamResponse","response","onDownloadProgress","totalBytes","transferredBytes","reader","stream","controller","done","value","percent","reason","streamRequest","request","onUploadProgress","originalBody","normalizeRetry","retry","DEFAULT_RETRY","normalizeHooks","hooks","mergeHeaders","target","source","result","value","key","mergeHooks","base","override","mergeOptions","defaults","overrides","merged","resolveInput","input","options","inputStr","prefix","path","appendSearchParams","url","searchParams","cleaned","params","normalizeOptions","normalized","normalizeRequestMethod","DEFAULT_TIMEOUT","headers","method","delay","ms","resolve","reject","signal","timer","parseRetryAfter","response","header","seconds","date","applyJitter","delayMs","jitter","isNetworkError","error","invalidSchemaMessage","validateJsonWithSchema","jsonValue","schema","standardSchema","result","SchemaValidationError","createManagedSignal","timeout","userSignal","controller","timer","readResponseText","response","timeoutMs","body","reader","decoder","chunks","totalBytes","maxSize","readAll","done","value","timeoutPromise","resolve","id","getResponseData","options","request","text","contentType","getNormalizedOptions","hooks","json","parseJson","stringifyJson","searchParams","totalTimeout","throwHttpErrors","fetch","context","_userSignal","prefix","baseUrl","onDownloadProgress","onUploadProgress","rest","calculateDelay","retry","retryCount","base","jittered","applyJitter","createResponsePromise","input","hook","startTime","currentRequest","getRemainingTotalTimeout","elapsed","getEffectiveTimeout","remaining","throwIfTotalTimeoutExhausted","TimeoutError","innerPromise","maxSafeTimeout","inputStr","resolveInput","url","appendSearchParams","_prefix","_baseUrl","fetchFn","requestInit","doFetch","effectiveTimeout","managed","fetchRequest","supportsRequestStreams","streamRequest","error","isNetworkError","NetworkError","attemptRetry","delayMs","safeDelay","delayOptions","delay","stop","getRetryDelayForFetchError","getRetryDelayForHttpError","retryAfter","parseRetryAfter","retryDelay","retryResult","responseFromHook","clonedResponse","hookResult","RetryMarker","ForceRetryError","shouldThrow","HTTPError","processedError","supportsResponseStreams","streamResponse","responsePromise","type","mimeType","responseTypes","createInstance","defaults","fn","input","options","merged","mergeOptions","normalized","normalizeOptions","createResponsePromise","method","HTTP_METHODS","newDefaults","RetryMarker","neta","index_default"]}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@anmetric/neta",
3
+ "version": "0.1.0",
4
+ "description": "Tiny, elegant HTTP client built on fetch for browser and Node.js",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./types/index.d.ts",
9
+ "import": "./dist/index.js",
10
+ "require": "./dist/index.cjs"
11
+ }
12
+ },
13
+ "sideEffects": false,
14
+ "main": "./dist/index.cjs",
15
+ "module": "./dist/index.js",
16
+ "types": "./types/index.d.ts",
17
+ "files": [
18
+ "dist",
19
+ "types"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "dev": "tsup --watch",
24
+ "test": "vitest run",
25
+ "test:watch": "vitest",
26
+ "typecheck": "tsc --noEmit",
27
+ "prepublishOnly": "npm run build"
28
+ },
29
+ "engines": {
30
+ "node": ">=18"
31
+ },
32
+ "devDependencies": {
33
+ "tsup": "^8.0.0",
34
+ "typescript": "^5.4.0",
35
+ "vitest": "^2.0.0"
36
+ },
37
+ "license": "MIT"
38
+ }
@@ -0,0 +1,12 @@
1
+ import type { RetryOptions } from './types.js';
2
+
3
+ export declare const HTTP_METHODS: string[];
4
+ export declare const DEFAULT_RETRY: RetryOptions;
5
+ export declare const DEFAULT_TIMEOUT: number;
6
+ export declare const maxSafeTimeout: number;
7
+ export declare const responseTypes: Record<string, string>;
8
+ export declare const supportsAbortController: boolean;
9
+ export declare const supportsAbortSignal: boolean;
10
+ export declare const supportsFormData: boolean;
11
+ export declare const supportsResponseStreams: boolean;
12
+ export declare const supportsRequestStreams: boolean;
@@ -0,0 +1,6 @@
1
+ import type { InternalOptions, ResponsePromise } from './types.js';
2
+
3
+ export declare function createResponsePromise(
4
+ input: string | URL | Request,
5
+ options: InternalOptions,
6
+ ): ResponsePromise;
@@ -0,0 +1,30 @@
1
+ import type { NormalizedOptions } from './types.js';
2
+
3
+ export declare class HTTPError extends Error {
4
+ response: Response;
5
+ request: Request;
6
+ options: NormalizedOptions;
7
+ data: unknown;
8
+ constructor(response: Response, request: Request, options: NormalizedOptions);
9
+ }
10
+
11
+ export declare class TimeoutError extends Error {
12
+ request: Request;
13
+ constructor(request: Request);
14
+ }
15
+
16
+ export declare class NetworkError extends Error {
17
+ request: Request;
18
+ constructor(request: Request, options?: { cause?: Error });
19
+ }
20
+
21
+ export declare class ForceRetryError extends Error {
22
+ customDelay?: number;
23
+ customRequest?: Request;
24
+ constructor(options?: { delay?: number; request?: Request });
25
+ }
26
+
27
+ export declare class SchemaValidationError extends Error {
28
+ issues: Array<{ message?: string; path?: Array<string | number | symbol> }>;
29
+ constructor(issues: Array<{ message?: string; path?: Array<string | number | symbol> }>);
30
+ }
@@ -0,0 +1,36 @@
1
+ import type { NetaInstance, Options } from './types.js';
2
+
3
+ export declare function createInstance(defaults?: Options): NetaInstance;
4
+
5
+ declare const neta: NetaInstance;
6
+ export default neta;
7
+ export { neta };
8
+
9
+ export { HTTPError, TimeoutError, NetworkError, ForceRetryError, SchemaValidationError } from './errors.js';
10
+ export { HTTPError as NetaError } from './errors.js';
11
+ export declare const NetaClient: new (defaults?: Options) => NetaInstance;
12
+ export type NetaClient = NetaInstance;
13
+ export { stop } from './types.js';
14
+ export type {
15
+ AfterResponseHook,
16
+ BeforeErrorHook,
17
+ BeforeRequestHook,
18
+ BeforeRetryHook,
19
+ DownloadProgress,
20
+ Hooks,
21
+ HttpMethod,
22
+ InitHook,
23
+ InternalOptions,
24
+ NetaInstance,
25
+ NetaResponse,
26
+ NormalizedHooks,
27
+ NormalizedOptions,
28
+ Options,
29
+ ResponsePromise,
30
+ RetryMarker,
31
+ RetryOptions,
32
+ SchemaValidationError as SchemaValidationErrorType,
33
+ SearchParamsInit,
34
+ StandardSchema,
35
+ UploadProgress,
36
+ } from './types.js';
@@ -0,0 +1,22 @@
1
+ import type { InternalOptions } from './types.js';
2
+
3
+ interface RetryState {
4
+ getRetryCount: () => number;
5
+ setRetryCount: (n: number) => void;
6
+ getStartTime: () => number | undefined;
7
+ }
8
+
9
+ export declare function executeWithRetry(
10
+ makeFetch: () => Promise<Response>,
11
+ request: Request,
12
+ options: InternalOptions,
13
+ state: RetryState,
14
+ ): Promise<Response>;
15
+
16
+ export declare function retryFromError(
17
+ error: unknown,
18
+ makeFetch: () => Promise<Response>,
19
+ request: Request,
20
+ options: InternalOptions,
21
+ state: RetryState,
22
+ ): Promise<Response | void>;
@@ -0,0 +1,12 @@
1
+ import type { DownloadProgress, UploadProgress } from './types.js';
2
+
3
+ export declare function streamResponse(
4
+ response: Response,
5
+ onDownloadProgress: (progress: DownloadProgress) => void,
6
+ ): Response;
7
+
8
+ export declare function streamRequest(
9
+ request: Request,
10
+ onUploadProgress: (progress: UploadProgress) => void,
11
+ originalBody?: BodyInit,
12
+ ): Request;
@@ -0,0 +1,164 @@
1
+ export type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options';
2
+
3
+ export type SearchParamsInit =
4
+ | string
5
+ | Record<string, string | number | boolean | undefined>
6
+ | URLSearchParams
7
+ | Array<[string, string]>;
8
+
9
+ export interface RetryOptions {
10
+ limit: number;
11
+ methods: string[];
12
+ statusCodes: number[];
13
+ afterStatusCodes: number[];
14
+ maxRetryAfter: number;
15
+ backoffLimit: number;
16
+ delay: (attemptCount: number) => number;
17
+ jitter: boolean | ((delay: number) => number);
18
+ retryOnTimeout: boolean;
19
+ shouldRetry?: (info: { error: Error; retryCount: number }) => boolean | undefined | Promise<boolean | undefined>;
20
+ }
21
+
22
+ export interface DownloadProgress {
23
+ percent: number;
24
+ transferredBytes: number;
25
+ totalBytes: number;
26
+ }
27
+
28
+ export interface UploadProgress {
29
+ percent: number;
30
+ transferredBytes: number;
31
+ totalBytes: number;
32
+ }
33
+
34
+ // Standard Schema v1 (https://github.com/standard-schema/standard-schema)
35
+ export interface StandardSchema {
36
+ '~standard': {
37
+ validate: (value: unknown) => { value?: unknown; issues?: Array<{ message?: string; path?: Array<string | number | symbol> }> } | Promise<{ value?: unknown; issues?: Array<{ message?: string; path?: Array<string | number | symbol> }> }>;
38
+ };
39
+ }
40
+
41
+ export interface InitHook {
42
+ (options: Options): void;
43
+ }
44
+
45
+ export interface BeforeRequestHook {
46
+ (info: {
47
+ request: Request;
48
+ options: NormalizedOptions;
49
+ retryCount: number;
50
+ }): Request | Response | void | Promise<Request | Response | void>;
51
+ }
52
+
53
+ export interface AfterResponseHook {
54
+ (info: {
55
+ request: Request;
56
+ options: NormalizedOptions;
57
+ response: Response;
58
+ retryCount: number;
59
+ }): Response | import('./types.js').RetryMarker | void | Promise<Response | import('./types.js').RetryMarker | void>;
60
+ }
61
+
62
+ export interface BeforeErrorHook {
63
+ (info: {
64
+ request: Request;
65
+ options: NormalizedOptions;
66
+ error: Error;
67
+ retryCount: number;
68
+ }): Error | void | Promise<Error | void>;
69
+ }
70
+
71
+ export interface BeforeRetryHook {
72
+ (info: {
73
+ request: Request;
74
+ options: NormalizedOptions;
75
+ error: Error;
76
+ retryCount: number;
77
+ }): Request | Response | typeof stop | void | Promise<Request | Response | typeof stop | void>;
78
+ }
79
+
80
+ export interface Hooks {
81
+ init?: InitHook[];
82
+ beforeRequest?: BeforeRequestHook[];
83
+ afterResponse?: AfterResponseHook[];
84
+ beforeError?: BeforeErrorHook[];
85
+ beforeRetry?: BeforeRetryHook[];
86
+ }
87
+
88
+ export interface NormalizedHooks {
89
+ init: InitHook[];
90
+ beforeRequest: BeforeRequestHook[];
91
+ afterResponse: AfterResponseHook[];
92
+ beforeError: BeforeErrorHook[];
93
+ beforeRetry: BeforeRetryHook[];
94
+ }
95
+
96
+ export interface Options extends Omit<RequestInit, 'method'> {
97
+ method?: HttpMethod | string;
98
+ prefix?: string | URL;
99
+ baseUrl?: string | URL;
100
+ retry?: number | Partial<RetryOptions>;
101
+ timeout?: number | false;
102
+ totalTimeout?: number | false;
103
+ hooks?: Hooks;
104
+ searchParams?: SearchParamsInit;
105
+ json?: unknown;
106
+ parseJson?: (text: string, context: { request: Request; response: Response }) => unknown;
107
+ stringifyJson?: (value: unknown) => string;
108
+ throwHttpErrors?: boolean | ((status: number) => boolean);
109
+ fetch?: typeof globalThis.fetch;
110
+ context?: Record<string, unknown>;
111
+ onDownloadProgress?: (progress: DownloadProgress) => void;
112
+ onUploadProgress?: (progress: UploadProgress) => void;
113
+ }
114
+
115
+ export interface InternalOptions extends Omit<Options, 'retry' | 'timeout' | 'totalTimeout' | 'hooks' | 'throwHttpErrors' | 'fetch' | 'context' | 'prefix'> {
116
+ method: string;
117
+ retry: RetryOptions;
118
+ timeout: number | false;
119
+ totalTimeout: number | false;
120
+ hooks: NormalizedHooks;
121
+ throwHttpErrors: boolean | ((status: number) => boolean);
122
+ fetch: typeof globalThis.fetch;
123
+ context: Record<string, unknown>;
124
+ prefix: string;
125
+ _userSignal?: AbortSignal;
126
+ }
127
+
128
+ export interface NormalizedOptions extends Omit<RequestInit, 'method'> {
129
+ method: string;
130
+ }
131
+
132
+ export interface NetaResponse extends Response {
133
+ json<T = unknown>(): Promise<T>;
134
+ }
135
+
136
+ export interface ResponsePromise extends Promise<NetaResponse> {
137
+ json<T = unknown>(schema?: StandardSchema): Promise<T>;
138
+ text(): Promise<string>;
139
+ blob(): Promise<Blob>;
140
+ arrayBuffer(): Promise<ArrayBuffer>;
141
+ formData(): Promise<FormData>;
142
+ bytes(): Promise<Uint8Array>;
143
+ }
144
+
145
+ export interface NetaInstance {
146
+ (input: string | URL | Request, options?: Options): ResponsePromise;
147
+ get(input: string | URL | Request, options?: Options): ResponsePromise;
148
+ post(input: string | URL | Request, options?: Options): ResponsePromise;
149
+ put(input: string | URL | Request, options?: Options): ResponsePromise;
150
+ patch(input: string | URL | Request, options?: Options): ResponsePromise;
151
+ delete(input: string | URL | Request, options?: Options): ResponsePromise;
152
+ head(input: string | URL | Request, options?: Options): ResponsePromise;
153
+ options(input: string | URL | Request, options?: Options): ResponsePromise;
154
+ create(defaults?: Options): NetaInstance;
155
+ extend(defaults?: Options): NetaInstance;
156
+ retry(options?: { delay?: number; request?: Request }): import('./types.js').RetryMarker;
157
+ }
158
+
159
+ export declare const stop: unique symbol;
160
+
161
+ export declare class RetryMarker {
162
+ options?: { delay?: number; request?: Request };
163
+ constructor(options?: { delay?: number; request?: Request });
164
+ }
@@ -0,0 +1,15 @@
1
+ import type { Hooks, InternalOptions, NormalizedHooks, Options, RetryOptions, SearchParamsInit } from './types.js';
2
+
3
+ export declare function normalizeRetry(retry: Options['retry']): RetryOptions;
4
+ export declare function normalizeHooks(hooks?: Options['hooks']): NormalizedHooks;
5
+ export declare function mergeHeaders(target?: HeadersInit, source?: HeadersInit): Headers;
6
+ export declare function mergeHooks(base?: Hooks, override?: Hooks): Hooks;
7
+ export declare function mergeOptions(defaults?: Options, overrides?: Options): Options;
8
+ export declare function resolveInput(input: string | URL | Request, options?: { prefix?: string; baseUrl?: string | URL }): string;
9
+ export declare function appendSearchParams(url: URL, searchParams?: SearchParamsInit): URL;
10
+ export declare function normalizeOptions(options: Options): InternalOptions;
11
+ export declare function normalizeRequestMethod(method?: string): string;
12
+ export declare function delay(ms: number, options?: { signal?: AbortSignal }): Promise<void>;
13
+ export declare function parseRetryAfter(response: Response): number | undefined;
14
+ export declare function applyJitter(delayMs: number, jitter: boolean | ((delay: number) => number)): number;
15
+ export declare function isNetworkError(error: unknown): boolean;