@sanity/client
Advanced tools
+1
-1
| { | ||
| "name": "@sanity/client", | ||
| "version": "7.23.0", | ||
| "version": "7.23.1", | ||
| "description": "Client for retrieving, creating and patching data from Sanity.io", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -8,7 +8,21 @@ import {defer, isObservable, mergeMap, Observable, of} from 'rxjs' | ||
| * @public | ||
| * Thrown if the EventSource connection could not be established. | ||
| * Note that ConnectionFailedErrors are rare, and disconnects will normally be handled by the EventSource instance itself and emitted as `reconnect` events. | ||
| * Thrown when the EventSource connection could not be established, or was rejected by the server. | ||
| * Transient failures (network drops, 5xx, 408, 429) are reconnected internally and emitted as | ||
| * `reconnect` events; a permanent rejection (any other 4xx, eg an expired token) errors the | ||
| * stream with this class so consumers can react — check `status` for the rejection code. | ||
| */ | ||
| export class ConnectionFailedError extends Error { | ||
| readonly name = 'ConnectionFailedError' | ||
| /** | ||
| * HTTP status code of the rejected connection attempt, if known. | ||
| * Only set when the EventSource implementation exposes it — the polyfill used in | ||
| * Node.js and when custom headers (eg authorization) are required does, while | ||
| * native EventSource implementations (browser and Node.js) do not. | ||
| */ | ||
| readonly status?: number | ||
| constructor(message?: string, options: ErrorOptions & {status?: number} = {}) { | ||
| const {status, ...errorOptions} = options | ||
| super(message, errorOptions) | ||
| this.status = status | ||
| } | ||
| } | ||
@@ -151,2 +165,14 @@ | ||
| // see https://html.spec.whatwg.org/multipage/server-sent-events.html#sse-processing-model | ||
| // The polyfills expose the HTTP status of a rejected connection on the error event | ||
| // (native EventSource implementations do not). A status means the server rejected the | ||
| // connection attempt, so error out regardless of readyState — the polyfills disagree | ||
| // on whether the connection closes before or after the error event is dispatched — | ||
| // and let `reconnectOnConnectionFailure` classify it (4xx fatal, otherwise retried). | ||
| const rawStatus = (evt as {status?: unknown}).status | ||
| const status = typeof rawStatus === 'number' ? rawStatus : undefined | ||
| if (status !== undefined) { | ||
| observer.error(new ConnectionFailedError('EventSource connection failed', {status})) | ||
| return | ||
| } | ||
| if (es.readyState === es.CLOSED) { | ||
@@ -153,0 +179,0 @@ // In these cases we'll signal to consumers (via the error path) that a retry/reconnect is needed. |
@@ -14,2 +14,4 @@ import { | ||
| const RETRYABLE_STATUSES = new Set([408, 429]) | ||
| /** | ||
@@ -24,3 +26,15 @@ * Note: connection failure is not the same as network disconnect which may happen more frequent. | ||
| catchError((err, caught) => { | ||
| if (err instanceof ConnectionFailedError) { | ||
| // Only reconnect on transient connection failures. A 4xx response is a | ||
| // rejection, not a transient failure — the server will keep rejecting | ||
| // (eg an expired token), so reconnecting would loop forever. The named | ||
| // exceptions are the explicitly transient 4xx statuses: 408 (request | ||
| // timeout) and 429 (rate limited). Anything else surfaces to the | ||
| // consumer instead. | ||
| if ( | ||
| err instanceof ConnectionFailedError && | ||
| (typeof err.status !== 'number' || | ||
| err.status < 400 || | ||
| err.status >= 500 || | ||
| RETRYABLE_STATUSES.has(err.status)) | ||
| ) { | ||
| return concat(of({type: 'reconnect' as const}), timer(1000).pipe(mergeMap(() => caught))) | ||
@@ -27,0 +41,0 @@ } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
5124787
0.43%59944
0.3%