@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.d.cts CHANGED
@@ -907,11 +907,26 @@ export declare function connectEventSource<EventName extends string>(
907
907
 
908
908
  /**
909
909
  * @public
910
- * Thrown if the EventSource connection could not be established.
911
- * Note that ConnectionFailedErrors are rare, and disconnects will normally be handled by the EventSource instance itself and emitted as `reconnect` events.
910
+ * Thrown when the EventSource connection could not be established, or was rejected by the server.
911
+ * Transient failures (network drops, 5xx, 408, 429) are reconnected internally and emitted as
912
+ * `reconnect` events; a permanent rejection (any other 4xx, eg an expired token) errors the
913
+ * stream with this class so consumers can react — check `status` for the rejection code.
912
914
  */
913
915
  export declare class ConnectionFailedError extends Error {
914
916
  readonly name = 'ConnectionFailedError'
917
+ /**
918
+ * HTTP status code of the rejected connection attempt, if known.
919
+ * Only set when the EventSource implementation exposes it — the polyfill used in
920
+ * Node.js and when custom headers (eg authorization) are required does, while
921
+ * native EventSource implementations (browser and Node.js) do not.
922
+ */
923
+ readonly status?: number
924
+ constructor(
925
+ message?: string,
926
+ options?: ErrorOptions & {
927
+ status?: number
928
+ },
929
+ )
915
930
  }
916
931
 
917
932
  /**
@@ -3191,6 +3206,20 @@ export declare class ObservableSanityClient {
3191
3206
  tag?: string
3192
3207
  },
3193
3208
  ): Observable<(SanityDocument<R> | null)[]>
3209
+ /**
3210
+ * Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
3211
+ * Returns a set of the IDs that exist.
3212
+ *
3213
+ * @param ids - Document IDs to check
3214
+ * @param options - Request options
3215
+ */
3216
+ documentsExists(
3217
+ ids: string[],
3218
+ options?: {
3219
+ signal?: AbortSignal
3220
+ tag?: string
3221
+ },
3222
+ ): Observable<Set<string>>
3194
3223
  /**
3195
3224
  * Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
3196
3225
  * Returns an observable that resolves to the created document.
@@ -5102,6 +5131,20 @@ export declare class SanityClient {
5102
5131
  tag?: string
5103
5132
  },
5104
5133
  ): Promise<(SanityDocument<R> | null)[]>
5134
+ /**
5135
+ * Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
5136
+ * Returns a set of the IDs that exist.
5137
+ *
5138
+ * @param ids - Document IDs to check
5139
+ * @param options - Request options
5140
+ */
5141
+ documentsExists(
5142
+ ids: string[],
5143
+ options?: {
5144
+ signal?: AbortSignal
5145
+ tag?: string
5146
+ },
5147
+ ): Promise<Set<string>>
5105
5148
  /**
5106
5149
  * Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
5107
5150
  * Returns a promise that resolves to the created document.
package/dist/index.d.ts CHANGED
@@ -907,11 +907,26 @@ export declare function connectEventSource<EventName extends string>(
907
907
 
908
908
  /**
909
909
  * @public
910
- * Thrown if the EventSource connection could not be established.
911
- * Note that ConnectionFailedErrors are rare, and disconnects will normally be handled by the EventSource instance itself and emitted as `reconnect` events.
910
+ * Thrown when the EventSource connection could not be established, or was rejected by the server.
911
+ * Transient failures (network drops, 5xx, 408, 429) are reconnected internally and emitted as
912
+ * `reconnect` events; a permanent rejection (any other 4xx, eg an expired token) errors the
913
+ * stream with this class so consumers can react — check `status` for the rejection code.
912
914
  */
913
915
  export declare class ConnectionFailedError extends Error {
914
916
  readonly name = 'ConnectionFailedError'
917
+ /**
918
+ * HTTP status code of the rejected connection attempt, if known.
919
+ * Only set when the EventSource implementation exposes it — the polyfill used in
920
+ * Node.js and when custom headers (eg authorization) are required does, while
921
+ * native EventSource implementations (browser and Node.js) do not.
922
+ */
923
+ readonly status?: number
924
+ constructor(
925
+ message?: string,
926
+ options?: ErrorOptions & {
927
+ status?: number
928
+ },
929
+ )
915
930
  }
916
931
 
917
932
  /**
@@ -3191,6 +3206,20 @@ export declare class ObservableSanityClient {
3191
3206
  tag?: string
3192
3207
  },
3193
3208
  ): Observable<(SanityDocument<R> | null)[]>
3209
+ /**
3210
+ * Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
3211
+ * Returns a set of the IDs that exist.
3212
+ *
3213
+ * @param ids - Document IDs to check
3214
+ * @param options - Request options
3215
+ */
3216
+ documentsExists(
3217
+ ids: string[],
3218
+ options?: {
3219
+ signal?: AbortSignal
3220
+ tag?: string
3221
+ },
3222
+ ): Observable<Set<string>>
3194
3223
  /**
3195
3224
  * Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
3196
3225
  * Returns an observable that resolves to the created document.
@@ -5102,6 +5131,20 @@ export declare class SanityClient {
5102
5131
  tag?: string
5103
5132
  },
5104
5133
  ): Promise<(SanityDocument<R> | null)[]>
5134
+ /**
5135
+ * Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
5136
+ * Returns a set of the IDs that exist.
5137
+ *
5138
+ * @param ids - Document IDs to check
5139
+ * @param options - Request options
5140
+ */
5141
+ documentsExists(
5142
+ ids: string[],
5143
+ options?: {
5144
+ signal?: AbortSignal
5145
+ tag?: string
5146
+ },
5147
+ ): Promise<Set<string>>
5105
5148
  /**
5106
5149
  * Create a document. Requires a `_type` property. If no `_id` is provided, it will be generated by the database.
5107
5150
  * Returns a promise that resolves to the created document.
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { retry, jsonRequest, jsonResponse, progress, observable, debug, headers,
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 } from "./_chunks-es/isRecord.js";
6
6
  import { stegaClean } from "./_chunks-es/stegaClean.js";
7
- import { combineLatestWith, map, filter, finalize as finalize$1 } from "rxjs/operators";
7
+ import { combineLatestWith, map, filter, concatMap, reduce, finalize as finalize$1 } from "rxjs/operators";
8
8
  import { getVersionFromId, isDraftId, getVersionId, getDraftId, isVersionId, getPublishedId } from "@sanity/client/csm";
9
9
  import { customAlphabet } from "nanoid";
10
10
  import { validateObject, validateInsert, requireDocumentId, validateDocumentId, requireDocumentType, printCreateVersionWithBaseIdWarning, resourceConfig, hasDataset, requestTag, printPreviewDraftsDeprecationWarning, validateApiPerspective, printCdnPreviewDraftsWarning, validateAssetType, resourceGuard, dataset, validateVersionIdMatch, defaultConfig, initConfig, printNoDefaultExport } from "./_chunks-es/config.js";
@@ -223,6 +223,17 @@ function shouldRetry(err, attempt, options) {
223
223
  const EXPERIMENTAL_API_WARNING = "This is an experimental API version";
224
224
  class ConnectionFailedError extends Error {
225
225
  name = "ConnectionFailedError";
226
+ /**
227
+ * HTTP status code of the rejected connection attempt, if known.
228
+ * Only set when the EventSource implementation exposes it — the polyfill used in
229
+ * Node.js and when custom headers (eg authorization) are required does, while
230
+ * native EventSource implementations (browser and Node.js) do not.
231
+ */
232
+ status;
233
+ constructor(message, options = {}) {
234
+ const { status, ...errorOptions } = options;
235
+ super(message, errorOptions), this.status = status;
236
+ }
226
237
  }
227
238
  class DisconnectError extends Error {
228
239
  name = "DisconnectError";
@@ -266,6 +277,11 @@ function connectWithESInstance(es, events) {
266
277
  );
267
278
  return;
268
279
  }
280
+ const rawStatus = evt.status, status = typeof rawStatus == "number" ? rawStatus : void 0;
281
+ if (status !== void 0) {
282
+ observer.error(new ConnectionFailedError("EventSource connection failed", { status }));
283
+ return;
284
+ }
269
285
  es.readyState === es.CLOSED ? observer.error(new ConnectionFailedError("EventSource connection failed")) : emitReconnect && observer.next({ type: "reconnect" });
270
286
  }
271
287
  function onOpen() {
@@ -783,6 +799,35 @@ function _getDocuments(client, httpRequest, ids, opts = {}) {
783
799
  })
784
800
  );
785
801
  }
802
+ const DOCUMENTS_EXISTS_BATCH_SIZE = 100;
803
+ function _documentsExists(client, httpRequest, ids, opts = {}) {
804
+ if (ids.length === 0)
805
+ return of(/* @__PURE__ */ new Set());
806
+ const batches = [];
807
+ for (let i = 0; i < ids.length; i += DOCUMENTS_EXISTS_BATCH_SIZE)
808
+ batches.push(ids.slice(i, i + DOCUMENTS_EXISTS_BATCH_SIZE));
809
+ const fetchBatch = (batchIds) => _requestObservable(client, httpRequest, {
810
+ uri: _getDataUrl(client, "doc", batchIds.map(encodeURIComponent).join(",")),
811
+ tag: opts.tag,
812
+ signal: opts.signal,
813
+ query: { excludeContent: !0 }
814
+ }).pipe(
815
+ filter(isResponse),
816
+ map((event) => {
817
+ const missing = /* @__PURE__ */ new Set();
818
+ for (const omitted of event.body.omitted || [])
819
+ omitted.reason === "existence" && missing.add(omitted.id);
820
+ return new Set(batchIds.filter((id) => !missing.has(id)));
821
+ })
822
+ );
823
+ return from(batches).pipe(
824
+ concatMap(fetchBatch),
825
+ reduce((acc, set) => {
826
+ for (const id of set) acc.add(id);
827
+ return acc;
828
+ }, /* @__PURE__ */ new Set())
829
+ );
830
+ }
786
831
  function _getReleaseDocuments(client, httpRequest, releaseId, opts = {}) {
787
832
  return _dataRequest(
788
833
  client,
@@ -919,7 +964,7 @@ const hasDataConfig = (client) => {
919
964
  return config.dataset !== void 0 && config.projectId !== void 0 || config.resource !== void 0;
920
965
  }, 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);
921
966
  function _requestObservable(client, httpRequest, options) {
922
- 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;
967
+ 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;
923
968
  let useCdn = (options.useCdn ?? config.useCdn) && canUseCdn;
924
969
  const tag = options.tag && config.requestTagPrefix ? [config.requestTagPrefix, options.tag].join(".") : options.tag || config.requestTagPrefix;
925
970
  if (tag && options.tag !== null && (options.query = { tag: requestTag(tag), ...options.query }), ["GET", "HEAD", "POST"].indexOf(options.method || "GET") >= 0 && isQuery(client, uri)) {
@@ -935,7 +980,8 @@ function _requestObservable(client, httpRequest, options) {
935
980
  const reqOptions = requestOptions(
936
981
  config,
937
982
  Object.assign({}, options, {
938
- url: _getUrl(client, uri, useCdn)
983
+ url: _getUrl(client, uri, useCdn),
984
+ callSiteStack
939
985
  })
940
986
  ), request = new Observable(
941
987
  (subscriber) => httpRequest(reqOptions, config.requester).subscribe(subscriber)
@@ -1205,11 +1251,11 @@ var defaults = (obj, defaults2) => Object.keys(defaults2).concat(Object.keys(obj
1205
1251
  const pick = (obj, props) => props.reduce((selection, prop) => (typeof obj[prop] > "u" || (selection[prop] = obj[prop]), selection), {}), eventSourcePolyfill = defer(() => import("@sanity/eventsource")).pipe(
1206
1252
  map(({ default: EventSource2 }) => EventSource2),
1207
1253
  shareReplay(1)
1208
- );
1254
+ ), RETRYABLE_STATUSES = /* @__PURE__ */ new Set([408, 429]);
1209
1255
  function reconnectOnConnectionFailure() {
1210
1256
  return function(source) {
1211
1257
  return source.pipe(
1212
- catchError((err, caught) => err instanceof ConnectionFailedError ? concat(of({ type: "reconnect" }), timer(1e3).pipe(mergeMap(() => caught))) : throwError(() => err))
1258
+ 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))
1213
1259
  );
1214
1260
  };
1215
1261
  }
@@ -2289,6 +2335,16 @@ class ObservableSanityClient {
2289
2335
  getDocuments(ids, options) {
2290
2336
  return _getDocuments(this, this.#httpRequest, ids, options);
2291
2337
  }
2338
+ /**
2339
+ * Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
2340
+ * Returns a set of the IDs that exist.
2341
+ *
2342
+ * @param ids - Document IDs to check
2343
+ * @param options - Request options
2344
+ */
2345
+ documentsExists(ids, options) {
2346
+ return _documentsExists(this, this.#httpRequest, ids, options);
2347
+ }
2292
2348
  create(document, options) {
2293
2349
  return _create(this, this.#httpRequest, document, "create", options);
2294
2350
  }
@@ -2566,6 +2622,16 @@ class SanityClient {
2566
2622
  getDocuments(ids, options) {
2567
2623
  return lastValueFrom(_getDocuments(this, this.#httpRequest, ids, options));
2568
2624
  }
2625
+ /**
2626
+ * Convenient and bandwidth efficient method of checking wether a set of document IDs exists.
2627
+ * Returns a set of the IDs that exist.
2628
+ *
2629
+ * @param ids - Document IDs to check
2630
+ * @param options - Request options
2631
+ */
2632
+ documentsExists(ids, options) {
2633
+ return lastValueFrom(_documentsExists(this, this.#httpRequest, ids, options));
2634
+ }
2569
2635
  create(document, options) {
2570
2636
  return lastValueFrom(
2571
2637
  _create(this, this.#httpRequest, document, "create", options)
@@ -2788,7 +2854,7 @@ function defineDeprecatedCreateClient(createClient2) {
2788
2854
  return printNoDefaultExport(), createClient2(config);
2789
2855
  };
2790
2856
  }
2791
- var name = "@sanity/client", version = "7.22.1";
2857
+ var name = "@sanity/client", version = "7.23.1";
2792
2858
  const middleware = [
2793
2859
  debug({ verbose: !0, namespace: "sanity:client" }),
2794
2860
  headers({ "User-Agent": `${name} ${version}` }),