@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.
@@ -914,11 +914,26 @@ export declare function connectEventSource<EventName extends string>(
914
914
 
915
915
  /**
916
916
  * @public
917
- * Thrown if the EventSource connection could not be established.
918
- * Note that ConnectionFailedErrors are rare, and disconnects will normally be handled by the EventSource instance itself and emitted as `reconnect` events.
917
+ * Thrown when the EventSource connection could not be established, or was rejected by the server.
918
+ * Transient failures (network drops, 5xx, 408, 429) are reconnected internally and emitted as
919
+ * `reconnect` events; a permanent rejection (any other 4xx, eg an expired token) errors the
920
+ * stream with this class so consumers can react — check `status` for the rejection code.
919
921
  */
920
922
  export declare class ConnectionFailedError extends Error {
921
923
  readonly name = 'ConnectionFailedError'
924
+ /**
925
+ * HTTP status code of the rejected connection attempt, if known.
926
+ * Only set when the EventSource implementation exposes it — the polyfill used in
927
+ * Node.js and when custom headers (eg authorization) are required does, while
928
+ * native EventSource implementations (browser and Node.js) do not.
929
+ */
930
+ readonly status?: number
931
+ constructor(
932
+ message?: string,
933
+ options?: ErrorOptions & {
934
+ status?: number
935
+ },
936
+ )
922
937
  }
923
938
 
924
939
  /**
@@ -3199,6 +3214,20 @@ export declare class ObservableSanityClient {
3199
3214
  tag?: string
3200
3215
  },
3201
3216
  ): Observable<(SanityDocument<R> | null)[]>
3217
+ /**
3218
+ * Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
3219
+ * Returns a set of the IDs that exist.
3220
+ *
3221
+ * @param ids - Document IDs to check
3222
+ * @param options - Request options
3223
+ */
3224
+ documentsExists(
3225
+ ids: string[],
3226
+ options?: {
3227
+ signal?: AbortSignal
3228
+ tag?: string
3229
+ },
3230
+ ): Observable<Set<string>>
3202
3231
  /**
3203
3232
  * Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
3204
3233
  * Returns an observable that resolves to the created document.
@@ -5110,6 +5139,20 @@ export declare class SanityClient {
5110
5139
  tag?: string
5111
5140
  },
5112
5141
  ): Promise<(SanityDocument<R> | null)[]>
5142
+ /**
5143
+ * Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
5144
+ * Returns a set of the IDs that exist.
5145
+ *
5146
+ * @param ids - Document IDs to check
5147
+ * @param options - Request options
5148
+ */
5149
+ documentsExists(
5150
+ ids: string[],
5151
+ options?: {
5152
+ signal?: AbortSignal
5153
+ tag?: string
5154
+ },
5155
+ ): Promise<Set<string>>
5113
5156
  /**
5114
5157
  * Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
5115
5158
  * Returns a promise that resolves to the created document.
@@ -914,11 +914,26 @@ export declare function connectEventSource<EventName extends string>(
914
914
 
915
915
  /**
916
916
  * @public
917
- * Thrown if the EventSource connection could not be established.
918
- * Note that ConnectionFailedErrors are rare, and disconnects will normally be handled by the EventSource instance itself and emitted as `reconnect` events.
917
+ * Thrown when the EventSource connection could not be established, or was rejected by the server.
918
+ * Transient failures (network drops, 5xx, 408, 429) are reconnected internally and emitted as
919
+ * `reconnect` events; a permanent rejection (any other 4xx, eg an expired token) errors the
920
+ * stream with this class so consumers can react — check `status` for the rejection code.
919
921
  */
920
922
  export declare class ConnectionFailedError extends Error {
921
923
  readonly name = 'ConnectionFailedError'
924
+ /**
925
+ * HTTP status code of the rejected connection attempt, if known.
926
+ * Only set when the EventSource implementation exposes it — the polyfill used in
927
+ * Node.js and when custom headers (eg authorization) are required does, while
928
+ * native EventSource implementations (browser and Node.js) do not.
929
+ */
930
+ readonly status?: number
931
+ constructor(
932
+ message?: string,
933
+ options?: ErrorOptions & {
934
+ status?: number
935
+ },
936
+ )
922
937
  }
923
938
 
924
939
  /**
@@ -3199,6 +3214,20 @@ export declare class ObservableSanityClient {
3199
3214
  tag?: string
3200
3215
  },
3201
3216
  ): Observable<(SanityDocument<R> | null)[]>
3217
+ /**
3218
+ * Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
3219
+ * Returns a set of the IDs that exist.
3220
+ *
3221
+ * @param ids - Document IDs to check
3222
+ * @param options - Request options
3223
+ */
3224
+ documentsExists(
3225
+ ids: string[],
3226
+ options?: {
3227
+ signal?: AbortSignal
3228
+ tag?: string
3229
+ },
3230
+ ): Observable<Set<string>>
3202
3231
  /**
3203
3232
  * Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
3204
3233
  * Returns an observable that resolves to the created document.
@@ -5110,6 +5139,20 @@ export declare class SanityClient {
5110
5139
  tag?: string
5111
5140
  },
5112
5141
  ): Promise<(SanityDocument<R> | null)[]>
5142
+ /**
5143
+ * Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
5144
+ * Returns a set of the IDs that exist.
5145
+ *
5146
+ * @param ids - Document IDs to check
5147
+ * @param options - Request options
5148
+ */
5149
+ documentsExists(
5150
+ ids: string[],
5151
+ options?: {
5152
+ signal?: AbortSignal
5153
+ tag?: string
5154
+ },
5155
+ ): Promise<Set<string>>
5113
5156
  /**
5114
5157
  * Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
5115
5158
  * Returns a promise that resolves to the created document.
@@ -3,7 +3,7 @@ import { adapter, environment } from "get-it";
3
3
  import { retry, jsonRequest, jsonResponse, progress, observable } from "get-it/middleware";
4
4
  import { Observable, defer, isObservable, of, mergeMap, from, lastValueFrom, shareReplay, catchError, concat, timer, throwError, tap, finalize, share, merge, map as map$1, firstValueFrom } from "rxjs";
5
5
  import { isRecord, stegaClean } from "./_chunks-es/stegaClean.js";
6
- import { combineLatestWith, map, filter, finalize as finalize$1 } from "rxjs/operators";
6
+ import { combineLatestWith, map, filter, concatMap, reduce, finalize as finalize$1 } from "rxjs/operators";
7
7
  import { getVersionFromId, isDraftId, getVersionId, getDraftId, isVersionId, getPublishedId } from "@sanity/client/csm";
8
8
  import { customAlphabet } from "nanoid";
9
9
  const NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
@@ -405,6 +405,17 @@ const initConfig = (config, prevConfig) => {
405
405
  };
406
406
  class ConnectionFailedError extends Error {
407
407
  name = "ConnectionFailedError";
408
+ /**
409
+ * HTTP status code of the rejected connection attempt, if known.
410
+ * Only set when the EventSource implementation exposes it — the polyfill used in
411
+ * Node.js and when custom headers (eg authorization) are required does, while
412
+ * native EventSource implementations (browser and Node.js) do not.
413
+ */
414
+ status;
415
+ constructor(message, options = {}) {
416
+ const { status, ...errorOptions } = options;
417
+ super(message, errorOptions), this.status = status;
418
+ }
408
419
  }
409
420
  class DisconnectError extends Error {
410
421
  name = "DisconnectError";
@@ -448,6 +459,11 @@ function connectWithESInstance(es, events) {
448
459
  );
449
460
  return;
450
461
  }
462
+ const rawStatus = evt.status, status = typeof rawStatus == "number" ? rawStatus : void 0;
463
+ if (status !== void 0) {
464
+ observer.error(new ConnectionFailedError("EventSource connection failed", { status }));
465
+ return;
466
+ }
451
467
  es.readyState === es.CLOSED ? observer.error(new ConnectionFailedError("EventSource connection failed")) : emitReconnect && observer.next({ type: "reconnect" });
452
468
  }
453
469
  function onOpen() {
@@ -965,6 +981,35 @@ function _getDocuments(client, httpRequest, ids, opts = {}) {
965
981
  })
966
982
  );
967
983
  }
984
+ const DOCUMENTS_EXISTS_BATCH_SIZE = 100;
985
+ function _documentsExists(client, httpRequest, ids, opts = {}) {
986
+ if (ids.length === 0)
987
+ return of(/* @__PURE__ */ new Set());
988
+ const batches = [];
989
+ for (let i = 0; i < ids.length; i += DOCUMENTS_EXISTS_BATCH_SIZE)
990
+ batches.push(ids.slice(i, i + DOCUMENTS_EXISTS_BATCH_SIZE));
991
+ const fetchBatch = (batchIds) => _requestObservable(client, httpRequest, {
992
+ uri: _getDataUrl(client, "doc", batchIds.map(encodeURIComponent).join(",")),
993
+ tag: opts.tag,
994
+ signal: opts.signal,
995
+ query: { excludeContent: !0 }
996
+ }).pipe(
997
+ filter(isResponse),
998
+ map((event) => {
999
+ const missing = /* @__PURE__ */ new Set();
1000
+ for (const omitted of event.body.omitted || [])
1001
+ omitted.reason === "existence" && missing.add(omitted.id);
1002
+ return new Set(batchIds.filter((id) => !missing.has(id)));
1003
+ })
1004
+ );
1005
+ return from(batches).pipe(
1006
+ concatMap(fetchBatch),
1007
+ reduce((acc, set) => {
1008
+ for (const id of set) acc.add(id);
1009
+ return acc;
1010
+ }, /* @__PURE__ */ new Set())
1011
+ );
1012
+ }
968
1013
  function _getReleaseDocuments(client, httpRequest, releaseId, opts = {}) {
969
1014
  return _dataRequest(
970
1015
  client,
@@ -1101,7 +1146,7 @@ const hasDataConfig = (client) => {
1101
1146
  return config.dataset !== void 0 && config.projectId !== void 0 || config.resource !== void 0;
1102
1147
  }, isQuery = (client, uri) => hasDataConfig(client) && uri.startsWith(_getDataUrl(client, "query")), isMutate = (client, uri) => hasDataConfig(client) && uri.startsWith(_getDataUrl(client, "mutate")), isDoc = (client, uri) => hasDataConfig(client) && uri.startsWith(_getDataUrl(client, "doc", "")), isListener = (client, uri) => hasDataConfig(client) && uri.startsWith(_getDataUrl(client, "listen")), isHistory = (client, uri) => hasDataConfig(client) && uri.startsWith(_getDataUrl(client, "history", "")), isData = (client, uri) => uri.startsWith("/data/") || isQuery(client, uri) || isMutate(client, uri) || isDoc(client, uri) || isListener(client, uri) || isHistory(client, uri);
1103
1148
  function _requestObservable(client, httpRequest, options) {
1104
- const uri = options.url || options.uri, config = client.config(), canUseCdn = typeof options.canUseCdn > "u" ? ["GET", "HEAD"].indexOf(options.method || "GET") >= 0 && isData(client, uri) : options.canUseCdn;
1149
+ const callSiteStack = new Error(), uri = options.url || options.uri, config = client.config(), canUseCdn = typeof options.canUseCdn > "u" ? ["GET", "HEAD"].indexOf(options.method || "GET") >= 0 && isData(client, uri) : options.canUseCdn;
1105
1150
  let useCdn = (options.useCdn ?? config.useCdn) && canUseCdn;
1106
1151
  const tag = options.tag && config.requestTagPrefix ? [config.requestTagPrefix, options.tag].join(".") : options.tag || config.requestTagPrefix;
1107
1152
  if (tag && options.tag !== null && (options.query = { tag: requestTag(tag), ...options.query }), ["GET", "HEAD", "POST"].indexOf(options.method || "GET") >= 0 && isQuery(client, uri)) {
@@ -1117,7 +1162,8 @@ function _requestObservable(client, httpRequest, options) {
1117
1162
  const reqOptions = requestOptions(
1118
1163
  config,
1119
1164
  Object.assign({}, options, {
1120
- url: _getUrl(client, uri, useCdn)
1165
+ url: _getUrl(client, uri, useCdn),
1166
+ callSiteStack
1121
1167
  })
1122
1168
  ), request = new Observable(
1123
1169
  (subscriber) => httpRequest(reqOptions, config.requester).subscribe(subscriber)
@@ -1387,11 +1433,11 @@ var defaults = (obj, defaults2) => Object.keys(defaults2).concat(Object.keys(obj
1387
1433
  const pick = (obj, props) => props.reduce((selection, prop) => (typeof obj[prop] > "u" || (selection[prop] = obj[prop]), selection), {}), eventSourcePolyfill = defer(() => import("@sanity/eventsource")).pipe(
1388
1434
  map(({ default: EventSource2 }) => EventSource2),
1389
1435
  shareReplay(1)
1390
- );
1436
+ ), RETRYABLE_STATUSES = /* @__PURE__ */ new Set([408, 429]);
1391
1437
  function reconnectOnConnectionFailure() {
1392
1438
  return function(source) {
1393
1439
  return source.pipe(
1394
- catchError((err, caught) => err instanceof ConnectionFailedError ? concat(of({ type: "reconnect" }), timer(1e3).pipe(mergeMap(() => caught))) : throwError(() => err))
1440
+ catchError((err, caught) => err instanceof ConnectionFailedError && (typeof err.status != "number" || err.status < 400 || err.status >= 500 || RETRYABLE_STATUSES.has(err.status)) ? concat(of({ type: "reconnect" }), timer(1e3).pipe(mergeMap(() => caught))) : throwError(() => err))
1395
1441
  );
1396
1442
  };
1397
1443
  }
@@ -2471,6 +2517,16 @@ class ObservableSanityClient {
2471
2517
  getDocuments(ids, options) {
2472
2518
  return _getDocuments(this, this.#httpRequest, ids, options);
2473
2519
  }
2520
+ /**
2521
+ * Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
2522
+ * Returns a set of the IDs that exist.
2523
+ *
2524
+ * @param ids - Document IDs to check
2525
+ * @param options - Request options
2526
+ */
2527
+ documentsExists(ids, options) {
2528
+ return _documentsExists(this, this.#httpRequest, ids, options);
2529
+ }
2474
2530
  create(document, options) {
2475
2531
  return _create(this, this.#httpRequest, document, "create", options);
2476
2532
  }
@@ -2748,6 +2804,16 @@ class SanityClient {
2748
2804
  getDocuments(ids, options) {
2749
2805
  return lastValueFrom(_getDocuments(this, this.#httpRequest, ids, options));
2750
2806
  }
2807
+ /**
2808
+ * Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
2809
+ * Returns a set of the IDs that exist.
2810
+ *
2811
+ * @param ids - Document IDs to check
2812
+ * @param options - Request options
2813
+ */
2814
+ documentsExists(ids, options) {
2815
+ return lastValueFrom(_documentsExists(this, this.#httpRequest, ids, options));
2816
+ }
2751
2817
  create(document, options) {
2752
2818
  return lastValueFrom(
2753
2819
  _create(this, this.#httpRequest, document, "create", options)