@sanity/client 8.6.2 → 8.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sanity/client",
3
- "version": "8.6.2",
3
+ "version": "8.8.0",
4
4
  "description": "Client for retrieving, creating and patching data from Sanity.io",
5
5
  "keywords": [
6
6
  "api",
@@ -43,14 +43,15 @@
43
43
  },
44
44
  "default": "./dist/index.js"
45
45
  },
46
+ "./collaboration": "./dist/collaboration.js",
46
47
  "./csm": "./dist/csm.js",
47
48
  "./stega": "./dist/stega.js",
48
49
  "./media-library": "./dist/media-library.js",
49
50
  "./package.json": "./package.json"
50
51
  },
51
52
  "dependencies": {
52
- "eventsource": "^5.1.1",
53
- "get-it": "^9.5.4",
53
+ "eventsource": "^5.1.2",
54
+ "get-it": "^9.5.7",
54
55
  "obug": "^3.0.0",
55
56
  "rxjs": "^7.8.2"
56
57
  },
@@ -1,7 +1,7 @@
1
- import {getPublishedId} from '@sanity/client/csm'
2
1
  import {type Observable, throwError} from 'rxjs'
3
2
  import {map} from 'rxjs/operators'
4
3
 
4
+ import {version} from '../../package.json'
5
5
  import {_requestObservable, getQuerySizeLimit} from '../data/dataMethods'
6
6
  import {encodeQueryString} from '../data/encodeQueryString'
7
7
  import {
@@ -21,9 +21,13 @@ import type {
21
21
  } from '../types'
22
22
  import defaults from '../util/defaults'
23
23
  import {pick} from '../util/pick'
24
+ import {type CommentResource, getCommentTargetDocumentRef} from './getCommentTargetDocumentRef'
24
25
  import {
26
+ type CollaborationCommentAnchor,
25
27
  type CollaborationCommentCreate,
26
28
  type CollaborationCommentDocument,
29
+ type CollaborationCommentFieldValue,
30
+ type CollaborationCommentRange,
27
31
  type CollaborationCommentReactionShortName,
28
32
  type CollaborationCommentsListenOptions,
29
33
  type CollaborationCommentsRequestOptions,
@@ -42,7 +46,7 @@ function commentUrl(id: string): string {
42
46
  return `/collaboration/comments/${encodeURIComponent(id)}`
43
47
  }
44
48
 
45
- function resolveCommentResource(client: Client): {type: string; id: string} {
49
+ function resolveCommentResource(client: Client): CommentResource {
46
50
  const {resource, projectId, dataset} = client.config()
47
51
 
48
52
  if (resource) {
@@ -86,9 +90,7 @@ export function _getTargetDocumentRef(
86
90
  throw new Error('Document ID must be provided')
87
91
  }
88
92
 
89
- const resource = resolveCommentResource(client)
90
-
91
- return `${resource.type}:${resource.id}:${getPublishedId(documentId)}`
93
+ return getCommentTargetDocumentRef(resolveCommentResource(client), documentId)
92
94
  }
93
95
 
94
96
  type WriteArgs = [
@@ -133,6 +135,8 @@ function write<T>(
133
135
  body,
134
136
  query: {
135
137
  ...resourceQuery(client),
138
+ // Records the client version for telemetry (writes only).
139
+ clientVersion: version,
136
140
  ...(options.transactionId ? {transactionId: options.transactionId} : {}),
137
141
  },
138
142
  ...pick(options, possibleRequestOptions),
@@ -170,6 +174,25 @@ function writeMutationResult(...args: WriteArgs): Observable<MultipleMutationRes
170
174
  )
171
175
  }
172
176
 
177
+ /**
178
+ * Moves the deprecated `range` + `fieldValue` onto a `portable-text` `anchor`.
179
+ * Anything else passes through unchanged, and invalid combinations are left
180
+ * for the API to reject.
181
+ */
182
+ function withAnchor(input: {
183
+ anchor?: CollaborationCommentAnchor | null
184
+ range?: CollaborationCommentRange | null
185
+ fieldValue?: CollaborationCommentFieldValue
186
+ }) {
187
+ const {range, fieldValue, ...rest} = input
188
+
189
+ if (range === undefined || input.anchor !== undefined) return input
190
+
191
+ if (range === null) return fieldValue ? input : {...rest, anchor: null}
192
+
193
+ return {...rest, anchor: {type: 'portable-text', ...range, ...(fieldValue && {fieldValue})}}
194
+ }
195
+
173
196
  /** @internal */
174
197
  export function _create(
175
198
  client: Client,
@@ -183,7 +206,7 @@ export function _create(
183
206
  httpRequest,
184
207
  'POST',
185
208
  '/collaboration/comments',
186
- body,
209
+ body.target ? {...body, target: withAnchor(body.target)} : body,
187
210
  options,
188
211
  )
189
212
  }
@@ -196,7 +219,7 @@ export function _update(
196
219
  body: CollaborationCommentUpdate,
197
220
  options?: CollaborationCommentsWriteOptions,
198
221
  ): Observable<CollaborationCommentDocument> {
199
- return writeDocument(id, client, httpRequest, 'PATCH', commentUrl(id), body, options)
222
+ return writeDocument(id, client, httpRequest, 'PATCH', commentUrl(id), withAnchor(body), options)
200
223
  }
201
224
 
202
225
  /** @internal */
@@ -0,0 +1,45 @@
1
+ import {getPublishedId} from '@sanity/client/csm'
2
+
3
+ import type {ClientConfig} from '../types'
4
+ import type {CollaborationCommentDocument} from './types'
5
+
6
+ /**
7
+ * The resource comments are stored against: one of the client's resource configurations.
8
+ *
9
+ * @internal
10
+ */
11
+ export type CommentResource = NonNullable<ClientConfig['resource']>
12
+
13
+ /**
14
+ * Build the global document reference a comment stores in `target.document._ref`,
15
+ * without a client.
16
+ *
17
+ * `client.collaboration.comments.getTargetDocumentRef` reads the resource off the
18
+ * client's configuration and calls this. Use this directly when the resource is
19
+ * already at hand and no client should be involved, for example inside a state
20
+ * selector that has to stay free of side effects.
21
+ *
22
+ * The reference always names the published document: a draft or version ID is
23
+ * reduced to its published form first.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * getCommentTargetDocumentRef({type: 'dataset', id: 'abc123.production'}, 'drafts.doc-1')
28
+ * // 'dataset:abc123.production:doc-1'
29
+ * ```
30
+ *
31
+ * @param resource - The resource the comments are stored against, as `ClientConfig['resource']` takes it
32
+ * @param documentId - Document ID, in published, draft or version form
33
+ * @returns Global document reference, of the form `resourceType:resourceId:documentId`
34
+ * @alpha
35
+ */
36
+ export function getCommentTargetDocumentRef(
37
+ resource: CommentResource,
38
+ documentId: string,
39
+ ): CollaborationCommentDocument['target']['document']['_ref'] {
40
+ if (!documentId) {
41
+ throw new Error('Document ID must be provided')
42
+ }
43
+
44
+ return `${resource.type}:${resource.id}:${getPublishedId(documentId)}`
45
+ }
@@ -0,0 +1 @@
1
+ export {getCommentTargetDocumentRef} from './getCommentTargetDocumentRef'
@@ -154,6 +154,7 @@ export interface CollaborationCommentDocument extends SanityDocument {
154
154
  * Each endpoint pairs the `_key` of a Portable Text block with a character
155
155
  * offset into that block's plain text.
156
156
  *
157
+ * @deprecated Use {@link CollaborationCommentAnchor}.
157
158
  * @alpha
158
159
  */
159
160
  export interface CollaborationCommentRange {
@@ -162,8 +163,8 @@ export interface CollaborationCommentRange {
162
163
  }
163
164
 
164
165
  /**
165
- * Portable Text covering a comment `range`. Callers can send just the blocks
166
- * from the `range` start `_key` through end `_key`, or the full field.
166
+ * Portable Text covering an inline comment anchor. Callers can send just the
167
+ * blocks from the anchor start `_key` through end `_key`, or the full field.
167
168
  *
168
169
  * @alpha
169
170
  */
@@ -173,16 +174,33 @@ export type CollaborationCommentFieldValue = Array<{
173
174
  [key: string]: Any
174
175
  }>
175
176
 
177
+ /**
178
+ * Where in `path` a comment is anchored.
179
+ *
180
+ * For `portable-text`, each endpoint pairs the `_key` of a Portable Text
181
+ * block with a character offset into that block's plain text. An optional
182
+ * `fieldValue` is Portable Text covering the anchor. When set, the selection
183
+ * is resolved from those blocks instead of from the live document.
184
+ *
185
+ * @alpha
186
+ */
187
+ export type CollaborationCommentAnchor = {
188
+ type: 'portable-text'
189
+ start: {_key: string; offset: number}
190
+ end: {_key: string; offset: number}
191
+ fieldValue?: CollaborationCommentFieldValue
192
+ }
193
+
176
194
  /**
177
195
  * Target for a top-level comment. Inline selections require both `path` and
178
- * `range`; field-level comments may set `path` alone.
196
+ * `anchor`; field-level comments may set `path` alone.
179
197
  *
180
198
  * The created comment stores this in a different shape: `path` becomes
181
- * `target.path.field`, and `range` is resolved against the document into
199
+ * `target.path.field`, and `anchor` is resolved against the document into
182
200
  * `target.path.selection` and `contentSnapshot` rather than being stored.
183
201
  *
184
- * An optional `fieldValue` is Portable Text covering the `range`. When set,
185
- * the `range` is resolved from those blocks instead of from the live document.
202
+ * Deprecated `range` + top-level `fieldValue` are still accepted and converted
203
+ * to a `portable-text` `anchor` before the request is sent.
186
204
  *
187
205
  * @alpha
188
206
  */
@@ -194,17 +212,43 @@ export type CollaborationCommentTarget = {
194
212
  | {
195
213
  /** Path to the field containing the inline comment selection */
196
214
  path: string
215
+ anchor: CollaborationCommentAnchor
216
+ /**
217
+ * @deprecated Use `anchor`.
218
+ */
219
+ range?: never
220
+ /**
221
+ * @deprecated Use `anchor.fieldValue`.
222
+ */
223
+ fieldValue?: never
224
+ }
225
+ | {
226
+ /** Path to the field containing the inline comment selection */
227
+ path: string
228
+ /**
229
+ * @deprecated Use `anchor`.
230
+ */
197
231
  range: CollaborationCommentRange
198
232
  /**
199
- * Portable Text covering the `range`. When set, the `range` is resolved
233
+ * Portable Text covering the `range`. When set, the selection is resolved
200
234
  * from these blocks instead of from the live document.
235
+ *
236
+ * @deprecated Use `anchor.fieldValue`.
201
237
  */
202
238
  fieldValue?: CollaborationCommentFieldValue
239
+ anchor?: never
203
240
  }
204
241
  | {
205
242
  /** Path to the commented field */
206
243
  path?: string
244
+ anchor?: never
245
+ /**
246
+ * @deprecated Use `anchor`.
247
+ */
207
248
  range?: never
249
+ /**
250
+ * @deprecated Use `anchor.fieldValue`.
251
+ */
208
252
  fieldValue?: never
209
253
  }
210
254
  )
@@ -234,7 +278,11 @@ export type CollaborationCommentTarget = {
234
278
  * documentId: 'doc-1',
235
279
  * documentType: 'article',
236
280
  * path: 'body',
237
- * range: {start: {_key: 'block-1', offset: 0}, end: {_key: 'block-1', offset: 5}},
281
+ * anchor: {
282
+ * type: 'portable-text',
283
+ * start: {_key: 'block-1', offset: 0},
284
+ * end: {_key: 'block-1', offset: 5},
285
+ * },
238
286
  * },
239
287
  * })
240
288
  * ```
@@ -270,11 +318,13 @@ export type CollaborationCommentCreate = {
270
318
  /**
271
319
  * Fields that can be updated on an existing comment.
272
320
  *
273
- * A `range` re-anchors the comment within the field it already targets.
321
+ * An `anchor` re-anchors the comment within the field it already targets.
274
322
  * Pass `null` to remove the selection and leave a field-level comment.
275
- * An optional `fieldValue` is Portable Text covering that `range`; when set,
276
- * the `range` is resolved from those blocks instead of from the live document.
277
- * `fieldValue` cannot be sent alone or together with `range: null`.
323
+ * An optional `fieldValue` on a `portable-text` anchor is resolved from those
324
+ * blocks instead of from the live document.
325
+ *
326
+ * Deprecated `range` + top-level `fieldValue` (and `range: null`) are still
327
+ * accepted and converted to `anchor` before the request is sent.
278
328
  *
279
329
  * @alpha
280
330
  */
@@ -285,19 +335,61 @@ export type CollaborationCommentUpdate = {
285
335
  status?: CollaborationCommentStatus
286
336
  } & (
287
337
  | {
338
+ anchor: CollaborationCommentAnchor
339
+ /**
340
+ * @deprecated Use `anchor`.
341
+ */
342
+ range?: never
343
+ /**
344
+ * @deprecated Use `anchor.fieldValue`.
345
+ */
346
+ fieldValue?: never
347
+ }
348
+ | {
349
+ anchor: null
350
+ /**
351
+ * @deprecated Use `anchor`.
352
+ */
353
+ range?: never
354
+ /**
355
+ * @deprecated Use `anchor.fieldValue`.
356
+ */
357
+ fieldValue?: never
358
+ }
359
+ | {
360
+ /**
361
+ * @deprecated Use `anchor`.
362
+ */
288
363
  range: CollaborationCommentRange
289
364
  /**
290
- * Portable Text covering the `range`. When set, the `range` is resolved
365
+ * Portable Text covering the `range`. When set, the selection is resolved
291
366
  * from these blocks instead of from the live document.
367
+ *
368
+ * @deprecated Use `anchor.fieldValue`.
292
369
  */
293
370
  fieldValue?: CollaborationCommentFieldValue
371
+ anchor?: never
294
372
  }
295
373
  | {
374
+ /**
375
+ * @deprecated Use `anchor: null`.
376
+ */
296
377
  range: null
378
+ /**
379
+ * @deprecated Use `anchor.fieldValue`.
380
+ */
297
381
  fieldValue?: never
382
+ anchor?: never
298
383
  }
299
384
  | {
385
+ anchor?: undefined
386
+ /**
387
+ * @deprecated Use `anchor`.
388
+ */
300
389
  range?: undefined
390
+ /**
391
+ * @deprecated Use `anchor.fieldValue`.
392
+ */
301
393
  fieldValue?: never
302
394
  }
303
395
  )