@sanity/client 7.26.2 → 8.0.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.
- package/README.md +5 -377
- package/dist/browserUpload-CQgx9YYo.js +86 -0
- package/dist/browserUpload-CQgx9YYo.js.map +1 -0
- package/dist/browserUpload-icWlVP15.js +86 -0
- package/dist/browserUpload-icWlVP15.js.map +1 -0
- package/dist/config-a8VajuEY.js +126 -0
- package/dist/config-a8VajuEY.js.map +1 -0
- package/dist/csm.d.ts +122 -335
- package/dist/csm.js +79 -91
- package/dist/csm.js.map +1 -1
- package/dist/dist-C9ExSk2R.js +73 -0
- package/dist/dist-C9ExSk2R.js.map +1 -0
- package/dist/dist-Z8cIRxoB.js +69 -0
- package/dist/dist-Z8cIRxoB.js.map +1 -0
- package/dist/index.d.ts +107 -6723
- package/dist/index.js +2822 -2847
- package/dist/index.js.map +1 -1
- package/dist/{index.d.cts → index.node.d.ts} +4291 -5328
- package/dist/index.node.js +3131 -0
- package/dist/index.node.js.map +1 -0
- package/dist/isRecord-Kfmt-nk-.js +7 -0
- package/dist/isRecord-Kfmt-nk-.js.map +1 -0
- package/dist/media-library.d.ts +9 -100
- package/dist/media-library.js +36 -14
- package/dist/media-library.js.map +1 -1
- package/dist/request-CJxcN16k.js +372 -0
- package/dist/request-CJxcN16k.js.map +1 -0
- package/dist/request-k7VS_NnC.js +354 -0
- package/dist/request-k7VS_NnC.js.map +1 -0
- package/dist/resolveEditInfo-sq7yF78q.js +325 -0
- package/dist/resolveEditInfo-sq7yF78q.js.map +1 -0
- package/dist/rolldown-runtime-vyAXikos.js +9 -0
- package/dist/stega.d.ts +78 -7137
- package/dist/stega.js +27 -20
- package/dist/stega.js.map +1 -1
- package/dist/stegaClean-C18wLWau.js +21 -0
- package/dist/stegaClean-C18wLWau.js.map +1 -0
- package/dist/stegaEncodeSourceMap-B2fGArSf.js +163 -0
- package/dist/stegaEncodeSourceMap-B2fGArSf.js.map +1 -0
- package/dist/stegaEncodeSourceMap-DkoIlutY.js +367 -0
- package/dist/stegaEncodeSourceMap-DkoIlutY.js.map +1 -0
- package/dist/{index.browser.d.cts → types-CUxZSgB2.d.ts} +3956 -5256
- package/dist/types-CfGzbXrl.d.ts +108 -0
- package/package.json +64 -141
- package/src/SanityClient.ts +82 -117
- package/src/agent/actions/AgentActionsClient.ts +12 -12
- package/src/agent/actions/commonTypes.ts +2 -1
- package/src/agent/actions/generate.ts +26 -6
- package/src/agent/actions/patch.ts +27 -7
- package/src/agent/actions/prompt.ts +19 -5
- package/src/agent/actions/transform.ts +23 -5
- package/src/agent/actions/translate.ts +23 -5
- package/src/assets/AssetsClient.ts +71 -23
- package/src/csm/applySourceDocuments.ts +3 -1
- package/src/csm/createEditUrl.ts +1 -1
- package/src/csm/draftUtils.ts +0 -1
- package/src/csm/index.ts +2 -2
- package/src/csm/studioPath.ts +2 -1
- package/src/csm/types.ts +8 -2
- package/src/data/dataMethods.ts +801 -349
- package/src/data/eventsource.ts +13 -10
- package/src/data/listen.ts +18 -23
- package/src/data/live.ts +44 -27
- package/src/data/resolveEventSourceFetch.ts +96 -0
- package/src/datasets/DatasetsClient.ts +58 -41
- package/src/defineCreateClient.ts +35 -23
- package/src/http/browserMiddleware.ts +7 -1
- package/src/http/browserUpload.ts +162 -0
- package/src/http/errors.ts +60 -6
- package/src/http/nodeMiddleware.ts +94 -30
- package/src/http/request.ts +310 -87
- package/src/http/requestOptions.ts +131 -15
- package/src/{index.browser.ts → index.node.ts} +9 -4
- package/src/index.ts +4 -3
- package/src/mediaLibrary/MediaLibraryVideoClient.ts +26 -11
- package/src/projects/ProjectsClient.ts +18 -16
- package/src/releases/ReleasesClient.ts +38 -33
- package/src/stega/index.ts +1 -2
- package/src/stega/stegaEncodeSourceMap.ts +5 -0
- package/src/stega/types.ts +2 -2
- package/src/types.ts +148 -105
- package/src/users/UsersClient.ts +10 -14
- package/src/util/shareReplayLatest.ts +1 -1
- package/src/warnings.ts +6 -1
- package/dist/_chunks-cjs/config.cjs +0 -206
- package/dist/_chunks-cjs/config.cjs.map +0 -1
- package/dist/_chunks-cjs/isRecord.cjs +0 -6
- package/dist/_chunks-cjs/isRecord.cjs.map +0 -1
- package/dist/_chunks-cjs/resolveEditInfo.cjs +0 -334
- package/dist/_chunks-cjs/resolveEditInfo.cjs.map +0 -1
- package/dist/_chunks-cjs/stegaClean.cjs +0 -46
- package/dist/_chunks-cjs/stegaClean.cjs.map +0 -1
- package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs +0 -388
- package/dist/_chunks-cjs/stegaEncodeSourceMap.cjs.map +0 -1
- package/dist/_chunks-es/config.js +0 -207
- package/dist/_chunks-es/config.js.map +0 -1
- package/dist/_chunks-es/isRecord.js +0 -7
- package/dist/_chunks-es/isRecord.js.map +0 -1
- package/dist/_chunks-es/resolveEditInfo.js +0 -335
- package/dist/_chunks-es/resolveEditInfo.js.map +0 -1
- package/dist/_chunks-es/stegaClean.js +0 -47
- package/dist/_chunks-es/stegaClean.js.map +0 -1
- package/dist/_chunks-es/stegaEncodeSourceMap.js +0 -389
- package/dist/_chunks-es/stegaEncodeSourceMap.js.map +0 -1
- package/dist/csm.cjs +0 -99
- package/dist/csm.cjs.map +0 -1
- package/dist/csm.d.cts +0 -391
- package/dist/index.browser.cjs +0 -3106
- package/dist/index.browser.cjs.map +0 -1
- package/dist/index.browser.d.ts +0 -6802
- package/dist/index.browser.js +0 -3082
- package/dist/index.browser.js.map +0 -1
- package/dist/index.cjs +0 -2946
- package/dist/index.cjs.map +0 -1
- package/dist/media-library.cjs +0 -20
- package/dist/media-library.cjs.map +0 -1
- package/dist/media-library.d.cts +0 -117
- package/dist/stega.browser.cjs +0 -29
- package/dist/stega.browser.cjs.map +0 -1
- package/dist/stega.browser.d.cts +0 -7200
- package/dist/stega.browser.d.ts +0 -7200
- package/dist/stega.browser.js +0 -24
- package/dist/stega.browser.js.map +0 -1
- package/dist/stega.cjs +0 -29
- package/dist/stega.cjs.map +0 -1
- package/dist/stega.d.cts +0 -7200
- package/src/data/eventsourcePolyfill.ts +0 -7
- package/umd/.gitkeep +0 -1
- package/umd/sanityClient.js +0 -6543
- 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)
|
|
@@ -148,23 +146,7 @@ export async function updateDocumentTitle(_id, title) {
|
|
|
148
146
|
- [Working with signed playback information](#working-with-signed-playback-information)
|
|
149
147
|
- [Downloading MP4 renditions](#downloading-mp4-renditions)
|
|
150
148
|
- [License](#license)
|
|
151
|
-
- [
|
|
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)
|
|
149
|
+
- [Migrate](#migrate)
|
|
168
150
|
|
|
169
151
|
## Requirements
|
|
170
152
|
|
|
@@ -208,24 +190,6 @@ const data = await client.fetch(`count(*)`)
|
|
|
208
190
|
console.log(`Number of documents: ${data}`)
|
|
209
191
|
```
|
|
210
192
|
|
|
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
193
|
#### [TypeScript]
|
|
230
194
|
|
|
231
195
|
```ts
|
|
@@ -437,51 +401,6 @@ const data = await client.fetch(`count(*)`)
|
|
|
437
401
|
console.log(`Number of documents: ${data}`)
|
|
438
402
|
```
|
|
439
403
|
|
|
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
404
|
### Specifying API version
|
|
486
405
|
|
|
487
406
|
Sanity uses ISO dates (YYYY-MM-DD) in UTC timezone for versioning. The explanation for this can be found [in the documentation][api-versioning]
|
|
@@ -2534,301 +2453,11 @@ MIT © [Sanity.io](https://www.sanity.io/)
|
|
|
2534
2453
|
|
|
2535
2454
|
# Migrate
|
|
2536
2455
|
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
### The default `useCdn` is changed to `true`
|
|
2540
|
-
|
|
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
|
|
2544
|
-
import {createClient} from '@sanity/client'
|
|
2545
|
-
|
|
2546
|
-
export const client = createClient({
|
|
2547
|
-
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
|
|
2551
|
-
})
|
|
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
|
-
|
|
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:
|
|
2456
|
+
Migration guides for major version upgrades:
|
|
2651
2457
|
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
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())
|
|
2699
|
-
```
|
|
2700
|
-
|
|
2701
|
-
After:
|
|
2702
|
-
|
|
2703
|
-
```ts
|
|
2704
|
-
import {createClient, ObservableSanityClient} from '@sanity/client'
|
|
2705
|
-
const client = createClient()
|
|
2706
|
-
|
|
2707
|
-
console.log(client.observable instanceof ObservableSanityClient)
|
|
2708
|
-
```
|
|
2709
|
-
|
|
2710
|
-
### `client._requestObservable` is removed, replace with `client.observable.request`
|
|
2711
|
-
|
|
2712
|
-
Before:
|
|
2713
|
-
|
|
2714
|
-
```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()
|
|
2728
|
-
```
|
|
2729
|
-
|
|
2730
|
-
### `client._dataRequest` is removed, replace with `client.dataRequest`
|
|
2731
|
-
|
|
2732
|
-
Before:
|
|
2733
|
-
|
|
2734
|
-
```ts
|
|
2735
|
-
import createClient from '@sanity/client'
|
|
2736
|
-
const client = createClient()
|
|
2737
|
-
|
|
2738
|
-
client._dataRequest(endpoint, body, options)
|
|
2739
|
-
```
|
|
2740
|
-
|
|
2741
|
-
After:
|
|
2742
|
-
|
|
2743
|
-
```ts
|
|
2744
|
-
import {createClient} from '@sanity/client'
|
|
2745
|
-
const client = createClient()
|
|
2746
|
-
|
|
2747
|
-
client.dataRequest(endpoint, body, options)
|
|
2748
|
-
```
|
|
2749
|
-
|
|
2750
|
-
### `client._create_` is removed, replace with one of `client.create`, `client.createIfNotExists` or `client.createOrReplace`
|
|
2751
|
-
|
|
2752
|
-
Before:
|
|
2753
|
-
|
|
2754
|
-
```ts
|
|
2755
|
-
import createClient from '@sanity/client'
|
|
2756
|
-
const client = createClient()
|
|
2757
|
-
|
|
2758
|
-
client._create(doc, 'create', options)
|
|
2759
|
-
client._create(doc, 'createIfNotExists', options)
|
|
2760
|
-
client._create(doc, 'createOrReplace', options)
|
|
2761
|
-
```
|
|
2762
|
-
|
|
2763
|
-
After:
|
|
2764
|
-
|
|
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)
|
|
2772
|
-
```
|
|
2773
|
-
|
|
2774
|
-
### `client.patch.replace` is removed, replace with `client.createOrReplace`
|
|
2775
|
-
|
|
2776
|
-
Before:
|
|
2777
|
-
|
|
2778
|
-
```ts
|
|
2779
|
-
import createClient from '@sanity/client'
|
|
2780
|
-
const client = createClient()
|
|
2781
|
-
|
|
2782
|
-
client.patch('tropic-hab').replace({name: 'Tropical Habanero', ingredients: []}).commit()
|
|
2783
|
-
```
|
|
2784
|
-
|
|
2785
|
-
After:
|
|
2786
|
-
|
|
2787
|
-
```ts
|
|
2788
|
-
import {createClient} from '@sanity/client'
|
|
2789
|
-
const client = createClient()
|
|
2790
|
-
|
|
2791
|
-
client.createOrReplace({
|
|
2792
|
-
_id: 'tropic-hab',
|
|
2793
|
-
_type: 'hotsauce',
|
|
2794
|
-
name: 'Tropical Habanero',
|
|
2795
|
-
ingredients: [],
|
|
2796
|
-
})
|
|
2797
|
-
```
|
|
2798
|
-
|
|
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()
|
|
2806
|
-
|
|
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
|
-
```
|
|
2816
|
-
|
|
2817
|
-
After:
|
|
2818
|
-
|
|
2819
|
-
```ts
|
|
2820
|
-
import {createclient, type AuthProviderResponse} from '@sanity/client'
|
|
2821
|
-
const client = createClient()
|
|
2822
|
-
|
|
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
|
-
```
|
|
2458
|
+
- From `v7`: [docs/MIGRATE-v7.md](docs/MIGRATE-v7.md)
|
|
2459
|
+
- From `v5`: [docs/MIGRATE-v5.md](docs/MIGRATE-v5.md)
|
|
2460
|
+
- From `v4`: [docs/MIGRATE-v4.md](docs/MIGRATE-v4.md)
|
|
2832
2461
|
|
|
2833
2462
|
[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
2463
|
[Deno]: https://deno.land/
|
|
@@ -2836,7 +2465,6 @@ await client.request<void>({uri: '/auth/logout', method: 'POST'})
|
|
|
2836
2465
|
[Bun]: https://bun.sh/
|
|
2837
2466
|
[gzip-badge]: https://img.shields.io/bundlephobia/minzip/@sanity/client?label=gzip%20size&style=flat-square
|
|
2838
2467
|
[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
2468
|
[bundlephobia]: https://bundlephobia.com/package/@sanity/client
|
|
2841
2469
|
[esm.sh]: https://esm.sh
|
|
2842
2470
|
[Node.js]: https://nodejs.org/en/
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { a as ServerError, n as parseJsonText, r as ClientError, s as httpResponseFromFetch } from "./request-CJxcN16k.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, method);
|
|
36
|
+
subscriber.error(xhr.status >= 500 ? new ServerError(canonical) : new ClientError(canonical));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
let responseBody;
|
|
40
|
+
try {
|
|
41
|
+
responseBody = JSON.parse(xhr.responseText);
|
|
42
|
+
} catch {
|
|
43
|
+
subscriber.error(/* @__PURE__ */ Error("Failed to parse upload response as JSON"));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
subscriber.next({
|
|
47
|
+
type: "response",
|
|
48
|
+
body: responseBody
|
|
49
|
+
}), subscriber.complete();
|
|
50
|
+
}, xhr.onerror = () => {
|
|
51
|
+
log("[%d] %s %s — network error", requestId, method, url), subscriber.error(/* @__PURE__ */ Error("XHR upload network error"));
|
|
52
|
+
}, xhr.ontimeout = () => {
|
|
53
|
+
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"));
|
|
54
|
+
}, xhr.onabort = () => {
|
|
55
|
+
subscriber.error(new DOMException("Upload aborted", "AbortError"));
|
|
56
|
+
};
|
|
57
|
+
let onSignalAbort = () => xhr.abort();
|
|
58
|
+
if (signal) {
|
|
59
|
+
if (signal.aborted) {
|
|
60
|
+
subscriber.error(new DOMException("Upload aborted", "AbortError"));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
signal.addEventListener("abort", onSignalAbort, { once: !0 });
|
|
64
|
+
}
|
|
65
|
+
return xhr.send(body), () => {
|
|
66
|
+
signal?.removeEventListener("abort", onSignalAbort), xhr.abort();
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Parse `XMLHttpRequest.getAllResponseHeaders()` output (CRLF-separated
|
|
72
|
+
* `name: value` lines) into a `Headers` instance.
|
|
73
|
+
*/
|
|
74
|
+
function parseXhrResponseHeaders(raw) {
|
|
75
|
+
let headers = new Headers();
|
|
76
|
+
for (let line of raw.split("\r\n")) {
|
|
77
|
+
let separator = line.indexOf(":");
|
|
78
|
+
if (!(separator <= 0)) try {
|
|
79
|
+
headers.append(line.slice(0, separator).trim(), line.slice(separator + 1).trim());
|
|
80
|
+
} catch {}
|
|
81
|
+
}
|
|
82
|
+
return headers;
|
|
83
|
+
}
|
|
84
|
+
export { uploadWithProgress };
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=browserUpload-CQgx9YYo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browserUpload-CQgx9YYo.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 },\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;EAkEjC,AA/DA,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;IACpD,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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { a as ServerError, n as parseJsonText, r as ClientError, s as httpResponseFromFetch } from "./request-k7VS_NnC.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, method);
|
|
36
|
+
subscriber.error(xhr.status >= 500 ? new ServerError(canonical) : new ClientError(canonical));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
let responseBody;
|
|
40
|
+
try {
|
|
41
|
+
responseBody = JSON.parse(xhr.responseText);
|
|
42
|
+
} catch {
|
|
43
|
+
subscriber.error(/* @__PURE__ */ Error("Failed to parse upload response as JSON"));
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
subscriber.next({
|
|
47
|
+
type: "response",
|
|
48
|
+
body: responseBody
|
|
49
|
+
}), subscriber.complete();
|
|
50
|
+
}, xhr.onerror = () => {
|
|
51
|
+
log("[%d] %s %s — network error", requestId, method, url), subscriber.error(/* @__PURE__ */ Error("XHR upload network error"));
|
|
52
|
+
}, xhr.ontimeout = () => {
|
|
53
|
+
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"));
|
|
54
|
+
}, xhr.onabort = () => {
|
|
55
|
+
subscriber.error(new DOMException("Upload aborted", "AbortError"));
|
|
56
|
+
};
|
|
57
|
+
let onSignalAbort = () => xhr.abort();
|
|
58
|
+
if (signal) {
|
|
59
|
+
if (signal.aborted) {
|
|
60
|
+
subscriber.error(new DOMException("Upload aborted", "AbortError"));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
signal.addEventListener("abort", onSignalAbort, { once: !0 });
|
|
64
|
+
}
|
|
65
|
+
return xhr.send(body), () => {
|
|
66
|
+
signal?.removeEventListener("abort", onSignalAbort), xhr.abort();
|
|
67
|
+
};
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Parse `XMLHttpRequest.getAllResponseHeaders()` output (CRLF-separated
|
|
72
|
+
* `name: value` lines) into a `Headers` instance.
|
|
73
|
+
*/
|
|
74
|
+
function parseXhrResponseHeaders(raw) {
|
|
75
|
+
let headers = new Headers();
|
|
76
|
+
for (let line of raw.split("\r\n")) {
|
|
77
|
+
let separator = line.indexOf(":");
|
|
78
|
+
if (!(separator <= 0)) try {
|
|
79
|
+
headers.append(line.slice(0, separator).trim(), line.slice(separator + 1).trim());
|
|
80
|
+
} catch {}
|
|
81
|
+
}
|
|
82
|
+
return headers;
|
|
83
|
+
}
|
|
84
|
+
export { uploadWithProgress };
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=browserUpload-icWlVP15.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browserUpload-icWlVP15.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 },\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;EAkEjC,AA/DA,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;IACpD,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"}
|