@molecule/app-http 1.2.1 → 1.4.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 +249 -1
- package/dist/client.d.ts +6 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/errors.d.ts +67 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +75 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +176 -131
- package/dist/provider.js.map +1 -1
- package/dist/retry.d.ts +105 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +144 -0
- package/dist/retry.js.map +1 -0
- package/dist/types.d.ts +47 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +37 -1
- package/dist/types.js.map +1 -1
- package/dist/unwrap.d.ts +5 -0
- package/dist/unwrap.d.ts.map +1 -1
- package/dist/unwrap.js +5 -0
- package/dist/unwrap.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@ AUTO-GENERATED — DO NOT EDIT THIS FILE.
|
|
|
3
3
|
Generated by `mlcl sync-docs` from the package's src/index.ts JSDoc + mlcl/registry.json.
|
|
4
4
|
Edits here are overwritten on the next commit (molecule's pre-commit hook regenerates).
|
|
5
5
|
To change this document, edit the module-level JSDoc in src/index.ts.
|
|
6
|
-
Generated: 2026-10-
|
|
6
|
+
Generated: 2026-10-19T22:40:45.495Z
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
# @molecule/app-http
|
|
@@ -187,6 +187,58 @@ interface HttpClientConfig {
|
|
|
187
187
|
* it returns.
|
|
188
188
|
*/
|
|
189
189
|
authScheme?: string
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Default retry policy for every request this client makes, or `false` to
|
|
193
|
+
* disable retries. A request's own `retry` overrides it.
|
|
194
|
+
*/
|
|
195
|
+
retry?: RetryOptions | false
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
#### `RetryOptions`
|
|
200
|
+
|
|
201
|
+
Tuning for the retry policy.
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
interface RetryOptions {
|
|
205
|
+
/**
|
|
206
|
+
* Maximum retries AFTER the first attempt. Defaults to `2` (three attempts
|
|
207
|
+
* in total).
|
|
208
|
+
*/
|
|
209
|
+
maxRetries?: number
|
|
210
|
+
|
|
211
|
+
/** Base backoff in milliseconds. Defaults to `300`. */
|
|
212
|
+
baseDelayMs?: number
|
|
213
|
+
|
|
214
|
+
/** Maximum backoff (before `Retry-After` can extend it). Defaults to `5000`. */
|
|
215
|
+
maxDelayMs?: number
|
|
216
|
+
|
|
217
|
+
/** Statuses treated as transient. Defaults to `[502, 503, 504]`. */
|
|
218
|
+
retryStatuses?: number[]
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### `RetryDecisionInput`
|
|
223
|
+
|
|
224
|
+
The request fields the policy decides from.
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
interface RetryDecisionInput {
|
|
228
|
+
/** The request method. */
|
|
229
|
+
method: HttpMethod
|
|
230
|
+
/** The request headers (lower-cased lookup is done here). */
|
|
231
|
+
headers: Record<string, string | undefined>
|
|
232
|
+
/** The HTTP status, or `0` when no response arrived. */
|
|
233
|
+
status: number
|
|
234
|
+
/** How many retries have already been made (0 for the first failure). */
|
|
235
|
+
attempt: number
|
|
236
|
+
/** The error message, used to recognize a connection reset/refusal. */
|
|
237
|
+
errorMessage?: string
|
|
238
|
+
/** `true` when the request was aborted before a response. */
|
|
239
|
+
aborted?: boolean
|
|
240
|
+
/** Overrides layered over {@link DEFAULT_RETRY_OPTIONS}. */
|
|
241
|
+
options?: RetryOptions | false
|
|
190
242
|
}
|
|
191
243
|
```
|
|
192
244
|
|
|
@@ -264,6 +316,17 @@ interface RequestConfig {
|
|
|
264
316
|
* Custom request options (implementation-specific).
|
|
265
317
|
*/
|
|
266
318
|
options?: Record<string, unknown>
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Retry policy for this request, or `false` to disable retries.
|
|
322
|
+
*
|
|
323
|
+
* The default policy retries only IDEMPOTENT requests (`GET`/`HEAD`/`PUT`/
|
|
324
|
+
* `DELETE`/`OPTIONS`, and `POST`/`PATCH` carrying an `Idempotency-Key`) on
|
|
325
|
+
* `502`/`503`/`504` or a reset/refused connection, twice, with exponential
|
|
326
|
+
* backoff and jitter, honoring `Retry-After`. See `@molecule/app-http`'s
|
|
327
|
+
* `shouldRetryRequest`.
|
|
328
|
+
*/
|
|
329
|
+
retry?: RetryOptions | false
|
|
267
330
|
}
|
|
268
331
|
````
|
|
269
332
|
|
|
@@ -401,14 +464,38 @@ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTION
|
|
|
401
464
|
|
|
402
465
|
HTTP error with response details.
|
|
403
466
|
|
|
467
|
+
**`status` is an HTTP status when the server answered, and `0` when it did not.**
|
|
468
|
+
A `0` means NO response exists: the request was aborted (an `AbortController`, a
|
|
469
|
+
component's effect cleanup, a route change tearing the request down) or the
|
|
470
|
+
network failed before anything came back. It is not an HTTP status at all, so it
|
|
471
|
+
says nothing about the session — an app must never treat `status < 500` as
|
|
472
|
+
"signed out", because every aborted request on a route change would clear the
|
|
473
|
+
session. The correct check is {@link isAuthFailure} (`status === 401 || status === 403`);
|
|
474
|
+
`isNoResponse` (`status === 0`) identifies this case.
|
|
475
|
+
|
|
404
476
|
```typescript
|
|
405
477
|
class HttpError extends Error {
|
|
478
|
+
/**
|
|
479
|
+
* Builds a failed-request error.
|
|
480
|
+
*
|
|
481
|
+
* @param message - Human-readable message (already translated where a key exists).
|
|
482
|
+
* @param status - HTTP status, or `0` when no response was received (aborted / network failure).
|
|
483
|
+
* @param response - Parsed response when the server answered, otherwise undefined.
|
|
484
|
+
* @param config - The request config that failed.
|
|
485
|
+
* @param errorKey - Translation key for the failure (`http.error.aborted` for an
|
|
486
|
+
* aborted request, `http.error.networkError` for a real network failure).
|
|
487
|
+
* @param aborted - Whether the request was aborted before a response: an
|
|
488
|
+
* `AbortController` signal (component cleanup, a cancelled request) or the
|
|
489
|
+
* browser tearing the fetch down during a navigation. Distinguishes an abort
|
|
490
|
+
* from a network outage on the same `status === 0`, without parsing the message.
|
|
491
|
+
*/
|
|
406
492
|
constructor(
|
|
407
493
|
message: string,
|
|
408
494
|
public status: number,
|
|
409
495
|
public response?: HttpResponse,
|
|
410
496
|
public config?: FullRequestConfig,
|
|
411
497
|
public errorKey?: string,
|
|
498
|
+
public aborted = false,
|
|
412
499
|
) {
|
|
413
500
|
super(message)
|
|
414
501
|
this.name = 'HttpError'
|
|
@@ -468,6 +555,66 @@ function awaitAuthGate(request?: AuthGateRequest): Promise<void>
|
|
|
468
555
|
|
|
469
556
|
**Returns:** A promise that settles when the gate has released the request.
|
|
470
557
|
|
|
558
|
+
#### `isHttpError(err)`
|
|
559
|
+
|
|
560
|
+
Whether `err` is an {@link HttpError} from this package.
|
|
561
|
+
|
|
562
|
+
```typescript
|
|
563
|
+
function isHttpError(err: unknown): boolean
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
- `err` — Any thrown value.
|
|
567
|
+
|
|
568
|
+
**Returns:** True for an `HttpError`.
|
|
569
|
+
|
|
570
|
+
#### `isAuthFailure(err)`
|
|
571
|
+
|
|
572
|
+
Whether the server REJECTED the request's credential — the only failure that
|
|
573
|
+
justifies clearing a session.
|
|
574
|
+
|
|
575
|
+
`401` (unauthenticated/expired token) and `403` (authenticated but refused) are
|
|
576
|
+
the two statuses that say "this credential no longer authorizes this session".
|
|
577
|
+
Everything else — `0` (aborted or offline), `404` (wrong endpoint), `5xx` (server
|
|
578
|
+
fault), a rate limit — says nothing about the credential.
|
|
579
|
+
|
|
580
|
+
```typescript
|
|
581
|
+
function isAuthFailure(err: unknown): boolean
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
- `err` — Any thrown value.
|
|
585
|
+
|
|
586
|
+
**Returns:** True only when `err` is an `HttpError` with status 401 or 403.
|
|
587
|
+
|
|
588
|
+
#### `isNoResponse(err)`
|
|
589
|
+
|
|
590
|
+
Whether no response was received at all: the request was aborted or the network
|
|
591
|
+
failed. `status === 0` is not an HTTP status — it must never be read as
|
|
592
|
+
"the user is not signed in".
|
|
593
|
+
|
|
594
|
+
```typescript
|
|
595
|
+
function isNoResponse(err: unknown): boolean
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
- `err` — Any thrown value.
|
|
599
|
+
|
|
600
|
+
**Returns:** True when `err` is an `HttpError` with status `0`.
|
|
601
|
+
|
|
602
|
+
#### `isAborted(err)`
|
|
603
|
+
|
|
604
|
+
Whether the request was ABORTED (an `AbortController` signal, or the browser
|
|
605
|
+
cancelling the fetch during a navigation) rather than failing on the network.
|
|
606
|
+
|
|
607
|
+
Both arrive as `status === 0`; this distinguishes them, so a UI can stay silent
|
|
608
|
+
for a cancelled request while still reporting a real outage.
|
|
609
|
+
|
|
610
|
+
```typescript
|
|
611
|
+
function isAborted(err: unknown): boolean
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
- `err` — Any thrown value.
|
|
615
|
+
|
|
616
|
+
**Returns:** True when `err` is an `HttpError` flagged `aborted`.
|
|
617
|
+
|
|
471
618
|
#### `createFetchClient(config)`
|
|
472
619
|
|
|
473
620
|
Creates a fetch-based HTTP client using the native Fetch API.
|
|
@@ -484,6 +631,83 @@ function createFetchClient(config?: HttpClientConfig): HttpClient
|
|
|
484
631
|
|
|
485
632
|
**Returns:** A fully configured `HttpClient` instance.
|
|
486
633
|
|
|
634
|
+
#### `isIdempotentRequest(method, headers)`
|
|
635
|
+
|
|
636
|
+
Whether a request may be repeated at all.
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
function isIdempotentRequest(
|
|
640
|
+
method: HttpMethod,
|
|
641
|
+
headers: Record<string, string | undefined>,
|
|
642
|
+
): boolean
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
- `method` — The HTTP method.
|
|
646
|
+
- `headers` — The request headers (an `Idempotency-Key` makes POST/PATCH repeatable).
|
|
647
|
+
|
|
648
|
+
**Returns:** `true` when repeating the request cannot duplicate a side effect.
|
|
649
|
+
|
|
650
|
+
#### `isTransientConnectionError(message)`
|
|
651
|
+
|
|
652
|
+
Whether a connection-level error is transient (a restarted process refuses
|
|
653
|
+
or resets connections; a DNS or TLS configuration error does not).
|
|
654
|
+
|
|
655
|
+
```typescript
|
|
656
|
+
function isTransientConnectionError(message: string | undefined): boolean
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
- `message` — The error message.
|
|
660
|
+
|
|
661
|
+
**Returns:** `true` for reset/refused/closed-early/timeout shapes.
|
|
662
|
+
|
|
663
|
+
#### `parseRetryAfter(value, now)`
|
|
664
|
+
|
|
665
|
+
Parse a `Retry-After` header into milliseconds from now.
|
|
666
|
+
|
|
667
|
+
```typescript
|
|
668
|
+
function parseRetryAfter(value: string | undefined, now?: number): number | undefined
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
- `value` — The header value (`seconds` or an HTTP date).
|
|
672
|
+
- `now` — The clock, injected for tests.
|
|
673
|
+
|
|
674
|
+
**Returns:** Milliseconds to wait, or undefined when absent/unparseable.
|
|
675
|
+
|
|
676
|
+
#### `shouldRetryRequest(input)`
|
|
677
|
+
|
|
678
|
+
Decide whether one failed request should be retried.
|
|
679
|
+
|
|
680
|
+
```typescript
|
|
681
|
+
function shouldRetryRequest(input: RetryDecisionInput): boolean
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
- `input` — The method, headers, status/error and attempt count.
|
|
685
|
+
|
|
686
|
+
**Returns:** `true` when the request may be repeated.
|
|
687
|
+
|
|
688
|
+
#### `retryDelayMs(retryAfter, attempt, options, random)`
|
|
689
|
+
|
|
690
|
+
Compute the wait before the next attempt.
|
|
691
|
+
|
|
692
|
+
`Retry-After` wins when the server sent one (it knows when the instance will
|
|
693
|
+
be back); otherwise exponential backoff with full jitter.
|
|
694
|
+
|
|
695
|
+
```typescript
|
|
696
|
+
function retryDelayMs(
|
|
697
|
+
retryAfter: string | undefined,
|
|
698
|
+
attempt: number,
|
|
699
|
+
options?: false | RetryOptions,
|
|
700
|
+
random?: () => number,
|
|
701
|
+
): number
|
|
702
|
+
```
|
|
703
|
+
|
|
704
|
+
- `retryAfter` — The raw `Retry-After` header value, when present.
|
|
705
|
+
- `attempt` — How many retries have already been made (0 for the first).
|
|
706
|
+
- `options` — Policy overrides.
|
|
707
|
+
- `random` — Jitter source, injected for tests (defaults to `Math.random`).
|
|
708
|
+
|
|
709
|
+
**Returns:** Milliseconds to wait before retrying.
|
|
710
|
+
|
|
487
711
|
#### `unwrapList(res)`
|
|
488
712
|
|
|
489
713
|
Normalize an unknown response body into a typed array.
|
|
@@ -507,6 +731,11 @@ r.json())`) or the `HttpResponse` returned by `useHttpClient().get(...)`.
|
|
|
507
731
|
Both shapes are handled here so pages don't have to remember to call
|
|
508
732
|
`unwrapList(res.data)` vs `unwrapList(res)`.
|
|
509
733
|
|
|
734
|
+
A custom envelope such as `{ items: [...], count: 10 }` is not a `data`
|
|
735
|
+
envelope and returns `[]`. Read its named array directly: `body.items` for
|
|
736
|
+
raw JSON, or `response.data.items` for an `HttpResponse`. Passing that
|
|
737
|
+
array to `unwrapList` is also valid; passing the enclosing object is not.
|
|
738
|
+
|
|
510
739
|
```typescript
|
|
511
740
|
function unwrapList(res: unknown): T[]
|
|
512
741
|
```
|
|
@@ -665,6 +894,14 @@ function del(url: string, config?: RequestConfig): Promise<HttpResponse<T>>
|
|
|
665
894
|
|
|
666
895
|
### Constants
|
|
667
896
|
|
|
897
|
+
#### `DEFAULT_RETRY_OPTIONS`
|
|
898
|
+
|
|
899
|
+
The resolved policy used when a caller passes no options.
|
|
900
|
+
|
|
901
|
+
```typescript
|
|
902
|
+
const DEFAULT_RETRY_OPTIONS: Required<RetryOptions>
|
|
903
|
+
```
|
|
904
|
+
|
|
668
905
|
#### `fetchClient`
|
|
669
906
|
|
|
670
907
|
Pre-created fetch client for environments where `fetch` is available.
|
|
@@ -751,6 +988,17 @@ skipAuthGate: true })`. Without the opt-out the gate waits on itself, the restor
|
|
|
751
988
|
settles, and every request the gate holds stalls until it times out (3 s).
|
|
752
989
|
`@molecule/app-auth`'s own restore does not need it (it calls `fetch`, not this client).
|
|
753
990
|
|
|
991
|
+
**A failed request's `status` is `0` when NO response arrived — never read it as
|
|
992
|
+
"signed out".** An aborted request (an `AbortController` signal, a component's
|
|
993
|
+
effect cleanup, a route change tearing the fetch down) and a network outage both
|
|
994
|
+
throw an `HttpError` with `status === 0`; the aborted ones also carry
|
|
995
|
+
`aborted: true` and the `http.error.aborted` key, the rest `http.error.networkError`.
|
|
996
|
+
Neither says anything about the session. To decide whether a session ended, use
|
|
997
|
+
`isAuthFailure(err)` (401/403 only); `isNoResponse(err)` identifies the no-response
|
|
998
|
+
case so a caller can stay silent instead of reporting an outage. **Do not write
|
|
999
|
+
`err instanceof HttpError && err.status < 500` as a sign-out check** — it clears
|
|
1000
|
+
the session on every aborted navigation request.
|
|
1001
|
+
|
|
754
1002
|
## Translations
|
|
755
1003
|
|
|
756
1004
|
Translation strings are provided by `@molecule/app-locales-http`.
|
package/dist/client.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* @module
|
|
7
7
|
*/
|
|
8
8
|
import type { ErrorInterceptor, RequestInterceptor, ResponseInterceptor } from './interceptors.js';
|
|
9
|
+
import type { RetryOptions } from './retry.js';
|
|
9
10
|
import type { FullRequestConfig, HttpResponse, RequestConfig } from './types.js';
|
|
10
11
|
/**
|
|
11
12
|
* HTTP client interface.
|
|
@@ -109,5 +110,10 @@ export interface HttpClientConfig {
|
|
|
109
110
|
* it returns.
|
|
110
111
|
*/
|
|
111
112
|
authScheme?: string;
|
|
113
|
+
/**
|
|
114
|
+
* Default retry policy for every request this client makes, or `false` to
|
|
115
|
+
* disable retries. A request's own `retry` overrides it.
|
|
116
|
+
*/
|
|
117
|
+
retry?: RetryOptions | false;
|
|
112
118
|
}
|
|
113
119
|
//# sourceMappingURL=client.d.ts.map
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAClG,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAEhF;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IAEf;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEtC;;;OAGG;IACH,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAEzE;;OAEG;IACH,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAE/E;;;;OAIG;IACH,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAEhG;;;OAGG;IACH,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAE/F;;;OAGG;IACH,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAEjG;;OAEG;IACH,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAElF;;;OAGG;IACH,qBAAqB,CAAC,WAAW,EAAE,kBAAkB,GAAG,MAAM,IAAI,CAAA;IAElE;;;OAGG;IACH,sBAAsB,CAAC,WAAW,EAAE,mBAAmB,GAAG,MAAM,IAAI,CAAA;IAEpE;;;OAGG;IACH,mBAAmB,CAAC,WAAW,EAAE,gBAAgB,GAAG,MAAM,IAAI,CAAA;IAE9D;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAExC;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,IAAI,CAAA;IAE7B;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;CAC7C;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEvC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IAEzB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAClG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAC9C,OAAO,KAAK,EAAE,iBAAiB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAEhF;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAA;IAEf;;OAEG;IACH,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEtC;;;OAGG;IACH,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAEzE;;OAEG;IACH,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAE/E;;;;OAIG;IACH,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAEhG;;;OAGG;IACH,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAE/F;;;OAGG;IACH,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAEjG;;OAEG;IACH,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAElF;;;OAGG;IACH,qBAAqB,CAAC,WAAW,EAAE,kBAAkB,GAAG,MAAM,IAAI,CAAA;IAElE;;;OAGG;IACH,sBAAsB,CAAC,WAAW,EAAE,mBAAmB,GAAG,MAAM,IAAI,CAAA;IAEpE;;;OAGG;IACH,mBAAmB,CAAC,WAAW,EAAE,gBAAgB,GAAG,MAAM,IAAI,CAAA;IAE9D;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAA;IAExC;;OAEG;IACH,YAAY,IAAI,MAAM,GAAG,IAAI,CAAA;IAE7B;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;CAC7C;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEvC;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IAEzB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,GAAG,KAAK,CAAA;CAC7B"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classify a failed request instead of reading its `status` by hand.
|
|
3
|
+
*
|
|
4
|
+
* A failure from this package is an {@link HttpError} whose `status` is either an
|
|
5
|
+
* HTTP status (the server answered) or `0` (it did not — the request was aborted or
|
|
6
|
+
* the network failed). Code that clears a session must ask "did the server REJECT
|
|
7
|
+
* the credential?", which is `status === 401 || status === 403` and nothing else:
|
|
8
|
+
*
|
|
9
|
+
* ```typescript
|
|
10
|
+
* try {
|
|
11
|
+
* await http.get('/projects')
|
|
12
|
+
* } catch (err) {
|
|
13
|
+
* if (isAuthFailure(err)) clearSession()
|
|
14
|
+
* else if (isNoResponse(err)) return // aborted / offline — keep the session
|
|
15
|
+
* else showError(err)
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* `err instanceof HttpError && err.status < 500` is the trap these helpers exist to
|
|
20
|
+
* replace: an aborted request (a component unmounting, a route change cancelling an
|
|
21
|
+
* in-flight fetch) and a network outage both arrive with `status === 0`, so that
|
|
22
|
+
* check signs the user out on every navigation that cancels a request.
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
25
|
+
*/
|
|
26
|
+
import { HttpError } from './types.js';
|
|
27
|
+
/**
|
|
28
|
+
* Whether `err` is an {@link HttpError} from this package.
|
|
29
|
+
*
|
|
30
|
+
* @param err - Any thrown value.
|
|
31
|
+
* @returns True for an `HttpError`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function isHttpError(err: unknown): err is HttpError;
|
|
34
|
+
/**
|
|
35
|
+
* Whether the server REJECTED the request's credential — the only failure that
|
|
36
|
+
* justifies clearing a session.
|
|
37
|
+
*
|
|
38
|
+
* `401` (unauthenticated/expired token) and `403` (authenticated but refused) are
|
|
39
|
+
* the two statuses that say "this credential no longer authorizes this session".
|
|
40
|
+
* Everything else — `0` (aborted or offline), `404` (wrong endpoint), `5xx` (server
|
|
41
|
+
* fault), a rate limit — says nothing about the credential.
|
|
42
|
+
*
|
|
43
|
+
* @param err - Any thrown value.
|
|
44
|
+
* @returns True only when `err` is an `HttpError` with status 401 or 403.
|
|
45
|
+
*/
|
|
46
|
+
export declare function isAuthFailure(err: unknown): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Whether no response was received at all: the request was aborted or the network
|
|
49
|
+
* failed. `status === 0` is not an HTTP status — it must never be read as
|
|
50
|
+
* "the user is not signed in".
|
|
51
|
+
*
|
|
52
|
+
* @param err - Any thrown value.
|
|
53
|
+
* @returns True when `err` is an `HttpError` with status `0`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function isNoResponse(err: unknown): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Whether the request was ABORTED (an `AbortController` signal, or the browser
|
|
58
|
+
* cancelling the fetch during a navigation) rather than failing on the network.
|
|
59
|
+
*
|
|
60
|
+
* Both arrive as `status === 0`; this distinguishes them, so a UI can stay silent
|
|
61
|
+
* for a cancelled request while still reporting a real outage.
|
|
62
|
+
*
|
|
63
|
+
* @param err - Any thrown value.
|
|
64
|
+
* @returns True when `err` is an `HttpError` flagged `aborted`.
|
|
65
|
+
*/
|
|
66
|
+
export declare function isAborted(err: unknown): boolean;
|
|
67
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEtC;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,SAAS,CAE1D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAEnD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAElD;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE/C"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classify a failed request instead of reading its `status` by hand.
|
|
3
|
+
*
|
|
4
|
+
* A failure from this package is an {@link HttpError} whose `status` is either an
|
|
5
|
+
* HTTP status (the server answered) or `0` (it did not — the request was aborted or
|
|
6
|
+
* the network failed). Code that clears a session must ask "did the server REJECT
|
|
7
|
+
* the credential?", which is `status === 401 || status === 403` and nothing else:
|
|
8
|
+
*
|
|
9
|
+
* ```typescript
|
|
10
|
+
* try {
|
|
11
|
+
* await http.get('/projects')
|
|
12
|
+
* } catch (err) {
|
|
13
|
+
* if (isAuthFailure(err)) clearSession()
|
|
14
|
+
* else if (isNoResponse(err)) return // aborted / offline — keep the session
|
|
15
|
+
* else showError(err)
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* `err instanceof HttpError && err.status < 500` is the trap these helpers exist to
|
|
20
|
+
* replace: an aborted request (a component unmounting, a route change cancelling an
|
|
21
|
+
* in-flight fetch) and a network outage both arrive with `status === 0`, so that
|
|
22
|
+
* check signs the user out on every navigation that cancels a request.
|
|
23
|
+
*
|
|
24
|
+
* @module
|
|
25
|
+
*/
|
|
26
|
+
import { HttpError } from './types.js';
|
|
27
|
+
/**
|
|
28
|
+
* Whether `err` is an {@link HttpError} from this package.
|
|
29
|
+
*
|
|
30
|
+
* @param err - Any thrown value.
|
|
31
|
+
* @returns True for an `HttpError`.
|
|
32
|
+
*/
|
|
33
|
+
export function isHttpError(err) {
|
|
34
|
+
return err instanceof HttpError;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Whether the server REJECTED the request's credential — the only failure that
|
|
38
|
+
* justifies clearing a session.
|
|
39
|
+
*
|
|
40
|
+
* `401` (unauthenticated/expired token) and `403` (authenticated but refused) are
|
|
41
|
+
* the two statuses that say "this credential no longer authorizes this session".
|
|
42
|
+
* Everything else — `0` (aborted or offline), `404` (wrong endpoint), `5xx` (server
|
|
43
|
+
* fault), a rate limit — says nothing about the credential.
|
|
44
|
+
*
|
|
45
|
+
* @param err - Any thrown value.
|
|
46
|
+
* @returns True only when `err` is an `HttpError` with status 401 or 403.
|
|
47
|
+
*/
|
|
48
|
+
export function isAuthFailure(err) {
|
|
49
|
+
return isHttpError(err) && (err.status === 401 || err.status === 403);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Whether no response was received at all: the request was aborted or the network
|
|
53
|
+
* failed. `status === 0` is not an HTTP status — it must never be read as
|
|
54
|
+
* "the user is not signed in".
|
|
55
|
+
*
|
|
56
|
+
* @param err - Any thrown value.
|
|
57
|
+
* @returns True when `err` is an `HttpError` with status `0`.
|
|
58
|
+
*/
|
|
59
|
+
export function isNoResponse(err) {
|
|
60
|
+
return isHttpError(err) && err.status === 0;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Whether the request was ABORTED (an `AbortController` signal, or the browser
|
|
64
|
+
* cancelling the fetch during a navigation) rather than failing on the network.
|
|
65
|
+
*
|
|
66
|
+
* Both arrive as `status === 0`; this distinguishes them, so a UI can stay silent
|
|
67
|
+
* for a cancelled request while still reporting a real outage.
|
|
68
|
+
*
|
|
69
|
+
* @param err - Any thrown value.
|
|
70
|
+
* @returns True when `err` is an `HttpError` flagged `aborted`.
|
|
71
|
+
*/
|
|
72
|
+
export function isAborted(err) {
|
|
73
|
+
return isHttpError(err) && err.aborted;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAEtC;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,OAAO,GAAG,YAAY,SAAS,CAAA;AACjC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,GAAY;IACxC,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,CAAA;AACvE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,CAAA;AAC7C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,SAAS,CAAC,GAAY;IACpC,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,CAAA;AACxC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -88,12 +88,25 @@
|
|
|
88
88
|
* settles, and every request the gate holds stalls until it times out (3 s).
|
|
89
89
|
* `@molecule/app-auth`'s own restore does not need it (it calls `fetch`, not this client).
|
|
90
90
|
*
|
|
91
|
+
* **A failed request's `status` is `0` when NO response arrived — never read it as
|
|
92
|
+
* "signed out".** An aborted request (an `AbortController` signal, a component's
|
|
93
|
+
* effect cleanup, a route change tearing the fetch down) and a network outage both
|
|
94
|
+
* throw an `HttpError` with `status === 0`; the aborted ones also carry
|
|
95
|
+
* `aborted: true` and the `http.error.aborted` key, the rest `http.error.networkError`.
|
|
96
|
+
* Neither says anything about the session. To decide whether a session ended, use
|
|
97
|
+
* `isAuthFailure(err)` (401/403 only); `isNoResponse(err)` identifies the no-response
|
|
98
|
+
* case so a caller can stay silent instead of reporting an outage. **Do not write
|
|
99
|
+
* `err instanceof HttpError && err.status < 500` as a sign-out check** — it clears
|
|
100
|
+
* the session on every aborted navigation request.
|
|
101
|
+
*
|
|
91
102
|
* @module
|
|
92
103
|
*/
|
|
93
104
|
export * from './auth-gate.js';
|
|
94
105
|
export * from './client.js';
|
|
106
|
+
export * from './errors.js';
|
|
95
107
|
export * from './interceptors.js';
|
|
96
108
|
export * from './provider.js';
|
|
109
|
+
export * from './retry.js';
|
|
97
110
|
export * from './types.js';
|
|
98
111
|
export * from './unwrap.js';
|
|
99
112
|
export * from './utilities.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsGG;AAEH,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -88,12 +88,25 @@
|
|
|
88
88
|
* settles, and every request the gate holds stalls until it times out (3 s).
|
|
89
89
|
* `@molecule/app-auth`'s own restore does not need it (it calls `fetch`, not this client).
|
|
90
90
|
*
|
|
91
|
+
* **A failed request's `status` is `0` when NO response arrived — never read it as
|
|
92
|
+
* "signed out".** An aborted request (an `AbortController` signal, a component's
|
|
93
|
+
* effect cleanup, a route change tearing the fetch down) and a network outage both
|
|
94
|
+
* throw an `HttpError` with `status === 0`; the aborted ones also carry
|
|
95
|
+
* `aborted: true` and the `http.error.aborted` key, the rest `http.error.networkError`.
|
|
96
|
+
* Neither says anything about the session. To decide whether a session ended, use
|
|
97
|
+
* `isAuthFailure(err)` (401/403 only); `isNoResponse(err)` identifies the no-response
|
|
98
|
+
* case so a caller can stay silent instead of reporting an outage. **Do not write
|
|
99
|
+
* `err instanceof HttpError && err.status < 500` as a sign-out check** — it clears
|
|
100
|
+
* the session on every aborted navigation request.
|
|
101
|
+
*
|
|
91
102
|
* @module
|
|
92
103
|
*/
|
|
93
104
|
export * from './auth-gate.js';
|
|
94
105
|
export * from './client.js';
|
|
106
|
+
export * from './errors.js';
|
|
95
107
|
export * from './interceptors.js';
|
|
96
108
|
export * from './provider.js';
|
|
109
|
+
export * from './retry.js';
|
|
97
110
|
export * from './types.js';
|
|
98
111
|
export * from './unwrap.js';
|
|
99
112
|
export * from './utilities.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsGG;AAEH,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,cAAc,mBAAmB,CAAA;AACjC,cAAc,eAAe,CAAA;AAC7B,cAAc,YAAY,CAAA;AAC1B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,gBAAgB,CAAA"}
|
package/dist/provider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAc/D;;;;;;;;;GASG;AACH,eAAO,MAAM,iBAAiB,GAAI,SAAQ,gBAAqB,KAAG,UA8ajE,CAAA"}
|