@sanity/client 7.22.1 → 7.23.1
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/dist/index.browser.cjs +70 -4
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.d.cts +45 -2
- package/dist/index.browser.d.ts +45 -2
- package/dist/index.browser.js +71 -5
- package/dist/index.browser.js.map +1 -1
- package/dist/index.cjs +71 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -2
- package/dist/index.d.ts +45 -2
- package/dist/index.js +72 -6
- package/dist/index.js.map +1 -1
- package/dist/stega.browser.d.cts +45 -2
- package/dist/stega.browser.d.ts +45 -2
- package/dist/stega.d.cts +45 -2
- package/dist/stega.d.ts +45 -2
- package/package.json +2 -2
- package/src/SanityClient.ts +28 -0
- package/src/data/dataMethods.ts +53 -2
- package/src/data/eventsource.ts +28 -2
- package/src/data/reconnectOnConnectionFailure.ts +15 -1
- package/umd/sanityClient.js +99 -6
- package/umd/sanityClient.min.js +2 -2
package/dist/stega.browser.d.cts
CHANGED
|
@@ -906,11 +906,26 @@ export declare function connectEventSource<EventName extends string>(
|
|
|
906
906
|
|
|
907
907
|
/**
|
|
908
908
|
* @public
|
|
909
|
-
* Thrown
|
|
910
|
-
*
|
|
909
|
+
* Thrown when the EventSource connection could not be established, or was rejected by the server.
|
|
910
|
+
* Transient failures (network drops, 5xx, 408, 429) are reconnected internally and emitted as
|
|
911
|
+
* `reconnect` events; a permanent rejection (any other 4xx, eg an expired token) errors the
|
|
912
|
+
* stream with this class so consumers can react — check `status` for the rejection code.
|
|
911
913
|
*/
|
|
912
914
|
export declare class ConnectionFailedError extends Error {
|
|
913
915
|
readonly name = 'ConnectionFailedError'
|
|
916
|
+
/**
|
|
917
|
+
* HTTP status code of the rejected connection attempt, if known.
|
|
918
|
+
* Only set when the EventSource implementation exposes it — the polyfill used in
|
|
919
|
+
* Node.js and when custom headers (eg authorization) are required does, while
|
|
920
|
+
* native EventSource implementations (browser and Node.js) do not.
|
|
921
|
+
*/
|
|
922
|
+
readonly status?: number
|
|
923
|
+
constructor(
|
|
924
|
+
message?: string,
|
|
925
|
+
options?: ErrorOptions & {
|
|
926
|
+
status?: number
|
|
927
|
+
},
|
|
928
|
+
)
|
|
914
929
|
}
|
|
915
930
|
|
|
916
931
|
/**
|
|
@@ -3363,6 +3378,20 @@ export declare class ObservableSanityClient {
|
|
|
3363
3378
|
tag?: string
|
|
3364
3379
|
},
|
|
3365
3380
|
): Observable<(SanityDocument<R> | null)[]>
|
|
3381
|
+
/**
|
|
3382
|
+
* Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
|
|
3383
|
+
* Returns a set of the IDs that exist.
|
|
3384
|
+
*
|
|
3385
|
+
* @param ids - Document IDs to check
|
|
3386
|
+
* @param options - Request options
|
|
3387
|
+
*/
|
|
3388
|
+
documentsExists(
|
|
3389
|
+
ids: string[],
|
|
3390
|
+
options?: {
|
|
3391
|
+
signal?: AbortSignal
|
|
3392
|
+
tag?: string
|
|
3393
|
+
},
|
|
3394
|
+
): Observable<Set<string>>
|
|
3366
3395
|
/**
|
|
3367
3396
|
* Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
|
|
3368
3397
|
* Returns an observable that resolves to the created document.
|
|
@@ -5286,6 +5315,20 @@ export declare class SanityClient {
|
|
|
5286
5315
|
tag?: string
|
|
5287
5316
|
},
|
|
5288
5317
|
): Promise<(SanityDocument<R> | null)[]>
|
|
5318
|
+
/**
|
|
5319
|
+
* Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
|
|
5320
|
+
* Returns a set of the IDs that exist.
|
|
5321
|
+
*
|
|
5322
|
+
* @param ids - Document IDs to check
|
|
5323
|
+
* @param options - Request options
|
|
5324
|
+
*/
|
|
5325
|
+
documentsExists(
|
|
5326
|
+
ids: string[],
|
|
5327
|
+
options?: {
|
|
5328
|
+
signal?: AbortSignal
|
|
5329
|
+
tag?: string
|
|
5330
|
+
},
|
|
5331
|
+
): Promise<Set<string>>
|
|
5289
5332
|
/**
|
|
5290
5333
|
* Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
|
|
5291
5334
|
* Returns a promise that resolves to the created document.
|
package/dist/stega.browser.d.ts
CHANGED
|
@@ -906,11 +906,26 @@ export declare function connectEventSource<EventName extends string>(
|
|
|
906
906
|
|
|
907
907
|
/**
|
|
908
908
|
* @public
|
|
909
|
-
* Thrown
|
|
910
|
-
*
|
|
909
|
+
* Thrown when the EventSource connection could not be established, or was rejected by the server.
|
|
910
|
+
* Transient failures (network drops, 5xx, 408, 429) are reconnected internally and emitted as
|
|
911
|
+
* `reconnect` events; a permanent rejection (any other 4xx, eg an expired token) errors the
|
|
912
|
+
* stream with this class so consumers can react — check `status` for the rejection code.
|
|
911
913
|
*/
|
|
912
914
|
export declare class ConnectionFailedError extends Error {
|
|
913
915
|
readonly name = 'ConnectionFailedError'
|
|
916
|
+
/**
|
|
917
|
+
* HTTP status code of the rejected connection attempt, if known.
|
|
918
|
+
* Only set when the EventSource implementation exposes it — the polyfill used in
|
|
919
|
+
* Node.js and when custom headers (eg authorization) are required does, while
|
|
920
|
+
* native EventSource implementations (browser and Node.js) do not.
|
|
921
|
+
*/
|
|
922
|
+
readonly status?: number
|
|
923
|
+
constructor(
|
|
924
|
+
message?: string,
|
|
925
|
+
options?: ErrorOptions & {
|
|
926
|
+
status?: number
|
|
927
|
+
},
|
|
928
|
+
)
|
|
914
929
|
}
|
|
915
930
|
|
|
916
931
|
/**
|
|
@@ -3363,6 +3378,20 @@ export declare class ObservableSanityClient {
|
|
|
3363
3378
|
tag?: string
|
|
3364
3379
|
},
|
|
3365
3380
|
): Observable<(SanityDocument<R> | null)[]>
|
|
3381
|
+
/**
|
|
3382
|
+
* Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
|
|
3383
|
+
* Returns a set of the IDs that exist.
|
|
3384
|
+
*
|
|
3385
|
+
* @param ids - Document IDs to check
|
|
3386
|
+
* @param options - Request options
|
|
3387
|
+
*/
|
|
3388
|
+
documentsExists(
|
|
3389
|
+
ids: string[],
|
|
3390
|
+
options?: {
|
|
3391
|
+
signal?: AbortSignal
|
|
3392
|
+
tag?: string
|
|
3393
|
+
},
|
|
3394
|
+
): Observable<Set<string>>
|
|
3366
3395
|
/**
|
|
3367
3396
|
* Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
|
|
3368
3397
|
* Returns an observable that resolves to the created document.
|
|
@@ -5286,6 +5315,20 @@ export declare class SanityClient {
|
|
|
5286
5315
|
tag?: string
|
|
5287
5316
|
},
|
|
5288
5317
|
): Promise<(SanityDocument<R> | null)[]>
|
|
5318
|
+
/**
|
|
5319
|
+
* Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
|
|
5320
|
+
* Returns a set of the IDs that exist.
|
|
5321
|
+
*
|
|
5322
|
+
* @param ids - Document IDs to check
|
|
5323
|
+
* @param options - Request options
|
|
5324
|
+
*/
|
|
5325
|
+
documentsExists(
|
|
5326
|
+
ids: string[],
|
|
5327
|
+
options?: {
|
|
5328
|
+
signal?: AbortSignal
|
|
5329
|
+
tag?: string
|
|
5330
|
+
},
|
|
5331
|
+
): Promise<Set<string>>
|
|
5289
5332
|
/**
|
|
5290
5333
|
* Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
|
|
5291
5334
|
* Returns a promise that resolves to the created document.
|
package/dist/stega.d.cts
CHANGED
|
@@ -906,11 +906,26 @@ export declare function connectEventSource<EventName extends string>(
|
|
|
906
906
|
|
|
907
907
|
/**
|
|
908
908
|
* @public
|
|
909
|
-
* Thrown
|
|
910
|
-
*
|
|
909
|
+
* Thrown when the EventSource connection could not be established, or was rejected by the server.
|
|
910
|
+
* Transient failures (network drops, 5xx, 408, 429) are reconnected internally and emitted as
|
|
911
|
+
* `reconnect` events; a permanent rejection (any other 4xx, eg an expired token) errors the
|
|
912
|
+
* stream with this class so consumers can react — check `status` for the rejection code.
|
|
911
913
|
*/
|
|
912
914
|
export declare class ConnectionFailedError extends Error {
|
|
913
915
|
readonly name = 'ConnectionFailedError'
|
|
916
|
+
/**
|
|
917
|
+
* HTTP status code of the rejected connection attempt, if known.
|
|
918
|
+
* Only set when the EventSource implementation exposes it — the polyfill used in
|
|
919
|
+
* Node.js and when custom headers (eg authorization) are required does, while
|
|
920
|
+
* native EventSource implementations (browser and Node.js) do not.
|
|
921
|
+
*/
|
|
922
|
+
readonly status?: number
|
|
923
|
+
constructor(
|
|
924
|
+
message?: string,
|
|
925
|
+
options?: ErrorOptions & {
|
|
926
|
+
status?: number
|
|
927
|
+
},
|
|
928
|
+
)
|
|
914
929
|
}
|
|
915
930
|
|
|
916
931
|
/**
|
|
@@ -3363,6 +3378,20 @@ export declare class ObservableSanityClient {
|
|
|
3363
3378
|
tag?: string
|
|
3364
3379
|
},
|
|
3365
3380
|
): Observable<(SanityDocument<R> | null)[]>
|
|
3381
|
+
/**
|
|
3382
|
+
* Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
|
|
3383
|
+
* Returns a set of the IDs that exist.
|
|
3384
|
+
*
|
|
3385
|
+
* @param ids - Document IDs to check
|
|
3386
|
+
* @param options - Request options
|
|
3387
|
+
*/
|
|
3388
|
+
documentsExists(
|
|
3389
|
+
ids: string[],
|
|
3390
|
+
options?: {
|
|
3391
|
+
signal?: AbortSignal
|
|
3392
|
+
tag?: string
|
|
3393
|
+
},
|
|
3394
|
+
): Observable<Set<string>>
|
|
3366
3395
|
/**
|
|
3367
3396
|
* Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
|
|
3368
3397
|
* Returns an observable that resolves to the created document.
|
|
@@ -5286,6 +5315,20 @@ export declare class SanityClient {
|
|
|
5286
5315
|
tag?: string
|
|
5287
5316
|
},
|
|
5288
5317
|
): Promise<(SanityDocument<R> | null)[]>
|
|
5318
|
+
/**
|
|
5319
|
+
* Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
|
|
5320
|
+
* Returns a set of the IDs that exist.
|
|
5321
|
+
*
|
|
5322
|
+
* @param ids - Document IDs to check
|
|
5323
|
+
* @param options - Request options
|
|
5324
|
+
*/
|
|
5325
|
+
documentsExists(
|
|
5326
|
+
ids: string[],
|
|
5327
|
+
options?: {
|
|
5328
|
+
signal?: AbortSignal
|
|
5329
|
+
tag?: string
|
|
5330
|
+
},
|
|
5331
|
+
): Promise<Set<string>>
|
|
5289
5332
|
/**
|
|
5290
5333
|
* Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
|
|
5291
5334
|
* Returns a promise that resolves to the created document.
|
package/dist/stega.d.ts
CHANGED
|
@@ -906,11 +906,26 @@ export declare function connectEventSource<EventName extends string>(
|
|
|
906
906
|
|
|
907
907
|
/**
|
|
908
908
|
* @public
|
|
909
|
-
* Thrown
|
|
910
|
-
*
|
|
909
|
+
* Thrown when the EventSource connection could not be established, or was rejected by the server.
|
|
910
|
+
* Transient failures (network drops, 5xx, 408, 429) are reconnected internally and emitted as
|
|
911
|
+
* `reconnect` events; a permanent rejection (any other 4xx, eg an expired token) errors the
|
|
912
|
+
* stream with this class so consumers can react — check `status` for the rejection code.
|
|
911
913
|
*/
|
|
912
914
|
export declare class ConnectionFailedError extends Error {
|
|
913
915
|
readonly name = 'ConnectionFailedError'
|
|
916
|
+
/**
|
|
917
|
+
* HTTP status code of the rejected connection attempt, if known.
|
|
918
|
+
* Only set when the EventSource implementation exposes it — the polyfill used in
|
|
919
|
+
* Node.js and when custom headers (eg authorization) are required does, while
|
|
920
|
+
* native EventSource implementations (browser and Node.js) do not.
|
|
921
|
+
*/
|
|
922
|
+
readonly status?: number
|
|
923
|
+
constructor(
|
|
924
|
+
message?: string,
|
|
925
|
+
options?: ErrorOptions & {
|
|
926
|
+
status?: number
|
|
927
|
+
},
|
|
928
|
+
)
|
|
914
929
|
}
|
|
915
930
|
|
|
916
931
|
/**
|
|
@@ -3363,6 +3378,20 @@ export declare class ObservableSanityClient {
|
|
|
3363
3378
|
tag?: string
|
|
3364
3379
|
},
|
|
3365
3380
|
): Observable<(SanityDocument<R> | null)[]>
|
|
3381
|
+
/**
|
|
3382
|
+
* Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
|
|
3383
|
+
* Returns a set of the IDs that exist.
|
|
3384
|
+
*
|
|
3385
|
+
* @param ids - Document IDs to check
|
|
3386
|
+
* @param options - Request options
|
|
3387
|
+
*/
|
|
3388
|
+
documentsExists(
|
|
3389
|
+
ids: string[],
|
|
3390
|
+
options?: {
|
|
3391
|
+
signal?: AbortSignal
|
|
3392
|
+
tag?: string
|
|
3393
|
+
},
|
|
3394
|
+
): Observable<Set<string>>
|
|
3366
3395
|
/**
|
|
3367
3396
|
* Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
|
|
3368
3397
|
* Returns an observable that resolves to the created document.
|
|
@@ -5286,6 +5315,20 @@ export declare class SanityClient {
|
|
|
5286
5315
|
tag?: string
|
|
5287
5316
|
},
|
|
5288
5317
|
): Promise<(SanityDocument<R> | null)[]>
|
|
5318
|
+
/**
|
|
5319
|
+
* Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
|
|
5320
|
+
* Returns a set of the IDs that exist.
|
|
5321
|
+
*
|
|
5322
|
+
* @param ids - Document IDs to check
|
|
5323
|
+
* @param options - Request options
|
|
5324
|
+
*/
|
|
5325
|
+
documentsExists(
|
|
5326
|
+
ids: string[],
|
|
5327
|
+
options?: {
|
|
5328
|
+
signal?: AbortSignal
|
|
5329
|
+
tag?: string
|
|
5330
|
+
},
|
|
5331
|
+
): Promise<Set<string>>
|
|
5289
5332
|
/**
|
|
5290
5333
|
* Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
|
|
5291
5334
|
* Returns a promise that resolves to the created document.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sanity/client",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.23.1",
|
|
4
4
|
"description": "Client for retrieving, creating and patching data from Sanity.io",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
},
|
|
131
131
|
"dependencies": {
|
|
132
132
|
"@sanity/eventsource": "^5.0.2",
|
|
133
|
-
"get-it": "^8.
|
|
133
|
+
"get-it": "^8.8.0",
|
|
134
134
|
"nanoid": "^3.3.11",
|
|
135
135
|
"rxjs": "^7.0.0"
|
|
136
136
|
},
|
package/src/SanityClient.ts
CHANGED
|
@@ -324,6 +324,20 @@ export class ObservableSanityClient {
|
|
|
324
324
|
return dataMethods._getDocuments<R>(this, this.#httpRequest, ids, options)
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
+
/**
|
|
328
|
+
* Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
|
|
329
|
+
* Returns a set of the IDs that exist.
|
|
330
|
+
*
|
|
331
|
+
* @param ids - Document IDs to check
|
|
332
|
+
* @param options - Request options
|
|
333
|
+
*/
|
|
334
|
+
documentsExists(
|
|
335
|
+
ids: string[],
|
|
336
|
+
options?: {signal?: AbortSignal; tag?: string},
|
|
337
|
+
): Observable<Set<string>> {
|
|
338
|
+
return dataMethods._documentsExists(this, this.#httpRequest, ids, options)
|
|
339
|
+
}
|
|
340
|
+
|
|
327
341
|
/**
|
|
328
342
|
* Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
|
|
329
343
|
* Returns an observable that resolves to the created document.
|
|
@@ -1390,6 +1404,20 @@ export class SanityClient {
|
|
|
1390
1404
|
return lastValueFrom(dataMethods._getDocuments<R>(this, this.#httpRequest, ids, options))
|
|
1391
1405
|
}
|
|
1392
1406
|
|
|
1407
|
+
/**
|
|
1408
|
+
* Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
|
|
1409
|
+
* Returns a set of the IDs that exist.
|
|
1410
|
+
*
|
|
1411
|
+
* @param ids - Document IDs to check
|
|
1412
|
+
* @param options - Request options
|
|
1413
|
+
*/
|
|
1414
|
+
documentsExists(
|
|
1415
|
+
ids: string[],
|
|
1416
|
+
options?: {signal?: AbortSignal; tag?: string},
|
|
1417
|
+
): Promise<Set<string>> {
|
|
1418
|
+
return lastValueFrom(dataMethods._documentsExists(this, this.#httpRequest, ids, options))
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1393
1421
|
/**
|
|
1394
1422
|
* Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
|
|
1395
1423
|
* Returns a promise that resolves to the created document.
|
package/src/data/dataMethods.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {getDraftId, getVersionFromId, getVersionId, isDraftId} from '@sanity/client/csm'
|
|
2
|
-
import {from, type MonoTypeOperatorFunction, Observable} from 'rxjs'
|
|
3
|
-
import {combineLatestWith, filter, map} from 'rxjs/operators'
|
|
2
|
+
import {from, type MonoTypeOperatorFunction, Observable, of} from 'rxjs'
|
|
3
|
+
import {combineLatestWith, concatMap, filter, map, reduce} from 'rxjs/operators'
|
|
4
4
|
|
|
5
5
|
import {validateApiPerspective} from '../config'
|
|
6
6
|
import {requestOptions} from '../http/requestOptions'
|
|
@@ -231,6 +231,51 @@ export function _getDocuments<R extends Record<string, Any>>(
|
|
|
231
231
|
)
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
+
const DOCUMENTS_EXISTS_BATCH_SIZE = 100
|
|
235
|
+
|
|
236
|
+
/** @internal */
|
|
237
|
+
export function _documentsExists(
|
|
238
|
+
client: Client,
|
|
239
|
+
httpRequest: HttpRequest,
|
|
240
|
+
ids: string[],
|
|
241
|
+
opts: {signal?: AbortSignal; tag?: string} = {},
|
|
242
|
+
): Observable<Set<string>> {
|
|
243
|
+
if (ids.length === 0) {
|
|
244
|
+
return of(new Set<string>())
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const batches: string[][] = []
|
|
248
|
+
for (let i = 0; i < ids.length; i += DOCUMENTS_EXISTS_BATCH_SIZE) {
|
|
249
|
+
batches.push(ids.slice(i, i + DOCUMENTS_EXISTS_BATCH_SIZE))
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const fetchBatch = (batchIds: string[]) =>
|
|
253
|
+
_requestObservable<Any>(client, httpRequest, {
|
|
254
|
+
uri: _getDataUrl(client, 'doc', batchIds.map(encodeURIComponent).join(',')),
|
|
255
|
+
tag: opts.tag,
|
|
256
|
+
signal: opts.signal,
|
|
257
|
+
query: {excludeContent: true},
|
|
258
|
+
}).pipe(
|
|
259
|
+
filter(isResponse),
|
|
260
|
+
map((event: Any) => {
|
|
261
|
+
const missing = new Set<string>()
|
|
262
|
+
for (const omitted of event.body.omitted || []) {
|
|
263
|
+
if (omitted.reason !== 'existence') continue
|
|
264
|
+
missing.add(omitted.id)
|
|
265
|
+
}
|
|
266
|
+
return new Set(batchIds.filter((id) => !missing.has(id)))
|
|
267
|
+
}),
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
return from(batches).pipe(
|
|
271
|
+
concatMap(fetchBatch),
|
|
272
|
+
reduce((acc, set) => {
|
|
273
|
+
for (const id of set) acc.add(id)
|
|
274
|
+
return acc
|
|
275
|
+
}, new Set<string>()),
|
|
276
|
+
)
|
|
277
|
+
}
|
|
278
|
+
|
|
234
279
|
/** @internal */
|
|
235
280
|
export function _getReleaseDocuments<R extends Record<string, Any>>(
|
|
236
281
|
client: ObservableSanityClient | SanityClient,
|
|
@@ -598,6 +643,11 @@ export function _requestObservable<R>(
|
|
|
598
643
|
httpRequest: HttpRequest,
|
|
599
644
|
options: RequestObservableOptions,
|
|
600
645
|
): Observable<HttpRequestEvent<R>> {
|
|
646
|
+
// Capture the call-site error here, where the caller's code is still
|
|
647
|
+
// on the synchronous call stack, and pass it through to get-it so errors
|
|
648
|
+
// include the originating call site rather than just internal plumbing.
|
|
649
|
+
const callSiteStack = new Error()
|
|
650
|
+
|
|
601
651
|
const uri = options.url || (options.uri as string)
|
|
602
652
|
const config = client.config()
|
|
603
653
|
|
|
@@ -667,6 +717,7 @@ export function _requestObservable<R>(
|
|
|
667
717
|
config,
|
|
668
718
|
Object.assign({}, options, {
|
|
669
719
|
url: _getUrl(client, uri, useCdn),
|
|
720
|
+
callSiteStack,
|
|
670
721
|
}),
|
|
671
722
|
) as RequestOptions
|
|
672
723
|
|
package/src/data/eventsource.ts
CHANGED
|
@@ -5,11 +5,25 @@ import {type Any} from '../types'
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @public
|
|
8
|
-
* Thrown
|
|
9
|
-
*
|
|
8
|
+
* Thrown when the EventSource connection could not be established, or was rejected by the server.
|
|
9
|
+
* Transient failures (network drops, 5xx, 408, 429) are reconnected internally and emitted as
|
|
10
|
+
* `reconnect` events; a permanent rejection (any other 4xx, eg an expired token) errors the
|
|
11
|
+
* stream with this class so consumers can react — check `status` for the rejection code.
|
|
10
12
|
*/
|
|
11
13
|
export class ConnectionFailedError extends Error {
|
|
12
14
|
readonly name = 'ConnectionFailedError'
|
|
15
|
+
/**
|
|
16
|
+
* HTTP status code of the rejected connection attempt, if known.
|
|
17
|
+
* Only set when the EventSource implementation exposes it — the polyfill used in
|
|
18
|
+
* Node.js and when custom headers (eg authorization) are required does, while
|
|
19
|
+
* native EventSource implementations (browser and Node.js) do not.
|
|
20
|
+
*/
|
|
21
|
+
readonly status?: number
|
|
22
|
+
constructor(message?: string, options: ErrorOptions & {status?: number} = {}) {
|
|
23
|
+
const {status, ...errorOptions} = options
|
|
24
|
+
super(message, errorOptions)
|
|
25
|
+
this.status = status
|
|
26
|
+
}
|
|
13
27
|
}
|
|
14
28
|
|
|
15
29
|
/**
|
|
@@ -147,6 +161,18 @@ function connectWithESInstance<EventTypeName extends string>(
|
|
|
147
161
|
// automatically, but in some cases (like when a laptop lid is closed), it will trigger onError
|
|
148
162
|
// if it can't reconnect.
|
|
149
163
|
// see https://html.spec.whatwg.org/multipage/server-sent-events.html#sse-processing-model
|
|
164
|
+
// The polyfills expose the HTTP status of a rejected connection on the error event
|
|
165
|
+
// (native EventSource implementations do not). A status means the server rejected the
|
|
166
|
+
// connection attempt, so error out regardless of readyState — the polyfills disagree
|
|
167
|
+
// on whether the connection closes before or after the error event is dispatched —
|
|
168
|
+
// and let `reconnectOnConnectionFailure` classify it (4xx fatal, otherwise retried).
|
|
169
|
+
const rawStatus = (evt as {status?: unknown}).status
|
|
170
|
+
const status = typeof rawStatus === 'number' ? rawStatus : undefined
|
|
171
|
+
if (status !== undefined) {
|
|
172
|
+
observer.error(new ConnectionFailedError('EventSource connection failed', {status}))
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
|
|
150
176
|
if (es.readyState === es.CLOSED) {
|
|
151
177
|
// In these cases we'll signal to consumers (via the error path) that a retry/reconnect is needed.
|
|
152
178
|
observer.error(new ConnectionFailedError('EventSource connection failed'))
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
|
|
12
12
|
import {ConnectionFailedError} from './eventsource'
|
|
13
13
|
|
|
14
|
+
const RETRYABLE_STATUSES = new Set([408, 429])
|
|
15
|
+
|
|
14
16
|
/**
|
|
15
17
|
* Note: connection failure is not the same as network disconnect which may happen more frequent.
|
|
16
18
|
* The EventSource instance will automatically reconnect in case of a network disconnect, however,
|
|
@@ -20,7 +22,19 @@ export function reconnectOnConnectionFailure<T>(): OperatorFunction<T, T | {type
|
|
|
20
22
|
return function (source: Observable<T>) {
|
|
21
23
|
return source.pipe(
|
|
22
24
|
catchError((err, caught) => {
|
|
23
|
-
|
|
25
|
+
// Only reconnect on transient connection failures. A 4xx response is a
|
|
26
|
+
// rejection, not a transient failure — the server will keep rejecting
|
|
27
|
+
// (eg an expired token), so reconnecting would loop forever. The named
|
|
28
|
+
// exceptions are the explicitly transient 4xx statuses: 408 (request
|
|
29
|
+
// timeout) and 429 (rate limited). Anything else surfaces to the
|
|
30
|
+
// consumer instead.
|
|
31
|
+
if (
|
|
32
|
+
err instanceof ConnectionFailedError &&
|
|
33
|
+
(typeof err.status !== 'number' ||
|
|
34
|
+
err.status < 400 ||
|
|
35
|
+
err.status >= 500 ||
|
|
36
|
+
RETRYABLE_STATUSES.has(err.status))
|
|
37
|
+
) {
|
|
24
38
|
return concat(of({type: 'reconnect' as const}), timer(1000).pipe(mergeMap(() => caught)))
|
|
25
39
|
}
|
|
26
40
|
return throwError(() => err)
|