@sanity/client 8.0.0 → 8.2.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 +265 -0
- package/dist/{browserUpload-CQgx9YYo.js → browserUpload-2tz6Sdqp.js} +4 -3
- package/dist/browserUpload-2tz6Sdqp.js.map +1 -0
- package/dist/{browserUpload-icWlVP15.js → browserUpload-CwpNx7Vl.js} +4 -3
- package/dist/browserUpload-CwpNx7Vl.js.map +1 -0
- package/dist/{config-a8VajuEY.js → config-3wiPP-sZ.js} +2 -2
- package/dist/config-3wiPP-sZ.js.map +1 -0
- package/dist/csm.js +2 -2
- package/dist/csm.js.map +1 -1
- package/dist/index.d.ts +17 -11
- package/dist/index.js +610 -136
- package/dist/index.js.map +1 -1
- package/dist/index.node.d.ts +918 -26
- package/dist/index.node.js +559 -66
- package/dist/index.node.js.map +1 -1
- package/dist/media-library.d.ts +1 -1
- package/dist/{request-CJxcN16k.js → request-BhMuKj0D.js} +10 -9
- package/dist/request-BhMuKj0D.js.map +1 -0
- package/dist/{request-k7VS_NnC.js → request-SnMg7nUX.js} +10 -9
- package/dist/request-SnMg7nUX.js.map +1 -0
- package/dist/{resolveEditInfo-sq7yF78q.js → resolveEditInfo-Cz-smq3a.js} +17 -3
- package/dist/resolveEditInfo-Cz-smq3a.js.map +1 -0
- package/dist/stega.js +1 -1
- package/dist/{stegaEncodeSourceMap-DkoIlutY.js → stegaEncodeSourceMap-DbM2fTN4.js} +8 -2
- package/dist/stegaEncodeSourceMap-DbM2fTN4.js.map +1 -0
- package/dist/{stegaEncodeSourceMap-B2fGArSf.js → stegaEncodeSourceMap-YR3NQ3iz.js} +2 -2
- package/dist/{stegaEncodeSourceMap-B2fGArSf.js.map → stegaEncodeSourceMap-YR3NQ3iz.js.map} +1 -1
- package/dist/{types-CUxZSgB2.d.ts → types-nJhm5Nyq.d.ts} +910 -24
- package/package.json +26 -11
- package/src/SanityClient.ts +39 -20
- package/src/assets/AssetsClient.ts +54 -5
- package/src/collaboration/CollaborationCommentsClient.ts +387 -0
- package/src/collaboration/comments.ts +313 -0
- package/src/collaboration/types.ts +252 -0
- package/src/csm/applySourceDocuments.ts +2 -4
- package/src/csm/draftUtils.ts +23 -4
- package/src/data/dataMethods.ts +9 -20
- package/src/data/eventsource.ts +71 -41
- package/src/data/listen.ts +20 -5
- package/src/data/live.ts +17 -9
- package/src/data/resolveEventSourceFetch.ts +9 -1
- package/src/defineCreateClient.ts +5 -1
- package/src/functions/FunctionsClient.ts +66 -0
- package/src/functions/invoke.ts +176 -0
- package/src/http/browserUpload.ts +1 -0
- package/src/http/errors.ts +2 -1
- package/src/http/request.ts +8 -14
- package/src/mediaLibrary/MediaLibraryVideoClient.ts +1 -1
- package/src/types.ts +420 -4
- package/src/validators.ts +1 -1
- package/src/warnings.ts +7 -1
- package/dist/browserUpload-CQgx9YYo.js.map +0 -1
- package/dist/browserUpload-icWlVP15.js.map +0 -1
- package/dist/config-a8VajuEY.js.map +0 -1
- package/dist/request-CJxcN16k.js.map +0 -1
- package/dist/request-k7VS_NnC.js.map +0 -1
- package/dist/resolveEditInfo-sq7yF78q.js.map +0 -1
- package/dist/stegaEncodeSourceMap-DkoIlutY.js.map +0 -1
package/README.md
CHANGED
|
@@ -145,6 +145,17 @@ export async function updateDocumentTitle(_id, title) {
|
|
|
145
145
|
- [Getting video playback information](#getting-video-playback-information)
|
|
146
146
|
- [Working with signed playback information](#working-with-signed-playback-information)
|
|
147
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)
|
|
152
|
+
- [Collaboration Comments API](#collaboration-comments-api)
|
|
153
|
+
- [Configuration](#configuration-1)
|
|
154
|
+
- [Creating comments and replies](#creating-comments-and-replies)
|
|
155
|
+
- [Updating and deleting comments](#updating-and-deleting-comments)
|
|
156
|
+
- [Reactions](#reactions)
|
|
157
|
+
- [Fetching comments](#fetching-comments)
|
|
158
|
+
- [Listening for comment changes](#listening-for-comment-changes)
|
|
148
159
|
- [License](#license)
|
|
149
160
|
- [Migrate](#migrate)
|
|
150
161
|
|
|
@@ -930,6 +941,8 @@ Likewise, you can also have the client return the document _before_ the mutation
|
|
|
930
941
|
|
|
931
942
|
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.
|
|
932
943
|
|
|
944
|
+
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.
|
|
945
|
+
|
|
933
946
|
### Fetch a single document
|
|
934
947
|
|
|
935
948
|
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.
|
|
@@ -2447,6 +2460,258 @@ if (playbackInfo.renditions?.length) {
|
|
|
2447
2460
|
|
|
2448
2461
|
Available resolutions depend on the source video but typically include `1080p`, `480p`, and `270p`.
|
|
2449
2462
|
|
|
2463
|
+
### Invoking functions
|
|
2464
|
+
|
|
2465
|
+
Call a Sanity Pubsub Function on demand. These APIs are available on the `client.functions` namespace.
|
|
2466
|
+
|
|
2467
|
+
Only `sanity.function.pubsub` functions can be invoked this way. Every other type is driven by its own trigger.
|
|
2468
|
+
|
|
2469
|
+
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.
|
|
2470
|
+
|
|
2471
|
+
```js
|
|
2472
|
+
import {createClient} from '@sanity/client'
|
|
2473
|
+
|
|
2474
|
+
const client = createClient({
|
|
2475
|
+
projectId: 'your-project-id',
|
|
2476
|
+
apiVersion: '2025-02-19',
|
|
2477
|
+
token: 'valid-token',
|
|
2478
|
+
stackId: 'your-stack-id',
|
|
2479
|
+
})
|
|
2480
|
+
|
|
2481
|
+
const result = await client.functions.invoke('my-function', {
|
|
2482
|
+
event: {data: {hello: 'world'}},
|
|
2483
|
+
})
|
|
2484
|
+
```
|
|
2485
|
+
|
|
2486
|
+
The payload given as `event.data` is what the function receives as `event.data`. It defaults to `{}` when omitted.
|
|
2487
|
+
|
|
2488
|
+
Both Promise and Observable forms are available:
|
|
2489
|
+
|
|
2490
|
+
- `client.functions.invoke(name, request)` resolves with the function's return value
|
|
2491
|
+
- `client.observable.functions.invoke(name, request)` emits it and completes
|
|
2492
|
+
|
|
2493
|
+
```ts
|
|
2494
|
+
// The return value is typed through the generic; it is not validated at runtime
|
|
2495
|
+
const summary = await client.functions.invoke<{words: number}>('summarize', {
|
|
2496
|
+
event: {data: {documentId: 'abc123'}},
|
|
2497
|
+
})
|
|
2498
|
+
```
|
|
2499
|
+
|
|
2500
|
+
#### Choosing a stack
|
|
2501
|
+
|
|
2502
|
+
`stackId` on the request wins over `stackId` in the client config, which lets one client reach functions in more than one stack:
|
|
2503
|
+
|
|
2504
|
+
```js
|
|
2505
|
+
await client.functions.invoke('my-function', {stackId: 'another-stack-id'})
|
|
2506
|
+
```
|
|
2507
|
+
|
|
2508
|
+
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.
|
|
2509
|
+
|
|
2510
|
+
Invoking a name the stack doesn't declare or a non-pubsub function rejects.
|
|
2511
|
+
|
|
2512
|
+
#### Scoping to an organization
|
|
2513
|
+
|
|
2514
|
+
Project scope is the default. For an organization-scoped stack, set `organizationId`:
|
|
2515
|
+
|
|
2516
|
+
```js
|
|
2517
|
+
const client = createClient({
|
|
2518
|
+
projectId: 'your-project-id',
|
|
2519
|
+
apiVersion: '2025-02-19',
|
|
2520
|
+
token: 'valid-token',
|
|
2521
|
+
stackId: 'your-stack-id',
|
|
2522
|
+
organizationId: 'your-organization-id',
|
|
2523
|
+
})
|
|
2524
|
+
```
|
|
2525
|
+
|
|
2526
|
+
It can also be passed per call, and wins over the client config:
|
|
2527
|
+
|
|
2528
|
+
```js
|
|
2529
|
+
await client.functions.invoke('my-function', {organizationId: 'another-organization-id'})
|
|
2530
|
+
```
|
|
2531
|
+
|
|
2532
|
+
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`.
|
|
2533
|
+
|
|
2534
|
+
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>`.
|
|
2535
|
+
|
|
2536
|
+
#### Return values and timeouts
|
|
2537
|
+
|
|
2538
|
+
The request stays open until the function finishes, and resolves with whatever it returned. A function that returns nothing resolves to `undefined`.
|
|
2539
|
+
|
|
2540
|
+
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:
|
|
2541
|
+
|
|
2542
|
+
```js
|
|
2543
|
+
const controller = new AbortController()
|
|
2544
|
+
|
|
2545
|
+
const result = await client.functions.invoke('slow-function', {
|
|
2546
|
+
timeout: 0, // or e.g. 600000 for a ten minute deadline
|
|
2547
|
+
signal: controller.signal,
|
|
2548
|
+
})
|
|
2549
|
+
```
|
|
2550
|
+
|
|
2551
|
+
### Collaboration Comments API
|
|
2552
|
+
|
|
2553
|
+
Read and write comments on documents in an organization resource. Available on `client.collaboration.comments`, with Observable equivalents on `client.observable.collaboration.comments`.
|
|
2554
|
+
|
|
2555
|
+
> **Note:** This API is currently in alpha and may change in future releases.
|
|
2556
|
+
|
|
2557
|
+
#### Configuration
|
|
2558
|
+
|
|
2559
|
+
Comments are organization-scoped. The client needs an `organizationId`, plus either a `resource` or `projectId` and `dataset`:
|
|
2560
|
+
|
|
2561
|
+
```js
|
|
2562
|
+
import {createClient} from '@sanity/client'
|
|
2563
|
+
|
|
2564
|
+
const client = createClient({
|
|
2565
|
+
apiVersion: '2026-07-18',
|
|
2566
|
+
token: 'valid-token',
|
|
2567
|
+
useCdn: false,
|
|
2568
|
+
organizationId: 'your-organization-id',
|
|
2569
|
+
resource: {
|
|
2570
|
+
type: 'canvas',
|
|
2571
|
+
id: 'your-canvas-id',
|
|
2572
|
+
},
|
|
2573
|
+
})
|
|
2574
|
+
```
|
|
2575
|
+
|
|
2576
|
+
A project-based client only needs `organizationId` added; the dataset resource is derived from `projectId` and `dataset`:
|
|
2577
|
+
|
|
2578
|
+
```js
|
|
2579
|
+
const client = createClient({
|
|
2580
|
+
projectId: 'your-project-id',
|
|
2581
|
+
dataset: 'production',
|
|
2582
|
+
apiVersion: '2026-07-18',
|
|
2583
|
+
token: 'valid-token',
|
|
2584
|
+
useCdn: false,
|
|
2585
|
+
organizationId: 'your-organization-id',
|
|
2586
|
+
})
|
|
2587
|
+
```
|
|
2588
|
+
|
|
2589
|
+
#### Creating comments and replies
|
|
2590
|
+
|
|
2591
|
+
A top-level comment needs a `target`. A reply needs a `parentCommentId` instead, and inherits `target`, `status`, and `threadId` from the parent. The `message` is Portable Text:
|
|
2592
|
+
|
|
2593
|
+
```js
|
|
2594
|
+
const message = [{_type: 'block', children: [{_type: 'span', text: 'Looks good to me'}]}]
|
|
2595
|
+
|
|
2596
|
+
const comment = await client.collaboration.comments.create({
|
|
2597
|
+
message,
|
|
2598
|
+
target: {documentId: 'doc-1', documentType: 'article'},
|
|
2599
|
+
})
|
|
2600
|
+
|
|
2601
|
+
const reply = await client.collaboration.comments.create({
|
|
2602
|
+
message,
|
|
2603
|
+
parentCommentId: comment._id,
|
|
2604
|
+
})
|
|
2605
|
+
```
|
|
2606
|
+
|
|
2607
|
+
Field comments pass a `path`. Inline comments also pass a `range` (block `_key` + character offset):
|
|
2608
|
+
|
|
2609
|
+
```js
|
|
2610
|
+
await client.collaboration.comments.create({
|
|
2611
|
+
message,
|
|
2612
|
+
target: {
|
|
2613
|
+
documentId: 'doc-1',
|
|
2614
|
+
documentType: 'article',
|
|
2615
|
+
path: 'body',
|
|
2616
|
+
range: {
|
|
2617
|
+
start: {_key: 'block-1', offset: 6},
|
|
2618
|
+
end: {_key: 'block-1', offset: 11},
|
|
2619
|
+
},
|
|
2620
|
+
},
|
|
2621
|
+
})
|
|
2622
|
+
```
|
|
2623
|
+
|
|
2624
|
+
When querying, the field is stored as `target.path.field`, so filter with `target.path.field == "body"`, not `target.path == "body"`. The `range` itself is not stored: the API resolves it into a selection (and content snapshot) when the comment is written.
|
|
2625
|
+
|
|
2626
|
+
#### Updating and deleting comments
|
|
2627
|
+
|
|
2628
|
+
`update()` can change `message`, `status`, and/or `range`. Status changes cascade to replies. A `range` re-anchors an inline comment within the field and source document it already targets; pass `null` to clear the selection:
|
|
2629
|
+
|
|
2630
|
+
```js
|
|
2631
|
+
await client.collaboration.comments.update('comment-1', {status: 'resolved'})
|
|
2632
|
+
await client.collaboration.comments.update('comment-1', {
|
|
2633
|
+
range: {start: {_key: 'block-1', offset: 0}, end: {_key: 'block-1', offset: 12}},
|
|
2634
|
+
})
|
|
2635
|
+
await client.collaboration.comments.update('comment-1', {range: null})
|
|
2636
|
+
```
|
|
2637
|
+
|
|
2638
|
+
`delete()` also deletes replies. The returned `documentIds` covers the comment and every deleted reply:
|
|
2639
|
+
|
|
2640
|
+
```js
|
|
2641
|
+
const {documentIds} = await client.collaboration.comments.delete('comment-1')
|
|
2642
|
+
```
|
|
2643
|
+
|
|
2644
|
+
#### Reactions
|
|
2645
|
+
|
|
2646
|
+
Reactions are added and removed on behalf of the authenticated user, and are identified by emoji short name:
|
|
2647
|
+
|
|
2648
|
+
```js
|
|
2649
|
+
await client.collaboration.comments.addReaction('comment-1', ':+1:')
|
|
2650
|
+
await client.collaboration.comments.removeReaction('comment-1', ':+1:')
|
|
2651
|
+
```
|
|
2652
|
+
|
|
2653
|
+
#### Fetching comments
|
|
2654
|
+
|
|
2655
|
+
`fetch()` runs GROQ against the organization store holding the comments for the configured resource. Same `query` / `params` shape as `client.fetch()`, but Content Lake options like `perspective` and `useCdn` do not apply. The store is not scoped to comments, so filter on `_type == "sanity.comment"`:
|
|
2656
|
+
|
|
2657
|
+
```js
|
|
2658
|
+
const comments = await client.collaboration.comments.fetch(
|
|
2659
|
+
'*[_type == "sanity.comment" && status == "open"] | order(_createdAt desc)[0...50]',
|
|
2660
|
+
)
|
|
2661
|
+
```
|
|
2662
|
+
|
|
2663
|
+
Use `getTargetDocumentRef()` to build the global document ref (`resourceType:resourceId:publishedId`) for filters. Draft and version ids are normalized to the published id:
|
|
2664
|
+
|
|
2665
|
+
```js
|
|
2666
|
+
client.collaboration.comments.getTargetDocumentRef('doc-1') // 'canvas:your-canvas-id:doc-1'
|
|
2667
|
+
client.collaboration.comments.getTargetDocumentRef('drafts.doc-1') // 'canvas:your-canvas-id:doc-1'
|
|
2668
|
+
|
|
2669
|
+
const ref = client.collaboration.comments.getTargetDocumentRef('doc-1')
|
|
2670
|
+
|
|
2671
|
+
const comments = await client.collaboration.comments.fetch(
|
|
2672
|
+
'*[_type == "sanity.comment" && target.document._ref == $ref]',
|
|
2673
|
+
{ref},
|
|
2674
|
+
)
|
|
2675
|
+
```
|
|
2676
|
+
|
|
2677
|
+
That returns comments across published, draft, and versions of the document. Narrow to one perspective with `target.sourceDocumentId`:
|
|
2678
|
+
|
|
2679
|
+
```js
|
|
2680
|
+
const draftComments = await client.collaboration.comments.fetch(
|
|
2681
|
+
'*[_type == "sanity.comment" && target.document._ref == $ref && target.sourceDocumentId == $sourceDocumentId]',
|
|
2682
|
+
{
|
|
2683
|
+
ref: client.collaboration.comments.getTargetDocumentRef('doc-1'),
|
|
2684
|
+
sourceDocumentId: 'drafts.doc-1',
|
|
2685
|
+
},
|
|
2686
|
+
)
|
|
2687
|
+
```
|
|
2688
|
+
|
|
2689
|
+
Pass a type parameter when you know the result shape:
|
|
2690
|
+
|
|
2691
|
+
```ts
|
|
2692
|
+
import type {CollaborationCommentDocument} from '@sanity/client'
|
|
2693
|
+
|
|
2694
|
+
const comments = await client.collaboration.comments.fetch<CollaborationCommentDocument[]>(
|
|
2695
|
+
'*[_type == "sanity.comment"]',
|
|
2696
|
+
)
|
|
2697
|
+
```
|
|
2698
|
+
|
|
2699
|
+
#### Listening for comment changes
|
|
2700
|
+
|
|
2701
|
+
`listen()` mirrors `client.listen()` and returns an Observable of mutation events:
|
|
2702
|
+
|
|
2703
|
+
```js
|
|
2704
|
+
const subscription = client.collaboration.comments
|
|
2705
|
+
.listen('*[_type == "sanity.comment" && target.document._ref == $ref]', {
|
|
2706
|
+
ref: client.collaboration.comments.getTargetDocumentRef('doc-1'),
|
|
2707
|
+
})
|
|
2708
|
+
.subscribe((event) => {
|
|
2709
|
+
console.log(event.documentId, event.transition)
|
|
2710
|
+
})
|
|
2711
|
+
|
|
2712
|
+
subscription.unsubscribe()
|
|
2713
|
+
```
|
|
2714
|
+
|
|
2450
2715
|
## License
|
|
2451
2716
|
|
|
2452
2717
|
MIT © [Sanity.io](https://www.sanity.io/)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ServerError, n as parseJsonText, r as ClientError, s as httpResponseFromFetch } from "./request-
|
|
1
|
+
import { a as ServerError, n as parseJsonText, r as ClientError, s as httpResponseFromFetch } from "./request-SnMg7nUX.js";
|
|
2
2
|
import { Observable } from "rxjs";
|
|
3
3
|
import { createDebug } from "obug";
|
|
4
4
|
const log = createDebug("sanity:client");
|
|
@@ -31,7 +31,8 @@ function uploadWithProgress(options) {
|
|
|
31
31
|
status: xhr.status,
|
|
32
32
|
statusText: xhr.statusText,
|
|
33
33
|
headers: errorHeaders,
|
|
34
|
-
body: parseJsonText(xhr.responseText, errorHeaders)
|
|
34
|
+
body: parseJsonText(xhr.responseText, errorHeaders),
|
|
35
|
+
url: xhr.responseURL
|
|
35
36
|
}, url, method);
|
|
36
37
|
subscriber.error(xhr.status >= 500 ? new ServerError(canonical) : new ClientError(canonical));
|
|
37
38
|
return;
|
|
@@ -83,4 +84,4 @@ function parseXhrResponseHeaders(raw) {
|
|
|
83
84
|
}
|
|
84
85
|
export { uploadWithProgress };
|
|
85
86
|
|
|
86
|
-
//# sourceMappingURL=browserUpload-
|
|
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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ServerError, n as parseJsonText, r as ClientError, s as httpResponseFromFetch } from "./request-
|
|
1
|
+
import { a as ServerError, n as parseJsonText, r as ClientError, s as httpResponseFromFetch } from "./request-BhMuKj0D.js";
|
|
2
2
|
import { Observable } from "rxjs";
|
|
3
3
|
import { createDebug } from "obug";
|
|
4
4
|
const log = createDebug("sanity:client");
|
|
@@ -31,7 +31,8 @@ function uploadWithProgress(options) {
|
|
|
31
31
|
status: xhr.status,
|
|
32
32
|
statusText: xhr.statusText,
|
|
33
33
|
headers: errorHeaders,
|
|
34
|
-
body: parseJsonText(xhr.responseText, errorHeaders)
|
|
34
|
+
body: parseJsonText(xhr.responseText, errorHeaders),
|
|
35
|
+
url: xhr.responseURL
|
|
35
36
|
}, url, method);
|
|
36
37
|
subscriber.error(xhr.status >= 500 ? new ServerError(canonical) : new ClientError(canonical));
|
|
37
38
|
return;
|
|
@@ -83,4 +84,4 @@ function parseXhrResponseHeaders(raw) {
|
|
|
83
84
|
}
|
|
84
85
|
export { uploadWithProgress };
|
|
85
86
|
|
|
86
|
-
//# sourceMappingURL=browserUpload-
|
|
87
|
+
//# sourceMappingURL=browserUpload-CwpNx7Vl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browserUpload-CwpNx7Vl.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"}
|
|
@@ -69,7 +69,7 @@ const createWarningPrinter = (message) => once((...args) => console.warn(message
|
|
|
69
69
|
"Since you haven't set a value for `useCdn`, we will deliver content using our",
|
|
70
70
|
"global, edge-cached API-CDN. If you wish to have content delivered faster, set",
|
|
71
71
|
"`useCdn: false` to use the Live API. Note: You may incur higher costs using the live API."
|
|
72
|
-
]), printCdnPreviewDraftsWarning = createWarningPrinter(["The Sanity client is configured with the `perspective` set to `drafts` or `previewDrafts`, which doesn't support the API-CDN.", "The Live API will be used instead. Set `useCdn: false` in your configuration to hide this warning."]), printPreviewDraftsDeprecationWarning = createWarningPrinter(["The `previewDrafts` perspective has been renamed to `drafts` and will be removed in a future API version"]), printBrowserTokenWarning = createWarningPrinter(["You have configured Sanity client to use a token in the browser. This may cause unintentional security issues.", `See ${generateHelpUrl("js-client-browser-token")} for more information and how to hide this warning.`]), printCredentialedTokenWarning = createWarningPrinter(["You have configured Sanity client to use a token, but also provided `withCredentials: true`.", "This is no longer supported - only token will be used - remove `withCredentials: true`."]), printNoApiVersionSpecifiedWarning = createWarningPrinter(["Using the Sanity client without specifying an API version is deprecated.", `See ${generateHelpUrl("js-client-api-version")}`]), printNoDefaultExport = createWarningPrinter(["The default export of @sanity/client has been deprecated. Use the named export `createClient` instead."]), printCreateVersionWithBaseIdWarning = createWarningPrinter(["You have called `createVersion()` with a defined `document`.
|
|
72
|
+
]), printCdnPreviewDraftsWarning = createWarningPrinter(["The Sanity client is configured with the `perspective` set to `drafts` or `previewDrafts`, which doesn't support the API-CDN.", "The Live API will be used instead. Set `useCdn: false` in your configuration to hide this warning."]), printPreviewDraftsDeprecationWarning = createWarningPrinter(["The `previewDrafts` perspective has been renamed to `drafts` and will be removed in a future API version"]), printBrowserTokenWarning = createWarningPrinter(["You have configured Sanity client to use a token in the browser. This may cause unintentional security issues.", `See ${generateHelpUrl("js-client-browser-token")} for more information and how to hide this warning.`]), printCredentialedTokenWarning = createWarningPrinter(["You have configured Sanity client to use a token, but also provided `withCredentials: true`.", "This is no longer supported - only token will be used - remove `withCredentials: true`."]), printNoApiVersionSpecifiedWarning = createWarningPrinter(["Using the Sanity client without specifying an API version is deprecated.", `See ${generateHelpUrl("js-client-api-version")}`]), printNoDefaultExport = createWarningPrinter(["The default export of @sanity/client has been deprecated. Use the named export `createClient` instead."]), printCreateVersionWithBaseIdWarning = createWarningPrinter(["You have called `createVersion()` with a defined `document`.", "If you are creating a version of a document that already exists, prefer providing `baseId` and `releaseId` instead."]), printDeprecatedUriOptionWarning = createWarningPrinter(["The `uri` request option has been renamed to `url`.", "Please update your code to use `url` instead. Support for `uri` will be removed in a future version."]), printDeprecatedResourceConfigWarning = createWarningPrinter(["The `~experimental_resource` configuration property has been renamed to `resource`.", "Please update your client configuration to use `resource` instead. Support for `~experimental_resource` will be removed in a future version."]), defaultConfig = {
|
|
73
73
|
apiHost: "https://api.sanity.io",
|
|
74
74
|
apiVersion: "1",
|
|
75
75
|
useProjectHostname: !0,
|
|
@@ -123,4 +123,4 @@ const initConfig = (config, prevConfig) => {
|
|
|
123
123
|
};
|
|
124
124
|
export { validateDocumentId as _, printCreateVersionWithBaseIdWarning as a, validateVersionIdMatch as b, printPreviewDraftsDeprecationWarning as c, requestTag as d, requireDocumentId as f, validateAssetType as g, resourceGuard as h, printCdnPreviewDraftsWarning as i, dataset as l, resourceConfig as m, initConfig as n, printDeprecatedUriOptionWarning as o, requireDocumentType as p, validateApiPerspective as r, printNoDefaultExport as s, defaultConfig as t, hasDataset as u, validateInsert as v, validateObject as y };
|
|
125
125
|
|
|
126
|
-
//# sourceMappingURL=config-
|
|
126
|
+
//# sourceMappingURL=config-3wiPP-sZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-3wiPP-sZ.js","names":["resourceConfig","validate.requestTag"],"sources":["../src/generateHelpUrl.ts","../src/validators.ts","../src/util/once.ts","../src/warnings.ts","../src/config.ts"],"sourcesContent":["const BASE_URL = 'https://www.sanity.io/help/'\n\nexport function generateHelpUrl(slug: string) {\n return BASE_URL + slug\n}\n","import type {Any, InitializedClientConfig, SanityDocumentStub} from './types'\n\nconst VALID_ASSET_TYPES = ['image', 'file']\nconst VALID_INSERT_LOCATIONS = ['before', 'after', 'replace']\n\nexport const dataset = (name: string) => {\n if (!/^(~[a-z0-9]{1}[-\\w]{0,63}|[a-z0-9]{1}[-\\w]{0,63})$/.test(name)) {\n throw new Error(\n 'Datasets can only contain lowercase characters, numbers, underscores and dashes, and start with tilde, and be maximum 64 characters',\n )\n }\n}\n\nexport const projectId = (id: string) => {\n if (!/^[-a-z0-9]+$/i.test(id)) {\n throw new Error('`projectId` can only contain only a-z, 0-9 and dashes')\n }\n}\n\nexport const validateAssetType = (type: string) => {\n if (VALID_ASSET_TYPES.indexOf(type) === -1) {\n throw new Error(`Invalid asset type: ${type}. Must be one of ${VALID_ASSET_TYPES.join(', ')}`)\n }\n}\n\nexport const validateObject = (op: string, val: Any) => {\n if (val === null || typeof val !== 'object' || Array.isArray(val)) {\n throw new Error(`${op}() takes an object of properties`)\n }\n}\n\nexport const validateDocumentId = (op: string, id: string) => {\n if (typeof id !== 'string' || !/^[a-z0-9_][a-z0-9_.-]{0,127}$/i.test(id) || id.includes('..')) {\n throw new Error(`${op}(): \"${id}\" is not a valid document ID`)\n }\n}\n\nexport const requireDocumentId = (op: string, doc: Record<string, Any>) => {\n if (!doc._id) {\n throw new Error(`${op}() requires that the document contains an ID (\"_id\" property)`)\n }\n\n validateDocumentId(op, doc._id)\n}\n\nconst validateDocumentType = (op: string, type: string) => {\n if (typeof type !== 'string') {\n throw new Error(`\\`${op}()\\`: \\`${type}\\` is not a valid document type`)\n }\n}\n\nexport const requireDocumentType = (op: string, doc: Record<string, Any>) => {\n if (!doc._type) {\n throw new Error(`\\`${op}()\\` requires that the document contains a type (\\`_type\\` property)`)\n }\n\n validateDocumentType(op, doc._type)\n}\n\nexport const validateVersionIdMatch = (builtVersionId: string, document: SanityDocumentStub) => {\n if (document._id && document._id !== builtVersionId) {\n throw new Error(\n `The provided document ID (\\`${document._id}\\`) does not match the generated version ID (\\`${builtVersionId}\\`)`,\n )\n }\n}\n\nexport const validateInsert = (at: string, selector: string, items: Any[]) => {\n const signature = 'insert(at, selector, items)'\n if (VALID_INSERT_LOCATIONS.indexOf(at) === -1) {\n const valid = VALID_INSERT_LOCATIONS.map((loc) => `\"${loc}\"`).join(', ')\n throw new Error(`${signature} takes an \"at\"-argument which is one of: ${valid}`)\n }\n\n if (typeof selector !== 'string') {\n throw new Error(`${signature} takes a \"selector\"-argument which must be a string`)\n }\n\n if (!Array.isArray(items)) {\n throw new Error(`${signature} takes an \"items\"-argument which must be an array`)\n }\n}\n\nexport const hasDataset = (config: InitializedClientConfig): string => {\n // Check if dataset is directly on the config\n if (config.dataset) {\n return config.dataset\n }\n\n // Check if dataset is in resource configuration\n // Note: ~experimental_resource is normalized to resource during client initialization\n const resource = config.resource\n if (resource && resource.type === 'dataset') {\n const segments = resource.id.split('.')\n if (segments.length !== 2) {\n throw new Error('Dataset resource ID must be in the format \"project.dataset\"')\n }\n return segments[1]\n }\n\n throw new Error('`dataset` must be provided to perform queries')\n}\n\nexport const requestTag = (tag: string) => {\n if (typeof tag !== 'string' || !/^[a-z0-9._-]{1,75}$/i.test(tag)) {\n throw new Error(\n `Tag can only contain alphanumeric characters, underscores, dashes and dots, and be between one and 75 characters long.`,\n )\n }\n\n return tag\n}\n\nexport const resourceConfig = (config: InitializedClientConfig): void => {\n // Note: ~experimental_resource is normalized to resource during client initialization\n const resource = config.resource\n if (!resource) {\n throw new Error('`resource` must be provided to perform resource queries')\n }\n const {type, id} = resource\n\n switch (type) {\n case 'dataset': {\n const segments = id.split('.')\n if (segments.length !== 2) {\n throw new Error('Dataset resource ID must be in the format \"project.dataset\"')\n }\n return\n }\n case 'dashboard':\n case 'media-library':\n case 'canvas': {\n return\n }\n default:\n // @ts-expect-error - handle all supported resource types\n throw new Error(`Unsupported resource type: ${type.toString()}`)\n }\n}\n\nexport const resourceGuard = (service: string, config: InitializedClientConfig): void => {\n // Note: ~experimental_resource is normalized to resource during client initialization\n const resource = config.resource\n if (resource) {\n throw new Error(`\\`${service}\\` does not support resource-based operations`)\n }\n}\n","import type {Any} from '../types'\n\nexport function once(fn: Any) {\n let didCall = false\n let returnValue: Any\n return (...args: Any[]) => {\n if (didCall) {\n return returnValue\n }\n returnValue = fn(...args)\n didCall = true\n return returnValue\n }\n}\n","import {generateHelpUrl} from './generateHelpUrl'\nimport {type Any} from './types'\nimport {once} from './util/once'\n\nconst createWarningPrinter = (message: string[]) =>\n // oxlint-disable-next-line no-console\n once((...args: Any[]) => console.warn(message.join(' '), ...args))\n\nexport const printCdnAndWithCredentialsWarning = createWarningPrinter([\n `Because you set \\`withCredentials\\` to true, we will override your \\`useCdn\\``,\n `setting to be false since (cookie-based) credentials are never set on the CDN`,\n])\n\nexport const printCdnWarning = createWarningPrinter([\n `Since you haven't set a value for \\`useCdn\\`, we will deliver content using our`,\n `global, edge-cached API-CDN. If you wish to have content delivered faster, set`,\n `\\`useCdn: false\\` to use the Live API. Note: You may incur higher costs using the live API.`,\n])\n\nexport const printCdnPreviewDraftsWarning = createWarningPrinter([\n `The Sanity client is configured with the \\`perspective\\` set to \\`drafts\\` or \\`previewDrafts\\`, which doesn't support the API-CDN.`,\n `The Live API will be used instead. Set \\`useCdn: false\\` in your configuration to hide this warning.`,\n])\n\nexport const printPreviewDraftsDeprecationWarning = createWarningPrinter([\n `The \\`previewDrafts\\` perspective has been renamed to \\`drafts\\` and will be removed in a future API version`,\n])\n\nexport const printBrowserTokenWarning = createWarningPrinter([\n 'You have configured Sanity client to use a token in the browser. This may cause unintentional security issues.',\n `See ${generateHelpUrl(\n 'js-client-browser-token',\n )} for more information and how to hide this warning.`,\n])\n\nexport const printCredentialedTokenWarning = createWarningPrinter([\n 'You have configured Sanity client to use a token, but also provided `withCredentials: true`.',\n 'This is no longer supported - only token will be used - remove `withCredentials: true`.',\n])\n\nexport const printNoApiVersionSpecifiedWarning = createWarningPrinter([\n 'Using the Sanity client without specifying an API version is deprecated.',\n `See ${generateHelpUrl('js-client-api-version')}`,\n])\n\nexport const printNoDefaultExport = createWarningPrinter([\n 'The default export of @sanity/client has been deprecated. Use the named export `createClient` instead.',\n])\n\n// Phrased as a condition rather than as a correction, because the client cannot\n// tell the two cases apart. `baseId` creates a version of a document that\n// already exists, so a caller creating a genuinely new document inside a release\n// has no alternative to `document` - and the previous wording told them they had\n// picked the wrong approach when they had not.\nexport const printCreateVersionWithBaseIdWarning = createWarningPrinter([\n 'You have called `createVersion()` with a defined `document`.',\n 'If you are creating a version of a document that already exists, prefer providing `baseId` and `releaseId` instead.',\n])\n\nexport const printDeprecatedUriOptionWarning = createWarningPrinter([\n 'The `uri` request option has been renamed to `url`.',\n 'Please update your code to use `url` instead. Support for `uri` will be removed in a future version.',\n])\n\nexport const printDeprecatedResourceConfigWarning = createWarningPrinter([\n 'The `~experimental_resource` configuration property has been renamed to `resource`.',\n 'Please update your client configuration to use `resource` instead. Support for `~experimental_resource` will be removed in a future version.',\n])\n","import {generateHelpUrl} from './generateHelpUrl'\nimport type {ClientConfig, ClientPerspective, InitializedClientConfig} from './types'\nimport * as validate from './validators'\nimport * as warnings from './warnings'\n\nconst defaultCdnHost = 'apicdn.sanity.io'\nexport const defaultConfig = {\n apiHost: 'https://api.sanity.io',\n apiVersion: '1',\n useProjectHostname: true,\n stega: {enabled: false},\n} satisfies ClientConfig\n\nconst LOCALHOSTS = ['localhost', '127.0.0.1', '0.0.0.0']\nconst isLocal = (host: string) => LOCALHOSTS.indexOf(host) !== -1\n\nfunction validateApiVersion(apiVersion: string) {\n if (apiVersion === '1' || apiVersion === 'X') {\n return\n }\n\n const apiDate = new Date(apiVersion)\n const apiVersionValid =\n /^\\d{4}-\\d{2}-\\d{2}$/.test(apiVersion) && apiDate instanceof Date && apiDate.getTime() > 0\n\n if (!apiVersionValid) {\n throw new Error('Invalid API version string, expected `1` or date in format `YYYY-MM-DD`')\n }\n}\n\n/**\n * @internal - it may have breaking changes in any release\n */\nexport function validateApiPerspective(\n perspective: unknown,\n): asserts perspective is ClientPerspective {\n if (Array.isArray(perspective) && perspective.length > 1 && perspective.includes('raw')) {\n throw new TypeError(\n `Invalid API perspective value: \"raw\". The raw-perspective can not be combined with other perspectives`,\n )\n }\n}\n\nexport const initConfig = (\n config: Partial<ClientConfig>,\n prevConfig: Partial<ClientConfig>,\n): InitializedClientConfig => {\n const specifiedConfig = {\n ...prevConfig,\n ...config,\n stega: {\n ...(typeof prevConfig.stega === 'boolean'\n ? {enabled: prevConfig.stega}\n : prevConfig.stega || defaultConfig.stega),\n ...(typeof config.stega === 'boolean' ? {enabled: config.stega} : config.stega || {}),\n },\n }\n if (!specifiedConfig.apiVersion) {\n warnings.printNoApiVersionSpecifiedWarning()\n }\n\n const newConfig = {\n ...defaultConfig,\n ...specifiedConfig,\n } as InitializedClientConfig\n\n // Normalize resource configuration - prefer `resource` over deprecated `~experimental_resource`\n if (newConfig['~experimental_resource'] && !newConfig.resource) {\n warnings.printDeprecatedResourceConfigWarning()\n newConfig.resource = newConfig['~experimental_resource']\n }\n\n const resourceConfig = newConfig.resource\n const projectBased = newConfig.useProjectHostname && !resourceConfig\n\n if (typeof Promise === 'undefined') {\n const helpUrl = generateHelpUrl('js-client-promise-polyfill')\n throw new Error(`No native Promise-implementation found, polyfill needed - see ${helpUrl}`)\n }\n\n if (projectBased && !newConfig.projectId) {\n throw new Error('Configuration must contain `projectId`')\n }\n\n if (resourceConfig) {\n validate.resourceConfig(newConfig)\n }\n\n if (typeof newConfig.perspective !== 'undefined') {\n validateApiPerspective(newConfig.perspective)\n }\n\n if ('encodeSourceMap' in newConfig) {\n throw new Error(\n `It looks like you're using options meant for '@sanity/preview-kit/client'. 'encodeSourceMap' is not supported in '@sanity/client'. Did you mean 'stega.enabled'?`,\n )\n }\n if ('encodeSourceMapAtPath' in newConfig) {\n throw new Error(\n `It looks like you're using options meant for '@sanity/preview-kit/client'. 'encodeSourceMapAtPath' is not supported in '@sanity/client'. Did you mean 'stega.filter'?`,\n )\n }\n if (typeof newConfig.stega.enabled !== 'boolean') {\n throw new Error(`stega.enabled must be a boolean, received ${newConfig.stega.enabled}`)\n }\n if (newConfig.stega.enabled && newConfig.stega.studioUrl === undefined) {\n throw new Error(`stega.studioUrl must be defined when stega.enabled is true`)\n }\n if (\n newConfig.stega.enabled &&\n typeof newConfig.stega.studioUrl !== 'string' &&\n typeof newConfig.stega.studioUrl !== 'function'\n ) {\n throw new Error(\n `stega.studioUrl must be a string or a function, received ${newConfig.stega.studioUrl}`,\n )\n }\n\n const isBrowser = typeof window !== 'undefined' && window.location && window.location.hostname\n const isLocalhost = isBrowser && isLocal(window.location.hostname)\n\n const hasToken = Boolean(newConfig.token)\n if (newConfig.withCredentials && hasToken) {\n warnings.printCredentialedTokenWarning()\n newConfig.withCredentials = false\n }\n\n if (isBrowser && isLocalhost && hasToken && newConfig.ignoreBrowserTokenWarning !== true) {\n warnings.printBrowserTokenWarning()\n } else if (typeof newConfig.useCdn === 'undefined') {\n warnings.printCdnWarning()\n }\n\n if (projectBased) {\n validate.projectId(newConfig.projectId!)\n }\n\n if (newConfig.dataset) {\n validate.dataset(newConfig.dataset)\n }\n\n if ('requestTagPrefix' in newConfig) {\n // Allow setting and unsetting request tag prefix\n newConfig.requestTagPrefix = newConfig.requestTagPrefix\n ? validate.requestTag(newConfig.requestTagPrefix).replace(/\\.+$/, '')\n : undefined\n }\n\n newConfig.apiVersion = `${newConfig.apiVersion}`.replace(/^v/, '')\n newConfig.isDefaultApi = newConfig.apiHost === defaultConfig.apiHost\n\n if (newConfig.useCdn === true && newConfig.withCredentials) {\n warnings.printCdnAndWithCredentialsWarning()\n }\n\n // If `useCdn` is undefined, we treat it as `true`\n newConfig.useCdn = newConfig.useCdn !== false && !newConfig.withCredentials\n\n validateApiVersion(newConfig.apiVersion)\n\n const hostParts = newConfig.apiHost.split('://', 2)\n const protocol = hostParts[0]\n const host = hostParts[1]\n const cdnHost = newConfig.isDefaultApi ? defaultCdnHost : host\n\n if (projectBased) {\n newConfig.url = `${protocol}://${newConfig.projectId}.${host}/v${newConfig.apiVersion}`\n newConfig.cdnUrl = `${protocol}://${newConfig.projectId}.${cdnHost}/v${newConfig.apiVersion}`\n } else {\n newConfig.url = `${newConfig.apiHost}/v${newConfig.apiVersion}`\n newConfig.cdnUrl = newConfig.url\n }\n\n return newConfig\n}\n"],"mappings":"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"}
|
package/dist/csm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as validateApiPerspective } from "./config-
|
|
2
|
-
import { S as toString, _ as isPublishedId, a as resolveMapping, c as parseJsonPath, d as VERSION_FOLDER, f as getDraftId, g as isDraftId, h as getVersionId, i as walkMap, l as studioPathToJsonPath, m as getVersionFromId, o as jsonPath, p as getPublishedId, r as createEditUrl, s as jsonPathToStudioPath, t as resolveEditInfo, u as DRAFTS_FOLDER, v as isVersionId, x as studioPath_exports, y as get } from "./resolveEditInfo-
|
|
1
|
+
import { r as validateApiPerspective } from "./config-3wiPP-sZ.js";
|
|
2
|
+
import { S as toString, _ as isPublishedId, a as resolveMapping, c as parseJsonPath, d as VERSION_FOLDER, f as getDraftId, g as isDraftId, h as getVersionId, i as walkMap, l as studioPathToJsonPath, m as getVersionFromId, o as jsonPath, p as getPublishedId, r as createEditUrl, s as jsonPathToStudioPath, t as resolveEditInfo, u as DRAFTS_FOLDER, v as isVersionId, x as studioPath_exports, y as get } from "./resolveEditInfo-Cz-smq3a.js";
|
|
3
3
|
/**
|
|
4
4
|
* This resolves the perspectives to how documents should be resolved when applying optimistic updates,
|
|
5
5
|
* like in `applySourceDocuments`.
|
package/dist/csm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csm.js","names":["paths.toString","paths.get"],"sources":["../src/csm/resolvePerspectives.ts","../src/csm/createSourceDocumentResolver.ts","../src/csm/applySourceDocuments.ts","../src/csm/resolvedKeyedSourcePath.ts","../src/csm/resolveEditUrl.ts"],"sourcesContent":["import {validateApiPerspective} from '../config'\nimport type {StackablePerspective} from '../types'\nimport type {ClientPerspective} from './types'\n\n/**\n * This resolves the perspectives to how documents should be resolved when applying optimistic updates,\n * like in `applySourceDocuments`.\n * @internal\n */\nexport function resolvePerspectives(\n perspective: Exclude<ClientPerspective, 'raw'>,\n): ('published' | 'drafts' | StackablePerspective)[] {\n validateApiPerspective(perspective)\n\n if (Array.isArray(perspective)) {\n if (!perspective.includes('published')) {\n return [...perspective, 'published']\n }\n return perspective\n }\n switch (perspective) {\n case 'previewDrafts':\n case 'drafts':\n return ['drafts', 'published']\n case 'published':\n default:\n return ['published']\n }\n}\n","import {getDraftId, getPublishedId, getVersionId} from './draftUtils'\nimport {resolvePerspectives} from './resolvePerspectives'\nimport type {ClientPerspective, ContentSourceMapDocuments, SanityDocument} from './types'\n\n/** @internal */\nexport type ResolvedDocument = Partial<SanityDocument> &\n Required<Pick<SanityDocument, '_id' | '_type'>>\n\n/** @internal */\nexport type MatchedDocument = Partial<SanityDocument> &\n Required<Pick<SanityDocument, '_id' | '_type' | '_originalId'>>\n\n/** @internal */\nexport function createSourceDocumentResolver(\n getCachedDocument: (\n sourceDocument: ContentSourceMapDocuments[number],\n ) => ResolvedDocument | null | undefined,\n _perspective: Exclude<ClientPerspective, 'raw'>,\n) {\n const perspectives = resolvePerspectives(_perspective)\n function findDocument(sourceDocument: ContentSourceMapDocuments[number]) {\n for (const perspective of perspectives) {\n let match: ReturnType<typeof getCachedDocument> = null\n if (perspective.startsWith('r')) {\n match = getCachedDocument({\n ...sourceDocument,\n _id: getVersionId(sourceDocument._id, perspective),\n })\n }\n if (perspective === 'drafts') {\n match = getCachedDocument({\n ...sourceDocument,\n _id: getDraftId(sourceDocument._id),\n })\n }\n if (perspective === 'published') {\n match = getCachedDocument({\n ...sourceDocument,\n _id: getPublishedId(sourceDocument._id),\n })\n }\n if (match) {\n return {...match, _id: getPublishedId(match._id), _originalId: match._id}\n }\n }\n return null\n }\n // define resolver that loops over source documents and perspectives\n return function resolveSourceDocument(\n sourceDocument: ContentSourceMapDocuments[number],\n ): MatchedDocument | null {\n return findDocument(sourceDocument)\n }\n}\n","import {createSourceDocumentResolver} from './createSourceDocumentResolver'\nimport {parseJsonPath} from './jsonPath'\nimport {resolveMapping} from './resolveMapping'\nimport * as paths from './studioPath'\nimport type {\n
|
|
1
|
+
{"version":3,"file":"csm.js","names":["paths.toString","paths.get"],"sources":["../src/csm/resolvePerspectives.ts","../src/csm/createSourceDocumentResolver.ts","../src/csm/applySourceDocuments.ts","../src/csm/resolvedKeyedSourcePath.ts","../src/csm/resolveEditUrl.ts"],"sourcesContent":["import {validateApiPerspective} from '../config'\nimport type {StackablePerspective} from '../types'\nimport type {ClientPerspective} from './types'\n\n/**\n * This resolves the perspectives to how documents should be resolved when applying optimistic updates,\n * like in `applySourceDocuments`.\n * @internal\n */\nexport function resolvePerspectives(\n perspective: Exclude<ClientPerspective, 'raw'>,\n): ('published' | 'drafts' | StackablePerspective)[] {\n validateApiPerspective(perspective)\n\n if (Array.isArray(perspective)) {\n if (!perspective.includes('published')) {\n return [...perspective, 'published']\n }\n return perspective\n }\n switch (perspective) {\n case 'previewDrafts':\n case 'drafts':\n return ['drafts', 'published']\n case 'published':\n default:\n return ['published']\n }\n}\n","import {getDraftId, getPublishedId, getVersionId} from './draftUtils'\nimport {resolvePerspectives} from './resolvePerspectives'\nimport type {ClientPerspective, ContentSourceMapDocuments, SanityDocument} from './types'\n\n/** @internal */\nexport type ResolvedDocument = Partial<SanityDocument> &\n Required<Pick<SanityDocument, '_id' | '_type'>>\n\n/** @internal */\nexport type MatchedDocument = Partial<SanityDocument> &\n Required<Pick<SanityDocument, '_id' | '_type' | '_originalId'>>\n\n/** @internal */\nexport function createSourceDocumentResolver(\n getCachedDocument: (\n sourceDocument: ContentSourceMapDocuments[number],\n ) => ResolvedDocument | null | undefined,\n _perspective: Exclude<ClientPerspective, 'raw'>,\n) {\n const perspectives = resolvePerspectives(_perspective)\n function findDocument(sourceDocument: ContentSourceMapDocuments[number]) {\n for (const perspective of perspectives) {\n let match: ReturnType<typeof getCachedDocument> = null\n if (perspective.startsWith('r')) {\n match = getCachedDocument({\n ...sourceDocument,\n _id: getVersionId(sourceDocument._id, perspective),\n })\n }\n if (perspective === 'drafts') {\n match = getCachedDocument({\n ...sourceDocument,\n _id: getDraftId(sourceDocument._id),\n })\n }\n if (perspective === 'published') {\n match = getCachedDocument({\n ...sourceDocument,\n _id: getPublishedId(sourceDocument._id),\n })\n }\n if (match) {\n return {...match, _id: getPublishedId(match._id), _originalId: match._id}\n }\n }\n return null\n }\n // define resolver that loops over source documents and perspectives\n return function resolveSourceDocument(\n sourceDocument: ContentSourceMapDocuments[number],\n ): MatchedDocument | null {\n return findDocument(sourceDocument)\n }\n}\n","import {createSourceDocumentResolver} from './createSourceDocumentResolver'\nimport {parseJsonPath} from './jsonPath'\nimport {resolveMapping} from './resolveMapping'\nimport * as paths from './studioPath'\nimport type {\n ApplySourceDocumentsUpdateFunction,\n ClientPerspective,\n ContentSourceMap,\n ContentSourceMapDocuments,\n SanityDocument,\n} from './types'\nimport {walkMap} from './walkMap'\n\n/**\n * Optimistically applies source documents to a result, using the content source map to trace fields.\n * Can be used to apply mutations to documents being edited in a Studio, or any mutation on Content Lake, to a result with extremely low latency.\n * @alpha\n */\nexport function applySourceDocuments<Result = unknown>(\n result: Result,\n resultSourceMap: ContentSourceMap | undefined,\n getCachedDocument: (\n sourceDocument: ContentSourceMapDocuments[number],\n ) =>\n | (Partial<SanityDocument> & Required<Pick<SanityDocument, '_id' | '_type'>>)\n | null\n | undefined,\n updateFn: ApplySourceDocumentsUpdateFunction,\n perspective: Exclude<ClientPerspective, 'raw'>,\n): Result {\n if (!resultSourceMap) return result\n\n const resolveDocument = createSourceDocumentResolver(getCachedDocument, perspective)\n const cachedDocuments = resultSourceMap.documents?.map?.(resolveDocument) || []\n\n return walkMap(JSON.parse(JSON.stringify(result)), (value, path) => {\n const resolveMappingResult = resolveMapping(path, resultSourceMap)\n if (!resolveMappingResult) {\n return value\n }\n\n const {mapping, pathSuffix} = resolveMappingResult\n if (mapping.type !== 'value') {\n return value\n }\n\n if (mapping.source.type !== 'documentValue') {\n return value\n }\n\n const sourceDocument = resultSourceMap.documents[mapping.source.document]\n const sourcePath = resultSourceMap.paths[mapping.source.path]\n\n if (sourceDocument) {\n const parsedPath = parseJsonPath(sourcePath + pathSuffix)\n const stringifiedPath = paths.toString(parsedPath)\n const cachedDocument = cachedDocuments[mapping.source.document]\n\n if (!cachedDocument) {\n return value\n }\n\n const changedValue = cachedDocument\n ? paths.get<Result[keyof Result]>(cachedDocument, stringifiedPath, value)\n : value\n return value === changedValue\n ? value\n : updateFn<Result[keyof Result]>(changedValue as Result[keyof Result], {\n cachedDocument,\n previousValue: value as Result[keyof Result],\n sourceDocument,\n sourcePath: parsedPath,\n })\n }\n\n return value\n }) as Result\n}\n","import {jsonPath, parseJsonPath} from './jsonPath'\nimport type {ContentSourceMapParsedPath} from './types'\n\n/**\n * @internal\n */\nexport function resolvedKeyedSourcePath(options: {\n keyedResultPath: ContentSourceMapParsedPath\n pathSuffix?: string\n sourceBasePath: string\n}): ContentSourceMapParsedPath {\n const {keyedResultPath, pathSuffix, sourceBasePath} = options\n\n const inferredResultPath = pathSuffix === undefined ? [] : parseJsonPath(pathSuffix)\n\n const inferredPath = keyedResultPath.slice(keyedResultPath.length - inferredResultPath.length)\n\n const inferredPathSuffix = inferredPath.length ? jsonPath(inferredPath).slice(1) : ''\n\n return parseJsonPath(sourceBasePath + inferredPathSuffix)\n}\n","import {createEditUrl} from './createEditUrl'\nimport {studioPathToJsonPath} from './jsonPath'\nimport {resolveEditInfo} from './resolveEditInfo'\nimport type {ResolveEditUrlOptions} from './types'\n\n/** @alpha */\nexport function resolveEditUrl(\n options: ResolveEditUrlOptions,\n): ReturnType<typeof createEditUrl> | undefined {\n const {resultSourceMap, studioUrl} = options\n const resultPath = studioPathToJsonPath(options.resultPath)\n\n const editInfo = resolveEditInfo({\n resultPath,\n resultSourceMap,\n studioUrl,\n })\n if (!editInfo) {\n return undefined\n }\n\n return createEditUrl(editInfo)\n}\n"],"mappings":";;;;;;;AASA,SAAgB,oBACd,aACmD;CAGnD,IAFA,uBAAuB,WAAW,GAE9B,MAAM,QAAQ,WAAW,GAI3B,OAHK,YAAY,SAAS,WAAW,IAG9B,cAFE,CAAC,GAAG,aAAa,WAAW;CAIvC,QAAQ,aAAR;EACE,KAAK;EACL,KAAK,UACH,OAAO,CAAC,UAAU,WAAW;EAE/B,SACE,OAAO,CAAC,WAAW;CACvB;AACF;;ACfA,SAAgB,6BACd,mBAGA,cACA;CACA,IAAM,eAAe,oBAAoB,YAAY;CACrD,SAAS,aAAa,gBAAmD;EACvE,KAAK,IAAM,eAAe,cAAc;GACtC,IAAI,QAA8C;GAmBlD,IAlBI,YAAY,WAAW,GAAG,MAC5B,QAAQ,kBAAkB;IACxB,GAAG;IACH,KAAK,aAAa,eAAe,KAAK,WAAW;GACnD,CAAC,IAEC,gBAAgB,aAClB,QAAQ,kBAAkB;IACxB,GAAG;IACH,KAAK,WAAW,eAAe,GAAG;GACpC,CAAC,IAEC,gBAAgB,gBAClB,QAAQ,kBAAkB;IACxB,GAAG;IACH,KAAK,eAAe,eAAe,GAAG;GACxC,CAAC,IAEC,OACF,OAAO;IAAC,GAAG;IAAO,KAAK,eAAe,MAAM,GAAG;IAAG,aAAa,MAAM;GAAG;EAE5E;EACA,OAAO;CACT;CAEA,OAAO,SAAS,sBACd,gBACwB;EACxB,OAAO,aAAa,cAAc;CACpC;AACF;;;;;;ACnCA,SAAgB,qBACd,QACA,iBACA,mBAMA,UACA,aACQ;CACR,IAAI,CAAC,iBAAiB,OAAO;CAE7B,IAAM,kBAAkB,6BAA6B,mBAAmB,WAAW,GAC7E,kBAAkB,gBAAgB,WAAW,MAAM,eAAe,KAAK,CAAC;CAE9E,OAAO,QAAQ,KAAK,MAAM,KAAK,UAAU,MAAM,CAAC,IAAI,OAAO,SAAS;EAClE,IAAM,uBAAuB,eAAe,MAAM,eAAe;EACjE,IAAI,CAAC,sBACH,OAAO;EAGT,IAAM,EAAC,SAAS,eAAc;EAK9B,IAJI,QAAQ,SAAS,WAIjB,QAAQ,OAAO,SAAS,iBAC1B,OAAO;EAGT,IAAM,iBAAiB,gBAAgB,UAAU,QAAQ,OAAO,WAC1D,aAAa,gBAAgB,MAAM,QAAQ,OAAO;EAExD,IAAI,gBAAgB;GAClB,IAAM,aAAa,cAAc,aAAa,UAAU,GAClD,kBAAkBA,SAAe,UAAU,GAC3C,iBAAiB,gBAAgB,QAAQ,OAAO;GAEtD,IAAI,CAAC,gBACH,OAAO;GAGT,IAAM,eAAe,iBACjBC,IAAgC,gBAAgB,iBAAiB,KAAK,IACtE;GACJ,OAAO,UAAU,eACb,QACA,SAA+B,cAAsC;IACnE;IACA,eAAe;IACf;IACA,YAAY;GACd,CAAC;EACP;EAEA,OAAO;CACT,CAAC;AACH;;;;ACvEA,SAAgB,wBAAwB,SAIT;CAC7B,IAAM,EAAC,iBAAiB,YAAY,mBAAkB,SAEhD,qBAAqB,eAAe,KAAA,IAAY,CAAC,IAAI,cAAc,UAAU,GAE7E,eAAe,gBAAgB,MAAM,gBAAgB,SAAS,mBAAmB,MAAM,GAEvF,qBAAqB,aAAa,SAAS,SAAS,YAAY,CAAC,CAAC,MAAM,CAAC,IAAI;CAEnF,OAAO,cAAc,iBAAiB,kBAAkB;AAC1D;;ACdA,SAAgB,eACd,SAC8C;CAC9C,IAAM,EAAC,iBAAiB,cAAa,SAC/B,aAAa,qBAAqB,QAAQ,UAAU,GAEpD,WAAW,gBAAgB;EAC/B;EACA;EACA;CACF,CAAC;CACI,cAIL,OAAO,cAAc,QAAQ;AAC/B"}
|