@sanity/client 7.26.2 → 8.1.0

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.
Files changed (133) hide show
  1. package/README.md +63 -341
  2. package/dist/browserUpload-2tz6Sdqp.js +87 -0
  3. package/dist/browserUpload-2tz6Sdqp.js.map +1 -0
  4. package/dist/browserUpload-CwpNx7Vl.js +87 -0
  5. package/dist/browserUpload-CwpNx7Vl.js.map +1 -0
  6. package/dist/config-3wiPP-sZ.js +126 -0
  7. package/dist/config-3wiPP-sZ.js.map +1 -0
  8. package/dist/csm.d.ts +122 -335
  9. package/dist/csm.js +79 -91
  10. package/dist/csm.js.map +1 -1
  11. package/dist/dist-C9ExSk2R.js +73 -0
  12. package/dist/dist-C9ExSk2R.js.map +1 -0
  13. package/dist/dist-Z8cIRxoB.js +69 -0
  14. package/dist/dist-Z8cIRxoB.js.map +1 -0
  15. package/dist/index.d.ts +112 -6722
  16. package/dist/index.js +2950 -2848
  17. package/dist/index.js.map +1 -1
  18. package/dist/{index.d.cts → index.node.d.ts} +4529 -5322
  19. package/dist/index.node.js +3264 -0
  20. package/dist/index.node.js.map +1 -0
  21. package/dist/isRecord-Kfmt-nk-.js +7 -0
  22. package/dist/isRecord-Kfmt-nk-.js.map +1 -0
  23. package/dist/media-library.d.ts +9 -100
  24. package/dist/media-library.js +36 -14
  25. package/dist/media-library.js.map +1 -1
  26. package/dist/request-BhMuKj0D.js +373 -0
  27. package/dist/request-BhMuKj0D.js.map +1 -0
  28. package/dist/request-SnMg7nUX.js +355 -0
  29. package/dist/request-SnMg7nUX.js.map +1 -0
  30. package/dist/resolveEditInfo-Cz-smq3a.js +339 -0
  31. package/dist/resolveEditInfo-Cz-smq3a.js.map +1 -0
  32. package/dist/rolldown-runtime-vyAXikos.js +9 -0
  33. package/dist/stega.d.ts +78 -7137
  34. package/dist/stega.js +27 -20
  35. package/dist/stega.js.map +1 -1
  36. package/dist/stegaClean-C18wLWau.js +21 -0
  37. package/dist/stegaClean-C18wLWau.js.map +1 -0
  38. package/dist/stegaEncodeSourceMap-DbM2fTN4.js +373 -0
  39. package/dist/stegaEncodeSourceMap-DbM2fTN4.js.map +1 -0
  40. package/dist/stegaEncodeSourceMap-YR3NQ3iz.js +163 -0
  41. package/dist/stegaEncodeSourceMap-YR3NQ3iz.js.map +1 -0
  42. package/dist/{index.browser.d.cts → types-BODIEY7F.d.ts} +4196 -5258
  43. package/dist/types-CfGzbXrl.d.ts +108 -0
  44. package/package.json +80 -142
  45. package/src/SanityClient.ts +101 -137
  46. package/src/agent/actions/AgentActionsClient.ts +12 -12
  47. package/src/agent/actions/commonTypes.ts +2 -1
  48. package/src/agent/actions/generate.ts +26 -6
  49. package/src/agent/actions/patch.ts +27 -7
  50. package/src/agent/actions/prompt.ts +19 -5
  51. package/src/agent/actions/transform.ts +23 -5
  52. package/src/agent/actions/translate.ts +23 -5
  53. package/src/assets/AssetsClient.ts +121 -24
  54. package/src/csm/applySourceDocuments.ts +5 -5
  55. package/src/csm/createEditUrl.ts +1 -1
  56. package/src/csm/draftUtils.ts +23 -5
  57. package/src/csm/index.ts +2 -2
  58. package/src/csm/studioPath.ts +2 -1
  59. package/src/csm/types.ts +8 -2
  60. package/src/data/dataMethods.ts +784 -349
  61. package/src/data/eventsource.ts +82 -49
  62. package/src/data/listen.ts +18 -23
  63. package/src/data/live.ts +60 -35
  64. package/src/data/resolveEventSourceFetch.ts +104 -0
  65. package/src/datasets/DatasetsClient.ts +58 -41
  66. package/src/defineCreateClient.ts +38 -22
  67. package/src/functions/FunctionsClient.ts +66 -0
  68. package/src/functions/invoke.ts +176 -0
  69. package/src/http/browserMiddleware.ts +7 -1
  70. package/src/http/browserUpload.ts +163 -0
  71. package/src/http/errors.ts +61 -6
  72. package/src/http/nodeMiddleware.ts +94 -30
  73. package/src/http/request.ts +304 -87
  74. package/src/http/requestOptions.ts +131 -15
  75. package/src/{index.browser.ts → index.node.ts} +9 -4
  76. package/src/index.ts +4 -3
  77. package/src/mediaLibrary/MediaLibraryVideoClient.ts +27 -12
  78. package/src/projects/ProjectsClient.ts +18 -16
  79. package/src/releases/ReleasesClient.ts +38 -33
  80. package/src/stega/index.ts +1 -2
  81. package/src/stega/stegaEncodeSourceMap.ts +5 -0
  82. package/src/stega/types.ts +2 -2
  83. package/src/types.ts +328 -103
  84. package/src/users/UsersClient.ts +10 -14
  85. package/src/util/shareReplayLatest.ts +1 -1
  86. package/src/validators.ts +1 -1
  87. package/src/warnings.ts +13 -2
  88. package/dist/_chunks-cjs/config.cjs +0 -206
  89. package/dist/_chunks-cjs/config.cjs.map +0 -1
  90. package/dist/_chunks-cjs/isRecord.cjs +0 -6
  91. package/dist/_chunks-cjs/isRecord.cjs.map +0 -1
  92. package/dist/_chunks-cjs/resolveEditInfo.cjs +0 -334
  93. package/dist/_chunks-cjs/resolveEditInfo.cjs.map +0 -1
  94. package/dist/_chunks-cjs/stegaClean.cjs +0 -46
  95. package/dist/_chunks-cjs/stegaClean.cjs.map +0 -1
  96. package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs +0 -388
  97. package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs.map +0 -1
  98. package/dist/_chunks-es/config.js +0 -207
  99. package/dist/_chunks-es/config.js.map +0 -1
  100. package/dist/_chunks-es/isRecord.js +0 -7
  101. package/dist/_chunks-es/isRecord.js.map +0 -1
  102. package/dist/_chunks-es/resolveEditInfo.js +0 -335
  103. package/dist/_chunks-es/resolveEditInfo.js.map +0 -1
  104. package/dist/_chunks-es/stegaClean.js +0 -47
  105. package/dist/_chunks-es/stegaClean.js.map +0 -1
  106. package/dist/_chunks-es/stegaEncodeSourceMap.js +0 -389
  107. package/dist/_chunks-es/stegaEncodeSourceMap.js.map +0 -1
  108. package/dist/csm.cjs +0 -99
  109. package/dist/csm.cjs.map +0 -1
  110. package/dist/csm.d.cts +0 -391
  111. package/dist/index.browser.cjs +0 -3106
  112. package/dist/index.browser.cjs.map +0 -1
  113. package/dist/index.browser.d.ts +0 -6802
  114. package/dist/index.browser.js +0 -3082
  115. package/dist/index.browser.js.map +0 -1
  116. package/dist/index.cjs +0 -2946
  117. package/dist/index.cjs.map +0 -1
  118. package/dist/media-library.cjs +0 -20
  119. package/dist/media-library.cjs.map +0 -1
  120. package/dist/media-library.d.cts +0 -117
  121. package/dist/stega.browser.cjs +0 -29
  122. package/dist/stega.browser.cjs.map +0 -1
  123. package/dist/stega.browser.d.cts +0 -7200
  124. package/dist/stega.browser.d.ts +0 -7200
  125. package/dist/stega.browser.js +0 -24
  126. package/dist/stega.browser.js.map +0 -1
  127. package/dist/stega.cjs +0 -29
  128. package/dist/stega.cjs.map +0 -1
  129. package/dist/stega.d.cts +0 -7200
  130. package/src/data/eventsourcePolyfill.ts +0 -7
  131. package/umd/.gitkeep +0 -1
  132. package/umd/sanityClient.js +0 -6543
  133. package/umd/sanityClient.min.js +0 -6
package/README.md CHANGED
@@ -60,14 +60,12 @@ export async function updateDocumentTitle(_id, title) {
60
60
  - [API](#api)
61
61
  - [Creating a client instance](#creating-a-client-instance)
62
62
  - [ESM](#esm)
63
- - [CommonJS](#commonjs)
64
63
  - [TypeScript](#typescript)
65
64
  - [Next.js App Router](#nextjs-app-router)
66
65
  - [Bun](#bun)
67
66
  - [Deno](#deno)
68
67
  - [Edge Runtime](#edge-runtime)
69
68
  - [Browser ESM CDN](#browser-esm-cdn)
70
- - [UMD](#umd)
71
69
  - [Specifying API version](#specifying-api-version)
72
70
  - [Request tags](#request-tags)
73
71
  - [Performing queries](#performing-queries)
@@ -147,24 +145,12 @@ export async function updateDocumentTitle(_id, title) {
147
145
  - [Getting video playback information](#getting-video-playback-information)
148
146
  - [Working with signed playback information](#working-with-signed-playback-information)
149
147
  - [Downloading MP4 renditions](#downloading-mp4-renditions)
148
+ - [Invoking functions](#invoking-functions)
149
+ - [Choosing a stack](#choosing-a-stack)
150
+ - [Scoping to an organization](#scoping-to-an-organization)
151
+ - [Return values and timeouts](#return-values-and-timeouts)
150
152
  - [License](#license)
151
- - [From `v5`](#from-v5)
152
- - [The default `useCdn` is changed to `true`](#the-default-usecdn-is-changed-to-true)
153
- - [From `v4`](#from-v4)
154
- - [No longer shipping `ES5`](#no-longer-shipping-es5)
155
- - [Node.js `v12` no longer supported](#nodejs-v12-no-longer-supported)
156
- - [The `default` export is replaced with the named export `createClient`](#the-default-export-is-replaced-with-the-named-export-createclient)
157
- - [`client.assets.delete` is removed](#clientassetsdelete-is-removed)
158
- - [`client.assets.getImageUrl` is removed, replace with `@sanity/image-url`](#clientassetsgetimageurl-is-removed-replace-with-sanityimage-url)
159
- - [`SanityClient` static properties moved to named exports](#sanityclient-static-properties-moved-to-named-exports)
160
- - [`client.clientConfig` is removed, replace with `client.config()`](#clientclientconfig-is-removed-replace-with-clientconfig)
161
- - [`client.isPromiseAPI()` is removed, replace with an `instanceof` check](#clientispromiseapi-is-removed-replace-with-an-instanceof-check)
162
- - [`client.observable.isObservableAPI()` is removed, replace with an `instanceof` check](#clientobservableisobservableapi-is-removed-replace-with-an-instanceof-check)
163
- - [`client._requestObservable` is removed, replace with `client.observable.request`](#client_requestobservable-is-removed-replace-with-clientobservablerequest)
164
- - [`client._dataRequest` is removed, replace with `client.dataRequest`](#client_datarequest-is-removed-replace-with-clientdatarequest)
165
- - [`client._create_` is removed, replace with one of `client.create`, `client.createIfNotExists` or `client.createOrReplace`](#client_create_-is-removed-replace-with-one-of-clientcreate-clientcreateifnotexists-or-clientcreateorreplace)
166
- - [`client.patch.replace` is removed, replace with `client.createOrReplace`](#clientpatchreplace-is-removed-replace-with-clientcreateorreplace)
167
- - [`client.auth` is removed, replace with `client.request`](#clientauth-is-removed-replace-with-clientrequest)
153
+ - [Migrate](#migrate)
168
154
 
169
155
  ## Requirements
170
156
 
@@ -208,24 +194,6 @@ const data = await client.fetch(`count(*)`)
208
194
  console.log(`Number of documents: ${data}`)
209
195
  ```
210
196
 
211
- #### [CommonJS]
212
-
213
- ```js
214
- const {createClient} = require('@sanity/client')
215
-
216
- const client = createClient({
217
- projectId: 'your-project-id',
218
- dataset: 'your-dataset-name',
219
- useCdn: true, // set to `false` to bypass the edge cache
220
- apiVersion: '2025-02-06', // use current date (YYYY-MM-DD) to target the latest API version. Note: this should always be hard coded. Setting API version based on a dynamic value (e.g. new Date()) may break your application at a random point in the future.
221
- })
222
-
223
- client
224
- .fetch(`count(*)`)
225
- .then((data) => console.log(`Number of documents: ${data}`))
226
- .catch(console.error)
227
- ```
228
-
229
197
  #### [TypeScript]
230
198
 
231
199
  ```ts
@@ -437,51 +405,6 @@ const data = await client.fetch(`count(*)`)
437
405
  console.log(`Number of documents: ${data}`)
438
406
  ```
439
407
 
440
- #### [UMD][unpkg-dist]
441
-
442
- Loading the UMD script creates a `SanityClient` global that have the same exports as `import * as SanityClient from '@sanity/client'`:
443
-
444
- ```html
445
- <script src="https://unpkg.com/@sanity/client"></script>
446
- <!-- Unminified build for debugging -->
447
- <!--<script src="https://unpkg.com/@sanity/client/umd/sanityClient.js"></script>-->
448
- <script>
449
- const {createClient} = SanityClient
450
-
451
- const client = createClient({
452
- projectId: 'your-project-id',
453
- dataset: 'your-dataset-name',
454
- useCdn: true, // set to `false` to bypass the edge cache
455
- apiVersion: '2025-02-06', // use current date (YYYY-MM-DD) to target the latest API version. Note: this should always be hard coded. Setting API version based on a dynamic value (e.g. new Date()) may break your application at a random point in the future.
456
- })
457
-
458
- client.fetch(`count(*)`).then((data) => console.log(`Number of documents: ${data}`))
459
- </script>
460
- ```
461
-
462
- The `require-unpkg` library lets you consume `npm` packages from `unpkg.com` similar to how `esm.sh` lets you `import()` anything:
463
-
464
- ```html
465
- <div id="results"></div>
466
- <script src="https://unpkg.com/require-unpkg"></script>
467
- <script>
468
- ;(async () => {
469
- // const {createClient} = await require('@sanity/client')
470
- const [$, {createClient}] = await require(['jquery', '@sanity/client'])
471
-
472
- const client = createClient({
473
- projectId: 'your-project-id',
474
- dataset: 'your-dataset-name',
475
- useCdn: true, // set to `false` to bypass the edge cache
476
- apiVersion: '2025-02-06', // use current date (YYYY-MM-DD) to target the latest API version. Note: this should always be hard coded. Setting API version based on a dynamic value (e.g. new Date()) may break your application at a random point in the future.
477
- })
478
-
479
- const data = await client.fetch(`count(*)`)
480
- $('#results').text(`Number of documents: ${data}`)
481
- })()
482
- </script>
483
- ```
484
-
485
408
  ### Specifying API version
486
409
 
487
410
  Sanity uses ISO dates (YYYY-MM-DD) in UTC timezone for versioning. The explanation for this can be found [in the documentation][api-versioning]
@@ -1011,6 +934,8 @@ Likewise, you can also have the client return the document _before_ the mutation
1011
934
 
1012
935
  If it's not relevant to know what mutations that was applied, you can also set `includeMutation` to `false` in the options, which will save some additional bandwidth by omitting the `mutation` property from the received events.
1013
936
 
937
+ On Cloudflare Workers, `client.listen()` and `client.live.events()` need a [`compatibility_date`](https://developers.cloudflare.com/workers/configuration/compatibility-dates/) of `2024-11-11` or later (or the `cache_option_enabled` compatibility flag). Both open a server-sent events connection, which sets the `cache` field on the request; earlier compatibility dates throw rather than ignore it. Other runtimes are unaffected.
938
+
1014
939
  ### Fetch a single document
1015
940
 
1016
941
  This will fetch a document from the [Doc endpoint](https://www.sanity.io/docs/http-doc). This endpoint cuts through any caching/indexing middleware that may involve delayed processing. As it is less scalable/performant than the other query mechanisms, it should be used sparingly. Performing a query is usually a better option.
@@ -2528,307 +2453,105 @@ if (playbackInfo.renditions?.length) {
2528
2453
 
2529
2454
  Available resolutions depend on the source video but typically include `1080p`, `480p`, and `270p`.
2530
2455
 
2531
- ## License
2532
-
2533
- MIT © [Sanity.io](https://www.sanity.io/)
2456
+ ### Invoking functions
2534
2457
 
2535
- # Migrate
2458
+ Call a Sanity Pubsub Function on demand. These APIs are available on the `client.functions` namespace.
2536
2459
 
2537
- ## From `v5`
2460
+ Only `sanity.function.pubsub` functions can be invoked this way. Every other type is driven by its own trigger.
2538
2461
 
2539
- ### The default `useCdn` is changed to `true`
2462
+ Functions are addressed by the `name` they are declared with in your blueprint. Names are unique within a stack. The client needs a `stackId` in order to resolve. Configure it once on the client, or pass it per call.
2540
2463
 
2541
- It was previously `false`. If you were relying on the default being `false` you can continue using the live API by setting it in the constructor:
2542
-
2543
- ```diff
2464
+ ```js
2544
2465
  import {createClient} from '@sanity/client'
2545
2466
 
2546
- export const client = createClient({
2467
+ const client = createClient({
2547
2468
  projectId: 'your-project-id',
2548
- dataset: 'your-dataset-name',
2549
- apiVersion: '2025-02-06',
2550
- + useCdn: false, // set to `true` to use the edge cache
2469
+ apiVersion: '2025-02-19',
2470
+ token: 'valid-token',
2471
+ stackId: 'your-stack-id',
2551
2472
  })
2552
- ```
2553
-
2554
- ## From `v4`
2555
-
2556
- ### No longer shipping `ES5`
2557
-
2558
- The target is changed to [modern browsers] that supports `ES6` `class`, `{...rest}` syntax and more. You may need to update your bundler to a recent major version. Or you could configure your bundler to transpile `@sanity/client`, and `get-it`, which is the engine that powers `@sanity/client` and uses the same output target.
2559
-
2560
- ### Node.js `v12` no longer supported
2561
-
2562
- Upgrade to the [LTS release, or one of the Maintenance releases](https://github.com/nodejs/release#release-schedule).
2563
-
2564
- ### The `default` export is replaced with the named export `createClient`
2565
-
2566
- Before:
2567
-
2568
- ```ts
2569
- import createClient from '@sanity/client'
2570
- const client = createClient()
2571
- ```
2572
-
2573
- ```ts
2574
- import SanityClient from '@sanity/client'
2575
- const client = new SanityClient()
2576
- ```
2577
-
2578
- After:
2579
-
2580
- ```ts
2581
- import {createClient} from '@sanity/client'
2582
- const client = createClient()
2583
- ```
2584
-
2585
- ### `client.assets.delete` is removed
2586
-
2587
- Before:
2588
-
2589
- ```ts
2590
- client.assets.delete('image', 'abc123_foobar-123x123-png')
2591
- client.assets.delete('image', 'image-abc123_foobar-123x123-png')
2592
- client.assets.delete({_id: 'image-abc123_foobar-123x123-png'})
2593
- ```
2594
-
2595
- After:
2596
-
2597
- ```ts
2598
- client.delete('image-abc123_foobar-123x123-png')
2599
- ```
2600
-
2601
- ### `client.assets.getImageUrl` is removed, replace with [`@sanity/image-url`](https://github.com/sanity-io/image-url)
2602
-
2603
- Before:
2604
-
2605
- ```ts
2606
- import createClient from '@sanity/client'
2607
- const client = createClient({projectId: 'abc123', dataset: 'foo'})
2608
-
2609
- client.assets.getImageUrl('image-abc123_foobar-123x123-png')
2610
- client.assets.getImageUrl('image-abc123_foobar-123x123-png', {auto: 'format'})
2611
- client.assets.getImageUrl({_ref: 'image-abc123_foobar-123x123-png'})
2612
- client.assets.getImageUrl({_ref: 'image-abc123_foobar-123x123-png'}, {auto: 'format'})
2613
- ```
2614
-
2615
- After:
2616
-
2617
- ```bash
2618
- npm install @sanity/image-url
2619
- ```
2620
-
2621
- ```ts
2622
- import imageUrlBuilder from '@sanity/image-url'
2623
- const builder = imageUrlBuilder({projectId: 'abc123', dataset: 'foo'})
2624
- const urlFor = (source) => builder.image(source)
2625
-
2626
- urlFor('image-abc123_foobar-123x123-png').url()
2627
- urlFor('image-abc123_foobar-123x123-png').auto('format').url()
2628
- urlFor({_ref: 'image-abc123_foobar-123x123-png'}).url()
2629
- urlFor({_ref: 'image-abc123_foobar-123x123-png'}).auto('format').url()
2630
- ```
2631
-
2632
- ### `SanityClient` static properties moved to named exports
2633
2473
 
2634
- Before:
2635
-
2636
- ```ts
2637
- import SanityClient from '@sanity/client'
2638
-
2639
- const {Patch, Transaction, ClientError, ServerError, requester} = SanityClient
2640
- ```
2641
-
2642
- After:
2643
-
2644
- ```ts
2645
- import {Patch, Transaction, ClientError, ServerError, requester} from '@sanity/client'
2646
- ```
2647
-
2648
- ### `client.clientConfig` is removed, replace with `client.config()`
2649
-
2650
- Before:
2651
-
2652
- ```ts
2653
- import createClient from '@sanity/client'
2654
- const client = createClient()
2655
-
2656
- console.log(client.clientConfig.projectId)
2657
- ```
2658
-
2659
- After:
2660
-
2661
- ```ts
2662
- import {createClient} from '@sanity/client'
2663
- const client = createClient()
2664
-
2665
- console.log(client.config().projectId)
2666
- ```
2667
-
2668
- ### `client.isPromiseAPI()` is removed, replace with an `instanceof` check
2669
-
2670
- Before:
2671
-
2672
- ```ts
2673
- import createClient from '@sanity/client'
2674
- const client = createClient()
2675
-
2676
- console.log(client.isPromiseAPI())
2677
- console.log(client.clientConfig.isPromiseAPI)
2678
- console.log(client.config().isPromiseAPI)
2679
- ```
2680
-
2681
- After:
2682
-
2683
- ```ts
2684
- import {createClient, SanityClient} from '@sanity/client'
2685
- const client = createClient()
2686
-
2687
- console.log(client instanceof SanityClient)
2688
- ```
2689
-
2690
- ### `client.observable.isObservableAPI()` is removed, replace with an `instanceof` check
2691
-
2692
- Before:
2693
-
2694
- ```ts
2695
- import createClient from '@sanity/client'
2696
- const client = createClient()
2697
-
2698
- console.log(client.observable.isObservableAPI())
2474
+ const result = await client.functions.invoke('my-function', {
2475
+ event: {data: {hello: 'world'}},
2476
+ })
2699
2477
  ```
2700
2478
 
2701
- After:
2479
+ The payload given as `event.data` is what the function receives as `event.data`. It defaults to `{}` when omitted.
2702
2480
 
2703
- ```ts
2704
- import {createClient, ObservableSanityClient} from '@sanity/client'
2705
- const client = createClient()
2706
-
2707
- console.log(client.observable instanceof ObservableSanityClient)
2708
- ```
2481
+ Both Promise and Observable forms are available:
2709
2482
 
2710
- ### `client._requestObservable` is removed, replace with `client.observable.request`
2711
-
2712
- Before:
2483
+ - `client.functions.invoke(name, request)` resolves with the function's return value
2484
+ - `client.observable.functions.invoke(name, request)` emits it and completes
2713
2485
 
2714
2486
  ```ts
2715
- import createClient from '@sanity/client'
2716
- const client = createClient()
2717
-
2718
- client._requestObservable({uri: '/ping'}).subscribe()
2719
- ```
2720
-
2721
- After:
2722
-
2723
- ```ts
2724
- import {createClient} from '@sanity/client'
2725
- const client = createClient()
2726
-
2727
- client.observable.request({uri: '/ping'}).subscribe()
2487
+ // The return value is typed through the generic; it is not validated at runtime
2488
+ const summary = await client.functions.invoke<{words: number}>('summarize', {
2489
+ event: {data: {documentId: 'abc123'}},
2490
+ })
2728
2491
  ```
2729
2492
 
2730
- ### `client._dataRequest` is removed, replace with `client.dataRequest`
2731
-
2732
- Before:
2493
+ #### Choosing a stack
2733
2494
 
2734
- ```ts
2735
- import createClient from '@sanity/client'
2736
- const client = createClient()
2495
+ `stackId` on the request wins over `stackId` in the client config, which lets one client reach functions in more than one stack:
2737
2496
 
2738
- client._dataRequest(endpoint, body, options)
2497
+ ```js
2498
+ await client.functions.invoke('my-function', {stackId: 'another-stack-id'})
2739
2499
  ```
2740
2500
 
2741
- After:
2742
-
2743
- ```ts
2744
- import {createClient} from '@sanity/client'
2745
- const client = createClient()
2746
-
2747
- client.dataRequest(endpoint, body, options)
2748
- ```
2501
+ Resolving the name takes one extra request per call: the client reads the stack to find the function, then invokes it. If neither the request nor the config supplies a `stackId`, the call rejects without touching the network.
2749
2502
 
2750
- ### `client._create_` is removed, replace with one of `client.create`, `client.createIfNotExists` or `client.createOrReplace`
2503
+ Invoking a name the stack doesn't declare or a non-pubsub function rejects.
2751
2504
 
2752
- Before:
2505
+ #### Scoping to an organization
2753
2506
 
2754
- ```ts
2755
- import createClient from '@sanity/client'
2756
- const client = createClient()
2507
+ Project scope is the default. For an organization-scoped stack, set `organizationId`:
2757
2508
 
2758
- client._create(doc, 'create', options)
2759
- client._create(doc, 'createIfNotExists', options)
2760
- client._create(doc, 'createOrReplace', options)
2509
+ ```js
2510
+ const client = createClient({
2511
+ projectId: 'your-project-id',
2512
+ apiVersion: '2025-02-19',
2513
+ token: 'valid-token',
2514
+ stackId: 'your-stack-id',
2515
+ organizationId: 'your-organization-id',
2516
+ })
2761
2517
  ```
2762
2518
 
2763
- After:
2519
+ It can also be passed per call, and wins over the client config:
2764
2520
 
2765
- ```ts
2766
- import {createClient} from '@sanity/client'
2767
- const client = createClient()
2768
-
2769
- client.create(doc, options)
2770
- client.createIfNotExists(doc, options)
2771
- client.createOrReplace(doc, options)
2521
+ ```js
2522
+ await client.functions.invoke('my-function', {organizationId: 'another-organization-id'})
2772
2523
  ```
2773
2524
 
2774
- ### `client.patch.replace` is removed, replace with `client.createOrReplace`
2525
+ An `organizationId` takes precedence over `projectId`, since a stack is only ever resolvable at one scope. `projectId` becomes optional in that case, provided the client is also configured with `useProjectHostname: false`.
2775
2526
 
2776
- Before:
2527
+ Scope has to match the token. A project-scoped token gets `403` on an organization-scoped stack; mint one that matches with `sanity blueprints mint-deploy-token --organization-id <id>`.
2777
2528
 
2778
- ```ts
2779
- import createClient from '@sanity/client'
2780
- const client = createClient()
2529
+ #### Return values and timeouts
2781
2530
 
2782
- client.patch('tropic-hab').replace({name: 'Tropical Habanero', ingredients: []}).commit()
2783
- ```
2531
+ The request stays open until the function finishes, and resolves with whatever it returned. A function that returns nothing resolves to `undefined`.
2784
2532
 
2785
- After:
2533
+ Requests time out after five minutes by default, so a longer-running function needs an explicit `timeout` (in milliseconds, `0` to disable it). A call can be aborted with an `AbortSignal` like any other request:
2786
2534
 
2787
- ```ts
2788
- import {createClient} from '@sanity/client'
2789
- const client = createClient()
2535
+ ```js
2536
+ const controller = new AbortController()
2790
2537
 
2791
- client.createOrReplace({
2792
- _id: 'tropic-hab',
2793
- _type: 'hotsauce',
2794
- name: 'Tropical Habanero',
2795
- ingredients: [],
2538
+ const result = await client.functions.invoke('slow-function', {
2539
+ timeout: 0, // or e.g. 600000 for a ten minute deadline
2540
+ signal: controller.signal,
2796
2541
  })
2797
2542
  ```
2798
2543
 
2799
- ### `client.auth` is removed, replace with `client.request`
2800
-
2801
- Before:
2802
-
2803
- ```ts
2804
- import createClient from '@sanity/client'
2805
- const client = createClient()
2544
+ ## License
2806
2545
 
2807
- /**
2808
- * Fetch available login providers
2809
- */
2810
- const loginProviders = await client.auth.getLoginProviders()
2811
- /**
2812
- * Revoke the configured session/token
2813
- */
2814
- await client.auth.logout()
2815
- ```
2546
+ MIT © [Sanity.io](https://www.sanity.io/)
2816
2547
 
2817
- After:
2548
+ # Migrate
2818
2549
 
2819
- ```ts
2820
- import {createclient, type AuthProviderResponse} from '@sanity/client'
2821
- const client = createClient()
2550
+ Migration guides for major version upgrades:
2822
2551
 
2823
- /**
2824
- * Fetch available login providers
2825
- */
2826
- const loginProviders = await client.request<AuthProviderResponse>({uri: '/auth/providers'})
2827
- /**
2828
- * Revoke the configured session/token
2829
- */
2830
- await client.request<void>({uri: '/auth/logout', method: 'POST'})
2831
- ```
2552
+ - From `v7`: [docs/MIGRATE-v7.md](docs/MIGRATE-v7.md)
2553
+ - From `v5`: [docs/MIGRATE-v5.md](docs/MIGRATE-v5.md)
2554
+ - From `v4`: [docs/MIGRATE-v4.md](docs/MIGRATE-v4.md)
2832
2555
 
2833
2556
  [modern browsers]: https://browsersl.ist/#q=%3E+0.2%25+and+supports+es6-module+and+supports+es6-module-dynamic-import+and+not+dead+and+not+IE+11
2834
2557
  [Deno]: https://deno.land/
@@ -2836,7 +2559,6 @@ await client.request<void>({uri: '/auth/logout', method: 'POST'})
2836
2559
  [Bun]: https://bun.sh/
2837
2560
  [gzip-badge]: https://img.shields.io/bundlephobia/minzip/@sanity/client?label=gzip%20size&style=flat-square
2838
2561
  [size-badge]: https://img.shields.io/bundlephobia/min/@sanity/client?label=size&style=flat-square
2839
- [unpkg-dist]: https://unpkg.com/@sanity/client/umd/
2840
2562
  [bundlephobia]: https://bundlephobia.com/package/@sanity/client
2841
2563
  [esm.sh]: https://esm.sh
2842
2564
  [Node.js]: https://nodejs.org/en/
@@ -0,0 +1,87 @@
1
+ import { a as ServerError, n as parseJsonText, r as ClientError, s as httpResponseFromFetch } from "./request-SnMg7nUX.js";
2
+ import { Observable } from "rxjs";
3
+ import { createDebug } from "obug";
4
+ const log = createDebug("sanity:client");
5
+ let nextRequestId = 1;
6
+ /**
7
+ * Run an asset upload through `XMLHttpRequest` so we can surface per-chunk
8
+ * upload progress events. get-it v9 / fetch has no equivalent hook in the
9
+ * browser, so the observable asset-upload API falls back to this path when
10
+ * `XMLHttpRequest` is available.
11
+ *
12
+ * @internal
13
+ */
14
+ function uploadWithProgress(options) {
15
+ return new Observable((subscriber) => {
16
+ let xhr = new XMLHttpRequest(), requestId = nextRequestId++, { url, method, headers, body, withCredentials, timeout, signal } = options;
17
+ log("[%d] %s %s (XHR upload with progress)", requestId, method, url), xhr.open(method, url), xhr.withCredentials = withCredentials, typeof timeout == "number" && timeout > 0 && (xhr.timeout = timeout);
18
+ for (let [key, value] of Object.entries(headers)) xhr.setRequestHeader(key, value);
19
+ xhr.upload.onprogress = (e) => {
20
+ subscriber.next({
21
+ type: "progress",
22
+ stage: "upload",
23
+ percent: e.lengthComputable ? Math.round(e.loaded / e.total * 100) : 0,
24
+ total: e.total || void 0,
25
+ loaded: e.loaded,
26
+ lengthComputable: e.lengthComputable
27
+ });
28
+ }, xhr.onload = () => {
29
+ if (log("[%d] %s %s — %d", requestId, method, url, xhr.status), xhr.status >= 400) {
30
+ let errorHeaders = parseXhrResponseHeaders(xhr.getAllResponseHeaders()), canonical = httpResponseFromFetch({
31
+ status: xhr.status,
32
+ statusText: xhr.statusText,
33
+ headers: errorHeaders,
34
+ body: parseJsonText(xhr.responseText, errorHeaders),
35
+ url: xhr.responseURL
36
+ }, url, method);
37
+ subscriber.error(xhr.status >= 500 ? new ServerError(canonical) : new ClientError(canonical));
38
+ return;
39
+ }
40
+ let responseBody;
41
+ try {
42
+ responseBody = JSON.parse(xhr.responseText);
43
+ } catch {
44
+ subscriber.error(/* @__PURE__ */ Error("Failed to parse upload response as JSON"));
45
+ return;
46
+ }
47
+ subscriber.next({
48
+ type: "response",
49
+ body: responseBody
50
+ }), subscriber.complete();
51
+ }, xhr.onerror = () => {
52
+ log("[%d] %s %s — network error", requestId, method, url), subscriber.error(/* @__PURE__ */ Error("XHR upload network error"));
53
+ }, xhr.ontimeout = () => {
54
+ log("[%d] %s %s — timed out after %dms", requestId, method, url, timeout), subscriber.error(new DOMException(`The operation timed out after ${timeout}ms while attempting to reach ${url}`, "TimeoutError"));
55
+ }, xhr.onabort = () => {
56
+ subscriber.error(new DOMException("Upload aborted", "AbortError"));
57
+ };
58
+ let onSignalAbort = () => xhr.abort();
59
+ if (signal) {
60
+ if (signal.aborted) {
61
+ subscriber.error(new DOMException("Upload aborted", "AbortError"));
62
+ return;
63
+ }
64
+ signal.addEventListener("abort", onSignalAbort, { once: !0 });
65
+ }
66
+ return xhr.send(body), () => {
67
+ signal?.removeEventListener("abort", onSignalAbort), xhr.abort();
68
+ };
69
+ });
70
+ }
71
+ /**
72
+ * Parse `XMLHttpRequest.getAllResponseHeaders()` output (CRLF-separated
73
+ * `name: value` lines) into a `Headers` instance.
74
+ */
75
+ function parseXhrResponseHeaders(raw) {
76
+ let headers = new Headers();
77
+ for (let line of raw.split("\r\n")) {
78
+ let separator = line.indexOf(":");
79
+ if (!(separator <= 0)) try {
80
+ headers.append(line.slice(0, separator).trim(), line.slice(separator + 1).trim());
81
+ } catch {}
82
+ }
83
+ return headers;
84
+ }
85
+ export { uploadWithProgress };
86
+
87
+ //# sourceMappingURL=browserUpload-2tz6Sdqp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browserUpload-2tz6Sdqp.js","names":[],"sources":["../src/http/browserUpload.ts"],"sourcesContent":["import {createDebug} from 'obug'\nimport {Observable} from 'rxjs'\n\nimport type {UploadEvent} from '../types'\nimport {ClientError, httpResponseFromFetch, ServerError} from './errors'\nimport {parseJsonText} from './request'\n\nconst log = createDebug('sanity:client')\n\nlet nextRequestId = 1\n\n/**\n * Options for a browser-side asset upload that needs progress events.\n *\n * @internal\n */\nexport interface BrowserUploadOptions {\n url: string\n method: string\n headers: Record<string, string>\n body: unknown\n withCredentials: boolean\n /** Milliseconds before the upload is aborted; `false` and `0` both disable the timeout. */\n timeout?: number | false\n signal?: AbortSignal\n}\n\n/**\n * Run an asset upload through `XMLHttpRequest` so we can surface per-chunk\n * upload progress events. get-it v9 / fetch has no equivalent hook in the\n * browser, so the observable asset-upload API falls back to this path when\n * `XMLHttpRequest` is available.\n *\n * @internal\n */\nexport function uploadWithProgress<T>(options: BrowserUploadOptions): Observable<UploadEvent<T>> {\n return new Observable<UploadEvent<T>>((subscriber) => {\n const xhr = new XMLHttpRequest()\n const requestId = nextRequestId++\n const {url, method, headers, body, withCredentials, timeout, signal} = options\n\n log('[%d] %s %s (XHR upload with progress)', requestId, method, url)\n\n xhr.open(method, url)\n xhr.withCredentials = withCredentials\n if (typeof timeout === 'number' && timeout > 0) {\n xhr.timeout = timeout\n }\n\n for (const [key, value] of Object.entries(headers)) {\n xhr.setRequestHeader(key, value)\n }\n\n xhr.upload.onprogress = (e) => {\n subscriber.next({\n type: 'progress',\n stage: 'upload',\n percent: e.lengthComputable ? Math.round((e.loaded / e.total) * 100) : 0,\n total: e.total || undefined,\n loaded: e.loaded,\n lengthComputable: e.lengthComputable,\n })\n }\n\n xhr.onload = () => {\n log('[%d] %s %s — %d', requestId, method, url, xhr.status)\n\n if (xhr.status >= 400) {\n // Same typed errors as the fetch transport, so consumers can keep\n // detecting `ClientError`/`ServerError` and reading `statusCode`,\n // `responseBody` and the structured API `details` on failed uploads.\n const errorHeaders = parseXhrResponseHeaders(xhr.getAllResponseHeaders())\n const canonical = httpResponseFromFetch(\n {\n status: xhr.status,\n statusText: xhr.statusText,\n headers: errorHeaders,\n body: parseJsonText(xhr.responseText, errorHeaders),\n url: xhr.responseURL,\n },\n url,\n method,\n )\n subscriber.error(\n xhr.status >= 500 ? new ServerError(canonical) : new ClientError(canonical),\n )\n return\n }\n\n let responseBody: T\n try {\n responseBody = JSON.parse(xhr.responseText) as T\n } catch {\n subscriber.error(new Error('Failed to parse upload response as JSON'))\n return\n }\n\n subscriber.next({type: 'response', body: responseBody})\n subscriber.complete()\n }\n\n xhr.onerror = () => {\n log('[%d] %s %s — network error', requestId, method, url)\n subscriber.error(new Error('XHR upload network error'))\n }\n\n xhr.ontimeout = () => {\n log('[%d] %s %s — timed out after %dms', requestId, method, url, timeout)\n // Same error shape as the fetch transport's timeout rejection.\n subscriber.error(\n new DOMException(\n `The operation timed out after ${timeout}ms while attempting to reach ${url}`,\n 'TimeoutError',\n ),\n )\n }\n\n xhr.onabort = () => {\n subscriber.error(new DOMException('Upload aborted', 'AbortError'))\n }\n\n const onSignalAbort = () => xhr.abort()\n if (signal) {\n if (signal.aborted) {\n // `xhr.abort()` before `send()` fires no `abort` event per spec, so\n // error out directly instead of relying on `onabort`.\n subscriber.error(new DOMException('Upload aborted', 'AbortError'))\n return undefined\n }\n signal.addEventListener('abort', onSignalAbort, {once: true})\n }\n\n xhr.send(body as XMLHttpRequestBodyInit)\n\n // Unsubscribing cancels the in-flight upload, mirroring how the fetch\n // path aborts its request (`_observe`). After settle this is a no-op —\n // except for detaching from the caller's signal, which may be long-lived\n // and must not accumulate a listener per upload.\n return () => {\n signal?.removeEventListener('abort', onSignalAbort)\n xhr.abort()\n }\n })\n}\n\n/**\n * Parse `XMLHttpRequest.getAllResponseHeaders()` output (CRLF-separated\n * `name: value` lines) into a `Headers` instance.\n */\nfunction parseXhrResponseHeaders(raw: string): Headers {\n const headers = new Headers()\n for (const line of raw.split('\\r\\n')) {\n const separator = line.indexOf(':')\n if (separator <= 0) continue\n try {\n headers.append(line.slice(0, separator).trim(), line.slice(separator + 1).trim())\n } catch {\n // Skip header lines the Headers constructor rejects — better a partial\n // header record on the error than no error details at all.\n }\n }\n return headers\n}\n"],"mappings":";;;AAOA,MAAM,MAAM,YAAY,eAAe;AAEvC,IAAI,gBAAgB;;;;;;;;;AA0BpB,SAAgB,mBAAsB,SAA2D;CAC/F,OAAO,IAAI,YAA4B,eAAe;EACpD,IAAM,MAAM,IAAI,eAAe,GACzB,YAAY,iBACZ,EAAC,KAAK,QAAQ,SAAS,MAAM,iBAAiB,SAAS,WAAU;EAMvE,AAJA,IAAI,yCAAyC,WAAW,QAAQ,GAAG,GAEnE,IAAI,KAAK,QAAQ,GAAG,GACpB,IAAI,kBAAkB,iBAClB,OAAO,WAAY,YAAY,UAAU,MAC3C,IAAI,UAAU;EAGhB,KAAK,IAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,GAC/C,IAAI,iBAAiB,KAAK,KAAK;EAmEjC,AAhEA,IAAI,OAAO,cAAc,MAAM;GAC7B,WAAW,KAAK;IACd,MAAM;IACN,OAAO;IACP,SAAS,EAAE,mBAAmB,KAAK,MAAO,EAAE,SAAS,EAAE,QAAS,GAAG,IAAI;IACvE,OAAO,EAAE,SAAS,KAAA;IAClB,QAAQ,EAAE;IACV,kBAAkB,EAAE;GACtB,CAAC;EACH,GAEA,IAAI,eAAe;GAGjB,IAFA,IAAI,mBAAmB,WAAW,QAAQ,KAAK,IAAI,MAAM,GAErD,IAAI,UAAU,KAAK;IAIrB,IAAM,eAAe,wBAAwB,IAAI,sBAAsB,CAAC,GAClE,YAAY,sBAChB;KACE,QAAQ,IAAI;KACZ,YAAY,IAAI;KAChB,SAAS;KACT,MAAM,cAAc,IAAI,cAAc,YAAY;KAClD,KAAK,IAAI;IACX,GACA,KACA,MACF;IACA,WAAW,MACT,IAAI,UAAU,MAAM,IAAI,YAAY,SAAS,IAAI,IAAI,YAAY,SAAS,CAC5E;IACA;GACF;GAEA,IAAI;GACJ,IAAI;IACF,eAAe,KAAK,MAAM,IAAI,YAAY;GAC5C,QAAQ;IACN,WAAW,MAAM,gBAAI,MAAM,yCAAyC,CAAC;IACrE;GACF;GAGA,AADA,WAAW,KAAK;IAAC,MAAM;IAAY,MAAM;GAAY,CAAC,GACtD,WAAW,SAAS;EACtB,GAEA,IAAI,gBAAgB;GAElB,AADA,IAAI,8BAA8B,WAAW,QAAQ,GAAG,GACxD,WAAW,MAAM,gBAAI,MAAM,0BAA0B,CAAC;EACxD,GAEA,IAAI,kBAAkB;GAGpB,AAFA,IAAI,qCAAqC,WAAW,QAAQ,KAAK,OAAO,GAExE,WAAW,MACT,IAAI,aACF,iCAAiC,QAAQ,+BAA+B,OACxE,cACF,CACF;EACF,GAEA,IAAI,gBAAgB;GAClB,WAAW,MAAM,IAAI,aAAa,kBAAkB,YAAY,CAAC;EACnE;EAEA,IAAM,sBAAsB,IAAI,MAAM;EACtC,IAAI,QAAQ;GACV,IAAI,OAAO,SAAS;IAGlB,WAAW,MAAM,IAAI,aAAa,kBAAkB,YAAY,CAAC;IACjE;GACF;GACA,OAAO,iBAAiB,SAAS,eAAe,EAAC,MAAM,GAAI,CAAC;EAC9D;EAQA,OANA,IAAI,KAAK,IAA8B,SAM1B;GAEX,AADA,QAAQ,oBAAoB,SAAS,aAAa,GAClD,IAAI,MAAM;EACZ;CACF,CAAC;AACH;;;;;AAMA,SAAS,wBAAwB,KAAsB;CACrD,IAAM,UAAU,IAAI,QAAQ;CAC5B,KAAK,IAAM,QAAQ,IAAI,MAAM,MAAM,GAAG;EACpC,IAAM,YAAY,KAAK,QAAQ,GAAG;EAC9B,mBAAa,IACjB,IAAI;GACF,QAAQ,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC,CAAC,KAAK,GAAG,KAAK,MAAM,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC;EAClF,QAAQ,CAGR;CACF;CACA,OAAO;AACT"}