@sanity/client 8.1.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 +171 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +408 -61
- package/dist/index.js.map +1 -1
- package/dist/index.node.d.ts +650 -2
- package/dist/index.node.js +379 -19
- package/dist/index.node.js.map +1 -1
- package/dist/media-library.d.ts +1 -1
- package/dist/{types-BODIEY7F.d.ts → types-nJhm5Nyq.d.ts} +651 -3
- package/package.json +1 -1
- package/src/SanityClient.ts +20 -0
- package/src/collaboration/CollaborationCommentsClient.ts +387 -0
- package/src/collaboration/comments.ts +313 -0
- package/src/collaboration/types.ts +252 -0
- package/src/data/dataMethods.ts +7 -1
- package/src/data/listen.ts +20 -5
- package/src/types.ts +234 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import {getPublishedId} from '@sanity/client/csm'
|
|
2
|
+
import {type Observable, throwError} from 'rxjs'
|
|
3
|
+
import {map} from 'rxjs/operators'
|
|
4
|
+
|
|
5
|
+
import {_requestObservable, getQuerySizeLimit} from '../data/dataMethods'
|
|
6
|
+
import {encodeQueryString} from '../data/encodeQueryString'
|
|
7
|
+
import {
|
|
8
|
+
_connectListenEventSource,
|
|
9
|
+
defaultOptions as defaultListenOptions,
|
|
10
|
+
type ListenEventFromOptions,
|
|
11
|
+
MAX_URL_LENGTH,
|
|
12
|
+
possibleOptions as possibleListenOptions,
|
|
13
|
+
} from '../data/listen'
|
|
14
|
+
import type {ObservableSanityClient, SanityClient} from '../SanityClient'
|
|
15
|
+
import type {
|
|
16
|
+
HttpRequest,
|
|
17
|
+
MultipleMutationResult,
|
|
18
|
+
MutationOperation,
|
|
19
|
+
QueryParams,
|
|
20
|
+
ResumableListenEventNames,
|
|
21
|
+
} from '../types'
|
|
22
|
+
import defaults from '../util/defaults'
|
|
23
|
+
import {pick} from '../util/pick'
|
|
24
|
+
import {
|
|
25
|
+
type CollaborationCommentCreate,
|
|
26
|
+
type CollaborationCommentDocument,
|
|
27
|
+
type CollaborationCommentReactionShortName,
|
|
28
|
+
type CollaborationCommentsListenOptions,
|
|
29
|
+
type CollaborationCommentsRequestOptions,
|
|
30
|
+
type CollaborationCommentsWriteOptions,
|
|
31
|
+
type CollaborationCommentUpdate,
|
|
32
|
+
possibleRequestOptions,
|
|
33
|
+
} from './types'
|
|
34
|
+
|
|
35
|
+
type Client = SanityClient | ObservableSanityClient
|
|
36
|
+
|
|
37
|
+
function commentUrl(id: string): string {
|
|
38
|
+
if (!id) {
|
|
39
|
+
throw new Error('Comment ID must be provided')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return `/collaboration/comments/${encodeURIComponent(id)}`
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function resolveCommentResource(client: Client): {type: string; id: string} {
|
|
46
|
+
const {resource, projectId, dataset} = client.config()
|
|
47
|
+
|
|
48
|
+
if (resource) {
|
|
49
|
+
return resource
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (projectId && dataset) {
|
|
53
|
+
return {type: 'dataset', id: `${projectId}.${dataset}`}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
throw new Error(
|
|
57
|
+
'`resource` or `projectId` and `dataset` must be configured to use collaboration comments',
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function resourceQuery(client: Client): Record<string, string> {
|
|
62
|
+
const {collaboration} = client.config()
|
|
63
|
+
const organizationId = collaboration?.organizationId
|
|
64
|
+
|
|
65
|
+
if (!organizationId) {
|
|
66
|
+
throw new Error(
|
|
67
|
+
'`collaboration.organizationId` must be configured to use collaboration comments',
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const resource = resolveCommentResource(client)
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
organizationId,
|
|
75
|
+
resourceId: resource.id,
|
|
76
|
+
resourceType: resource.type,
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** @internal */
|
|
81
|
+
export function _getTargetDocumentRef(
|
|
82
|
+
client: Client,
|
|
83
|
+
documentId: string,
|
|
84
|
+
): CollaborationCommentDocument['target']['document']['_ref'] {
|
|
85
|
+
if (!documentId) {
|
|
86
|
+
throw new Error('Document ID must be provided')
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const resource = resolveCommentResource(client)
|
|
90
|
+
|
|
91
|
+
return `${resource.type}:${resource.id}:${getPublishedId(documentId)}`
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
type WriteArgs = [
|
|
95
|
+
client: Client,
|
|
96
|
+
httpRequest: HttpRequest,
|
|
97
|
+
method: 'POST' | 'PATCH' | 'DELETE',
|
|
98
|
+
url: string,
|
|
99
|
+
body: unknown,
|
|
100
|
+
options?: CollaborationCommentsWriteOptions,
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The write endpoints pass the mutation response through as-is, mirroring
|
|
105
|
+
* `client.mutate`.
|
|
106
|
+
*/
|
|
107
|
+
interface CommentMutationResponse {
|
|
108
|
+
transactionId: string
|
|
109
|
+
results: {id: string; operation: MutationOperation}[]
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Writes that return a comment come back with the document, since the API
|
|
114
|
+
* requests documents from the org store and 404s when nothing matched. A
|
|
115
|
+
* status update carries one result per cascaded reply on top of the comment
|
|
116
|
+
* itself.
|
|
117
|
+
*/
|
|
118
|
+
interface CommentDocumentMutationResponse extends CommentMutationResponse {
|
|
119
|
+
results: {id: string; operation: MutationOperation; document: CollaborationCommentDocument}[]
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function write<T>(
|
|
123
|
+
client: Client,
|
|
124
|
+
httpRequest: HttpRequest,
|
|
125
|
+
method: 'POST' | 'PATCH' | 'DELETE',
|
|
126
|
+
url: string,
|
|
127
|
+
body: unknown,
|
|
128
|
+
options: CollaborationCommentsWriteOptions = {},
|
|
129
|
+
): Observable<T> {
|
|
130
|
+
return _requestObservable<T>(client, httpRequest, {
|
|
131
|
+
method,
|
|
132
|
+
url,
|
|
133
|
+
body,
|
|
134
|
+
query: {
|
|
135
|
+
...resourceQuery(client),
|
|
136
|
+
...(options.transactionId ? {transactionId: options.transactionId} : {}),
|
|
137
|
+
},
|
|
138
|
+
...pick(options, possibleRequestOptions),
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* `commentId` picks the written comment out of the results: a status update
|
|
144
|
+
* cascades to the comment's replies, and the API leaves the results unordered.
|
|
145
|
+
* Creates pass the requested `_id`, which is undefined when the API assigns
|
|
146
|
+
* one, and always come back with a single result.
|
|
147
|
+
*/
|
|
148
|
+
function writeDocument(
|
|
149
|
+
commentId: string | undefined,
|
|
150
|
+
...args: WriteArgs
|
|
151
|
+
): Observable<CollaborationCommentDocument> {
|
|
152
|
+
return write<CommentDocumentMutationResponse>(...args).pipe(
|
|
153
|
+
map(({results}) => {
|
|
154
|
+
const result = commentId ? results.find(({id}) => id === commentId) : results[0]
|
|
155
|
+
if (!result?.document) {
|
|
156
|
+
throw new Error('Comment write did not return a comment document')
|
|
157
|
+
}
|
|
158
|
+
return result.document
|
|
159
|
+
}),
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function writeMutationResult(...args: WriteArgs): Observable<MultipleMutationResult> {
|
|
164
|
+
return write<CommentMutationResponse>(...args).pipe(
|
|
165
|
+
map(({transactionId, results}) => ({
|
|
166
|
+
transactionId,
|
|
167
|
+
documentIds: results.map((result) => result.id),
|
|
168
|
+
results,
|
|
169
|
+
})),
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** @internal */
|
|
174
|
+
export function _create(
|
|
175
|
+
client: Client,
|
|
176
|
+
httpRequest: HttpRequest,
|
|
177
|
+
body: CollaborationCommentCreate,
|
|
178
|
+
options?: CollaborationCommentsWriteOptions,
|
|
179
|
+
): Observable<CollaborationCommentDocument> {
|
|
180
|
+
return writeDocument(
|
|
181
|
+
body._id,
|
|
182
|
+
client,
|
|
183
|
+
httpRequest,
|
|
184
|
+
'POST',
|
|
185
|
+
'/collaboration/comments',
|
|
186
|
+
body,
|
|
187
|
+
options,
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** @internal */
|
|
192
|
+
export function _update(
|
|
193
|
+
client: Client,
|
|
194
|
+
httpRequest: HttpRequest,
|
|
195
|
+
id: string,
|
|
196
|
+
body: CollaborationCommentUpdate,
|
|
197
|
+
options?: CollaborationCommentsWriteOptions,
|
|
198
|
+
): Observable<CollaborationCommentDocument> {
|
|
199
|
+
return writeDocument(id, client, httpRequest, 'PATCH', commentUrl(id), body, options)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** @internal */
|
|
203
|
+
export function _delete(
|
|
204
|
+
client: Client,
|
|
205
|
+
httpRequest: HttpRequest,
|
|
206
|
+
id: string,
|
|
207
|
+
options?: CollaborationCommentsWriteOptions,
|
|
208
|
+
): Observable<MultipleMutationResult> {
|
|
209
|
+
return writeMutationResult(client, httpRequest, 'DELETE', commentUrl(id), undefined, options)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** @internal */
|
|
213
|
+
export function _addReaction(
|
|
214
|
+
client: Client,
|
|
215
|
+
httpRequest: HttpRequest,
|
|
216
|
+
id: string,
|
|
217
|
+
shortName: CollaborationCommentReactionShortName,
|
|
218
|
+
options?: CollaborationCommentsWriteOptions,
|
|
219
|
+
): Observable<CollaborationCommentDocument> {
|
|
220
|
+
return writeDocument(
|
|
221
|
+
id,
|
|
222
|
+
client,
|
|
223
|
+
httpRequest,
|
|
224
|
+
'POST',
|
|
225
|
+
`${commentUrl(id)}/reactions`,
|
|
226
|
+
{shortName},
|
|
227
|
+
options,
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** @internal */
|
|
232
|
+
export function _removeReaction(
|
|
233
|
+
client: Client,
|
|
234
|
+
httpRequest: HttpRequest,
|
|
235
|
+
id: string,
|
|
236
|
+
shortName: CollaborationCommentReactionShortName,
|
|
237
|
+
options?: CollaborationCommentsWriteOptions,
|
|
238
|
+
): Observable<CollaborationCommentDocument> {
|
|
239
|
+
return writeDocument(
|
|
240
|
+
id,
|
|
241
|
+
client,
|
|
242
|
+
httpRequest,
|
|
243
|
+
'DELETE',
|
|
244
|
+
`${commentUrl(id)}/reactions/${encodeURIComponent(shortName)}`,
|
|
245
|
+
undefined,
|
|
246
|
+
options,
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** @internal */
|
|
251
|
+
export function _fetch<R>(
|
|
252
|
+
client: Client,
|
|
253
|
+
httpRequest: HttpRequest,
|
|
254
|
+
query: string,
|
|
255
|
+
params?: QueryParams,
|
|
256
|
+
options?: CollaborationCommentsRequestOptions,
|
|
257
|
+
): Observable<R> {
|
|
258
|
+
const search = resourceQuery(client)
|
|
259
|
+
|
|
260
|
+
// Mirrors `client.fetch`: GET while the query fits in the URL, POST beyond that.
|
|
261
|
+
const useGet = encodeQueryString({query, params}).length < getQuerySizeLimit
|
|
262
|
+
const request = useGet
|
|
263
|
+
? {
|
|
264
|
+
method: 'GET',
|
|
265
|
+
url: `/collaboration/comments/query${encodeQueryString({query, params, options: search})}`,
|
|
266
|
+
}
|
|
267
|
+
: {
|
|
268
|
+
method: 'POST',
|
|
269
|
+
url: '/collaboration/comments/query',
|
|
270
|
+
query: search,
|
|
271
|
+
body: {query, params: params ?? {}},
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return _requestObservable<{result: R}>(client, httpRequest, {
|
|
275
|
+
...request,
|
|
276
|
+
...pick(options || {}, possibleRequestOptions),
|
|
277
|
+
}).pipe(map((response) => response.result))
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/** @internal */
|
|
281
|
+
export function _listen<
|
|
282
|
+
Opts extends CollaborationCommentsListenOptions = CollaborationCommentsListenOptions,
|
|
283
|
+
>(
|
|
284
|
+
client: Client,
|
|
285
|
+
query: string,
|
|
286
|
+
params?: QueryParams,
|
|
287
|
+
options?: Opts,
|
|
288
|
+
): Observable<ListenEventFromOptions<CollaborationCommentDocument, Opts>> {
|
|
289
|
+
const opts: CollaborationCommentsListenOptions = options ?? {}
|
|
290
|
+
|
|
291
|
+
// Mirrors `_listen` in data/listen.ts, but against the comments listen endpoint
|
|
292
|
+
const {requestTagPrefix} = client.config()
|
|
293
|
+
const tag = opts.tag && requestTagPrefix ? [requestTagPrefix, opts.tag].join('.') : opts.tag
|
|
294
|
+
const listenOpts = pick({...defaults(opts, defaultListenOptions), tag}, possibleListenOptions)
|
|
295
|
+
const qs = encodeQueryString({
|
|
296
|
+
query,
|
|
297
|
+
params,
|
|
298
|
+
options: {...listenOpts, ...resourceQuery(client)},
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
const uri = `${client.getUrl('/collaboration/comments/listen')}${qs}`
|
|
302
|
+
if (uri.length > MAX_URL_LENGTH) {
|
|
303
|
+
return throwError(() => new Error('Query too large for listener'))
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const events: ResumableListenEventNames[] = opts.events ? opts.events : ['mutation']
|
|
307
|
+
|
|
308
|
+
return _connectListenEventSource<ListenEventFromOptions<CollaborationCommentDocument, Opts>>(
|
|
309
|
+
client,
|
|
310
|
+
uri,
|
|
311
|
+
events,
|
|
312
|
+
)
|
|
313
|
+
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Any,
|
|
3
|
+
ListenOptions,
|
|
4
|
+
RequestOptions,
|
|
5
|
+
ResumableListenOptions,
|
|
6
|
+
SanityDocument,
|
|
7
|
+
} from '../types'
|
|
8
|
+
|
|
9
|
+
/** @internal */
|
|
10
|
+
export const possibleRequestOptions = ['headers', 'signal', 'tag', 'timeout', 'token'] as const
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Request options honored by the collaboration comments methods.
|
|
14
|
+
*
|
|
15
|
+
* @alpha
|
|
16
|
+
*/
|
|
17
|
+
export type CollaborationCommentsRequestOptions = Pick<
|
|
18
|
+
RequestOptions,
|
|
19
|
+
(typeof possibleRequestOptions)[number]
|
|
20
|
+
>
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Options for collaboration comments write methods.
|
|
24
|
+
*
|
|
25
|
+
* @alpha
|
|
26
|
+
*/
|
|
27
|
+
export type CollaborationCommentsWriteOptions = CollaborationCommentsRequestOptions & {
|
|
28
|
+
/** Transaction ID to associate the write with */
|
|
29
|
+
transactionId?: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Listener options for `collaboration.comments.listen`.
|
|
34
|
+
*
|
|
35
|
+
* `includeAllVersions` is left out: comments are stored as `sanity.comment`
|
|
36
|
+
* documents with no drafts or versions, so it would never make a difference.
|
|
37
|
+
*
|
|
38
|
+
* @alpha
|
|
39
|
+
*/
|
|
40
|
+
export type CollaborationCommentsListenOptions =
|
|
41
|
+
| Omit<ListenOptions, 'includeAllVersions'>
|
|
42
|
+
| Omit<ResumableListenOptions, 'includeAllVersions'>
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Status of a comment thread. Replies always share the status of their parent comment.
|
|
46
|
+
*
|
|
47
|
+
* @alpha
|
|
48
|
+
*/
|
|
49
|
+
export type CollaborationCommentStatus = 'open' | 'resolved'
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Emoji short names that can be used as comment reactions.
|
|
53
|
+
*
|
|
54
|
+
* @alpha
|
|
55
|
+
*/
|
|
56
|
+
export type CollaborationCommentReactionShortName =
|
|
57
|
+
| ':-1:'
|
|
58
|
+
| ':+1:'
|
|
59
|
+
| ':eyes:'
|
|
60
|
+
| ':heart:'
|
|
61
|
+
| ':heavy_plus_sign:'
|
|
62
|
+
| ':rocket:'
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* A single Portable Text block, as used in comment messages and content snapshots.
|
|
66
|
+
*
|
|
67
|
+
* @alpha
|
|
68
|
+
*/
|
|
69
|
+
export interface CollaborationCommentPortableTextBlock {
|
|
70
|
+
_type: string
|
|
71
|
+
children: Array<{_type: string; [key: string]: Any}>
|
|
72
|
+
[key: string]: Any
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Comment message, as an array of Portable Text blocks.
|
|
77
|
+
*
|
|
78
|
+
* @alpha
|
|
79
|
+
*/
|
|
80
|
+
export type CollaborationCommentMessage = CollaborationCommentPortableTextBlock[]
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The text an inline comment was anchored to, resolved by the API when the
|
|
84
|
+
* comment was created.
|
|
85
|
+
*
|
|
86
|
+
* Holds one entry per Portable Text block the selection spans, keyed by the
|
|
87
|
+
* block it came from. `text` is the plain text of that block with the selected
|
|
88
|
+
* part wrapped in the marker characters `\uF000` (start) and `\uF001` (end).
|
|
89
|
+
*
|
|
90
|
+
* @alpha
|
|
91
|
+
*/
|
|
92
|
+
export interface CollaborationCommentSelection {
|
|
93
|
+
type: 'text'
|
|
94
|
+
value: {_key: string; text: string}[]
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* A comment document, as stored by the Comments API.
|
|
99
|
+
*
|
|
100
|
+
* @alpha
|
|
101
|
+
*/
|
|
102
|
+
export interface CollaborationCommentDocument extends SanityDocument {
|
|
103
|
+
_type: 'sanity.comment'
|
|
104
|
+
_system?: {
|
|
105
|
+
/** ID of the user that created the comment */
|
|
106
|
+
createdBy?: string
|
|
107
|
+
}
|
|
108
|
+
/** ID shared by a top-level comment and all of its replies */
|
|
109
|
+
threadId?: string
|
|
110
|
+
/** Set on replies, pointing to the comment being replied to */
|
|
111
|
+
parentCommentId?: string
|
|
112
|
+
message: CollaborationCommentMessage
|
|
113
|
+
reactions: {
|
|
114
|
+
_key: string
|
|
115
|
+
shortName: CollaborationCommentReactionShortName
|
|
116
|
+
userId: string
|
|
117
|
+
addedAt: string
|
|
118
|
+
}[]
|
|
119
|
+
/** Arbitrary metadata stored with the comment by the creating application */
|
|
120
|
+
context?: Record<string, unknown>
|
|
121
|
+
target: {
|
|
122
|
+
/** Global document reference (`resourceType:resourceId:documentId`, using the published document ID) */
|
|
123
|
+
document: {
|
|
124
|
+
_ref: `${string}:${string}:${string}`
|
|
125
|
+
_type: 'globalDocumentReference'
|
|
126
|
+
_weak: true
|
|
127
|
+
}
|
|
128
|
+
documentType: string
|
|
129
|
+
/** The exact document ID the comment was created against, e.g. a draft or version ID */
|
|
130
|
+
sourceDocumentId: string
|
|
131
|
+
documentRevisionId?: string
|
|
132
|
+
/**
|
|
133
|
+
* Set for field and inline comments. `field` is the `path` the comment was
|
|
134
|
+
* created with; `selection` is set for inline comments only.
|
|
135
|
+
*/
|
|
136
|
+
path?: {
|
|
137
|
+
field: string
|
|
138
|
+
selection?: CollaborationCommentSelection
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Copy of the commented content, as it looked when the comment was created.
|
|
143
|
+
* Set for inline comments only, and holds just the selected fragment of each
|
|
144
|
+
* Portable Text block the selection spans.
|
|
145
|
+
*/
|
|
146
|
+
contentSnapshot?: CollaborationCommentPortableTextBlock[]
|
|
147
|
+
status: CollaborationCommentStatus
|
|
148
|
+
/** Set when the message has been updated after creation */
|
|
149
|
+
lastEditedAt?: string
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Inline text selection within a Portable Text field.
|
|
154
|
+
* Each endpoint pairs the `_key` of a Portable Text block with a character
|
|
155
|
+
* offset into that block's plain text.
|
|
156
|
+
*
|
|
157
|
+
* @alpha
|
|
158
|
+
*/
|
|
159
|
+
export interface CollaborationCommentRange {
|
|
160
|
+
start: {_key: string; offset: number}
|
|
161
|
+
end: {_key: string; offset: number}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Target for a top-level comment. Inline selections require both `path` and
|
|
166
|
+
* `range`; field-level comments may set `path` alone.
|
|
167
|
+
*
|
|
168
|
+
* The created comment stores this in a different shape: `path` becomes
|
|
169
|
+
* `target.path.field`, and `range` is resolved against the document into
|
|
170
|
+
* `target.path.selection` and `contentSnapshot` rather than being stored.
|
|
171
|
+
*
|
|
172
|
+
* @alpha
|
|
173
|
+
*/
|
|
174
|
+
export type CollaborationCommentTarget = {
|
|
175
|
+
documentId: string
|
|
176
|
+
documentType: string
|
|
177
|
+
documentRevisionId?: string
|
|
178
|
+
} & (
|
|
179
|
+
| {
|
|
180
|
+
/** Path to the field containing the inline comment selection */
|
|
181
|
+
path: string
|
|
182
|
+
range: CollaborationCommentRange
|
|
183
|
+
}
|
|
184
|
+
| {
|
|
185
|
+
/** Path to the commented field */
|
|
186
|
+
path?: string
|
|
187
|
+
range?: never
|
|
188
|
+
}
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Comment to create with `collaboration.comments.create`.
|
|
193
|
+
*
|
|
194
|
+
* A top-level comment requires `target`; a reply requires `parentCommentId` (never both).
|
|
195
|
+
* Replies inherit `target`, `status`, and `threadId` from the parent comment.
|
|
196
|
+
*
|
|
197
|
+
* ### Examples
|
|
198
|
+
*
|
|
199
|
+
* #### Top-level comment
|
|
200
|
+
* ```ts
|
|
201
|
+
* // `message` is an array of Portable Text blocks
|
|
202
|
+
* await client.collaboration.comments.create({
|
|
203
|
+
* message,
|
|
204
|
+
* target: {documentId: 'doc-1', documentType: 'article'},
|
|
205
|
+
* })
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* #### Reply
|
|
209
|
+
* ```ts
|
|
210
|
+
* await client.collaboration.comments.create({
|
|
211
|
+
* message,
|
|
212
|
+
* parentCommentId: 'comment-1',
|
|
213
|
+
* })
|
|
214
|
+
* ```
|
|
215
|
+
*
|
|
216
|
+
* @alpha
|
|
217
|
+
*/
|
|
218
|
+
export type CollaborationCommentCreate = {
|
|
219
|
+
/** Provide to control the ID of the created comment document */
|
|
220
|
+
_id?: string
|
|
221
|
+
message: CollaborationCommentMessage
|
|
222
|
+
context?: Record<string, unknown>
|
|
223
|
+
} & (
|
|
224
|
+
| {
|
|
225
|
+
target: CollaborationCommentTarget
|
|
226
|
+
threadId?: string
|
|
227
|
+
parentCommentId?: never
|
|
228
|
+
}
|
|
229
|
+
| {
|
|
230
|
+
parentCommentId: string
|
|
231
|
+
target?: never
|
|
232
|
+
threadId?: never
|
|
233
|
+
}
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Fields that can be updated on an existing comment.
|
|
238
|
+
*
|
|
239
|
+
* @alpha
|
|
240
|
+
*/
|
|
241
|
+
export interface CollaborationCommentUpdate {
|
|
242
|
+
/** Replaces the current message */
|
|
243
|
+
message?: CollaborationCommentMessage
|
|
244
|
+
/** Cascades to the comment's replies */
|
|
245
|
+
status?: CollaborationCommentStatus
|
|
246
|
+
/**
|
|
247
|
+
* Re-anchors the comment within the field and source document it already
|
|
248
|
+
* targets. Pass `null` to remove the selection and leave a field-level
|
|
249
|
+
* comment.
|
|
250
|
+
*/
|
|
251
|
+
range?: CollaborationCommentRange | null
|
|
252
|
+
}
|
package/src/data/dataMethods.ts
CHANGED
|
@@ -73,7 +73,13 @@ const indexBy = (docs: Any[], attr: Any) =>
|
|
|
73
73
|
return indexed
|
|
74
74
|
}, Object.create(null))
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Encoded query strings longer than this are sent as a `POST` body rather than
|
|
78
|
+
* in the request URL.
|
|
79
|
+
*
|
|
80
|
+
* @internal
|
|
81
|
+
*/
|
|
82
|
+
export const getQuerySizeLimit = 11264
|
|
77
83
|
|
|
78
84
|
/**
|
|
79
85
|
* Resolve the effective stega config, cleaned params, response mapper and
|
package/src/data/listen.ts
CHANGED
|
@@ -29,9 +29,11 @@ import {resolveEventSourceFetch} from './resolveEventSourceFetch'
|
|
|
29
29
|
// Limit is 16K for a _request_, eg including headers. Have to account for an
|
|
30
30
|
// unknown range of headers, but an average EventSource request from Chrome seems
|
|
31
31
|
// to have around 700 bytes of cruft, so let us account for 1.2K to be "safe"
|
|
32
|
-
|
|
32
|
+
/** @internal */
|
|
33
|
+
export const MAX_URL_LENGTH = 16000 - 1200
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
/** @internal */
|
|
36
|
+
export const possibleOptions = [
|
|
35
37
|
'includePreviousRevision',
|
|
36
38
|
'includeResult',
|
|
37
39
|
'includeMutations',
|
|
@@ -42,7 +44,8 @@ const possibleOptions = [
|
|
|
42
44
|
'tag',
|
|
43
45
|
]
|
|
44
46
|
|
|
45
|
-
|
|
47
|
+
/** @internal */
|
|
48
|
+
export const defaultOptions = {
|
|
46
49
|
includeResult: true,
|
|
47
50
|
}
|
|
48
51
|
|
|
@@ -137,7 +140,7 @@ export function _listen<
|
|
|
137
140
|
opts: Opts = {} as Opts,
|
|
138
141
|
): Observable<ListenEventFromOptions<R, Opts>> {
|
|
139
142
|
const config = this.config()
|
|
140
|
-
const {url,
|
|
143
|
+
const {url, requestTagPrefix} = config
|
|
141
144
|
const tag = opts.tag && requestTagPrefix ? [requestTagPrefix, opts.tag].join('.') : opts.tag
|
|
142
145
|
const options = {...defaults(opts, defaultOptions), tag}
|
|
143
146
|
const listenOpts = pick(options, possibleOptions)
|
|
@@ -150,6 +153,18 @@ export function _listen<
|
|
|
150
153
|
|
|
151
154
|
const listenFor = (options.events ? options.events : ['mutation']) satisfies Opts['events']
|
|
152
155
|
|
|
156
|
+
return _connectListenEventSource<ListenEventFromOptions<R, Opts>>(this, uri, listenFor)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** @internal */
|
|
160
|
+
export function _connectListenEventSource<TEvent extends {type: string}>(
|
|
161
|
+
client: SanityClient | ObservableSanityClient,
|
|
162
|
+
uri: string,
|
|
163
|
+
listenFor: string[],
|
|
164
|
+
): Observable<TEvent> {
|
|
165
|
+
const config = client.config()
|
|
166
|
+
const {token, withCredentials, headers: configHeaders} = config
|
|
167
|
+
|
|
153
168
|
const headers: Record<string, string> = {}
|
|
154
169
|
if (token) {
|
|
155
170
|
headers.Authorization = `Bearer ${token}`
|
|
@@ -173,5 +188,5 @@ export function _listen<
|
|
|
173
188
|
type: event.type,
|
|
174
189
|
...('data' in event ? (event.data as object) : {}),
|
|
175
190
|
})),
|
|
176
|
-
) as Observable<
|
|
191
|
+
) as Observable<TEvent>
|
|
177
192
|
}
|