@sanity/client 7.10.0 → 7.11.0-cors-check.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/README.md CHANGED
@@ -142,6 +142,9 @@ export async function updateDocumentTitle(_id, title) {
142
142
  - [Example: Storing language in a field](#example-storing-language-in-a-field)
143
143
  - [Prompt the LLM](#prompt-the-llm)
144
144
  - [Patch with a schema-aware API](#patch-with-a-schema-aware-api)
145
+ - [Media Library API](#media-library-api)
146
+ - [Getting video playback information](#getting-video-playback-information)
147
+ - [Working with signed playback information](#working-with-signed-playback-information)
145
148
  - [License](#license)
146
149
  - [From `v5`](#from-v5)
147
150
  - [The default `useCdn` is changed to `true`](#the-default-usecdn-is-changed-to-true)
@@ -2273,6 +2276,104 @@ const result = await client.agent.action.patch({
2273
2276
  })
2274
2277
  ```
2275
2278
 
2279
+ ### Media Library API
2280
+
2281
+ The Media Library provides centralized asset management for your organization. Store, organize, and manage digital assets across multiple applications and datasets with programmatic access through the `client.mediaLibrary` interface.
2282
+
2283
+ 👉 Read more about [Media Library in Sanity](https://www.sanity.io/docs/media-library)
2284
+
2285
+ #### Getting video playback information
2286
+
2287
+ ```js
2288
+ const client = createClient({
2289
+ token: 'valid-token',
2290
+ useCdn: false,
2291
+ '~experimental_resource': {
2292
+ type: 'media-library',
2293
+ id: 'mediaLibraryId',
2294
+ },
2295
+ })
2296
+
2297
+ // Basic usage with video asset ID
2298
+ const playbackInfo = await client.mediaLibrary.video.getPlaybackInfo('video-30rh9U3GDEK3ToiId1Zje4uvalC-mp4')
2299
+
2300
+ // With transformations
2301
+ const playbackInfo = await client.mediaLibrary.video.getPlaybackInfo('video-30rh9U3GDEK3ToiId1Zje4uvalC-mp4', {
2302
+ transformations: {
2303
+ thumbnail: { width: 300, format: 'webp', fit: 'smartcrop' },
2304
+ animated: { width: 200, fps: 15, format: 'webp' }
2305
+ },
2306
+ expiration: 3600 // seconds
2307
+ })
2308
+
2309
+ // Using Global Dataset Reference (GDR)
2310
+ const playbackInfo = await client.mediaLibrary.video.getPlaybackInfo({
2311
+ _ref: 'media-library:mlZxz9rvqf76:30rh9U3GDEK3ToiId1Zje4uvalC'
2312
+ })
2313
+ ```
2314
+
2315
+ The response contains playback URLs and metadata:
2316
+
2317
+ ```js
2318
+ // Public playback response
2319
+ {
2320
+ id: "30rh9U3GDEK3ToiId1Zje4uvalC",
2321
+ stream: { url: "https://stream.m.sanity-cdn.com/..." },
2322
+ thumbnail: { url: "https://image.m.sanity-cdn.com/..." },
2323
+ animated: { url: "https://image.m.sanity-cdn.com/..." },
2324
+ storyboard: { url: "https://storyboard.m.sanity-cdn.com/..." },
2325
+ duration: 120.5,
2326
+ aspectRatio: 1.77
2327
+ }
2328
+
2329
+ // Signed playback response (when video requires authentication)
2330
+ {
2331
+ id: "30rh9U3GDEK3ToiId1Zje4uvalC",
2332
+ stream: {
2333
+ url: "https://stream.m.sanity-cdn.com/...",
2334
+ token: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
2335
+ },
2336
+ thumbnail: {
2337
+ url: "https://image.m.sanity-cdn.com/...",
2338
+ token: "eyJ0a2VuIjoiVGh1bWJuYWlsVG9rZW4tMTIz..."
2339
+ },
2340
+ animated: {
2341
+ url: "https://image.m.sanity-cdn.com/...",
2342
+ token: "eyJ0a2VuIjoiQW5pbWF0ZWRUb2tlbi1kZWY..."
2343
+ },
2344
+ storyboard: {
2345
+ url: "https://storyboard.m.sanity-cdn.com/...",
2346
+ token: "eyJ0a2VuIjoiU3Rvcnlib2FyZFRva2VuLTc4..."
2347
+ },
2348
+ duration: 120.5,
2349
+ aspectRatio: 1.77
2350
+ }
2351
+ ```
2352
+
2353
+ #### Working with signed playback information
2354
+
2355
+ ```js
2356
+ import {getPlaybackTokens, isSignedPlaybackInfo} from '@sanity/client/media-library'
2357
+
2358
+ const playbackInfo = await client.mediaLibrary.video.getPlaybackInfo('video-30rh9U3GDEK3ToiId1Zje4uvalC-mp4')
2359
+
2360
+ // Check if the response requires signed URLs
2361
+ if (isSignedPlaybackInfo(playbackInfo)) {
2362
+ // Extract tokens for use with video players
2363
+ const tokens = getPlaybackTokens(playbackInfo)
2364
+ console.log(tokens)
2365
+ // {
2366
+ // stream: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
2367
+ // thumbnail: "eyJ0a2VuIjoiVGh1bWJuYWlsVG9rZW4tMTIz...",
2368
+ // animated: "eyJ0a2VuIjoiQW5pbWF0ZWRUb2tlbi1kZWY...",
2369
+ // storyboard: "eyJ0a2VuIjoiU3Rvcnlib2FyZFRva2VuLTc4..."
2370
+ // }
2371
+
2372
+ // Use with Mux Player or other compatible players
2373
+ // The tokens authenticate access to the video resources
2374
+ }
2375
+ ```
2376
+
2276
2377
  ## License
2277
2378
 
2278
2379
  MIT © [Sanity.io](https://www.sanity.io/)
@@ -929,11 +929,19 @@ function _getDocument(client, httpRequest, id, opts = {}) {
929
929
  uri: _getDataUrl(client, "doc", docId),
930
930
  json: !0,
931
931
  tag: opts.tag,
932
- signal: opts.signal
932
+ signal: opts.signal,
933
+ query: opts.includeAllVersions !== void 0 ? { includeAllVersions: opts.includeAllVersions } : void 0
933
934
  };
934
- return _requestObservable(client, httpRequest, options).pipe(
935
+ return _requestObservable(
936
+ client,
937
+ httpRequest,
938
+ options
939
+ ).pipe(
935
940
  operators.filter(isResponse),
936
- operators.map((event) => event.body.documents && event.body.documents[0])
941
+ operators.map((event) => {
942
+ const documents = event.body.documents;
943
+ return documents ? opts.includeAllVersions ? documents : documents[0] : opts.includeAllVersions ? [] : void 0;
944
+ })
937
945
  );
938
946
  }
939
947
  function _getDocuments(client, httpRequest, ids, opts = {}) {
@@ -1473,26 +1481,31 @@ class LiveClient {
1473
1481
  "welcome",
1474
1482
  "reconnect",
1475
1483
  "goaway"
1476
- ]).pipe(
1477
- reconnectOnConnectionFailure(),
1478
- operators.map((event) => {
1479
- if (event.type === "message") {
1480
- const { data, ...rest } = event;
1481
- return { ...rest, tags: data.tags };
1482
- }
1483
- return event;
1484
- })
1485
- ), checkCors = fetchObservable(url, {
1484
+ ]), checkCors$ = fetchObservable(url, {
1486
1485
  method: "OPTIONS",
1487
1486
  mode: "cors",
1488
1487
  credentials: esOptions.withCredentials ? "include" : "omit",
1489
1488
  headers: esOptions.headers
1490
1489
  }).pipe(
1491
- rxjs.mergeMap(() => rxjs.EMPTY),
1492
1490
  rxjs.catchError(() => {
1493
1491
  throw new CorsOriginError({ projectId: projectId2 });
1492
+ }),
1493
+ operators.shareReplay(1)
1494
+ // run only once
1495
+ ), observable = events.pipe(
1496
+ // Do our best to detect CORS errors first
1497
+ rxjs.catchError((err) => checkCors$.pipe(rxjs.mergeMap(() => {
1498
+ throw err;
1499
+ }))),
1500
+ reconnectOnConnectionFailure(),
1501
+ operators.map((event) => {
1502
+ if (event.type === "message") {
1503
+ const { data, ...rest } = event;
1504
+ return { ...rest, tags: data.tags };
1505
+ }
1506
+ return event;
1494
1507
  })
1495
- ), observable = rxjs.concat(checkCors, events).pipe(
1508
+ ).pipe(
1496
1509
  operators.finalize(() => eventsCache.delete(key)),
1497
1510
  shareReplayLatest({
1498
1511
  predicate: (event) => event.type === "welcome"
@@ -1616,6 +1629,80 @@ function _modify(client, httpRequest, method, name, options) {
1616
1629
  tag: null
1617
1630
  });
1618
1631
  }
1632
+ class ObservableMediaLibraryVideoClient {
1633
+ #client;
1634
+ #httpRequest;
1635
+ constructor(client, httpRequest) {
1636
+ this.#client = client, this.#httpRequest = httpRequest;
1637
+ }
1638
+ /**
1639
+ * Get video playback information for a media library asset
1640
+ *
1641
+ * @param assetIdentifier - Asset instance identifier (GDR, video-prefixed ID, or container ID)
1642
+ * @param options - Options for transformations and expiration
1643
+ */
1644
+ getPlaybackInfo(assetIdentifier, options = {}) {
1645
+ const configMediaLibraryId = this.#client.config()["~experimental_resource"]?.id, { instanceId, libraryId } = parseAssetInstanceId(assetIdentifier), effectiveLibraryId = libraryId || configMediaLibraryId;
1646
+ if (!effectiveLibraryId)
1647
+ throw new Error(
1648
+ "Could not determine Media Library ID - you need to provide a valid Media Library ID in the client config or a Media Library GDR"
1649
+ );
1650
+ const uri = buildVideoPlaybackInfoUrl(instanceId, effectiveLibraryId), queryParams = buildQueryParams(options);
1651
+ return _request(this.#client, this.#httpRequest, {
1652
+ method: "GET",
1653
+ uri,
1654
+ query: queryParams
1655
+ });
1656
+ }
1657
+ }
1658
+ class MediaLibraryVideoClient {
1659
+ #client;
1660
+ #httpRequest;
1661
+ constructor(client, httpRequest) {
1662
+ this.#client = client, this.#httpRequest = httpRequest;
1663
+ }
1664
+ /**
1665
+ * Get video playback information for a media library asset
1666
+ *
1667
+ * @param assetIdentifier - Asset instance identifier (GDR, video-prefixed ID, or container ID)
1668
+ * @param options - Options for transformations and expiration
1669
+ */
1670
+ getPlaybackInfo(assetIdentifier, options = {}) {
1671
+ return rxjs.lastValueFrom(
1672
+ new ObservableMediaLibraryVideoClient(
1673
+ this.#client.observable,
1674
+ this.#httpRequest
1675
+ ).getPlaybackInfo(assetIdentifier, options)
1676
+ );
1677
+ }
1678
+ }
1679
+ const ML_GDR_PATTERN = /^media-library:(ml[^:]+):([^:]+)$/;
1680
+ function isSanityReference(assetIdentifier) {
1681
+ return typeof assetIdentifier == "object" && "_ref" in assetIdentifier;
1682
+ }
1683
+ function parseAssetInstanceId(assetIdentifier) {
1684
+ const ref = isSanityReference(assetIdentifier) ? assetIdentifier._ref : assetIdentifier, match = ML_GDR_PATTERN.exec(ref);
1685
+ if (match) {
1686
+ const [, libraryId, instanceId] = match;
1687
+ return { libraryId, instanceId };
1688
+ }
1689
+ if (typeof assetIdentifier == "string" && assetIdentifier.startsWith("video-"))
1690
+ return { instanceId: assetIdentifier };
1691
+ throw new Error(
1692
+ `Invalid video asset instance identifier "${ref}": must be a valid video instance id or a Global Dataset Reference (GDR) to the video asset in the Media Library`
1693
+ );
1694
+ }
1695
+ function buildVideoPlaybackInfoUrl(instanceId, libraryId) {
1696
+ return `/media-libraries/${libraryId}/video/${instanceId}/playback-info`;
1697
+ }
1698
+ function buildQueryParams(options) {
1699
+ const params = {};
1700
+ if (options.transformations) {
1701
+ const { thumbnail, animated, storyboard } = options.transformations;
1702
+ thumbnail && (thumbnail.width && (params.thumbnailWidth = thumbnail.width), thumbnail.height && (params.thumbnailHeight = thumbnail.height), thumbnail.time !== void 0 && (params.thumbnailTime = thumbnail.time), thumbnail.fit && (params.thumbnailFit = thumbnail.fit), thumbnail.format && (params.thumbnailFormat = thumbnail.format)), animated && (animated.width && (params.animatedWidth = animated.width), animated.height && (params.animatedHeight = animated.height), animated.start !== void 0 && (params.animatedStart = animated.start), animated.end !== void 0 && (params.animatedEnd = animated.end), animated.fps && (params.animatedFps = animated.fps), animated.format && (params.animatedFormat = animated.format)), storyboard && storyboard.format && (params.storyboardFormat = storyboard.format);
1703
+ }
1704
+ return options.expiration && (params.expiration = options.expiration), params;
1705
+ }
1619
1706
  class ObservableProjectsClient {
1620
1707
  #client;
1621
1708
  #httpRequest;
@@ -2190,6 +2277,7 @@ class ObservableSanityClient {
2190
2277
  assets;
2191
2278
  datasets;
2192
2279
  live;
2280
+ mediaLibrary;
2193
2281
  projects;
2194
2282
  users;
2195
2283
  agent;
@@ -2204,7 +2292,9 @@ class ObservableSanityClient {
2204
2292
  */
2205
2293
  listen = _listen;
2206
2294
  constructor(httpRequest, config = defaultConfig) {
2207
- this.config(config), this.#httpRequest = httpRequest, this.assets = new ObservableAssetsClient(this, this.#httpRequest), this.datasets = new ObservableDatasetsClient(this, this.#httpRequest), this.live = new LiveClient(this), this.projects = new ObservableProjectsClient(this, this.#httpRequest), this.users = new ObservableUsersClient(this, this.#httpRequest), this.agent = {
2295
+ this.config(config), this.#httpRequest = httpRequest, this.assets = new ObservableAssetsClient(this, this.#httpRequest), this.datasets = new ObservableDatasetsClient(this, this.#httpRequest), this.live = new LiveClient(this), this.mediaLibrary = {
2296
+ video: new ObservableMediaLibraryVideoClient(this, this.#httpRequest)
2297
+ }, this.projects = new ObservableProjectsClient(this, this.#httpRequest), this.users = new ObservableUsersClient(this, this.#httpRequest), this.agent = {
2208
2298
  action: new ObservableAgentsActionClient(this, this.#httpRequest)
2209
2299
  }, this.releases = new ObservableReleasesClient(this, this.#httpRequest);
2210
2300
  }
@@ -2249,14 +2339,19 @@ class ObservableSanityClient {
2249
2339
  options
2250
2340
  );
2251
2341
  }
2252
- /**
2253
- * Fetch a single document with the given ID.
2254
- *
2255
- * @param id - Document ID to fetch
2256
- * @param options - Request options
2257
- */
2258
2342
  getDocument(id, options) {
2259
- return _getDocument(this, this.#httpRequest, id, options);
2343
+ if (options?.includeAllVersions === !0)
2344
+ return _getDocument(this, this.#httpRequest, id, {
2345
+ ...options,
2346
+ includeAllVersions: !0
2347
+ });
2348
+ const opts = {
2349
+ signal: options?.signal,
2350
+ tag: options?.tag,
2351
+ releaseId: options?.releaseId,
2352
+ ...options && "includeAllVersions" in options ? { includeAllVersions: !1 } : {}
2353
+ };
2354
+ return _getDocument(this, this.#httpRequest, id, opts);
2260
2355
  }
2261
2356
  /**
2262
2357
  * Fetch multiple documents in one request.
@@ -2442,6 +2537,7 @@ class SanityClient {
2442
2537
  assets;
2443
2538
  datasets;
2444
2539
  live;
2540
+ mediaLibrary;
2445
2541
  projects;
2446
2542
  users;
2447
2543
  agent;
@@ -2460,7 +2556,9 @@ class SanityClient {
2460
2556
  */
2461
2557
  listen = _listen;
2462
2558
  constructor(httpRequest, config = defaultConfig) {
2463
- this.config(config), this.#httpRequest = httpRequest, this.assets = new AssetsClient(this, this.#httpRequest), this.datasets = new DatasetsClient(this, this.#httpRequest), this.live = new LiveClient(this), this.projects = new ProjectsClient(this, this.#httpRequest), this.users = new UsersClient(this, this.#httpRequest), this.agent = {
2559
+ this.config(config), this.#httpRequest = httpRequest, this.assets = new AssetsClient(this, this.#httpRequest), this.datasets = new DatasetsClient(this, this.#httpRequest), this.live = new LiveClient(this), this.mediaLibrary = {
2560
+ video: new MediaLibraryVideoClient(this, this.#httpRequest)
2561
+ }, this.projects = new ProjectsClient(this, this.#httpRequest), this.users = new UsersClient(this, this.#httpRequest), this.agent = {
2464
2562
  action: new AgentActionsClient(this, this.#httpRequest)
2465
2563
  }, this.releases = new ReleasesClient(this, this.#httpRequest), this.observable = new ObservableSanityClient(httpRequest, config);
2466
2564
  }
@@ -2507,14 +2605,21 @@ class SanityClient {
2507
2605
  )
2508
2606
  );
2509
2607
  }
2510
- /**
2511
- * Fetch a single document with the given ID.
2512
- *
2513
- * @param id - Document ID to fetch
2514
- * @param options - Request options
2515
- */
2516
2608
  getDocument(id, options) {
2517
- return rxjs.lastValueFrom(_getDocument(this, this.#httpRequest, id, options));
2609
+ if (options?.includeAllVersions === !0)
2610
+ return rxjs.lastValueFrom(
2611
+ _getDocument(this, this.#httpRequest, id, {
2612
+ ...options,
2613
+ includeAllVersions: !0
2614
+ })
2615
+ );
2616
+ const opts = {
2617
+ signal: options?.signal,
2618
+ tag: options?.tag,
2619
+ releaseId: options?.releaseId,
2620
+ ...options && "includeAllVersions" in options ? { includeAllVersions: !1 } : {}
2621
+ };
2622
+ return rxjs.lastValueFrom(_getDocument(this, this.#httpRequest, id, opts));
2518
2623
  }
2519
2624
  /**
2520
2625
  * Fetch multiple documents in one request.